annotate ext/sord/src/zix/btree.c @ 245:b32c68f08ec0

Use local sord/serd build
author Chris Cannam <cannam@all-day-breakfast.com>
date Thu, 15 Jun 2017 09:38:52 +0100
parents c5cdc9e6a4bf
children
rev   line source
cannam@226 1 /*
cannam@226 2 Copyright 2011-2014 David Robillard <http://drobilla.net>
cannam@226 3
cannam@226 4 Permission to use, copy, modify, and/or distribute this software for any
cannam@226 5 purpose with or without fee is hereby granted, provided that the above
cannam@226 6 copyright notice and this permission notice appear in all copies.
cannam@226 7
cannam@226 8 THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
cannam@226 9 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
cannam@226 10 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
cannam@226 11 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
cannam@226 12 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
cannam@226 13 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
cannam@226 14 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
cannam@226 15 */
cannam@226 16
cannam@226 17 #include <assert.h>
cannam@226 18 #include <stdint.h>
cannam@226 19 #include <stdio.h>
cannam@226 20 #include <stdlib.h>
cannam@226 21 #include <string.h>
cannam@226 22
cannam@245 23 #include "btree.h"
cannam@226 24
cannam@226 25 // #define ZIX_BTREE_DEBUG 1
cannam@226 26
cannam@226 27 #define ZIX_BTREE_PAGE_SIZE 4096
cannam@226 28 #define ZIX_BTREE_NODE_SPACE (ZIX_BTREE_PAGE_SIZE - 2 * sizeof(uint16_t))
cannam@226 29 #define ZIX_BTREE_LEAF_VALS ((ZIX_BTREE_NODE_SPACE / sizeof(void*)) - 1)
cannam@226 30 #define ZIX_BTREE_INODE_VALS (ZIX_BTREE_LEAF_VALS / 2)
cannam@226 31
cannam@226 32 struct ZixBTreeImpl {
cannam@226 33 ZixBTreeNode* root;
cannam@226 34 ZixDestroyFunc destroy;
cannam@226 35 ZixComparator cmp;
cannam@226 36 void* cmp_data;
cannam@226 37 size_t size;
cannam@226 38 unsigned height; ///< Number of levels, i.e. root only has height 1
cannam@226 39 };
cannam@226 40
cannam@226 41 struct ZixBTreeNodeImpl {
cannam@226 42 uint16_t is_leaf;
cannam@226 43 uint16_t n_vals;
cannam@226 44 // On 64-bit we rely on some padding here to get page-sized nodes
cannam@226 45 void* vals[ZIX_BTREE_INODE_VALS]; // ZIX_BTREE_LEAF_VALS for leaves
cannam@226 46 ZixBTreeNode* children[ZIX_BTREE_INODE_VALS + 1]; // Nonexistent for leaves
cannam@226 47 };
cannam@226 48
cannam@226 49 typedef struct {
cannam@226 50 ZixBTreeNode* node;
cannam@226 51 unsigned index;
cannam@226 52 } ZixBTreeIterFrame;
cannam@226 53
cannam@226 54 struct ZixBTreeIterImpl {
cannam@226 55 unsigned level; ///< Current level in stack
cannam@226 56 ZixBTreeIterFrame stack[]; ///< Position stack
cannam@226 57 };
cannam@226 58
cannam@226 59 #ifdef ZIX_BTREE_DEBUG
cannam@226 60
cannam@226 61 ZIX_PRIVATE void
cannam@226 62 print_node(const ZixBTreeNode* n, const char* prefix)
cannam@226 63 {
cannam@226 64 printf("%s[", prefix);
cannam@226 65 for (uint16_t v = 0; v < n->n_vals; ++v) {
cannam@226 66 printf(" %lu", (uintptr_t)n->vals[v]);
cannam@226 67 }
cannam@226 68 printf(" ]\n");
cannam@226 69 }
cannam@226 70
cannam@226 71 ZIX_PRIVATE void
cannam@226 72 print_tree(const ZixBTreeNode* parent, const ZixBTreeNode* node, int level)
cannam@226 73 {
cannam@226 74 if (node) {
cannam@226 75 if (!parent) {
cannam@226 76 printf("TREE {\n");
cannam@226 77 }
cannam@226 78 for (int i = 0; i < level + 1; ++i) {
cannam@226 79 printf(" ");
cannam@226 80 }
cannam@226 81 print_node(node, "");
cannam@226 82 if (!node->is_leaf) {
cannam@226 83 for (uint16_t i = 0; i < node->n_vals + 1; ++i) {
cannam@226 84 print_tree(node, node->children[i], level + 1);
cannam@226 85 }
cannam@226 86 }
cannam@226 87 if (!parent) {
cannam@226 88 printf("}\n");
cannam@226 89 }
cannam@226 90 }
cannam@226 91 }
cannam@226 92
cannam@226 93 #endif // ZIX_BTREE_DEBUG
cannam@226 94
cannam@226 95 ZIX_PRIVATE ZixBTreeNode*
cannam@226 96 zix_btree_node_new(const bool leaf)
cannam@226 97 {
cannam@226 98 assert(sizeof(ZixBTreeNode) == ZIX_BTREE_PAGE_SIZE);
cannam@226 99 ZixBTreeNode* node = (ZixBTreeNode*)malloc(sizeof(ZixBTreeNode));
cannam@226 100 if (node) {
cannam@226 101 node->is_leaf = leaf;
cannam@226 102 node->n_vals = 0;
cannam@226 103 }
cannam@226 104 return node;
cannam@226 105 }
cannam@226 106
cannam@226 107 ZIX_API ZixBTree*
cannam@226 108 zix_btree_new(const ZixComparator cmp,
cannam@226 109 void* const cmp_data,
cannam@226 110 const ZixDestroyFunc destroy)
cannam@226 111 {
cannam@226 112 ZixBTree* t = (ZixBTree*)malloc(sizeof(ZixBTree));
cannam@226 113 if (t) {
cannam@226 114 t->root = zix_btree_node_new(true);
cannam@226 115 t->destroy = destroy;
cannam@226 116 t->cmp = cmp;
cannam@226 117 t->cmp_data = cmp_data;
cannam@226 118 t->size = 0;
cannam@226 119 t->height = 1;
cannam@226 120 if (!t->root) {
cannam@226 121 free(t);
cannam@226 122 return NULL;
cannam@226 123 }
cannam@226 124 }
cannam@226 125 return t;
cannam@226 126 }
cannam@226 127
cannam@226 128 ZIX_PRIVATE void
cannam@226 129 zix_btree_free_rec(ZixBTree* const t, ZixBTreeNode* const n)
cannam@226 130 {
cannam@226 131 if (n) {
cannam@226 132 if (t->destroy) {
cannam@226 133 for (uint16_t i = 0; i < n->n_vals; ++i) {
cannam@226 134 t->destroy(n->vals[i]);
cannam@226 135 }
cannam@226 136 }
cannam@226 137 if (!n->is_leaf) {
cannam@226 138 for (uint16_t i = 0; i < n->n_vals + 1; ++i) {
cannam@226 139 zix_btree_free_rec(t, n->children[i]);
cannam@226 140 }
cannam@226 141 }
cannam@226 142 free(n);
cannam@226 143 }
cannam@226 144 }
cannam@226 145
cannam@226 146 ZIX_API void
cannam@226 147 zix_btree_free(ZixBTree* const t)
cannam@226 148 {
cannam@226 149 if (t) {
cannam@226 150 zix_btree_free_rec(t, t->root);
cannam@226 151 free(t);
cannam@226 152 }
cannam@226 153 }
cannam@226 154
cannam@226 155 ZIX_API size_t
cannam@226 156 zix_btree_size(const ZixBTree* const t)
cannam@226 157 {
cannam@226 158 return t->size;
cannam@226 159 }
cannam@226 160
cannam@226 161 ZIX_PRIVATE uint16_t
cannam@226 162 zix_btree_max_vals(const ZixBTreeNode* const node)
cannam@226 163 {
cannam@226 164 return node->is_leaf ? ZIX_BTREE_LEAF_VALS : ZIX_BTREE_INODE_VALS;
cannam@226 165 }
cannam@226 166
cannam@226 167 ZIX_PRIVATE uint16_t
cannam@226 168 zix_btree_min_vals(const ZixBTreeNode* const node)
cannam@226 169 {
cannam@226 170 return ((zix_btree_max_vals(node) + 1) / 2) - 1;
cannam@226 171 }
cannam@226 172
cannam@226 173 /** Shift pointers in `array` of length `n` right starting at `i`. */
cannam@226 174 ZIX_PRIVATE void
cannam@226 175 zix_btree_ainsert(void** const array,
cannam@226 176 const uint16_t n,
cannam@226 177 const uint16_t i,
cannam@226 178 void* const e)
cannam@226 179 {
cannam@226 180 memmove(array + i + 1, array + i, (n - i) * sizeof(e));
cannam@226 181 array[i] = e;
cannam@226 182 }
cannam@226 183
cannam@226 184 /** Erase element `i` in `array` of length `n` and return erased element. */
cannam@226 185 ZIX_PRIVATE void*
cannam@226 186 zix_btree_aerase(void** const array, const uint16_t n, const uint16_t i)
cannam@226 187 {
cannam@226 188 void* const ret = array[i];
cannam@226 189 memmove(array + i, array + i + 1, (n - i) * sizeof(ret));
cannam@226 190 return ret;
cannam@226 191 }
cannam@226 192
cannam@226 193 /** Split lhs, the i'th child of `n`, into two nodes. */
cannam@226 194 ZIX_PRIVATE ZixBTreeNode*
cannam@226 195 zix_btree_split_child(ZixBTreeNode* const n,
cannam@226 196 const uint16_t i,
cannam@226 197 ZixBTreeNode* const lhs)
cannam@226 198 {
cannam@226 199 assert(lhs->n_vals == zix_btree_max_vals(lhs));
cannam@226 200 assert(n->n_vals < ZIX_BTREE_INODE_VALS);
cannam@226 201 assert(i < n->n_vals + 1);
cannam@226 202 assert(n->children[i] == lhs);
cannam@226 203
cannam@226 204 const uint16_t max_n_vals = zix_btree_max_vals(lhs);
cannam@226 205 ZixBTreeNode* rhs = zix_btree_node_new(lhs->is_leaf);
cannam@226 206 if (!rhs) {
cannam@226 207 return NULL;
cannam@226 208 }
cannam@226 209
cannam@226 210 // LHS and RHS get roughly half, less the middle value which moves up
cannam@226 211 lhs->n_vals = max_n_vals / 2;
cannam@226 212 rhs->n_vals = max_n_vals - lhs->n_vals - 1;
cannam@226 213
cannam@226 214 // Copy large half of values from LHS to new RHS node
cannam@226 215 memcpy(rhs->vals,
cannam@226 216 lhs->vals + lhs->n_vals + 1,
cannam@226 217 rhs->n_vals * sizeof(void*));
cannam@226 218
cannam@226 219 // Copy large half of children from LHS to new RHS node
cannam@226 220 if (!lhs->is_leaf) {
cannam@226 221 memcpy(rhs->children,
cannam@226 222 lhs->children + lhs->n_vals + 1,
cannam@226 223 (rhs->n_vals + 1) * sizeof(ZixBTreeNode*));
cannam@226 224 }
cannam@226 225
cannam@226 226 // Move middle value up to parent
cannam@226 227 zix_btree_ainsert(n->vals, n->n_vals, i, lhs->vals[lhs->n_vals]);
cannam@226 228
cannam@226 229 // Insert new RHS node in parent at position i
cannam@226 230 zix_btree_ainsert((void**)n->children, ++n->n_vals, i + 1, rhs);
cannam@226 231
cannam@226 232 return rhs;
cannam@226 233 }
cannam@226 234
cannam@226 235 /** Find the first value in `n` that is not less than `e` (lower bound). */
cannam@226 236 ZIX_PRIVATE uint16_t
cannam@226 237 zix_btree_node_find(const ZixBTree* const t,
cannam@226 238 const ZixBTreeNode* const n,
cannam@226 239 const void* const e,
cannam@226 240 bool* const equal)
cannam@226 241 {
cannam@226 242 uint16_t first = 0;
cannam@226 243 uint16_t len = n->n_vals;
cannam@226 244 while (len > 0) {
cannam@226 245 const uint16_t half = len >> 1;
cannam@226 246 const uint16_t i = first + half;
cannam@226 247 const int cmp = t->cmp(n->vals[i], e, t->cmp_data);
cannam@226 248 if (cmp == 0) {
cannam@226 249 *equal = true;
cannam@226 250 len = half; // Keep searching for wildcard matches
cannam@226 251 } else if (cmp < 0) {
cannam@226 252 const uint16_t chop = half + 1;
cannam@226 253 first += chop;
cannam@226 254 len -= chop;
cannam@226 255 } else {
cannam@226 256 len = half;
cannam@226 257 }
cannam@226 258 }
cannam@226 259 assert(!*equal || t->cmp(n->vals[first], e, t->cmp_data) == 0);
cannam@226 260 return first;
cannam@226 261 }
cannam@226 262
cannam@226 263 ZIX_API ZixStatus
cannam@226 264 zix_btree_insert(ZixBTree* const t, void* const e)
cannam@226 265 {
cannam@226 266 ZixBTreeNode* parent = NULL; // Parent of n
cannam@226 267 ZixBTreeNode* n = t->root; // Current node
cannam@226 268 uint16_t i = 0; // Index of n in parent
cannam@226 269 while (n) {
cannam@226 270 if (n->n_vals == zix_btree_max_vals(n)) {
cannam@226 271 // Node is full, split to ensure there is space for a leaf split
cannam@226 272 if (!parent) {
cannam@226 273 // Root is full, grow tree upwards
cannam@226 274 if (!(parent = zix_btree_node_new(false))) {
cannam@226 275 return ZIX_STATUS_NO_MEM;
cannam@226 276 }
cannam@226 277 t->root = parent;
cannam@226 278 parent->children[0] = n;
cannam@226 279 ++t->height;
cannam@226 280 }
cannam@226 281
cannam@226 282 ZixBTreeNode* const rhs = zix_btree_split_child(parent, i, n);
cannam@226 283 if (!rhs) {
cannam@226 284 return ZIX_STATUS_NO_MEM;
cannam@226 285 }
cannam@226 286
cannam@226 287 const int cmp = t->cmp(parent->vals[i], e, t->cmp_data);
cannam@226 288 if (cmp == 0) {
cannam@226 289 return ZIX_STATUS_EXISTS;
cannam@226 290 } else if (cmp < 0) {
cannam@226 291 // Move to new RHS
cannam@226 292 n = rhs;
cannam@226 293 ++i;
cannam@226 294 }
cannam@226 295 }
cannam@226 296
cannam@226 297 assert(!parent || parent->children[i] == n);
cannam@226 298
cannam@226 299 bool equal = false;
cannam@226 300 i = zix_btree_node_find(t, n, e, &equal);
cannam@226 301 if (equal) {
cannam@226 302 return ZIX_STATUS_EXISTS;
cannam@226 303 } else if (!n->is_leaf) {
cannam@226 304 // Descend to child node left of value
cannam@226 305 parent = n;
cannam@226 306 n = n->children[i];
cannam@226 307 } else {
cannam@226 308 // Insert into internal node
cannam@226 309 zix_btree_ainsert(n->vals, n->n_vals++, i, e);
cannam@226 310 break;
cannam@226 311 }
cannam@226 312 }
cannam@226 313
cannam@226 314 ++t->size;
cannam@226 315
cannam@226 316 return ZIX_STATUS_SUCCESS;
cannam@226 317 }
cannam@226 318
cannam@226 319 ZIX_PRIVATE ZixBTreeIter*
cannam@226 320 zix_btree_iter_new(const ZixBTree* const t)
cannam@226 321 {
cannam@226 322 const size_t s = t->height * sizeof(ZixBTreeIterFrame);
cannam@226 323 ZixBTreeIter* const i = (ZixBTreeIter*)malloc(sizeof(ZixBTreeIter) + s);
cannam@226 324 if (i) {
cannam@226 325 i->level = 0;
cannam@226 326 }
cannam@226 327 return i;
cannam@226 328 }
cannam@226 329
cannam@226 330 ZIX_PRIVATE void
cannam@226 331 zix_btree_iter_set_frame(ZixBTreeIter* const ti,
cannam@226 332 ZixBTreeNode* const n,
cannam@226 333 const uint16_t i)
cannam@226 334 {
cannam@226 335 if (ti) {
cannam@226 336 ti->stack[ti->level].node = n;
cannam@226 337 ti->stack[ti->level].index = i;
cannam@226 338 }
cannam@226 339 }
cannam@226 340
cannam@226 341 ZIX_PRIVATE bool
cannam@226 342 zix_btree_node_is_minimal(ZixBTreeNode* const n)
cannam@226 343 {
cannam@226 344 assert(n->n_vals >= zix_btree_min_vals(n));
cannam@226 345 return n->n_vals == zix_btree_min_vals(n);
cannam@226 346 }
cannam@226 347
cannam@226 348 /** Enlarge left child by stealing a value from its right sibling. */
cannam@226 349 ZIX_PRIVATE ZixBTreeNode*
cannam@226 350 zix_btree_rotate_left(ZixBTreeNode* const parent, const uint16_t i)
cannam@226 351 {
cannam@226 352 ZixBTreeNode* const lhs = parent->children[i];
cannam@226 353 ZixBTreeNode* const rhs = parent->children[i + 1];
cannam@226 354
cannam@226 355 // Move parent value to end of LHS
cannam@226 356 lhs->vals[lhs->n_vals++] = parent->vals[i];
cannam@226 357
cannam@226 358 // Move first child pointer from RHS to end of LHS
cannam@226 359 if (!lhs->is_leaf) {
cannam@226 360 lhs->children[lhs->n_vals] = (ZixBTreeNode*)zix_btree_aerase(
cannam@226 361 (void**)rhs->children, rhs->n_vals, 0);
cannam@226 362 }
cannam@226 363
cannam@226 364 // Move first value in RHS to parent
cannam@226 365 parent->vals[i] = zix_btree_aerase(rhs->vals, --rhs->n_vals, 0);
cannam@226 366
cannam@226 367 return lhs;
cannam@226 368 }
cannam@226 369
cannam@226 370 /** Enlarge right child by stealing a value from its left sibling. */
cannam@226 371 ZIX_PRIVATE ZixBTreeNode*
cannam@226 372 zix_btree_rotate_right(ZixBTreeNode* const parent, const uint16_t i)
cannam@226 373 {
cannam@226 374 ZixBTreeNode* const lhs = parent->children[i - 1];
cannam@226 375 ZixBTreeNode* const rhs = parent->children[i];
cannam@226 376
cannam@226 377 // Prepend parent value to RHS
cannam@226 378 zix_btree_ainsert(rhs->vals, rhs->n_vals++, 0, parent->vals[i - 1]);
cannam@226 379
cannam@226 380 // Move last child pointer from LHS and prepend to RHS
cannam@226 381 if (!lhs->is_leaf) {
cannam@226 382 zix_btree_ainsert((void**)rhs->children,
cannam@226 383 rhs->n_vals,
cannam@226 384 0,
cannam@226 385 lhs->children[lhs->n_vals]);
cannam@226 386 }
cannam@226 387
cannam@226 388 // Move last value from LHS to parent
cannam@226 389 parent->vals[i - 1] = lhs->vals[--lhs->n_vals];
cannam@226 390
cannam@226 391 return rhs;
cannam@226 392 }
cannam@226 393
cannam@226 394 /** Move n[i] down, merge the left and right child, return the merged node. */
cannam@226 395 ZIX_PRIVATE ZixBTreeNode*
cannam@226 396 zix_btree_merge(ZixBTree* const t, ZixBTreeNode* const n, const uint16_t i)
cannam@226 397 {
cannam@226 398 ZixBTreeNode* const lhs = n->children[i];
cannam@226 399 ZixBTreeNode* const rhs = n->children[i + 1];
cannam@226 400
cannam@226 401 assert(zix_btree_node_is_minimal(n->children[i]));
cannam@226 402 assert(lhs->n_vals + rhs->n_vals < zix_btree_max_vals(lhs));
cannam@226 403
cannam@226 404 // Move parent value to end of LHS
cannam@226 405 lhs->vals[lhs->n_vals++] = zix_btree_aerase(n->vals, n->n_vals, i);
cannam@226 406
cannam@226 407 // Erase corresponding child pointer (to RHS) in parent
cannam@226 408 zix_btree_aerase((void**)n->children, n->n_vals, i + 1);
cannam@226 409
cannam@226 410 // Add everything from RHS to end of LHS
cannam@226 411 memcpy(lhs->vals + lhs->n_vals, rhs->vals, rhs->n_vals * sizeof(void*));
cannam@226 412 if (!lhs->is_leaf) {
cannam@226 413 memcpy(lhs->children + lhs->n_vals,
cannam@226 414 rhs->children,
cannam@226 415 (rhs->n_vals + 1) * sizeof(void*));
cannam@226 416 }
cannam@226 417 lhs->n_vals += rhs->n_vals;
cannam@226 418
cannam@226 419 if (--n->n_vals == 0) {
cannam@226 420 // Root is now empty, replace it with its only child
cannam@226 421 assert(n == t->root);
cannam@226 422 t->root = lhs;
cannam@226 423 free(n);
cannam@226 424 }
cannam@226 425
cannam@226 426 free(rhs);
cannam@226 427 return lhs;
cannam@226 428 }
cannam@226 429
cannam@226 430 /** Remove and return the min value from the subtree rooted at `n`. */
cannam@226 431 ZIX_PRIVATE void*
cannam@226 432 zix_btree_remove_min(ZixBTree* const t, ZixBTreeNode* n)
cannam@226 433 {
cannam@226 434 while (!n->is_leaf) {
cannam@226 435 if (zix_btree_node_is_minimal(n->children[0])) {
cannam@226 436 // Leftmost child is minimal, must expand
cannam@226 437 if (!zix_btree_node_is_minimal(n->children[1])) {
cannam@226 438 // Child's right sibling has at least one key to steal
cannam@226 439 n = zix_btree_rotate_left(n, 0);
cannam@226 440 } else {
cannam@226 441 // Both child and right sibling are minimal, merge
cannam@226 442 n = zix_btree_merge(t, n, 0);
cannam@226 443 }
cannam@226 444 } else {
cannam@226 445 n = n->children[0];
cannam@226 446 }
cannam@226 447 }
cannam@226 448
cannam@226 449 return zix_btree_aerase(n->vals, --n->n_vals, 0);
cannam@226 450 }
cannam@226 451
cannam@226 452 /** Remove and return the max value from the subtree rooted at `n`. */
cannam@226 453 ZIX_PRIVATE void*
cannam@226 454 zix_btree_remove_max(ZixBTree* const t, ZixBTreeNode* n)
cannam@226 455 {
cannam@226 456 while (!n->is_leaf) {
cannam@226 457 if (zix_btree_node_is_minimal(n->children[n->n_vals])) {
cannam@226 458 // Leftmost child is minimal, must expand
cannam@226 459 if (!zix_btree_node_is_minimal(n->children[n->n_vals - 1])) {
cannam@226 460 // Child's left sibling has at least one key to steal
cannam@226 461 n = zix_btree_rotate_right(n, n->n_vals);
cannam@226 462 } else {
cannam@226 463 // Both child and left sibling are minimal, merge
cannam@226 464 n = zix_btree_merge(t, n, n->n_vals - 1);
cannam@226 465 }
cannam@226 466 } else {
cannam@226 467 n = n->children[n->n_vals];
cannam@226 468 }
cannam@226 469 }
cannam@226 470
cannam@226 471 return n->vals[--n->n_vals];
cannam@226 472 }
cannam@226 473
cannam@226 474 ZIX_API ZixStatus
cannam@226 475 zix_btree_remove(ZixBTree* const t,
cannam@226 476 const void* const e,
cannam@226 477 void** const out,
cannam@226 478 ZixBTreeIter** const next)
cannam@226 479 {
cannam@226 480 ZixBTreeNode* n = t->root;
cannam@226 481 ZixBTreeIter* ti = NULL;
cannam@226 482 const bool user_iter = next && *next;
cannam@226 483 if (next) {
cannam@226 484 if (!*next && !(*next = zix_btree_iter_new(t))) {
cannam@226 485 return ZIX_STATUS_NO_MEM;
cannam@226 486 }
cannam@226 487 ti = *next;
cannam@226 488 ti->level = 0;
cannam@226 489 }
cannam@226 490
cannam@226 491 while (true) {
cannam@226 492 /* To remove in a single walk down, the tree is adjusted along the way
cannam@226 493 so that the current node always has at least one more value than the
cannam@226 494 minimum required in general. Thus, there is always room to remove
cannam@226 495 without adjusting on the way back up. */
cannam@226 496 assert(n == t->root || !zix_btree_node_is_minimal(n));
cannam@226 497
cannam@226 498 bool equal = false;
cannam@226 499 const uint16_t i = zix_btree_node_find(t, n, e, &equal);
cannam@226 500 zix_btree_iter_set_frame(ti, n, i);
cannam@226 501 if (n->is_leaf) {
cannam@226 502 if (equal) {
cannam@226 503 // Found in leaf node
cannam@226 504 *out = zix_btree_aerase(n->vals, --n->n_vals, i);
cannam@226 505 if (ti && i == n->n_vals) {
cannam@226 506 if (i == 0) {
cannam@226 507 ti->stack[ti->level = 0].node = NULL;
cannam@226 508 } else {
cannam@226 509 --ti->stack[ti->level].index;
cannam@226 510 zix_btree_iter_increment(ti);
cannam@226 511 }
cannam@226 512 }
cannam@226 513 --t->size;
cannam@226 514 return ZIX_STATUS_SUCCESS;
cannam@226 515 } else {
cannam@226 516 // Not found in leaf node, or tree
cannam@226 517 if (ti && !user_iter) {
cannam@226 518 zix_btree_iter_free(ti);
cannam@226 519 *next = NULL;
cannam@226 520 }
cannam@226 521 return ZIX_STATUS_NOT_FOUND;
cannam@226 522 }
cannam@226 523 } else if (equal) {
cannam@226 524 // Found in internal node
cannam@226 525 if (!zix_btree_node_is_minimal(n->children[i])) {
cannam@226 526 // Left child can remove without merge
cannam@226 527 *out = n->vals[i];
cannam@226 528 n->vals[i] = zix_btree_remove_max(t, n->children[i]);
cannam@226 529 --t->size;
cannam@226 530 return ZIX_STATUS_SUCCESS;
cannam@226 531 } else if (!zix_btree_node_is_minimal(n->children[i + 1])) {
cannam@226 532 // Right child can remove without merge
cannam@226 533 *out = n->vals[i];
cannam@226 534 n->vals[i] = zix_btree_remove_min(t, n->children[i + 1]);
cannam@226 535 --t->size;
cannam@226 536 return ZIX_STATUS_SUCCESS;
cannam@226 537 } else {
cannam@226 538 // Both preceding and succeeding child are minimal
cannam@226 539 n = zix_btree_merge(t, n, i);
cannam@226 540 }
cannam@226 541 } else {
cannam@226 542 // Not found in internal node, key is in/under children[i]
cannam@226 543 if (zix_btree_node_is_minimal(n->children[i])) {
cannam@226 544 if (i > 0 && !zix_btree_node_is_minimal(n->children[i - 1])) {
cannam@226 545 // Steal a key from child's left sibling
cannam@226 546 n = zix_btree_rotate_right(n, i);
cannam@226 547 } else if (i < n->n_vals &&
cannam@226 548 !zix_btree_node_is_minimal(n->children[i + 1])) {
cannam@226 549 // Steal a key from child's right sibling
cannam@226 550 n = zix_btree_rotate_left(n, i);
cannam@226 551 } else {
cannam@226 552 // Both child's siblings are minimal, merge them
cannam@226 553 if (i < n->n_vals) {
cannam@226 554 n = zix_btree_merge(t, n, i);
cannam@226 555 } else {
cannam@226 556 n = zix_btree_merge(t, n, i - 1);
cannam@226 557 if (ti) {
cannam@226 558 --ti->stack[ti->level].index;
cannam@226 559 }
cannam@226 560 }
cannam@226 561 }
cannam@226 562 } else {
cannam@226 563 n = n->children[i];
cannam@226 564 }
cannam@226 565 }
cannam@226 566 if (ti) {
cannam@226 567 ++ti->level;
cannam@226 568 }
cannam@226 569 }
cannam@226 570
cannam@226 571 assert(false); // Not reached
cannam@226 572 return ZIX_STATUS_ERROR;
cannam@226 573 }
cannam@226 574
cannam@226 575 ZIX_API ZixStatus
cannam@226 576 zix_btree_find(const ZixBTree* const t,
cannam@226 577 const void* const e,
cannam@226 578 ZixBTreeIter** const ti)
cannam@226 579 {
cannam@226 580 ZixBTreeNode* n = t->root;
cannam@226 581 if (!(*ti = zix_btree_iter_new(t))) {
cannam@226 582 return ZIX_STATUS_NO_MEM;
cannam@226 583 }
cannam@226 584
cannam@226 585 while (n) {
cannam@226 586 bool equal = false;
cannam@226 587 const uint16_t i = zix_btree_node_find(t, n, e, &equal);
cannam@226 588
cannam@226 589 zix_btree_iter_set_frame(*ti, n, i);
cannam@226 590
cannam@226 591 if (equal) {
cannam@226 592 return ZIX_STATUS_SUCCESS;
cannam@226 593 } else if (n->is_leaf) {
cannam@226 594 break;
cannam@226 595 } else {
cannam@226 596 ++(*ti)->level;
cannam@226 597 n = n->children[i];
cannam@226 598 }
cannam@226 599 }
cannam@226 600
cannam@226 601 zix_btree_iter_free(*ti);
cannam@226 602 *ti = NULL;
cannam@226 603 return ZIX_STATUS_NOT_FOUND;
cannam@226 604 }
cannam@226 605
cannam@226 606 ZIX_API ZixStatus
cannam@226 607 zix_btree_lower_bound(const ZixBTree* const t,
cannam@226 608 const void* const e,
cannam@226 609 ZixBTreeIter** const ti)
cannam@226 610 {
cannam@226 611 if (!t) {
cannam@226 612 *ti = NULL;
cannam@226 613 return ZIX_STATUS_BAD_ARG;
cannam@226 614 }
cannam@226 615
cannam@226 616 ZixBTreeNode* n = t->root;
cannam@226 617 bool found = false;
cannam@226 618 unsigned found_level = 0;
cannam@226 619 if (!(*ti = zix_btree_iter_new(t))) {
cannam@226 620 return ZIX_STATUS_NO_MEM;
cannam@226 621 }
cannam@226 622
cannam@226 623 while (n) {
cannam@226 624 bool equal = false;
cannam@226 625 const uint16_t i = zix_btree_node_find(t, n, e, &equal);
cannam@226 626
cannam@226 627 zix_btree_iter_set_frame(*ti, n, i);
cannam@226 628
cannam@226 629 if (equal) {
cannam@226 630 found_level = (*ti)->level;
cannam@226 631 found = true;
cannam@226 632 }
cannam@226 633
cannam@226 634 if (n->is_leaf) {
cannam@226 635 break;
cannam@226 636 } else {
cannam@226 637 ++(*ti)->level;
cannam@226 638 n = n->children[i];
cannam@226 639 assert(n);
cannam@226 640 }
cannam@226 641 }
cannam@226 642
cannam@226 643 const ZixBTreeIterFrame* const frame = &(*ti)->stack[(*ti)->level];
cannam@226 644 if (frame->index == frame->node->n_vals) {
cannam@226 645 if (found) {
cannam@226 646 // Found on a previous level but went too far
cannam@226 647 (*ti)->level = found_level;
cannam@226 648 } else {
cannam@226 649 // Reached end (key is greater than everything in tree)
cannam@226 650 (*ti)->stack[0].node = NULL;
cannam@226 651 }
cannam@226 652 }
cannam@226 653
cannam@226 654 return ZIX_STATUS_SUCCESS;
cannam@226 655 }
cannam@226 656
cannam@226 657 ZIX_API void*
cannam@226 658 zix_btree_get(const ZixBTreeIter* const ti)
cannam@226 659 {
cannam@226 660 const ZixBTreeIterFrame* const frame = &ti->stack[ti->level];
cannam@226 661 assert(frame->index < frame->node->n_vals);
cannam@226 662 return frame->node->vals[frame->index];
cannam@226 663 }
cannam@226 664
cannam@226 665 ZIX_API ZixBTreeIter*
cannam@226 666 zix_btree_begin(const ZixBTree* const t)
cannam@226 667 {
cannam@226 668 ZixBTreeIter* const i = zix_btree_iter_new(t);
cannam@226 669 if (!i) {
cannam@226 670 return NULL;
cannam@226 671 } else if (t->size == 0) {
cannam@226 672 i->stack[0].node = NULL;
cannam@226 673 } else {
cannam@226 674 ZixBTreeNode* n = t->root;
cannam@226 675 i->stack[0].node = n;
cannam@226 676 i->stack[0].index = 0;
cannam@226 677 while (!n->is_leaf) {
cannam@226 678 n = n->children[0];
cannam@226 679 ++i->level;
cannam@226 680 i->stack[i->level].node = n;
cannam@226 681 i->stack[i->level].index = 0;
cannam@226 682 }
cannam@226 683 }
cannam@226 684 return i;
cannam@226 685 }
cannam@226 686
cannam@226 687 ZIX_API bool
cannam@226 688 zix_btree_iter_is_end(const ZixBTreeIter* const i)
cannam@226 689 {
cannam@226 690 return !i || i->stack[0].node == NULL;
cannam@226 691 }
cannam@226 692
cannam@226 693 ZIX_API void
cannam@226 694 zix_btree_iter_increment(ZixBTreeIter* const i)
cannam@226 695 {
cannam@226 696 ZixBTreeIterFrame* f = &i->stack[i->level];
cannam@226 697 if (f->node->is_leaf) {
cannam@226 698 // Leaf, move right
cannam@226 699 assert(f->index < f->node->n_vals);
cannam@226 700 if (++f->index == f->node->n_vals) {
cannam@226 701 // Reached end of leaf, move up
cannam@226 702 f = &i->stack[i->level];
cannam@226 703 while (i->level > 0 && f->index == f->node->n_vals) {
cannam@226 704 f = &i->stack[--i->level];
cannam@226 705 assert(f->index <= f->node->n_vals);
cannam@226 706 }
cannam@226 707
cannam@226 708 if (f->index == f->node->n_vals) {
cannam@226 709 // Reached end of tree
cannam@226 710 assert(i->level == 0);
cannam@226 711 f->node = NULL;
cannam@226 712 f->index = 0;
cannam@226 713 }
cannam@226 714 }
cannam@226 715 } else {
cannam@226 716 // Internal node, move down to next child
cannam@226 717 assert(f->index < f->node->n_vals);
cannam@226 718 ZixBTreeNode* child = f->node->children[++f->index];
cannam@226 719
cannam@226 720 f = &i->stack[++i->level];
cannam@226 721 f->node = child;
cannam@226 722 f->index = 0;
cannam@226 723
cannam@226 724 // Move down and left until we hit a leaf
cannam@226 725 while (!f->node->is_leaf) {
cannam@226 726 child = f->node->children[0];
cannam@226 727 f = &i->stack[++i->level];
cannam@226 728 f->node = child;
cannam@226 729 f->index = 0;
cannam@226 730 }
cannam@226 731 }
cannam@226 732 }
cannam@226 733
cannam@226 734 ZIX_API void
cannam@226 735 zix_btree_iter_free(ZixBTreeIter* const i)
cannam@226 736 {
cannam@226 737 free(i);
cannam@226 738 }