]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/hashmap.h
b674910397881c3249319f2fbeae7ae3879a9bfe
[thirdparty/systemd.git] / src / basic / hashmap.h
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 #pragma once
3
4 /***
5 This file is part of systemd.
6
7 Copyright 2010 Lennart Poettering
8 Copyright 2014 Michal Schmidt
9
10 systemd is free software; you can redistribute it and/or modify it
11 under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 2.1 of the License, or
13 (at your option) any later version.
14
15 systemd is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
19
20 You should have received a copy of the GNU Lesser General Public License
21 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 ***/
23
24 #include <limits.h>
25 #include <stdbool.h>
26 #include <stddef.h>
27
28 #include "hash-funcs.h"
29 #include "macro.h"
30 #include "util.h"
31
32 /*
33 * A hash table implementation. As a minor optimization a NULL hashmap object
34 * will be treated as empty hashmap for all read operations. That way it is not
35 * necessary to instantiate an object for each Hashmap use.
36 *
37 * If ENABLE_DEBUG_HASHMAP is defined (by configuring with --enable-debug=hashmap),
38 * the implemention will:
39 * - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py)
40 * - perform extra checks for invalid use of iterators
41 */
42
43 #define HASH_KEY_SIZE 16
44
45 /* The base type for all hashmap and set types. Many functions in the
46 * implementation take (HashmapBase*) parameters and are run-time polymorphic,
47 * though the API is not meant to be polymorphic (do not call functions
48 * internal_*() directly). */
49 typedef struct HashmapBase HashmapBase;
50
51 /* Specific hashmap/set types */
52 typedef struct Hashmap Hashmap; /* Maps keys to values */
53 typedef struct OrderedHashmap OrderedHashmap; /* Like Hashmap, but also remembers entry insertion order */
54 typedef struct Set Set; /* Stores just keys */
55
56 typedef struct IteratedCache IteratedCache; /* Caches the iterated order of one of the above */
57
58 /* Ideally the Iterator would be an opaque struct, but it is instantiated
59 * by hashmap users, so the definition has to be here. Do not use its fields
60 * directly. */
61 typedef struct {
62 unsigned idx; /* index of an entry to be iterated next */
63 const void *next_key; /* expected value of that entry's key pointer */
64 #if ENABLE_DEBUG_HASHMAP
65 unsigned put_count; /* hashmap's put_count recorded at start of iteration */
66 unsigned rem_count; /* hashmap's rem_count in previous iteration */
67 unsigned prev_idx; /* idx in previous iteration */
68 #endif
69 } Iterator;
70
71 #define _IDX_ITERATOR_FIRST (UINT_MAX - 1)
72 #define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL })
73
74 /* Macros for type checking */
75 #define PTR_COMPATIBLE_WITH_HASHMAP_BASE(h) \
76 (__builtin_types_compatible_p(typeof(h), HashmapBase*) || \
77 __builtin_types_compatible_p(typeof(h), Hashmap*) || \
78 __builtin_types_compatible_p(typeof(h), OrderedHashmap*) || \
79 __builtin_types_compatible_p(typeof(h), Set*))
80
81 #define PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h) \
82 (__builtin_types_compatible_p(typeof(h), Hashmap*) || \
83 __builtin_types_compatible_p(typeof(h), OrderedHashmap*)) \
84
85 #define HASHMAP_BASE(h) \
86 __builtin_choose_expr(PTR_COMPATIBLE_WITH_HASHMAP_BASE(h), \
87 (HashmapBase*)(h), \
88 (void)0)
89
90 #define PLAIN_HASHMAP(h) \
91 __builtin_choose_expr(PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h), \
92 (Hashmap*)(h), \
93 (void)0)
94
95 #if ENABLE_DEBUG_HASHMAP
96 # define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line
97 # define HASHMAP_DEBUG_SRC_ARGS , __func__, __FILE__, __LINE__
98 # define HASHMAP_DEBUG_PASS_ARGS , func, file, line
99 #else
100 # define HASHMAP_DEBUG_PARAMS
101 # define HASHMAP_DEBUG_SRC_ARGS
102 # define HASHMAP_DEBUG_PASS_ARGS
103 #endif
104
105 Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
106 OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
107 #define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
108 #define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
109
110 HashmapBase *internal_hashmap_free(HashmapBase *h);
111 static inline Hashmap *hashmap_free(Hashmap *h) {
112 return (void*)internal_hashmap_free(HASHMAP_BASE(h));
113 }
114 static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) {
115 return (void*)internal_hashmap_free(HASHMAP_BASE(h));
116 }
117
118 HashmapBase *internal_hashmap_free_free(HashmapBase *h);
119 static inline Hashmap *hashmap_free_free(Hashmap *h) {
120 return (void*)internal_hashmap_free_free(HASHMAP_BASE(h));
121 }
122 static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) {
123 return (void*)internal_hashmap_free_free(HASHMAP_BASE(h));
124 }
125
126 Hashmap *hashmap_free_free_free(Hashmap *h);
127 static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) {
128 return (void*)hashmap_free_free_free(PLAIN_HASHMAP(h));
129 }
130
131 IteratedCache *iterated_cache_free(IteratedCache *cache);
132 int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries);
133
134 HashmapBase *internal_hashmap_copy(HashmapBase *h);
135 static inline Hashmap *hashmap_copy(Hashmap *h) {
136 return (Hashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
137 }
138 static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) {
139 return (OrderedHashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
140 }
141
142 int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
143 int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
144 #define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
145 #define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
146
147 IteratedCache *internal_hashmap_iterated_cache_new(HashmapBase *h);
148 static inline IteratedCache *hashmap_iterated_cache_new(Hashmap *h) {
149 return (IteratedCache*) internal_hashmap_iterated_cache_new(HASHMAP_BASE(h));
150 }
151 static inline IteratedCache *ordered_hashmap_iterated_cache_new(OrderedHashmap *h) {
152 return (IteratedCache*) internal_hashmap_iterated_cache_new(HASHMAP_BASE(h));
153 }
154
155 int hashmap_put(Hashmap *h, const void *key, void *value);
156 static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *value) {
157 return hashmap_put(PLAIN_HASHMAP(h), key, value);
158 }
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 *internal_hashmap_get(HashmapBase *h, const void *key);
171 static inline void *hashmap_get(Hashmap *h, const void *key) {
172 return internal_hashmap_get(HASHMAP_BASE(h), key);
173 }
174 static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) {
175 return internal_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 internal_hashmap_contains(HashmapBase *h, const void *key);
184 static inline bool hashmap_contains(Hashmap *h, const void *key) {
185 return internal_hashmap_contains(HASHMAP_BASE(h), key);
186 }
187 static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) {
188 return internal_hashmap_contains(HASHMAP_BASE(h), key);
189 }
190
191 void *internal_hashmap_remove(HashmapBase *h, const void *key);
192 static inline void *hashmap_remove(Hashmap *h, const void *key) {
193 return internal_hashmap_remove(HASHMAP_BASE(h), key);
194 }
195 static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) {
196 return internal_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(Hashmap *h, const void *key, void *value);
205 static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) {
206 return hashmap_remove_value(PLAIN_HASHMAP(h), key, value);
207 }
208
209 int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value);
210 static inline int ordered_hashmap_remove_and_put(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) {
211 return hashmap_remove_and_put(PLAIN_HASHMAP(h), old_key, new_key, value);
212 }
213
214 int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value);
215 static inline int ordered_hashmap_remove_and_replace(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) {
216 return hashmap_remove_and_replace(PLAIN_HASHMAP(h), old_key, new_key, value);
217 }
218
219 /* Since merging data from a OrderedHashmap into a Hashmap or vice-versa
220 * should just work, allow this by having looser type-checking here. */
221 int internal_hashmap_merge(Hashmap *h, Hashmap *other);
222 #define hashmap_merge(h, other) internal_hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other))
223 #define ordered_hashmap_merge(h, other) hashmap_merge(h, other)
224
225 int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add);
226 static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) {
227 return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
228 }
229 static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) {
230 return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
231 }
232
233 int internal_hashmap_move(HashmapBase *h, HashmapBase *other);
234 /* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */
235 static inline int hashmap_move(Hashmap *h, Hashmap *other) {
236 return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
237 }
238 static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) {
239 return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
240 }
241
242 int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key);
243 static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
244 return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
245 }
246 static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) {
247 return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
248 }
249
250 unsigned internal_hashmap_size(HashmapBase *h) _pure_;
251 static inline unsigned hashmap_size(Hashmap *h) {
252 return internal_hashmap_size(HASHMAP_BASE(h));
253 }
254 static inline unsigned ordered_hashmap_size(OrderedHashmap *h) {
255 return internal_hashmap_size(HASHMAP_BASE(h));
256 }
257
258 static inline bool hashmap_isempty(Hashmap *h) {
259 return hashmap_size(h) == 0;
260 }
261 static inline bool ordered_hashmap_isempty(OrderedHashmap *h) {
262 return ordered_hashmap_size(h) == 0;
263 }
264
265 unsigned internal_hashmap_buckets(HashmapBase *h) _pure_;
266 static inline unsigned hashmap_buckets(Hashmap *h) {
267 return internal_hashmap_buckets(HASHMAP_BASE(h));
268 }
269 static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) {
270 return internal_hashmap_buckets(HASHMAP_BASE(h));
271 }
272
273 bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key);
274 static inline bool hashmap_iterate(Hashmap *h, Iterator *i, void **value, const void **key) {
275 return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
276 }
277 static inline bool ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, void **value, const void **key) {
278 return internal_hashmap_iterate(HASHMAP_BASE(h), i, value, key);
279 }
280
281 void internal_hashmap_clear(HashmapBase *h);
282 static inline void hashmap_clear(Hashmap *h) {
283 internal_hashmap_clear(HASHMAP_BASE(h));
284 }
285 static inline void ordered_hashmap_clear(OrderedHashmap *h) {
286 internal_hashmap_clear(HASHMAP_BASE(h));
287 }
288
289 void internal_hashmap_clear_free(HashmapBase *h);
290 static inline void hashmap_clear_free(Hashmap *h) {
291 internal_hashmap_clear_free(HASHMAP_BASE(h));
292 }
293 static inline void ordered_hashmap_clear_free(OrderedHashmap *h) {
294 internal_hashmap_clear_free(HASHMAP_BASE(h));
295 }
296
297 void hashmap_clear_free_free(Hashmap *h);
298 static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) {
299 hashmap_clear_free_free(PLAIN_HASHMAP(h));
300 }
301
302 /*
303 * Note about all *_first*() functions
304 *
305 * For plain Hashmaps and Sets the order of entries is undefined.
306 * The functions find whatever entry is first in the implementation
307 * internal order.
308 *
309 * Only for OrderedHashmaps the order is well defined and finding
310 * the first entry is O(1).
311 */
312
313 void *internal_hashmap_steal_first(HashmapBase *h);
314 static inline void *hashmap_steal_first(Hashmap *h) {
315 return internal_hashmap_steal_first(HASHMAP_BASE(h));
316 }
317 static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) {
318 return internal_hashmap_steal_first(HASHMAP_BASE(h));
319 }
320
321 void *internal_hashmap_steal_first_key(HashmapBase *h);
322 static inline void *hashmap_steal_first_key(Hashmap *h) {
323 return internal_hashmap_steal_first_key(HASHMAP_BASE(h));
324 }
325 static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) {
326 return internal_hashmap_steal_first_key(HASHMAP_BASE(h));
327 }
328
329 void *internal_hashmap_first_key(HashmapBase *h) _pure_;
330 static inline void *hashmap_first_key(Hashmap *h) {
331 return internal_hashmap_first_key(HASHMAP_BASE(h));
332 }
333 static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
334 return internal_hashmap_first_key(HASHMAP_BASE(h));
335 }
336
337 void *internal_hashmap_first(HashmapBase *h) _pure_;
338 static inline void *hashmap_first(Hashmap *h) {
339 return internal_hashmap_first(HASHMAP_BASE(h));
340 }
341 static inline void *ordered_hashmap_first(OrderedHashmap *h) {
342 return internal_hashmap_first(HASHMAP_BASE(h));
343 }
344
345 #define hashmap_clear_with_destructor(_s, _f) \
346 ({ \
347 void *_item; \
348 while ((_item = hashmap_steal_first(_s))) \
349 _f(_item); \
350 })
351 #define hashmap_free_with_destructor(_s, _f) \
352 ({ \
353 hashmap_clear_with_destructor(_s, _f); \
354 hashmap_free(_s); \
355 })
356 #define ordered_hashmap_clear_with_destructor(_s, _f) \
357 ({ \
358 void *_item; \
359 while ((_item = ordered_hashmap_steal_first(_s))) \
360 _f(_item); \
361 })
362 #define ordered_hashmap_free_with_destructor(_s, _f) \
363 ({ \
364 ordered_hashmap_clear_with_destructor(_s, _f); \
365 ordered_hashmap_free(_s); \
366 })
367
368 /* no hashmap_next */
369 void *ordered_hashmap_next(OrderedHashmap *h, const void *key);
370
371 char **internal_hashmap_get_strv(HashmapBase *h);
372 static inline char **hashmap_get_strv(Hashmap *h) {
373 return internal_hashmap_get_strv(HASHMAP_BASE(h));
374 }
375 static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
376 return internal_hashmap_get_strv(HASHMAP_BASE(h));
377 }
378
379 /*
380 * Hashmaps are iterated in unpredictable order.
381 * OrderedHashmaps are an exception to this. They are iterated in the order
382 * the entries were inserted.
383 * It is safe to remove the current entry.
384 */
385 #define HASHMAP_FOREACH(e, h, i) \
386 for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), NULL); )
387
388 #define ORDERED_HASHMAP_FOREACH(e, h, i) \
389 for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), NULL); )
390
391 #define HASHMAP_FOREACH_KEY(e, k, h, i) \
392 for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); )
393
394 #define ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \
395 for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); )
396
397 DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free);
398 DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free);
399 DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free);
400 DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free);
401 DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free);
402 DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free);
403
404 #define _cleanup_hashmap_free_ _cleanup_(hashmap_freep)
405 #define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep)
406 #define _cleanup_hashmap_free_free_free_ _cleanup_(hashmap_free_free_freep)
407 #define _cleanup_ordered_hashmap_free_ _cleanup_(ordered_hashmap_freep)
408 #define _cleanup_ordered_hashmap_free_free_ _cleanup_(ordered_hashmap_free_freep)
409 #define _cleanup_ordered_hashmap_free_free_free_ _cleanup_(ordered_hashmap_free_free_freep)
410
411 DEFINE_TRIVIAL_CLEANUP_FUNC(IteratedCache*, iterated_cache_free);
412
413 #define _cleanup_iterated_cache_free_ _cleanup_(iterated_cache_freep)