]>
Commit | Line | Data |
---|---|---|
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ | |
2 | #pragma once | |
3 | ||
4 | #include <limits.h> | |
5 | #include <stdbool.h> | |
6 | #include <stddef.h> | |
7 | ||
8 | #include "hash-funcs.h" | |
9 | #include "macro.h" | |
10 | #include "util.h" | |
11 | ||
12 | /* | |
13 | * A hash table implementation. As a minor optimization a NULL hashmap object | |
14 | * will be treated as empty hashmap for all read operations. That way it is not | |
15 | * necessary to instantiate an object for each Hashmap use. | |
16 | * | |
17 | * If ENABLE_DEBUG_HASHMAP is defined (by configuring with -Ddebug-extra=hashmap), | |
18 | * the implementation will: | |
19 | * - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py) | |
20 | * - perform extra checks for invalid use of iterators | |
21 | */ | |
22 | ||
23 | #define HASH_KEY_SIZE 16 | |
24 | ||
25 | typedef void* (*hashmap_destroy_t)(void *p); | |
26 | ||
27 | /* The base type for all hashmap and set types. Many functions in the implementation take (HashmapBase*) | |
28 | * parameters and are run-time polymorphic, though the API is not meant to be polymorphic (do not call | |
29 | * underscore-prefixed functions directly). */ | |
30 | typedef struct HashmapBase HashmapBase; | |
31 | ||
32 | /* Specific hashmap/set types */ | |
33 | typedef struct Hashmap Hashmap; /* Maps keys to values */ | |
34 | typedef struct OrderedHashmap OrderedHashmap; /* Like Hashmap, but also remembers entry insertion order */ | |
35 | typedef struct Set Set; /* Stores just keys */ | |
36 | ||
37 | typedef struct IteratedCache IteratedCache; /* Caches the iterated order of one of the above */ | |
38 | ||
39 | /* Ideally the Iterator would be an opaque struct, but it is instantiated | |
40 | * by hashmap users, so the definition has to be here. Do not use its fields | |
41 | * directly. */ | |
42 | typedef struct { | |
43 | unsigned idx; /* index of an entry to be iterated next */ | |
44 | const void *next_key; /* expected value of that entry's key pointer */ | |
45 | #if ENABLE_DEBUG_HASHMAP | |
46 | unsigned put_count; /* hashmap's put_count recorded at start of iteration */ | |
47 | unsigned rem_count; /* hashmap's rem_count in previous iteration */ | |
48 | unsigned prev_idx; /* idx in previous iteration */ | |
49 | #endif | |
50 | } Iterator; | |
51 | ||
52 | #define _IDX_ITERATOR_FIRST (UINT_MAX - 1) | |
53 | #define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL }) | |
54 | ||
55 | /* Macros for type checking */ | |
56 | #define PTR_COMPATIBLE_WITH_HASHMAP_BASE(h) \ | |
57 | (__builtin_types_compatible_p(typeof(h), HashmapBase*) || \ | |
58 | __builtin_types_compatible_p(typeof(h), Hashmap*) || \ | |
59 | __builtin_types_compatible_p(typeof(h), OrderedHashmap*) || \ | |
60 | __builtin_types_compatible_p(typeof(h), Set*)) | |
61 | ||
62 | #define PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h) \ | |
63 | (__builtin_types_compatible_p(typeof(h), Hashmap*) || \ | |
64 | __builtin_types_compatible_p(typeof(h), OrderedHashmap*)) \ | |
65 | ||
66 | #define HASHMAP_BASE(h) \ | |
67 | __builtin_choose_expr(PTR_COMPATIBLE_WITH_HASHMAP_BASE(h), \ | |
68 | (HashmapBase*)(h), \ | |
69 | (void)0) | |
70 | ||
71 | #define PLAIN_HASHMAP(h) \ | |
72 | __builtin_choose_expr(PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h), \ | |
73 | (Hashmap*)(h), \ | |
74 | (void)0) | |
75 | ||
76 | #if ENABLE_DEBUG_HASHMAP | |
77 | # define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line | |
78 | # define HASHMAP_DEBUG_SRC_ARGS , __func__, PROJECT_FILE, __LINE__ | |
79 | # define HASHMAP_DEBUG_PASS_ARGS , func, file, line | |
80 | #else | |
81 | # define HASHMAP_DEBUG_PARAMS | |
82 | # define HASHMAP_DEBUG_SRC_ARGS | |
83 | # define HASHMAP_DEBUG_PASS_ARGS | |
84 | #endif | |
85 | ||
86 | Hashmap* _hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); | |
87 | OrderedHashmap* _ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); | |
88 | #define hashmap_new(ops) _hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) | |
89 | #define ordered_hashmap_new(ops) _ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS) | |
90 | ||
91 | #define hashmap_free_and_replace(a, b) \ | |
92 | ({ \ | |
93 | hashmap_free(a); \ | |
94 | (a) = (b); \ | |
95 | (b) = NULL; \ | |
96 | 0; \ | |
97 | }) | |
98 | ||
99 | HashmapBase* _hashmap_free(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value); | |
100 | static inline Hashmap* hashmap_free(Hashmap *h) { | |
101 | return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL); | |
102 | } | |
103 | static inline OrderedHashmap* ordered_hashmap_free(OrderedHashmap *h) { | |
104 | return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL); | |
105 | } | |
106 | ||
107 | static inline Hashmap* hashmap_free_free(Hashmap *h) { | |
108 | return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free); | |
109 | } | |
110 | static inline OrderedHashmap* ordered_hashmap_free_free(OrderedHashmap *h) { | |
111 | return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free); | |
112 | } | |
113 | ||
114 | static inline Hashmap* hashmap_free_free_key(Hashmap *h) { | |
115 | return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL); | |
116 | } | |
117 | static inline OrderedHashmap* ordered_hashmap_free_free_key(OrderedHashmap *h) { | |
118 | return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL); | |
119 | } | |
120 | ||
121 | static inline Hashmap* hashmap_free_free_free(Hashmap *h) { | |
122 | return (void*) _hashmap_free(HASHMAP_BASE(h), free, free); | |
123 | } | |
124 | static inline OrderedHashmap* ordered_hashmap_free_free_free(OrderedHashmap *h) { | |
125 | return (void*) _hashmap_free(HASHMAP_BASE(h), free, free); | |
126 | } | |
127 | ||
128 | IteratedCache* iterated_cache_free(IteratedCache *cache); | |
129 | int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries); | |
130 | ||
131 | HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS); | |
132 | #define hashmap_copy(h) ((Hashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS)) | |
133 | #define ordered_hashmap_copy(h) ((OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS)) | |
134 | ||
135 | int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); | |
136 | int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); | |
137 | #define hashmap_ensure_allocated(h, ops) _hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) | |
138 | #define ordered_hashmap_ensure_allocated(h, ops) _ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) | |
139 | ||
140 | int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS); | |
141 | #define ordered_hashmap_ensure_put(s, ops, key, value) _ordered_hashmap_ensure_put(s, ops, key, value HASHMAP_DEBUG_SRC_ARGS) | |
142 | ||
143 | IteratedCache* _hashmap_iterated_cache_new(HashmapBase *h); | |
144 | static inline IteratedCache* hashmap_iterated_cache_new(Hashmap *h) { | |
145 | return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h)); | |
146 | } | |
147 | static inline IteratedCache* ordered_hashmap_iterated_cache_new(OrderedHashmap *h) { | |
148 | return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h)); | |
149 | } | |
150 | ||
151 | int hashmap_put(Hashmap *h, const void *key, void *value); | |
152 | static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *value) { | |
153 | return hashmap_put(PLAIN_HASHMAP(h), key, value); | |
154 | } | |
155 | ||
156 | int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v HASHMAP_DEBUG_PARAMS); | |
157 | #define hashmap_put_strdup_full(h, hash_ops, k, v) _hashmap_put_strdup_full(h, hash_ops, k, v HASHMAP_DEBUG_SRC_ARGS) | |
158 | #define hashmap_put_strdup(h, k, v) hashmap_put_strdup_full(h, &string_hash_ops_free_free, k, v) | |
159 | ||
160 | int hashmap_update(Hashmap *h, const void *key, void *value); | |
161 | static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) { | |
162 | return hashmap_update(PLAIN_HASHMAP(h), key, value); | |
163 | } | |
164 | ||
165 | int hashmap_replace(Hashmap *h, const void *key, void *value); | |
166 | static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, void *value) { | |
167 | return hashmap_replace(PLAIN_HASHMAP(h), key, value); | |
168 | } | |
169 | ||
170 | void* _hashmap_get(HashmapBase *h, const void *key); | |
171 | static inline void *hashmap_get(Hashmap *h, const void *key) { | |
172 | return _hashmap_get(HASHMAP_BASE(h), key); | |
173 | } | |
174 | static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) { | |
175 | return _hashmap_get(HASHMAP_BASE(h), key); | |
176 | } | |
177 | ||
178 | void* hashmap_get2(Hashmap *h, const void *key, void **rkey); | |
179 | static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, void **rkey) { | |
180 | return hashmap_get2(PLAIN_HASHMAP(h), key, rkey); | |
181 | } | |
182 | ||
183 | bool _hashmap_contains(HashmapBase *h, const void *key); | |
184 | static inline bool hashmap_contains(Hashmap *h, const void *key) { | |
185 | return _hashmap_contains(HASHMAP_BASE(h), key); | |
186 | } | |
187 | static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) { | |
188 | return _hashmap_contains(HASHMAP_BASE(h), key); | |
189 | } | |
190 | ||
191 | void* _hashmap_remove(HashmapBase *h, const void *key); | |
192 | static inline void *hashmap_remove(Hashmap *h, const void *key) { | |
193 | return _hashmap_remove(HASHMAP_BASE(h), key); | |
194 | } | |
195 | static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) { | |
196 | return _hashmap_remove(HASHMAP_BASE(h), key); | |
197 | } | |
198 | ||
199 | void* hashmap_remove2(Hashmap *h, const void *key, void **rkey); | |
200 | static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key, void **rkey) { | |
201 | return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey); | |
202 | } | |
203 | ||
204 | void* _hashmap_remove_value(HashmapBase *h, const void *key, void *value); | |
205 | static inline void *hashmap_remove_value(Hashmap *h, const void *key, void *value) { | |
206 | return _hashmap_remove_value(HASHMAP_BASE(h), key, value); | |
207 | } | |
208 | ||
209 | static inline void* ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) { | |
210 | return hashmap_remove_value(PLAIN_HASHMAP(h), key, value); | |
211 | } | |
212 | ||
213 | int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value); | |
214 | static inline int ordered_hashmap_remove_and_put(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) { | |
215 | return hashmap_remove_and_put(PLAIN_HASHMAP(h), old_key, new_key, value); | |
216 | } | |
217 | ||
218 | int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value); | |
219 | static inline int ordered_hashmap_remove_and_replace(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) { | |
220 | return hashmap_remove_and_replace(PLAIN_HASHMAP(h), old_key, new_key, value); | |
221 | } | |
222 | ||
223 | /* Since merging data from a OrderedHashmap into a Hashmap or vice-versa | |
224 | * should just work, allow this by having looser type-checking here. */ | |
225 | int _hashmap_merge(Hashmap *h, Hashmap *other); | |
226 | #define hashmap_merge(h, other) _hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other)) | |
227 | #define ordered_hashmap_merge(h, other) hashmap_merge(h, other) | |
228 | ||
229 | int _hashmap_reserve(HashmapBase *h, unsigned entries_add); | |
230 | static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) { | |
231 | return _hashmap_reserve(HASHMAP_BASE(h), entries_add); | |
232 | } | |
233 | static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) { | |
234 | return _hashmap_reserve(HASHMAP_BASE(h), entries_add); | |
235 | } | |
236 | ||
237 | int _hashmap_move(HashmapBase *h, HashmapBase *other); | |
238 | /* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */ | |
239 | static inline int hashmap_move(Hashmap *h, Hashmap *other) { | |
240 | return _hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); | |
241 | } | |
242 | static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) { | |
243 | return _hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); | |
244 | } | |
245 | ||
246 | int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key); | |
247 | static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) { | |
248 | return _hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key); | |
249 | } | |
250 | static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) { | |
251 | return _hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key); | |
252 | } | |
253 | ||
254 | unsigned _hashmap_size(HashmapBase *h) _pure_; | |
255 | static inline unsigned hashmap_size(Hashmap *h) { | |
256 | return _hashmap_size(HASHMAP_BASE(h)); | |
257 | } | |
258 | static inline unsigned ordered_hashmap_size(OrderedHashmap *h) { | |
259 | return _hashmap_size(HASHMAP_BASE(h)); | |
260 | } | |
261 | ||
262 | static inline bool hashmap_isempty(Hashmap *h) { | |
263 | return hashmap_size(h) == 0; | |
264 | } | |
265 | static inline bool ordered_hashmap_isempty(OrderedHashmap *h) { | |
266 | return ordered_hashmap_size(h) == 0; | |
267 | } | |
268 | ||
269 | unsigned _hashmap_buckets(HashmapBase *h) _pure_; | |
270 | static inline unsigned hashmap_buckets(Hashmap *h) { | |
271 | return _hashmap_buckets(HASHMAP_BASE(h)); | |
272 | } | |
273 | static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) { | |
274 | return _hashmap_buckets(HASHMAP_BASE(h)); | |
275 | } | |
276 | ||
277 | bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key); | |
278 | static inline bool hashmap_iterate(Hashmap *h, Iterator *i, void **value, const void **key) { | |
279 | return _hashmap_iterate(HASHMAP_BASE(h), i, value, key); | |
280 | } | |
281 | static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void **value, const void **key) { | |
282 | return _hashmap_iterate(HASHMAP_BASE(h), i, value, key); | |
283 | } | |
284 | ||
285 | void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value); | |
286 | static inline void hashmap_clear(Hashmap *h) { | |
287 | _hashmap_clear(HASHMAP_BASE(h), NULL, NULL); | |
288 | } | |
289 | static inline void ordered_hashmap_clear(OrderedHashmap *h) { | |
290 | _hashmap_clear(HASHMAP_BASE(h), NULL, NULL); | |
291 | } | |
292 | ||
293 | static inline void hashmap_clear_free(Hashmap *h) { | |
294 | _hashmap_clear(HASHMAP_BASE(h), NULL, free); | |
295 | } | |
296 | static inline void ordered_hashmap_clear_free(OrderedHashmap *h) { | |
297 | _hashmap_clear(HASHMAP_BASE(h), NULL, free); | |
298 | } | |
299 | ||
300 | static inline void hashmap_clear_free_key(Hashmap *h) { | |
301 | _hashmap_clear(HASHMAP_BASE(h), free, NULL); | |
302 | } | |
303 | static inline void ordered_hashmap_clear_free_key(OrderedHashmap *h) { | |
304 | _hashmap_clear(HASHMAP_BASE(h), free, NULL); | |
305 | } | |
306 | ||
307 | static inline void hashmap_clear_free_free(Hashmap *h) { | |
308 | _hashmap_clear(HASHMAP_BASE(h), free, free); | |
309 | } | |
310 | static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) { | |
311 | _hashmap_clear(HASHMAP_BASE(h), free, free); | |
312 | } | |
313 | ||
314 | /* | |
315 | * Note about all *_first*() functions | |
316 | * | |
317 | * For plain Hashmaps and Sets the order of entries is undefined. | |
318 | * The functions find whatever entry is first in the implementation | |
319 | * internal order. | |
320 | * | |
321 | * Only for OrderedHashmaps the order is well defined and finding | |
322 | * the first entry is O(1). | |
323 | */ | |
324 | ||
325 | void *_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key); | |
326 | static inline void *hashmap_steal_first_key_and_value(Hashmap *h, void **ret) { | |
327 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret); | |
328 | } | |
329 | static inline void *ordered_hashmap_steal_first_key_and_value(OrderedHashmap *h, void **ret) { | |
330 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret); | |
331 | } | |
332 | static inline void *hashmap_first_key_and_value(Hashmap *h, void **ret) { | |
333 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret); | |
334 | } | |
335 | static inline void *ordered_hashmap_first_key_and_value(OrderedHashmap *h, void **ret) { | |
336 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret); | |
337 | } | |
338 | ||
339 | static inline void *hashmap_steal_first(Hashmap *h) { | |
340 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL); | |
341 | } | |
342 | static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) { | |
343 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL); | |
344 | } | |
345 | static inline void *hashmap_first(Hashmap *h) { | |
346 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL); | |
347 | } | |
348 | static inline void *ordered_hashmap_first(OrderedHashmap *h) { | |
349 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL); | |
350 | } | |
351 | ||
352 | static inline void *_hashmap_first_key(HashmapBase *h, bool remove) { | |
353 | void *key = NULL; | |
354 | ||
355 | (void) _hashmap_first_key_and_value(HASHMAP_BASE(h), remove, &key); | |
356 | return key; | |
357 | } | |
358 | static inline void *hashmap_steal_first_key(Hashmap *h) { | |
359 | return _hashmap_first_key(HASHMAP_BASE(h), true); | |
360 | } | |
361 | static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) { | |
362 | return _hashmap_first_key(HASHMAP_BASE(h), true); | |
363 | } | |
364 | static inline void *hashmap_first_key(Hashmap *h) { | |
365 | return _hashmap_first_key(HASHMAP_BASE(h), false); | |
366 | } | |
367 | static inline void *ordered_hashmap_first_key(OrderedHashmap *h) { | |
368 | return _hashmap_first_key(HASHMAP_BASE(h), false); | |
369 | } | |
370 | ||
371 | #define hashmap_clear_with_destructor(_s, _f) \ | |
372 | ({ \ | |
373 | void *_item; \ | |
374 | while ((_item = hashmap_steal_first(_s))) \ | |
375 | _f(_item); \ | |
376 | }) | |
377 | #define hashmap_free_with_destructor(_s, _f) \ | |
378 | ({ \ | |
379 | hashmap_clear_with_destructor(_s, _f); \ | |
380 | hashmap_free(_s); \ | |
381 | }) | |
382 | #define ordered_hashmap_clear_with_destructor(_s, _f) \ | |
383 | ({ \ | |
384 | void *_item; \ | |
385 | while ((_item = ordered_hashmap_steal_first(_s))) \ | |
386 | _f(_item); \ | |
387 | }) | |
388 | #define ordered_hashmap_free_with_destructor(_s, _f) \ | |
389 | ({ \ | |
390 | ordered_hashmap_clear_with_destructor(_s, _f); \ | |
391 | ordered_hashmap_free(_s); \ | |
392 | }) | |
393 | ||
394 | /* no hashmap_next */ | |
395 | void* ordered_hashmap_next(OrderedHashmap *h, const void *key); | |
396 | ||
397 | char** _hashmap_get_strv(HashmapBase *h); | |
398 | static inline char** hashmap_get_strv(Hashmap *h) { | |
399 | return _hashmap_get_strv(HASHMAP_BASE(h)); | |
400 | } | |
401 | static inline char** ordered_hashmap_get_strv(OrderedHashmap *h) { | |
402 | return _hashmap_get_strv(HASHMAP_BASE(h)); | |
403 | } | |
404 | ||
405 | /* | |
406 | * Hashmaps are iterated in unpredictable order. | |
407 | * OrderedHashmaps are an exception to this. They are iterated in the order | |
408 | * the entries were inserted. | |
409 | * It is safe to remove the current entry. | |
410 | */ | |
411 | #define _HASHMAP_FOREACH(e, h, i) \ | |
412 | for (Iterator i = ITERATOR_FIRST; hashmap_iterate((h), &i, (void**)&(e), NULL); ) | |
413 | #define HASHMAP_FOREACH(e, h) \ | |
414 | _HASHMAP_FOREACH(e, h, UNIQ_T(i, UNIQ)) | |
415 | ||
416 | #define _ORDERED_HASHMAP_FOREACH(e, h, i) \ | |
417 | for (Iterator i = ITERATOR_FIRST; ordered_hashmap_iterate((h), &i, (void**)&(e), NULL); ) | |
418 | #define ORDERED_HASHMAP_FOREACH(e, h) \ | |
419 | _ORDERED_HASHMAP_FOREACH(e, h, UNIQ_T(i, UNIQ)) | |
420 | ||
421 | #define _HASHMAP_FOREACH_KEY(e, k, h, i) \ | |
422 | for (Iterator i = ITERATOR_FIRST; hashmap_iterate((h), &i, (void**)&(e), (const void**) &(k)); ) | |
423 | #define HASHMAP_FOREACH_KEY(e, k, h) \ | |
424 | _HASHMAP_FOREACH_KEY(e, k, h, UNIQ_T(i, UNIQ)) | |
425 | ||
426 | #define _ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \ | |
427 | for (Iterator i = ITERATOR_FIRST; ordered_hashmap_iterate((h), &i, (void**)&(e), (const void**) &(k)); ) | |
428 | #define ORDERED_HASHMAP_FOREACH_KEY(e, k, h) \ | |
429 | _ORDERED_HASHMAP_FOREACH_KEY(e, k, h, UNIQ_T(i, UNIQ)) | |
430 | ||
431 | DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free); | |
432 | DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free); | |
433 | DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_key); | |
434 | DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free); | |
435 | DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free); | |
436 | DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free); | |
437 | DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_key); | |
438 | DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free); | |
439 | ||
440 | #define _cleanup_hashmap_free_ _cleanup_(hashmap_freep) | |
441 | #define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep) | |
442 | #define _cleanup_hashmap_free_free_free_ _cleanup_(hashmap_free_free_freep) | |
443 | #define _cleanup_ordered_hashmap_free_ _cleanup_(ordered_hashmap_freep) | |
444 | #define _cleanup_ordered_hashmap_free_free_ _cleanup_(ordered_hashmap_free_freep) | |
445 | #define _cleanup_ordered_hashmap_free_free_free_ _cleanup_(ordered_hashmap_free_free_freep) | |
446 | ||
447 | DEFINE_TRIVIAL_CLEANUP_FUNC(IteratedCache*, iterated_cache_free); | |
448 | ||
449 | #define _cleanup_iterated_cache_free_ _cleanup_(iterated_cache_freep) |