Browse Source

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 <dev@codyps.com>
Cody P Schafer 9 years ago
parent
commit
7b56762984
5 changed files with 43 additions and 2 deletions
  1. 11 0
      ccan/htable/htable.c
  2. 15 0
      ccan/htable/htable.h
  3. 6 0
      ccan/htable/htable_type.h
  4. 5 1
      ccan/htable/test/run-type.c
  5. 6 1
      ccan/htable/test/run.c

+ 11 - 0
ccan/htable/htable.c

@@ -135,6 +135,17 @@ void *htable_next(const struct htable *ht, struct htable_iter *i)
 	return NULL;
 	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. */
 /* 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)
 static void ht_add(struct htable *ht, const void *new, size_t h)
 {
 {

+ 15 - 0
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);
 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
  * htable_delval - remove an iterated pointer from a hash table
  * @ht: the htable
  * @ht: the htable

+ 6 - 0
ccan/htable/htable_type.h

@@ -43,6 +43,7 @@
  * Iteration over hashtable is also supported:
  * Iteration over hashtable is also supported:
  *	type *<name>_first(const struct <name> *ht, struct <name>_iter *i);
  *	type *<name>_first(const struct <name> *ht, struct <name>_iter *i);
  *	type *<name>_next(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
  * It's currently safe to iterate over a changing hashtable, but you might
  * miss an element.  Iteration isn't very efficient, either.
  * miss an element.  Iteration isn't very efficient, either.
@@ -137,6 +138,11 @@
 					struct name##_iter *iter)	\
 					struct name##_iter *iter)	\
 	{								\
 	{								\
 		return htable_next(&ht->raw, &iter->i);			\
 		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
 #if HAVE_TYPEOF

+ 5 - 1
ccan/htable/test/run-type.c

@@ -116,7 +116,7 @@ int main(int argc, char *argv[])
 	void *p;
 	void *p;
 	struct htable_obj_iter iter;
 	struct htable_obj_iter iter;
 
 
-	plan_tests(26);
+	plan_tests(27);
 	for (i = 0; i < NUM_VALS; i++)
 	for (i = 0; i < NUM_VALS; i++)
 		val[i].key = i;
 		val[i].key = i;
 	dne = 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))
 	for (p = htable_obj_first(&ht,&iter); p; p = htable_obj_next(&ht, &iter))
 		i++;
 		i++;
 	ok1(i == NUM_VALS);
 	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. */
 	/* Delete all. */
 	del_vals(&ht, val, NUM_VALS);
 	del_vals(&ht, val, NUM_VALS);

+ 6 - 1
ccan/htable/test/run.c

@@ -105,7 +105,7 @@ int main(int argc, char *argv[])
 	void *p;
 	void *p;
 	struct htable_iter iter;
 	struct htable_iter iter;
 
 
-	plan_tests(35);
+	plan_tests(36);
 	for (i = 0; i < NUM_VALS; i++)
 	for (i = 0; i < NUM_VALS; i++)
 		val[i] = i;
 		val[i] = i;
 	dne = i;
 	dne = i;
@@ -156,6 +156,11 @@ int main(int argc, char *argv[])
 		i++;
 		i++;
 	ok1(i == NUM_VALS);
 	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. */
 	/* Delete all. */
 	del_vals(&ht, val, NUM_VALS);
 	del_vals(&ht, val, NUM_VALS);
 	ok1(!htable_get(&ht, hash(&val[0], NULL), objcmp, &val[0]));
 	ok1(!htable_get(&ht, hash(&val[0], NULL), objcmp, &val[0]));