From 123ae1a34788cf5c0aecce1c46492d8f5db59dab Mon Sep 17 00:00:00 2001 From: Bruno BELANYI Date: Tue, 24 Nov 2020 19:45:28 +0100 Subject: [PATCH] tupperware: avl: add range mapping function --- include/tupperware/avl.h | 2 ++ src/avl.c | 62 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/include/tupperware/avl.h b/include/tupperware/avl.h index 462dbdb..6e19f1d 100644 --- a/include/tupperware/avl.h +++ b/include/tupperware/avl.h @@ -60,5 +60,7 @@ void avl_merge_all(struct avl *tree, struct avl *more); void avl_prefix_map(struct avl *tree, avl_map_f map, void *cookie); void avl_infix_map(struct avl *tree, avl_map_f map, void *cookie); void avl_postfix_map(struct avl *tree, avl_map_f map, void *cookie); +void avl_map_between(const struct avl *tree, + struct avl_node *inter[2], avl_map_f map, void *cookie); #endif /* !TUPPERWARE_AVL_H */ diff --git a/src/avl.c b/src/avl.c index 307d09c..65c9e46 100644 --- a/src/avl.c +++ b/src/avl.c @@ -522,3 +522,65 @@ struct between_parameters { avl_map_f map; void *cookie; }; + +static bool map_between_helper(struct avl_node *cur, + const struct avl_node *end, avl_map_f map, void *cookie) { + if (!cur) + return false; + if (cur == end) + return true; + if (map_between_helper(cur->left, end, map, cookie)) + return true; + map(cur, cookie); + return map_between_helper(cur->right, end, map, cookie); +} + +static bool map_between_right(struct avl_node *cur, + const struct avl_node *end, avl_map_f map, void *cookie) { + if (!cur) + return false; + if (cur == end) + return true; + map(cur, cookie); + return map_between_helper(cur->right, end, map, cookie); +} + +static struct avl_node *find_parent(const struct avl *tree, + struct avl_node *cur, const struct avl_node *v) { + struct avl_node *parent = NULL; + + int c = 0; + while (cur && (c = tree->cmp(v, cur, tree->cookie))) { + parent = cur; + if (c < 0) + cur = cur->left; + else + cur = cur->right; + } + + if (!cur) + return NULL; + if (cur == v) + return parent; + if (cur->left == v || cur->right == v) + return cur; // NOTE: needs better handling + if ((parent = find_parent(tree, cur->right, v))) + return parent; + if ((parent = find_parent(tree, cur->left, v))) + return parent; + + return NULL; +} + +void avl_map_between(const struct avl *tree, + struct avl_node *inter[2], avl_map_f map, void *cookie) { + if (!tree || !tree->root) + return; + + struct avl_node *begin = inter[0]; + const struct avl_node *end = inter[1]; + // FIXME: finding the parent is inefficient + while (begin && !map_between_right(begin, end, map, cookie)) { + begin = find_parent(tree, tree->root, begin); + } +}