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