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