aboutsummaryrefslogtreecommitdiff
path: root/src/common/container.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/container.c')
-rw-r--r--src/common/container.c797
1 files changed, 367 insertions, 430 deletions
diff --git a/src/common/container.c b/src/common/container.c
index c668068e9e..ec59dccf62 100644
--- a/src/common/container.c
+++ b/src/common/container.c
@@ -1,6 +1,6 @@
/* Copyright (c) 2003-2004, Roger Dingledine
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2013, The Tor Project, Inc. */
+ * Copyright (c) 2007-2016, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/**
@@ -28,21 +28,21 @@
/** Allocate and return an empty smartlist.
*/
-smartlist_t *
-smartlist_new(void)
+MOCK_IMPL(smartlist_t *,
+smartlist_new,(void))
{
smartlist_t *sl = tor_malloc(sizeof(smartlist_t));
sl->num_used = 0;
sl->capacity = SMARTLIST_DEFAULT_CAPACITY;
- sl->list = tor_malloc(sizeof(void *) * sl->capacity);
+ sl->list = tor_calloc(sizeof(void *), sl->capacity);
return sl;
}
/** Deallocate a smartlist. Does not release storage associated with the
* list's elements.
*/
-void
-smartlist_free(smartlist_t *sl)
+MOCK_IMPL(void,
+smartlist_free,(smartlist_t *sl))
{
if (!sl)
return;
@@ -55,6 +55,7 @@ smartlist_free(smartlist_t *sl)
void
smartlist_clear(smartlist_t *sl)
{
+ memset(sl->list, 0, sizeof(void *) * sl->num_used);
sl->num_used = 0;
}
@@ -63,7 +64,7 @@ smartlist_clear(smartlist_t *sl)
#endif
/** Make sure that <b>sl</b> can hold at least <b>size</b> entries. */
-static INLINE void
+static inline void
smartlist_ensure_capacity(smartlist_t *sl, size_t size)
{
/* Set MAX_CAPACITY to MIN(INT_MAX, SIZE_MAX / sizeof(void*)) */
@@ -72,21 +73,25 @@ smartlist_ensure_capacity(smartlist_t *sl, size_t size)
#else
#define MAX_CAPACITY (int)((SIZE_MAX / (sizeof(void*))))
#endif
+
tor_assert(size <= MAX_CAPACITY);
if (size > (size_t) sl->capacity) {
size_t higher = (size_t) sl->capacity;
if (PREDICT_UNLIKELY(size > MAX_CAPACITY/2)) {
- tor_assert(size <= MAX_CAPACITY);
higher = MAX_CAPACITY;
} else {
while (size > higher)
higher *= 2;
}
- tor_assert(higher <= INT_MAX); /* Redundant */
+ sl->list = tor_reallocarray(sl->list, sizeof(void *),
+ ((size_t)higher));
+ memset(sl->list + sl->capacity, 0,
+ sizeof(void *) * (higher - sl->capacity));
sl->capacity = (int) higher;
- sl->list = tor_realloc(sl->list, sizeof(void*)*((size_t)sl->capacity));
}
+#undef ASSERT_CAPACITY
+#undef MAX_CAPACITY
}
/** Append element to the end of the list. */
@@ -123,6 +128,7 @@ smartlist_remove(smartlist_t *sl, const void *element)
if (sl->list[i] == element) {
sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */
i--; /* so we process the new i'th element */
+ sl->list[sl->num_used] = NULL;
}
}
@@ -132,9 +138,11 @@ void *
smartlist_pop_last(smartlist_t *sl)
{
tor_assert(sl);
- if (sl->num_used)
- return sl->list[--sl->num_used];
- else
+ if (sl->num_used) {
+ void *tmp = sl->list[--sl->num_used];
+ sl->list[sl->num_used] = NULL;
+ return tmp;
+ } else
return NULL;
}
@@ -165,6 +173,7 @@ smartlist_string_remove(smartlist_t *sl, const char *element)
tor_free(sl->list[i]);
sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */
i--; /* so we process the new i'th element */
+ sl->list[sl->num_used] = NULL;
}
}
}
@@ -208,6 +217,19 @@ smartlist_string_pos(const smartlist_t *sl, const char *element)
return -1;
}
+/** If <b>element</b> is the same pointer as an element of <b>sl</b>, return
+ * that element's index. Otherwise, return -1. */
+int
+smartlist_pos(const smartlist_t *sl, const void *element)
+{
+ int i;
+ if (!sl) return -1;
+ for (i=0; i < sl->num_used; i++)
+ if (element == sl->list[i])
+ return i;
+ return -1;
+}
+
/** Return true iff <b>sl</b> has some element E such that
* !strcasecmp(E,<b>element</b>)
*/
@@ -308,6 +330,7 @@ smartlist_intersect(smartlist_t *sl1, const smartlist_t *sl2)
if (!smartlist_contains(sl2, sl1->list[i])) {
sl1->list[i] = sl1->list[--sl1->num_used]; /* swap with the end */
i--; /* so we process the new i'th element */
+ sl1->list[sl1->num_used] = NULL;
}
}
@@ -332,6 +355,7 @@ smartlist_del(smartlist_t *sl, int idx)
tor_assert(idx>=0);
tor_assert(idx < sl->num_used);
sl->list[idx] = sl->list[--sl->num_used];
+ sl->list[sl->num_used] = NULL;
}
/** Remove the <b>idx</b>th element of sl; if idx is not the last element,
@@ -347,6 +371,7 @@ smartlist_del_keeporder(smartlist_t *sl, int idx)
--sl->num_used;
if (idx < sl->num_used)
memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx));
+ sl->list[sl->num_used] = NULL;
}
/** Insert the value <b>val</b> as the new <b>idx</b>th element of
@@ -518,11 +543,13 @@ smartlist_sort(smartlist_t *sl, int (*compare)(const void **a, const void **b))
/** Given a smartlist <b>sl</b> sorted with the function <b>compare</b>,
* return the most frequent member in the list. Break ties in favor of
- * later elements. If the list is empty, return NULL.
+ * later elements. If the list is empty, return NULL. If count_out is
+ * non-null, set it to the count of the most frequent member.
*/
void *
-smartlist_get_most_frequent(const smartlist_t *sl,
- int (*compare)(const void **a, const void **b))
+smartlist_get_most_frequent_(const smartlist_t *sl,
+ int (*compare)(const void **a, const void **b),
+ int *count_out)
{
const void *most_frequent = NULL;
int most_frequent_count = 0;
@@ -530,8 +557,11 @@ smartlist_get_most_frequent(const smartlist_t *sl,
const void *cur = NULL;
int i, count=0;
- if (!sl->num_used)
+ if (!sl->num_used) {
+ if (count_out)
+ *count_out = 0;
return NULL;
+ }
for (i = 0; i < sl->num_used; ++i) {
const void *item = sl->list[i];
if (cur && 0 == compare(&cur, &item)) {
@@ -549,6 +579,8 @@ smartlist_get_most_frequent(const smartlist_t *sl,
most_frequent = cur;
most_frequent_count = count;
}
+ if (count_out)
+ *count_out = most_frequent_count;
return (void*)most_frequent;
}
@@ -722,12 +754,22 @@ smartlist_sort_strings(smartlist_t *sl)
}
/** Return the most frequent string in the sorted list <b>sl</b> */
-char *
+const char *
smartlist_get_most_frequent_string(smartlist_t *sl)
{
return smartlist_get_most_frequent(sl, compare_string_ptrs_);
}
+/** Return the most frequent string in the sorted list <b>sl</b>.
+ * If <b>count_out</b> is provided, set <b>count_out</b> to the
+ * number of times that string appears.
+ */
+const char *
+smartlist_get_most_frequent_string_(smartlist_t *sl, int *count_out)
+{
+ return smartlist_get_most_frequent_(sl, compare_string_ptrs_, count_out);
+}
+
/** Remove duplicate strings from a sorted list, and free them with tor_free().
*/
void
@@ -798,9 +840,17 @@ smartlist_sort_pointers(smartlist_t *sl)
*
* For a 1-indexed array, we would use LEFT_CHILD[x] = 2*x and RIGHT_CHILD[x]
* = 2*x + 1. But this is C, so we have to adjust a little. */
-//#define LEFT_CHILD(i) ( ((i)+1)*2 - 1)
-//#define RIGHT_CHILD(i) ( ((i)+1)*2 )
-//#define PARENT(i) ( ((i)+1)/2 - 1)
+
+/* MAX_PARENT_IDX is the largest IDX in the smartlist which might have
+ * children whose indices fit inside an int.
+ * LEFT_CHILD(MAX_PARENT_IDX) == INT_MAX-2;
+ * RIGHT_CHILD(MAX_PARENT_IDX) == INT_MAX-1;
+ * LEFT_CHILD(MAX_PARENT_IDX + 1) == INT_MAX // impossible, see max list size.
+ */
+#define MAX_PARENT_IDX ((INT_MAX - 2) / 2)
+/* If this is true, then i is small enough to potentially have children
+ * in the smartlist, and it is save to use LEFT_CHILD/RIGHT_CHILD on it. */
+#define IDX_MAY_HAVE_CHILDREN(i) ((i) <= MAX_PARENT_IDX)
#define LEFT_CHILD(i) ( 2*(i) + 1 )
#define RIGHT_CHILD(i) ( 2*(i) + 2 )
#define PARENT(i) ( ((i)-1) / 2 )
@@ -827,13 +877,21 @@ smartlist_sort_pointers(smartlist_t *sl)
/** Helper. <b>sl</b> may have at most one violation of the heap property:
* the item at <b>idx</b> may be greater than one or both of its children.
* Restore the heap property. */
-static INLINE void
+static inline void
smartlist_heapify(smartlist_t *sl,
int (*compare)(const void *a, const void *b),
int idx_field_offset,
int idx)
{
while (1) {
+ if (! IDX_MAY_HAVE_CHILDREN(idx)) {
+ /* idx is so large that it cannot have any children, since doing so
+ * would mean the smartlist was over-capacity. Therefore it cannot
+ * violate the heap property by being greater than a child (since it
+ * doesn't have any). */
+ return;
+ }
+
int left_idx = LEFT_CHILD(idx);
int best_idx;
@@ -907,9 +965,11 @@ smartlist_pqueue_pop(smartlist_t *sl,
*IDXP(top)=-1;
if (--sl->num_used) {
sl->list[0] = sl->list[sl->num_used];
+ sl->list[sl->num_used] = NULL;
UPDATE_IDX(0);
smartlist_heapify(sl, compare, idx_field_offset, 0);
}
+ sl->list[sl->num_used] = NULL;
return top;
}
@@ -929,9 +989,11 @@ smartlist_pqueue_remove(smartlist_t *sl,
--sl->num_used;
*IDXP(item) = -1;
if (idx == sl->num_used) {
+ sl->list[sl->num_used] = NULL;
return;
} else {
sl->list[idx] = sl->list[sl->num_used];
+ sl->list[sl->num_used] = NULL;
UPDATE_IDX(idx);
smartlist_heapify(sl, compare, idx_field_offset, idx);
}
@@ -990,7 +1052,7 @@ smartlist_sort_digests256(smartlist_t *sl)
/** Return the most frequent member of the sorted list of DIGEST256_LEN
* digests in <b>sl</b> */
-char *
+const uint8_t *
smartlist_get_most_frequent_digest256(smartlist_t *sl)
{
return smartlist_get_most_frequent(sl, compare_digests256_);
@@ -1021,233 +1083,333 @@ smartlist_uniq_digests256(smartlist_t *sl)
DEFINE_MAP_STRUCTS(strmap_t, char *key, strmap_);
DEFINE_MAP_STRUCTS(digestmap_t, char key[DIGEST_LEN], digestmap_);
+DEFINE_MAP_STRUCTS(digest256map_t, uint8_t key[DIGEST256_LEN], digest256map_);
/** Helper: compare strmap_entry_t objects by key value. */
-static INLINE int
+static inline int
strmap_entries_eq(const strmap_entry_t *a, const strmap_entry_t *b)
{
return !strcmp(a->key, b->key);
}
/** Helper: return a hash value for a strmap_entry_t. */
-static INLINE unsigned int
+static inline unsigned int
strmap_entry_hash(const strmap_entry_t *a)
{
return (unsigned) siphash24g(a->key, strlen(a->key));
}
/** Helper: compare digestmap_entry_t objects by key value. */
-static INLINE int
+static inline int
digestmap_entries_eq(const digestmap_entry_t *a, const digestmap_entry_t *b)
{
return tor_memeq(a->key, b->key, DIGEST_LEN);
}
/** Helper: return a hash value for a digest_map_t. */
-static INLINE unsigned int
+static inline unsigned int
digestmap_entry_hash(const digestmap_entry_t *a)
{
return (unsigned) siphash24g(a->key, DIGEST_LEN);
}
+/** Helper: compare digestmap_entry_t objects by key value. */
+static inline int
+digest256map_entries_eq(const digest256map_entry_t *a,
+ const digest256map_entry_t *b)
+{
+ return tor_memeq(a->key, b->key, DIGEST256_LEN);
+}
+
+/** Helper: return a hash value for a digest_map_t. */
+static inline unsigned int
+digest256map_entry_hash(const digest256map_entry_t *a)
+{
+ return (unsigned) siphash24g(a->key, DIGEST256_LEN);
+}
+
HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
strmap_entries_eq)
-HT_GENERATE(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
- strmap_entries_eq, 0.6, malloc, realloc, free)
+HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
+ strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
digestmap_entries_eq)
-HT_GENERATE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
- digestmap_entries_eq, 0.6, malloc, realloc, free)
+HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
+ digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_)
-/** Constructor to create a new empty map from strings to void*'s.
- */
-strmap_t *
-strmap_new(void)
+HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node,
+ digest256map_entry_hash,
+ digest256map_entries_eq)
+HT_GENERATE2(digest256map_impl, digest256map_entry_t, node,
+ digest256map_entry_hash,
+ digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_)
+
+static inline void
+strmap_entry_free(strmap_entry_t *ent)
{
- strmap_t *result;
- result = tor_malloc(sizeof(strmap_t));
- HT_INIT(strmap_impl, &result->head);
- return result;
+ tor_free(ent->key);
+ tor_free(ent);
}
-
-/** Constructor to create a new empty map from digests to void*'s.
- */
-digestmap_t *
-digestmap_new(void)
+static inline void
+digestmap_entry_free(digestmap_entry_t *ent)
{
- digestmap_t *result;
- result = tor_malloc(sizeof(digestmap_t));
- HT_INIT(digestmap_impl, &result->head);
- return result;
+ tor_free(ent);
}
-
-/** Set the current value for <b>key</b> to <b>val</b>. Returns the previous
- * value for <b>key</b> if one was set, or NULL if one was not.
- *
- * This function makes a copy of <b>key</b> if necessary, but not of
- * <b>val</b>.
- */
-void *
-strmap_set(strmap_t *map, const char *key, void *val)
-{
- strmap_entry_t *resolve;
- strmap_entry_t search;
- void *oldval;
- tor_assert(map);
- tor_assert(key);
- tor_assert(val);
- search.key = (char*)key;
- resolve = HT_FIND(strmap_impl, &map->head, &search);
- if (resolve) {
- oldval = resolve->val;
- resolve->val = val;
- return oldval;
- } else {
- resolve = tor_malloc_zero(sizeof(strmap_entry_t));
- resolve->key = tor_strdup(key);
- resolve->val = val;
- tor_assert(!HT_FIND(strmap_impl, &map->head, resolve));
- HT_INSERT(strmap_impl, &map->head, resolve);
- return NULL;
- }
+static inline void
+digest256map_entry_free(digest256map_entry_t *ent)
+{
+ tor_free(ent);
}
-#define OPTIMIZED_DIGESTMAP_SET
-
-/** Like strmap_set() above but for digestmaps. */
-void *
-digestmap_set(digestmap_t *map, const char *key, void *val)
+static inline void
+strmap_assign_tmp_key(strmap_entry_t *ent, const char *key)
{
-#ifndef OPTIMIZED_DIGESTMAP_SET
- digestmap_entry_t *resolve;
-#endif
- digestmap_entry_t search;
- void *oldval;
- tor_assert(map);
- tor_assert(key);
- tor_assert(val);
- memcpy(&search.key, key, DIGEST_LEN);
-#ifndef OPTIMIZED_DIGESTMAP_SET
- resolve = HT_FIND(digestmap_impl, &map->head, &search);
- if (resolve) {
- oldval = resolve->val;
- resolve->val = val;
- return oldval;
- } else {
- resolve = tor_malloc_zero(sizeof(digestmap_entry_t));
- memcpy(resolve->key, key, DIGEST_LEN);
- resolve->val = val;
- HT_INSERT(digestmap_impl, &map->head, resolve);
- return NULL;
- }
-#else
- /* We spend up to 5% of our time in this function, so the code below is
- * meant to optimize the check/alloc/set cycle by avoiding the two trips to
- * the hash table that we do in the unoptimized code above. (Each of
- * HT_INSERT and HT_FIND calls HT_SET_HASH and HT_FIND_P.)
- */
- HT_FIND_OR_INSERT_(digestmap_impl, node, digestmap_entry_hash, &(map->head),
- digestmap_entry_t, &search, ptr,
- {
- /* we found an entry. */
- oldval = (*ptr)->val;
- (*ptr)->val = val;
- return oldval;
- },
- {
- /* We didn't find the entry. */
- digestmap_entry_t *newent =
- tor_malloc_zero(sizeof(digestmap_entry_t));
- memcpy(newent->key, key, DIGEST_LEN);
- newent->val = val;
- HT_FOI_INSERT_(node, &(map->head), &search, newent, ptr);
- return NULL;
- });
-#endif
+ ent->key = (char*)key;
}
-
-/** Return the current value associated with <b>key</b>, or NULL if no
- * value is set.
- */
-void *
-strmap_get(const strmap_t *map, const char *key)
-{
- strmap_entry_t *resolve;
- strmap_entry_t search;
- tor_assert(map);
- tor_assert(key);
- search.key = (char*)key;
- resolve = HT_FIND(strmap_impl, &map->head, &search);
- if (resolve) {
- return resolve->val;
- } else {
- return NULL;
- }
+static inline void
+digestmap_assign_tmp_key(digestmap_entry_t *ent, const char *key)
+{
+ memcpy(ent->key, key, DIGEST_LEN);
}
-
-/** Like strmap_get() above but for digestmaps. */
-void *
-digestmap_get(const digestmap_t *map, const char *key)
-{
- digestmap_entry_t *resolve;
- digestmap_entry_t search;
- tor_assert(map);
- tor_assert(key);
- memcpy(&search.key, key, DIGEST_LEN);
- resolve = HT_FIND(digestmap_impl, &map->head, &search);
- if (resolve) {
- return resolve->val;
- } else {
- return NULL;
- }
+static inline void
+digest256map_assign_tmp_key(digest256map_entry_t *ent, const uint8_t *key)
+{
+ memcpy(ent->key, key, DIGEST256_LEN);
+}
+static inline void
+strmap_assign_key(strmap_entry_t *ent, const char *key)
+{
+ ent->key = tor_strdup(key);
+}
+static inline void
+digestmap_assign_key(digestmap_entry_t *ent, const char *key)
+{
+ memcpy(ent->key, key, DIGEST_LEN);
+}
+static inline void
+digest256map_assign_key(digest256map_entry_t *ent, const uint8_t *key)
+{
+ memcpy(ent->key, key, DIGEST256_LEN);
}
-/** Remove the value currently associated with <b>key</b> from the map.
- * Return the value if one was set, or NULL if there was no entry for
- * <b>key</b>.
- *
- * Note: you must free any storage associated with the returned value.
+/**
+ * Macro: implement all the functions for a map that are declared in
+ * container.h by the DECLARE_MAP_FNS() macro. You must additionally define a
+ * prefix_entry_free_() function to free entries (and their keys), a
+ * prefix_assign_tmp_key() function to temporarily set a stack-allocated
+ * entry to hold a key, and a prefix_assign_key() function to set a
+ * heap-allocated entry to hold a key.
*/
-void *
-strmap_remove(strmap_t *map, const char *key)
-{
- strmap_entry_t *resolve;
- strmap_entry_t search;
- void *oldval;
- tor_assert(map);
- tor_assert(key);
- search.key = (char*)key;
- resolve = HT_REMOVE(strmap_impl, &map->head, &search);
- if (resolve) {
- oldval = resolve->val;
- tor_free(resolve->key);
- tor_free(resolve);
- return oldval;
- } else {
- return NULL;
+#define IMPLEMENT_MAP_FNS(maptype, keytype, prefix) \
+ /** Create and return a new empty map. */ \
+ MOCK_IMPL(maptype *, \
+ prefix##_new,(void)) \
+ { \
+ maptype *result; \
+ result = tor_malloc(sizeof(maptype)); \
+ HT_INIT(prefix##_impl, &result->head); \
+ return result; \
+ } \
+ \
+ /** Return the item from <b>map</b> whose key matches <b>key</b>, or \
+ * NULL if no such value exists. */ \
+ void * \
+ prefix##_get(const maptype *map, const keytype key) \
+ { \
+ prefix ##_entry_t *resolve; \
+ prefix ##_entry_t search; \
+ tor_assert(map); \
+ tor_assert(key); \
+ prefix ##_assign_tmp_key(&search, key); \
+ resolve = HT_FIND(prefix ##_impl, &map->head, &search); \
+ if (resolve) { \
+ return resolve->val; \
+ } else { \
+ return NULL; \
+ } \
+ } \
+ \
+ /** Add an entry to <b>map</b> mapping <b>key</b> to <b>val</b>; \
+ * return the previous value, or NULL if no such value existed. */ \
+ void * \
+ prefix##_set(maptype *map, const keytype key, void *val) \
+ { \
+ prefix##_entry_t search; \
+ void *oldval; \
+ tor_assert(map); \
+ tor_assert(key); \
+ tor_assert(val); \
+ prefix##_assign_tmp_key(&search, key); \
+ /* We a lot of our time in this function, so the code below is */ \
+ /* meant to optimize the check/alloc/set cycle by avoiding the two */\
+ /* trips to the hash table that we would do in the unoptimized */ \
+ /* version of this code. (Each of HT_INSERT and HT_FIND calls */ \
+ /* HT_SET_HASH and HT_FIND_P.) */ \
+ HT_FIND_OR_INSERT_(prefix##_impl, node, prefix##_entry_hash, \
+ &(map->head), \
+ prefix##_entry_t, &search, ptr, \
+ { \
+ /* we found an entry. */ \
+ oldval = (*ptr)->val; \
+ (*ptr)->val = val; \
+ return oldval; \
+ }, \
+ { \
+ /* We didn't find the entry. */ \
+ prefix##_entry_t *newent = \
+ tor_malloc_zero(sizeof(prefix##_entry_t)); \
+ prefix##_assign_key(newent, key); \
+ newent->val = val; \
+ HT_FOI_INSERT_(node, &(map->head), \
+ &search, newent, ptr); \
+ return NULL; \
+ }); \
+ } \
+ \
+ /** Remove the value currently associated with <b>key</b> from the map. \
+ * Return the value if one was set, or NULL if there was no entry for \
+ * <b>key</b>. \
+ * \
+ * Note: you must free any storage associated with the returned value. \
+ */ \
+ void * \
+ prefix##_remove(maptype *map, const keytype key) \
+ { \
+ prefix##_entry_t *resolve; \
+ prefix##_entry_t search; \
+ void *oldval; \
+ tor_assert(map); \
+ tor_assert(key); \
+ prefix##_assign_tmp_key(&search, key); \
+ resolve = HT_REMOVE(prefix##_impl, &map->head, &search); \
+ if (resolve) { \
+ oldval = resolve->val; \
+ prefix##_entry_free(resolve); \
+ return oldval; \
+ } else { \
+ return NULL; \
+ } \
+ } \
+ \
+ /** Return the number of elements in <b>map</b>. */ \
+ int \
+ prefix##_size(const maptype *map) \
+ { \
+ return HT_SIZE(&map->head); \
+ } \
+ \
+ /** Return true iff <b>map</b> has no entries. */ \
+ int \
+ prefix##_isempty(const maptype *map) \
+ { \
+ return HT_EMPTY(&map->head); \
+ } \
+ \
+ /** Assert that <b>map</b> is not corrupt. */ \
+ void \
+ prefix##_assert_ok(const maptype *map) \
+ { \
+ tor_assert(!prefix##_impl_HT_REP_IS_BAD_(&map->head)); \
+ } \
+ \
+ /** Remove all entries from <b>map</b>, and deallocate storage for \
+ * those entries. If free_val is provided, invoked it every value in \
+ * <b>map</b>. */ \
+ MOCK_IMPL(void, \
+ prefix##_free, (maptype *map, void (*free_val)(void*))) \
+ { \
+ prefix##_entry_t **ent, **next, *this; \
+ if (!map) \
+ return; \
+ for (ent = HT_START(prefix##_impl, &map->head); ent != NULL; \
+ ent = next) { \
+ this = *ent; \
+ next = HT_NEXT_RMV(prefix##_impl, &map->head, ent); \
+ if (free_val) \
+ free_val(this->val); \
+ prefix##_entry_free(this); \
+ } \
+ tor_assert(HT_EMPTY(&map->head)); \
+ HT_CLEAR(prefix##_impl, &map->head); \
+ tor_free(map); \
+ } \
+ \
+ /** return an <b>iterator</b> pointer to the front of a map. \
+ * \
+ * Iterator example: \
+ * \
+ * \code \
+ * // uppercase values in "map", removing empty values. \
+ * \
+ * strmap_iter_t *iter; \
+ * const char *key; \
+ * void *val; \
+ * char *cp; \
+ * \
+ * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) { \
+ * strmap_iter_get(iter, &key, &val); \
+ * cp = (char*)val; \
+ * if (!*cp) { \
+ * iter = strmap_iter_next_rmv(map,iter); \
+ * free(val); \
+ * } else { \
+ * for (;*cp;cp++) *cp = TOR_TOUPPER(*cp); \
+ */ \
+ prefix##_iter_t * \
+ prefix##_iter_init(maptype *map) \
+ { \
+ tor_assert(map); \
+ return HT_START(prefix##_impl, &map->head); \
+ } \
+ \
+ /** Advance <b>iter</b> a single step to the next entry, and return \
+ * its new value. */ \
+ prefix##_iter_t * \
+ prefix##_iter_next(maptype *map, prefix##_iter_t *iter) \
+ { \
+ tor_assert(map); \
+ tor_assert(iter); \
+ return HT_NEXT(prefix##_impl, &map->head, iter); \
+ } \
+ /** Advance <b>iter</b> a single step to the next entry, removing the \
+ * current entry, and return its new value. */ \
+ prefix##_iter_t * \
+ prefix##_iter_next_rmv(maptype *map, prefix##_iter_t *iter) \
+ { \
+ prefix##_entry_t *rmv; \
+ tor_assert(map); \
+ tor_assert(iter); \
+ tor_assert(*iter); \
+ rmv = *iter; \
+ iter = HT_NEXT_RMV(prefix##_impl, &map->head, iter); \
+ prefix##_entry_free(rmv); \
+ return iter; \
+ } \
+ /** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed \
+ * to by iter. */ \
+ void \
+ prefix##_iter_get(prefix##_iter_t *iter, const keytype *keyp, \
+ void **valp) \
+ { \
+ tor_assert(iter); \
+ tor_assert(*iter); \
+ tor_assert(keyp); \
+ tor_assert(valp); \
+ *keyp = (*iter)->key; \
+ *valp = (*iter)->val; \
+ } \
+ /** Return true iff <b>iter</b> has advanced past the last entry of \
+ * <b>map</b>. */ \
+ int \
+ prefix##_iter_done(prefix##_iter_t *iter) \
+ { \
+ return iter == NULL; \
}
-}
-/** Like strmap_remove() above but for digestmaps. */
-void *
-digestmap_remove(digestmap_t *map, const char *key)
-{
- digestmap_entry_t *resolve;
- digestmap_entry_t search;
- void *oldval;
- tor_assert(map);
- tor_assert(key);
- memcpy(&search.key, key, DIGEST_LEN);
- resolve = HT_REMOVE(digestmap_impl, &map->head, &search);
- if (resolve) {
- oldval = resolve->val;
- tor_free(resolve);
- return oldval;
- } else {
- return NULL;
- }
-}
+IMPLEMENT_MAP_FNS(strmap_t, char *, strmap)
+IMPLEMENT_MAP_FNS(digestmap_t, char *, digestmap)
+IMPLEMENT_MAP_FNS(digest256map_t, uint8_t *, digest256map)
/** Same as strmap_set, but first converts <b>key</b> to lowercase. */
void *
@@ -1287,231 +1449,6 @@ strmap_remove_lc(strmap_t *map, const char *key)
return v;
}
-/** return an <b>iterator</b> pointer to the front of a map.
- *
- * Iterator example:
- *
- * \code
- * // uppercase values in "map", removing empty values.
- *
- * strmap_iter_t *iter;
- * const char *key;
- * void *val;
- * char *cp;
- *
- * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) {
- * strmap_iter_get(iter, &key, &val);
- * cp = (char*)val;
- * if (!*cp) {
- * iter = strmap_iter_next_rmv(map,iter);
- * free(val);
- * } else {
- * for (;*cp;cp++) *cp = TOR_TOUPPER(*cp);
- * iter = strmap_iter_next(map,iter);
- * }
- * }
- * \endcode
- *
- */
-strmap_iter_t *
-strmap_iter_init(strmap_t *map)
-{
- tor_assert(map);
- return HT_START(strmap_impl, &map->head);
-}
-
-/** Start iterating through <b>map</b>. See strmap_iter_init() for example. */
-digestmap_iter_t *
-digestmap_iter_init(digestmap_t *map)
-{
- tor_assert(map);
- return HT_START(digestmap_impl, &map->head);
-}
-
-/** Advance the iterator <b>iter</b> for <b>map</b> a single step to the next
- * entry, and return its new value. */
-strmap_iter_t *
-strmap_iter_next(strmap_t *map, strmap_iter_t *iter)
-{
- tor_assert(map);
- tor_assert(iter);
- return HT_NEXT(strmap_impl, &map->head, iter);
-}
-
-/** Advance the iterator <b>iter</b> for map a single step to the next entry,
- * and return its new value. */
-digestmap_iter_t *
-digestmap_iter_next(digestmap_t *map, digestmap_iter_t *iter)
-{
- tor_assert(map);
- tor_assert(iter);
- return HT_NEXT(digestmap_impl, &map->head, iter);
-}
-
-/** Advance the iterator <b>iter</b> a single step to the next entry, removing
- * the current entry, and return its new value.
- */
-strmap_iter_t *
-strmap_iter_next_rmv(strmap_t *map, strmap_iter_t *iter)
-{
- strmap_entry_t *rmv;
- tor_assert(map);
- tor_assert(iter);
- tor_assert(*iter);
- rmv = *iter;
- iter = HT_NEXT_RMV(strmap_impl, &map->head, iter);
- tor_free(rmv->key);
- tor_free(rmv);
- return iter;
-}
-
-/** Advance the iterator <b>iter</b> a single step to the next entry, removing
- * the current entry, and return its new value.
- */
-digestmap_iter_t *
-digestmap_iter_next_rmv(digestmap_t *map, digestmap_iter_t *iter)
-{
- digestmap_entry_t *rmv;
- tor_assert(map);
- tor_assert(iter);
- tor_assert(*iter);
- rmv = *iter;
- iter = HT_NEXT_RMV(digestmap_impl, &map->head, iter);
- tor_free(rmv);
- return iter;
-}
-
-/** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed to by
- * iter. */
-void
-strmap_iter_get(strmap_iter_t *iter, const char **keyp, void **valp)
-{
- tor_assert(iter);
- tor_assert(*iter);
- tor_assert(keyp);
- tor_assert(valp);
- *keyp = (*iter)->key;
- *valp = (*iter)->val;
-}
-
-/** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed to by
- * iter. */
-void
-digestmap_iter_get(digestmap_iter_t *iter, const char **keyp, void **valp)
-{
- tor_assert(iter);
- tor_assert(*iter);
- tor_assert(keyp);
- tor_assert(valp);
- *keyp = (*iter)->key;
- *valp = (*iter)->val;
-}
-
-/** Return true iff <b>iter</b> has advanced past the last entry of
- * <b>map</b>. */
-int
-strmap_iter_done(strmap_iter_t *iter)
-{
- return iter == NULL;
-}
-
-/** Return true iff <b>iter</b> has advanced past the last entry of
- * <b>map</b>. */
-int
-digestmap_iter_done(digestmap_iter_t *iter)
-{
- return iter == NULL;
-}
-
-/** Remove all entries from <b>map</b>, and deallocate storage for those
- * entries. If free_val is provided, it is invoked on every value in
- * <b>map</b>.
- */
-void
-strmap_free(strmap_t *map, void (*free_val)(void*))
-{
- strmap_entry_t **ent, **next, *this;
- if (!map)
- return;
-
- for (ent = HT_START(strmap_impl, &map->head); ent != NULL; ent = next) {
- this = *ent;
- next = HT_NEXT_RMV(strmap_impl, &map->head, ent);
- tor_free(this->key);
- if (free_val)
- free_val(this->val);
- tor_free(this);
- }
- tor_assert(HT_EMPTY(&map->head));
- HT_CLEAR(strmap_impl, &map->head);
- tor_free(map);
-}
-
-/** Remove all entries from <b>map</b>, and deallocate storage for those
- * entries. If free_val is provided, it is invoked on every value in
- * <b>map</b>.
- */
-void
-digestmap_free(digestmap_t *map, void (*free_val)(void*))
-{
- digestmap_entry_t **ent, **next, *this;
- if (!map)
- return;
- for (ent = HT_START(digestmap_impl, &map->head); ent != NULL; ent = next) {
- this = *ent;
- next = HT_NEXT_RMV(digestmap_impl, &map->head, ent);
- if (free_val)
- free_val(this->val);
- tor_free(this);
- }
- tor_assert(HT_EMPTY(&map->head));
- HT_CLEAR(digestmap_impl, &map->head);
- tor_free(map);
-}
-
-/** Fail with an assertion error if anything has gone wrong with the internal
- * representation of <b>map</b>. */
-void
-strmap_assert_ok(const strmap_t *map)
-{
- tor_assert(!strmap_impl_HT_REP_IS_BAD_(&map->head));
-}
-/** Fail with an assertion error if anything has gone wrong with the internal
- * representation of <b>map</b>. */
-void
-digestmap_assert_ok(const digestmap_t *map)
-{
- tor_assert(!digestmap_impl_HT_REP_IS_BAD_(&map->head));
-}
-
-/** Return true iff <b>map</b> has no entries. */
-int
-strmap_isempty(const strmap_t *map)
-{
- return HT_EMPTY(&map->head);
-}
-
-/** Return true iff <b>map</b> has no entries. */
-int
-digestmap_isempty(const digestmap_t *map)
-{
- return HT_EMPTY(&map->head);
-}
-
-/** Return the number of items in <b>map</b>. */
-int
-strmap_size(const strmap_t *map)
-{
- return HT_SIZE(&map->head);
-}
-
-/** Return the number of items in <b>map</b>. */
-int
-digestmap_size(const digestmap_t *map)
-{
- return HT_SIZE(&map->head);
-}
-
/** Declare a function called <b>funcname</b> that acts as a find_nth_FOO
* function for an array of type <b>elt_t</b>*.
*