diff --git a/.gitignore b/.gitignore index f620f64..7c29342 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ /sord-0.16.4.tar.bz2 /sord-0.16.6.tar.bz2 /sord-0.16.8.tar.bz2 +/sord-0.16.10.tar.bz2 diff --git a/sord-update-zix.patch b/sord-update-zix.patch deleted file mode 100644 index 395dc15..0000000 --- a/sord-update-zix.patch +++ /dev/null @@ -1,2642 +0,0 @@ -From 5bc9b6e08b2555f2f1a9fe65db266dc97f4a50ba Mon Sep 17 00:00:00 2001 -From: David Robillard -Date: Tue, 12 Jan 2021 15:18:49 +0100 -Subject: [PATCH] Update zix - -This fixes, once again, a potential BTree crash with GCC 10 which got lost -somewhere along the way. ---- - NEWS | 6 + - src/sord_config.h | 2 +- - src/zix/btree.c | 1336 +++++++++++++++++++++++---------------------- - src/zix/btree.h | 55 +- - src/zix/common.h | 109 ++-- - src/zix/digest.c | 120 ++-- - src/zix/digest.h | 16 +- - src/zix/hash.c | 289 +++++----- - src/zix/hash.h | 48 +- - wscript | 2 +- - 10 files changed, 1004 insertions(+), 979 deletions(-) - -diff --git a/NEWS b/NEWS -index b09bba5..325be60 100644 ---- a/NEWS -+++ b/NEWS -@@ -1,3 +1,9 @@ -+sord (0.16.9) unstable; -+ -+ * Fix potential crash or incorrectness issue with GCC 10 again -+ -+ -- David Robillard Tue, 12 Jan 2021 14:17:39 +0000 -+ - sord (0.16.8) stable; - - * Clean up code -diff --git a/src/zix/btree.c b/src/zix/btree.c -index 3279f6c..7926a56 100644 ---- a/src/zix/btree.c -+++ b/src/zix/btree.c -@@ -25,121 +25,119 @@ - // #define ZIX_BTREE_SORTED_CHECK 1 - - #ifndef ZIX_BTREE_PAGE_SIZE --# define ZIX_BTREE_PAGE_SIZE 4096 -+# define ZIX_BTREE_PAGE_SIZE 4096 - #endif - - #define ZIX_BTREE_NODE_SPACE (ZIX_BTREE_PAGE_SIZE - 2 * sizeof(uint16_t)) --#define ZIX_BTREE_LEAF_VALS ((ZIX_BTREE_NODE_SPACE / sizeof(void*)) - 1) -+#define ZIX_BTREE_LEAF_VALS ((ZIX_BTREE_NODE_SPACE / sizeof(void*)) - 1) - #define ZIX_BTREE_INODE_VALS (ZIX_BTREE_LEAF_VALS / 2) - - struct ZixBTreeImpl { -- ZixBTreeNode* root; -- ZixDestroyFunc destroy; -- ZixComparator cmp; -- const void* cmp_data; -- size_t size; -- unsigned height; ///< Number of levels, i.e. root only has height 1 -+ ZixBTreeNode* root; -+ ZixDestroyFunc destroy; -+ ZixComparator cmp; -+ const void* cmp_data; -+ size_t size; -+ unsigned height; ///< Number of levels, i.e. root only has height 1 - }; - - struct ZixBTreeNodeImpl { -- uint16_t is_leaf; -- uint16_t n_vals; -- // On 64-bit we rely on some padding here to get page-sized nodes -- union { -- struct { -- void* vals[ZIX_BTREE_LEAF_VALS]; -- } leaf; -- -- struct { -- void* vals[ZIX_BTREE_INODE_VALS]; -- ZixBTreeNode* children[ZIX_BTREE_INODE_VALS + 1]; -- } inode; -- } data; -+ uint16_t is_leaf; -+ uint16_t n_vals; -+ // On 64-bit we rely on some padding here to get page-sized nodes -+ union { -+ struct { -+ void* vals[ZIX_BTREE_LEAF_VALS]; -+ } leaf; -+ -+ struct { -+ void* vals[ZIX_BTREE_INODE_VALS]; -+ ZixBTreeNode* children[ZIX_BTREE_INODE_VALS + 1]; -+ } inode; -+ } data; - }; - - #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112l) || \ -- (defined(__cplusplus) && __cplusplus >= 201103L) -+ (defined(__cplusplus) && __cplusplus >= 201103L) - static_assert(sizeof(ZixBTreeNode) == ZIX_BTREE_PAGE_SIZE, ""); - #endif - - typedef struct { -- ZixBTreeNode* node; -- unsigned index; -+ ZixBTreeNode* node; -+ unsigned index; - } ZixBTreeIterFrame; - - struct ZixBTreeIterImpl { -- unsigned n_levels; ///< Maximum depth of stack -- unsigned level; ///< Current level in stack -- ZixBTreeIterFrame stack[]; ///< Position stack -+ unsigned n_levels; ///< Maximum depth of stack -+ unsigned level; ///< Current level in stack -+ ZixBTreeIterFrame stack[]; ///< Position stack - }; - - #ifdef ZIX_BTREE_DEBUG - --ZIX_PRIVATE void -+static void - print_node(const ZixBTreeNode* n, const char* prefix) - { -- printf("%s[", prefix); -- for (uint16_t v = 0; v < n->n_vals; ++v) { -- printf(" %lu", (uintptr_t)n->vals[v]); -- } -- printf(" ]\n"); -+ printf("%s[", prefix); -+ for (uint16_t v = 0; v < n->n_vals; ++v) { -+ printf(" %lu", (uintptr_t)n->vals[v]); -+ } -+ printf(" ]\n"); - } - --ZIX_PRIVATE void -+static void - print_tree(const ZixBTreeNode* parent, const ZixBTreeNode* node, int level) - { -- if (node) { -- if (!parent) { -- printf("TREE {\n"); -- } -- for (int i = 0; i < level + 1; ++i) { -- printf(" "); -- } -- print_node(node, ""); -- if (!node->is_leaf) { -- for (uint16_t i = 0; i < node->n_vals + 1; ++i) { -- print_tree(node, node->data.inode.children[i], level + 1); -- } -- } -- if (!parent) { -- printf("}\n"); -- } -- } --} -- --#endif // ZIX_BTREE_DEBUG -- --ZIX_PRIVATE ZixBTreeNode* -+ if (node) { -+ if (!parent) { -+ printf("TREE {\n"); -+ } -+ for (int i = 0; i < level + 1; ++i) { -+ printf(" "); -+ } -+ print_node(node, ""); -+ if (!node->is_leaf) { -+ for (uint16_t i = 0; i < node->n_vals + 1; ++i) { -+ print_tree(node, node->data.inode.children[i], level + 1); -+ } -+ } -+ if (!parent) { -+ printf("}\n"); -+ } -+ } -+} -+ -+#endif // ZIX_BTREE_DEBUG -+ -+static ZixBTreeNode* - zix_btree_node_new(const bool leaf) - { - #if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112l) || \ - (defined(__cplusplus) && __cplusplus >= 201103L)) -- assert(sizeof(ZixBTreeNode) == ZIX_BTREE_PAGE_SIZE); -+ assert(sizeof(ZixBTreeNode) == ZIX_BTREE_PAGE_SIZE); - #endif - -- ZixBTreeNode* node = (ZixBTreeNode*)malloc(sizeof(ZixBTreeNode)); -- if (node) { -- node->is_leaf = leaf; -- node->n_vals = 0; -- } -- return node; -+ ZixBTreeNode* node = (ZixBTreeNode*)malloc(sizeof(ZixBTreeNode)); -+ if (node) { -+ node->is_leaf = leaf; -+ node->n_vals = 0; -+ } -+ return node; - } - --ZIX_PRIVATE --void* -+static void* - zix_btree_value(const ZixBTreeNode* const node, const unsigned i) - { -- assert(i < node->n_vals); -- return node->is_leaf ? node->data.leaf.vals[i] : node->data.inode.vals[i]; -+ assert(i < node->n_vals); -+ return node->is_leaf ? node->data.leaf.vals[i] : node->data.inode.vals[i]; - } - --ZIX_PRIVATE --ZixBTreeNode* -+static ZixBTreeNode* - zix_btree_child(const ZixBTreeNode* const node, const unsigned i) - { -- assert(!node->is_leaf); -- assert(i <= ZIX_BTREE_INODE_VALS); -- return node->data.inode.children[i]; -+ assert(!node->is_leaf); -+ assert(i <= ZIX_BTREE_INODE_VALS); -+ return node->data.inode.children[i]; - } - - ZixBTree* -@@ -147,455 +145,452 @@ zix_btree_new(const ZixComparator cmp, - const void* const cmp_data, - const ZixDestroyFunc destroy) - { -- ZixBTree* t = (ZixBTree*)malloc(sizeof(ZixBTree)); -- if (t) { -- t->root = zix_btree_node_new(true); -- t->destroy = destroy; -- t->cmp = cmp; -- t->cmp_data = cmp_data; -- t->size = 0; -- t->height = 1; -- if (!t->root) { -- free(t); -- return NULL; -- } -- } -- return t; --} -- --ZIX_PRIVATE void -+ ZixBTree* t = (ZixBTree*)malloc(sizeof(ZixBTree)); -+ if (t) { -+ t->root = zix_btree_node_new(true); -+ t->destroy = destroy; -+ t->cmp = cmp; -+ t->cmp_data = cmp_data; -+ t->size = 0; -+ t->height = 1; -+ if (!t->root) { -+ free(t); -+ return NULL; -+ } -+ } -+ return t; -+} -+ -+static void - zix_btree_free_rec(ZixBTree* const t, ZixBTreeNode* const n) - { -- if (n) { -- if (n->is_leaf) { -- if (t->destroy) { -- for (uint16_t i = 0; i < n->n_vals; ++i) { -- t->destroy(n->data.leaf.vals[i]); -- } -- } -- } else { -- if (t->destroy) { -- for (uint16_t i = 0; i < n->n_vals; ++i) { -- t->destroy(n->data.inode.vals[i]); -- } -- } -- -- for (uint16_t i = 0; i < n->n_vals + 1; ++i) { -- zix_btree_free_rec(t, zix_btree_child(n, i)); -- } -- } -- free(n); -- } -+ if (n) { -+ if (n->is_leaf) { -+ if (t->destroy) { -+ for (uint16_t i = 0; i < n->n_vals; ++i) { -+ t->destroy(n->data.leaf.vals[i]); -+ } -+ } -+ } else { -+ if (t->destroy) { -+ for (uint16_t i = 0; i < n->n_vals; ++i) { -+ t->destroy(n->data.inode.vals[i]); -+ } -+ } -+ -+ for (uint16_t i = 0; i < n->n_vals + 1; ++i) { -+ zix_btree_free_rec(t, zix_btree_child(n, i)); -+ } -+ } -+ -+ free(n); -+ } - } - - void - zix_btree_free(ZixBTree* const t) - { -- if (t) { -- zix_btree_free_rec(t, t->root); -- free(t); -- } -+ if (t) { -+ zix_btree_free_rec(t, t->root); -+ free(t); -+ } - } - - size_t - zix_btree_size(const ZixBTree* const t) - { -- return t->size; -+ return t->size; - } - --ZIX_PRIVATE uint16_t -+static uint16_t - zix_btree_max_vals(const ZixBTreeNode* const node) - { -- return node->is_leaf ? ZIX_BTREE_LEAF_VALS : ZIX_BTREE_INODE_VALS; -+ return node->is_leaf ? ZIX_BTREE_LEAF_VALS : ZIX_BTREE_INODE_VALS; - } - --ZIX_PRIVATE uint16_t -+static uint16_t - zix_btree_min_vals(const ZixBTreeNode* const node) - { -- return (uint16_t)(((zix_btree_max_vals(node) + 1U) / 2U) - 1U); -+ return (uint16_t)(((zix_btree_max_vals(node) + 1U) / 2U) - 1U); - } - - /** Shift pointers in `array` of length `n` right starting at `i`. */ --ZIX_PRIVATE void -+static void - zix_btree_ainsert(void** const array, - const unsigned n, - const unsigned i, - void* const e) - { -- memmove(array + i + 1, array + i, (n - i) * sizeof(e)); -- array[i] = e; -+ memmove(array + i + 1, array + i, (n - i) * sizeof(e)); -+ array[i] = e; - } - - /** Erase element `i` in `array` of length `n` and return erased element. */ --ZIX_PRIVATE void* -+static void* - zix_btree_aerase(void** const array, const unsigned n, const unsigned i) - { -- void* const ret = array[i]; -- memmove(array + i, array + i + 1, (n - i) * sizeof(ret)); -- return ret; -+ void* const ret = array[i]; -+ memmove(array + i, array + i + 1, (n - i) * sizeof(ret)); -+ return ret; - } - - /** Split lhs, the i'th child of `n`, into two nodes. */ --ZIX_PRIVATE ZixBTreeNode* -+static ZixBTreeNode* - zix_btree_split_child(ZixBTreeNode* const n, - const unsigned i, - ZixBTreeNode* const lhs) - { -- assert(lhs->n_vals == zix_btree_max_vals(lhs)); -- assert(n->n_vals < ZIX_BTREE_INODE_VALS); -- assert(i < n->n_vals + 1U); -- assert(zix_btree_child(n, i) == lhs); -- -- const uint16_t max_n_vals = zix_btree_max_vals(lhs); -- ZixBTreeNode* rhs = zix_btree_node_new(lhs->is_leaf); -- if (!rhs) { -- return NULL; -- } -- -- // LHS and RHS get roughly half, less the middle value which moves up -- lhs->n_vals = max_n_vals / 2U; -- rhs->n_vals = (uint16_t)(max_n_vals - lhs->n_vals - 1); -- -- if (lhs->is_leaf) { -- // Copy large half from LHS to new RHS node -- memcpy(rhs->data.leaf.vals, -- lhs->data.leaf.vals + lhs->n_vals + 1, -- rhs->n_vals * sizeof(void*)); -- -- // Move middle value up to parent -- zix_btree_ainsert(n->data.inode.vals, -- n->n_vals, -- i, -- lhs->data.leaf.vals[lhs->n_vals]); -- } else { -- // Copy large half from LHS to new RHS node -- memcpy(rhs->data.inode.vals, -- lhs->data.inode.vals + lhs->n_vals + 1, -- rhs->n_vals * sizeof(void*)); -- memcpy(rhs->data.inode.children, -- lhs->data.inode.children + lhs->n_vals + 1, -- (rhs->n_vals + 1U) * sizeof(ZixBTreeNode*)); -- -- // Move middle value up to parent -- zix_btree_ainsert(n->data.inode.vals, -- n->n_vals, -- i, -- lhs->data.inode.vals[lhs->n_vals]); -- } -- -- // Insert new RHS node in parent at position i -- zix_btree_ainsert((void**)n->data.inode.children, ++n->n_vals, i + 1U, rhs); -- -- return rhs; -+ assert(lhs->n_vals == zix_btree_max_vals(lhs)); -+ assert(n->n_vals < ZIX_BTREE_INODE_VALS); -+ assert(i < n->n_vals + 1U); -+ assert(zix_btree_child(n, i) == lhs); -+ -+ const uint16_t max_n_vals = zix_btree_max_vals(lhs); -+ ZixBTreeNode* rhs = zix_btree_node_new(lhs->is_leaf); -+ if (!rhs) { -+ return NULL; -+ } -+ -+ // LHS and RHS get roughly half, less the middle value which moves up -+ lhs->n_vals = max_n_vals / 2U; -+ rhs->n_vals = (uint16_t)(max_n_vals - lhs->n_vals - 1); -+ -+ if (lhs->is_leaf) { -+ // Copy large half from LHS to new RHS node -+ memcpy(rhs->data.leaf.vals, -+ lhs->data.leaf.vals + lhs->n_vals + 1, -+ rhs->n_vals * sizeof(void*)); -+ -+ // Move middle value up to parent -+ zix_btree_ainsert( -+ n->data.inode.vals, n->n_vals, i, lhs->data.leaf.vals[lhs->n_vals]); -+ } else { -+ // Copy large half from LHS to new RHS node -+ memcpy(rhs->data.inode.vals, -+ lhs->data.inode.vals + lhs->n_vals + 1, -+ rhs->n_vals * sizeof(void*)); -+ memcpy(rhs->data.inode.children, -+ lhs->data.inode.children + lhs->n_vals + 1, -+ (rhs->n_vals + 1U) * sizeof(ZixBTreeNode*)); -+ -+ // Move middle value up to parent -+ zix_btree_ainsert( -+ n->data.inode.vals, n->n_vals, i, lhs->data.inode.vals[lhs->n_vals]); -+ } -+ -+ // Insert new RHS node in parent at position i -+ zix_btree_ainsert((void**)n->data.inode.children, ++n->n_vals, i + 1U, rhs); -+ -+ return rhs; - } - - #ifdef ZIX_BTREE_SORTED_CHECK - /** Check that `n` is sorted with respect to search key `e`. */ --ZIX_PRIVATE bool -+static bool - zix_btree_node_is_sorted_with_respect_to(const ZixBTree* const t, - const ZixBTreeNode* const n, - const void* const e) - { -- if (n->n_vals <= 1) { -- return true; -- } -+ if (n->n_vals <= 1) { -+ return true; -+ } - -- int cmp = t->cmp(zix_btree_value(n, 0), e, t->cmp_data); -- for (uint16_t i = 1; i < n->n_vals; ++i) { -- const int next_cmp = t->cmp(zix_btree_value(n, i), e, t->cmp_data); -- if ((cmp >= 0 && next_cmp < 0) || -- (cmp > 0 && next_cmp <= 0)) { -- return false; -- } -- cmp = next_cmp; -- } -+ int cmp = t->cmp(zix_btree_value(n, 0), e, t->cmp_data); -+ for (uint16_t i = 1; i < n->n_vals; ++i) { -+ const int next_cmp = t->cmp(zix_btree_value(n, i), e, t->cmp_data); -+ if ((cmp >= 0 && next_cmp < 0) || (cmp > 0 && next_cmp <= 0)) { -+ return false; -+ } -+ cmp = next_cmp; -+ } - -- return true; -+ return true; - } - #endif - - /** Find the first value in `n` that is not less than `e` (lower bound). */ --ZIX_PRIVATE unsigned -+static unsigned - zix_btree_node_find(const ZixBTree* const t, - const ZixBTreeNode* const n, - const void* const e, - bool* const equal) - { - #ifdef ZIX_BTREE_SORTED_CHECK -- assert(zix_btree_node_is_sorted_with_respect_to(t, n, e)); -+ assert(zix_btree_node_is_sorted_with_respect_to(t, n, e)); - #endif - -- unsigned first = 0U; -- unsigned len = n->n_vals; -- while (len > 0) { -- const unsigned half = len >> 1U; -- const unsigned i = first + half; -- const int cmp = t->cmp(zix_btree_value(n, i), e, t->cmp_data); -- if (cmp == 0) { -- *equal = true; -- len = half; // Keep searching for wildcard matches -- } else if (cmp < 0) { -- const unsigned chop = half + 1U; -- first += chop; -- len -= chop; -- } else { -- len = half; -- } -- } -- assert(!*equal || t->cmp(zix_btree_value(n, first), e, t->cmp_data) == 0); -- return first; -+ unsigned first = 0U; -+ unsigned len = n->n_vals; -+ while (len > 0) { -+ const unsigned half = len >> 1U; -+ const unsigned i = first + half; -+ const int cmp = t->cmp(zix_btree_value(n, i), e, t->cmp_data); -+ if (cmp == 0) { -+ *equal = true; -+ len = half; // Keep searching for wildcard matches -+ } else if (cmp < 0) { -+ const unsigned chop = half + 1U; -+ first += chop; -+ len -= chop; -+ } else { -+ len = half; -+ } -+ } -+ -+ assert(!*equal || t->cmp(zix_btree_value(n, first), e, t->cmp_data) == 0); -+ return first; - } - - ZixStatus - zix_btree_insert(ZixBTree* const t, void* const e) - { -- ZixBTreeNode* parent = NULL; // Parent of n -- ZixBTreeNode* n = t->root; // Current node -- unsigned i = 0; // Index of n in parent -- while (n) { -- if (n->n_vals == zix_btree_max_vals(n)) { -- // Node is full, split to ensure there is space for a leaf split -- if (!parent) { -- // Root is full, grow tree upwards -- if (!(parent = zix_btree_node_new(false))) { -- return ZIX_STATUS_NO_MEM; -- } -- t->root = parent; -- parent->data.inode.children[0] = n; -- ++t->height; -- } -- -- ZixBTreeNode* const rhs = zix_btree_split_child(parent, i, n); -- if (!rhs) { -- return ZIX_STATUS_NO_MEM; -- } -- -- const int cmp = t->cmp(parent->data.inode.vals[i], e, t->cmp_data); -- if (cmp == 0) { -- return ZIX_STATUS_EXISTS; -- } else if (cmp < 0) { -- // Move to new RHS -- n = rhs; -- ++i; -- } -- } -- -- assert(!parent || zix_btree_child(parent, i) == n); -- -- bool equal = false; -- i = zix_btree_node_find(t, n, e, &equal); -- if (equal) { -- return ZIX_STATUS_EXISTS; -- } else if (!n->is_leaf) { -- // Descend to child node left of value -- parent = n; -- n = zix_btree_child(n, i); -- } else { -- // Insert into internal node -- zix_btree_ainsert(n->data.leaf.vals, n->n_vals++, i, e); -- break; -- } -- } -- -- ++t->size; -- -- return ZIX_STATUS_SUCCESS; --} -- --ZIX_PRIVATE ZixBTreeIter* -+ ZixBTreeNode* parent = NULL; // Parent of n -+ ZixBTreeNode* n = t->root; // Current node -+ unsigned i = 0; // Index of n in parent -+ while (n) { -+ if (n->n_vals == zix_btree_max_vals(n)) { -+ // Node is full, split to ensure there is space for a leaf split -+ if (!parent) { -+ // Root is full, grow tree upwards -+ if (!(parent = zix_btree_node_new(false))) { -+ return ZIX_STATUS_NO_MEM; -+ } -+ t->root = parent; -+ parent->data.inode.children[0] = n; -+ ++t->height; -+ } -+ -+ ZixBTreeNode* const rhs = zix_btree_split_child(parent, i, n); -+ if (!rhs) { -+ return ZIX_STATUS_NO_MEM; -+ } -+ -+ const int cmp = t->cmp(parent->data.inode.vals[i], e, t->cmp_data); -+ if (cmp == 0) { -+ return ZIX_STATUS_EXISTS; -+ } -+ -+ if (cmp < 0) { -+ // Move to new RHS -+ n = rhs; -+ ++i; -+ } -+ } -+ -+ assert(!parent || zix_btree_child(parent, i) == n); -+ -+ bool equal = false; -+ i = zix_btree_node_find(t, n, e, &equal); -+ if (equal) { -+ return ZIX_STATUS_EXISTS; -+ } -+ -+ if (!n->is_leaf) { -+ // Descend to child node left of value -+ parent = n; -+ n = zix_btree_child(n, i); -+ } else { -+ // Insert into internal node -+ zix_btree_ainsert(n->data.leaf.vals, n->n_vals++, i, e); -+ break; -+ } -+ } -+ -+ ++t->size; -+ -+ return ZIX_STATUS_SUCCESS; -+} -+ -+static ZixBTreeIter* - zix_btree_iter_new(const ZixBTree* const t) - { -- const size_t s = t->height * sizeof(ZixBTreeIterFrame); -+ const size_t s = t->height * sizeof(ZixBTreeIterFrame); - -- ZixBTreeIter* i = (ZixBTreeIter*)calloc(1, sizeof(ZixBTreeIter) + s); -- if (i) { -- i->n_levels = t->height; -- } -- return i; -+ ZixBTreeIter* i = (ZixBTreeIter*)calloc(1, sizeof(ZixBTreeIter) + s); -+ if (i) { -+ i->n_levels = t->height; -+ } -+ return i; - } - --ZIX_PRIVATE void -+static void - zix_btree_iter_set_frame(ZixBTreeIter* const ti, - ZixBTreeNode* const n, - const unsigned i) - { -- if (ti) { -- ti->stack[ti->level].node = n; -- ti->stack[ti->level].index = i; -- } -+ if (ti) { -+ ti->stack[ti->level].node = n; -+ ti->stack[ti->level].index = i; -+ } - } - --ZIX_PRIVATE bool -+static bool - zix_btree_node_is_minimal(ZixBTreeNode* const n) - { -- assert(n->n_vals >= zix_btree_min_vals(n)); -- return n->n_vals == zix_btree_min_vals(n); -+ assert(n->n_vals >= zix_btree_min_vals(n)); -+ return n->n_vals == zix_btree_min_vals(n); - } - - /** Enlarge left child by stealing a value from its right sibling. */ --ZIX_PRIVATE ZixBTreeNode* -+static ZixBTreeNode* - zix_btree_rotate_left(ZixBTreeNode* const parent, const unsigned i) - { -- ZixBTreeNode* const lhs = zix_btree_child(parent, i); -- ZixBTreeNode* const rhs = zix_btree_child(parent, i + 1); -+ ZixBTreeNode* const lhs = zix_btree_child(parent, i); -+ ZixBTreeNode* const rhs = zix_btree_child(parent, i + 1); - -- assert(lhs->is_leaf == rhs->is_leaf); -+ assert(lhs->is_leaf == rhs->is_leaf); - -- if (lhs->is_leaf) { -- // Move parent value to end of LHS -- lhs->data.leaf.vals[lhs->n_vals++] = parent->data.inode.vals[i]; -+ if (lhs->is_leaf) { -+ // Move parent value to end of LHS -+ lhs->data.leaf.vals[lhs->n_vals++] = parent->data.inode.vals[i]; - -- // Move first value in RHS to parent -- parent->data.inode.vals[i] = -- zix_btree_aerase(rhs->data.leaf.vals, rhs->n_vals, 0); -- } else { -- // Move parent value to end of LHS -- lhs->data.inode.vals[lhs->n_vals++] = parent->data.inode.vals[i]; -+ // Move first value in RHS to parent -+ parent->data.inode.vals[i] = -+ zix_btree_aerase(rhs->data.leaf.vals, rhs->n_vals, 0); -+ } else { -+ // Move parent value to end of LHS -+ lhs->data.inode.vals[lhs->n_vals++] = parent->data.inode.vals[i]; - -- // Move first value in RHS to parent -- parent->data.inode.vals[i] = -- zix_btree_aerase(rhs->data.inode.vals, rhs->n_vals, 0); -+ // Move first value in RHS to parent -+ parent->data.inode.vals[i] = -+ zix_btree_aerase(rhs->data.inode.vals, rhs->n_vals, 0); - -- // Move first child pointer from RHS to end of LHS -- lhs->data.inode.children[lhs->n_vals] = (ZixBTreeNode*)zix_btree_aerase( -- (void**)rhs->data.inode.children, rhs->n_vals, 0); -- } -+ // Move first child pointer from RHS to end of LHS -+ lhs->data.inode.children[lhs->n_vals] = (ZixBTreeNode*)zix_btree_aerase( -+ (void**)rhs->data.inode.children, rhs->n_vals, 0); -+ } - -- --rhs->n_vals; -+ --rhs->n_vals; - -- return lhs; -+ return lhs; - } - - /** Enlarge right child by stealing a value from its left sibling. */ --ZIX_PRIVATE ZixBTreeNode* -+static ZixBTreeNode* - zix_btree_rotate_right(ZixBTreeNode* const parent, const unsigned i) - { -- ZixBTreeNode* const lhs = zix_btree_child(parent, i - 1); -- ZixBTreeNode* const rhs = zix_btree_child(parent, i); -+ ZixBTreeNode* const lhs = zix_btree_child(parent, i - 1); -+ ZixBTreeNode* const rhs = zix_btree_child(parent, i); - -- assert(lhs->is_leaf == rhs->is_leaf); -+ assert(lhs->is_leaf == rhs->is_leaf); - -- if (lhs->is_leaf) { -- // Prepend parent value to RHS -- zix_btree_ainsert(rhs->data.leaf.vals, -- rhs->n_vals++, -- 0, -- parent->data.inode.vals[i - 1]); -+ if (lhs->is_leaf) { -+ // Prepend parent value to RHS -+ zix_btree_ainsert( -+ rhs->data.leaf.vals, rhs->n_vals++, 0, parent->data.inode.vals[i - 1]); - -- // Move last value from LHS to parent -- parent->data.inode.vals[i - 1] = lhs->data.leaf.vals[--lhs->n_vals]; -- } else { -- // Prepend parent value to RHS -- zix_btree_ainsert(rhs->data.inode.vals, -- rhs->n_vals++, -- 0, -- parent->data.inode.vals[i - 1]); -+ // Move last value from LHS to parent -+ parent->data.inode.vals[i - 1] = lhs->data.leaf.vals[--lhs->n_vals]; -+ } else { -+ // Prepend parent value to RHS -+ zix_btree_ainsert( -+ rhs->data.inode.vals, rhs->n_vals++, 0, parent->data.inode.vals[i - 1]); - -- // Move last child pointer from LHS and prepend to RHS -- zix_btree_ainsert((void**)rhs->data.inode.children, -- rhs->n_vals, -- 0, -- lhs->data.inode.children[lhs->n_vals]); -+ // Move last child pointer from LHS and prepend to RHS -+ zix_btree_ainsert((void**)rhs->data.inode.children, -+ rhs->n_vals, -+ 0, -+ lhs->data.inode.children[lhs->n_vals]); - -- // Move last value from LHS to parent -- parent->data.inode.vals[i - 1] = lhs->data.inode.vals[--lhs->n_vals]; -- } -+ // Move last value from LHS to parent -+ parent->data.inode.vals[i - 1] = lhs->data.inode.vals[--lhs->n_vals]; -+ } - -- return rhs; -+ return rhs; - } - - /** Move n[i] down, merge the left and right child, return the merged node. */ --ZIX_PRIVATE ZixBTreeNode* -+static ZixBTreeNode* - zix_btree_merge(ZixBTree* const t, ZixBTreeNode* const n, const unsigned i) - { -- ZixBTreeNode* const lhs = zix_btree_child(n, i); -- ZixBTreeNode* const rhs = zix_btree_child(n, i + 1); -- -- assert(lhs->is_leaf == rhs->is_leaf); -- assert(zix_btree_node_is_minimal(lhs)); -- assert(lhs->n_vals + rhs->n_vals < zix_btree_max_vals(lhs)); -- -- // Move parent value to end of LHS -- if (lhs->is_leaf) { -- lhs->data.leaf.vals[lhs->n_vals++] = -- zix_btree_aerase(n->data.inode.vals, n->n_vals, i); -- } else { -- lhs->data.inode.vals[lhs->n_vals++] = -- zix_btree_aerase(n->data.inode.vals, n->n_vals, i); -- } -- -- // Erase corresponding child pointer (to RHS) in parent -- zix_btree_aerase((void**)n->data.inode.children, n->n_vals, i + 1U); -- -- // Add everything from RHS to end of LHS -- if (lhs->is_leaf) { -- memcpy(lhs->data.leaf.vals + lhs->n_vals, -- rhs->data.leaf.vals, -- rhs->n_vals * sizeof(void*)); -- } else { -- memcpy(lhs->data.inode.vals + lhs->n_vals, -- rhs->data.inode.vals, -- rhs->n_vals * sizeof(void*)); -- memcpy(lhs->data.inode.children + lhs->n_vals, -- rhs->data.inode.children, -- (rhs->n_vals + 1U) * sizeof(void*)); -- } -- -- lhs->n_vals = (uint16_t)(lhs->n_vals + rhs->n_vals); -- -- if (--n->n_vals == 0) { -- // Root is now empty, replace it with its only child -- assert(n == t->root); -- t->root = lhs; -- free(n); -- } -- -- free(rhs); -- return lhs; -+ ZixBTreeNode* const lhs = zix_btree_child(n, i); -+ ZixBTreeNode* const rhs = zix_btree_child(n, i + 1); -+ -+ assert(lhs->is_leaf == rhs->is_leaf); -+ assert(zix_btree_node_is_minimal(lhs)); -+ assert(lhs->n_vals + rhs->n_vals < zix_btree_max_vals(lhs)); -+ -+ // Move parent value to end of LHS -+ if (lhs->is_leaf) { -+ lhs->data.leaf.vals[lhs->n_vals++] = -+ zix_btree_aerase(n->data.inode.vals, n->n_vals, i); -+ } else { -+ lhs->data.inode.vals[lhs->n_vals++] = -+ zix_btree_aerase(n->data.inode.vals, n->n_vals, i); -+ } -+ -+ // Erase corresponding child pointer (to RHS) in parent -+ zix_btree_aerase((void**)n->data.inode.children, n->n_vals, i + 1U); -+ -+ // Add everything from RHS to end of LHS -+ if (lhs->is_leaf) { -+ memcpy(lhs->data.leaf.vals + lhs->n_vals, -+ rhs->data.leaf.vals, -+ rhs->n_vals * sizeof(void*)); -+ } else { -+ memcpy(lhs->data.inode.vals + lhs->n_vals, -+ rhs->data.inode.vals, -+ rhs->n_vals * sizeof(void*)); -+ memcpy(lhs->data.inode.children + lhs->n_vals, -+ rhs->data.inode.children, -+ (rhs->n_vals + 1U) * sizeof(void*)); -+ } -+ -+ lhs->n_vals = (uint16_t)(lhs->n_vals + rhs->n_vals); -+ -+ if (--n->n_vals == 0) { -+ // Root is now empty, replace it with its only child -+ assert(n == t->root); -+ t->root = lhs; -+ free(n); -+ } -+ -+ free(rhs); -+ return lhs; - } - - /** Remove and return the min value from the subtree rooted at `n`. */ --ZIX_PRIVATE void* -+static void* - zix_btree_remove_min(ZixBTree* const t, ZixBTreeNode* n) - { -- while (!n->is_leaf) { -- if (zix_btree_node_is_minimal(zix_btree_child(n, 0))) { -- // Leftmost child is minimal, must expand -- if (!zix_btree_node_is_minimal(zix_btree_child(n, 1))) { -- // Child's right sibling has at least one key to steal -- n = zix_btree_rotate_left(n, 0); -- } else { -- // Both child and right sibling are minimal, merge -- n = zix_btree_merge(t, n, 0); -- } -- } else { -- n = zix_btree_child(n, 0); -- } -- } -+ while (!n->is_leaf) { -+ if (zix_btree_node_is_minimal(zix_btree_child(n, 0))) { -+ // Leftmost child is minimal, must expand -+ if (!zix_btree_node_is_minimal(zix_btree_child(n, 1))) { -+ // Child's right sibling has at least one key to steal -+ n = zix_btree_rotate_left(n, 0); -+ } else { -+ // Both child and right sibling are minimal, merge -+ n = zix_btree_merge(t, n, 0); -+ } -+ } else { -+ n = zix_btree_child(n, 0); -+ } -+ } - -- return zix_btree_aerase(n->data.leaf.vals, --n->n_vals, 0); -+ return zix_btree_aerase(n->data.leaf.vals, --n->n_vals, 0); - } - - /** Remove and return the max value from the subtree rooted at `n`. */ --ZIX_PRIVATE void* -+static void* - zix_btree_remove_max(ZixBTree* const t, ZixBTreeNode* n) - { -- while (!n->is_leaf) { -- if (zix_btree_node_is_minimal(zix_btree_child(n, n->n_vals))) { -- // Leftmost child is minimal, must expand -- if (!zix_btree_node_is_minimal(zix_btree_child(n, n->n_vals - 1))) { -- // Child's left sibling has at least one key to steal -- n = zix_btree_rotate_right(n, n->n_vals); -- } else { -- // Both child and left sibling are minimal, merge -- n = zix_btree_merge(t, n, n->n_vals - 1U); -- } -- } else { -- n = zix_btree_child(n, n->n_vals); -- } -- } -+ while (!n->is_leaf) { -+ if (zix_btree_node_is_minimal(zix_btree_child(n, n->n_vals))) { -+ // Leftmost child is minimal, must expand -+ if (!zix_btree_node_is_minimal(zix_btree_child(n, n->n_vals - 1))) { -+ // Child's left sibling has at least one key to steal -+ n = zix_btree_rotate_right(n, n->n_vals); -+ } else { -+ // Both child and left sibling are minimal, merge -+ n = zix_btree_merge(t, n, n->n_vals - 1U); -+ } -+ } else { -+ n = zix_btree_child(n, n->n_vals); -+ } -+ } - -- return n->data.leaf.vals[--n->n_vals]; -+ return n->data.leaf.vals[--n->n_vals]; - } - - ZixStatus -@@ -604,120 +599,120 @@ zix_btree_remove(ZixBTree* const t, - void** const out, - ZixBTreeIter** const next) - { -- ZixBTreeNode* n = t->root; -- ZixBTreeIter* ti = NULL; -- const bool user_iter = next && *next; -- if (next) { -- if (!*next && !(*next = zix_btree_iter_new(t))) { -- return ZIX_STATUS_NO_MEM; -- } -- ti = *next; -- ti->level = 0; -- } -- -- while (true) { -- /* To remove in a single walk down, the tree is adjusted along the way -- so that the current node always has at least one more value than the -- minimum required in general. Thus, there is always room to remove -- without adjusting on the way back up. */ -- assert(n == t->root || !zix_btree_node_is_minimal(n)); -- -- bool equal = false; -- const unsigned i = zix_btree_node_find(t, n, e, &equal); -- zix_btree_iter_set_frame(ti, n, i); -- if (n->is_leaf) { -- if (equal) { -- // Found in leaf node -- *out = zix_btree_aerase(n->data.leaf.vals, --n->n_vals, i); -- if (ti && i == n->n_vals) { -- if (i == 0) { -- ti->level = 0; -- ti->stack[0].node = NULL; -- } else { -- --ti->stack[ti->level].index; -- zix_btree_iter_increment(ti); -- } -- } -- --t->size; -- return ZIX_STATUS_SUCCESS; -- } else { -- // Not found in leaf node, or tree -- if (ti && !user_iter) { -- zix_btree_iter_free(ti); -- *next = NULL; -- } -- return ZIX_STATUS_NOT_FOUND; -- } -- } else if (equal) { -- // Found in internal node -- ZixBTreeNode* const lhs = zix_btree_child(n, i); -- ZixBTreeNode* const rhs = zix_btree_child(n, i + 1); -- const size_t l_size = lhs->n_vals; -- const size_t r_size = rhs->n_vals; -- if (zix_btree_node_is_minimal(lhs) && -- zix_btree_node_is_minimal(rhs)) { -- // Both preceding and succeeding child are minimal -- n = zix_btree_merge(t, n, i); -- } else if (l_size >= r_size) { -- // Left child can remove without merge -- assert(!zix_btree_node_is_minimal(lhs)); -- *out = n->data.inode.vals[i]; -- n->data.inode.vals[i] = zix_btree_remove_max(t, lhs); -- --t->size; -- return ZIX_STATUS_SUCCESS; -- } else { -- // Right child can remove without merge -- assert(!zix_btree_node_is_minimal(rhs)); -- *out = n->data.inode.vals[i]; -- n->data.inode.vals[i] = zix_btree_remove_min(t, rhs); -- --t->size; -- return ZIX_STATUS_SUCCESS; -- } -- } else { -- // Not found in internal node, key is in/under children[i] -- if (zix_btree_node_is_minimal(zix_btree_child(n, i))) { -- if (i > 0 && -- !zix_btree_node_is_minimal(zix_btree_child(n, i - 1))) { -- // Steal a key from child's left sibling -- n = zix_btree_rotate_right(n, i); -- } else if (i < n->n_vals && -- !zix_btree_node_is_minimal( -- zix_btree_child(n, i + 1))) { -- // Steal a key from child's right sibling -- n = zix_btree_rotate_left(n, i); -- } else if (n == t->root && n->n_vals == 1) { -- // Root has two children, both minimal, delete it -- assert(i == 0 || i == 1); -- const uint16_t counts[2] = {zix_btree_child(n, 0)->n_vals, -- zix_btree_child(n, 1)->n_vals}; -- -- n = zix_btree_merge(t, n, 0); -- if (ti) { -- ti->stack[ti->level].node = n; -- ti->stack[ti->level].index = counts[i]; -- } -- } else { -- // Both child's siblings are minimal, merge them -- if (i < n->n_vals) { -- n = zix_btree_merge(t, n, i); -- } else { -- n = zix_btree_merge(t, n, i - 1U); -- if (ti) { -- --ti->stack[ti->level].index; -- } -- } -- } -- } else { -- n = zix_btree_child(n, i); -- } -- } -- if (ti) { -- ++ti->level; -- } -- } -- -- assert(false); // Not reached -- return ZIX_STATUS_ERROR; -+ ZixBTreeNode* n = t->root; -+ ZixBTreeIter* ti = NULL; -+ const bool user_iter = next && *next; -+ if (next) { -+ if (!*next && !(*next = zix_btree_iter_new(t))) { -+ return ZIX_STATUS_NO_MEM; -+ } -+ ti = *next; -+ ti->level = 0; -+ } -+ -+ while (true) { -+ /* To remove in a single walk down, the tree is adjusted along the way -+ so that the current node always has at least one more value than the -+ minimum required in general. Thus, there is always room to remove -+ without adjusting on the way back up. */ -+ assert(n == t->root || !zix_btree_node_is_minimal(n)); -+ -+ bool equal = false; -+ const unsigned i = zix_btree_node_find(t, n, e, &equal); -+ zix_btree_iter_set_frame(ti, n, i); -+ if (n->is_leaf) { -+ if (equal) { -+ // Found in leaf node -+ *out = zix_btree_aerase(n->data.leaf.vals, --n->n_vals, i); -+ if (ti && i == n->n_vals) { -+ if (i == 0) { -+ ti->level = 0; -+ ti->stack[0].node = NULL; -+ } else { -+ --ti->stack[ti->level].index; -+ zix_btree_iter_increment(ti); -+ } -+ } -+ --t->size; -+ return ZIX_STATUS_SUCCESS; -+ } -+ -+ // Not found in leaf node, or tree -+ if (ti && !user_iter) { -+ zix_btree_iter_free(ti); -+ *next = NULL; -+ } -+ -+ return ZIX_STATUS_NOT_FOUND; -+ } -+ -+ if (equal) { -+ // Found in internal node -+ ZixBTreeNode* const lhs = zix_btree_child(n, i); -+ ZixBTreeNode* const rhs = zix_btree_child(n, i + 1); -+ const size_t l_size = lhs->n_vals; -+ const size_t r_size = rhs->n_vals; -+ if (zix_btree_node_is_minimal(lhs) && zix_btree_node_is_minimal(rhs)) { -+ // Both preceding and succeeding child are minimal -+ n = zix_btree_merge(t, n, i); -+ } else if (l_size >= r_size) { -+ // Left child can remove without merge -+ assert(!zix_btree_node_is_minimal(lhs)); -+ *out = n->data.inode.vals[i]; -+ n->data.inode.vals[i] = zix_btree_remove_max(t, lhs); -+ --t->size; -+ return ZIX_STATUS_SUCCESS; -+ } else { -+ // Right child can remove without merge -+ assert(!zix_btree_node_is_minimal(rhs)); -+ *out = n->data.inode.vals[i]; -+ n->data.inode.vals[i] = zix_btree_remove_min(t, rhs); -+ --t->size; -+ return ZIX_STATUS_SUCCESS; -+ } -+ } else { -+ // Not found in internal node, key is in/under children[i] -+ if (zix_btree_node_is_minimal(zix_btree_child(n, i))) { -+ if (i > 0 && !zix_btree_node_is_minimal(zix_btree_child(n, i - 1))) { -+ // Steal a key from child's left sibling -+ n = zix_btree_rotate_right(n, i); -+ } else if (i < n->n_vals && -+ !zix_btree_node_is_minimal(zix_btree_child(n, i + 1))) { -+ // Steal a key from child's right sibling -+ n = zix_btree_rotate_left(n, i); -+ } else if (n == t->root && n->n_vals == 1) { -+ // Root has two children, both minimal, delete it -+ assert(i == 0 || i == 1); -+ const uint16_t counts[2] = {zix_btree_child(n, 0)->n_vals, -+ zix_btree_child(n, 1)->n_vals}; -+ -+ n = zix_btree_merge(t, n, 0); -+ if (ti) { -+ ti->stack[ti->level].node = n; -+ ti->stack[ti->level].index = counts[i]; -+ } -+ } else { -+ // Both child's siblings are minimal, merge them -+ if (i < n->n_vals) { -+ n = zix_btree_merge(t, n, i); -+ } else { -+ n = zix_btree_merge(t, n, i - 1U); -+ if (ti) { -+ --ti->stack[ti->level].index; -+ } -+ } -+ } -+ } else { -+ n = zix_btree_child(n, i); -+ } -+ } -+ if (ti) { -+ ++ti->level; -+ } -+ } -+ -+ assert(false); // Not reached -+ return ZIX_STATUS_ERROR; - } - - ZixStatus -@@ -725,30 +720,32 @@ zix_btree_find(const ZixBTree* const t, - const void* const e, - ZixBTreeIter** const ti) - { -- ZixBTreeNode* n = t->root; -- if (!(*ti = zix_btree_iter_new(t))) { -- return ZIX_STATUS_NO_MEM; -- } -+ ZixBTreeNode* n = t->root; -+ if (!(*ti = zix_btree_iter_new(t))) { -+ return ZIX_STATUS_NO_MEM; -+ } -+ -+ while (n) { -+ bool equal = false; -+ const unsigned i = zix_btree_node_find(t, n, e, &equal); -+ -+ zix_btree_iter_set_frame(*ti, n, i); - -- while (n) { -- bool equal = false; -- const unsigned i = zix_btree_node_find(t, n, e, &equal); -+ if (equal) { -+ return ZIX_STATUS_SUCCESS; -+ } - -- zix_btree_iter_set_frame(*ti, n, i); -+ if (n->is_leaf) { -+ break; -+ } - -- if (equal) { -- return ZIX_STATUS_SUCCESS; -- } else if (n->is_leaf) { -- break; -- } else { -- ++(*ti)->level; -- n = zix_btree_child(n, i); -- } -- } -+ ++(*ti)->level; -+ n = zix_btree_child(n, i); -+ } - -- zix_btree_iter_free(*ti); -- *ti = NULL; -- return ZIX_STATUS_NOT_FOUND; -+ zix_btree_iter_free(*ti); -+ *ti = NULL; -+ return ZIX_STATUS_NOT_FOUND; - } - - ZixStatus -@@ -756,175 +753,184 @@ zix_btree_lower_bound(const ZixBTree* const t, - const void* const e, - ZixBTreeIter** const ti) - { -- if (!t) { -- *ti = NULL; -- return ZIX_STATUS_BAD_ARG; -- } else if (!t->root) { -- *ti = NULL; -- return ZIX_STATUS_SUCCESS; -- } -- -- ZixBTreeNode* n = t->root; -- bool found = false; -- unsigned found_level = 0; -- if (!(*ti = zix_btree_iter_new(t))) { -- return ZIX_STATUS_NO_MEM; -- } -- -- while (n) { -- bool equal = false; -- const unsigned i = zix_btree_node_find(t, n, e, &equal); -- -- zix_btree_iter_set_frame(*ti, n, i); -- -- if (equal) { -- found_level = (*ti)->level; -- found = true; -- } -- -- if (n->is_leaf) { -- break; -- } else { -- ++(*ti)->level; -- n = zix_btree_child(n, i); -- assert(n); -- } -- } -- -- const ZixBTreeIterFrame* const frame = &(*ti)->stack[(*ti)->level]; -- assert(frame->node); -- if (frame->index == frame->node->n_vals) { -- if (found) { -- // Found on a previous level but went too far -- (*ti)->level = found_level; -- } else { -- // Reached end (key is greater than everything in tree) -- (*ti)->level = 0; -- (*ti)->stack[0].node = NULL; -- } -- } -- -- return ZIX_STATUS_SUCCESS; -+ if (!t) { -+ *ti = NULL; -+ return ZIX_STATUS_BAD_ARG; -+ } -+ -+ if (!t->root) { -+ *ti = NULL; -+ return ZIX_STATUS_SUCCESS; -+ } -+ -+ ZixBTreeNode* n = t->root; -+ bool found = false; -+ unsigned found_level = 0; -+ if (!(*ti = zix_btree_iter_new(t))) { -+ return ZIX_STATUS_NO_MEM; -+ } -+ -+ while (n) { -+ bool equal = false; -+ const unsigned i = zix_btree_node_find(t, n, e, &equal); -+ -+ zix_btree_iter_set_frame(*ti, n, i); -+ -+ if (equal) { -+ found_level = (*ti)->level; -+ found = true; -+ } -+ -+ if (n->is_leaf) { -+ break; -+ } -+ -+ ++(*ti)->level; -+ n = zix_btree_child(n, i); -+ assert(n); -+ } -+ -+ const ZixBTreeIterFrame* const frame = &(*ti)->stack[(*ti)->level]; -+ assert(frame->node); -+ if (frame->index == frame->node->n_vals) { -+ if (found) { -+ // Found on a previous level but went too far -+ (*ti)->level = found_level; -+ } else { -+ // Reached end (key is greater than everything in tree) -+ (*ti)->level = 0; -+ (*ti)->stack[0].node = NULL; -+ } -+ } -+ -+ return ZIX_STATUS_SUCCESS; - } - - void* - zix_btree_get(const ZixBTreeIter* const ti) - { -- const ZixBTreeIterFrame* const frame = &ti->stack[ti->level]; -- assert(frame->node); -- assert(frame->index < frame->node->n_vals); -- return zix_btree_value(frame->node, frame->index); -+ const ZixBTreeIterFrame* const frame = &ti->stack[ti->level]; -+ assert(frame->node); -+ assert(frame->index < frame->node->n_vals); -+ return zix_btree_value(frame->node, frame->index); - } - - ZixBTreeIter* - zix_btree_begin(const ZixBTree* const t) - { -- ZixBTreeIter* const i = zix_btree_iter_new(t); -- if (!i) { -- return NULL; -- } else if (t->size == 0) { -- i->level = 0; -- i->stack[0].node = NULL; -- } else { -- ZixBTreeNode* n = t->root; -- i->stack[0].node = n; -- i->stack[0].index = 0; -- while (!n->is_leaf) { -- n = zix_btree_child(n, 0); -- ++i->level; -- i->stack[i->level].node = n; -- i->stack[i->level].index = 0; -- } -- } -- return i; -+ ZixBTreeIter* const i = zix_btree_iter_new(t); -+ if (!i) { -+ return NULL; -+ } -+ -+ if (t->size == 0) { -+ i->level = 0; -+ i->stack[0].node = NULL; -+ } else { -+ ZixBTreeNode* n = t->root; -+ i->stack[0].node = n; -+ i->stack[0].index = 0; -+ while (!n->is_leaf) { -+ n = zix_btree_child(n, 0); -+ ++i->level; -+ i->stack[i->level].node = n; -+ i->stack[i->level].index = 0; -+ } -+ } -+ -+ return i; - } - - ZixBTreeIter* - zix_btree_end(const ZixBTree* const t) - { -- return zix_btree_iter_new(t); -+ return zix_btree_iter_new(t); - } - - ZixBTreeIter* - zix_btree_iter_copy(const ZixBTreeIter* const i) - { -- if (!i) { -- return NULL; -- } -+ if (!i) { -+ return NULL; -+ } - -- const size_t s = i->n_levels * sizeof(ZixBTreeIterFrame); -- ZixBTreeIter* j = (ZixBTreeIter*)calloc(1, sizeof(ZixBTreeIter) + s); -- if (j) { -- memcpy(j, i, sizeof(ZixBTreeIter) + s); -- } -- return j; -+ const size_t s = i->n_levels * sizeof(ZixBTreeIterFrame); -+ ZixBTreeIter* j = (ZixBTreeIter*)calloc(1, sizeof(ZixBTreeIter) + s); -+ if (j) { -+ memcpy(j, i, sizeof(ZixBTreeIter) + s); -+ } -+ -+ return j; - } - - bool - zix_btree_iter_is_end(const ZixBTreeIter* const i) - { -- return !i || i->stack[0].node == NULL; -+ return !i || (i->level == 0 && i->stack[0].node == NULL); - } - - bool --zix_btree_iter_equals(const ZixBTreeIter* const lhs, const ZixBTreeIter* const rhs) -+zix_btree_iter_equals(const ZixBTreeIter* const lhs, -+ const ZixBTreeIter* const rhs) - { -- if (zix_btree_iter_is_end(lhs) && zix_btree_iter_is_end(rhs)) { -- return true; -- } else if (zix_btree_iter_is_end(lhs) || zix_btree_iter_is_end(rhs) || -- lhs->level != rhs->level) { -- return false; -- } -+ if (zix_btree_iter_is_end(lhs) && zix_btree_iter_is_end(rhs)) { -+ return true; -+ } -+ -+ if (zix_btree_iter_is_end(lhs) || zix_btree_iter_is_end(rhs) || -+ lhs->level != rhs->level) { -+ return false; -+ } - -- return !memcmp(lhs, -- rhs, -- sizeof(ZixBTreeIter) + -- (lhs->level + 1) * sizeof(ZixBTreeIterFrame)); -+ return !memcmp(lhs, -+ rhs, -+ sizeof(ZixBTreeIter) + -+ (lhs->level + 1) * sizeof(ZixBTreeIterFrame)); - } - - void - zix_btree_iter_increment(ZixBTreeIter* const i) - { -- ZixBTreeIterFrame* f = &i->stack[i->level]; -- if (f->node->is_leaf) { -- // Leaf, move right -- assert(f->index < f->node->n_vals); -- if (++f->index == f->node->n_vals) { -- // Reached end of leaf, move up -- f = &i->stack[i->level]; -- while (i->level > 0 && f->index == f->node->n_vals) { -- f = &i->stack[--i->level]; -- assert(f->index <= f->node->n_vals); -- } -- -- if (f->index == f->node->n_vals) { -- // Reached end of tree -- assert(i->level == 0); -- f->node = NULL; -- f->index = 0; -- } -- } -- } else { -- // Internal node, move down to next child -- assert(f->index < f->node->n_vals); -- ZixBTreeNode* child = zix_btree_child(f->node, ++f->index); -- -- f = &i->stack[++i->level]; -- f->node = child; -- f->index = 0; -- -- // Move down and left until we hit a leaf -- while (!f->node->is_leaf) { -- child = zix_btree_child(f->node, 0); -- f = &i->stack[++i->level]; -- f->node = child; -- f->index = 0; -- } -- } -+ ZixBTreeIterFrame* f = &i->stack[i->level]; -+ if (f->node->is_leaf) { -+ // Leaf, move right -+ assert(f->index < f->node->n_vals); -+ if (++f->index == f->node->n_vals) { -+ // Reached end of leaf, move up -+ f = &i->stack[i->level]; -+ while (i->level > 0 && f->index == f->node->n_vals) { -+ f = &i->stack[--i->level]; -+ assert(f->index <= f->node->n_vals); -+ } -+ -+ if (f->index == f->node->n_vals) { -+ // Reached end of tree -+ assert(i->level == 0); -+ f->node = NULL; -+ f->index = 0; -+ } -+ } -+ } else { -+ // Internal node, move down to next child -+ assert(f->index < f->node->n_vals); -+ ZixBTreeNode* child = zix_btree_child(f->node, ++f->index); -+ -+ f = &i->stack[++i->level]; -+ f->node = child; -+ f->index = 0; -+ -+ // Move down and left until we hit a leaf -+ while (!f->node->is_leaf) { -+ child = zix_btree_child(f->node, 0); -+ f = &i->stack[++i->level]; -+ f->node = child; -+ f->index = 0; -+ } -+ } - } - - void - zix_btree_iter_free(ZixBTreeIter* const i) - { -- free(i); -+ free(i); - } -diff --git a/src/zix/btree.h b/src/zix/btree.h -index 6333a91..bec0698 100644 ---- a/src/zix/btree.h -+++ b/src/zix/btree.h -@@ -1,5 +1,5 @@ - /* -- Copyright 2011-2016 David Robillard -+ Copyright 2011-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above -@@ -54,27 +54,29 @@ typedef struct ZixBTreeIterImpl ZixBTreeIter; - /** - Create a new (empty) B-Tree. - */ --ZIX_API ZixBTree* --zix_btree_new(ZixComparator cmp, -- const void* cmp_data, -- ZixDestroyFunc destroy); -+ZIX_API -+ZixBTree* -+zix_btree_new(ZixComparator cmp, const void* cmp_data, ZixDestroyFunc destroy); - - /** - Free `t`. - */ --ZIX_API void -+ZIX_API -+void - zix_btree_free(ZixBTree* t); - - /** - Return the number of elements in `t`. - */ --ZIX_PURE_API size_t -+ZIX_PURE_API -+size_t - zix_btree_size(const ZixBTree* t); - - /** - Insert the element `e` into `t`. - */ --ZIX_API ZixStatus -+ZIX_API -+ZixStatus - zix_btree_insert(ZixBTree* t, void* e); - - /** -@@ -90,14 +92,16 @@ zix_btree_insert(ZixBTree* t, void* e); - also non-NULL, the iterator is reused, otherwise a new one is allocated. To - reuse an iterator, no items may have been added since its creation. - */ --ZIX_API ZixStatus -+ZIX_API -+ZixStatus - zix_btree_remove(ZixBTree* t, const void* e, void** out, ZixBTreeIter** next); - - /** - Set `ti` to an element equal to `e` in `t`. - If no such item exists, `ti` is set to NULL. - */ --ZIX_API ZixStatus -+ZIX_API -+ZixStatus - zix_btree_find(const ZixBTree* t, const void* e, ZixBTreeIter** ti); - - /** -@@ -107,13 +111,15 @@ zix_btree_find(const ZixBTree* t, const void* e, ZixBTreeIter** ti); - values in the tree, `ti` will be set to the least such element. The search - key `e` is always passed as the second argument to the comparator. - */ --ZIX_API ZixStatus -+ZIX_API -+ZixStatus - zix_btree_lower_bound(const ZixBTree* t, const void* e, ZixBTreeIter** ti); - - /** - Return the data associated with the given tree item. - */ --ZIX_PURE_API void* -+ZIX_PURE_API -+void* - zix_btree_get(const ZixBTreeIter* ti); - - /** -@@ -121,7 +127,8 @@ zix_btree_get(const ZixBTreeIter* ti); - - The returned iterator must be freed with zix_btree_iter_free(). - */ --ZIX_PURE_API ZixBTreeIter* -+ZIX_PURE_API -+ZixBTreeIter* - zix_btree_begin(const ZixBTree* t); - - /** -@@ -129,37 +136,43 @@ zix_btree_begin(const ZixBTree* t); - - The returned iterator must be freed with zix_btree_iter_free(). - */ --ZIX_API ZixBTreeIter* -+ZIX_API -+ZixBTreeIter* - zix_btree_end(const ZixBTree* t); - - /** - Return a new copy of `i`. - */ --ZIX_API ZixBTreeIter* -+ZIX_API -+ZixBTreeIter* - zix_btree_iter_copy(const ZixBTreeIter* i); - - /** - Return true iff `lhs` is equal to `rhs`. - */ --ZIX_PURE_API bool -+ZIX_PURE_API -+bool - zix_btree_iter_equals(const ZixBTreeIter* lhs, const ZixBTreeIter* rhs); - - /** - Return true iff `i` is an iterator to the end of its tree. - */ --ZIX_PURE_API bool -+ZIX_PURE_API -+bool - zix_btree_iter_is_end(const ZixBTreeIter* i); - - /** - Increment `i` to point to the next element in the tree. - */ --ZIX_API void -+ZIX_API -+void - zix_btree_iter_increment(ZixBTreeIter* i); - - /** - Free `i`. - */ --ZIX_API void -+ZIX_API -+void - zix_btree_iter_free(ZixBTreeIter* i); - - /** -@@ -168,7 +181,7 @@ zix_btree_iter_free(ZixBTreeIter* i); - */ - - #ifdef __cplusplus --} /* extern "C" */ -+} /* extern "C" */ - #endif - --#endif /* ZIX_BTREE_H */ -+#endif /* ZIX_BTREE_H */ -diff --git a/src/zix/common.h b/src/zix/common.h -index cf07451..d47586c 100644 ---- a/src/zix/common.h -+++ b/src/zix/common.h -@@ -1,5 +1,5 @@ - /* -- Copyright 2016 David Robillard -+ Copyright 2016-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above -@@ -25,41 +25,37 @@ - */ - - /** @cond */ --#ifdef ZIX_SHARED --# ifdef _WIN32 --# define ZIX_LIB_IMPORT __declspec(dllimport) --# define ZIX_LIB_EXPORT __declspec(dllexport) --# else --# define ZIX_LIB_IMPORT __attribute__((visibility("default"))) --# define ZIX_LIB_EXPORT __attribute__((visibility("default"))) --# endif --# ifdef ZIX_INTERNAL --# define ZIX_API ZIX_LIB_EXPORT --# else --# define ZIX_API ZIX_LIB_IMPORT --# endif --# define ZIX_PRIVATE static --#elif defined(ZIX_INLINE) --# define ZIX_API static inline --# define ZIX_PRIVATE static inline -+#if defined(_WIN32) && !defined(ZIX_STATIC) && defined(ZIX_INTERNAL) -+# define ZIX_API __declspec(dllexport) -+#elif defined(_WIN32) && !defined(ZIX_STATIC) -+# define ZIX_API __declspec(dllimport) -+#elif defined(__GNUC__) -+# define ZIX_API __attribute__((visibility("default"))) - #else --# define ZIX_API --# define ZIX_PRIVATE static -+# define ZIX_API - #endif - - #ifdef __GNUC__ --# define ZIX_PURE_FUNC __attribute__((pure)) --# define ZIX_CONST_FUNC __attribute__((const)) --# define ZIX_MALLOC_FUNC __attribute__((malloc)) -+# define ZIX_PURE_FUNC __attribute__((pure)) -+# define ZIX_CONST_FUNC __attribute__((const)) -+# define ZIX_MALLOC_FUNC __attribute__((malloc)) - #else --# define ZIX_PURE_FUNC --# define ZIX_CONST_FUNC --# define ZIX_MALLOC_FUNC -+# define ZIX_PURE_FUNC -+# define ZIX_CONST_FUNC -+# define ZIX_MALLOC_FUNC - #endif - --#define ZIX_PURE_API ZIX_API ZIX_PURE_FUNC --#define ZIX_CONST_API ZIX_API ZIX_CONST_FUNC --#define ZIX_MALLOC_API ZIX_API ZIX_MALLOC_FUNC -+#define ZIX_PURE_API \ -+ ZIX_API \ -+ ZIX_PURE_FUNC -+ -+#define ZIX_CONST_API \ -+ ZIX_API \ -+ ZIX_CONST_FUNC -+ -+#define ZIX_MALLOC_API \ -+ ZIX_API \ -+ ZIX_MALLOC_FUNC - - /** @endcond */ - -@@ -68,43 +64,50 @@ extern "C" { - #endif - - #ifdef __GNUC__ --#define ZIX_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) -+# define ZIX_LOG_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) - #else --#define ZIX_LOG_FUNC(fmt, arg1) -+# define ZIX_LOG_FUNC(fmt, arg1) - #endif - - // Unused parameter macro to suppresses warnings and make it impossible to use - #if defined(__cplusplus) --# define ZIX_UNUSED(name) -+# define ZIX_UNUSED(name) - #elif defined(__GNUC__) --# define ZIX_UNUSED(name) name##_unused __attribute__((__unused__)) -+# define ZIX_UNUSED(name) name##_unused __attribute__((__unused__)) - #else --# define ZIX_UNUSED(name) name -+# define ZIX_UNUSED(name) name - #endif - - typedef enum { -- ZIX_STATUS_SUCCESS, -- ZIX_STATUS_ERROR, -- ZIX_STATUS_NO_MEM, -- ZIX_STATUS_NOT_FOUND, -- ZIX_STATUS_EXISTS, -- ZIX_STATUS_BAD_ARG, -- ZIX_STATUS_BAD_PERMS -+ ZIX_STATUS_SUCCESS, -+ ZIX_STATUS_ERROR, -+ ZIX_STATUS_NO_MEM, -+ ZIX_STATUS_NOT_FOUND, -+ ZIX_STATUS_EXISTS, -+ ZIX_STATUS_BAD_ARG, -+ ZIX_STATUS_BAD_PERMS - } ZixStatus; - - static inline const char* - zix_strerror(const ZixStatus status) - { -- switch (status) { -- case ZIX_STATUS_SUCCESS: return "Success"; -- case ZIX_STATUS_ERROR: return "Unknown error"; -- case ZIX_STATUS_NO_MEM: return "Out of memory"; -- case ZIX_STATUS_NOT_FOUND: return "Not found"; -- case ZIX_STATUS_EXISTS: return "Exists"; -- case ZIX_STATUS_BAD_ARG: return "Bad argument"; -- case ZIX_STATUS_BAD_PERMS: return "Bad permissions"; -- } -- return "Unknown error"; -+ switch (status) { -+ case ZIX_STATUS_SUCCESS: -+ return "Success"; -+ case ZIX_STATUS_ERROR: -+ return "Unknown error"; -+ case ZIX_STATUS_NO_MEM: -+ return "Out of memory"; -+ case ZIX_STATUS_NOT_FOUND: -+ return "Not found"; -+ case ZIX_STATUS_EXISTS: -+ return "Exists"; -+ case ZIX_STATUS_BAD_ARG: -+ return "Bad argument"; -+ case ZIX_STATUS_BAD_PERMS: -+ return "Bad permissions"; -+ } -+ return "Unknown error"; - } - - /** -@@ -129,7 +132,7 @@ typedef void (*ZixDestroyFunc)(void* ptr); - */ - - #ifdef __cplusplus --} /* extern "C" */ -+} /* extern "C" */ - #endif - --#endif /* ZIX_COMMON_H */ -+#endif /* ZIX_COMMON_H */ -diff --git a/src/zix/digest.c b/src/zix/digest.c -index 8d08ae2..47d27b9 100644 ---- a/src/zix/digest.c -+++ b/src/zix/digest.c -@@ -17,7 +17,7 @@ - #include "zix/digest.h" - - #ifdef __SSE4_2__ --# include -+# include - #endif - - #include -@@ -30,75 +30,75 @@ - uint32_t - zix_digest_start(void) - { -- return 1; -+ return 1; - } - - uint32_t - zix_digest_add(uint32_t hash, const void* const buf, const size_t len) - { -- const uint8_t* str = (const uint8_t*)buf; -- --#ifdef __x86_64__ -- for (size_t i = 0; i < (len / sizeof(uint64_t)); ++i) { -- hash = (uint32_t)_mm_crc32_u64(hash, *(const uint64_t*)str); -- str += sizeof(uint64_t); -- } -- if (len & sizeof(uint32_t)) { -- hash = _mm_crc32_u32(hash, *(const uint32_t*)str); -- str += sizeof(uint32_t); -- } --#else -- for (size_t i = 0; i < (len / sizeof(uint32_t)); ++i) { -- hash = _mm_crc32_u32(hash, *(const uint32_t*)str); -- str += sizeof(uint32_t); -- } --#endif -- if (len & sizeof(uint16_t)) { -- hash = _mm_crc32_u16(hash, *(const uint16_t*)str); -- str += sizeof(uint16_t); -- } -- if (len & sizeof(uint8_t)) { -- hash = _mm_crc32_u8(hash, *(const uint8_t*)str); -- } -- -- return hash; -+ const uint8_t* str = (const uint8_t*)buf; -+ -+# ifdef __x86_64__ -+ for (size_t i = 0; i < (len / sizeof(uint64_t)); ++i) { -+ hash = (uint32_t)_mm_crc32_u64(hash, *(const uint64_t*)str); -+ str += sizeof(uint64_t); -+ } -+ if (len & sizeof(uint32_t)) { -+ hash = _mm_crc32_u32(hash, *(const uint32_t*)str); -+ str += sizeof(uint32_t); -+ } -+# else -+ for (size_t i = 0; i < (len / sizeof(uint32_t)); ++i) { -+ hash = _mm_crc32_u32(hash, *(const uint32_t*)str); -+ str += sizeof(uint32_t); -+ } -+# endif -+ if (len & sizeof(uint16_t)) { -+ hash = _mm_crc32_u16(hash, *(const uint16_t*)str); -+ str += sizeof(uint16_t); -+ } -+ if (len & sizeof(uint8_t)) { -+ hash = _mm_crc32_u8(hash, *(const uint8_t*)str); -+ } -+ -+ return hash; - } - - uint32_t - zix_digest_add_64(uint32_t hash, const void* const buf, const size_t len) - { -- assert((uintptr_t)buf % sizeof(uint64_t) == 0); -- assert(len % sizeof(uint64_t) == 0); -+ assert((uintptr_t)buf % sizeof(uint64_t) == 0); -+ assert(len % sizeof(uint64_t) == 0); - --#ifdef __x86_64__ -- const uint64_t* ptr = (const uint64_t*)buf; -+# ifdef __x86_64__ -+ const uint64_t* ptr = (const uint64_t*)buf; - -- for (size_t i = 0; i < (len / sizeof(uint64_t)); ++i) { -- hash = (uint32_t)_mm_crc32_u64(hash, *ptr); -- ++ptr; -- } -+ for (size_t i = 0; i < (len / sizeof(uint64_t)); ++i) { -+ hash = (uint32_t)_mm_crc32_u64(hash, *ptr); -+ ++ptr; -+ } - -- return hash; --#else -- const uint32_t* ptr = (const uint32_t*)buf; -+ return hash; -+# else -+ const uint32_t* ptr = (const uint32_t*)buf; - -- for (size_t i = 0; i < (len / sizeof(uint32_t)); ++i) { -- hash = _mm_crc32_u32(hash, *ptr); -- ++ptr; -- } -+ for (size_t i = 0; i < (len / sizeof(uint32_t)); ++i) { -+ hash = _mm_crc32_u32(hash, *ptr); -+ ++ptr; -+ } - -- return hash; --#endif -+ return hash; -+# endif - } - - uint32_t - zix_digest_add_ptr(const uint32_t hash, const void* const ptr) - { --#ifdef __x86_64__ -- return (uint32_t)_mm_crc32_u64(hash, (uintptr_t)ptr); --#else -- return _mm_crc32_u32(hash, (uintptr_t)ptr); --#endif -+# ifdef __x86_64__ -+ return (uint32_t)_mm_crc32_u64(hash, (uintptr_t)ptr); -+# else -+ return _mm_crc32_u32(hash, (uintptr_t)ptr); -+# endif - } - - #else -@@ -108,34 +108,34 @@ zix_digest_add_ptr(const uint32_t hash, const void* const ptr) - uint32_t - zix_digest_start(void) - { -- return 5381; -+ return 5381; - } - - uint32_t - zix_digest_add(uint32_t hash, const void* const buf, const size_t len) - { -- const uint8_t* str = (const uint8_t*)buf; -+ const uint8_t* str = (const uint8_t*)buf; - -- for (size_t i = 0; i < len; ++i) { -- hash = (hash << 5u) + hash + str[i]; -- } -+ for (size_t i = 0; i < len; ++i) { -+ hash = (hash << 5u) + hash + str[i]; -+ } - -- return hash; -+ return hash; - } - - uint32_t - zix_digest_add_64(uint32_t hash, const void* const buf, const size_t len) - { -- assert((uintptr_t)buf % sizeof(uint64_t) == 0); -- assert(len % sizeof(uint64_t) == 0); -+ assert((uintptr_t)buf % sizeof(uint64_t) == 0); -+ assert(len % sizeof(uint64_t) == 0); - -- return zix_digest_add(hash, buf, len); -+ return zix_digest_add(hash, buf, len); - } - - uint32_t - zix_digest_add_ptr(const uint32_t hash, const void* const ptr) - { -- return zix_digest_add(hash, &ptr, sizeof(ptr)); -+ return zix_digest_add(hash, &ptr, sizeof(ptr)); - } - - #endif -diff --git a/src/zix/digest.h b/src/zix/digest.h -index 74d13f9..1fde77a 100644 ---- a/src/zix/digest.h -+++ b/src/zix/digest.h -@@ -29,7 +29,8 @@ extern "C" { - /** - Return an initial empty digest value. - */ --ZIX_CONST_API uint32_t -+ZIX_CONST_API -+uint32_t - zix_digest_start(void); - - /** -@@ -37,7 +38,8 @@ zix_digest_start(void); - - This can be used for any size or alignment. - */ --ZIX_PURE_API uint32_t -+ZIX_PURE_API -+uint32_t - zix_digest_add(uint32_t hash, const void* buf, size_t len); - - /** -@@ -45,7 +47,8 @@ zix_digest_add(uint32_t hash, const void* buf, size_t len); - - Both `buf` and `len` must be evenly divisible by 8 (64 bits). - */ --ZIX_PURE_API uint32_t -+ZIX_PURE_API -+uint32_t - zix_digest_add_64(uint32_t hash, const void* buf, size_t len); - - /** -@@ -53,11 +56,12 @@ zix_digest_add_64(uint32_t hash, const void* buf, size_t len); - - This hashes the value of the pointer itself, and does not dereference `ptr`. - */ --ZIX_CONST_API uint32_t -+ZIX_CONST_API -+uint32_t - zix_digest_add_ptr(uint32_t hash, const void* ptr); - - #ifdef __cplusplus --} /* extern "C" */ -+} /* extern "C" */ - #endif - --#endif /* ZIX_DIGEST_H */ -+#endif /* ZIX_DIGEST_H */ -diff --git a/src/zix/hash.c b/src/zix/hash.c -index a498b0f..8183082 100644 ---- a/src/zix/hash.c -+++ b/src/zix/hash.c -@@ -1,5 +1,5 @@ - /* -- Copyright 2011-2018 David Robillard -+ Copyright 2011-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above -@@ -25,109 +25,107 @@ - from powers of two as possible. - */ - static const unsigned sizes[] = { -- 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593, 49157, 98317, -- 196613, 393241, 786433, 1572869, 3145739, 6291469, 12582917, 25165843, -- 50331653, 100663319, 201326611, 402653189, 805306457, 1610612741, 0 --}; -+ 53, 97, 193, 389, 769, 1543, 3079, -+ 6151, 12289, 24593, 49157, 98317, 196613, 393241, -+ 786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653, -+ 100663319, 201326611, 402653189, 805306457, 1610612741, 0}; - - typedef struct ZixHashEntry { -- struct ZixHashEntry* next; ///< Next entry in bucket -- uint32_t hash; ///< Non-modulo hash value -- // Value follows here (access with zix_hash_value) -+ struct ZixHashEntry* next; ///< Next entry in bucket -+ uint32_t hash; ///< Non-modulo hash value -+ // Value follows here (access with zix_hash_value) - } ZixHashEntry; - - struct ZixHashImpl { -- ZixHashFunc hash_func; -- ZixEqualFunc equal_func; -- ZixHashEntry** buckets; -- const unsigned* n_buckets; -- size_t value_size; -- unsigned count; -+ ZixHashFunc hash_func; -+ ZixEqualFunc equal_func; -+ ZixHashEntry** buckets; -+ const unsigned* n_buckets; -+ size_t value_size; -+ unsigned count; - }; - - static inline void* - zix_hash_value(ZixHashEntry* entry) - { -- return entry + 1; -+ return entry + 1; - } - - ZixHash* --zix_hash_new(ZixHashFunc hash_func, -- ZixEqualFunc equal_func, -- size_t value_size) -+zix_hash_new(ZixHashFunc hash_func, ZixEqualFunc equal_func, size_t value_size) - { -- ZixHash* hash = (ZixHash*)malloc(sizeof(ZixHash)); -- if (hash) { -- hash->hash_func = hash_func; -- hash->equal_func = equal_func; -- hash->n_buckets = &sizes[0]; -- hash->value_size = value_size; -- hash->count = 0; -- if (!(hash->buckets = (ZixHashEntry**)calloc(*hash->n_buckets, -- sizeof(ZixHashEntry*)))) { -- free(hash); -- return NULL; -- } -- } -- return hash; -+ ZixHash* hash = (ZixHash*)malloc(sizeof(ZixHash)); -+ if (hash) { -+ hash->hash_func = hash_func; -+ hash->equal_func = equal_func; -+ hash->n_buckets = &sizes[0]; -+ hash->value_size = value_size; -+ hash->count = 0; -+ if (!(hash->buckets = -+ (ZixHashEntry**)calloc(*hash->n_buckets, sizeof(ZixHashEntry*)))) { -+ free(hash); -+ return NULL; -+ } -+ } -+ return hash; - } - - void - zix_hash_free(ZixHash* hash) - { -- if (!hash) { -- return; -- } -- -- for (unsigned b = 0; b < *hash->n_buckets; ++b) { -- ZixHashEntry* bucket = hash->buckets[b]; -- for (ZixHashEntry* e = bucket; e;) { -- ZixHashEntry* next = e->next; -- free(e); -- e = next; -- } -- } -- -- free(hash->buckets); -- free(hash); -+ if (!hash) { -+ return; -+ } -+ -+ for (unsigned b = 0; b < *hash->n_buckets; ++b) { -+ ZixHashEntry* bucket = hash->buckets[b]; -+ for (ZixHashEntry* e = bucket; e;) { -+ ZixHashEntry* next = e->next; -+ free(e); -+ e = next; -+ } -+ } -+ -+ free(hash->buckets); -+ free(hash); - } - - size_t - zix_hash_size(const ZixHash* hash) - { -- return hash->count; -+ return hash->count; - } - - static inline void - insert_entry(ZixHashEntry** bucket, ZixHashEntry* entry) - { -- entry->next = *bucket; -- *bucket = entry; -+ entry->next = *bucket; -+ *bucket = entry; - } - - static inline ZixStatus - rehash(ZixHash* hash, unsigned new_n_buckets) - { -- ZixHashEntry** new_buckets = (ZixHashEntry**)calloc( -- new_n_buckets, sizeof(ZixHashEntry*)); -- if (!new_buckets) { -- return ZIX_STATUS_NO_MEM; -- } -- -- const unsigned old_n_buckets = *hash->n_buckets; -- for (unsigned b = 0; b < old_n_buckets; ++b) { -- for (ZixHashEntry* e = hash->buckets[b]; e;) { -- ZixHashEntry* const next = e->next; -- const unsigned h = e->hash % new_n_buckets; -- insert_entry(&new_buckets[h], e); -- e = next; -- } -- } -- -- free(hash->buckets); -- hash->buckets = new_buckets; -- -- return ZIX_STATUS_SUCCESS; -+ ZixHashEntry** new_buckets = -+ (ZixHashEntry**)calloc(new_n_buckets, sizeof(ZixHashEntry*)); -+ if (!new_buckets) { -+ return ZIX_STATUS_NO_MEM; -+ } -+ -+ const unsigned old_n_buckets = *hash->n_buckets; -+ for (unsigned b = 0; b < old_n_buckets; ++b) { -+ for (ZixHashEntry* e = hash->buckets[b]; e;) { -+ ZixHashEntry* const next = e->next; -+ const unsigned h = e->hash % new_n_buckets; -+ insert_entry(&new_buckets[h], e); -+ e = next; -+ } -+ } -+ -+ free(hash->buckets); -+ hash->buckets = new_buckets; -+ -+ return ZIX_STATUS_SUCCESS; - } - - static inline ZixHashEntry* -@@ -136,100 +134,97 @@ find_entry(const ZixHash* hash, - const unsigned h, - const unsigned h_nomod) - { -- for (ZixHashEntry* e = hash->buckets[h]; e; e = e->next) { -- if (e->hash == h_nomod && hash->equal_func(zix_hash_value(e), key)) { -- return e; -- } -- } -- return NULL; -+ for (ZixHashEntry* e = hash->buckets[h]; e; e = e->next) { -+ if (e->hash == h_nomod && hash->equal_func(zix_hash_value(e), key)) { -+ return e; -+ } -+ } -+ return NULL; - } - - void* - zix_hash_find(const ZixHash* hash, const void* value) - { -- const unsigned h_nomod = hash->hash_func(value); -- const unsigned h = h_nomod % *hash->n_buckets; -- ZixHashEntry* const entry = find_entry(hash, value, h, h_nomod); -- return entry ? zix_hash_value(entry) : 0; -+ const unsigned h_nomod = hash->hash_func(value); -+ const unsigned h = h_nomod % *hash->n_buckets; -+ ZixHashEntry* const entry = find_entry(hash, value, h, h_nomod); -+ return entry ? zix_hash_value(entry) : 0; - } - - ZixStatus - zix_hash_insert(ZixHash* hash, const void* value, void** inserted) - { -- unsigned h_nomod = hash->hash_func(value); -- unsigned h = h_nomod % *hash->n_buckets; -- -- ZixHashEntry* elem = find_entry(hash, value, h, h_nomod); -- if (elem) { -- assert(elem->hash == h_nomod); -- if (inserted) { -- *inserted = zix_hash_value(elem); -- } -- return ZIX_STATUS_EXISTS; -- } -- -- elem = (ZixHashEntry*)malloc(sizeof(ZixHashEntry) + hash->value_size); -- if (!elem) { -- return ZIX_STATUS_NO_MEM; -- } -- elem->next = NULL; -- elem->hash = h_nomod; -- memcpy(elem + 1, value, hash->value_size); -- -- const unsigned next_n_buckets = *(hash->n_buckets + 1); -- if (next_n_buckets != 0 && (hash->count + 1) >= next_n_buckets) { -- if (!rehash(hash, next_n_buckets)) { -- h = h_nomod % *(++hash->n_buckets); -- } -- } -- -- insert_entry(&hash->buckets[h], elem); -- ++hash->count; -- if (inserted) { -- *inserted = zix_hash_value(elem); -- } -- return ZIX_STATUS_SUCCESS; -+ unsigned h_nomod = hash->hash_func(value); -+ unsigned h = h_nomod % *hash->n_buckets; -+ -+ ZixHashEntry* elem = find_entry(hash, value, h, h_nomod); -+ if (elem) { -+ assert(elem->hash == h_nomod); -+ if (inserted) { -+ *inserted = zix_hash_value(elem); -+ } -+ return ZIX_STATUS_EXISTS; -+ } -+ -+ elem = (ZixHashEntry*)malloc(sizeof(ZixHashEntry) + hash->value_size); -+ if (!elem) { -+ return ZIX_STATUS_NO_MEM; -+ } -+ elem->next = NULL; -+ elem->hash = h_nomod; -+ memcpy(elem + 1, value, hash->value_size); -+ -+ const unsigned next_n_buckets = *(hash->n_buckets + 1); -+ if (next_n_buckets != 0 && (hash->count + 1) >= next_n_buckets) { -+ if (!rehash(hash, next_n_buckets)) { -+ h = h_nomod % *(++hash->n_buckets); -+ } -+ } -+ -+ insert_entry(&hash->buckets[h], elem); -+ ++hash->count; -+ if (inserted) { -+ *inserted = zix_hash_value(elem); -+ } -+ return ZIX_STATUS_SUCCESS; - } - - ZixStatus - zix_hash_remove(ZixHash* hash, const void* value) - { -- const unsigned h_nomod = hash->hash_func(value); -- const unsigned h = h_nomod % *hash->n_buckets; -- -- ZixHashEntry** next_ptr = &hash->buckets[h]; -- for (ZixHashEntry* e = hash->buckets[h]; e; e = e->next) { -- if (h_nomod == e->hash && -- hash->equal_func(zix_hash_value(e), value)) { -- *next_ptr = e->next; -- free(e); -- return ZIX_STATUS_SUCCESS; -- } -- next_ptr = &e->next; -- } -- -- if (hash->n_buckets != sizes) { -- const unsigned prev_n_buckets = *(hash->n_buckets - 1); -- if (hash->count - 1 <= prev_n_buckets) { -- if (!rehash(hash, prev_n_buckets)) { -- --hash->n_buckets; -- } -- } -- } -- -- --hash->count; -- return ZIX_STATUS_NOT_FOUND; -+ const unsigned h_nomod = hash->hash_func(value); -+ const unsigned h = h_nomod % *hash->n_buckets; -+ -+ ZixHashEntry** next_ptr = &hash->buckets[h]; -+ for (ZixHashEntry* e = hash->buckets[h]; e; e = e->next) { -+ if (h_nomod == e->hash && hash->equal_func(zix_hash_value(e), value)) { -+ *next_ptr = e->next; -+ free(e); -+ return ZIX_STATUS_SUCCESS; -+ } -+ next_ptr = &e->next; -+ } -+ -+ if (hash->n_buckets != sizes) { -+ const unsigned prev_n_buckets = *(hash->n_buckets - 1); -+ if (hash->count - 1 <= prev_n_buckets) { -+ if (!rehash(hash, prev_n_buckets)) { -+ --hash->n_buckets; -+ } -+ } -+ } -+ -+ --hash->count; -+ return ZIX_STATUS_NOT_FOUND; - } - - void --zix_hash_foreach(ZixHash* hash, -- ZixHashVisitFunc f, -- void* user_data) -+zix_hash_foreach(ZixHash* hash, ZixHashVisitFunc f, void* user_data) - { -- for (unsigned b = 0; b < *hash->n_buckets; ++b) { -- ZixHashEntry* bucket = hash->buckets[b]; -- for (ZixHashEntry* e = bucket; e; e = e->next) { -- f(zix_hash_value(e), user_data); -- } -- } -+ for (unsigned b = 0; b < *hash->n_buckets; ++b) { -+ ZixHashEntry* bucket = hash->buckets[b]; -+ for (ZixHashEntry* e = bucket; e; e = e->next) { -+ f(zix_hash_value(e), user_data); -+ } -+ } - } -diff --git a/src/zix/hash.h b/src/zix/hash.h -index ce7fdc6..3905038 100644 ---- a/src/zix/hash.h -+++ b/src/zix/hash.h -@@ -1,5 +1,5 @@ - /* -- Copyright 2011-2015 David Robillard -+ Copyright 2011-2020 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above -@@ -43,8 +43,7 @@ typedef uint32_t (*ZixHashFunc)(const void* value); - /** - Function to visit a hash element. - */ --typedef void (*ZixHashVisitFunc)(void* value, -- void* user_data); -+typedef void (*ZixHashVisitFunc)(void* value, void* user_data); - - /** - Create a new hash table. -@@ -59,21 +58,22 @@ typedef void (*ZixHashVisitFunc)(void* value, - @param equal_func A function to test value equality. - @param value_size The size of the values to be stored. - */ --ZIX_API ZixHash* --zix_hash_new(ZixHashFunc hash_func, -- ZixEqualFunc equal_func, -- size_t value_size); -+ZIX_API -+ZixHash* -+zix_hash_new(ZixHashFunc hash_func, ZixEqualFunc equal_func, size_t value_size); - - /** - Free `hash`. - */ --ZIX_API void -+ZIX_API -+void - zix_hash_free(ZixHash* hash); - - /** - Return the number of elements in `hash`. - */ --ZIX_PURE_API size_t -+ZIX_PURE_API -+size_t - zix_hash_size(const ZixHash* hash); - - /** -@@ -90,10 +90,9 @@ zix_hash_size(const ZixHash* hash); - @param inserted The copy of `value` in the hash table. - @return ZIX_STATUS_SUCCESS, ZIX_STATUS_EXISTS, or ZIX_STATUS_NO_MEM. - */ --ZIX_API ZixStatus --zix_hash_insert(ZixHash* hash, -- const void* value, -- void** inserted); -+ZIX_API -+ZixStatus -+zix_hash_insert(ZixHash* hash, const void* value, void** inserted); - - /** - Remove an item from `hash`. -@@ -102,9 +101,9 @@ zix_hash_insert(ZixHash* hash, - @param value The value to remove. - @return ZIX_STATUS_SUCCES or ZIX_STATUS_NOT_FOUND. - */ --ZIX_API ZixStatus --zix_hash_remove(ZixHash* hash, -- const void* value); -+ZIX_API -+ZixStatus -+zix_hash_remove(ZixHash* hash, const void* value); - - /** - Search for an item in `hash`. -@@ -112,9 +111,9 @@ zix_hash_remove(ZixHash* hash, - @param hash The hash table. - @param value The value to search for. - */ --ZIX_API void* --zix_hash_find(const ZixHash* hash, -- const void* value); -+ZIX_API -+void* -+zix_hash_find(const ZixHash* hash, const void* value); - - /** - Call `f` on each value in `hash`. -@@ -123,10 +122,9 @@ zix_hash_find(const ZixHash* hash, - @param f The function to call on each value. - @param user_data The user_data parameter passed to `f`. - */ --ZIX_API void --zix_hash_foreach(ZixHash* hash, -- ZixHashVisitFunc f, -- void* user_data); -+ZIX_API -+void -+zix_hash_foreach(ZixHash* hash, ZixHashVisitFunc f, void* user_data); - - /** - @} -@@ -134,7 +132,7 @@ zix_hash_foreach(ZixHash* hash, - */ - - #ifdef __cplusplus --} /* extern "C" */ -+} /* extern "C" */ - #endif - --#endif /* ZIX_HASH_H */ -+#endif /* ZIX_HASH_H */ -2.29.2 - diff --git a/sord.spec b/sord.spec index 1cf96d0..94fbe8e 100644 --- a/sord.spec +++ b/sord.spec @@ -1,16 +1,13 @@ %global maj 0 -%{!?_pkgdocdir: %global _pkgdocdir %{_docdir}/%{name}-%{version}} Name: sord -Version: 0.16.8 -Release: 3%{?dist} +Version: 0.16.10 +Release: 1%{?dist} Summary: A lightweight Resource Description Framework (RDF) C library License: ISC URL: http://drobilla.net/software/sord/ Source0: http://download.drobilla.net/%{name}-%{version}.tar.bz2 -# This fixes a potential BTree crash with GCC 10, patch from upstream -Patch0: %{name}-update-zix.patch BuildRequires: boost-devel BuildRequires: doxygen @@ -65,7 +62,6 @@ install -pm 644 AUTHORS NEWS README.md %{buildroot}%{_pkgdocdir} %files %{_pkgdocdir} %exclude %{_pkgdocdir}/%{name}-%{maj}/ -%exclude %{_pkgdocdir}/COPYING %license COPYING %{_libdir}/lib%{name}-%{maj}.so.* %{_bindir}/sordi @@ -80,6 +76,9 @@ install -pm 644 AUTHORS NEWS README.md %{buildroot}%{_pkgdocdir} %{_mandir}/man3/%{name}*.3* %changelog +* Wed Jun 15 2022 Guido Aulisi - 0.16.10-1 +- Update to 0.16.10 + * Sat Jan 22 2022 Fedora Release Engineering - 0.16.8-3 - Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild diff --git a/sources b/sources index 4795341..c143b3a 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (sord-0.16.8.tar.bz2) = 24ed50de8e5bb321e557bac6d3e441b2ed49adabf828bf0e1b33a080c89306dde80443dc8b563098fcc184c4d6e53b7e716b523ddccdf56d08301d1b0120f2b2 +SHA512 (sord-0.16.10.tar.bz2) = 715201eaf4a13a3635337cf8fa7c1a1f229f1d589f70cdf8f67183d90df29cd8b4af180650ce9cd0c651c712d11901bfdc6b51f9b8d7c6e70d8d8f30b1861281