ht->deleted++;
}
+void *htable_pick_(const struct htable *ht, size_t seed, struct htable_iter *i)
+{
+ void *e;
+ struct htable_iter unwanted;
+
+ if (!i)
+ i = &unwanted;
+ i->off = seed % ((size_t)1 << ht->bits);
+ e = htable_next(ht, i);
+ if (!e)
+ e = htable_first(ht, i);
+ return e;
+}
+
struct htable *htable_check(const struct htable *ht, const char *abortstr)
{
void *p;
htable_delval_(htable_debug(htable, HTABLE_LOC), i)
void htable_delval_(struct htable *ht, struct htable_iter *i);
+/**
+ * htable_pick - set iterator to a random valid entry.
+ * @ht: the htable
+ * @seed: a random number to use.
+ * @i: the htable_iter which is output (or NULL).
+ *
+ * Usually used with htable_delval to delete a random entry. Returns
+ * NULL iff the table is empty, otherwise a random entry.
+ */
+#define htable_pick(htable, seed, i) \
+ htable_pick_(htable_debug(htable, HTABLE_LOC), seed, i)
+void *htable_pick_(const struct htable *ht, size_t seed, struct htable_iter *i);
+
/**
* htable_set_allocator - set calloc/free functions.
* @alloc: allocator to use, must zero memory!
* 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);
- *
+ * type *<name>_pick(const struct <name> *ht, size_t seed,
+ * 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.
*
return name##_del(ht, elem); \
return false; \
} \
+ static inline UNNEEDED bool name##_pick(const struct name *ht, \
+ size_t seed, \
+ struct name##_iter *iter) \
+ { \
+ /* Note &iter->i == NULL iff iter is NULL */ \
+ return htable_pick(&ht->raw, seed, &iter->i); \
+ } \
static inline UNNEEDED type *name##_first(const struct name *ht, \
struct name##_iter *iter) \
{ \
void *p;
struct htable_obj_iter iter;
- plan_tests(32);
+ plan_tests(35);
for (i = 0; i < NUM_VALS; i++)
val[i].key = i;
dne = i;
/* We cannot find an entry which doesn't exist. */
ok1(!htable_obj_get(&ht, &dne));
+ ok1(!htable_obj_pick(&ht, 0, NULL));
/* Fill it, it should increase in size. */
add_vals(&ht, val, NUM_VALS);
/* Find all. */
find_vals(&ht, val, NUM_VALS);
ok1(!htable_obj_get(&ht, &dne));
+ ok1(htable_obj_pick(&ht, 0, NULL));
+ ok1(htable_obj_pick(&ht, 0, &iter));
/* Walk once, should get them all. */
i = 0;
void *p;
struct htable_iter iter;
- plan_tests(38);
+ plan_tests(43);
for (i = 0; i < NUM_VALS; i++)
val[i] = i;
dne = i;
/* Mask should be set. */
ok1(check_mask(&ht, val, 1));
+ /* htable_pick should always return that value */
+ ok1(htable_pick(&ht, 0, NULL) == val);
+ ok1(htable_pick(&ht, 1, NULL) == val);
+ ok1(htable_pick(&ht, 0, &iter) == val);
+ ok1(get_raw_ptr(&ht, ht.table[iter.off]) == val);
+
/* This should increase it again. */
add_vals(&ht, val, 1, 1);
ok1(ht.bits == 2);
htable_clear(&ht);
ok1(htable_count(&ht) == 0);
+ ok1(htable_pick(&ht, 0, NULL) == NULL);
return exit_status();
}