mirror of
https://github.com/lvgl/lvgl.git
synced 2024-11-24 02:03:53 +08:00
feat(lv_rb_t): add red black tree to lvgl (#4585)
This commit is contained in:
parent
6bc99b1d1f
commit
71da024e55
1
lvgl.h
1
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"
|
||||
|
||||
|
520
src/misc/lv_rb.c
Normal file
520
src/misc/lv_rb.c
Normal 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
78
src/misc/lv_rb.h
Normal 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*/
|
Loading…
Reference in New Issue
Block a user