From 71da024e55011b99cd67e09eb1773b764d718a65 Mon Sep 17 00:00:00 2001 From: Benign X <1341398182@qq.com> Date: Thu, 30 Nov 2023 16:42:39 +0800 Subject: [PATCH] feat(lv_rb_t): add red black tree to lvgl (#4585) --- lvgl.h | 1 + src/misc/lv_rb.c | 520 +++++++++++++++++++++++++++++++++++++++++++++++ src/misc/lv_rb.h | 78 +++++++ 3 files changed, 599 insertions(+) create mode 100644 src/misc/lv_rb.c create mode 100644 src/misc/lv_rb.h diff --git a/lvgl.h b/lvgl.h index 9f69d372a..bff014939 100644 --- a/lvgl.h +++ b/lvgl.h @@ -34,6 +34,7 @@ extern "C" { #include "src/misc/lv_async.h" #include "src/misc/lv_anim_timeline.h" #include "src/misc/lv_profiler_builtin.h" +#include "src/misc/lv_rb.h" #include "src/tick/lv_tick.h" diff --git a/src/misc/lv_rb.c b/src/misc/lv_rb.c new file mode 100644 index 000000000..f9ee98d11 --- /dev/null +++ b/src/misc/lv_rb.c @@ -0,0 +1,520 @@ +/** + * @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; +} + +bool lv_rb_remove(lv_rb_t * tree, const void * key) +{ + LV_ASSERT_NULL(tree); + if(tree == NULL) { + return false; + } + + 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 false; + } + + 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); + } + + lv_free(node->data); + lv_free(node); + return true; + } + + 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); + } + + lv_free(node->data); + lv_free(node); + return true; +} + +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; + } + } +} + +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(sizeof(lv_rb_node_t)); + LV_ASSERT_MALLOC(node); + if(node == NULL) { + return NULL; + } + + node->data = lv_malloc(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; +} diff --git a/src/misc/lv_rb.h b/src/misc/lv_rb.h new file mode 100644 index 000000000..c266b1f1e --- /dev/null +++ b/src/misc/lv_rb.h @@ -0,0 +1,78 @@ +/** + * @file lv_rb.h + * + */ + + +#ifndef LV_RB_H +#define LV_RB_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ +#include "lv_types.h" +#include "stdbool.h" +#include "lv_assert.h" + +/********************* + * DEFINES + *********************/ + +/********************** + * TYPEDEFS + **********************/ + +typedef enum { + LV_RB_COLOR_RED, + LV_RB_COLOR_BLACK +} lv_rb_color_t; + +typedef struct lv_rb_node_t { + struct lv_rb_node_t * parent; + struct lv_rb_node_t * left; + struct lv_rb_node_t * right; + lv_rb_color_t color; + void * data; +} lv_rb_node_t; + +typedef int8_t lv_rb_compare_res_t; + +typedef lv_rb_compare_res_t (*lv_rb_compare_t)(const void * a, const void * b); + +typedef struct { + lv_rb_node_t * root; + lv_rb_compare_t compare; + size_t size; +} lv_rb_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +bool lv_rb_init(lv_rb_t * tree, lv_rb_compare_t compare, size_t node_size); +lv_rb_node_t * lv_rb_insert(lv_rb_t * tree, void * key); +lv_rb_node_t * lv_rb_find(lv_rb_t * tree, const void * key); +bool lv_rb_remove(lv_rb_t * tree, const void * key); +lv_rb_node_t * lv_rb_minimum(lv_rb_t * node); +lv_rb_node_t * lv_rb_maximum(lv_rb_t * node); +lv_rb_node_t * lv_rb_minimum_from(lv_rb_node_t * node); +lv_rb_node_t * lv_rb_maximum_from(lv_rb_node_t * node); +void lv_rb_destroy(lv_rb_t * tree); + +/************************* + * GLOBAL VARIABLES + *************************/ + +/********************** + * MACROS + **********************/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_RB_H*/