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