From: Cody P Schafer Date: Fri, 3 Jun 2016 15:55:45 +0000 (-0400) Subject: htable: add a htable_prev method to oppose _next X-Git-Url: http://git.ozlabs.org/?p=ccan;a=commitdiff_plain;h=7b56762984ce66f38728b542ca347bcb6fe3e981;hp=d81e79b8dfdfb0da8766c022e767a5b040e5d07b htable: add a htable_prev method to oppose _next Useful for unwinding actions taken while iterating over a htable. Signed-off-by: Cody P Schafer --- diff --git a/ccan/htable/htable.c b/ccan/htable/htable.c index 59048dc0..5a773cd8 100644 --- a/ccan/htable/htable.c +++ b/ccan/htable/htable.c @@ -135,6 +135,17 @@ void *htable_next(const struct htable *ht, struct htable_iter *i) return NULL; } +void *htable_prev(const struct htable *ht, struct htable_iter *i) +{ + for (;;) { + if (!i->off) + return NULL; + i->off --; + if (entry_is_valid(ht->table[i->off])) + return get_raw_ptr(ht, ht->table[i->off]); + } +} + /* This does not expand the hash table, that's up to caller. */ static void ht_add(struct htable *ht, const void *new, size_t h) { diff --git a/ccan/htable/htable.h b/ccan/htable/htable.h index 03193567..e150c2ef 100644 --- a/ccan/htable/htable.h +++ b/ccan/htable/htable.h @@ -178,6 +178,21 @@ void *htable_first(const struct htable *htable, struct htable_iter *i); */ void *htable_next(const struct htable *htable, struct htable_iter *i); +/** + * htable_prev - find the previous entry in the hash table + * @ht: the hashtable + * @i: the struct htable_iter to use + * + * Get previous entry in the hashtable; NULL if all done. + * + * "previous" here only means the item that would have been returned by + * htable_next() before the item it returned most recently. + * + * This is usually used in the middle of (or after) a htable_next iteration and + * to "unwind" actions taken. + */ +void *htable_prev(const struct htable *htable, struct htable_iter *i); + /** * htable_delval - remove an iterated pointer from a hash table * @ht: the htable diff --git a/ccan/htable/htable_type.h b/ccan/htable/htable_type.h index 15a70fc2..ba33f139 100644 --- a/ccan/htable/htable_type.h +++ b/ccan/htable/htable_type.h @@ -43,6 +43,7 @@ * Iteration over hashtable is also supported: * type *_first(const struct *ht, struct _iter *i); * type *_next(const struct *ht, struct _iter *i); + * type *_prev(const struct *ht, struct _iter *i); * * It's currently safe to iterate over a changing hashtable, but you might * miss an element. Iteration isn't very efficient, either. @@ -137,6 +138,11 @@ struct name##_iter *iter) \ { \ return htable_next(&ht->raw, &iter->i); \ + } \ + static inline UNNEEDED type *name##_prev(const struct name *ht, \ + struct name##_iter *iter) \ + { \ + return htable_prev(&ht->raw, &iter->i); \ } #if HAVE_TYPEOF diff --git a/ccan/htable/test/run-type.c b/ccan/htable/test/run-type.c index 11ce54ba..51a85ff2 100644 --- a/ccan/htable/test/run-type.c +++ b/ccan/htable/test/run-type.c @@ -116,7 +116,7 @@ int main(int argc, char *argv[]) void *p; struct htable_obj_iter iter; - plan_tests(26); + plan_tests(27); for (i = 0; i < NUM_VALS; i++) val[i].key = i; dne = i; @@ -147,6 +147,10 @@ int main(int argc, char *argv[]) for (p = htable_obj_first(&ht,&iter); p; p = htable_obj_next(&ht, &iter)) i++; ok1(i == NUM_VALS); + i = 0; + for (p = htable_obj_prev(&ht,&iter); p; p = htable_obj_prev(&ht, &iter)) + i++; + ok1(i == NUM_VALS); /* Delete all. */ del_vals(&ht, val, NUM_VALS); diff --git a/ccan/htable/test/run.c b/ccan/htable/test/run.c index c5272c15..09cde890 100644 --- a/ccan/htable/test/run.c +++ b/ccan/htable/test/run.c @@ -105,7 +105,7 @@ int main(int argc, char *argv[]) void *p; struct htable_iter iter; - plan_tests(35); + plan_tests(36); for (i = 0; i < NUM_VALS; i++) val[i] = i; dne = i; @@ -156,6 +156,11 @@ int main(int argc, char *argv[]) i++; ok1(i == NUM_VALS); + i = 0; + for (p = htable_prev(&ht, &iter); p; p = htable_prev(&ht, &iter)) + i++; + ok1(i == NUM_VALS); + /* Delete all. */ del_vals(&ht, val, NUM_VALS); ok1(!htable_get(&ht, hash(&val[0], NULL), objcmp, &val[0]));