]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/hashmap.c
meson.build: make docdir configurable (#8068)
[thirdparty/systemd.git] / src / basic / hashmap.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
a7334b09
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
89439d4f 6 Copyright 2014 Michal Schmidt
a7334b09
LP
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
a7334b09
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
a7334b09 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
a7334b09
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
60918275 22#include <errno.h>
11c3a366 23#include <stdint.h>
d4510856 24#include <stdlib.h>
11c3a366 25#include <string.h>
60918275 26
b5efdb8a 27#include "alloc-util.h"
60918275 28#include "hashmap.h"
556c7bae 29#include "fileio.h"
60918275 30#include "macro.h"
b3dcf58e 31#include "mempool.h"
d4510856 32#include "process-util.h"
3df3e884 33#include "random-util.h"
d4510856
LP
34#include "set.h"
35#include "siphash24.h"
556c7bae 36#include "string-util.h"
d4510856
LP
37#include "strv.h"
38#include "util.h"
60918275 39
349cc4a5 40#if ENABLE_DEBUG_HASHMAP
3d4db144 41#include <pthread.h>
2eec67ac
TA
42#include "list.h"
43#endif
44
89439d4f
MS
45/*
46 * Implementation of hashmaps.
47 * Addressing: open
48 * - uses less RAM compared to closed addressing (chaining), because
49 * our entries are small (especially in Sets, which tend to contain
50 * the majority of entries in systemd).
51 * Collision resolution: Robin Hood
52 * - tends to equalize displacement of entries from their optimal buckets.
53 * Probe sequence: linear
54 * - though theoretically worse than random probing/uniform hashing/double
55 * hashing, it is good for cache locality.
56 *
57 * References:
58 * Celis, P. 1986. Robin Hood Hashing.
59 * Ph.D. Dissertation. University of Waterloo, Waterloo, Ont., Canada, Canada.
60 * https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf
61 * - The results are derived for random probing. Suggests deletion with
62 * tombstones and two mean-centered search methods. None of that works
63 * well for linear probing.
64 *
65 * Janson, S. 2005. Individual displacements for linear probing hashing with different insertion policies.
66 * ACM Trans. Algorithms 1, 2 (October 2005), 177-213.
67 * DOI=10.1145/1103963.1103964 http://doi.acm.org/10.1145/1103963.1103964
68 * http://www.math.uu.se/~svante/papers/sj157.pdf
69 * - Applies to Robin Hood with linear probing. Contains remarks on
70 * the unsuitability of mean-centered search with linear probing.
71 *
72 * Viola, A. 2005. Exact distribution of individual displacements in linear probing hashing.
73 * ACM Trans. Algorithms 1, 2 (October 2005), 214-242.
74 * DOI=10.1145/1103963.1103965 http://doi.acm.org/10.1145/1103963.1103965
75 * - Similar to Janson. Note that Viola writes about C_{m,n} (number of probes
76 * in a successful search), and Janson writes about displacement. C = d + 1.
77 *
78 * Goossaert, E. 2013. Robin Hood hashing: backward shift deletion.
79 * http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/
80 * - Explanation of backward shift deletion with pictures.
81 *
82 * Khuong, P. 2013. The Other Robin Hood Hashing.
83 * http://www.pvk.ca/Blog/2013/11/26/the-other-robin-hood-hashing/
84 * - Short summary of random vs. linear probing, and tombstones vs. backward shift.
85 */
86
87/*
88 * XXX Ideas for improvement:
89 * For unordered hashmaps, randomize iteration order, similarly to Perl:
90 * http://blog.booking.com/hardening-perls-hash-function.html
91 */
92
93/* INV_KEEP_FREE = 1 / (1 - max_load_factor)
94 * e.g. 1 / (1 - 0.8) = 5 ... keep one fifth of the buckets free. */
95#define INV_KEEP_FREE 5U
96
97/* Fields common to entries of all hashmap/set types */
98struct hashmap_base_entry {
60918275 99 const void *key;
89439d4f
MS
100};
101
102/* Entry types for specific hashmap/set types
103 * hashmap_base_entry must be at the beginning of each entry struct. */
104
105struct plain_hashmap_entry {
106 struct hashmap_base_entry b;
60918275 107 void *value;
60918275
LP
108};
109
89439d4f
MS
110struct ordered_hashmap_entry {
111 struct plain_hashmap_entry p;
112 unsigned iterate_next, iterate_previous;
113};
60918275 114
89439d4f
MS
115struct set_entry {
116 struct hashmap_base_entry b;
117};
45fa9e29 118
89439d4f
MS
119/* In several functions it is advantageous to have the hash table extended
120 * virtually by a couple of additional buckets. We reserve special index values
121 * for these "swap" buckets. */
122#define _IDX_SWAP_BEGIN (UINT_MAX - 3)
123#define IDX_PUT (_IDX_SWAP_BEGIN + 0)
124#define IDX_TMP (_IDX_SWAP_BEGIN + 1)
125#define _IDX_SWAP_END (_IDX_SWAP_BEGIN + 2)
39c2a6f1 126
89439d4f
MS
127#define IDX_FIRST (UINT_MAX - 1) /* special index for freshly initialized iterators */
128#define IDX_NIL UINT_MAX /* special index value meaning "none" or "end" */
129
130assert_cc(IDX_FIRST == _IDX_SWAP_END);
131assert_cc(IDX_FIRST == _IDX_ITERATOR_FIRST);
132
133/* Storage space for the "swap" buckets.
134 * All entry types can fit into a ordered_hashmap_entry. */
135struct swap_entries {
136 struct ordered_hashmap_entry e[_IDX_SWAP_END - _IDX_SWAP_BEGIN];
60918275
LP
137};
138
89439d4f
MS
139/* Distance from Initial Bucket */
140typedef uint8_t dib_raw_t;
3ef11dcf
ZJS
141#define DIB_RAW_OVERFLOW ((dib_raw_t)0xfdU) /* indicates DIB value is greater than representable */
142#define DIB_RAW_REHASH ((dib_raw_t)0xfeU) /* entry yet to be rehashed during in-place resize */
143#define DIB_RAW_FREE ((dib_raw_t)0xffU) /* a free bucket */
144#define DIB_RAW_INIT ((char)DIB_RAW_FREE) /* a byte to memset a DIB store with when initializing */
89439d4f
MS
145
146#define DIB_FREE UINT_MAX
147
349cc4a5 148#if ENABLE_DEBUG_HASHMAP
89439d4f
MS
149struct hashmap_debug_info {
150 LIST_FIELDS(struct hashmap_debug_info, debug_list);
151 unsigned max_entries; /* high watermark of n_entries */
152
153 /* who allocated this hashmap */
154 int line;
155 const char *file;
156 const char *func;
157
158 /* fields to detect modification while iterating */
159 unsigned put_count; /* counts puts into the hashmap */
160 unsigned rem_count; /* counts removals from hashmap */
161 unsigned last_rem_idx; /* remembers last removal index */
39c2a6f1
LP
162};
163
89439d4f
MS
164/* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */
165static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list);
4f1b3061 166static pthread_mutex_t hashmap_debug_list_mutex = PTHREAD_MUTEX_INITIALIZER;
39c2a6f1 167
89439d4f 168#define HASHMAP_DEBUG_FIELDS struct hashmap_debug_info debug;
39c2a6f1 169
fc86aa0e 170#else /* !ENABLE_DEBUG_HASHMAP */
89439d4f 171#define HASHMAP_DEBUG_FIELDS
fc86aa0e 172#endif /* ENABLE_DEBUG_HASHMAP */
39c2a6f1 173
89439d4f
MS
174enum HashmapType {
175 HASHMAP_TYPE_PLAIN,
176 HASHMAP_TYPE_ORDERED,
177 HASHMAP_TYPE_SET,
178 _HASHMAP_TYPE_MAX
179};
39c2a6f1 180
89439d4f 181struct _packed_ indirect_storage {
1a39bc8c 182 void *storage; /* where buckets and DIBs are stored */
89439d4f
MS
183 uint8_t hash_key[HASH_KEY_SIZE]; /* hash key; changes during resize */
184
185 unsigned n_entries; /* number of stored entries */
186 unsigned n_buckets; /* number of buckets */
187
188 unsigned idx_lowest_entry; /* Index below which all buckets are free.
189 Makes "while(hashmap_steal_first())" loops
190 O(n) instead of O(n^2) for unordered hashmaps. */
191 uint8_t _pad[3]; /* padding for the whole HashmapBase */
192 /* The bitfields in HashmapBase complete the alignment of the whole thing. */
193};
194
195struct direct_storage {
196 /* This gives us 39 bytes on 64bit, or 35 bytes on 32bit.
197 * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit,
198 * or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */
1a39bc8c 199 uint8_t storage[sizeof(struct indirect_storage)];
89439d4f
MS
200};
201
202#define DIRECT_BUCKETS(entry_t) \
203 (sizeof(struct direct_storage) / (sizeof(entry_t) + sizeof(dib_raw_t)))
204
205/* We should be able to store at least one entry directly. */
206assert_cc(DIRECT_BUCKETS(struct ordered_hashmap_entry) >= 1);
207
208/* We have 3 bits for n_direct_entries. */
209assert_cc(DIRECT_BUCKETS(struct set_entry) < (1 << 3));
210
211/* Hashmaps with directly stored entries all use this shared hash key.
212 * It's no big deal if the key is guessed, because there can be only
213 * a handful of directly stored entries in a hashmap. When a hashmap
214 * outgrows direct storage, it gets its own key for indirect storage. */
215static uint8_t shared_hash_key[HASH_KEY_SIZE];
216static bool shared_hash_key_initialized;
217
218/* Fields that all hashmap/set types must have */
219struct HashmapBase {
220 const struct hash_ops *hash_ops; /* hash and compare ops to use */
221
222 union _packed_ {
223 struct indirect_storage indirect; /* if has_indirect */
224 struct direct_storage direct; /* if !has_indirect */
225 };
226
227 enum HashmapType type:2; /* HASHMAP_TYPE_* */
228 bool has_indirect:1; /* whether indirect storage is used */
229 unsigned n_direct_entries:3; /* Number of entries in direct storage.
230 * Only valid if !has_indirect. */
231 bool from_pool:1; /* whether was allocated from mempool */
45ea84d8
VC
232 bool dirty:1; /* whether dirtied since last iterated_cache_get() */
233 bool cached:1; /* whether this hashmap is being cached */
89439d4f
MS
234 HASHMAP_DEBUG_FIELDS /* optional hashmap_debug_info */
235};
236
237/* Specific hash types
238 * HashmapBase must be at the beginning of each hashmap struct. */
239
240struct Hashmap {
241 struct HashmapBase b;
242};
243
244struct OrderedHashmap {
245 struct HashmapBase b;
246 unsigned iterate_list_head, iterate_list_tail;
247};
248
249struct Set {
250 struct HashmapBase b;
251};
252
45ea84d8
VC
253typedef struct CacheMem {
254 const void **ptr;
255 size_t n_populated, n_allocated;
256 bool active:1;
257} CacheMem;
258
259struct IteratedCache {
260 HashmapBase *hashmap;
261 CacheMem keys, values;
262};
263
89439d4f
MS
264DEFINE_MEMPOOL(hashmap_pool, Hashmap, 8);
265DEFINE_MEMPOOL(ordered_hashmap_pool, OrderedHashmap, 8);
266/* No need for a separate Set pool */
267assert_cc(sizeof(Hashmap) == sizeof(Set));
268
269struct hashmap_type_info {
270 size_t head_size;
271 size_t entry_size;
272 struct mempool *mempool;
273 unsigned n_direct_buckets;
274};
275
276static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
277 [HASHMAP_TYPE_PLAIN] = {
278 .head_size = sizeof(Hashmap),
279 .entry_size = sizeof(struct plain_hashmap_entry),
280 .mempool = &hashmap_pool,
281 .n_direct_buckets = DIRECT_BUCKETS(struct plain_hashmap_entry),
282 },
283 [HASHMAP_TYPE_ORDERED] = {
284 .head_size = sizeof(OrderedHashmap),
285 .entry_size = sizeof(struct ordered_hashmap_entry),
286 .mempool = &ordered_hashmap_pool,
287 .n_direct_buckets = DIRECT_BUCKETS(struct ordered_hashmap_entry),
288 },
289 [HASHMAP_TYPE_SET] = {
290 .head_size = sizeof(Set),
291 .entry_size = sizeof(struct set_entry),
292 .mempool = &hashmap_pool,
293 .n_direct_buckets = DIRECT_BUCKETS(struct set_entry),
294 },
295};
39c2a6f1 296
556c7bae
ZJS
297#ifdef VALGRIND
298__attribute__((destructor)) static void cleanup_pools(void) {
299 _cleanup_free_ char *t = NULL;
300 int r;
301
302 /* Be nice to valgrind */
303
304 /* The pool is only allocated by the main thread, but the memory can
305 * be passed to other threads. Let's clean up if we are the main thread
306 * and no other threads are live. */
307 if (!is_main_thread())
308 return;
309
310 r = get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t);
311 if (r < 0 || !streq(t, "1"))
312 return;
313
314 mempool_drop(&hashmap_pool);
315 mempool_drop(&ordered_hashmap_pool);
316}
317#endif
318
89439d4f
MS
319static unsigned n_buckets(HashmapBase *h) {
320 return h->has_indirect ? h->indirect.n_buckets
321 : hashmap_type_info[h->type].n_direct_buckets;
322}
323
324static unsigned n_entries(HashmapBase *h) {
325 return h->has_indirect ? h->indirect.n_entries
326 : h->n_direct_entries;
327}
328
329static void n_entries_inc(HashmapBase *h) {
330 if (h->has_indirect)
331 h->indirect.n_entries++;
332 else
333 h->n_direct_entries++;
334}
335
336static void n_entries_dec(HashmapBase *h) {
337 if (h->has_indirect)
338 h->indirect.n_entries--;
339 else
340 h->n_direct_entries--;
341}
342
1a39bc8c 343static void *storage_ptr(HashmapBase *h) {
89439d4f
MS
344 return h->has_indirect ? h->indirect.storage
345 : h->direct.storage;
346}
347
348static uint8_t *hash_key(HashmapBase *h) {
349 return h->has_indirect ? h->indirect.hash_key
350 : shared_hash_key;
351}
352
353static unsigned base_bucket_hash(HashmapBase *h, const void *p) {
b826ab58 354 struct siphash state;
0cb3c286 355 uint64_t hash;
b826ab58 356
0cb3c286 357 siphash24_init(&state, hash_key(h));
b826ab58
TG
358
359 h->hash_ops->hash(p, &state);
360
933f9cae 361 hash = siphash24_finalize(&state);
0cb3c286
TG
362
363 return (unsigned) (hash % n_buckets(h));
9bf3b535 364}
89439d4f 365#define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p)
9bf3b535 366
84dcca75
VC
367static inline void base_set_dirty(HashmapBase *h) {
368 h->dirty = true;
369}
370#define hashmap_set_dirty(h) base_set_dirty(HASHMAP_BASE(h))
371
9bf3b535
LP
372static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) {
373 static uint8_t current[HASH_KEY_SIZE];
374 static bool current_initialized = false;
375
376 /* Returns a hash function key to use. In order to keep things
377 * fast we will not generate a new key each time we allocate a
378 * new hash table. Instead, we'll just reuse the most recently
379 * generated one, except if we never generated one or when we
380 * are rehashing an entire hash table because we reached a
381 * fill level */
382
383 if (!current_initialized || !reuse_is_ok) {
384 random_bytes(current, sizeof(current));
385 current_initialized = true;
386 }
387
388 memcpy(hash_key, current, sizeof(current));
a3b6fafe
LP
389}
390
89439d4f
MS
391static struct hashmap_base_entry *bucket_at(HashmapBase *h, unsigned idx) {
392 return (struct hashmap_base_entry*)
1a39bc8c 393 ((uint8_t*) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
89439d4f
MS
394}
395
396static struct plain_hashmap_entry *plain_bucket_at(Hashmap *h, unsigned idx) {
397 return (struct plain_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
398}
399
400static struct ordered_hashmap_entry *ordered_bucket_at(OrderedHashmap *h, unsigned idx) {
401 return (struct ordered_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
402}
39c2a6f1 403
89439d4f
MS
404static struct set_entry *set_bucket_at(Set *h, unsigned idx) {
405 return (struct set_entry*) bucket_at(HASHMAP_BASE(h), idx);
406}
39c2a6f1 407
89439d4f
MS
408static struct ordered_hashmap_entry *bucket_at_swap(struct swap_entries *swap, unsigned idx) {
409 return &swap->e[idx - _IDX_SWAP_BEGIN];
410}
39c2a6f1 411
89439d4f
MS
412/* Returns a pointer to the bucket at index idx.
413 * Understands real indexes and swap indexes, hence "_virtual". */
414static struct hashmap_base_entry *bucket_at_virtual(HashmapBase *h, struct swap_entries *swap,
415 unsigned idx) {
416 if (idx < _IDX_SWAP_BEGIN)
417 return bucket_at(h, idx);
418
419 if (idx < _IDX_SWAP_END)
420 return &bucket_at_swap(swap, idx)->p.b;
421
422 assert_not_reached("Invalid index");
423}
424
425static dib_raw_t *dib_raw_ptr(HashmapBase *h) {
426 return (dib_raw_t*)
1a39bc8c 427 ((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h));
89439d4f
MS
428}
429
430static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) {
431 return idx >= from ? idx - from
432 : n_buckets(h) + idx - from;
433}
434
435static unsigned bucket_calculate_dib(HashmapBase *h, unsigned idx, dib_raw_t raw_dib) {
436 unsigned initial_bucket;
437
438 if (raw_dib == DIB_RAW_FREE)
439 return DIB_FREE;
440
441 if (_likely_(raw_dib < DIB_RAW_OVERFLOW))
442 return raw_dib;
443
444 /*
445 * Having an overflow DIB value is very unlikely. The hash function
446 * would have to be bad. For example, in a table of size 2^24 filled
447 * to load factor 0.9 the maximum observed DIB is only about 60.
448 * In theory (assuming I used Maxima correctly), for an infinite size
449 * hash table with load factor 0.8 the probability of a given entry
450 * having DIB > 40 is 1.9e-8.
451 * This returns the correct DIB value by recomputing the hash value in
452 * the unlikely case. XXX Hitting this case could be a hint to rehash.
453 */
454 initial_bucket = bucket_hash(h, bucket_at(h, idx)->key);
455 return bucket_distance(h, idx, initial_bucket);
456}
457
458static void bucket_set_dib(HashmapBase *h, unsigned idx, unsigned dib) {
459 dib_raw_ptr(h)[idx] = dib != DIB_FREE ? MIN(dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE;
460}
461
462static unsigned skip_free_buckets(HashmapBase *h, unsigned idx) {
463 dib_raw_t *dibs;
464
465 dibs = dib_raw_ptr(h);
466
467 for ( ; idx < n_buckets(h); idx++)
468 if (dibs[idx] != DIB_RAW_FREE)
469 return idx;
470
471 return IDX_NIL;
472}
473
474static void bucket_mark_free(HashmapBase *h, unsigned idx) {
eccaf899 475 memzero(bucket_at(h, idx), hashmap_type_info[h->type].entry_size);
89439d4f
MS
476 bucket_set_dib(h, idx, DIB_FREE);
477}
478
479static void bucket_move_entry(HashmapBase *h, struct swap_entries *swap,
480 unsigned from, unsigned to) {
481 struct hashmap_base_entry *e_from, *e_to;
482
483 assert(from != to);
39c2a6f1 484
89439d4f
MS
485 e_from = bucket_at_virtual(h, swap, from);
486 e_to = bucket_at_virtual(h, swap, to);
487
488 memcpy(e_to, e_from, hashmap_type_info[h->type].entry_size);
489
490 if (h->type == HASHMAP_TYPE_ORDERED) {
491 OrderedHashmap *lh = (OrderedHashmap*) h;
492 struct ordered_hashmap_entry *le, *le_to;
493
494 le_to = (struct ordered_hashmap_entry*) e_to;
495
496 if (le_to->iterate_next != IDX_NIL) {
497 le = (struct ordered_hashmap_entry*)
498 bucket_at_virtual(h, swap, le_to->iterate_next);
499 le->iterate_previous = to;
500 }
501
502 if (le_to->iterate_previous != IDX_NIL) {
503 le = (struct ordered_hashmap_entry*)
504 bucket_at_virtual(h, swap, le_to->iterate_previous);
505 le->iterate_next = to;
506 }
507
508 if (lh->iterate_list_head == from)
509 lh->iterate_list_head = to;
510 if (lh->iterate_list_tail == from)
511 lh->iterate_list_tail = to;
39c2a6f1 512 }
89439d4f 513}
60918275 514
89439d4f
MS
515static unsigned next_idx(HashmapBase *h, unsigned idx) {
516 return (idx + 1U) % n_buckets(h);
517}
60918275 518
89439d4f
MS
519static unsigned prev_idx(HashmapBase *h, unsigned idx) {
520 return (n_buckets(h) + idx - 1U) % n_buckets(h);
521}
60918275 522
89439d4f
MS
523static void *entry_value(HashmapBase *h, struct hashmap_base_entry *e) {
524 switch (h->type) {
45fa9e29 525
89439d4f
MS
526 case HASHMAP_TYPE_PLAIN:
527 case HASHMAP_TYPE_ORDERED:
528 return ((struct plain_hashmap_entry*)e)->value;
39c2a6f1 529
89439d4f
MS
530 case HASHMAP_TYPE_SET:
531 return (void*) e->key;
a3b6fafe 532
89439d4f
MS
533 default:
534 assert_not_reached("Unknown hashmap type");
535 }
60918275
LP
536}
537
89439d4f
MS
538static void base_remove_entry(HashmapBase *h, unsigned idx) {
539 unsigned left, right, prev, dib;
540 dib_raw_t raw_dib, *dibs;
45fa9e29 541
89439d4f
MS
542 dibs = dib_raw_ptr(h);
543 assert(dibs[idx] != DIB_RAW_FREE);
034c6ed7 544
349cc4a5 545#if ENABLE_DEBUG_HASHMAP
89439d4f
MS
546 h->debug.rem_count++;
547 h->debug.last_rem_idx = idx;
548#endif
034c6ed7 549
89439d4f
MS
550 left = idx;
551 /* Find the stop bucket ("right"). It is either free or has DIB == 0. */
552 for (right = next_idx(h, left); ; right = next_idx(h, right)) {
553 raw_dib = dibs[right];
4c701096 554 if (IN_SET(raw_dib, 0, DIB_RAW_FREE))
89439d4f
MS
555 break;
556
557 /* The buckets are not supposed to be all occupied and with DIB > 0.
558 * That would mean we could make everyone better off by shifting them
559 * backward. This scenario is impossible. */
560 assert(left != right);
561 }
034c6ed7 562
89439d4f
MS
563 if (h->type == HASHMAP_TYPE_ORDERED) {
564 OrderedHashmap *lh = (OrderedHashmap*) h;
565 struct ordered_hashmap_entry *le = ordered_bucket_at(lh, idx);
566
567 if (le->iterate_next != IDX_NIL)
568 ordered_bucket_at(lh, le->iterate_next)->iterate_previous = le->iterate_previous;
569 else
570 lh->iterate_list_tail = le->iterate_previous;
571
572 if (le->iterate_previous != IDX_NIL)
573 ordered_bucket_at(lh, le->iterate_previous)->iterate_next = le->iterate_next;
574 else
575 lh->iterate_list_head = le->iterate_next;
576 }
577
578 /* Now shift all buckets in the interval (left, right) one step backwards */
579 for (prev = left, left = next_idx(h, left); left != right;
580 prev = left, left = next_idx(h, left)) {
581 dib = bucket_calculate_dib(h, left, dibs[left]);
582 assert(dib != 0);
583 bucket_move_entry(h, NULL, left, prev);
584 bucket_set_dib(h, prev, dib - 1);
585 }
586
587 bucket_mark_free(h, prev);
588 n_entries_dec(h);
84dcca75 589 base_set_dirty(h);
034c6ed7 590}
89439d4f
MS
591#define remove_entry(h, idx) base_remove_entry(HASHMAP_BASE(h), idx)
592
593static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *i) {
594 struct ordered_hashmap_entry *e;
595 unsigned idx;
034c6ed7 596
101d8e63 597 assert(h);
89439d4f
MS
598 assert(i);
599
600 if (i->idx == IDX_NIL)
601 goto at_end;
602
603 if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL)
604 goto at_end;
605
606 if (i->idx == IDX_FIRST) {
607 idx = h->iterate_list_head;
608 e = ordered_bucket_at(h, idx);
101d8e63 609 } else {
89439d4f
MS
610 idx = i->idx;
611 e = ordered_bucket_at(h, idx);
612 /*
613 * We allow removing the current entry while iterating, but removal may cause
614 * a backward shift. The next entry may thus move one bucket to the left.
615 * To detect when it happens, we remember the key pointer of the entry we were
616 * going to iterate next. If it does not match, there was a backward shift.
617 */
618 if (e->p.b.key != i->next_key) {
619 idx = prev_idx(HASHMAP_BASE(h), idx);
620 e = ordered_bucket_at(h, idx);
621 }
622 assert(e->p.b.key == i->next_key);
101d8e63 623 }
101d8e63 624
349cc4a5 625#if ENABLE_DEBUG_HASHMAP
89439d4f
MS
626 i->prev_idx = idx;
627#endif
628
629 if (e->iterate_next != IDX_NIL) {
630 struct ordered_hashmap_entry *n;
631 i->idx = e->iterate_next;
632 n = ordered_bucket_at(h, i->idx);
633 i->next_key = n->p.b.key;
634 } else
635 i->idx = IDX_NIL;
636
637 return idx;
638
639at_end:
640 i->idx = IDX_NIL;
641 return IDX_NIL;
101d8e63
LP
642}
643
89439d4f
MS
644static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) {
645 unsigned idx;
646
60918275 647 assert(h);
89439d4f 648 assert(i);
60918275 649
89439d4f
MS
650 if (i->idx == IDX_NIL)
651 goto at_end;
60918275 652
89439d4f
MS
653 if (i->idx == IDX_FIRST) {
654 /* fast forward to the first occupied bucket */
655 if (h->has_indirect) {
656 i->idx = skip_free_buckets(h, h->indirect.idx_lowest_entry);
657 h->indirect.idx_lowest_entry = i->idx;
658 } else
659 i->idx = skip_free_buckets(h, 0);
660
661 if (i->idx == IDX_NIL)
662 goto at_end;
663 } else {
664 struct hashmap_base_entry *e;
665
666 assert(i->idx > 0);
60918275 667
89439d4f
MS
668 e = bucket_at(h, i->idx);
669 /*
670 * We allow removing the current entry while iterating, but removal may cause
671 * a backward shift. The next entry may thus move one bucket to the left.
672 * To detect when it happens, we remember the key pointer of the entry we were
673 * going to iterate next. If it does not match, there was a backward shift.
674 */
675 if (e->key != i->next_key)
676 e = bucket_at(h, --i->idx);
60918275 677
89439d4f
MS
678 assert(e->key == i->next_key);
679 }
680
681 idx = i->idx;
349cc4a5 682#if ENABLE_DEBUG_HASHMAP
89439d4f
MS
683 i->prev_idx = idx;
684#endif
685
686 i->idx = skip_free_buckets(h, i->idx + 1);
687 if (i->idx != IDX_NIL)
688 i->next_key = bucket_at(h, i->idx)->key;
101d8e63 689 else
89439d4f
MS
690 i->idx = IDX_NIL;
691
692 return idx;
60918275 693
89439d4f
MS
694at_end:
695 i->idx = IDX_NIL;
696 return IDX_NIL;
60918275
LP
697}
698
89439d4f
MS
699static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
700 if (!h) {
701 i->idx = IDX_NIL;
702 return IDX_NIL;
703 }
101d8e63 704
349cc4a5 705#if ENABLE_DEBUG_HASHMAP
89439d4f
MS
706 if (i->idx == IDX_FIRST) {
707 i->put_count = h->debug.put_count;
708 i->rem_count = h->debug.rem_count;
709 } else {
710 /* While iterating, must not add any new entries */
711 assert(i->put_count == h->debug.put_count);
712 /* ... or remove entries other than the current one */
713 assert(i->rem_count == h->debug.rem_count ||
714 (i->rem_count == h->debug.rem_count - 1 &&
715 i->prev_idx == h->debug.last_rem_idx));
716 /* Reset our removals counter */
717 i->rem_count = h->debug.rem_count;
718 }
719#endif
101d8e63 720
89439d4f
MS
721 return h->type == HASHMAP_TYPE_ORDERED ? hashmap_iterate_in_insertion_order((OrderedHashmap*) h, i)
722 : hashmap_iterate_in_internal_order(h, i);
723}
39c2a6f1 724
8927b1da 725bool internal_hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) {
89439d4f
MS
726 struct hashmap_base_entry *e;
727 void *data;
728 unsigned idx;
729
730 idx = hashmap_iterate_entry(h, i);
731 if (idx == IDX_NIL) {
8927b1da
DH
732 if (value)
733 *value = NULL;
89439d4f
MS
734 if (key)
735 *key = NULL;
736
8927b1da 737 return false;
89439d4f
MS
738 }
739
740 e = bucket_at(h, idx);
741 data = entry_value(h, e);
8927b1da
DH
742 if (value)
743 *value = data;
89439d4f
MS
744 if (key)
745 *key = e->key;
746
8927b1da 747 return true;
101d8e63
LP
748}
749
8927b1da
DH
750bool set_iterate(Set *s, Iterator *i, void **value) {
751 return internal_hashmap_iterate(HASHMAP_BASE(s), i, value, NULL);
89439d4f 752}
60918275 753
89439d4f
MS
754#define HASHMAP_FOREACH_IDX(idx, h, i) \
755 for ((i) = ITERATOR_FIRST, (idx) = hashmap_iterate_entry((h), &(i)); \
756 (idx != IDX_NIL); \
757 (idx) = hashmap_iterate_entry((h), &(i)))
758
45ea84d8
VC
759IteratedCache *internal_hashmap_iterated_cache_new(HashmapBase *h) {
760 IteratedCache *cache;
761
762 assert(h);
763 assert(!h->cached);
764
765 if (h->cached)
766 return NULL;
767
768 cache = new0(IteratedCache, 1);
769 if (!cache)
770 return NULL;
771
772 cache->hashmap = h;
773 h->cached = true;
774
775 return cache;
776}
777
89439d4f
MS
778static void reset_direct_storage(HashmapBase *h) {
779 const struct hashmap_type_info *hi = &hashmap_type_info[h->type];
780 void *p;
781
782 assert(!h->has_indirect);
783
784 p = mempset(h->direct.storage, 0, hi->entry_size * hi->n_direct_buckets);
785 memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets);
786}
787
3ef11dcf 788static struct HashmapBase *hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) {
89439d4f
MS
789 HashmapBase *h;
790 const struct hashmap_type_info *hi = &hashmap_type_info[type];
791 bool use_pool;
792
793 use_pool = is_main_thread();
794
795 h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
67f3c402 796
60918275 797 if (!h)
89439d4f
MS
798 return NULL;
799
800 h->type = type;
801 h->from_pool = use_pool;
802 h->hash_ops = hash_ops ? hash_ops : &trivial_hash_ops;
803
804 if (type == HASHMAP_TYPE_ORDERED) {
805 OrderedHashmap *lh = (OrderedHashmap*)h;
806 lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
807 }
808
809 reset_direct_storage(h);
60918275 810
89439d4f
MS
811 if (!shared_hash_key_initialized) {
812 random_bytes(shared_hash_key, sizeof(shared_hash_key));
813 shared_hash_key_initialized= true;
814 }
815
349cc4a5 816#if ENABLE_DEBUG_HASHMAP
89439d4f
MS
817 h->debug.func = func;
818 h->debug.file = file;
819 h->debug.line = line;
4f1b3061
TG
820 assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
821 LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug);
822 assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
89439d4f
MS
823#endif
824
825 return h;
826}
60918275 827
89439d4f 828Hashmap *internal_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
3ef11dcf 829 return (Hashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
89439d4f
MS
830}
831
832OrderedHashmap *internal_ordered_hashmap_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
3ef11dcf 833 return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
89439d4f
MS
834}
835
836Set *internal_set_new(const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
3ef11dcf 837 return (Set*) hashmap_base_new(hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
89439d4f
MS
838}
839
840static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops,
3ef11dcf 841 enum HashmapType type HASHMAP_DEBUG_PARAMS) {
89439d4f
MS
842 HashmapBase *q;
843
844 assert(h);
845
846 if (*h)
847 return 0;
848
3ef11dcf 849 q = hashmap_base_new(hash_ops, type HASHMAP_DEBUG_PASS_ARGS);
89439d4f
MS
850 if (!q)
851 return -ENOMEM;
852
853 *h = q;
854 return 0;
855}
856
857int internal_hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
3ef11dcf 858 return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN HASHMAP_DEBUG_PASS_ARGS);
89439d4f
MS
859}
860
861int internal_ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
3ef11dcf 862 return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED HASHMAP_DEBUG_PASS_ARGS);
89439d4f
MS
863}
864
865int internal_set_ensure_allocated(Set **s, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS) {
3ef11dcf 866 return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET HASHMAP_DEBUG_PASS_ARGS);
89439d4f
MS
867}
868
869static void hashmap_free_no_clear(HashmapBase *h) {
870 assert(!h->has_indirect);
871 assert(!h->n_direct_entries);
872
349cc4a5 873#if ENABLE_DEBUG_HASHMAP
4f1b3061 874 assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
89439d4f 875 LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug);
4f1b3061 876 assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
89439d4f 877#endif
45fa9e29 878
39c2a6f1 879 if (h->from_pool)
89439d4f 880 mempool_free_tile(hashmap_type_info[h->type].mempool, h);
39c2a6f1
LP
881 else
882 free(h);
60918275
LP
883}
884
cfe561a4 885HashmapBase *internal_hashmap_free(HashmapBase *h) {
89439d4f
MS
886
887 /* Free the hashmap, but nothing in it */
888
cfe561a4
DH
889 if (h) {
890 internal_hashmap_clear(h);
891 hashmap_free_no_clear(h);
892 }
89439d4f 893
cfe561a4 894 return NULL;
89439d4f
MS
895}
896
cfe561a4 897HashmapBase *internal_hashmap_free_free(HashmapBase *h) {
67f3c402
LP
898
899 /* Free the hashmap and all data objects in it, but not the
900 * keys */
901
cfe561a4
DH
902 if (h) {
903 internal_hashmap_clear_free(h);
904 hashmap_free_no_clear(h);
905 }
61b1477c 906
cfe561a4 907 return NULL;
449ddb2d
LP
908}
909
cfe561a4 910Hashmap *hashmap_free_free_free(Hashmap *h) {
fabe5c0e
LP
911
912 /* Free the hashmap and all data and key objects in it */
913
cfe561a4
DH
914 if (h) {
915 hashmap_clear_free_free(h);
916 hashmap_free_no_clear(HASHMAP_BASE(h));
917 }
fabe5c0e 918
cfe561a4 919 return NULL;
fabe5c0e
LP
920}
921
89439d4f 922void internal_hashmap_clear(HashmapBase *h) {
11dd41ce
LP
923 if (!h)
924 return;
925
89439d4f
MS
926 if (h->has_indirect) {
927 free(h->indirect.storage);
928 h->has_indirect = false;
929 }
930
931 h->n_direct_entries = 0;
932 reset_direct_storage(h);
933
934 if (h->type == HASHMAP_TYPE_ORDERED) {
935 OrderedHashmap *lh = (OrderedHashmap*) h;
936 lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
937 }
84dcca75
VC
938
939 base_set_dirty(h);
11dd41ce
LP
940}
941
89439d4f
MS
942void internal_hashmap_clear_free(HashmapBase *h) {
943 unsigned idx;
9946996c 944
61b1477c
LP
945 if (!h)
946 return;
9946996c 947
89439d4f
MS
948 for (idx = skip_free_buckets(h, 0); idx != IDX_NIL;
949 idx = skip_free_buckets(h, idx + 1))
950 free(entry_value(h, bucket_at(h, idx)));
951
952 internal_hashmap_clear(h);
9946996c
LP
953}
954
fabe5c0e 955void hashmap_clear_free_free(Hashmap *h) {
89439d4f
MS
956 unsigned idx;
957
fabe5c0e
LP
958 if (!h)
959 return;
960
89439d4f
MS
961 for (idx = skip_free_buckets(HASHMAP_BASE(h), 0); idx != IDX_NIL;
962 idx = skip_free_buckets(HASHMAP_BASE(h), idx + 1)) {
963 struct plain_hashmap_entry *e = plain_bucket_at(h, idx);
964 free((void*)e->b.key);
965 free(e->value);
fabe5c0e 966 }
89439d4f
MS
967
968 internal_hashmap_clear(HASHMAP_BASE(h));
fabe5c0e
LP
969}
970
89439d4f
MS
971static int resize_buckets(HashmapBase *h, unsigned entries_add);
972
973/*
974 * Finds an empty bucket to put an entry into, starting the scan at 'idx'.
975 * Performs Robin Hood swaps as it goes. The entry to put must be placed
976 * by the caller into swap slot IDX_PUT.
977 * If used for in-place resizing, may leave a displaced entry in swap slot
978 * IDX_PUT. Caller must rehash it next.
979 * Returns: true if it left a displaced entry to rehash next in IDX_PUT,
980 * false otherwise.
981 */
982static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
983 struct swap_entries *swap) {
984 dib_raw_t raw_dib, *dibs;
985 unsigned dib, distance;
986
349cc4a5 987#if ENABLE_DEBUG_HASHMAP
89439d4f
MS
988 h->debug.put_count++;
989#endif
990
991 dibs = dib_raw_ptr(h);
992
993 for (distance = 0; ; distance++) {
994 raw_dib = dibs[idx];
3742095b 995 if (IN_SET(raw_dib, DIB_RAW_FREE, DIB_RAW_REHASH)) {
89439d4f
MS
996 if (raw_dib == DIB_RAW_REHASH)
997 bucket_move_entry(h, swap, idx, IDX_TMP);
998
999 if (h->has_indirect && h->indirect.idx_lowest_entry > idx)
1000 h->indirect.idx_lowest_entry = idx;
60918275 1001
89439d4f
MS
1002 bucket_set_dib(h, idx, distance);
1003 bucket_move_entry(h, swap, IDX_PUT, idx);
1004 if (raw_dib == DIB_RAW_REHASH) {
1005 bucket_move_entry(h, swap, IDX_TMP, IDX_PUT);
1006 return true;
1007 }
60918275 1008
89439d4f
MS
1009 return false;
1010 }
1011
1012 dib = bucket_calculate_dib(h, idx, raw_dib);
1013
1014 if (dib < distance) {
1015 /* Found a wealthier entry. Go Robin Hood! */
89439d4f
MS
1016 bucket_set_dib(h, idx, distance);
1017
1018 /* swap the entries */
1019 bucket_move_entry(h, swap, idx, IDX_TMP);
1020 bucket_move_entry(h, swap, IDX_PUT, idx);
1021 bucket_move_entry(h, swap, IDX_TMP, IDX_PUT);
1022
1023 distance = dib;
1024 }
1025
1026 idx = next_idx(h, idx);
1027 }
60918275
LP
1028}
1029
89439d4f
MS
1030/*
1031 * Puts an entry into a hashmap, boldly - no check whether key already exists.
1032 * The caller must place the entry (only its key and value, not link indexes)
1033 * in swap slot IDX_PUT.
1034 * Caller must ensure: the key does not exist yet in the hashmap.
1035 * that resize is not needed if !may_resize.
1036 * Returns: 1 if entry was put successfully.
1037 * -ENOMEM if may_resize==true and resize failed with -ENOMEM.
1038 * Cannot return -ENOMEM if !may_resize.
1039 */
1040static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx,
1041 struct swap_entries *swap, bool may_resize) {
1042 struct ordered_hashmap_entry *new_entry;
1043 int r;
1044
1045 assert(idx < n_buckets(h));
1046
1047 new_entry = bucket_at_swap(swap, IDX_PUT);
1048
1049 if (may_resize) {
1050 r = resize_buckets(h, 1);
1051 if (r < 0)
1052 return r;
1053 if (r > 0)
1054 idx = bucket_hash(h, new_entry->p.b.key);
1055 }
1056 assert(n_entries(h) < n_buckets(h));
1057
1058 if (h->type == HASHMAP_TYPE_ORDERED) {
1059 OrderedHashmap *lh = (OrderedHashmap*) h;
1060
1061 new_entry->iterate_next = IDX_NIL;
1062 new_entry->iterate_previous = lh->iterate_list_tail;
1063
1064 if (lh->iterate_list_tail != IDX_NIL) {
1065 struct ordered_hashmap_entry *old_tail;
1066
1067 old_tail = ordered_bucket_at(lh, lh->iterate_list_tail);
1068 assert(old_tail->iterate_next == IDX_NIL);
1069 old_tail->iterate_next = IDX_PUT;
1070 }
1071
1072 lh->iterate_list_tail = IDX_PUT;
1073 if (lh->iterate_list_head == IDX_NIL)
1074 lh->iterate_list_head = IDX_PUT;
1075 }
1076
1077 assert_se(hashmap_put_robin_hood(h, idx, swap) == false);
1078
1079 n_entries_inc(h);
349cc4a5 1080#if ENABLE_DEBUG_HASHMAP
89439d4f
MS
1081 h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h));
1082#endif
1083
84dcca75
VC
1084 base_set_dirty(h);
1085
89439d4f
MS
1086 return 1;
1087}
1088#define hashmap_put_boldly(h, idx, swap, may_resize) \
1089 hashmap_base_put_boldly(HASHMAP_BASE(h), idx, swap, may_resize)
1090
1091/*
1092 * Returns 0 if resize is not needed.
f131770b 1093 * 1 if successfully resized.
89439d4f
MS
1094 * -ENOMEM on allocation failure.
1095 */
1096static int resize_buckets(HashmapBase *h, unsigned entries_add) {
1097 struct swap_entries swap;
1a39bc8c 1098 void *new_storage;
89439d4f
MS
1099 dib_raw_t *old_dibs, *new_dibs;
1100 const struct hashmap_type_info *hi;
1101 unsigned idx, optimal_idx;
1102 unsigned old_n_buckets, new_n_buckets, n_rehashed, new_n_entries;
1103 uint8_t new_shift;
1104 bool rehash_next;
45fa9e29
LP
1105
1106 assert(h);
1107
89439d4f
MS
1108 hi = &hashmap_type_info[h->type];
1109 new_n_entries = n_entries(h) + entries_add;
e4c691b5
MS
1110
1111 /* overflow? */
89439d4f 1112 if (_unlikely_(new_n_entries < entries_add))
e4c691b5
MS
1113 return -ENOMEM;
1114
89439d4f
MS
1115 /* For direct storage we allow 100% load, because it's tiny. */
1116 if (!h->has_indirect && new_n_entries <= hi->n_direct_buckets)
9700d698 1117 return 0;
45fa9e29 1118
89439d4f
MS
1119 /*
1120 * Load factor = n/m = 1 - (1/INV_KEEP_FREE).
1121 * From it follows: m = n + n/(INV_KEEP_FREE - 1)
1122 */
1123 new_n_buckets = new_n_entries + new_n_entries / (INV_KEEP_FREE - 1);
1124 /* overflow? */
1125 if (_unlikely_(new_n_buckets < new_n_entries))
9700d698 1126 return -ENOMEM;
45fa9e29 1127
89439d4f
MS
1128 if (_unlikely_(new_n_buckets > UINT_MAX / (hi->entry_size + sizeof(dib_raw_t))))
1129 return -ENOMEM;
a3b6fafe 1130
89439d4f 1131 old_n_buckets = n_buckets(h);
45fa9e29 1132
89439d4f
MS
1133 if (_likely_(new_n_buckets <= old_n_buckets))
1134 return 0;
45fa9e29 1135
89439d4f
MS
1136 new_shift = log2u_round_up(MAX(
1137 new_n_buckets * (hi->entry_size + sizeof(dib_raw_t)),
1138 2 * sizeof(struct direct_storage)));
45fa9e29 1139
89439d4f
MS
1140 /* Realloc storage (buckets and DIB array). */
1141 new_storage = realloc(h->has_indirect ? h->indirect.storage : NULL,
1142 1U << new_shift);
1143 if (!new_storage)
1144 return -ENOMEM;
45fa9e29 1145
89439d4f
MS
1146 /* Must upgrade direct to indirect storage. */
1147 if (!h->has_indirect) {
1148 memcpy(new_storage, h->direct.storage,
1149 old_n_buckets * (hi->entry_size + sizeof(dib_raw_t)));
1150 h->indirect.n_entries = h->n_direct_entries;
1151 h->indirect.idx_lowest_entry = 0;
1152 h->n_direct_entries = 0;
1153 }
45fa9e29 1154
89439d4f
MS
1155 /* Get a new hash key. If we've just upgraded to indirect storage,
1156 * allow reusing a previously generated key. It's still a different key
1157 * from the shared one that we used for direct storage. */
1158 get_hash_key(h->indirect.hash_key, !h->has_indirect);
1159
1160 h->has_indirect = true;
1161 h->indirect.storage = new_storage;
1162 h->indirect.n_buckets = (1U << new_shift) /
1163 (hi->entry_size + sizeof(dib_raw_t));
1164
1a39bc8c 1165 old_dibs = (dib_raw_t*)((uint8_t*) new_storage + hi->entry_size * old_n_buckets);
89439d4f
MS
1166 new_dibs = dib_raw_ptr(h);
1167
1168 /*
1169 * Move the DIB array to the new place, replacing valid DIB values with
1170 * DIB_RAW_REHASH to indicate all of the used buckets need rehashing.
1171 * Note: Overlap is not possible, because we have at least doubled the
1172 * number of buckets and dib_raw_t is smaller than any entry type.
1173 */
1174 for (idx = 0; idx < old_n_buckets; idx++) {
1175 assert(old_dibs[idx] != DIB_RAW_REHASH);
1176 new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE
1177 : DIB_RAW_REHASH;
45fa9e29
LP
1178 }
1179
89439d4f 1180 /* Zero the area of newly added entries (including the old DIB area) */
eccaf899 1181 memzero(bucket_at(h, old_n_buckets),
89439d4f 1182 (n_buckets(h) - old_n_buckets) * hi->entry_size);
45fa9e29 1183
89439d4f
MS
1184 /* The upper half of the new DIB array needs initialization */
1185 memset(&new_dibs[old_n_buckets], DIB_RAW_INIT,
1186 (n_buckets(h) - old_n_buckets) * sizeof(dib_raw_t));
9bf3b535 1187
89439d4f
MS
1188 /* Rehash entries that need it */
1189 n_rehashed = 0;
1190 for (idx = 0; idx < old_n_buckets; idx++) {
1191 if (new_dibs[idx] != DIB_RAW_REHASH)
1192 continue;
45fa9e29 1193
89439d4f 1194 optimal_idx = bucket_hash(h, bucket_at(h, idx)->key);
45fa9e29 1195
89439d4f
MS
1196 /*
1197 * Not much to do if by luck the entry hashes to its current
1198 * location. Just set its DIB.
1199 */
1200 if (optimal_idx == idx) {
1201 new_dibs[idx] = 0;
1202 n_rehashed++;
1203 continue;
1204 }
1205
1206 new_dibs[idx] = DIB_RAW_FREE;
1207 bucket_move_entry(h, &swap, idx, IDX_PUT);
1208 /* bucket_move_entry does not clear the source */
eccaf899 1209 memzero(bucket_at(h, idx), hi->entry_size);
89439d4f
MS
1210
1211 do {
1212 /*
1213 * Find the new bucket for the current entry. This may make
1214 * another entry homeless and load it into IDX_PUT.
1215 */
1216 rehash_next = hashmap_put_robin_hood(h, optimal_idx, &swap);
1217 n_rehashed++;
1218
1219 /* Did the current entry displace another one? */
1220 if (rehash_next)
1221 optimal_idx = bucket_hash(h, bucket_at_swap(&swap, IDX_PUT)->p.b.key);
1222 } while (rehash_next);
1223 }
60918275 1224
89439d4f 1225 assert(n_rehashed == n_entries(h));
60918275 1226
89439d4f
MS
1227 return 1;
1228}
45fa9e29 1229
89439d4f
MS
1230/*
1231 * Finds an entry with a matching key
1232 * Returns: index of the found entry, or IDX_NIL if not found.
1233 */
1234static unsigned base_bucket_scan(HashmapBase *h, unsigned idx, const void *key) {
1235 struct hashmap_base_entry *e;
1236 unsigned dib, distance;
1237 dib_raw_t *dibs = dib_raw_ptr(h);
39c2a6f1 1238
89439d4f 1239 assert(idx < n_buckets(h));
60918275 1240
89439d4f
MS
1241 for (distance = 0; ; distance++) {
1242 if (dibs[idx] == DIB_RAW_FREE)
1243 return IDX_NIL;
60918275 1244
89439d4f 1245 dib = bucket_calculate_dib(h, idx, dibs[idx]);
60918275 1246
89439d4f
MS
1247 if (dib < distance)
1248 return IDX_NIL;
1249 if (dib == distance) {
1250 e = bucket_at(h, idx);
1251 if (h->hash_ops->compare(e->key, key) == 0)
1252 return idx;
1253 }
1254
1255 idx = next_idx(h, idx);
1256 }
60918275 1257}
89439d4f 1258#define bucket_scan(h, idx, key) base_bucket_scan(HASHMAP_BASE(h), idx, key)
60918275 1259
923041cb 1260int hashmap_put(Hashmap *h, const void *key, void *value) {
89439d4f
MS
1261 struct swap_entries swap;
1262 struct plain_hashmap_entry *e;
1263 unsigned hash, idx;
923041cb
MS
1264
1265 assert(h);
1266
1267 hash = bucket_hash(h, key);
89439d4f
MS
1268 idx = bucket_scan(h, hash, key);
1269 if (idx != IDX_NIL) {
1270 e = plain_bucket_at(h, idx);
923041cb
MS
1271 if (e->value == value)
1272 return 0;
1273 return -EEXIST;
1274 }
1275
89439d4f
MS
1276 e = &bucket_at_swap(&swap, IDX_PUT)->p;
1277 e->b.key = key;
1278 e->value = value;
1279 return hashmap_put_boldly(h, hash, &swap, true);
1280}
1281
1282int set_put(Set *s, const void *key) {
1283 struct swap_entries swap;
1284 struct hashmap_base_entry *e;
1285 unsigned hash, idx;
1286
1287 assert(s);
1288
1289 hash = bucket_hash(s, key);
1290 idx = bucket_scan(s, hash, key);
1291 if (idx != IDX_NIL)
1292 return 0;
1293
1294 e = &bucket_at_swap(&swap, IDX_PUT)->p.b;
1295 e->key = key;
1296 return hashmap_put_boldly(s, hash, &swap, true);
923041cb
MS
1297}
1298
3158713e 1299int hashmap_replace(Hashmap *h, const void *key, void *value) {
89439d4f
MS
1300 struct swap_entries swap;
1301 struct plain_hashmap_entry *e;
1302 unsigned hash, idx;
3158713e
LP
1303
1304 assert(h);
1305
a3b6fafe 1306 hash = bucket_hash(h, key);
89439d4f
MS
1307 idx = bucket_scan(h, hash, key);
1308 if (idx != IDX_NIL) {
1309 e = plain_bucket_at(h, idx);
349cc4a5 1310#if ENABLE_DEBUG_HASHMAP
89439d4f
MS
1311 /* Although the key is equal, the key pointer may have changed,
1312 * and this would break our assumption for iterating. So count
1313 * this operation as incompatible with iteration. */
1314 if (e->b.key != key) {
1315 h->b.debug.put_count++;
1316 h->b.debug.rem_count++;
1317 h->b.debug.last_rem_idx = idx;
1318 }
1319#endif
1320 e->b.key = key;
3158713e 1321 e->value = value;
84dcca75
VC
1322 hashmap_set_dirty(h);
1323
3158713e
LP
1324 return 0;
1325 }
1326
89439d4f
MS
1327 e = &bucket_at_swap(&swap, IDX_PUT)->p;
1328 e->b.key = key;
1329 e->value = value;
1330 return hashmap_put_boldly(h, hash, &swap, true);
3158713e
LP
1331}
1332
d99ae53a 1333int hashmap_update(Hashmap *h, const void *key, void *value) {
89439d4f
MS
1334 struct plain_hashmap_entry *e;
1335 unsigned hash, idx;
d99ae53a
LP
1336
1337 assert(h);
1338
a3b6fafe 1339 hash = bucket_hash(h, key);
89439d4f
MS
1340 idx = bucket_scan(h, hash, key);
1341 if (idx == IDX_NIL)
d99ae53a
LP
1342 return -ENOENT;
1343
89439d4f 1344 e = plain_bucket_at(h, idx);
d99ae53a 1345 e->value = value;
84dcca75
VC
1346 hashmap_set_dirty(h);
1347
d99ae53a
LP
1348 return 0;
1349}
1350
89439d4f
MS
1351void *internal_hashmap_get(HashmapBase *h, const void *key) {
1352 struct hashmap_base_entry *e;
1353 unsigned hash, idx;
60918275
LP
1354
1355 if (!h)
1356 return NULL;
1357
a3b6fafe 1358 hash = bucket_hash(h, key);
89439d4f
MS
1359 idx = bucket_scan(h, hash, key);
1360 if (idx == IDX_NIL)
60918275
LP
1361 return NULL;
1362
89439d4f
MS
1363 e = bucket_at(h, idx);
1364 return entry_value(h, e);
60918275
LP
1365}
1366
89439d4f
MS
1367void *hashmap_get2(Hashmap *h, const void *key, void **key2) {
1368 struct plain_hashmap_entry *e;
1369 unsigned hash, idx;
d99ae53a
LP
1370
1371 if (!h)
1372 return NULL;
1373
a3b6fafe 1374 hash = bucket_hash(h, key);
89439d4f
MS
1375 idx = bucket_scan(h, hash, key);
1376 if (idx == IDX_NIL)
d99ae53a
LP
1377 return NULL;
1378
89439d4f 1379 e = plain_bucket_at(h, idx);
d99ae53a 1380 if (key2)
89439d4f 1381 *key2 = (void*) e->b.key;
d99ae53a
LP
1382
1383 return e->value;
1384}
1385
89439d4f 1386bool internal_hashmap_contains(HashmapBase *h, const void *key) {
96342de6 1387 unsigned hash;
96342de6
LN
1388
1389 if (!h)
1390 return false;
1391
a3b6fafe 1392 hash = bucket_hash(h, key);
89439d4f 1393 return bucket_scan(h, hash, key) != IDX_NIL;
96342de6
LN
1394}
1395
89439d4f
MS
1396void *internal_hashmap_remove(HashmapBase *h, const void *key) {
1397 struct hashmap_base_entry *e;
1398 unsigned hash, idx;
60918275
LP
1399 void *data;
1400
1401 if (!h)
1402 return NULL;
1403
a3b6fafe 1404 hash = bucket_hash(h, key);
89439d4f
MS
1405 idx = bucket_scan(h, hash, key);
1406 if (idx == IDX_NIL)
60918275
LP
1407 return NULL;
1408
89439d4f
MS
1409 e = bucket_at(h, idx);
1410 data = entry_value(h, e);
1411 remove_entry(h, idx);
60918275
LP
1412
1413 return data;
1414}
1415
89439d4f
MS
1416void *hashmap_remove2(Hashmap *h, const void *key, void **rkey) {
1417 struct plain_hashmap_entry *e;
1418 unsigned hash, idx;
c582a3b3
LP
1419 void *data;
1420
1421 if (!h) {
1422 if (rkey)
1423 *rkey = NULL;
1424 return NULL;
1425 }
1426
1427 hash = bucket_hash(h, key);
89439d4f
MS
1428 idx = bucket_scan(h, hash, key);
1429 if (idx == IDX_NIL) {
c582a3b3
LP
1430 if (rkey)
1431 *rkey = NULL;
1432 return NULL;
1433 }
1434
89439d4f 1435 e = plain_bucket_at(h, idx);
c582a3b3
LP
1436 data = e->value;
1437 if (rkey)
89439d4f 1438 *rkey = (void*) e->b.key;
c582a3b3 1439
89439d4f 1440 remove_entry(h, idx);
c582a3b3
LP
1441
1442 return data;
1443}
1444
101d8e63 1445int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) {
89439d4f
MS
1446 struct swap_entries swap;
1447 struct plain_hashmap_entry *e;
1448 unsigned old_hash, new_hash, idx;
101d8e63
LP
1449
1450 if (!h)
1451 return -ENOENT;
1452
a3b6fafe 1453 old_hash = bucket_hash(h, old_key);
89439d4f
MS
1454 idx = bucket_scan(h, old_hash, old_key);
1455 if (idx == IDX_NIL)
101d8e63
LP
1456 return -ENOENT;
1457
a3b6fafe 1458 new_hash = bucket_hash(h, new_key);
89439d4f 1459 if (bucket_scan(h, new_hash, new_key) != IDX_NIL)
101d8e63
LP
1460 return -EEXIST;
1461
89439d4f 1462 remove_entry(h, idx);
101d8e63 1463
89439d4f
MS
1464 e = &bucket_at_swap(&swap, IDX_PUT)->p;
1465 e->b.key = new_key;
101d8e63 1466 e->value = value;
89439d4f
MS
1467 assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1);
1468
1469 return 0;
1470}
1471
1472int set_remove_and_put(Set *s, const void *old_key, const void *new_key) {
1473 struct swap_entries swap;
1474 struct hashmap_base_entry *e;
1475 unsigned old_hash, new_hash, idx;
101d8e63 1476
89439d4f
MS
1477 if (!s)
1478 return -ENOENT;
1479
1480 old_hash = bucket_hash(s, old_key);
1481 idx = bucket_scan(s, old_hash, old_key);
1482 if (idx == IDX_NIL)
1483 return -ENOENT;
1484
1485 new_hash = bucket_hash(s, new_key);
1486 if (bucket_scan(s, new_hash, new_key) != IDX_NIL)
1487 return -EEXIST;
1488
1489 remove_entry(s, idx);
1490
1491 e = &bucket_at_swap(&swap, IDX_PUT)->p.b;
1492 e->key = new_key;
1493 assert_se(hashmap_put_boldly(s, new_hash, &swap, false) == 1);
101d8e63
LP
1494
1495 return 0;
1496}
1497
8fe914ec 1498int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) {
89439d4f
MS
1499 struct swap_entries swap;
1500 struct plain_hashmap_entry *e;
1501 unsigned old_hash, new_hash, idx_old, idx_new;
8fe914ec
LP
1502
1503 if (!h)
1504 return -ENOENT;
1505
a3b6fafe 1506 old_hash = bucket_hash(h, old_key);
89439d4f
MS
1507 idx_old = bucket_scan(h, old_hash, old_key);
1508 if (idx_old == IDX_NIL)
8fe914ec
LP
1509 return -ENOENT;
1510
89439d4f 1511 old_key = bucket_at(HASHMAP_BASE(h), idx_old)->key;
8fe914ec 1512
89439d4f
MS
1513 new_hash = bucket_hash(h, new_key);
1514 idx_new = bucket_scan(h, new_hash, new_key);
1515 if (idx_new != IDX_NIL)
1516 if (idx_old != idx_new) {
1517 remove_entry(h, idx_new);
1518 /* Compensate for a possible backward shift. */
1519 if (old_key != bucket_at(HASHMAP_BASE(h), idx_old)->key)
1520 idx_old = prev_idx(HASHMAP_BASE(h), idx_old);
1521 assert(old_key == bucket_at(HASHMAP_BASE(h), idx_old)->key);
1522 }
1523
1524 remove_entry(h, idx_old);
1525
1526 e = &bucket_at_swap(&swap, IDX_PUT)->p;
1527 e->b.key = new_key;
8fe914ec 1528 e->value = value;
89439d4f 1529 assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1);
8fe914ec
LP
1530
1531 return 0;
1532}
1533
89439d4f
MS
1534void *hashmap_remove_value(Hashmap *h, const void *key, void *value) {
1535 struct plain_hashmap_entry *e;
1536 unsigned hash, idx;
3158713e
LP
1537
1538 if (!h)
1539 return NULL;
1540
a3b6fafe 1541 hash = bucket_hash(h, key);
89439d4f
MS
1542 idx = bucket_scan(h, hash, key);
1543 if (idx == IDX_NIL)
3158713e
LP
1544 return NULL;
1545
89439d4f 1546 e = plain_bucket_at(h, idx);
3158713e
LP
1547 if (e->value != value)
1548 return NULL;
1549
89439d4f 1550 remove_entry(h, idx);
3158713e
LP
1551
1552 return value;
1553}
1554
89439d4f
MS
1555static unsigned find_first_entry(HashmapBase *h) {
1556 Iterator i = ITERATOR_FIRST;
60918275 1557
89439d4f
MS
1558 if (!h || !n_entries(h))
1559 return IDX_NIL;
60918275 1560
89439d4f 1561 return hashmap_iterate_entry(h, &i);
60918275
LP
1562}
1563
89439d4f
MS
1564void *internal_hashmap_first(HashmapBase *h) {
1565 unsigned idx;
60918275 1566
89439d4f
MS
1567 idx = find_first_entry(h);
1568 if (idx == IDX_NIL)
60918275
LP
1569 return NULL;
1570
89439d4f 1571 return entry_value(h, bucket_at(h, idx));
60918275
LP
1572}
1573
89439d4f
MS
1574void *internal_hashmap_first_key(HashmapBase *h) {
1575 struct hashmap_base_entry *e;
1576 unsigned idx;
2e4a6ff4 1577
89439d4f
MS
1578 idx = find_first_entry(h);
1579 if (idx == IDX_NIL)
2e4a6ff4
LP
1580 return NULL;
1581
89439d4f
MS
1582 e = bucket_at(h, idx);
1583 return (void*) e->key;
2e4a6ff4
LP
1584}
1585
89439d4f
MS
1586void *internal_hashmap_steal_first(HashmapBase *h) {
1587 struct hashmap_base_entry *e;
60918275 1588 void *data;
89439d4f 1589 unsigned idx;
60918275 1590
89439d4f
MS
1591 idx = find_first_entry(h);
1592 if (idx == IDX_NIL)
60918275
LP
1593 return NULL;
1594
89439d4f
MS
1595 e = bucket_at(h, idx);
1596 data = entry_value(h, e);
1597 remove_entry(h, idx);
60918275
LP
1598
1599 return data;
1600}
1601
89439d4f
MS
1602void *internal_hashmap_steal_first_key(HashmapBase *h) {
1603 struct hashmap_base_entry *e;
22be093f 1604 void *key;
89439d4f 1605 unsigned idx;
22be093f 1606
89439d4f
MS
1607 idx = find_first_entry(h);
1608 if (idx == IDX_NIL)
22be093f
LP
1609 return NULL;
1610
89439d4f
MS
1611 e = bucket_at(h, idx);
1612 key = (void*) e->key;
1613 remove_entry(h, idx);
22be093f
LP
1614
1615 return key;
1616}
1617
89439d4f 1618unsigned internal_hashmap_size(HashmapBase *h) {
60918275
LP
1619
1620 if (!h)
1621 return 0;
1622
89439d4f 1623 return n_entries(h);
60918275
LP
1624}
1625
89439d4f 1626unsigned internal_hashmap_buckets(HashmapBase *h) {
45fa9e29
LP
1627
1628 if (!h)
1629 return 0;
1630
89439d4f 1631 return n_buckets(h);
45fa9e29
LP
1632}
1633
89439d4f
MS
1634int internal_hashmap_merge(Hashmap *h, Hashmap *other) {
1635 Iterator i;
1636 unsigned idx;
60918275 1637
89439d4f 1638 assert(h);
60918275 1639
89439d4f
MS
1640 HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) {
1641 struct plain_hashmap_entry *pe = plain_bucket_at(other, idx);
1642 int r;
91cdde8a 1643
89439d4f
MS
1644 r = hashmap_put(h, pe->b.key, pe->value);
1645 if (r < 0 && r != -EEXIST)
1646 return r;
1647 }
91cdde8a 1648
89439d4f
MS
1649 return 0;
1650}
91cdde8a 1651
89439d4f
MS
1652int set_merge(Set *s, Set *other) {
1653 Iterator i;
1654 unsigned idx;
91cdde8a 1655
89439d4f
MS
1656 assert(s);
1657
1658 HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) {
1659 struct set_entry *se = set_bucket_at(other, idx);
91cdde8a
LP
1660 int r;
1661
89439d4f
MS
1662 r = set_put(s, se->b.key);
1663 if (r < 0)
a3b6fafe 1664 return r;
91cdde8a
LP
1665 }
1666
1667 return 0;
1668}
1669
89439d4f 1670int internal_hashmap_reserve(HashmapBase *h, unsigned entries_add) {
e4c691b5
MS
1671 int r;
1672
1673 assert(h);
1674
1675 r = resize_buckets(h, entries_add);
1676 if (r < 0)
1677 return r;
1678
1679 return 0;
1680}
1681
89439d4f
MS
1682/*
1683 * The same as hashmap_merge(), but every new item from other is moved to h.
1684 * Keys already in h are skipped and stay in other.
1685 * Returns: 0 on success.
1686 * -ENOMEM on alloc failure, in which case no move has been done.
1687 */
1688int internal_hashmap_move(HashmapBase *h, HashmapBase *other) {
1689 struct swap_entries swap;
1690 struct hashmap_base_entry *e, *n;
1691 Iterator i;
1692 unsigned idx;
1693 int r;
101d8e63
LP
1694
1695 assert(h);
1696
101d8e63 1697 if (!other)
7ad63f57 1698 return 0;
101d8e63 1699
89439d4f
MS
1700 assert(other->type == h->type);
1701
1702 /*
1703 * This reserves buckets for the worst case, where none of other's
1704 * entries are yet present in h. This is preferable to risking
1705 * an allocation failure in the middle of the moving and having to
1706 * rollback or return a partial result.
1707 */
1708 r = resize_buckets(h, n_entries(other));
1709 if (r < 0)
1710 return r;
101d8e63 1711
89439d4f
MS
1712 HASHMAP_FOREACH_IDX(idx, other, i) {
1713 unsigned h_hash;
101d8e63 1714
89439d4f 1715 e = bucket_at(other, idx);
a3b6fafe 1716 h_hash = bucket_hash(h, e->key);
89439d4f 1717 if (bucket_scan(h, h_hash, e->key) != IDX_NIL)
101d8e63
LP
1718 continue;
1719
89439d4f
MS
1720 n = &bucket_at_swap(&swap, IDX_PUT)->p.b;
1721 n->key = e->key;
1722 if (h->type != HASHMAP_TYPE_SET)
1723 ((struct plain_hashmap_entry*) n)->value =
1724 ((struct plain_hashmap_entry*) e)->value;
1725 assert_se(hashmap_put_boldly(h, h_hash, &swap, false) == 1);
1726
1727 remove_entry(other, idx);
101d8e63 1728 }
7ad63f57
MS
1729
1730 return 0;
101d8e63
LP
1731}
1732
89439d4f
MS
1733int internal_hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
1734 struct swap_entries swap;
1735 unsigned h_hash, other_hash, idx;
1736 struct hashmap_base_entry *e, *n;
1737 int r;
101d8e63 1738
101d8e63
LP
1739 assert(h);
1740
a3b6fafe 1741 h_hash = bucket_hash(h, key);
89439d4f 1742 if (bucket_scan(h, h_hash, key) != IDX_NIL)
101d8e63
LP
1743 return -EEXIST;
1744
bf3d3e2b
MS
1745 if (!other)
1746 return -ENOENT;
1747
89439d4f
MS
1748 assert(other->type == h->type);
1749
a3b6fafe 1750 other_hash = bucket_hash(other, key);
89439d4f
MS
1751 idx = bucket_scan(other, other_hash, key);
1752 if (idx == IDX_NIL)
101d8e63
LP
1753 return -ENOENT;
1754
89439d4f
MS
1755 e = bucket_at(other, idx);
1756
1757 n = &bucket_at_swap(&swap, IDX_PUT)->p.b;
1758 n->key = e->key;
1759 if (h->type != HASHMAP_TYPE_SET)
1760 ((struct plain_hashmap_entry*) n)->value =
1761 ((struct plain_hashmap_entry*) e)->value;
1762 r = hashmap_put_boldly(h, h_hash, &swap, true);
1763 if (r < 0)
1764 return r;
101d8e63 1765
89439d4f 1766 remove_entry(other, idx);
101d8e63
LP
1767 return 0;
1768}
1769
89439d4f
MS
1770HashmapBase *internal_hashmap_copy(HashmapBase *h) {
1771 HashmapBase *copy;
1772 int r;
91cdde8a
LP
1773
1774 assert(h);
1775
89439d4f 1776 copy = hashmap_base_new(h->hash_ops, h->type HASHMAP_DEBUG_SRC_ARGS);
45fa9e29 1777 if (!copy)
91cdde8a
LP
1778 return NULL;
1779
89439d4f
MS
1780 switch (h->type) {
1781 case HASHMAP_TYPE_PLAIN:
1782 case HASHMAP_TYPE_ORDERED:
1783 r = hashmap_merge((Hashmap*)copy, (Hashmap*)h);
1784 break;
1785 case HASHMAP_TYPE_SET:
1786 r = set_merge((Set*)copy, (Set*)h);
1787 break;
1788 default:
1789 assert_not_reached("Unknown hashmap type");
1790 }
1791
1792 if (r < 0) {
1793 internal_hashmap_free(copy);
91cdde8a
LP
1794 return NULL;
1795 }
1796
1797 return copy;
1798}
db1413d7 1799
89439d4f 1800char **internal_hashmap_get_strv(HashmapBase *h) {
db1413d7 1801 char **sv;
89439d4f
MS
1802 Iterator i;
1803 unsigned idx, n;
db1413d7 1804
89439d4f 1805 sv = new(char*, n_entries(h)+1);
729e3769 1806 if (!sv)
db1413d7
KS
1807 return NULL;
1808
1809 n = 0;
89439d4f
MS
1810 HASHMAP_FOREACH_IDX(idx, h, i)
1811 sv[n++] = entry_value(h, bucket_at(h, idx));
db1413d7
KS
1812 sv[n] = NULL;
1813
1814 return sv;
1815}
3c1668da 1816
89439d4f
MS
1817void *ordered_hashmap_next(OrderedHashmap *h, const void *key) {
1818 struct ordered_hashmap_entry *e;
1819 unsigned hash, idx;
3c1668da 1820
3c1668da
LP
1821 if (!h)
1822 return NULL;
1823
a3b6fafe 1824 hash = bucket_hash(h, key);
89439d4f
MS
1825 idx = bucket_scan(h, hash, key);
1826 if (idx == IDX_NIL)
3c1668da
LP
1827 return NULL;
1828
89439d4f
MS
1829 e = ordered_bucket_at(h, idx);
1830 if (e->iterate_next == IDX_NIL)
3c1668da 1831 return NULL;
89439d4f
MS
1832 return ordered_bucket_at(h, e->iterate_next)->p.value;
1833}
3c1668da 1834
89439d4f
MS
1835int set_consume(Set *s, void *value) {
1836 int r;
1837
d97c5aea
LP
1838 assert(s);
1839 assert(value);
1840
89439d4f 1841 r = set_put(s, value);
575ccc1b 1842 if (r <= 0)
89439d4f
MS
1843 free(value);
1844
1845 return r;
1846}
1847
1848int set_put_strdup(Set *s, const char *p) {
1849 char *c;
89439d4f
MS
1850
1851 assert(s);
1852 assert(p);
1853
454f0f86
LP
1854 if (set_contains(s, (char*) p))
1855 return 0;
1856
89439d4f
MS
1857 c = strdup(p);
1858 if (!c)
1859 return -ENOMEM;
1860
454f0f86 1861 return set_consume(s, c);
89439d4f
MS
1862}
1863
1864int set_put_strdupv(Set *s, char **l) {
1865 int n = 0, r;
1866 char **i;
1867
d97c5aea
LP
1868 assert(s);
1869
89439d4f
MS
1870 STRV_FOREACH(i, l) {
1871 r = set_put_strdup(s, *i);
1872 if (r < 0)
1873 return r;
1874
1875 n += r;
1876 }
1877
1878 return n;
3c1668da 1879}
d97c5aea
LP
1880
1881int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) {
1882 const char *p = v;
1883 int r;
1884
1885 assert(s);
1886 assert(v);
1887
1888 for (;;) {
1889 char *word;
1890
1891 r = extract_first_word(&p, &word, separators, flags);
1892 if (r <= 0)
1893 return r;
1894
1895 r = set_consume(s, word);
1896 if (r < 0)
1897 return r;
1898 }
1899}
45ea84d8
VC
1900
1901/* expand the cachemem if needed, return true if newly (re)activated. */
1902static int cachemem_maintain(CacheMem *mem, unsigned size) {
1903 int r = false;
1904
1905 assert(mem);
1906
1907 if (!GREEDY_REALLOC(mem->ptr, mem->n_allocated, size)) {
1908 if (size > 0)
1909 return -ENOMEM;
1910 }
1911
1912 if (!mem->active)
1913 mem->active = r = true;
1914
1915 return r;
1916}
1917
1918int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries) {
1919 bool sync_keys = false, sync_values = false;
1920 unsigned size;
1921 int r;
1922
1923 assert(cache);
1924 assert(cache->hashmap);
1925
1926 size = n_entries(cache->hashmap);
1927
1928 if (res_keys) {
1929 r = cachemem_maintain(&cache->keys, size);
1930 if (r < 0)
1931 return r;
1932
1933 sync_keys = r;
1934 } else
1935 cache->keys.active = false;
1936
1937 if (res_values) {
1938 r = cachemem_maintain(&cache->values, size);
1939 if (r < 0)
1940 return r;
1941
1942 sync_values = r;
1943 } else
1944 cache->values.active = false;
1945
1946 if (cache->hashmap->dirty) {
1947 if (cache->keys.active)
1948 sync_keys = true;
1949 if (cache->values.active)
1950 sync_values = true;
1951
1952 cache->hashmap->dirty = false;
1953 }
1954
1955 if (sync_keys || sync_values) {
1956 unsigned i, idx;
1957 Iterator iter;
1958
1959 i = 0;
1960 HASHMAP_FOREACH_IDX(idx, cache->hashmap, iter) {
1961 struct hashmap_base_entry *e;
1962
1963 e = bucket_at(cache->hashmap, idx);
1964
1965 if (sync_keys)
1966 cache->keys.ptr[i] = e->key;
1967 if (sync_values)
1968 cache->values.ptr[i] = entry_value(cache->hashmap, e);
1969 i++;
1970 }
1971 }
1972
1973 if (res_keys)
1974 *res_keys = cache->keys.ptr;
1975 if (res_values)
1976 *res_values = cache->values.ptr;
1977 if (res_n_entries)
1978 *res_n_entries = size;
1979
1980 return 0;
1981}
1982
1983IteratedCache *iterated_cache_free(IteratedCache *cache) {
1984 if (cache) {
1985 free(cache->keys.ptr);
1986 free(cache->values.ptr);
1987 free(cache);
1988 }
1989
1990 return NULL;
1991}