]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/hashmap.h
Add SPDX license identifiers to source files under the LGPL
[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 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
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
a7334b09
LP
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
5430f7f2 18 Lesser General Public License for more details.
a7334b09 19
5430f7f2 20 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
21 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22***/
23
11c3a366 24#include <limits.h>
60918275 25#include <stdbool.h>
11c3a366 26#include <stddef.h>
60918275 27
758dd67e 28#include "hash-funcs.h"
44a6b1b6 29#include "macro.h"
5e2f14e6 30#include "util.h"
44a6b1b6 31
89439d4f
MS
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 *
fc86aa0e 37 * If ENABLE_DEBUG_HASHMAP is defined (by configuring with --enable-debug=hashmap),
89439d4f
MS
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 */
60918275 42
9bf3b535
LP
43#define HASH_KEY_SIZE 16
44
89439d4f
MS
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
90df619e 48 * internal_*() directly). */
89439d4f
MS
49typedef struct HashmapBase HashmapBase;
50
51/* Specific hashmap/set types */
52typedef struct Hashmap Hashmap; /* Maps keys to values */
53typedef struct OrderedHashmap OrderedHashmap; /* Like Hashmap, but also remembers entry insertion order */
54typedef struct Set Set; /* Stores just keys */
55
56/* Ideally the Iterator would be an opaque struct, but it is instantiated
57 * by hashmap users, so the definition has to be here. Do not use its fields
58 * directly. */
59typedef struct {
60 unsigned idx; /* index of an entry to be iterated next */
61 const void *next_key; /* expected value of that entry's key pointer */
349cc4a5 62#if ENABLE_DEBUG_HASHMAP
89439d4f
MS
63 unsigned put_count; /* hashmap's put_count recorded at start of iteration */
64 unsigned rem_count; /* hashmap's rem_count in previous iteration */
65 unsigned prev_idx; /* idx in previous iteration */
66#endif
67} Iterator;
034c6ed7 68
89439d4f
MS
69#define _IDX_ITERATOR_FIRST (UINT_MAX - 1)
70#define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL })
60918275 71
89439d4f
MS
72/* Macros for type checking */
73#define PTR_COMPATIBLE_WITH_HASHMAP_BASE(h) \
74 (__builtin_types_compatible_p(typeof(h), HashmapBase*) || \
75 __builtin_types_compatible_p(typeof(h), Hashmap*) || \
76 __builtin_types_compatible_p(typeof(h), OrderedHashmap*) || \
77 __builtin_types_compatible_p(typeof(h), Set*))
78
79#define PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h) \
80 (__builtin_types_compatible_p(typeof(h), Hashmap*) || \
81 __builtin_types_compatible_p(typeof(h), OrderedHashmap*)) \
82
83#define HASHMAP_BASE(h) \
84 __builtin_choose_expr(PTR_COMPATIBLE_WITH_HASHMAP_BASE(h), \
85 (HashmapBase*)(h), \
86 (void)0)
87
88#define PLAIN_HASHMAP(h) \
89 __builtin_choose_expr(PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h), \
90 (Hashmap*)(h), \
91 (void)0)
92
349cc4a5 93#if ENABLE_DEBUG_HASHMAP
89439d4f
MS
94# define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line
95# define HASHMAP_DEBUG_SRC_ARGS , __func__, __FILE__, __LINE__
96# define HASHMAP_DEBUG_PASS_ARGS , func, file, line
97#else
98# define HASHMAP_DEBUG_PARAMS
99# define HASHMAP_DEBUG_SRC_ARGS
100# define HASHMAP_DEBUG_PASS_ARGS
101#endif
102
103Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
104OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
105#define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
106#define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
107
cfe561a4
DH
108HashmapBase *internal_hashmap_free(HashmapBase *h);
109static inline Hashmap *hashmap_free(Hashmap *h) {
110 return (void*)internal_hashmap_free(HASHMAP_BASE(h));
5ba43716 111}
cfe561a4
DH
112static inline OrderedHashmap *ordered_hashmap_free(OrderedHashmap *h) {
113 return (void*)internal_hashmap_free(HASHMAP_BASE(h));
89439d4f
MS
114}
115
cfe561a4
DH
116HashmapBase *internal_hashmap_free_free(HashmapBase *h);
117static inline Hashmap *hashmap_free_free(Hashmap *h) {
118 return (void*)internal_hashmap_free_free(HASHMAP_BASE(h));
5ba43716 119}
cfe561a4
DH
120static inline OrderedHashmap *ordered_hashmap_free_free(OrderedHashmap *h) {
121 return (void*)internal_hashmap_free_free(HASHMAP_BASE(h));
5ba43716 122}
89439d4f 123
cfe561a4
DH
124Hashmap *hashmap_free_free_free(Hashmap *h);
125static inline OrderedHashmap *ordered_hashmap_free_free_free(OrderedHashmap *h) {
126 return (void*)hashmap_free_free_free(PLAIN_HASHMAP(h));
5ba43716 127}
89439d4f
MS
128
129HashmapBase *internal_hashmap_copy(HashmapBase *h);
130static inline Hashmap *hashmap_copy(Hashmap *h) {
131 return (Hashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
5ba43716 132}
89439d4f
MS
133static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) {
134 return (OrderedHashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
5ba43716 135}
60918275 136
89439d4f
MS
137int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
138int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
139#define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
140#define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
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
332/* no hashmap_next */
333void *ordered_hashmap_next(OrderedHashmap *h, const void *key);
3c1668da 334
89439d4f
MS
335char **internal_hashmap_get_strv(HashmapBase *h);
336static inline char **hashmap_get_strv(Hashmap *h) {
337 return internal_hashmap_get_strv(HASHMAP_BASE(h));
338}
5ba43716 339static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
89439d4f 340 return internal_hashmap_get_strv(HASHMAP_BASE(h));
5ba43716 341}
db1413d7 342
89439d4f
MS
343/*
344 * Hashmaps are iterated in unpredictable order.
345 * OrderedHashmaps are an exception to this. They are iterated in the order
346 * the entries were inserted.
347 * It is safe to remove the current entry.
348 */
034c6ed7 349#define HASHMAP_FOREACH(e, h, i) \
8927b1da 350 for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), NULL); )
60918275 351
5ba43716 352#define ORDERED_HASHMAP_FOREACH(e, h, i) \
8927b1da 353 for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), NULL); )
5ba43716 354
034c6ed7 355#define HASHMAP_FOREACH_KEY(e, k, h, i) \
8927b1da 356 for ((i) = ITERATOR_FIRST; hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); )
11dd41ce 357
5ba43716 358#define ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \
8927b1da 359 for ((i) = ITERATOR_FIRST; ordered_hashmap_iterate((h), &(i), (void**)&(e), (const void**) &(k)); )
5ba43716 360
5e2f14e6
LP
361DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free);
362DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free);
363DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free);
5ba43716
MS
364DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free);
365DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free);
366DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free);
89439d4f 367
5e2f14e6
LP
368#define _cleanup_hashmap_free_ _cleanup_(hashmap_freep)
369#define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep)
370#define _cleanup_hashmap_free_free_free_ _cleanup_(hashmap_free_free_freep)
5ba43716
MS
371#define _cleanup_ordered_hashmap_free_ _cleanup_(ordered_hashmap_freep)
372#define _cleanup_ordered_hashmap_free_free_ _cleanup_(ordered_hashmap_free_freep)
373#define _cleanup_ordered_hashmap_free_free_free_ _cleanup_(ordered_hashmap_free_free_freep)