aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorAlex Auvolat <alex.auvolat@ens.fr>2015-02-14 20:08:40 +0100
committerAlex Auvolat <alex.auvolat@ens.fr>2015-02-14 20:08:40 +0100
commitfea4c7a29e26bccab9a2982d600bd272e21a925a (patch)
tree410eb29058b1be429aee79911566a18d71dae7de /src/common
parentdc86ed35a4a41ab53bb595e69fe57c29264fd146 (diff)
downloadkogata-fea4c7a29e26bccab9a2982d600bd272e21a925a.tar.gz
kogata-fea4c7a29e26bccab9a2982d600bd272e21a925a.zip
Add btree_remove_v to selectively remove bindings that have a key
Diffstat (limited to 'src/common')
-rw-r--r--src/common/include/btree.h2
-rw-r--r--src/common/libalgo/btree.c55
2 files changed, 57 insertions, 0 deletions
diff --git a/src/common/include/btree.h b/src/common/include/btree.h
index 34fd2b3..9975885 100644
--- a/src/common/include/btree.h
+++ b/src/common/include/btree.h
@@ -7,6 +7,7 @@
// - btree_lower returns any item with matching key, or if none returns last item with smaller key
// - btree_upper returns any item with matching key, or if none returns first item with bigger key
// - btree_remove removes *all bindings* with matching key
+// - btree_remove_v removes bindings with matching *key and value*
// - btree_iter_on calls iterator function on all bindings with matching key
// Memory management is same as for hashtbl (a kv_iter_fun_t is called when an item is released)
@@ -19,6 +20,7 @@ void delete_btree(btree_t *t);
bool btree_add(btree_t *t, void* key, void* val);
void btree_remove(btree_t *t, const void* key);
+void btree_remove_v(btree_t *t, const void* key, const void* value);
void* btree_find(btree_t *i, const void* key);
void* btree_lower(btree_t *i, const void* key);
diff --git a/src/common/libalgo/btree.c b/src/common/libalgo/btree.c
index 20323aa..d3a030a 100644
--- a/src/common/libalgo/btree.c
+++ b/src/common/libalgo/btree.c
@@ -193,6 +193,61 @@ void btree_remove(btree_t *t, const void* key) {
t->root = remove_aux(t, t->root, key);
}
+void btree_remove_v(btree_t *t, const void* key, const void* val) {
+ btree_item_t *extract_smallest(btree_item_t *i, btree_item_t **out_smallest) {
+ ASSERT(i != 0);
+ if (i->left == 0) {
+ *out_smallest = i;
+ return i->right;
+ } else {
+ i->left = extract_smallest(i->left, out_smallest);
+ recalc_height(i);
+ return equilibrate(i);
+ }
+ }
+
+ btree_item_t *remove_aux(btree_t *t, btree_item_t *i, const void* key, const void* val) {
+ if (i == 0) return 0;
+
+ int c = t->cf(key, i->key);
+ if (c < 0) {
+ i->left = remove_aux(t, i->left, key, val);
+ return equilibrate(i);
+ } else if (c > 0) {
+ i->right = remove_aux(t, i->right, key, val);
+ return equilibrate(i);
+ } else if (i->val == i) {
+ // remove item i
+
+ btree_item_t *new_i;
+ if (i->right == 0 || i->left == 0) {
+ new_i = (i->right == 0 ? i->left : i->right);
+ } else {
+ btree_item_t *new_i_right = extract_smallest(i->right, &new_i);
+
+ new_i->left = i->left;
+ new_i->right = new_i_right;
+
+ recalc_height(new_i);
+ new_i = equilibrate(new_i);
+ }
+
+ if (t->releasef) t->releasef(i->key, i->val);
+ free(i);
+ t->nitems--;
+
+ return remove_aux(t, new_i, key, val); // loop because several elements may correspond
+ } else {
+ i->left = remove_aux(t, i->left, key, val);
+ i->right = remove_aux(t, i->right, key, val);
+ recalc_height(i);
+ return equilibrate(i);
+ }
+ }
+
+ t->root = remove_aux(t, t->root, key, val);
+}
+
// ======================== //
// LOOKING UP AND ITERATING //
// ======================== //