190 lines
4.9 KiB
C
190 lines
4.9 KiB
C
/**
|
|
* @file lv_tree.c
|
|
* Tree.
|
|
* The nodes are dynamically allocated by the 'lv_mem' module,
|
|
*/
|
|
|
|
/*********************
|
|
* INCLUDES
|
|
*********************/
|
|
#include "lv_tree.h"
|
|
#include "../stdlib/lv_mem.h"
|
|
#include "../stdlib/lv_string.h"
|
|
|
|
#include "lv_assert.h"
|
|
|
|
/*********************
|
|
* DEFINES
|
|
*********************/
|
|
#define INIT_CHILDREN_CAP 4
|
|
|
|
/**********************
|
|
* TYPEDEFS
|
|
**********************/
|
|
|
|
/**********************
|
|
* STATIC PROTOTYPES
|
|
**********************/
|
|
|
|
/**********************
|
|
* STATIC VARIABLES
|
|
**********************/
|
|
|
|
const lv_tree_class_t lv_tree_node_class = {
|
|
.base_class = NULL,
|
|
.instance_size = sizeof(lv_tree_node_t),
|
|
.constructor_cb = NULL,
|
|
.destructor_cb = NULL,
|
|
};
|
|
|
|
/**********************
|
|
* MACROS
|
|
**********************/
|
|
|
|
/**********************
|
|
* GLOBAL FUNCTIONS
|
|
**********************/
|
|
|
|
static void _lv_tree_node_construct(const lv_tree_class_t * class_p, lv_tree_node_t * node)
|
|
{
|
|
if(node->class_p->base_class) {
|
|
const lv_tree_class_t * original_class_p = node->class_p;
|
|
|
|
node->class_p = node->class_p->base_class;
|
|
|
|
_lv_tree_node_construct(class_p, node);
|
|
|
|
node->class_p = original_class_p;
|
|
}
|
|
|
|
if(node->class_p->constructor_cb) node->class_p->constructor_cb(class_p, node);
|
|
}
|
|
|
|
static void _lv_tree_node_destruct(lv_tree_node_t * node)
|
|
{
|
|
if(node->class_p->destructor_cb) node->class_p->destructor_cb(node->class_p, node);
|
|
|
|
if(node->class_p->base_class) {
|
|
node->class_p = node->class_p->base_class;
|
|
|
|
_lv_tree_node_destruct(node);
|
|
}
|
|
}
|
|
|
|
static uint32_t get_instance_size(const lv_tree_class_t * class_p)
|
|
{
|
|
const lv_tree_class_t * base = class_p;
|
|
while(base && base->instance_size == 0)
|
|
base = base->base_class;
|
|
|
|
LV_ASSERT_NULL(base);
|
|
|
|
return base->instance_size;
|
|
}
|
|
|
|
static lv_tree_node_t * _lv_tree_class_create_node(const lv_tree_class_t * class_p, lv_tree_node_t * parent)
|
|
{
|
|
uint32_t s = get_instance_size(class_p);
|
|
lv_tree_node_t * node = lv_malloc(s);
|
|
if(node == NULL) return NULL;
|
|
lv_memzero(node, s);
|
|
node->class_p = class_p;
|
|
node->parent = parent;
|
|
node->child_cap = INIT_CHILDREN_CAP;
|
|
node->children = lv_malloc(sizeof(lv_tree_node_t *) * node->child_cap);
|
|
if(parent != NULL) {
|
|
parent->child_cnt++;
|
|
if(parent->child_cnt == parent->child_cap) {
|
|
parent->child_cap <<= 1;
|
|
parent->children = lv_realloc(parent->children, sizeof(lv_tree_node_t *) * parent->child_cap);
|
|
}
|
|
parent->children[parent->child_cnt - 1] = node;
|
|
}
|
|
return node;
|
|
}
|
|
|
|
lv_tree_node_t * lv_tree_node_create(const lv_tree_class_t * class_p, lv_tree_node_t * parent)
|
|
{
|
|
LV_ASSERT_NULL(class_p);
|
|
lv_tree_node_t * node = _lv_tree_class_create_node(class_p, parent);
|
|
LV_ASSERT_NULL(node);
|
|
_lv_tree_node_construct(node->class_p, node);
|
|
return node;
|
|
}
|
|
|
|
static bool _lv_tree_node_destructor_cb(const lv_tree_node_t * n, void * user_data)
|
|
{
|
|
LV_UNUSED(user_data);
|
|
if(n) {
|
|
lv_tree_node_t * node = (lv_tree_node_t *)n;
|
|
_lv_tree_node_destruct(node);
|
|
lv_free(node->children);
|
|
lv_free(node);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void lv_tree_node_delete(lv_tree_node_t * node)
|
|
{
|
|
if(node) {
|
|
if(node->parent) {
|
|
/* Remove from parent */
|
|
lv_tree_node_t * parent = node->parent;
|
|
for(uint32_t i = 0; i < parent->child_cnt; i++) {
|
|
if(parent->children[i] == node) {
|
|
parent->children[i] = NULL;
|
|
}
|
|
}
|
|
}
|
|
lv_tree_walk(node, LV_TREE_WALK_POST_ORDER, _lv_tree_node_destructor_cb, NULL, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
bool lv_tree_walk(const lv_tree_node_t * node,
|
|
lv_tree_walk_mode_t mode,
|
|
lv_tree_traverse_cb_t cb,
|
|
lv_tree_before_cb_t bcb,
|
|
lv_tree_after_cb_t acb,
|
|
void * user_data)
|
|
{
|
|
if(node && cb) {
|
|
if(mode == LV_TREE_WALK_PRE_ORDER) {
|
|
if(bcb && !bcb(node, user_data)) {
|
|
return false;
|
|
}
|
|
if(!cb(node, user_data)) {
|
|
return false;
|
|
}
|
|
}
|
|
for(uint32_t i = 0; i < node->child_cnt; i++) {
|
|
if(!lv_tree_walk(node->children[i], mode, cb, bcb, acb, user_data)) {
|
|
return false;
|
|
}
|
|
}
|
|
if(mode == LV_TREE_WALK_PRE_ORDER) {
|
|
if(acb) {
|
|
acb(node, user_data);
|
|
}
|
|
}
|
|
|
|
if(mode == LV_TREE_WALK_POST_ORDER) {
|
|
if(bcb && !bcb(node, user_data)) {
|
|
return false;
|
|
}
|
|
if(!cb(node, user_data)) {
|
|
return false;
|
|
}
|
|
if(acb) {
|
|
acb(node, user_data);
|
|
}
|
|
return true;
|
|
}
|
|
else {
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
return true;
|
|
}
|
|
}
|