4 * @brief Bitwise trie tree implementation for sparse array.
8 * @copyright Copyright (c) 2022
12 #include <lunaix/ds/btrie.h>
13 #include <lunaix/mm/valloc.h>
14 #include <lunaix/spike.h>
16 enum btrie_query_mode {
22 #define remove_visit_flag(node) ((struct btrie_node*)(__ptr(node) & ~1))
25 __btrie_addchild(struct btrie* root,
26 struct btrie_node* parent, struct btrie_node* child)
28 if (unlikely(!parent->children)) {
29 parent->children = vcalloc(sizeof(parent), 1 << root->order);
32 parent->children_cnt++;
33 parent->children[child->index] = child;
36 static inline struct btrie_node*
37 __btrie_get_child(struct btrie_node* node, int index)
39 if (unlikely(!node || !node->children)) {
43 return remove_visit_flag(node->children[index]);
47 __btrie_child_visited(struct btrie_node* node, int index)
49 if (unlikely(!node || !node->children)) {
53 return !!(__ptr(node->children[index]) & 1);
57 __btrie_visit_child(struct btrie_node* node, int index)
59 if (unlikely(!node || !node->children)) {
64 = (struct btrie_node*)(__ptr(node->children[index]) | 1);
68 __btrie_unvisit_child(struct btrie_node* node, int index)
70 if (unlikely(!node || !node->children)) {
74 node->children[index] = remove_visit_flag(node->children[index]);
78 __btrie_free_node(struct btrie_node* node)
80 vfree_safe(node->children);
85 __full_node(struct btrie* root, struct btrie_node* node)
87 return node->children_cnt == 1 << root->order;
90 static inline struct btrie_node*
91 __btrie_create(struct btrie* root, struct btrie_node* parent, int index)
93 struct btrie_node* node;
95 node = vzalloc(sizeof(struct btrie_node));
97 node->parent = parent;
100 llist_append(&root->btrie_root->nodes, &node->nodes);
101 __btrie_addchild(root, parent, node);
107 static struct btrie_node*
108 __btrie_traversal(struct btrie* root,
109 unsigned long key, enum btrie_query_mode mode)
111 unsigned long lz, bitmask, i = 0;
112 struct btrie_node *subtree, *tree = root->btrie_root;
114 lz = !key ? 0 : (msbitl - clzl(key)) / root->order;
115 lz = lz * root->order;
116 bitmask = ((1 << root->order) - 1) << lz;
118 // Time complexity: O(log_2(log_2(N))) where N is the key to lookup
119 while (bitmask && tree) {
120 i = (key & bitmask) >> lz;
121 subtree = __btrie_get_child(tree, i);
123 if (!lz && mode == BTRIE_FIND_PARENT) {
127 if (!subtree && (mode != BTRIE_FIND)) {
128 tree = __btrie_create(root, tree, i);
134 bitmask = bitmask >> root->order;
141 #define check_partial(loc, start, end, mask) \
142 (((long)(start) - (long)mask - 1) <= (long)loc && loc < end)
144 static inline struct btrie_node*
145 __get_immediate_node(struct btrie* tree, struct btrie_node *root,
146 unsigned long start, unsigned long end, unsigned long loc)
150 struct btrie_node *node;
152 mask = (1UL << tree->order) - 1;
154 for (int i = 0; i <= mask; ++i, index = (index + 1) & mask)
156 loc = (loc & ~mask) + index;
157 node = __btrie_get_child(root, index);
159 if (loc < start || loc >= end) {
164 return __btrie_create(tree, root, index);
175 static struct btrie_node*
176 __btrie_find_free(struct btrie* tree, struct btrie_node *root,
177 unsigned long start, unsigned long end, unsigned long loc)
179 unsigned long mask, next_loc;
180 struct btrie_node *node, *found;
182 if (!root) return NULL;
184 mask = (1UL << tree->order) - 1;
186 __btrie_visit_child(root->parent, root->index);
188 if (!__full_node(tree, root)) {
189 found = __get_immediate_node(tree, root, start, end, loc);
190 if (found) goto done;
193 for (unsigned int i = 0; i <= mask; i++)
195 next_loc = ((loc & ~mask) + i) << tree->order;
197 if (!next_loc || !check_partial(next_loc, start, end, mask)) {
201 if (__btrie_child_visited(root, i)) {
205 node = __btrie_get_child(root, i);
206 node = node ?: __btrie_create(tree, root, i);
208 found = __btrie_find_free(tree, node, start, end, next_loc);
216 found = __btrie_find_free(tree, root->parent, start, end, loc + 1);
219 __btrie_unvisit_child(root->parent, root->index);
224 __btrie_alloc_slot(struct btrie* tree, struct btrie_node **slot,
225 unsigned long start, unsigned long end)
228 unsigned long result, mask;
229 struct btrie_node *found, *node;
232 mask = (1 << od) - 1;
233 found = tree->btrie_root;
236 if (!start && !__btrie_get_child(found, 0)) {
237 *slot = __btrie_create(tree, found, 0);
241 found = __btrie_traversal(tree, start, BTRIE_FIND_PARENT);
242 found = __btrie_find_free(tree, found, start, end, start);
247 result |= node->index << od;
253 return found ? result : -1UL;
257 btrie_init(struct btrie* btrie, unsigned int order)
259 btrie->btrie_root = __btrie_create(btrie, NULL, 0);
260 btrie->order = order;
262 llist_init_head(&btrie->btrie_root->nodes);
266 btrie_get(struct btrie* root, unsigned long index)
268 struct btrie_node* node;
270 node = __btrie_traversal(root, index, BTRIE_FIND);
279 btrie_set(struct btrie* root, unsigned long index, void* data)
281 struct btrie_node* node;
283 node = __btrie_traversal(root, index, BTRIE_INSERT);
288 __btrie_rm_recursive(struct btrie_node* node)
290 struct btrie_node* parent = node->parent;
296 parent->children[node->index] = NULL;
297 parent->children_cnt--;
298 __btrie_free_node(node);
300 if (!parent->children_cnt && !parent->data) {
301 __btrie_rm_recursive(parent);
306 btrie_map(struct btrie* root,
307 unsigned long start, unsigned long end, void* data)
309 struct btrie_node* node = NULL;
310 unsigned long alloced;
312 alloced = __btrie_alloc_slot(root, &node, start, end);
322 btrie_remove(struct btrie* root, unsigned long index)
325 struct btrie_node* node;
327 node = __btrie_traversal(root, index, BTRIE_FIND);
333 if (!node->children_cnt) {
336 __btrie_rm_recursive(node);
343 btrie_release(struct btrie* tree)
345 struct btrie_node *pos, *n;
346 llist_for_each(pos, n, &tree->btrie_root->nodes, nodes)
348 __btrie_free_node(pos);
351 __btrie_free_node(tree->btrie_root);