1 /**
2  * @file lv_tree.c
3  * Tree.
4  * The nodes are dynamically allocated by the 'lv_mem' module,
5  */
6 
7 /*********************
8  *      INCLUDES
9  *********************/
10 #include "lv_tree.h"
11 #include "../stdlib/lv_mem.h"
12 #include "../stdlib/lv_string.h"
13 
14 #include "lv_assert.h"
15 
16 /*********************
17  *      DEFINES
18  *********************/
19 #define INIT_CHILDREN_CAP 4
20 
21 /**********************
22  *      TYPEDEFS
23  **********************/
24 
25 /**********************
26  *  STATIC PROTOTYPES
27  **********************/
28 
29 /**********************
30  *  STATIC VARIABLES
31  **********************/
32 
33 const lv_tree_class_t lv_tree_node_class = {
34     .base_class = NULL,
35     .instance_size = sizeof(lv_tree_node_t),
36     .constructor_cb = NULL,
37     .destructor_cb = NULL,
38 };
39 
40 /**********************
41  *      MACROS
42  **********************/
43 
44 /**********************
45  *   GLOBAL FUNCTIONS
46  **********************/
47 
_lv_tree_node_construct(const lv_tree_class_t * class_p,lv_tree_node_t * node)48 static void _lv_tree_node_construct(const lv_tree_class_t * class_p, lv_tree_node_t * node)
49 {
50     if(node->class_p->base_class) {
51         const lv_tree_class_t * original_class_p = node->class_p;
52 
53         node->class_p = node->class_p->base_class;
54 
55         _lv_tree_node_construct(class_p, node);
56 
57         node->class_p = original_class_p;
58     }
59 
60     if(node->class_p->constructor_cb) node->class_p->constructor_cb(class_p, node);
61 }
62 
_lv_tree_node_destruct(lv_tree_node_t * node)63 static void _lv_tree_node_destruct(lv_tree_node_t * node)
64 {
65     if(node->class_p->destructor_cb) node->class_p->destructor_cb(node->class_p, node);
66 
67     if(node->class_p->base_class) {
68         node->class_p = node->class_p->base_class;
69 
70         _lv_tree_node_destruct(node);
71     }
72 }
73 
get_instance_size(const lv_tree_class_t * class_p)74 static uint32_t get_instance_size(const lv_tree_class_t * class_p)
75 {
76     const lv_tree_class_t * base = class_p;
77     while(base && base->instance_size == 0)
78         base = base->base_class;
79 
80     return base->instance_size;
81 }
82 
_lv_tree_class_create_node(const lv_tree_class_t * class_p,lv_tree_node_t * parent)83 static lv_tree_node_t * _lv_tree_class_create_node(const lv_tree_class_t * class_p, lv_tree_node_t * parent)
84 {
85     uint32_t s = get_instance_size(class_p);
86     lv_tree_node_t * node = lv_malloc(s);
87     if(node == NULL) return NULL;
88     lv_memzero(node, s);
89     node->class_p = class_p;
90     node->parent = parent;
91     node->child_cap = INIT_CHILDREN_CAP;
92     node->children = lv_malloc(sizeof(lv_tree_node_t *) * node->child_cap);
93     if(parent != NULL) {
94         parent->child_cnt++;
95         if(parent->child_cnt == parent->child_cap) {
96             parent->child_cap <<= 1;
97             parent->children = lv_realloc(parent->children, sizeof(lv_tree_node_t *) * parent->child_cap);
98         }
99         parent->children[parent->child_cnt - 1] = node;
100     }
101     return node;
102 }
103 
lv_tree_node_create(const lv_tree_class_t * class_p,lv_tree_node_t * parent)104 lv_tree_node_t * lv_tree_node_create(const lv_tree_class_t * class_p, lv_tree_node_t * parent)
105 {
106     LV_ASSERT_NULL(class_p);
107     lv_tree_node_t * node = _lv_tree_class_create_node(class_p, parent);
108     LV_ASSERT_NULL(node);
109     _lv_tree_node_construct(node->class_p, node);
110     return node;
111 }
112 
_lv_tree_node_destructor_cb(const lv_tree_node_t * n,void * user_data)113 static bool _lv_tree_node_destructor_cb(const lv_tree_node_t * n, void * user_data)
114 {
115     LV_UNUSED(user_data);
116     if(n) {
117         lv_tree_node_t * node = (lv_tree_node_t *)n;
118         _lv_tree_node_destruct(node);
119         lv_free(node->children);
120         lv_free(node);
121     }
122     return true;
123 }
124 
lv_tree_node_delete(lv_tree_node_t * node)125 void lv_tree_node_delete(lv_tree_node_t * node)
126 {
127     if(node) {
128         if(node->parent) {
129             /* Remove from parent */
130             lv_tree_node_t * parent = node->parent;
131             for(uint32_t i = 0; i < parent->child_cnt; i++) {
132                 if(parent->children[i] == node) {
133                     parent->children[i] = NULL;
134                 }
135             }
136         }
137         lv_tree_walk(node, LV_TREE_WALK_POST_ORDER, _lv_tree_node_destructor_cb, NULL, NULL, NULL);
138     }
139 }
140 
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)141 bool lv_tree_walk(const lv_tree_node_t * node,
142                   lv_tree_walk_mode_t mode,
143                   lv_tree_traverse_cb_t cb,
144                   lv_tree_before_cb_t bcb,
145                   lv_tree_after_cb_t acb,
146                   void * user_data)
147 {
148     if(node && cb) {
149         if(mode == LV_TREE_WALK_PRE_ORDER) {
150             if(bcb && !bcb(node, user_data)) {
151                 return false;
152             }
153             if(!cb(node, user_data)) {
154                 return false;
155             }
156         }
157         for(uint32_t i = 0; i < node->child_cnt; i++) {
158             if(!lv_tree_walk(node->children[i], mode, cb, bcb, acb, user_data)) {
159                 return false;
160             }
161         }
162         if(mode == LV_TREE_WALK_PRE_ORDER) {
163             if(acb) {
164                 acb(node, user_data);
165             }
166         }
167 
168         if(mode == LV_TREE_WALK_POST_ORDER) {
169             if(bcb && !bcb(node, user_data)) {
170                 return false;
171             }
172             if(!cb(node, user_data)) {
173                 return false;
174             }
175             if(acb) {
176                 acb(node, user_data);
177             }
178             return true;
179         }
180         else {
181             return true;
182         }
183     }
184     else {
185         return true;
186     }
187 }
188