libclod
C library for interacting with NBTs, region files, LOD data and other things.
Loading...
Searching...
No Matches
tree.c
1#include "config.h"
2#include "debug.h"
4
5#define TYPE_NONE 0
6#define TYPE_LEAF 1
7#define TYPE_INTL 2
8
11typedef struct clod_tree_node {
12 unsigned char header[32];
13 char keys[];
14} node;
15
16static node *ptroff_get(const void *base, const unsigned char *data) {
17 const ptrdiff_t offset = (ptrdiff_t)(
18 (uint64_t)data[0] << 56 | (uint64_t)data[1] << 48 |
19 (uint64_t)data[2] << 40 | (uint64_t)data[3] << 32 |
20 (uint64_t)data[4] << 24 | (uint64_t)data[5] << 16 |
21 (uint64_t)data[6] << 8 | (uint64_t)data[7]);
22 if (offset == 0) return nullptr;
23 return (node*)((char*)base + offset - 1);
24}
25static void ptroff_set(const void *base, unsigned char *data, const node *ptr) {
26 uint64_t offset;
27 if (ptr) {
28 offset = (uint64_t)((char*)ptr - (char*)base) + 1;
29 } else {
30 offset = 0;
31 }
32 data[0] = (unsigned char)(offset >> 56); data[1] = (unsigned char)(offset >> 48);
33 data[2] = (unsigned char)(offset >> 40); data[3] = (unsigned char)(offset >> 32);
34 data[4] = (unsigned char)(offset >> 24); data[5] = (unsigned char)(offset >> 16);
35 data[6] = (unsigned char)(offset >> 8 ); data[7] = (unsigned char)offset;
36}
37static void copy(void *dst, const void *src, const size_t n) {
38 if (dst == src) return;
39
40 assert_fatal(CLOD_DEBUG, (char*)dst + n <= (char*)src || (char*)dst >= (char*)src + n,
41 "Copying key/value in tree has buffers that overlap. This implies serious implementation bug.");
42
43 for (size_t i = 0; i < n; i++) {
44 ((char*)dst)[i] = ((char*)src)[i];
45 }
46}
47
48#define KEY_SIZE (tree->key_size)
49#define VAL_SIZE (tree->val_size)
50#define INTL_CAPACITY ((tree->node_size - (int)sizeof(node) - 8) / (tree->key_size + 8))
51#define LEAF_CAPACITY ((tree->node_size - (int)sizeof(node)) / (tree->key_size + tree->val_size))
52
53#define checksum_get(node) (\
54 (uint32_t)(node)->header[0] << 24 |\
55 (uint32_t)(node)->header[1] << 16 |\
56 (uint32_t)(node)->header[2] << 8 |\
57 (uint32_t)(node)->header[3])
58
59#define checksum_set(node, val) (\
60 (node)->header[0] = (unsigned char)((val) >> 24),\
61 (node)->header[1] = (unsigned char)((val) >> 16),\
62 (node)->header[2] = (unsigned char)((val) >> 8),\
63 (node)->header[3] = (unsigned char)((val)))
64
65#define type_get(n) ((n)->header[4])
66#define type_set(n, val) ((n)->header[4] = (val))
67#define length_get(n) ((n)->header[6] << 8 | (n)->header[7])
68#define length_set(n, val) ((n)->header[6] = (unsigned char)((val) >> 8), (n)->header[7] = (unsigned char)(val))
69#define parent_get(n) (node*)ptroff_get(tree->root, (n)->header + 8)
70#define parent_set(n, val) ptroff_set(tree->root, (n)->header + 8, val)
71#define next_get(n) (node*)ptroff_get(tree->root, (n)->header + 16)
72#define next_set(n, val) ptroff_set(tree->root, (n)->header + 16, val)
73#define prev_get(n) (node*)ptroff_get(tree->root, (n)->header + 24)
74#define prev_set(n, val) ptroff_set(tree->root, (n)->header + 24, val)
75
76#define key_get(n, index) (\
77 assert_fatal(CLOD_DEBUG, index >= 0 && index < length_get(n),\
78 "Key index %i out of bounds for node %ptr with %i keys.",\
79 index, (void*)n, length_get(n)),\
80 ((n)->keys + (index) * KEY_SIZE))
81
82#define key_set(n, index, val) \
83 assert_fatal(CLOD_DEBUG, index >= 0 && index < (type_get(n) == TYPE_LEAF ? LEAF_CAPACITY : INTL_CAPACITY),\
84 "Key index %i out of bounds for node %ptr with maximum %i keys.",\
85 index, (void*)n, type_get(n) == TYPE_LEAF ? LEAF_CAPACITY : INTL_CAPACITY),\
86 copy(((n)->keys + (index) * KEY_SIZE), (val), KEY_SIZE);
87
88#define val_get(n, index) (\
89 assert_fatal(CLOD_DEBUG, index >= 0 && index < length_get(n),\
90 "Value index %i out of bounds for node %ptr with %i keys.",\
91 index, (void*)n, length_get(n)),\
92 ((n)->keys + LEAF_CAPACITY * KEY_SIZE + (index) * VAL_SIZE))
93
94#define val_set(n, index, val) \
95 assert_fatal(CLOD_DEBUG, index >= 0 && index < LEAF_CAPACITY,\
96 "Value index %i out of bounds for node %ptr with maximum %i values.",\
97 index, (void*)n, LEAF_CAPACITY),\
98 copy(((n)->keys + LEAF_CAPACITY * KEY_SIZE + (index) * VAL_SIZE), (val), VAL_SIZE);
99
100#define branch_get(n, index) (\
101 assert_fatal(CLOD_DEBUG, index >= 0 && index <= length_get(n),\
102 "Branch index %i out of bounds for node %ptr with %i keys.",\
103 index, (void*)n, length_get(n)),\
104 (node*)ptroff_get(tree->root, (unsigned char*)(n)->keys + INTL_CAPACITY * KEY_SIZE + (index) * 8))
105
106#define branch_set(n, index, val) \
107 assert_fatal(CLOD_DEBUG, index >= 0 && index <= INTL_CAPACITY,\
108 "Branch index %i out of bounds for node %ptr with maximum %i branches.",\
109 index, (void*)n, INTL_CAPACITY + 1),\
110 ptroff_set(tree->root, (unsigned char*)(n)->keys + INTL_CAPACITY * KEY_SIZE + (index) * 8, val)
111
112#if CLOD_DEBUG
113CLOD_API
114void clod_tree_debug_print(const struct clod_tree *tree, const node *n, const int depth) {
115 if (depth == 0)
116 clod_stream_format(clod_stderr, CLOD_STRING_C("\n==== Begin Tree Debug ====\n"));
117
118 if (depth > 8)
119 clod_stream_format(clod_stderr, CLOD_STRING_C("Tree is too deep to print. Skipping...\n"));
120
121 for (int i = 0; i < depth; i++)
122 clod_stream_format(clod_stderr, CLOD_STRING_C("\t"));
123
124 if (n == nullptr) {
125 clod_stream_format(clod_stderr, CLOD_STRING_C("NULL\n"));
126 return;
127 }
128
129 if (((uintptr_t)n & 0xFFFF700000000000ull) != 0x0000700000000000ull) {
130 clod_stream_format(clod_stderr, CLOD_STRING_C("Node %ptr is not a valid node!\n"), (void*)n);
131 return;
132 }
133
134 if (type_get(n) == TYPE_LEAF) {
135 clod_stream_format(clod_stderr, CLOD_STRING_C("Leaf %ptr (Parent: %ptr, Next: %ptr, Prev: %ptr, Keys: %i)\n"),
136 (void*)n, (void*)parent_get(n), (void*)next_get(n), (void*)prev_get(n), length_get(n));
137 if (length_get(n)) {
138 for (int i = 0; i <= depth; i++)
139 clod_stream_format(clod_stderr, CLOD_STRING_C("\t"));
140 for (int i = 0; i < length_get(n); i++) {
141 clod_stream_format(clod_stderr, CLOD_STRING_C("| [%u]: %i -> %i "), i, *(int*)key_get(n, i), *(int*)val_get(n, i));
142 }
143 clod_stream_format(clod_stderr, CLOD_STRING_C("|\n"));
144 }
145 } else {
146 clod_stream_format(clod_stderr, CLOD_STRING_C("Intl %ptr (Parent: %ptr, Keys: %i)\n"),
147 (void*)n, (void*)parent_get(n), length_get(n));
148
149 for (int i = 0; i <= depth; i++)
150 clod_stream_format(clod_stderr, CLOD_STRING_C("\t"));
151
152 for (int i = 0; i < length_get(n); i++) {
153 clod_stream_format(clod_stderr, CLOD_STRING_C("| Branch: %ptr | Key: %i "), branch_get(n, i), *(int*)key_get(n, i));
154 }
155 clod_stream_format(clod_stderr, CLOD_STRING_C("| Branch: %ptr |\n"), branch_get(n, length_get(n)));
156
157
158 for (int i = 0; i < length_get(n); i++) {
159 clod_tree_debug_print(tree, branch_get(n, i), depth + 1);
160
161 for (int k = 0; k < depth; k++)
162 clod_stream_format(clod_stderr, CLOD_STRING_C("\t"));
163 clod_stream_format(clod_stderr, CLOD_STRING_C("Key: %i\n"), *(int*)key_get(n, i));
164 }
165
166 clod_tree_debug_print(tree, branch_get(n, length_get(n)), depth + 1);
167 }
168
169 if (depth == 0)
170 clod_stream_format(clod_stderr, CLOD_STRING_C("==== End Tree Debug ====\n\n"));
171}
172#endif
173
176static bool search(const struct clod_tree *tree, const node *n, const void *key, int *index) {
177 int l = 0, h = length_get(n);
178 while (l < h) {
179 const int m = (l + h) / 2;
180 const int cmp = tree->compare(key_get(n, m), key, tree->compare_user);
181 if (cmp < 0) {
182 l = m + 1;
183 } else if (cmp > 0) {
184 h = m;
185 } else {
186 *index = m;
187 return true;
188 }
189 }
190
191 *index = l;
192 return false;
193}
194
196static node *parent_branch_get(const struct clod_tree *tree, const node *n, int *parent_index) {
197 node *parent = parent_get(n);
198 if (!parent) {
199 return nullptr;
200 }
201
202 for (int i = 0; i <= length_get(parent); i++) {
203 if (branch_get(parent, i) == n) {
204 if (parent_index) *parent_index = i;
205 return parent;
206 }
207 }
208
209 assert_fatal(CLOD_DEBUG, false, "Parent of %ptr does not contain it! Invalid tree.", (void*)n);
210}
211
213static void leaf_insert(const struct clod_tree *tree, node *n, int index, const void *key, const void *val) {
214 const int len = length_get(n);
215 assert_fatal(CLOD_DEBUG, index <= len,
216 "Index %i out of bounds for inserting into node %ptr with %i keys.",
217 index, (void*)n, len);
218
219 for (int i = len; i > index; i--) key_set(n, i, key_get(n, i - 1));
220 for (int i = len; i > index; i--) val_set(n, i, val_get(n, i - 1));
221
222 length_set(n, len + 1);
223 key_set(n, index, key);
224 val_set(n, index, val);
225
226 if (index != len) {
227 return;
228 }
229
230 node *parent = parent_branch_get(tree, n, &index);
231 while (parent && index == length_get(parent)) {
232 parent = parent_branch_get(tree, parent, &index);
233 }
234
235 if (parent) {
236 key_set(parent, index, key_get(n, len));
237 }
238}
239
241static void intl_insert_left(const struct clod_tree *tree, node *n, const int index, const void *key, node *branch) {
242 for (int i = length_get(n) + 1; i > index; i--) branch_set(n, i, branch_get(n, i - 1));
243 for (int i = length_get(n); i > index; i--) key_set(n, i, key_get(n, i - 1));
244
245 length_set(n, length_get(n) + 1);
246 key_set(n, index, key);
247 branch_set(n, index, branch);
248 parent_set(branch, n);
249}
250
252static void intl_insert_right(const struct clod_tree *tree, node *n, const int index, const void *key, node *branch) {
253 for (int i = length_get(n) + 1; i > index + 1; i--) branch_set(n, i, branch_get(n, i - 1));
254 for (int i = length_get(n); i > index; i--) key_set(n, i, key_get(n, i - 1));
255
256 length_set(n, length_get(n) + 1);
257 key_set(n, index, key);
258 branch_set(n, index + 1, branch);
259 parent_set(branch, n);
260}
261
264static void leaf_remove(const struct clod_tree *tree, node *const n, int index) {
265 const int len = length_get(n);
266 for (int i = index; i < len - 1; i++) val_set(n, i, val_get(n, i + 1));
267 for (int i = index; i < len - 1; i++) key_set(n, i, key_get(n, i + 1));
268 length_set(n, len - 1);
269
270 if (index != len - 1) {
271 return;
272 }
273
274 node *parent = parent_branch_get(tree, n, &index);
275 while (parent && index == length_get(parent)) {
276 parent = parent_branch_get(tree, parent, &index);
277 }
278
279 if (parent) {
280 key_set(parent, index, key_get(n, len - 2));
281 }
282}
283
285static void intl_remove_left(const struct clod_tree *tree, node *const n, const int index) {
286 for (int i = index; i < length_get(n); i++) branch_set(n, i, branch_get(n, i + 1));
287 for (int i = index; i < length_get(n) - 1; i++) key_set(n, i, key_get(n, i + 1));
288 length_set(n, length_get(n) - 1);
289}
290
292static void intl_remove_right(const struct clod_tree *tree, node *const n, const int index) {
293 for (int i = index + 1; i < length_get(n); i++) branch_set(n, i, branch_get(n, i + 1));
294 for (int i = index; i < length_get(n) - 1; i++) key_set(n, i, key_get(n, i + 1));
295 length_set(n, length_get(n) - 1);
296}
297
300static int leaf_split(const struct clod_tree *tree, const node *n, node *left, node *right) {
301 const int keys = length_get(n);
302 const int left_size = (keys + 1) / 2;
303 const int right_size = keys - left_size;
304
305 assert_fatal(CLOD_DEBUG, keys >= LEAF_CAPACITY / 2,
306 "Refusing to split leaf node %ptr with %i keys. Nodes may never be less than half full.",
307 (void*)n, keys);
308
309 int parent_index;
310 node *const parent = parent_branch_get(tree, n, &parent_index);
311 assert_fatal(CLOD_DEBUG, !parent || length_get(parent) < INTL_CAPACITY,
312 "Cannot split leaf node %ptr when its parent %ptr has %i out of %i keys occupied.",
313 (void*)n, (void*)parent, length_get(parent), INTL_CAPACITY);
314
315 type_set(left, TYPE_LEAF);
316 type_set(right, TYPE_LEAF);
317 parent_set(left, parent);
318 parent_set(right, parent);
319 const node *n_next = next_get(n), *n_prev = prev_get(n);
320 next_set(left, right);
321 next_set(right, n_next);
322 prev_set(left, n_prev);
323 prev_set(right, left);
324
325 if (parent) {
326 branch_set(parent, parent_index, left);
327 intl_insert_right(tree, parent, parent_index, key_get(n, left_size - 1), right);
328 }
329
330 if (n == left) {
331 for (int i = 0; i < right_size; i++) key_set(right, i, key_get(n, i + left_size));
332 for (int i = 0; i < right_size; i++) val_set(right, i, val_get(n, i + left_size));
333 } else {
334 for (int i = 0; i < left_size; i++) key_set(left, i, key_get(n, i));
335 for (int i = 0; i < right_size; i++) key_set(right, i, key_get(n, i + left_size));
336 for (int i = 0; i < left_size; i++) val_set(left, i, val_get(n, i));
337 for (int i = 0; i < right_size; i++) val_set(right, i, val_get(n, i + left_size));
338 }
339
340 length_set(left, left_size);
341 length_set(right, right_size);
342 return left_size - 1;
343}
344
347static int intl_split(const struct clod_tree *tree, const node *n, node *left, node *right) {
348 const int keys = length_get(n);
349 const int left_size = keys / 2;
350 const int right_size = keys - left_size - 1;
351
352 assert_fatal(CLOD_DEBUG, keys >= INTL_CAPACITY / 2,
353 "Refusing to split internal node %ptr with %i keys. Nodes may never be less than half full.",
354 (void*)n, keys);
355
356 int parent_index;
357 node *const parent = parent_branch_get(tree, n, &parent_index);
358 assert_fatal(CLOD_DEBUG, !parent || length_get(parent) < INTL_CAPACITY,
359 "Cannot split leaf node when its parent %ptr has no space.", (void*)parent);
360
361 type_set(left, TYPE_INTL);
362 type_set(right, TYPE_INTL);
363 parent_set(left, parent);
364 parent_set(right, parent);
365 if (parent) {
366 branch_set(parent, parent_index, left);
367 intl_insert_right(tree, parent, parent_index, key_get(n, left_size), right);
368 }
369
370 if (n == left) {
371 for (int i = 0; i < right_size; i++) key_set(right, i, key_get(n, i + left_size + 1));
372 for (int i = 0; i <= right_size; i++) branch_set(right, i, branch_get(n, i + left_size + 1));
373 } else {
374 for (int i = 0; i < left_size; i++) key_set(left, i, key_get(n, i));
375 for (int i = 0; i < right_size; i++) key_set(right, i, key_get(n, i + left_size + 1));
376 for (int i = 0; i <= left_size; i++) branch_set(left, i, branch_get(n, i));
377 for (int i = 0; i <= right_size; i++) branch_set(right, i, branch_get(n, i + left_size + 1));
378 }
379
380 length_set(left, left_size);
381 length_set(right, right_size);
382 for (int i = 0; i <= left_size; i++) parent_set(branch_get(left, i), left);
383 for (int i = 0; i <= right_size; i++) parent_set(branch_get(right, i), right);
384
385 return left_size;
386}
387
389static void leaf_merge(const struct clod_tree *tree, node *n, const node *left, const node *right) {
390 const int left_len = length_get(left);
391 const int right_len = length_get(right);
392
393 assert_fatal(CLOD_DEBUG, left_len + right_len <= LEAF_CAPACITY,
394 "Cannot merge leaf nodes %ptr and %ptr because their combined elements %i + %i = %i is larger than the maximum %i.",
395 (void*)left, (void*)right, left_len, right_len, left_len + right_len, LEAF_CAPACITY);
396
397 int parent_index;
398 node *parent = parent_branch_get(tree, left, &parent_index);
399 assert_fatal(CLOD_DEBUG, parent == parent_get(right),
400 "Cannot merge leaf nodes %ptr and %ptr that belong to different parents %ptr and %ptr.",
401 (void*)left, (void*)right, (void*)parent_get(left), (void*)parent_get(right));
402
403 type_set(n, TYPE_LEAF);
404 length_set(n, left_len + right_len);
405 parent_set(n, parent);
406 next_set(n, next_get(right));
407 prev_set(n, prev_get(left));
408
409 intl_remove_right(tree, parent, parent_index);
410 branch_set(parent, parent_index, n);
411
412 if (n == left) {
413 for (int i = 0; i < right_len; i++) key_set(n, i + left_len, key_get(right, i));
414 for (int i = 0; i < right_len; i++) val_set(n, i + left_len, val_get(right, i));
415 } else {
416 for (int i = right_len - 1; i >= 0; i--) key_set(n, i + left_len, key_get(right, i));
417 for (int i = 0; i < left_len; i++) key_set(n, i, key_get(left, i));
418 for (int i = right_len - 1; i >= 0; i--) val_set(n, i + left_len, val_get(right, i));
419 for (int i = 0; i < left_len; i++) val_set(n, i, val_get(left, i));
420 }
421}
422
425static int intl_merge(const struct clod_tree *tree, node *n, const node *left, const node *right) {
426 const int left_len = length_get(left);
427 const int right_len = length_get(right);
428
429 assert_fatal(CLOD_DEBUG, left_len + right_len <= INTL_CAPACITY,
430 "Cannot merge internal nodes %ptr and %ptr because their combined elements %i + %i = %i is larger than the maximum %i.",
431 (void*)left, (void*)right, left_len, right_len, left_len + right_len, INTL_CAPACITY);
432
433 int parent_index;
434 node *parent = parent_branch_get(tree, left, &parent_index);
435 assert_fatal(CLOD_DEBUG, parent == parent_get(right),
436 "Cannot merge internal nodes %ptr and %ptr that belong to different parents %ptr and %ptr.",
437 (void*)left, (void*)right, (void*)parent_get(left), (void*)parent_get(right));
438
439 type_set(n, TYPE_INTL);
440 length_set(n, left_len + right_len + 1);
441 parent_set(n, parent);
442
443 intl_remove_right(tree, parent, parent_index);
444 branch_set(parent, parent_index, n);
445
446 if (n == left) {
447 for (int i = 0; i < right_len; i++) key_set(n, i + left_len + 1, key_get(right, i));
448 for (int i = 0; i <= right_len; i++) branch_set(n, i + left_len + 1, branch_get(right, i));
449 } else {
450 for (int i = right_len - 1; i >= 0; i--) key_set(n, i + left_len + 1, key_get(right, i));
451 for (int i = 0; i < left_len; i++) key_set(n, i, key_get(left, i));
452 for (int i = right_len - 1; i >= 0; i--) branch_set(n, i + left_len + 1, branch_get(right, i));
453 for (int i = 0; i <= left_len; i++) branch_set(n, i, branch_get(left, i));
454 }
455
456 for (int i = 0; i <= length_get(n); i++) parent_set(branch_get(n, i), n);
457
458 return left_len;
459}
460
462static void balance(const struct clod_tree *tree, node *n) {
463 int index;
464 node *parent = parent_branch_get(tree, n, &index);
465 if (!parent) {
466 debug(CLOD_DEBUG, "Cannot balance root node.");
467 return;
468 }
469
470 node *left, *right;
471 if (index == 0) {
472 left = n;
473 right = branch_get(parent, 1);
474 } else {
475 left = branch_get(parent, index - 1);
476 right = n;
477 }
478 const int left_len = length_get(left), right_len = length_get(right);
479
480 if (type_get(n) == TYPE_LEAF) {
481 if (left_len + right_len <= LEAF_CAPACITY) {
482
483 leaf_merge(tree, left, left, right);
484 tree->allocator.free(right, tree->allocator.self);
485
486 } else if (left_len < right_len) {
487
488 leaf_insert(tree, left, left_len, key_get(right, 0), val_get(right, 0));
489 leaf_remove(tree, right, 0);
490
491 } else if (right_len < left_len) {
492
493 leaf_insert(tree, right, 0, key_get(left, left_len - 1), val_get(left, left_len - 1));
494 leaf_remove(tree, left, left_len - 1);
495
496 }
497 } else if (type_get(n) == TYPE_INTL) {
498
499 if (left_len + right_len <= INTL_CAPACITY) {
500
501 intl_merge(tree, left, left, right);
502 tree->allocator.free(right, tree->allocator.self);
503
504 } else if (left_len < right_len) {
505
506 intl_insert_right(tree, left, left_len, key_get(parent, index), branch_get(right, 0));
507 key_set(parent, index, key_get(right, 0));
508 intl_remove_left(tree, right, 0);
509
510 } else if (right_len < left_len) {
511
512 intl_insert_left(tree, right, 0, key_get(parent, index), branch_get(left, left_len - 1));
513 key_set(parent, index, key_get(left, left_len - 1));
514 intl_remove_right(tree, left, left_len - 1);
515
516 }
517
518 }
519}
520
521bool clod_tree_create(struct clod_tree *tree) {
522 if (tree->key_size == 0) {
523 debug(CLOD_DEBUG, "Tree key size cannot be zero.");
524 return false;
525 }
526
527 const size_t min_node_size = sizeof(node) + tree->key_size + (tree->val_size < 16 ? 16 : tree->val_size);
528 if (tree->node_size < min_node_size) {
529 debug(CLOD_DEBUG, "Tree node size of %i is too small. Need %i for a key and value size of %i and %i.",
530 tree->node_size, min_node_size, tree->key_size, tree->val_size);
531 return false;
532 }
533
534 if (!tree->compare) {
535 debug(CLOD_DEBUG, "Tree compare function cannot be null.");
536 return false;
537 }
538
539 if (!tree->root) {
540 if (!tree->allocator.allocate || !tree->allocator.free) {
541 debug(CLOD_DEBUG, "Tree allocator methods cannot be null.");
542 return false;
543 }
544
545 tree->root = tree->allocator.allocate(tree->node_size, tree->allocator.self);
546 if (!tree->root) {
547 debug(CLOD_DEBUG, "Failed to allocate root node.");
548 return false;
549 }
550
551 type_set(tree->root, TYPE_LEAF);
552 length_set(tree->root, 0);
553 parent_set(tree->root, nullptr);
554 }
555
556 return true;
557}
558
559void clod_tree_destroy(struct clod_tree *tree) {
560 if (!tree->root) return;
561 node *n = tree->root;
562 while (n) {
563 const int len = length_get(n);
564
565 if (
566 type_get(n) == TYPE_LEAF ||
567 (length_get(n) == 0 && branch_get(n, 0) == nullptr)
568 ) {
569 node *tmp = parent_get(n);
570 tree->allocator.free(n, tree->allocator.self);
571 n = tmp;
572 continue;
573 }
574
575 node *next = branch_get(n, len);
576 branch_set(n, len, nullptr);
577 if (len > 0) {
578 length_set(n, len - 1);
579 }
580 n = next;
581 }
582
583 tree->root = nullptr;
584}
585
586bool clod_tree_add(const struct clod_tree *tree, const void *key, const void *val, void *key_out, void *val_out) {
587 node *n = tree->root;
588 int index;
589
590 while (type_get(n) == TYPE_INTL) {
591 search(tree, n, key, &index);
592 n = branch_get(n, index);
593 }
594
595 if (search(tree, n, key, &index)) {
596 if (key_out) copy(key_out, key_get(n, index), tree->key_size);
597 if (val_out) copy(val_out, val_get(n, index), tree->val_size);
598 return false;
599 }
600
601 if (length_get(n) < LEAF_CAPACITY) {
602 leaf_insert(tree, n, index, key, val);
603 return true;
604 }
605
606 while (parent_get(n) && length_get(parent_get(n)) >= INTL_CAPACITY) {
607 int parent_index;
608 node *parent = parent_branch_get(tree, n, &parent_index);
609
610 if (parent_index > 0 && length_get(branch_get(parent, parent_index - 1)) < INTL_CAPACITY) {
611 node *left = branch_get(parent, parent_index - 1);
612 intl_insert_right(tree, left, length_get(left), key_get(parent, parent_index - 1), branch_get(n, 0));
613 key_set(parent, parent_index - 1, key_get(n, 0));
614 intl_remove_left(tree, n, 0);
615
616 search(tree, parent, key, &index);
617 n = branch_get(parent, index);
618 search(tree, n, key, &index);
619 n = branch_get(n, index);
620 break;
621 }
622
623 if (parent_index < length_get(parent) - 1 && length_get(branch_get(parent, parent_index + 1)) < INTL_CAPACITY) {
624 node *right = branch_get(parent, parent_index + 1);
625 intl_insert_left(tree, right, 0, key_get(parent, parent_index), branch_get(n, length_get(n)));
626 key_set(parent, parent_index, key_get(n, length_get(n) - 1));
627 intl_remove_right(tree, n, length_get(n) - 1);
628
629 search(tree, parent, key, &index);
630 n = branch_get(parent, index);
631 search(tree, n, key, &index);
632 n = branch_get(n, index);
633 break;
634 }
635
636 n = parent_get(n);
637 }
638
639 if (parent_get(n) == nullptr) {
640 node *left = tree->allocator.allocate(tree->node_size, tree->allocator.self);
641 node *right = tree->allocator.allocate(tree->node_size, tree->allocator.self);
642 if (!left || !right) {
643 debug(CLOD_DEBUG, "Failed to allocate new internal node.");
644 if (left) tree->allocator.free(left, tree->allocator.self);
645 if (right) tree->allocator.free(right, tree->allocator.self);
646 return false;
647 }
648
649 if (type_get(n) == TYPE_LEAF) {
650 const int split = leaf_split(tree, n, left, right);
651
652 type_set(n, TYPE_INTL);
653 key_set(n, 0, key_get(n, split));
654 length_set(n, 1);
655 branch_set(n, 0, left);
656 branch_set(n, 1, right);
657 parent_set(left, n);
658 parent_set(right, n);
659
660 search(tree, n, key, &index);
661 n = branch_get(n, index);
662 search(tree, n, key, &index);
663 leaf_insert(tree, n, index, key, val);
664 return true;
665 }
666
667 if (type_get(n) == TYPE_INTL) {
668 const int split = intl_split(tree, n, left, right);
669
670 type_set(n, TYPE_INTL);
671 key_set(n, 0, key_get(n, split));
672 length_set(n, 1);
673 branch_set(n, 0, left);
674 branch_set(n, 1, right);
675 parent_set(left, n);
676 parent_set(right, n);
677
678 search(tree, n, key, &index);
679 n = branch_get(n, index);
680 search(tree, n, key, &index);
681 n = branch_get(n, index);
682 }
683 }
684
685 while (type_get(n) == TYPE_INTL) {
686 node *new = tree->allocator.allocate(tree->node_size, tree->allocator.self);
687 if (!new) {
688 debug(CLOD_DEBUG, "Failed to allocate new internal node.");
689 return false;
690 }
691
692 search(tree, n, key, &index);
693 const int split = intl_split(tree, n, n, new);
694 if (index < split) {
695 n = branch_get(n, index);
696 } else {
697 n = branch_get(new, index - split - 1);
698 }
699 }
700
701 node *new = tree->allocator.allocate(tree->node_size, tree->allocator.self);
702 if (!new) {
703 debug(CLOD_DEBUG, "Failed to allocate new leaf node.");
704 return false;
705 }
706
707 search(tree, n, key, &index);
708 const int split = leaf_split(tree, n, n, new);
709 if (index >= split) {
710 n = new;
711 index = index - split - 1;
712 }
713
714 leaf_insert(tree, n, index, key, val);
715 return true;
716}
717
718bool clod_tree_get(const struct clod_tree *tree, const void *key, void *key_out, void *val_out) {
719 const node *n = tree->root;
720 int index;
721 while (type_get(n) == TYPE_INTL) {
722 search(tree, n, key, &index);
723 n = branch_get(n, index);
724 }
725
726 if (search(tree, n, key, &index)) {
727 if (key_out) copy(key_out, key_get(n, index), tree->key_size);
728 if (val_out) copy(val_out, val_get(n, index), tree->val_size);
729 return true;
730 }
731 return false;
732}
733
734bool clod_tree_del(const struct clod_tree *tree, const void *key, void *key_out, void *val_out) {
735 node *n = tree->root;
736 int index;
737 while (type_get(n) == TYPE_INTL) {
738 search(tree, n, key, &index);
739 n = branch_get(n, index);
740 }
741
742 if (!search(tree, n, key, &index)) {
743 return false;
744 }
745
746 if (key_out) copy(key_out, key_get(n, index), tree->key_size);
747 if (val_out) copy(val_out, val_get(n, index), tree->val_size);
748 leaf_remove(tree, n, index);
749
750 while (n && length_get(n) < LEAF_CAPACITY / 2) {
751 balance(tree, n);
752 n = parent_get(n);
753 }
754
755 return true;
756}
#define CLOD_STRING_C(cstr)
String literal constant.
Definition string.h:43
void * self
Value passed to invocations of allocate and free.
Definition memory.h:18
void(* free)(void *ptr, void *self)
Definition memory.h:33
void *(* allocate)(size_t size, void *self)
Definition memory.h:26
int(* compare)(const void *key1, const void *key2, void *user)
Comparison function.
Definition tree.h:43
unsigned char val_size
Size of values in the tree.
Definition tree.h:31
unsigned short node_size
Size of each node in the tree.
Definition tree.h:37
void * compare_user
User variable passed to invocations of compare.
Definition tree.h:40
unsigned char key_size
Size of keys in the tree.
Definition tree.h:28
struct clod_tree_node * root
Pointer to the root node.
Definition tree.h:25
clod_allocator allocator
Definition tree.h:47
bool clod_tree_create(struct clod_tree *tree)
Definition tree.c:521
bool clod_tree_del(const struct clod_tree *tree, const void *key, void *key_out, void *val_out)
Definition tree.c:734
void clod_tree_destroy(struct clod_tree *tree)
Definition tree.c:559
bool clod_tree_get(const struct clod_tree *tree, const void *key, void *key_out, void *val_out)
Definition tree.c:718
bool clod_tree_add(const struct clod_tree *tree, const void *key, const void *val, void *key_out, void *val_out)
Definition tree.c:586