/** * @file lv_rb.c * */ /********************* * INCLUDES *********************/ #include "lv_rb.h" #include "../stdlib/lv_string.h" /********************* * DEFINES *********************/ /********************** * TYPEDEFS **********************/ /********************** * STATIC PROTOTYPES **********************/ static lv_rb_node_t * rb_create_node(lv_rb_t * tree); static lv_rb_node_t * rb_find_leaf_parent(lv_rb_t * tree, lv_rb_node_t * node); static void rb_right_rotate(lv_rb_t * tree, lv_rb_node_t * node); static void rb_left_rotate(lv_rb_t * tree, lv_rb_node_t * node); static void rb_insert_color(lv_rb_t * tree, lv_rb_node_t * node); static void rb_delete_color(lv_rb_t * tree, lv_rb_node_t * node1, lv_rb_node_t * node2); /********************** * GLOBAL VARIABLES **********************/ /********************** * STATIC VARIABLES **********************/ /********************** * MACROS **********************/ /********************** * GLOBAL FUNCTIONS **********************/ bool lv_rb_init(lv_rb_t * tree, lv_rb_compare_t compare, size_t node_size) { LV_ASSERT_NULL(tree); LV_ASSERT_NULL(compare); LV_ASSERT(node_size > 0); if(tree == NULL || compare == NULL || node_size == 0) { return false; } lv_memzero(tree, sizeof(lv_rb_t)); tree->root = NULL; tree->compare = compare; tree->size = node_size; return true; } lv_rb_node_t * lv_rb_insert(lv_rb_t * tree, void * key) { LV_ASSERT_NULL(tree); if(tree == NULL) { return NULL; } lv_rb_node_t * node = lv_rb_find(tree, key); if(node) return node; else { node = rb_create_node(tree); if(node == NULL) return NULL; if(tree->root == NULL) { tree->root = node; node->parent = NULL; node->color = LV_RB_COLOR_BLACK; return node; } } void * new_data = node->data; node->data = key; lv_rb_node_t * parent = rb_find_leaf_parent(tree, node); node->parent = parent; node->color = LV_RB_COLOR_RED; if(tree->compare(key, parent->data) < 0) parent->left = node; else parent->right = node; rb_insert_color(tree, node); node->data = new_data; return node; } lv_rb_node_t * lv_rb_find(lv_rb_t * tree, const void * key) { LV_ASSERT_NULL(tree); if(tree == NULL) { return NULL; } lv_rb_node_t * current = tree->root; while(current != NULL) { lv_rb_compare_res_t cmp = tree->compare(key, current->data); if(cmp == 0) { return current; } else if(cmp < 0) { current = current->left; } else { current = current->right; } } return NULL; } void * lv_rb_remove_node(lv_rb_t * tree, lv_rb_node_t * node) { lv_rb_node_t * child = NULL; lv_rb_node_t * parent = NULL; lv_rb_color_t color = LV_RB_COLOR_BLACK; if(node->left != NULL && node->right != NULL) { lv_rb_node_t * replace = node; replace = lv_rb_minimum_from(replace->right); if(node->parent != NULL) { if(node->parent->left == node) { node->parent->left = replace; } else { node->parent->right = replace; } } else { tree->root = replace; } child = replace->right; parent = replace->parent; color = replace->color; if(parent == node) { parent = replace; } else { if(child != NULL) { child->parent = parent; } parent->left = child; replace->right = node->right; node->right->parent = replace; } replace->parent = node->parent; replace->color = node->color; replace->left = node->left; node->left->parent = replace; if(color == LV_RB_COLOR_BLACK) { rb_delete_color(tree, child, parent); } void * data = node->data; lv_free(node); return data; } child = node->right != NULL ? node->right : node->left; parent = node->parent; color = node->color; if(child != NULL) { child->parent = parent; } if(parent != NULL) { if(parent->left == node) { parent->left = child; } else { parent->right = child; } } else { tree->root = child; } if(color == LV_RB_COLOR_BLACK) { rb_delete_color(tree, child, parent); } void * data = node->data; lv_free(node); return data; } void * lv_rb_remove(lv_rb_t * tree, const void * key) { LV_ASSERT_NULL(tree); if(tree == NULL) { return NULL; } lv_rb_node_t * node = lv_rb_find(tree, key); LV_ASSERT_NULL(node); if(node == NULL) { LV_LOG_WARN("rb delete %d not found", (int)(uintptr_t)key); return NULL; } return lv_rb_remove_node(tree, node); } bool lv_rb_drop_node(lv_rb_t * tree, lv_rb_node_t * node) { LV_ASSERT_NULL(tree); if(tree == NULL) { return false; } void * data = lv_rb_remove_node(tree, node); if(data) { lv_free(data); return true; } return false; } bool lv_rb_drop(lv_rb_t * tree, const void * key) { LV_ASSERT_NULL(tree); if(tree == NULL) { return false; } void * data = lv_rb_remove(tree, key); if(data) { lv_free(data); return true; } return false; } void lv_rb_destroy(lv_rb_t * tree) { LV_ASSERT_NULL(tree); if(tree == NULL) { return; } lv_rb_node_t * node = tree->root; lv_rb_node_t * parent = NULL; while(node != NULL) { if(node->left != NULL) { node = node->left; } else if(node->right != NULL) { node = node->right; } else { parent = node->parent; if(parent != NULL) { if(parent->left == node) { parent->left = NULL; } else { parent->right = NULL; } } lv_free(node->data); lv_free(node); node = parent; } } tree->root = NULL; } lv_rb_node_t * lv_rb_minimum(lv_rb_t * tree) { LV_ASSERT_NULL(tree); if(tree == NULL) { return NULL; } return lv_rb_minimum_from(tree->root); } lv_rb_node_t * lv_rb_maximum(lv_rb_t * tree) { LV_ASSERT_NULL(tree); if(tree == NULL) { return NULL; } return lv_rb_maximum_from(tree->root); } lv_rb_node_t * lv_rb_minimum_from(lv_rb_node_t * node) { while(node->left != NULL) { node = node->left; } return node; } lv_rb_node_t * lv_rb_maximum_from(lv_rb_node_t * node) { while(node->right != NULL) { node = node->right; } return node; } /********************** * STATIC FUNCTIONS **********************/ static lv_rb_node_t * rb_create_node(lv_rb_t * tree) { lv_rb_node_t * node = lv_malloc_zeroed(sizeof(lv_rb_node_t)); LV_ASSERT_MALLOC(node); if(node == NULL) { return NULL; } node->data = lv_malloc_zeroed(tree->size); LV_ASSERT_MALLOC(node->data); if(node->data == NULL) { lv_free(node); return NULL; } node->color = LV_RB_COLOR_RED; node->left = NULL; node->right = NULL; return node; } static lv_rb_node_t * rb_find_leaf_parent(lv_rb_t * tree, lv_rb_node_t * node) { lv_rb_node_t * current = tree->root; lv_rb_node_t * parent = current; while(current != NULL) { parent = current; if(tree->compare(node->data, current->data) < 0) { current = current->left; } else { current = current->right; } } return parent; } static void rb_right_rotate(lv_rb_t * tree, lv_rb_node_t * node) { lv_rb_node_t * left = node->left; node->left = left->right; if(left->right != NULL) { left->right->parent = node; } left->parent = node->parent; if(node->parent == NULL) { tree->root = left; } else if(node == node->parent->right) { node->parent->right = left; } else { node->parent->left = left; } left->right = node; node->parent = left; } static void rb_left_rotate(lv_rb_t * tree, lv_rb_node_t * node) { lv_rb_node_t * right = node->right; node->right = right->left; if(right->left != NULL) { right->left->parent = node; } right->parent = node->parent; if(node->parent == NULL) { tree->root = right; } else if(node == node->parent->left) { node->parent->left = right; } else { node->parent->right = right; } right->left = node; node->parent = right; } static void rb_insert_color(lv_rb_t * tree, lv_rb_node_t * node) { lv_rb_node_t * parent = NULL; lv_rb_node_t * gparent = NULL; while((parent = node->parent) && parent->color == LV_RB_COLOR_RED) { gparent = parent->parent; if(parent == gparent->left) { { lv_rb_node_t * uncle = gparent->right; if(uncle && uncle->color == LV_RB_COLOR_RED) { uncle->color = LV_RB_COLOR_BLACK; parent->color = LV_RB_COLOR_BLACK; gparent->color = LV_RB_COLOR_RED; node = gparent; continue; } } if(parent->right == node) { lv_rb_node_t * tmp; rb_left_rotate(tree, parent); tmp = parent; parent = node; node = tmp; } parent->color = LV_RB_COLOR_BLACK; gparent->color = LV_RB_COLOR_RED; rb_right_rotate(tree, gparent); } else { { lv_rb_node_t * uncle = gparent->left; if(uncle && uncle->color == LV_RB_COLOR_RED) { uncle->color = LV_RB_COLOR_BLACK; parent->color = LV_RB_COLOR_BLACK; gparent->color = LV_RB_COLOR_RED; node = gparent; continue; } } if(parent->left == node) { lv_rb_node_t * tmp; rb_right_rotate(tree, parent); tmp = parent; parent = node; node = tmp; } parent->color = LV_RB_COLOR_BLACK; gparent->color = LV_RB_COLOR_RED; rb_left_rotate(tree, gparent); } } tree->root->color = LV_RB_COLOR_BLACK; } static void rb_delete_color(lv_rb_t * tree, lv_rb_node_t * node1, lv_rb_node_t * node2) { LV_ASSERT_NULL(tree); if(tree == NULL) { return; } while((node1 == NULL || node1->color == LV_RB_COLOR_BLACK) && node1 != tree->root) { if(node2->left == node1) { lv_rb_node_t * pNode2 = node2->right; if(pNode2->color == LV_RB_COLOR_RED) { pNode2->color = LV_RB_COLOR_BLACK; node2->color = LV_RB_COLOR_RED; rb_left_rotate(tree, node2); pNode2 = node2->right; } if((pNode2->left == NULL || pNode2->left->color == LV_RB_COLOR_BLACK) && (pNode2->right == NULL || pNode2->right->color == LV_RB_COLOR_BLACK)) { pNode2->color = LV_RB_COLOR_RED; node1 = node2; node2 = node2->parent; } else { if(pNode2->right == NULL || pNode2->right->color == LV_RB_COLOR_BLACK) { pNode2->left->color = LV_RB_COLOR_BLACK; pNode2->color = LV_RB_COLOR_RED; rb_right_rotate(tree, pNode2); pNode2 = node2->right; } pNode2->color = node2->color; node2->color = LV_RB_COLOR_BLACK; pNode2->right->color = LV_RB_COLOR_BLACK; rb_left_rotate(tree, node2); node1 = tree->root; break; } } else { lv_rb_node_t * pNode2 = node2->left; if(pNode2->color == LV_RB_COLOR_RED) { pNode2->color = LV_RB_COLOR_BLACK; node2->color = LV_RB_COLOR_RED; rb_right_rotate(tree, node2); pNode2 = node2->left; } if((pNode2->left == NULL || pNode2->left->color == LV_RB_COLOR_BLACK) && (pNode2->right == NULL || pNode2->right->color == LV_RB_COLOR_BLACK)) { pNode2->color = LV_RB_COLOR_RED; node1 = node2; node2 = node2->parent; } else { if(pNode2->left == NULL || pNode2->left->color == LV_RB_COLOR_BLACK) { pNode2->right->color = LV_RB_COLOR_BLACK; pNode2->color = LV_RB_COLOR_RED; rb_left_rotate(tree, pNode2); pNode2 = node2->left; } pNode2->color = node2->color; node2->color = LV_RB_COLOR_BLACK; pNode2->left->color = LV_RB_COLOR_BLACK; rb_right_rotate(tree, node2); node1 = tree->root; break; } } } if(node1 != NULL) node1->color = LV_RB_COLOR_BLACK; }