summaryrefslogtreecommitdiff
path: root/src/lib/btree.c
diff options
context:
space:
mode:
authorSander Vrijders <sander.vrijders@ugent.be>2017-03-31 16:14:58 +0200
committerSander Vrijders <sander.vrijders@ugent.be>2017-03-31 16:19:21 +0200
commit81558308ca6d0707b27fd5b5d4b332bd2eb6e6d3 (patch)
treec263f233e8398680be529f5c46ccd70ae8c1eeab /src/lib/btree.c
parent02523d780b9c629a98e863b5218f054cde2f0426 (diff)
downloadouroboros-81558308ca6d0707b27fd5b5d4b332bd2eb6e6d3.tar.gz
ouroboros-81558308ca6d0707b27fd5b5d4b332bd2eb6e6d3.zip
lib: Fix bugs in B-tree
This fixes some bugs in the B-tree implementation. The test has also been rewritten to be more thorough.
Diffstat (limited to 'src/lib/btree.c')
-rw-r--r--src/lib/btree.c54
1 files changed, 33 insertions, 21 deletions
diff --git a/src/lib/btree.c b/src/lib/btree.c
index 10a900d6..48df8e39 100644
--- a/src/lib/btree.c
+++ b/src/lib/btree.c
@@ -115,18 +115,23 @@ static struct btnode * btnode_create(size_t k)
static void btnode_destroy(struct btnode * node)
{
- size_t i = 0;
-
assert(node);
- for (i = 0; !node->leaf && i <= node->used; ++i)
- btnode_destroy(node->children[i]);
-
free(node->children);
free(node->keyvals);
free(node);
}
+static void btnode_destroy_subtree(struct btnode * node)
+{
+ size_t i;
+
+ for (i = 0; !node->leaf && i <= node->used; ++i)
+ btnode_destroy_subtree(node->children[i]);
+
+ btnode_destroy(node);
+}
+
static int btnode_insert(struct btnode * node,
struct key_val kv,
struct key_val * med,
@@ -211,15 +216,15 @@ void merge(struct btnode * node,
if (!chld->leaf)
memmove(&chld->children[node->k / 2],
&next->children[0],
- sizeof(*next->children) * next->used + 1);
+ sizeof(*next->children) * (next->used + 1));
memmove(&node->keyvals[i],
&node->keyvals[i + 1],
- sizeof(*node->keyvals) * node->used - i - 1);
+ sizeof(*node->keyvals) * (node->used - i - 1));
memmove(&node->children[i + 1],
&node->children[i + 2],
- sizeof(*node->children) * node->used - i);
+ sizeof(*node->children) * (node->used - i));
chld->used += next->used + 1;
node->used--;
@@ -262,6 +267,7 @@ static void fill(struct btnode * node,
/* Feed from next sibling. */
if (i != node->used && node->children[i + 1]->used >= node->k / 2) {
struct btnode * next = node->children[i + 1];
+
chld->keyvals[chld->used] = node->keyvals[i];
if (!chld->leaf)
@@ -294,11 +300,11 @@ static void fill(struct btnode * node,
static struct key_val btnode_pred(struct btnode * node,
size_t i)
{
- struct btnode * pred = node->children[i - 1];
+ struct btnode * pred = node->children[i];
while (!pred->leaf)
pred = pred->children[pred->used];
- return pred->keyvals[pred->used -1];
+ return pred->keyvals[pred->used - 1];
}
static struct key_val btnode_succ(struct btnode * node,
@@ -314,6 +320,7 @@ static int btnode_delete(struct btnode * node,
uint32_t key)
{
size_t i;
+ int ret = 0;
assert(node);
@@ -329,15 +336,15 @@ static int btnode_delete(struct btnode * node,
} else {
if (node->children[i]->used >= node->k / 2) {
node->keyvals[i] = btnode_pred(node, i);
- btnode_delete(node->children[i],
- node->keyvals[i].key);
+ ret = btnode_delete(node->children[i],
+ node->keyvals[i].key);
} else if (node->children[i + 1]->used >= node->k / 2) {
node->keyvals[i] = btnode_succ(node, i);
- btnode_delete(node->children[i + 1],
- node->keyvals[i].key);
+ ret = btnode_delete(node->children[i + 1],
+ node->keyvals[i].key);
} else {
merge(node, i);
- btnode_delete(node, key);
+ ret = btnode_delete(node, key);
}
}
} else {
@@ -345,16 +352,16 @@ static int btnode_delete(struct btnode * node,
return -1; /* value not in tree */
} else {
bool flag = (i == node->used ? true : false);
- if (node->children[i]->used > node->children[i]->k / 2)
+ if (node->children[i]->used < node->children[i]->k / 2)
fill(node, i);
if (flag && i > node->used)
- btnode_delete(node->children[i - 1], key);
+ ret = btnode_delete(node->children[i - 1], key);
else
- btnode_delete(node->children[i + 1], key);
+ ret = btnode_delete(node->children[i], key);
}
}
- return 0;
+ return ret;
}
struct btree * btree_create(size_t k)
@@ -378,7 +385,7 @@ void btree_destroy(struct btree * tree)
return;
if (tree->root != NULL)
- btnode_destroy(tree->root);
+ btnode_destroy_subtree(tree->root);
free(tree);
}
@@ -435,20 +442,25 @@ int btree_insert(struct btree * tree,
int btree_remove(struct btree * tree,
uint32_t key)
{
+ struct btnode * prev_root;
+
if (tree == NULL)
return -EINVAL;
if (tree->root == NULL)
return 0;
- btnode_delete(tree->root, key);
+ if (btnode_delete(tree->root, key))
+ return -1;
if (tree->root->used == 0) {
if (tree->root->leaf) {
btnode_destroy(tree->root);
tree->root = NULL;
} else {
+ prev_root = tree->root;
tree->root = tree->root->children[0];
+ btnode_destroy(prev_root);
}
}