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