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