]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
c2f1db8f | 2 | #pragma once |
60918275 | 3 | |
11c3a366 | 4 | #include <limits.h> |
60918275 | 5 | #include <stdbool.h> |
11c3a366 | 6 | #include <stddef.h> |
60918275 | 7 | |
758dd67e | 8 | #include "hash-funcs.h" |
44a6b1b6 | 9 | #include "macro.h" |
5e2f14e6 | 10 | #include "util.h" |
44a6b1b6 | 11 | |
89439d4f MS |
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 | * | |
06134457 | 17 | * If ENABLE_DEBUG_HASHMAP is defined (by configuring with -Ddebug-extra=hashmap), |
f21f31b2 | 18 | * the implementation will: |
89439d4f MS |
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 | */ | |
60918275 | 22 | |
9bf3b535 LP |
23 | #define HASH_KEY_SIZE 16 |
24 | ||
59a5cda7 YW |
25 | typedef void* (*hashmap_destroy_t)(void *p); |
26 | ||
138f49e4 ZJS |
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). */ | |
89439d4f MS |
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 | ||
45ea84d8 VC |
37 | typedef struct IteratedCache IteratedCache; /* Caches the iterated order of one of the above */ |
38 | ||
89439d4f MS |
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 */ | |
349cc4a5 | 45 | #if ENABLE_DEBUG_HASHMAP |
89439d4f MS |
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; | |
034c6ed7 | 51 | |
89439d4f MS |
52 | #define _IDX_ITERATOR_FIRST (UINT_MAX - 1) |
53 | #define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL }) | |
60918275 | 54 | |
89439d4f MS |
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 | ||
349cc4a5 | 76 | #if ENABLE_DEBUG_HASHMAP |
89439d4f | 77 | # define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line |
62c6bbbc | 78 | # define HASHMAP_DEBUG_SRC_ARGS , __func__, PROJECT_FILE, __LINE__ |
89439d4f MS |
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 | ||
8a35af80 ZJS |
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); | |
138f49e4 ZJS |
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) | |
89439d4f | 90 | |
3fb2326f ZJS |
91 | #define hashmap_free_and_replace(a, b) \ |
92 | ({ \ | |
93 | hashmap_free(a); \ | |
94 | (a) = (b); \ | |
95 | (b) = NULL; \ | |
96 | 0; \ | |
97 | }) | |
98 | ||
8a35af80 ZJS |
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) { | |
138f49e4 | 101 | return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL); |
5ba43716 | 102 | } |
8a35af80 | 103 | static inline OrderedHashmap* ordered_hashmap_free(OrderedHashmap *h) { |
138f49e4 | 104 | return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, NULL); |
89439d4f MS |
105 | } |
106 | ||
8a35af80 | 107 | static inline Hashmap* hashmap_free_free(Hashmap *h) { |
138f49e4 | 108 | return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free); |
5ba43716 | 109 | } |
8a35af80 | 110 | static inline OrderedHashmap* ordered_hashmap_free_free(OrderedHashmap *h) { |
138f49e4 | 111 | return (void*) _hashmap_free(HASHMAP_BASE(h), NULL, free); |
5ba43716 | 112 | } |
89439d4f | 113 | |
8a35af80 | 114 | static inline Hashmap* hashmap_free_free_key(Hashmap *h) { |
138f49e4 | 115 | return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL); |
59a5cda7 | 116 | } |
8a35af80 | 117 | static inline OrderedHashmap* ordered_hashmap_free_free_key(OrderedHashmap *h) { |
138f49e4 | 118 | return (void*) _hashmap_free(HASHMAP_BASE(h), free, NULL); |
59a5cda7 YW |
119 | } |
120 | ||
8a35af80 | 121 | static inline Hashmap* hashmap_free_free_free(Hashmap *h) { |
138f49e4 | 122 | return (void*) _hashmap_free(HASHMAP_BASE(h), free, free); |
59a5cda7 | 123 | } |
8a35af80 | 124 | static inline OrderedHashmap* ordered_hashmap_free_free_free(OrderedHashmap *h) { |
138f49e4 | 125 | return (void*) _hashmap_free(HASHMAP_BASE(h), free, free); |
5ba43716 | 126 | } |
89439d4f | 127 | |
8a35af80 | 128 | IteratedCache* iterated_cache_free(IteratedCache *cache); |
45ea84d8 VC |
129 | int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries); |
130 | ||
8a35af80 | 131 | HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS); |
add74e89 ZJS |
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)) | |
60918275 | 134 | |
138f49e4 ZJS |
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) | |
89439d4f | 139 | |
b7847e05 SS |
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 | ||
8a35af80 ZJS |
143 | IteratedCache* _hashmap_iterated_cache_new(HashmapBase *h); |
144 | static inline IteratedCache* hashmap_iterated_cache_new(Hashmap *h) { | |
138f49e4 | 145 | return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h)); |
45ea84d8 | 146 | } |
8a35af80 | 147 | static inline IteratedCache* ordered_hashmap_iterated_cache_new(OrderedHashmap *h) { |
138f49e4 | 148 | return (IteratedCache*) _hashmap_iterated_cache_new(HASHMAP_BASE(h)); |
45ea84d8 VC |
149 | } |
150 | ||
60918275 | 151 | int hashmap_put(Hashmap *h, const void *key, void *value); |
5ba43716 | 152 | static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *value) { |
89439d4f | 153 | return hashmap_put(PLAIN_HASHMAP(h), key, value); |
5ba43716 | 154 | } |
89439d4f | 155 | |
11e9fec2 YW |
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) | |
87da8784 | 159 | |
d99ae53a | 160 | int hashmap_update(Hashmap *h, const void *key, void *value); |
5ba43716 | 161 | static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) { |
89439d4f | 162 | return hashmap_update(PLAIN_HASHMAP(h), key, value); |
5ba43716 | 163 | } |
89439d4f | 164 | |
3158713e | 165 | int hashmap_replace(Hashmap *h, const void *key, void *value); |
5ba43716 | 166 | static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, void *value) { |
89439d4f MS |
167 | return hashmap_replace(PLAIN_HASHMAP(h), key, value); |
168 | } | |
169 | ||
8a35af80 | 170 | void* _hashmap_get(HashmapBase *h, const void *key); |
89439d4f | 171 | static inline void *hashmap_get(Hashmap *h, const void *key) { |
138f49e4 | 172 | return _hashmap_get(HASHMAP_BASE(h), key); |
5ba43716 | 173 | } |
5ba43716 | 174 | static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) { |
138f49e4 | 175 | return _hashmap_get(HASHMAP_BASE(h), key); |
5ba43716 | 176 | } |
89439d4f | 177 | |
8a35af80 | 178 | void* hashmap_get2(Hashmap *h, const void *key, void **rkey); |
5ba43716 | 179 | static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, void **rkey) { |
89439d4f MS |
180 | return hashmap_get2(PLAIN_HASHMAP(h), key, rkey); |
181 | } | |
182 | ||
138f49e4 | 183 | bool _hashmap_contains(HashmapBase *h, const void *key); |
89439d4f | 184 | static inline bool hashmap_contains(Hashmap *h, const void *key) { |
138f49e4 | 185 | return _hashmap_contains(HASHMAP_BASE(h), key); |
5ba43716 | 186 | } |
5ba43716 | 187 | static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) { |
138f49e4 | 188 | return _hashmap_contains(HASHMAP_BASE(h), key); |
89439d4f MS |
189 | } |
190 | ||
8a35af80 | 191 | void* _hashmap_remove(HashmapBase *h, const void *key); |
89439d4f | 192 | static inline void *hashmap_remove(Hashmap *h, const void *key) { |
138f49e4 | 193 | return _hashmap_remove(HASHMAP_BASE(h), key); |
5ba43716 | 194 | } |
5ba43716 | 195 | static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) { |
138f49e4 | 196 | return _hashmap_remove(HASHMAP_BASE(h), key); |
5ba43716 | 197 | } |
89439d4f | 198 | |
8a35af80 | 199 | void* hashmap_remove2(Hashmap *h, const void *key, void **rkey); |
5ba43716 | 200 | static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key, void **rkey) { |
89439d4f | 201 | return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey); |
5ba43716 | 202 | } |
89439d4f | 203 | |
8a35af80 | 204 | void* _hashmap_remove_value(HashmapBase *h, const void *key, void *value); |
c380b84d | 205 | static inline void *hashmap_remove_value(Hashmap *h, const void *key, void *value) { |
138f49e4 | 206 | return _hashmap_remove_value(HASHMAP_BASE(h), key, value); |
c380b84d LP |
207 | } |
208 | ||
8a35af80 | 209 | static inline void* ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) { |
89439d4f | 210 | return hashmap_remove_value(PLAIN_HASHMAP(h), key, value); |
5ba43716 | 211 | } |
89439d4f | 212 | |
101d8e63 | 213 | int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value); |
5ba43716 | 214 | static inline int ordered_hashmap_remove_and_put(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) { |
89439d4f | 215 | return hashmap_remove_and_put(PLAIN_HASHMAP(h), old_key, new_key, value); |
5ba43716 | 216 | } |
89439d4f | 217 | |
8fe914ec | 218 | int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value); |
5ba43716 | 219 | static inline int ordered_hashmap_remove_and_replace(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) { |
89439d4f | 220 | return hashmap_remove_and_replace(PLAIN_HASHMAP(h), old_key, new_key, value); |
5ba43716 | 221 | } |
60918275 | 222 | |
89439d4f MS |
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. */ | |
138f49e4 ZJS |
225 | int _hashmap_merge(Hashmap *h, Hashmap *other); |
226 | #define hashmap_merge(h, other) _hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other)) | |
89439d4f MS |
227 | #define ordered_hashmap_merge(h, other) hashmap_merge(h, other) |
228 | ||
138f49e4 | 229 | int _hashmap_reserve(HashmapBase *h, unsigned entries_add); |
89439d4f | 230 | static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) { |
138f49e4 | 231 | return _hashmap_reserve(HASHMAP_BASE(h), entries_add); |
5ba43716 | 232 | } |
e4c691b5 | 233 | static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) { |
138f49e4 | 234 | return _hashmap_reserve(HASHMAP_BASE(h), entries_add); |
89439d4f MS |
235 | } |
236 | ||
138f49e4 | 237 | int _hashmap_move(HashmapBase *h, HashmapBase *other); |
89439d4f MS |
238 | /* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */ |
239 | static inline int hashmap_move(Hashmap *h, Hashmap *other) { | |
138f49e4 | 240 | return _hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); |
e4c691b5 | 241 | } |
7ad63f57 | 242 | static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) { |
138f49e4 | 243 | return _hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other)); |
89439d4f MS |
244 | } |
245 | ||
138f49e4 | 246 | int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key); |
89439d4f | 247 | static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) { |
138f49e4 | 248 | return _hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key); |
5ba43716 | 249 | } |
5ba43716 | 250 | static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) { |
138f49e4 | 251 | return _hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key); |
5ba43716 | 252 | } |
91cdde8a | 253 | |
138f49e4 | 254 | unsigned _hashmap_size(HashmapBase *h) _pure_; |
89439d4f | 255 | static inline unsigned hashmap_size(Hashmap *h) { |
138f49e4 | 256 | return _hashmap_size(HASHMAP_BASE(h)); |
89439d4f | 257 | } |
5ba43716 | 258 | static inline unsigned ordered_hashmap_size(OrderedHashmap *h) { |
138f49e4 | 259 | return _hashmap_size(HASHMAP_BASE(h)); |
89439d4f MS |
260 | } |
261 | ||
262 | static inline bool hashmap_isempty(Hashmap *h) { | |
263 | return hashmap_size(h) == 0; | |
5ba43716 | 264 | } |
5ba43716 | 265 | static inline bool ordered_hashmap_isempty(OrderedHashmap *h) { |
89439d4f MS |
266 | return ordered_hashmap_size(h) == 0; |
267 | } | |
268 | ||
138f49e4 | 269 | unsigned _hashmap_buckets(HashmapBase *h) _pure_; |
89439d4f | 270 | static inline unsigned hashmap_buckets(Hashmap *h) { |
138f49e4 | 271 | return _hashmap_buckets(HASHMAP_BASE(h)); |
5ba43716 | 272 | } |
5ba43716 | 273 | static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) { |
138f49e4 | 274 | return _hashmap_buckets(HASHMAP_BASE(h)); |
5ba43716 | 275 | } |
60918275 | 276 | |
138f49e4 | 277 | bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key); |
8927b1da | 278 | static inline bool hashmap_iterate(Hashmap *h, Iterator *i, void **value, const void **key) { |
138f49e4 | 279 | return _hashmap_iterate(HASHMAP_BASE(h), i, value, key); |
89439d4f | 280 | } |
8927b1da | 281 | static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void **value, const void **key) { |
138f49e4 | 282 | return _hashmap_iterate(HASHMAP_BASE(h), i, value, key); |
5ba43716 | 283 | } |
60918275 | 284 | |
138f49e4 | 285 | void _hashmap_clear(HashmapBase *h, free_func_t default_free_key, free_func_t default_free_value); |
89439d4f | 286 | static inline void hashmap_clear(Hashmap *h) { |
138f49e4 | 287 | _hashmap_clear(HASHMAP_BASE(h), NULL, NULL); |
89439d4f | 288 | } |
5ba43716 | 289 | static inline void ordered_hashmap_clear(OrderedHashmap *h) { |
138f49e4 | 290 | _hashmap_clear(HASHMAP_BASE(h), NULL, NULL); |
89439d4f MS |
291 | } |
292 | ||
89439d4f | 293 | static inline void hashmap_clear_free(Hashmap *h) { |
138f49e4 | 294 | _hashmap_clear(HASHMAP_BASE(h), NULL, free); |
5ba43716 | 295 | } |
5ba43716 | 296 | static inline void ordered_hashmap_clear_free(OrderedHashmap *h) { |
138f49e4 | 297 | _hashmap_clear(HASHMAP_BASE(h), NULL, free); |
5ba43716 | 298 | } |
89439d4f | 299 | |
59a5cda7 | 300 | static inline void hashmap_clear_free_key(Hashmap *h) { |
138f49e4 | 301 | _hashmap_clear(HASHMAP_BASE(h), free, NULL); |
59a5cda7 YW |
302 | } |
303 | static inline void ordered_hashmap_clear_free_key(OrderedHashmap *h) { | |
138f49e4 | 304 | _hashmap_clear(HASHMAP_BASE(h), free, NULL); |
59a5cda7 YW |
305 | } |
306 | ||
307 | static inline void hashmap_clear_free_free(Hashmap *h) { | |
138f49e4 | 308 | _hashmap_clear(HASHMAP_BASE(h), free, free); |
59a5cda7 | 309 | } |
5ba43716 | 310 | static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) { |
138f49e4 | 311 | _hashmap_clear(HASHMAP_BASE(h), free, free); |
5ba43716 | 312 | } |
9946996c | 313 | |
89439d4f MS |
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 | ||
138f49e4 | 325 | void *_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key); |
7ef670c3 | 326 | static inline void *hashmap_steal_first_key_and_value(Hashmap *h, void **ret) { |
138f49e4 | 327 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret); |
7ef670c3 YW |
328 | } |
329 | static inline void *ordered_hashmap_steal_first_key_and_value(OrderedHashmap *h, void **ret) { | |
138f49e4 | 330 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, ret); |
7ef670c3 YW |
331 | } |
332 | static inline void *hashmap_first_key_and_value(Hashmap *h, void **ret) { | |
138f49e4 | 333 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret); |
7ef670c3 YW |
334 | } |
335 | static inline void *ordered_hashmap_first_key_and_value(OrderedHashmap *h, void **ret) { | |
138f49e4 | 336 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, ret); |
7ef670c3 YW |
337 | } |
338 | ||
89439d4f | 339 | static inline void *hashmap_steal_first(Hashmap *h) { |
138f49e4 | 340 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL); |
89439d4f | 341 | } |
5ba43716 | 342 | static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) { |
138f49e4 | 343 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), true, NULL); |
7ef670c3 YW |
344 | } |
345 | static inline void *hashmap_first(Hashmap *h) { | |
138f49e4 | 346 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL); |
7ef670c3 YW |
347 | } |
348 | static inline void *ordered_hashmap_first(OrderedHashmap *h) { | |
138f49e4 | 349 | return _hashmap_first_key_and_value(HASHMAP_BASE(h), false, NULL); |
89439d4f MS |
350 | } |
351 | ||
138f49e4 | 352 | static inline void *_hashmap_first_key(HashmapBase *h, bool remove) { |
7ef670c3 YW |
353 | void *key = NULL; |
354 | ||
138f49e4 | 355 | (void) _hashmap_first_key_and_value(HASHMAP_BASE(h), remove, &key); |
7ef670c3 YW |
356 | return key; |
357 | } | |
89439d4f | 358 | static inline void *hashmap_steal_first_key(Hashmap *h) { |
138f49e4 | 359 | return _hashmap_first_key(HASHMAP_BASE(h), true); |
5ba43716 | 360 | } |
5ba43716 | 361 | static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) { |
138f49e4 | 362 | return _hashmap_first_key(HASHMAP_BASE(h), true); |
5ba43716 | 363 | } |
89439d4f | 364 | static inline void *hashmap_first_key(Hashmap *h) { |
138f49e4 | 365 | return _hashmap_first_key(HASHMAP_BASE(h), false); |
5ba43716 | 366 | } |
5ba43716 | 367 | static inline void *ordered_hashmap_first_key(OrderedHashmap *h) { |
138f49e4 | 368 | return _hashmap_first_key(HASHMAP_BASE(h), false); |
89439d4f MS |
369 | } |
370 | ||
224b0e7a ZJS |
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 | ||
89439d4f | 394 | /* no hashmap_next */ |
8a35af80 | 395 | void* ordered_hashmap_next(OrderedHashmap *h, const void *key); |
3c1668da | 396 | |
8a35af80 ZJS |
397 | char** _hashmap_get_strv(HashmapBase *h); |
398 | static inline char** hashmap_get_strv(Hashmap *h) { | |
138f49e4 | 399 | return _hashmap_get_strv(HASHMAP_BASE(h)); |
89439d4f | 400 | } |
8a35af80 | 401 | static inline char** ordered_hashmap_get_strv(OrderedHashmap *h) { |
138f49e4 | 402 | return _hashmap_get_strv(HASHMAP_BASE(h)); |
5ba43716 | 403 | } |
db1413d7 | 404 | |
89439d4f MS |
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 | */ | |
90e74a66 ZJS |
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)) | |
5ba43716 | 430 | |
5e2f14e6 LP |
431 | DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free); |
432 | DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free); | |
f9974167 | 433 | DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_key); |
5e2f14e6 | 434 | DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free); |
5ba43716 MS |
435 | DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free); |
436 | DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free); | |
f9974167 | 437 | DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_key); |
5ba43716 | 438 | DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free); |
89439d4f | 439 | |
5e2f14e6 LP |
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) | |
5ba43716 MS |
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) | |
45ea84d8 VC |
446 | |
447 | DEFINE_TRIVIAL_CLEANUP_FUNC(IteratedCache*, iterated_cache_free); | |
448 | ||
449 | #define _cleanup_iterated_cache_free_ _cleanup_(iterated_cache_freep) |