/src/tor/src/lib/container/map.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (c) 2003-2004, Roger Dingledine |
2 | | * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. |
3 | | * Copyright (c) 2007-2021, The Tor Project, Inc. */ |
4 | | /* See LICENSE for licensing information */ |
5 | | |
6 | | /** |
7 | | * \file map.c |
8 | | * |
9 | | * \brief Hash-table implementations of a string-to-void* map, and of |
10 | | * a digest-to-void* map. |
11 | | **/ |
12 | | |
13 | | #include "lib/container/map.h" |
14 | | #include "lib/ctime/di_ops.h" |
15 | | #include "lib/defs/digest_sizes.h" |
16 | | #include "lib/string/util_string.h" |
17 | | #include "lib/malloc/malloc.h" |
18 | | |
19 | | #include "lib/log/util_bug.h" |
20 | | |
21 | | #include <stdlib.h> |
22 | | #include <string.h> |
23 | | |
24 | | #include "ext/ht.h" |
25 | | |
26 | | /** Helper: Declare an entry type and a map type to implement a mapping using |
27 | | * ht.h. The map type will be called <b>maptype</b>. The key part of each |
28 | | * entry is declared using the C declaration <b>keydecl</b>. All functions |
29 | | * and types associated with the map get prefixed with <b>prefix</b> */ |
30 | | #define DEFINE_MAP_STRUCTS(maptype, keydecl, prefix) \ |
31 | | typedef struct prefix ## entry_t { \ |
32 | | HT_ENTRY(prefix ## entry_t) node; \ |
33 | | void *val; \ |
34 | | keydecl; \ |
35 | | } prefix ## entry_t; \ |
36 | | struct maptype { \ |
37 | | HT_HEAD(prefix ## impl, prefix ## entry_t) head; \ |
38 | | } |
39 | | |
40 | | DEFINE_MAP_STRUCTS(strmap_t, char *key, strmap_); |
41 | | DEFINE_MAP_STRUCTS(digestmap_t, char key[DIGEST_LEN], digestmap_); |
42 | | DEFINE_MAP_STRUCTS(digest256map_t, uint8_t key[DIGEST256_LEN], digest256map_); |
43 | | |
44 | | /** Helper: compare strmap_entry_t objects by key value. */ |
45 | | static inline int |
46 | | strmap_entries_eq(const strmap_entry_t *a, const strmap_entry_t *b) |
47 | 8.64k | { |
48 | 8.64k | return !strcmp(a->key, b->key); |
49 | 8.64k | } |
50 | | |
51 | | /** Helper: return a hash value for a strmap_entry_t. */ |
52 | | static inline unsigned int |
53 | | strmap_entry_hash(const strmap_entry_t *a) |
54 | 8.60k | { |
55 | 8.60k | return (unsigned) siphash24g(a->key, strlen(a->key)); |
56 | 8.60k | } |
57 | | |
58 | | /** Helper: compare digestmap_entry_t objects by key value. */ |
59 | | static inline int |
60 | | digestmap_entries_eq(const digestmap_entry_t *a, const digestmap_entry_t *b) |
61 | 0 | { |
62 | 0 | return tor_memeq(a->key, b->key, DIGEST_LEN); |
63 | 0 | } |
64 | | |
65 | | /** Helper: return a hash value for a digest_map_t. */ |
66 | | static inline unsigned int |
67 | | digestmap_entry_hash(const digestmap_entry_t *a) |
68 | 0 | { |
69 | 0 | return (unsigned) siphash24g(a->key, DIGEST_LEN); |
70 | 0 | } |
71 | | |
72 | | /** Helper: compare digestmap_entry_t objects by key value. */ |
73 | | static inline int |
74 | | digest256map_entries_eq(const digest256map_entry_t *a, |
75 | | const digest256map_entry_t *b) |
76 | 49 | { |
77 | 49 | return tor_memeq(a->key, b->key, DIGEST256_LEN); |
78 | 49 | } |
79 | | |
80 | | /** Helper: return a hash value for a digest_map_t. */ |
81 | | static inline unsigned int |
82 | | digest256map_entry_hash(const digest256map_entry_t *a) |
83 | 104 | { |
84 | 104 | return (unsigned) siphash24g(a->key, DIGEST256_LEN); |
85 | 104 | } |
86 | | |
87 | | HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash, |
88 | | strmap_entries_eq); |
89 | | HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash, |
90 | | strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_); |
91 | | |
92 | | HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, |
93 | | digestmap_entries_eq); |
94 | | HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash, |
95 | | digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_); |
96 | | |
97 | | HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node, |
98 | | digest256map_entry_hash, |
99 | | digest256map_entries_eq); |
100 | | HT_GENERATE2(digest256map_impl, digest256map_entry_t, node, |
101 | | digest256map_entry_hash, |
102 | | digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_); |
103 | | |
104 | | #define strmap_entry_free(ent) \ |
105 | 0 | FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent)) |
106 | | #define digestmap_entry_free(ent) \ |
107 | 0 | FREE_AND_NULL(digestmap_entry_t, digestmap_entry_free_, (ent)) |
108 | | #define digest256map_entry_free(ent) \ |
109 | 51 | FREE_AND_NULL(digest256map_entry_t, digest256map_entry_free_, (ent)) |
110 | | |
111 | | static inline void |
112 | | strmap_entry_free_(strmap_entry_t *ent) |
113 | 0 | { |
114 | 0 | tor_free(ent->key); |
115 | 0 | tor_free(ent); |
116 | 0 | } |
117 | | static inline void |
118 | | digestmap_entry_free_(digestmap_entry_t *ent) |
119 | 0 | { |
120 | 0 | tor_free(ent); |
121 | 0 | } |
122 | | static inline void |
123 | | digest256map_entry_free_(digest256map_entry_t *ent) |
124 | 51 | { |
125 | 51 | tor_free(ent); |
126 | 51 | } |
127 | | |
128 | | static inline void |
129 | | strmap_assign_tmp_key(strmap_entry_t *ent, const char *key) |
130 | 8.60k | { |
131 | 8.60k | ent->key = (char*)key; |
132 | 8.60k | } |
133 | | static inline void |
134 | | digestmap_assign_tmp_key(digestmap_entry_t *ent, const char *key) |
135 | 0 | { |
136 | 0 | memcpy(ent->key, key, DIGEST_LEN); |
137 | 0 | } |
138 | | static inline void |
139 | | digest256map_assign_tmp_key(digest256map_entry_t *ent, const uint8_t *key) |
140 | 104 | { |
141 | 104 | memcpy(ent->key, key, DIGEST256_LEN); |
142 | 104 | } |
143 | | static inline void |
144 | | strmap_assign_key(strmap_entry_t *ent, const char *key) |
145 | 2.17k | { |
146 | 2.17k | ent->key = tor_strdup(key); |
147 | 2.17k | } |
148 | | static inline void |
149 | | digestmap_assign_key(digestmap_entry_t *ent, const char *key) |
150 | 0 | { |
151 | 0 | memcpy(ent->key, key, DIGEST_LEN); |
152 | 0 | } |
153 | | static inline void |
154 | | digest256map_assign_key(digest256map_entry_t *ent, const uint8_t *key) |
155 | 51 | { |
156 | 51 | memcpy(ent->key, key, DIGEST256_LEN); |
157 | 51 | } |
158 | | |
159 | | /** |
160 | | * Macro: implement all the functions for a map that are declared in |
161 | | * map.h by the DECLARE_MAP_FNS() macro. You must additionally define a |
162 | | * prefix_entry_free_() function to free entries (and their keys), a |
163 | | * prefix_assign_tmp_key() function to temporarily set a stack-allocated |
164 | | * entry to hold a key, and a prefix_assign_key() function to set a |
165 | | * heap-allocated entry to hold a key. |
166 | | */ |
167 | | #define IMPLEMENT_MAP_FNS(maptype, keytype, prefix) \ |
168 | | /** Create and return a new empty map. */ \ |
169 | | MOCK_IMPL(maptype *, \ |
170 | | prefix##_new,(void)) \ |
171 | 515 | { \ |
172 | 515 | maptype *result; \ |
173 | 515 | result = tor_malloc(sizeof(maptype)); \ |
174 | 515 | HT_INIT(prefix##_impl, &result->head); \ |
175 | 515 | return result; \ |
176 | 515 | } \ Line | Count | Source | 171 | 21 | { \ | 172 | 21 | maptype *result; \ | 173 | 21 | result = tor_malloc(sizeof(maptype)); \ | 174 | 21 | HT_INIT(prefix##_impl, &result->head); \ | 175 | 21 | return result; \ | 176 | 21 | } \ |
Unexecuted instantiation: digestmap_new__real Line | Count | Source | 171 | 494 | { \ | 172 | 494 | maptype *result; \ | 173 | 494 | result = tor_malloc(sizeof(maptype)); \ | 174 | 494 | HT_INIT(prefix##_impl, &result->head); \ | 175 | 494 | return result; \ | 176 | 494 | } \ |
|
177 | | \ |
178 | | /** Return the item from <b>map</b> whose key matches <b>key</b>, or \ |
179 | | * NULL if no such value exists. */ \ |
180 | | void * \ |
181 | | prefix##_get(const maptype *map, const keytype key) \ |
182 | 6.47k | { \ |
183 | 6.47k | prefix ##_entry_t *resolve; \ |
184 | 6.47k | prefix ##_entry_t search; \ |
185 | 6.47k | tor_assert(map); \ |
186 | 6.47k | tor_assert(key); \ |
187 | 6.47k | prefix ##_assign_tmp_key(&search, key); \ |
188 | 6.47k | resolve = HT_FIND(prefix ##_impl, &map->head, &search); \ |
189 | 6.47k | if (resolve) { \ |
190 | 4.02k | return resolve->val; \ |
191 | 4.02k | } else { \ |
192 | 2.45k | return NULL; \ |
193 | 2.45k | } \ |
194 | 6.47k | } \ Line | Count | Source | 182 | 6.42k | { \ | 183 | 6.42k | prefix ##_entry_t *resolve; \ | 184 | 6.42k | prefix ##_entry_t search; \ | 185 | 6.42k | tor_assert(map); \ | 186 | 6.42k | tor_assert(key); \ | 187 | 6.42k | prefix ##_assign_tmp_key(&search, key); \ | 188 | 6.42k | resolve = HT_FIND(prefix ##_impl, &map->head, &search); \ | 189 | 6.42k | if (resolve) { \ | 190 | 4.02k | return resolve->val; \ | 191 | 4.02k | } else { \ | 192 | 2.40k | return NULL; \ | 193 | 2.40k | } \ | 194 | 6.42k | } \ |
Unexecuted instantiation: digestmap_get Line | Count | Source | 182 | 53 | { \ | 183 | 53 | prefix ##_entry_t *resolve; \ | 184 | 53 | prefix ##_entry_t search; \ | 185 | 53 | tor_assert(map); \ | 186 | 53 | tor_assert(key); \ | 187 | 53 | prefix ##_assign_tmp_key(&search, key); \ | 188 | 53 | resolve = HT_FIND(prefix ##_impl, &map->head, &search); \ | 189 | 53 | if (resolve) { \ | 190 | 2 | return resolve->val; \ | 191 | 51 | } else { \ | 192 | 51 | return NULL; \ | 193 | 51 | } \ | 194 | 53 | } \ |
|
195 | | \ |
196 | | /** Add an entry to <b>map</b> mapping <b>key</b> to <b>val</b>; \ |
197 | | * return the previous value, or NULL if no such value existed. */ \ |
198 | | void * \ |
199 | | prefix##_set(maptype *map, const keytype key, void *val) \ |
200 | 2.22k | { \ |
201 | 2.22k | prefix##_entry_t search; \ |
202 | 2.22k | void *oldval; \ |
203 | 2.22k | tor_assert(map); \ |
204 | 2.22k | tor_assert(key); \ |
205 | 2.22k | tor_assert(val); \ |
206 | 2.22k | prefix##_assign_tmp_key(&search, key); \ |
207 | 2.22k | /* We a lot of our time in this function, so the code below is */ \ |
208 | 2.22k | /* meant to optimize the check/alloc/set cycle by avoiding the two */\ |
209 | 2.22k | /* trips to the hash table that we would do in the unoptimized */ \ |
210 | 2.22k | /* version of this code. (Each of HT_INSERT and HT_FIND calls */ \ |
211 | 2.22k | /* HT_SET_HASH and HT_FIND_P.) */ \ |
212 | 2.22k | HT_FIND_OR_INSERT_(prefix##_impl, node, prefix##_entry_hash, \ |
213 | 2.22k | &(map->head), \ |
214 | 2.22k | prefix##_entry_t, &search, ptr, \ |
215 | 2.22k | { \ |
216 | 2.22k | /* we found an entry. */ \ |
217 | 2.22k | oldval = (*ptr)->val; \ |
218 | 2.22k | (*ptr)->val = val; \ |
219 | 2.22k | return oldval; \ |
220 | 2.22k | }, \ |
221 | 2.22k | { \ |
222 | 2.22k | /* We didn't find the entry. */ \ |
223 | 2.22k | prefix##_entry_t *newent = \ |
224 | 2.22k | tor_malloc_zero(sizeof(prefix##_entry_t)); \ |
225 | 2.22k | prefix##_assign_key(newent, key); \ |
226 | 2.22k | newent->val = val; \ |
227 | 2.22k | HT_FOI_INSERT_(node, &(map->head), \ |
228 | 2.22k | &search, newent, ptr); \ |
229 | 2.22k | return NULL; \ |
230 | 2.22k | }); \ |
231 | 0 | } \ Line | Count | Source | 200 | 2.17k | { \ | 201 | 2.17k | prefix##_entry_t search; \ | 202 | 2.17k | void *oldval; \ | 203 | 2.17k | tor_assert(map); \ | 204 | 2.17k | tor_assert(key); \ | 205 | 2.17k | tor_assert(val); \ | 206 | 2.17k | prefix##_assign_tmp_key(&search, key); \ | 207 | 2.17k | /* We a lot of our time in this function, so the code below is */ \ | 208 | 2.17k | /* meant to optimize the check/alloc/set cycle by avoiding the two */\ | 209 | 2.17k | /* trips to the hash table that we would do in the unoptimized */ \ | 210 | 2.17k | /* version of this code. (Each of HT_INSERT and HT_FIND calls */ \ | 211 | 2.17k | /* HT_SET_HASH and HT_FIND_P.) */ \ | 212 | 2.17k | HT_FIND_OR_INSERT_(prefix##_impl, node, prefix##_entry_hash, \ | 213 | 2.17k | &(map->head), \ | 214 | 2.17k | prefix##_entry_t, &search, ptr, \ | 215 | 2.17k | { \ | 216 | 2.17k | /* we found an entry. */ \ | 217 | 2.17k | oldval = (*ptr)->val; \ | 218 | 2.17k | (*ptr)->val = val; \ | 219 | 2.17k | return oldval; \ | 220 | 2.17k | }, \ | 221 | 2.17k | { \ | 222 | 2.17k | /* We didn't find the entry. */ \ | 223 | 2.17k | prefix##_entry_t *newent = \ | 224 | 2.17k | tor_malloc_zero(sizeof(prefix##_entry_t)); \ | 225 | 2.17k | prefix##_assign_key(newent, key); \ | 226 | 2.17k | newent->val = val; \ | 227 | 2.17k | HT_FOI_INSERT_(node, &(map->head), \ | 228 | 2.17k | &search, newent, ptr); \ | 229 | 2.17k | return NULL; \ | 230 | 2.17k | }); \ | 231 | 0 | } \ |
Unexecuted instantiation: digestmap_set Line | Count | Source | 200 | 51 | { \ | 201 | 51 | prefix##_entry_t search; \ | 202 | 51 | void *oldval; \ | 203 | 51 | tor_assert(map); \ | 204 | 51 | tor_assert(key); \ | 205 | 51 | tor_assert(val); \ | 206 | 51 | prefix##_assign_tmp_key(&search, key); \ | 207 | 51 | /* We a lot of our time in this function, so the code below is */ \ | 208 | 51 | /* meant to optimize the check/alloc/set cycle by avoiding the two */\ | 209 | 51 | /* trips to the hash table that we would do in the unoptimized */ \ | 210 | 51 | /* version of this code. (Each of HT_INSERT and HT_FIND calls */ \ | 211 | 51 | /* HT_SET_HASH and HT_FIND_P.) */ \ | 212 | 51 | HT_FIND_OR_INSERT_(prefix##_impl, node, prefix##_entry_hash, \ | 213 | 51 | &(map->head), \ | 214 | 51 | prefix##_entry_t, &search, ptr, \ | 215 | 51 | { \ | 216 | 51 | /* we found an entry. */ \ | 217 | 51 | oldval = (*ptr)->val; \ | 218 | 51 | (*ptr)->val = val; \ | 219 | 51 | return oldval; \ | 220 | 51 | }, \ | 221 | 51 | { \ | 222 | 51 | /* We didn't find the entry. */ \ | 223 | 51 | prefix##_entry_t *newent = \ | 224 | 51 | tor_malloc_zero(sizeof(prefix##_entry_t)); \ | 225 | 51 | prefix##_assign_key(newent, key); \ | 226 | 51 | newent->val = val; \ | 227 | 51 | HT_FOI_INSERT_(node, &(map->head), \ | 228 | 51 | &search, newent, ptr); \ | 229 | 51 | return NULL; \ | 230 | 51 | }); \ | 231 | 0 | } \ |
|
232 | | \ |
233 | | /** Remove the value currently associated with <b>key</b> from the map. \ |
234 | | * Return the value if one was set, or NULL if there was no entry for \ |
235 | | * <b>key</b>. \ |
236 | | * \ |
237 | | * Note: you must free any storage associated with the returned value. \ |
238 | | */ \ |
239 | | void * \ |
240 | | prefix##_remove(maptype *map, const keytype key) \ |
241 | 0 | { \ |
242 | 0 | prefix##_entry_t *resolve; \ |
243 | 0 | prefix##_entry_t search; \ |
244 | 0 | void *oldval; \ |
245 | 0 | tor_assert(map); \ |
246 | 0 | tor_assert(key); \ |
247 | 0 | prefix##_assign_tmp_key(&search, key); \ |
248 | 0 | resolve = HT_REMOVE(prefix##_impl, &map->head, &search); \ |
249 | 0 | if (resolve) { \ |
250 | 0 | oldval = resolve->val; \ |
251 | 0 | prefix##_entry_free(resolve); \ |
252 | 0 | return oldval; \ |
253 | 0 | } else { \ |
254 | 0 | return NULL; \ |
255 | 0 | } \ |
256 | 0 | } \ Unexecuted instantiation: strmap_remove Unexecuted instantiation: digestmap_remove Unexecuted instantiation: digest256map_remove |
257 | | \ |
258 | | /** Return the number of elements in <b>map</b>. */ \ |
259 | | int \ |
260 | | prefix##_size(const maptype *map) \ |
261 | 6.19k | { \ |
262 | 6.19k | return HT_SIZE(&map->head); \ |
263 | 6.19k | } \ Line | Count | Source | 261 | 6.19k | { \ | 262 | 6.19k | return HT_SIZE(&map->head); \ | 263 | 6.19k | } \ |
Unexecuted instantiation: digestmap_size Unexecuted instantiation: digest256map_size |
264 | | \ |
265 | | /** Return true iff <b>map</b> has no entries. */ \ |
266 | | int \ |
267 | | prefix##_isempty(const maptype *map) \ |
268 | 0 | { \ |
269 | 0 | return HT_EMPTY(&map->head); \ |
270 | 0 | } \ Unexecuted instantiation: strmap_isempty Unexecuted instantiation: digestmap_isempty Unexecuted instantiation: digest256map_isempty |
271 | | \ |
272 | | /** Assert that <b>map</b> is not corrupt. */ \ |
273 | | void \ |
274 | | prefix##_assert_ok(const maptype *map) \ |
275 | 0 | { \ |
276 | 0 | tor_assert(!prefix##_impl_HT_REP_IS_BAD_(&map->head)); \ |
277 | 0 | } \ Unexecuted instantiation: strmap_assert_ok Unexecuted instantiation: digestmap_assert_ok Unexecuted instantiation: digest256map_assert_ok |
278 | | \ |
279 | | /** Remove all entries from <b>map</b>, and deallocate storage for \ |
280 | | * those entries. If free_val is provided, invoked it every value in \ |
281 | | * <b>map</b>. */ \ |
282 | | MOCK_IMPL(void, \ |
283 | | prefix##_free_, (maptype *map, void (*free_val)(void*))) \ |
284 | 8.03k | { \ |
285 | 8.03k | prefix##_entry_t **ent, **next, *this; \ |
286 | 8.03k | if (!map) \ |
287 | 8.03k | return; \ |
288 | 8.03k | for (ent = HT_START(prefix##_impl, &map->head); ent != NULL; \ |
289 | 494 | ent = next) { \ |
290 | 51 | this = *ent; \ |
291 | 51 | next = HT_NEXT_RMV(prefix##_impl, &map->head, ent); \ |
292 | 51 | if (free_val) \ |
293 | 51 | free_val(this->val); \ |
294 | 51 | prefix##_entry_free(this); \ |
295 | 51 | } \ |
296 | 494 | tor_assert(HT_EMPTY(&map->head)); \ |
297 | 494 | HT_CLEAR(prefix##_impl, &map->head); \ |
298 | 494 | tor_free(map); \ |
299 | 494 | } \ Unexecuted instantiation: strmap_free___real Line | Count | Source | 284 | 7.53k | { \ | 285 | 7.53k | prefix##_entry_t **ent, **next, *this; \ | 286 | 7.53k | if (!map) \ | 287 | 7.53k | return; \ | 288 | 7.53k | for (ent = HT_START(prefix##_impl, &map->head); ent != NULL; \ | 289 | 0 | ent = next) { \ | 290 | 0 | this = *ent; \ | 291 | 0 | next = HT_NEXT_RMV(prefix##_impl, &map->head, ent); \ | 292 | 0 | if (free_val) \ | 293 | 0 | free_val(this->val); \ | 294 | 0 | prefix##_entry_free(this); \ | 295 | 0 | } \ | 296 | 0 | tor_assert(HT_EMPTY(&map->head)); \ | 297 | 0 | HT_CLEAR(prefix##_impl, &map->head); \ | 298 | 0 | tor_free(map); \ | 299 | 0 | } \ |
Line | Count | Source | 284 | 494 | { \ | 285 | 494 | prefix##_entry_t **ent, **next, *this; \ | 286 | 494 | if (!map) \ | 287 | 494 | return; \ | 288 | 545 | for (ent = HT_START(prefix##_impl, &map->head); ent != NULL; \ | 289 | 494 | ent = next) { \ | 290 | 51 | this = *ent; \ | 291 | 51 | next = HT_NEXT_RMV(prefix##_impl, &map->head, ent); \ | 292 | 51 | if (free_val) \ | 293 | 51 | free_val(this->val); \ | 294 | 51 | prefix##_entry_free(this); \ | 295 | 51 | } \ | 296 | 494 | tor_assert(HT_EMPTY(&map->head)); \ | 297 | 494 | HT_CLEAR(prefix##_impl, &map->head); \ | 298 | 494 | tor_free(map); \ | 299 | 494 | } \ |
|
300 | | \ |
301 | | /** return an <b>iterator</b> pointer to the front of a map. \ |
302 | | * \ |
303 | | * Iterator example: \ |
304 | | * \ |
305 | | * \code \ |
306 | | * // uppercase values in "map", removing empty values. \ |
307 | | * \ |
308 | | * strmap_iter_t *iter; \ |
309 | | * const char *key; \ |
310 | | * void *val; \ |
311 | | * char *cp; \ |
312 | | * \ |
313 | | * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) { \ |
314 | | * strmap_iter_get(iter, &key, &val); \ |
315 | | * cp = (char*)val; \ |
316 | | * if (!*cp) { \ |
317 | | * iter = strmap_iter_next_rmv(map,iter); \ |
318 | | * free(val); \ |
319 | | * } else { \ |
320 | | * for (;*cp;cp++) *cp = TOR_TOUPPER(*cp); \ |
321 | | */ \ |
322 | | prefix##_iter_t * \ |
323 | | prefix##_iter_init(maptype *map) \ |
324 | 0 | { \ |
325 | 0 | tor_assert(map); \ |
326 | 0 | return HT_START(prefix##_impl, &map->head); \ |
327 | 0 | } \ Unexecuted instantiation: strmap_iter_init Unexecuted instantiation: digestmap_iter_init Unexecuted instantiation: digest256map_iter_init |
328 | | \ |
329 | | /** Advance <b>iter</b> a single step to the next entry, and return \ |
330 | | * its new value. */ \ |
331 | | prefix##_iter_t * \ |
332 | | prefix##_iter_next(maptype *map, prefix##_iter_t *iter) \ |
333 | 0 | { \ |
334 | 0 | tor_assert(map); \ |
335 | 0 | tor_assert(iter); \ |
336 | 0 | return HT_NEXT(prefix##_impl, &map->head, iter); \ |
337 | 0 | } \ Unexecuted instantiation: strmap_iter_next Unexecuted instantiation: digestmap_iter_next Unexecuted instantiation: digest256map_iter_next |
338 | | /** Advance <b>iter</b> a single step to the next entry, removing the \ |
339 | | * current entry, and return its new value. */ \ |
340 | | prefix##_iter_t * \ |
341 | | prefix##_iter_next_rmv(maptype *map, prefix##_iter_t *iter) \ |
342 | 0 | { \ |
343 | 0 | prefix##_entry_t *rmv; \ |
344 | 0 | tor_assert(map); \ |
345 | 0 | tor_assert(iter); \ |
346 | 0 | tor_assert(*iter); \ |
347 | 0 | rmv = *iter; \ |
348 | 0 | iter = HT_NEXT_RMV(prefix##_impl, &map->head, iter); \ |
349 | 0 | prefix##_entry_free(rmv); \ |
350 | 0 | return iter; \ |
351 | 0 | } \ Unexecuted instantiation: strmap_iter_next_rmv Unexecuted instantiation: digestmap_iter_next_rmv Unexecuted instantiation: digest256map_iter_next_rmv |
352 | | /** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed \ |
353 | | * to by iter. */ \ |
354 | | void \ |
355 | | prefix##_iter_get(prefix##_iter_t *iter, const keytype *keyp, \ |
356 | | void **valp) \ |
357 | 0 | { \ |
358 | 0 | tor_assert(iter); \ |
359 | 0 | tor_assert(*iter); \ |
360 | 0 | tor_assert(keyp); \ |
361 | 0 | tor_assert(valp); \ |
362 | 0 | *keyp = (*iter)->key; \ |
363 | 0 | *valp = (*iter)->val; \ |
364 | 0 | } \ Unexecuted instantiation: strmap_iter_get Unexecuted instantiation: digestmap_iter_get Unexecuted instantiation: digest256map_iter_get |
365 | | /** Return true iff <b>iter</b> has advanced past the last entry of \ |
366 | | * <b>map</b>. */ \ |
367 | | int \ |
368 | | prefix##_iter_done(prefix##_iter_t *iter) \ |
369 | 0 | { \ |
370 | 0 | return iter == NULL; \ |
371 | 0 | } Unexecuted instantiation: strmap_iter_done Unexecuted instantiation: digestmap_iter_done Unexecuted instantiation: digest256map_iter_done |
372 | | |
373 | | IMPLEMENT_MAP_FNS(strmap_t, char *, strmap) |
374 | | IMPLEMENT_MAP_FNS(digestmap_t, char *, digestmap) |
375 | | IMPLEMENT_MAP_FNS(digest256map_t, uint8_t *, digest256map) |
376 | | |
377 | | /** Same as strmap_set, but first converts <b>key</b> to lowercase. */ |
378 | | void * |
379 | | strmap_set_lc(strmap_t *map, const char *key, void *val) |
380 | 0 | { |
381 | | /* We could be a little faster by using strcasecmp instead, and a separate |
382 | | * type, but I don't think it matters. */ |
383 | 0 | void *v; |
384 | 0 | char *lc_key = tor_strdup(key); |
385 | 0 | tor_strlower(lc_key); |
386 | 0 | v = strmap_set(map,lc_key,val); |
387 | 0 | tor_free(lc_key); |
388 | 0 | return v; |
389 | 0 | } |
390 | | |
391 | | /** Same as strmap_get, but first converts <b>key</b> to lowercase. */ |
392 | | void * |
393 | | strmap_get_lc(const strmap_t *map, const char *key) |
394 | 227 | { |
395 | 227 | void *v; |
396 | 227 | char *lc_key = tor_strdup(key); |
397 | 227 | tor_strlower(lc_key); |
398 | 227 | v = strmap_get(map,lc_key); |
399 | 227 | tor_free(lc_key); |
400 | 227 | return v; |
401 | 227 | } |
402 | | |
403 | | /** Same as strmap_remove, but first converts <b>key</b> to lowercase */ |
404 | | void * |
405 | | strmap_remove_lc(strmap_t *map, const char *key) |
406 | 0 | { |
407 | 0 | void *v; |
408 | 0 | char *lc_key = tor_strdup(key); |
409 | 0 | tor_strlower(lc_key); |
410 | 0 | v = strmap_remove(map,lc_key); |
411 | 0 | tor_free(lc_key); |
412 | 0 | return v; |
413 | 0 | } |