feat(lv_rb_t): add red black tree to lvgl (#4585)

This commit is contained in:
Benign X 2023-11-30 16:42:39 +08:00 committed by GitHub
parent 6bc99b1d1f
commit 71da024e55
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 599 additions and 0 deletions

1
lvgl.h
View File

@ -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"

520
src/misc/lv_rb.c Normal file
View File

@ -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;
}

78
src/misc/lv_rb.h Normal file
View File

@ -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*/