Репозиторий Sisyphus
Последнее обновление: 1 октября 2023 | Пакетов: 18631 | Посещений: 37543347
en ru br
Репозитории ALT

Группа :: Система/Библиотеки
Пакет: libsord

 Главная   Изменения   Спек   Патчи   Sources   Загрузить   Gear   Bugs and FR  Repocop 

Патч: sord-update-zix.patch
Скачать


From 5bc9b6e08b2555f2f1a9fe65db266dc97f4a50ba Mon Sep 17 00:00:00 2001
From: David Robillard <d@drobilla.net>
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 <d@drobilla.net>  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 <d@drobilla.net>
+  Copyright 2011-2020 David Robillard <d@drobilla.net>
 
   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 <d@drobilla.net>
+  Copyright 2016-2020 David Robillard <d@drobilla.net>
 
   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 <smmintrin.h>
+#  include <smmintrin.h>
 #endif
 
 #include <assert.h>
@@ -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 <d@drobilla.net>
+  Copyright 2011-2020 David Robillard <d@drobilla.net>
 
   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 <d@drobilla.net>
+  Copyright 2011-2020 David Robillard <d@drobilla.net>
 
   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
 
дизайн и разработка: Vladimir Lettiev aka crux © 2004-2005, Andrew Avramenko aka liks © 2007-2008
текущий майнтейнер: Michael Shigorin