]> git.proxmox.com Git - systemd.git/blame - src/shared/hashmap.h
Imported Upstream version 218
[systemd.git] / src / shared / hashmap.h
CommitLineData
663996b3
MS
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
f47781d8 9 Copyright 2014 Michal Schmidt
663996b3
MS
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 <stdbool.h>
26
27#include "macro.h"
60f067b4 28#include "util.h"
663996b3 29
f47781d8
MP
30/*
31 * A hash table implementation. As a minor optimization a NULL hashmap object
32 * will be treated as empty hashmap for all read operations. That way it is not
33 * necessary to instantiate an object for each Hashmap use.
34 *
35 * If ENABLE_HASHMAP_DEBUG is defined (by configuring with --enable-hashmap-debug),
36 * the implemention will:
37 * - store extra data for debugging and statistics (see tools/gdb-sd_dump_hashmaps.py)
38 * - perform extra checks for invalid use of iterators
39 */
663996b3 40
60f067b4
JS
41#define HASH_KEY_SIZE 16
42
f47781d8
MP
43/* The base type for all hashmap and set types. Many functions in the
44 * implementation take (HashmapBase*) parameters and are run-time polymorphic,
45 * though the API is not meant to be polymorphic (do not call functions
46 * prefixed with two underscores directly). */
47typedef struct HashmapBase HashmapBase;
48
49/* Specific hashmap/set types */
50typedef struct Hashmap Hashmap; /* Maps keys to values */
51typedef struct OrderedHashmap OrderedHashmap; /* Like Hashmap, but also remembers entry insertion order */
52typedef struct Set Set; /* Stores just keys */
53
54/* Ideally the Iterator would be an opaque struct, but it is instantiated
55 * by hashmap users, so the definition has to be here. Do not use its fields
56 * directly. */
57typedef struct {
58 unsigned idx; /* index of an entry to be iterated next */
59 const void *next_key; /* expected value of that entry's key pointer */
60#ifdef ENABLE_HASHMAP_DEBUG
61 unsigned put_count; /* hashmap's put_count recorded at start of iteration */
62 unsigned rem_count; /* hashmap's rem_count in previous iteration */
63 unsigned prev_idx; /* idx in previous iteration */
64#endif
65} Iterator;
663996b3 66
f47781d8
MP
67#define _IDX_ITERATOR_FIRST (UINT_MAX - 1)
68#define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL })
663996b3 69
60f067b4 70typedef unsigned long (*hash_func_t)(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]);
663996b3
MS
71typedef int (*compare_func_t)(const void *a, const void *b);
72
5eef597e
MP
73struct hash_ops {
74 hash_func_t hash;
75 compare_func_t compare;
76};
77
60f067b4 78unsigned long string_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
663996b3 79int string_compare_func(const void *a, const void *b) _pure_;
5eef597e 80extern const struct hash_ops string_hash_ops;
663996b3
MS
81
82/* This will compare the passed pointers directly, and will not
83 * dereference them. This is hence not useful for strings or
84 * suchlike. */
60f067b4 85unsigned long trivial_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
663996b3 86int trivial_compare_func(const void *a, const void *b) _const_;
5eef597e 87extern const struct hash_ops trivial_hash_ops;
663996b3 88
5eef597e
MP
89/* 32bit values we can always just embedd in the pointer itself, but
90 * in order to support 32bit archs we need store 64bit values
91 * indirectly, since they don't fit in a pointer. */
60f067b4 92unsigned long uint64_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
663996b3 93int uint64_compare_func(const void *a, const void *b) _pure_;
5eef597e
MP
94extern const struct hash_ops uint64_hash_ops;
95
96/* On some archs dev_t is 32bit, and on others 64bit. And sometimes
97 * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */
98#if SIZEOF_DEV_T != 8
99unsigned long devt_hash_func(const void *p, const uint8_t hash_key[HASH_KEY_SIZE]) _pure_;
100int devt_compare_func(const void *a, const void *b) _pure_;
101extern const struct hash_ops devt_hash_ops = {
102 .hash = devt_hash_func,
103 .compare = devt_compare_func
104};
105#else
106#define devt_hash_func uint64_hash_func
107#define devt_compare_func uint64_compare_func
108#define devt_hash_ops uint64_hash_ops
109#endif
663996b3 110
f47781d8
MP
111/* Macros for type checking */
112#define PTR_COMPATIBLE_WITH_HASHMAP_BASE(h) \
113 (__builtin_types_compatible_p(typeof(h), HashmapBase*) || \
114 __builtin_types_compatible_p(typeof(h), Hashmap*) || \
115 __builtin_types_compatible_p(typeof(h), OrderedHashmap*) || \
116 __builtin_types_compatible_p(typeof(h), Set*))
117
118#define PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h) \
119 (__builtin_types_compatible_p(typeof(h), Hashmap*) || \
120 __builtin_types_compatible_p(typeof(h), OrderedHashmap*)) \
121
122#define HASHMAP_BASE(h) \
123 __builtin_choose_expr(PTR_COMPATIBLE_WITH_HASHMAP_BASE(h), \
124 (HashmapBase*)(h), \
125 (void)0)
126
127#define PLAIN_HASHMAP(h) \
128 __builtin_choose_expr(PTR_COMPATIBLE_WITH_PLAIN_HASHMAP(h), \
129 (Hashmap*)(h), \
130 (void)0)
131
132#ifdef ENABLE_HASHMAP_DEBUG
133# define HASHMAP_DEBUG_PARAMS , const char *func, const char *file, int line
134# define HASHMAP_DEBUG_SRC_ARGS , __func__, __FILE__, __LINE__
135# define HASHMAP_DEBUG_PASS_ARGS , func, file, line
136#else
137# define HASHMAP_DEBUG_PARAMS
138# define HASHMAP_DEBUG_SRC_ARGS
139# define HASHMAP_DEBUG_PASS_ARGS
140#endif
141
142Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
143OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
144#define hashmap_new(ops) internal_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
145#define ordered_hashmap_new(ops) internal_ordered_hashmap_new(ops HASHMAP_DEBUG_SRC_ARGS)
146
147void internal_hashmap_free(HashmapBase *h);
148static inline void hashmap_free(Hashmap *h) {
149 internal_hashmap_free(HASHMAP_BASE(h));
5eef597e 150}
5eef597e 151static inline void ordered_hashmap_free(OrderedHashmap *h) {
f47781d8
MP
152 internal_hashmap_free(HASHMAP_BASE(h));
153}
154
155void internal_hashmap_free_free(HashmapBase *h);
156static inline void hashmap_free_free(Hashmap *h) {
157 internal_hashmap_free_free(HASHMAP_BASE(h));
5eef597e 158}
5eef597e 159static inline void ordered_hashmap_free_free(OrderedHashmap *h) {
f47781d8 160 internal_hashmap_free_free(HASHMAP_BASE(h));
5eef597e 161}
f47781d8 162
663996b3 163void hashmap_free_free_free(Hashmap *h);
5eef597e 164static inline void ordered_hashmap_free_free_free(OrderedHashmap *h) {
f47781d8 165 hashmap_free_free_free(PLAIN_HASHMAP(h));
5eef597e 166}
f47781d8
MP
167
168HashmapBase *internal_hashmap_copy(HashmapBase *h);
169static inline Hashmap *hashmap_copy(Hashmap *h) {
170 return (Hashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
5eef597e 171}
f47781d8
MP
172static inline OrderedHashmap *ordered_hashmap_copy(OrderedHashmap *h) {
173 return (OrderedHashmap*) internal_hashmap_copy(HASHMAP_BASE(h));
5eef597e 174}
663996b3 175
f47781d8
MP
176int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
177int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS);
178#define hashmap_ensure_allocated(h, ops) internal_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
179#define ordered_hashmap_ensure_allocated(h, ops) internal_ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS)
180
663996b3 181int hashmap_put(Hashmap *h, const void *key, void *value);
5eef597e 182static inline int ordered_hashmap_put(OrderedHashmap *h, const void *key, void *value) {
f47781d8 183 return hashmap_put(PLAIN_HASHMAP(h), key, value);
5eef597e 184}
f47781d8 185
663996b3 186int hashmap_update(Hashmap *h, const void *key, void *value);
5eef597e 187static inline int ordered_hashmap_update(OrderedHashmap *h, const void *key, void *value) {
f47781d8 188 return hashmap_update(PLAIN_HASHMAP(h), key, value);
5eef597e 189}
f47781d8 190
663996b3 191int hashmap_replace(Hashmap *h, const void *key, void *value);
5eef597e 192static inline int ordered_hashmap_replace(OrderedHashmap *h, const void *key, void *value) {
f47781d8
MP
193 return hashmap_replace(PLAIN_HASHMAP(h), key, value);
194}
195
196void *internal_hashmap_get(HashmapBase *h, const void *key);
197static inline void *hashmap_get(Hashmap *h, const void *key) {
198 return internal_hashmap_get(HASHMAP_BASE(h), key);
5eef597e 199}
5eef597e 200static inline void *ordered_hashmap_get(OrderedHashmap *h, const void *key) {
f47781d8 201 return internal_hashmap_get(HASHMAP_BASE(h), key);
5eef597e 202}
f47781d8 203
663996b3 204void *hashmap_get2(Hashmap *h, const void *key, void **rkey);
5eef597e 205static inline void *ordered_hashmap_get2(OrderedHashmap *h, const void *key, void **rkey) {
f47781d8
MP
206 return hashmap_get2(PLAIN_HASHMAP(h), key, rkey);
207}
208
209bool internal_hashmap_contains(HashmapBase *h, const void *key);
210static inline bool hashmap_contains(Hashmap *h, const void *key) {
211 return internal_hashmap_contains(HASHMAP_BASE(h), key);
5eef597e 212}
5eef597e 213static inline bool ordered_hashmap_contains(OrderedHashmap *h, const void *key) {
f47781d8
MP
214 return internal_hashmap_contains(HASHMAP_BASE(h), key);
215}
216
217void *internal_hashmap_remove(HashmapBase *h, const void *key);
218static inline void *hashmap_remove(Hashmap *h, const void *key) {
219 return internal_hashmap_remove(HASHMAP_BASE(h), key);
5eef597e 220}
5eef597e 221static inline void *ordered_hashmap_remove(OrderedHashmap *h, const void *key) {
f47781d8 222 return internal_hashmap_remove(HASHMAP_BASE(h), key);
5eef597e 223}
f47781d8 224
60f067b4 225void *hashmap_remove2(Hashmap *h, const void *key, void **rkey);
5eef597e 226static inline void *ordered_hashmap_remove2(OrderedHashmap *h, const void *key, void **rkey) {
f47781d8 227 return hashmap_remove2(PLAIN_HASHMAP(h), key, rkey);
5eef597e 228}
f47781d8 229
663996b3 230void *hashmap_remove_value(Hashmap *h, const void *key, void *value);
5eef597e 231static inline void *ordered_hashmap_remove_value(OrderedHashmap *h, const void *key, void *value) {
f47781d8 232 return hashmap_remove_value(PLAIN_HASHMAP(h), key, value);
5eef597e 233}
f47781d8 234
663996b3 235int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value);
5eef597e 236static inline int ordered_hashmap_remove_and_put(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) {
f47781d8 237 return hashmap_remove_and_put(PLAIN_HASHMAP(h), old_key, new_key, value);
5eef597e 238}
f47781d8 239
663996b3 240int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value);
5eef597e 241static inline int ordered_hashmap_remove_and_replace(OrderedHashmap *h, const void *old_key, const void *new_key, void *value) {
f47781d8 242 return hashmap_remove_and_replace(PLAIN_HASHMAP(h), old_key, new_key, value);
5eef597e 243}
663996b3 244
f47781d8
MP
245/* Since merging data from a OrderedHashmap into a Hashmap or vice-versa
246 * should just work, allow this by having looser type-checking here. */
247int internal_hashmap_merge(Hashmap *h, Hashmap *other);
248#define hashmap_merge(h, other) internal_hashmap_merge(PLAIN_HASHMAP(h), PLAIN_HASHMAP(other))
249#define ordered_hashmap_merge(h, other) hashmap_merge(h, other)
250
251int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add);
252static inline int hashmap_reserve(Hashmap *h, unsigned entries_add) {
253 return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
5eef597e 254}
5eef597e 255static inline int ordered_hashmap_reserve(OrderedHashmap *h, unsigned entries_add) {
f47781d8
MP
256 return internal_hashmap_reserve(HASHMAP_BASE(h), entries_add);
257}
258
259int internal_hashmap_move(HashmapBase *h, HashmapBase *other);
260/* Unlike hashmap_merge, hashmap_move does not allow mixing the types. */
261static inline int hashmap_move(Hashmap *h, Hashmap *other) {
262 return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
5eef597e 263}
5eef597e 264static inline int ordered_hashmap_move(OrderedHashmap *h, OrderedHashmap *other) {
f47781d8
MP
265 return internal_hashmap_move(HASHMAP_BASE(h), HASHMAP_BASE(other));
266}
267
268int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key);
269static inline int hashmap_move_one(Hashmap *h, Hashmap *other, const void *key) {
270 return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
5eef597e 271}
5eef597e 272static inline int ordered_hashmap_move_one(OrderedHashmap *h, OrderedHashmap *other, const void *key) {
f47781d8 273 return internal_hashmap_move_one(HASHMAP_BASE(h), HASHMAP_BASE(other), key);
5eef597e 274}
663996b3 275
f47781d8
MP
276unsigned internal_hashmap_size(HashmapBase *h) _pure_;
277static inline unsigned hashmap_size(Hashmap *h) {
278 return internal_hashmap_size(HASHMAP_BASE(h));
279}
5eef597e 280static inline unsigned ordered_hashmap_size(OrderedHashmap *h) {
f47781d8
MP
281 return internal_hashmap_size(HASHMAP_BASE(h));
282}
283
284static inline bool hashmap_isempty(Hashmap *h) {
285 return hashmap_size(h) == 0;
5eef597e 286}
5eef597e 287static inline bool ordered_hashmap_isempty(OrderedHashmap *h) {
f47781d8
MP
288 return ordered_hashmap_size(h) == 0;
289}
290
291unsigned internal_hashmap_buckets(HashmapBase *h) _pure_;
292static inline unsigned hashmap_buckets(Hashmap *h) {
293 return internal_hashmap_buckets(HASHMAP_BASE(h));
5eef597e 294}
5eef597e 295static inline unsigned ordered_hashmap_buckets(OrderedHashmap *h) {
f47781d8 296 return internal_hashmap_buckets(HASHMAP_BASE(h));
5eef597e 297}
663996b3 298
f47781d8
MP
299void *internal_hashmap_iterate(HashmapBase *h, Iterator *i, const void **key);
300static inline void *hashmap_iterate(Hashmap *h, Iterator *i, const void **key) {
301 return internal_hashmap_iterate(HASHMAP_BASE(h), i, key);
302}
5eef597e 303static inline void *ordered_hashmap_iterate(OrderedHashmap *h, Iterator *i, const void **key) {
f47781d8 304 return internal_hashmap_iterate(HASHMAP_BASE(h), i, key);
5eef597e 305}
663996b3 306
f47781d8
MP
307void internal_hashmap_clear(HashmapBase *h);
308static inline void hashmap_clear(Hashmap *h) {
309 internal_hashmap_clear(HASHMAP_BASE(h));
310}
5eef597e 311static inline void ordered_hashmap_clear(OrderedHashmap *h) {
f47781d8
MP
312 internal_hashmap_clear(HASHMAP_BASE(h));
313}
314
315void internal_hashmap_clear_free(HashmapBase *h);
316static inline void hashmap_clear_free(Hashmap *h) {
317 internal_hashmap_clear_free(HASHMAP_BASE(h));
5eef597e 318}
5eef597e 319static inline void ordered_hashmap_clear_free(OrderedHashmap *h) {
f47781d8 320 internal_hashmap_clear_free(HASHMAP_BASE(h));
5eef597e 321}
f47781d8 322
663996b3 323void hashmap_clear_free_free(Hashmap *h);
5eef597e 324static inline void ordered_hashmap_clear_free_free(OrderedHashmap *h) {
f47781d8 325 hashmap_clear_free_free(PLAIN_HASHMAP(h));
5eef597e 326}
663996b3 327
f47781d8
MP
328/*
329 * Note about all *_first*() functions
330 *
331 * For plain Hashmaps and Sets the order of entries is undefined.
332 * The functions find whatever entry is first in the implementation
333 * internal order.
334 *
335 * Only for OrderedHashmaps the order is well defined and finding
336 * the first entry is O(1).
337 */
338
339void *internal_hashmap_steal_first(HashmapBase *h);
340static inline void *hashmap_steal_first(Hashmap *h) {
341 return internal_hashmap_steal_first(HASHMAP_BASE(h));
342}
5eef597e 343static inline void *ordered_hashmap_steal_first(OrderedHashmap *h) {
f47781d8
MP
344 return internal_hashmap_steal_first(HASHMAP_BASE(h));
345}
346
347void *internal_hashmap_steal_first_key(HashmapBase *h);
348static inline void *hashmap_steal_first_key(Hashmap *h) {
349 return internal_hashmap_steal_first_key(HASHMAP_BASE(h));
5eef597e 350}
5eef597e 351static inline void *ordered_hashmap_steal_first_key(OrderedHashmap *h) {
f47781d8 352 return internal_hashmap_steal_first_key(HASHMAP_BASE(h));
5eef597e 353}
f47781d8
MP
354
355void *internal_hashmap_first_key(HashmapBase *h) _pure_;
356static inline void *hashmap_first_key(Hashmap *h) {
357 return internal_hashmap_first_key(HASHMAP_BASE(h));
5eef597e 358}
5eef597e 359static inline void *ordered_hashmap_first_key(OrderedHashmap *h) {
f47781d8 360 return internal_hashmap_first_key(HASHMAP_BASE(h));
5eef597e 361}
663996b3 362
f47781d8
MP
363void *internal_hashmap_first(HashmapBase *h) _pure_;
364static inline void *hashmap_first(Hashmap *h) {
365 return internal_hashmap_first(HASHMAP_BASE(h));
5eef597e 366}
f47781d8
MP
367static inline void *ordered_hashmap_first(OrderedHashmap *h) {
368 return internal_hashmap_first(HASHMAP_BASE(h));
369}
370
371/* no hashmap_next */
372void *ordered_hashmap_next(OrderedHashmap *h, const void *key);
663996b3 373
f47781d8
MP
374char **internal_hashmap_get_strv(HashmapBase *h);
375static inline char **hashmap_get_strv(Hashmap *h) {
376 return internal_hashmap_get_strv(HASHMAP_BASE(h));
377}
5eef597e 378static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
f47781d8 379 return internal_hashmap_get_strv(HASHMAP_BASE(h));
5eef597e 380}
663996b3 381
f47781d8
MP
382/*
383 * Hashmaps are iterated in unpredictable order.
384 * OrderedHashmaps are an exception to this. They are iterated in the order
385 * the entries were inserted.
386 * It is safe to remove the current entry.
387 */
663996b3 388#define HASHMAP_FOREACH(e, h, i) \
f47781d8
MP
389 for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), NULL); \
390 (e); \
391 (e) = hashmap_iterate((h), &(i), NULL))
663996b3 392
5eef597e
MP
393#define ORDERED_HASHMAP_FOREACH(e, h, i) \
394 for ((i) = ITERATOR_FIRST, (e) = ordered_hashmap_iterate((h), &(i), NULL); \
395 (e); \
396 (e) = ordered_hashmap_iterate((h), &(i), NULL))
397
663996b3 398#define HASHMAP_FOREACH_KEY(e, k, h, i) \
f47781d8
MP
399 for ((i) = ITERATOR_FIRST, (e) = hashmap_iterate((h), &(i), (const void**) &(k)); \
400 (e); \
401 (e) = hashmap_iterate((h), &(i), (const void**) &(k)))
663996b3 402
5eef597e
MP
403#define ORDERED_HASHMAP_FOREACH_KEY(e, k, h, i) \
404 for ((i) = ITERATOR_FIRST, (e) = ordered_hashmap_iterate((h), &(i), (const void**) &(k)); \
405 (e); \
406 (e) = ordered_hashmap_iterate((h), &(i), (const void**) &(k)))
60f067b4
JS
407
408DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free);
409DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free);
410DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free);
5eef597e
MP
411DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free);
412DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free);
413DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free);
f47781d8 414
60f067b4
JS
415#define _cleanup_hashmap_free_ _cleanup_(hashmap_freep)
416#define _cleanup_hashmap_free_free_ _cleanup_(hashmap_free_freep)
417#define _cleanup_hashmap_free_free_free_ _cleanup_(hashmap_free_free_freep)
5eef597e
MP
418#define _cleanup_ordered_hashmap_free_ _cleanup_(ordered_hashmap_freep)
419#define _cleanup_ordered_hashmap_free_free_ _cleanup_(ordered_hashmap_free_freep)
420#define _cleanup_ordered_hashmap_free_free_free_ _cleanup_(ordered_hashmap_free_free_freep)