Useful for unwinding actions taken while iterating over a htable.
Signed-off-by: Cody P Schafer <dev@codyps.com>
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)
{
*/
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
* Iteration over hashtable is also supported:
* type *<name>_first(const struct <name> *ht, struct <name>_iter *i);
* type *<name>_next(const struct <name> *ht, struct <name>_iter *i);
+ * type *<name>_prev(const struct <name> *ht, struct <name>_iter *i);
*
* It's currently safe to iterate over a changing hashtable, but you might
* miss an element. Iteration isn't very efficient, either.
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
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;
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);
void *p;
struct htable_iter iter;
- plan_tests(35);
+ plan_tests(36);
for (i = 0; i < NUM_VALS; i++)
val[i] = i;
dne = i;
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]));