diff options
Diffstat (limited to 'src/btree.c')
-rw-r--r-- | src/btree.c | 90 |
1 files changed, 50 insertions, 40 deletions
diff --git a/src/btree.c b/src/btree.c index 7970796..dabd406 100644 --- a/src/btree.c +++ b/src/btree.c @@ -1,7 +1,11 @@ -// Copyright 2011-2021 David Robillard <d@drobilla.net> +// Copyright 2011-2024 David Robillard <d@drobilla.net> // SPDX-License-Identifier: ISC -#include "zix/btree.h" +#include <zix/btree.h> + +#include <zix/allocator.h> +#include <zix/attributes.h> +#include <zix/status.h> #include <assert.h> #include <stdint.h> @@ -10,9 +14,9 @@ // #define ZIX_BTREE_SORTED_CHECK 1 // Define ZixShort as an integer type half the size of a pointer -#if UINTPTR_MAX >= UINT32_MAX +#if UINTPTR_MAX > UINT32_MAX // 64-bit typedef uint32_t ZixShort; -#else +#else // 32-bit typedef uint16_t ZixShort; #endif @@ -78,8 +82,7 @@ zix_btree_node_new(ZixAllocator* const allocator, const bool leaf) return node; } -ZIX_PURE_FUNC -static ZixBTreeNode* +ZIX_PURE_FUNC static ZixBTreeNode* zix_btree_child(const ZixBTreeNode* const node, const unsigned i) { assert(!node->is_leaf); @@ -99,23 +102,15 @@ zix_btree_new(ZixAllocator* const allocator, assert(cmp); - ZixBTree* const t = (ZixBTree*)zix_aligned_alloc( - allocator, ZIX_BTREE_PAGE_SIZE, ZIX_BTREE_PAGE_SIZE); - - if (!t) { - return NULL; - } - - if (!(t->root = zix_btree_node_new(allocator, true))) { - zix_aligned_free(allocator, t); - return NULL; + ZixBTree* const t = (ZixBTree*)zix_malloc(allocator, sizeof(ZixBTree)); + if (t) { + t->allocator = allocator; + t->root = NULL; + t->cmp = cmp; + t->cmp_data = cmp_data; + t->size = 0U; } - t->allocator = allocator; - t->cmp = cmp; - t->cmp_data = cmp_data; - t->size = 0U; - return t; } @@ -154,20 +149,22 @@ zix_btree_free(ZixBTree* const t, if (t) { zix_btree_clear(t, destroy, destroy_user_data); zix_aligned_free(t->allocator, t->root); - zix_aligned_free(t->allocator, t); + zix_free(t->allocator, t); } } void -zix_btree_clear(ZixBTree* const t, - ZixBTreeDestroyFunc destroy, - const void* destroy_user_data) +zix_btree_clear(ZixBTree* const t, + const ZixBTreeDestroyFunc destroy, + const void* const destroy_user_data) { - zix_btree_free_children(t, t->root, destroy, destroy_user_data); + if (t->root) { + zix_btree_free_children(t, t->root, destroy, destroy_user_data); + zix_aligned_free(t->allocator, t->root); + t->root = NULL; + } - memset(t->root, 0U, sizeof(ZixBTreeNode)); - t->root->is_leaf = true; - t->size = 0U; + t->size = 0U; } size_t @@ -196,7 +193,7 @@ zix_btree_ainsert(void** const array, const unsigned i, void* const e) { - memmove(array + i + 1U, array + i, (n - i) * sizeof(e)); + memmove(array + i + 1U, array + i, ((size_t)n - i) * sizeof(e)); array[i] = e; } @@ -205,7 +202,7 @@ static void* zix_btree_aerase(void** const array, const unsigned n, const unsigned i) { void* const ret = array[i]; - memmove(array + i, array + i + 1U, (n - i) * sizeof(ret)); + memmove(array + i, array + i + 1U, ((size_t)n - i) * sizeof(ret)); return ret; } @@ -221,7 +218,7 @@ zix_btree_split_child(ZixAllocator* const allocator, assert(i < n->n_vals + 1U); assert(zix_btree_child(n, i) == lhs); - const ZixShort max_n_vals = zix_btree_max_vals(lhs); + const unsigned max_n_vals = zix_btree_max_vals(lhs); ZixBTreeNode* rhs = zix_btree_node_new(allocator, lhs->is_leaf); if (!rhs) { return NULL; @@ -247,7 +244,7 @@ zix_btree_split_child(ZixAllocator* const allocator, rhs->n_vals * sizeof(void*)); memcpy(rhs->data.inode.children, lhs->data.inode.children + lhs->n_vals + 1U, - (rhs->n_vals + 1U) * sizeof(ZixBTreeNode*)); + ((size_t)rhs->n_vals + 1U) * sizeof(ZixBTreeNode*)); // Move middle value up to parent zix_btree_ainsert( @@ -394,14 +391,14 @@ zix_btree_leaf_find(const ZixBTree* const t, t->cmp, t->cmp_data, n->data.leaf.vals, n->n_vals, e, equal); } -static inline bool +ZIX_PURE_FUNC static inline bool zix_btree_can_remove_from(const ZixBTreeNode* const n) { assert(n->n_vals >= zix_btree_min_vals(n)); return n->n_vals > zix_btree_min_vals(n); } -static inline bool +ZIX_PURE_FUNC static inline bool zix_btree_is_full(const ZixBTreeNode* const n) { assert(n->n_vals <= zix_btree_max_vals(n)); @@ -433,8 +430,13 @@ zix_btree_insert(ZixBTree* const t, void* const e) ZixStatus st = ZIX_STATUS_SUCCESS; - // Grow up if necessary to ensure the root is not full - if (zix_btree_is_full(t->root)) { + if (!t->root) { + // Empty tree, create a new leaf root + if (!(t->root = zix_btree_node_new(t->allocator, true))) { + return ZIX_STATUS_NO_MEM; + } + } else if (zix_btree_is_full(t->root)) { + // Grow up if necessary to ensure the root is not full if ((st = zix_btree_grow_up(t))) { return st; } @@ -490,8 +492,9 @@ zix_btree_insert(ZixBTree* const t, void* const e) static void zix_btree_iter_set_frame(ZixBTreeIter* const ti, ZixBTreeNode* const n, - const ZixShort i) + const unsigned i) { + assert(i <= UINT16_MAX); ti->nodes[ti->level] = n; ti->indexes[ti->level] = (uint16_t)i; } @@ -617,7 +620,7 @@ zix_btree_merge(ZixBTree* const t, ZixBTreeNode* const n, const unsigned i) rhs->n_vals * sizeof(void*)); memcpy(lhs->data.inode.children + lhs->n_vals, rhs->data.inode.children, - (rhs->n_vals + 1U) * sizeof(void*)); + ((size_t)rhs->n_vals + 1U) * sizeof(void*)); } lhs->n_vals += rhs->n_vals; @@ -677,6 +680,7 @@ zix_btree_fatten_child(ZixBTree* const t, ZixBTreeIter* const iter) assert(n); assert(!n->is_leaf); + assert(n->n_vals); ZixBTreeNode* const* const children = n->data.inode.children; if (i > 0U && zix_btree_can_remove_from(children[i - 1U])) { @@ -825,6 +829,9 @@ zix_btree_find(const ZixBTree* const t, ZixBTreeNode* n = t->root; *ti = zix_btree_end_iter; + if (!n) { + return ZIX_STATUS_NOT_FOUND; + } while (!n->is_leaf) { bool equal = false; @@ -866,6 +873,9 @@ zix_btree_lower_bound(const ZixBTree* const t, ZixBTreeNode* n = t->root; // Current node uint16_t found_level = 0U; // Lowest level a match was found at bool found = false; // True if a match was ever found + if (!n) { + return ZIX_STATUS_SUCCESS; + } // Search down until we reach a leaf while (!n->is_leaf) { @@ -959,7 +969,7 @@ zix_btree_end(const ZixBTree* const t) bool zix_btree_iter_equals(const ZixBTreeIter lhs, const ZixBTreeIter rhs) { - const size_t indexes_size = (lhs.level + 1U) * sizeof(uint16_t); + const size_t indexes_size = ((size_t)lhs.level + 1U) * sizeof(uint16_t); return (lhs.level == rhs.level) && (lhs.nodes[0U] == rhs.nodes[0U]) && (!lhs.nodes[0U] || !memcmp(lhs.indexes, rhs.indexes, indexes_size)); |