From a45661e5b62fa8761bb268dc81058a3fa4263836 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Mon, 9 Jan 2017 14:34:14 -0800 Subject: [PATCH] Add _prev version of treap lookup and iteration _lookup() and _lookup_next() each had nearly identical loops that took a dirty boolean. We combine them into one walker with flags for dirty and next and add a prev prev as well, giving us all the exported functions with combinations of the flags. We also add _last() to match _first() and _prev() to match _next(). Signed-off-by: Zach Brown --- kmod/src/treap.c | 122 ++++++++++++++++++++++++++++++++--------------- kmod/src/treap.h | 4 ++ 2 files changed, 87 insertions(+), 39 deletions(-) diff --git a/kmod/src/treap.c b/kmod/src/treap.c index 41bbb40c..692b25a2 100644 --- a/kmod/src/treap.c +++ b/kmod/src/treap.c @@ -845,30 +845,46 @@ out: return ret; } -static void *treap_lookup(struct scoutfs_treap *treap, void *key, bool dirty) +enum { + LU_DIRTY, + LU_NEXT, + LU_PREV, +}; + +static void *treap_lookup(struct scoutfs_treap *treap, void *key, int flags) { struct treap_ref *ref = &treap->root_ref; struct treap_node *parent = NULL; struct treap_node *node = NULL; + struct treap_node *prev = NULL; + struct treap_node *next = NULL; int cmp; while (ref->gen) { - node = read_node(treap, parent, ref, dirty); + node = read_node(treap, parent, ref, flags & LU_DIRTY); if (IS_ERR(node)) break; cmp = treap->ops->compare(key, node->data); - if (cmp < 0) + if (cmp < 0) { ref = &node->left; - else if (cmp > 0) + next = node; + } else if (cmp > 0) { ref = &node->right; - else + prev = node; + } else { break; + } parent = node; node = NULL; } + if (!node && (flags & LU_PREV) && prev) + node = prev; + else if (!node && (flags & LU_NEXT) && next) + node = next; + if (IS_ERR(node)) return ERR_CAST(node); if (node) @@ -878,12 +894,32 @@ static void *treap_lookup(struct scoutfs_treap *treap, void *key, bool dirty) void *scoutfs_treap_lookup(struct scoutfs_treap *treap, void *key) { - return treap_lookup(treap, key, false); + return treap_lookup(treap, key, 0); } void *scoutfs_treap_lookup_dirty(struct scoutfs_treap *treap, void *key) { - return treap_lookup(treap, key, true); + return treap_lookup(treap, key, LU_DIRTY); +} + +void *scoutfs_treap_lookup_next(struct scoutfs_treap *treap, void *key) +{ + return treap_lookup(treap, key, LU_NEXT); +} + +void *scoutfs_treap_lookup_next_dirty(struct scoutfs_treap *treap, void *key) +{ + return treap_lookup(treap, key, LU_NEXT | LU_DIRTY); +} + +void *scoutfs_treap_lookup_prev(struct scoutfs_treap *treap, void *key) +{ + return treap_lookup(treap, key, LU_PREV); +} + +void *scoutfs_treap_lookup_prev_dirty(struct scoutfs_treap *treap, void *key) +{ + return treap_lookup(treap, key, LU_PREV | LU_DIRTY); } void *scoutfs_treap_first(struct scoutfs_treap *treap) @@ -908,6 +944,28 @@ void *scoutfs_treap_first(struct scoutfs_treap *treap) return NULL; } +void *scoutfs_treap_last(struct scoutfs_treap *treap) +{ + struct treap_ref *ref = &treap->root_ref; + struct treap_node *parent = NULL; + struct treap_node *node = NULL; + + while (ref->gen) { + node = read_node(treap, parent, ref, false); + if (IS_ERR(node)) + break; + + ref = &node->right; + parent = node; + } + + if (IS_ERR(node)) + return ERR_CAST(node); + if (node) + return node->data; + return NULL; +} + void *scoutfs_treap_next(struct scoutfs_treap *treap, void *data) { struct treap_node *node = container_of(data, struct treap_node, data); @@ -939,51 +997,37 @@ out: return NULL; } -static void *lookup_next(struct scoutfs_treap *treap, void *key, bool dirty) +void *scoutfs_treap_prev(struct scoutfs_treap *treap, void *data) { - struct treap_ref *ref = &treap->root_ref; - struct treap_node *parent = NULL; - struct treap_node *node = NULL; - struct treap_node *next = NULL; - int cmp; + struct treap_node *node = container_of(data, struct treap_node, data); + struct treap_node *parent; - while (ref->off) { - node = read_node(treap, parent, ref, dirty); + if (node->left.gen) { + node = read_node(treap, node, &node->left, false); if (IS_ERR(node)) - break; + goto out; - cmp = treap->ops->compare(key, node->data); - if (cmp < 0) { - ref = &node->left; - next = node; - } else if (cmp > 0) { - ref = &node->right; - } else { - next = node; - break; + while (node->right.gen) { + node = read_node(treap, node, &node->right, false); + if (IS_ERR(node)) + goto out; } - parent = node; - node = NULL; + goto out; } + while (((parent = node->parent)) && node == parent->left.node) + node = parent; + node = parent; + +out: if (IS_ERR(node)) return ERR_CAST(node); - if (next) - return next->data; + if (node) + return node->data; return NULL; } -void *scoutfs_treap_lookup_next(struct scoutfs_treap *treap, void *key) -{ - return lookup_next(treap, key, false); -} - -void *scoutfs_treap_lookup_next_dirty(struct scoutfs_treap *treap, void *key) -{ - return lookup_next(treap, key, true); -} - int scoutfs_treap_has_dirty(struct scoutfs_treap *treap) { return !!(treap->root_ref.aug_bits & SCOUTFS_TREAP_AUG_DIRTY); diff --git a/kmod/src/treap.h b/kmod/src/treap.h index 0265611e..e69fbde1 100644 --- a/kmod/src/treap.h +++ b/kmod/src/treap.h @@ -29,9 +29,13 @@ void *scoutfs_treap_lookup(struct scoutfs_treap *treap, void *key); void *scoutfs_treap_lookup_dirty(struct scoutfs_treap *treap, void *key); void *scoutfs_treap_lookup_next(struct scoutfs_treap *treap, void *key); void *scoutfs_treap_lookup_next_dirty(struct scoutfs_treap *treap, void *key); +void *scoutfs_treap_lookup_prev(struct scoutfs_treap *treap, void *key); +void *scoutfs_treap_lookup_prev_dirty(struct scoutfs_treap *treap, void *key); void *scoutfs_treap_first(struct scoutfs_treap *treap); +void *scoutfs_treap_last(struct scoutfs_treap *treap); void *scoutfs_treap_next(struct scoutfs_treap *treap, void *data); +void *scoutfs_treap_prev(struct scoutfs_treap *treap, void *data); int scoutfs_treap_has_dirty(struct scoutfs_treap *treap); int scoutfs_treap_dirty_ring(struct scoutfs_treap *treap);