• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 29709461870

19 Jul 2026 07:23PM UTC coverage: 72.889% (-0.09%) from 72.979%
29709461870

push

github

web-flow
Manage dlopen notes at beginning of execution, and downgrade priorities in shared libraries (#43060)

184 of 218 new or added lines in 86 files covered. (84.4%)

1195 existing lines in 53 files now uncovered.

345898 of 474552 relevant lines covered (72.89%)

1349499.83 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.69
/src/basic/hashmap.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <fnmatch.h>
4
#include <pthread.h>
5
#include <unistd.h>
6
#if HAVE_VALGRIND_VALGRIND_H
7
#  include <valgrind/valgrind.h>
8
#endif
9

10
#include "alloc-util.h"
11
#include "extract-word.h"
12
#include "hashmap.h"
13
#include "log.h"
14
#include "logarithm.h"
15
#include "memory-util.h"
16
#include "mempool.h"
17
#include "process-util.h"
18
#include "random-util.h"
19
#include "set.h"
20
#include "siphash24.h"
21
#include "sort-util.h"
22
#include "string-util.h"
23
#include "strv.h"
24

25
#if ENABLE_DEBUG_HASHMAP
26
#include "list.h"
27
#endif
28

29
/*
30
 * Implementation of hashmaps.
31
 * Addressing: open
32
 *   - uses less RAM compared to closed addressing (chaining), because
33
 *     our entries are small (especially in Sets, which tend to contain
34
 *     the majority of entries in systemd).
35
 * Collision resolution: Robin Hood
36
 *   - tends to equalize displacement of entries from their optimal buckets.
37
 * Probe sequence: linear
38
 *   - though theoretically worse than random probing/uniform hashing/double
39
 *     hashing, it is good for cache locality.
40
 *
41
 * References:
42
 * Celis, P. 1986. Robin Hood Hashing.
43
 * Ph.D. Dissertation. University of Waterloo, Waterloo, Ont., Canada, Canada.
44
 * https://cs.uwaterloo.ca/research/tr/1986/CS-86-14.pdf
45
 * - The results are derived for random probing. Suggests deletion with
46
 *   tombstones and two mean-centered search methods. None of that works
47
 *   well for linear probing.
48
 *
49
 * Janson, S. 2005. Individual displacements for linear probing hashing with different insertion policies.
50
 * ACM Trans. Algorithms 1, 2 (October 2005), 177-213.
51
 * DOI=10.1145/1103963.1103964 http://doi.acm.org/10.1145/1103963.1103964
52
 * http://www.math.uu.se/~svante/papers/sj157.pdf
53
 * - Applies to Robin Hood with linear probing. Contains remarks on
54
 *   the unsuitability of mean-centered search with linear probing.
55
 *
56
 * Viola, A. 2005. Exact distribution of individual displacements in linear probing hashing.
57
 * ACM Trans. Algorithms 1, 2 (October 2005), 214-242.
58
 * DOI=10.1145/1103963.1103965 http://doi.acm.org/10.1145/1103963.1103965
59
 * - Similar to Janson. Note that Viola writes about C_{m,n} (number of probes
60
 *   in a successful search), and Janson writes about displacement. C = d + 1.
61
 *
62
 * Goossaert, E. 2013. Robin Hood hashing: backward shift deletion.
63
 * http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/
64
 * - Explanation of backward shift deletion with pictures.
65
 *
66
 * Khuong, P. 2013. The Other Robin Hood Hashing.
67
 * http://www.pvk.ca/Blog/2013/11/26/the-other-robin-hood-hashing/
68
 * - Short summary of random vs. linear probing, and tombstones vs. backward shift.
69
 */
70

71
/*
72
 * XXX Ideas for improvement:
73
 * For unordered hashmaps, randomize iteration order, similarly to Perl:
74
 * http://blog.booking.com/hardening-perls-hash-function.html
75
 */
76

77
/* INV_KEEP_FREE = 1 / (1 - max_load_factor)
78
 * e.g. 1 / (1 - 0.8) = 5 ... keep one fifth of the buckets free. */
79
#define INV_KEEP_FREE            5U
80

81
/* Fields common to entries of all hashmap/set types */
82
struct hashmap_base_entry {
83
        const void *key;
84
};
85

86
/* Entry types for specific hashmap/set types
87
 * hashmap_base_entry must be at the beginning of each entry struct. */
88

89
struct plain_hashmap_entry {
90
        struct hashmap_base_entry b;
91
        void *value;
92
};
93

94
struct ordered_hashmap_entry {
95
        struct plain_hashmap_entry p;
96
        unsigned iterate_next, iterate_previous;
97
};
98

99
struct set_entry {
100
        struct hashmap_base_entry b;
101
};
102

103
/* In several functions it is advantageous to have the hash table extended
104
 * virtually by a couple of additional buckets. We reserve special index values
105
 * for these "swap" buckets. */
106
#define _IDX_SWAP_BEGIN     (UINT_MAX - 3)
107
#define IDX_PUT             (_IDX_SWAP_BEGIN + 0)
108
#define IDX_TMP             (_IDX_SWAP_BEGIN + 1)
109
#define _IDX_SWAP_END       (_IDX_SWAP_BEGIN + 2)
110

111
#define IDX_FIRST           (UINT_MAX - 1) /* special index for freshly initialized iterators */
112
#define IDX_NIL             UINT_MAX       /* special index value meaning "none" or "end" */
113

114
assert_cc(IDX_FIRST == _IDX_SWAP_END);
115
assert_cc(IDX_FIRST == _IDX_ITERATOR_FIRST);
116

117
/* Storage space for the "swap" buckets.
118
 * All entry types can fit into an ordered_hashmap_entry. */
119
struct swap_entries {
120
        struct ordered_hashmap_entry e[_IDX_SWAP_END - _IDX_SWAP_BEGIN];
121
};
122

123
/* Distance from Initial Bucket */
124
typedef uint8_t dib_raw_t;
125
#define DIB_RAW_OVERFLOW ((dib_raw_t)0xfdU)   /* indicates DIB value is greater than representable */
126
#define DIB_RAW_REHASH   ((dib_raw_t)0xfeU)   /* entry yet to be rehashed during in-place resize */
127
#define DIB_RAW_FREE     ((dib_raw_t)0xffU)   /* a free bucket */
128
#define DIB_RAW_INIT     ((char)DIB_RAW_FREE) /* a byte to memset a DIB store with when initializing */
129

130
#define DIB_FREE UINT_MAX
131

132
#if ENABLE_DEBUG_HASHMAP
133
struct hashmap_debug_info {
134
        LIST_FIELDS(struct hashmap_debug_info, debug_list);
135
        unsigned max_entries;  /* high watermark of n_entries */
136

137
        /* fields to detect modification while iterating */
138
        unsigned put_count;    /* counts puts into the hashmap */
139
        unsigned rem_count;    /* counts removals from hashmap */
140
        unsigned last_rem_idx; /* remembers last removal index */
141
};
142

143
/* Tracks all existing hashmaps. Get at it from gdb. See sd_dump_hashmaps.py */
144
static LIST_HEAD(struct hashmap_debug_info, hashmap_debug_list);
145
static pthread_mutex_t hashmap_debug_list_mutex = PTHREAD_MUTEX_INITIALIZER;
146
#endif
147

148
enum HashmapType {
149
        HASHMAP_TYPE_PLAIN,
150
        HASHMAP_TYPE_ORDERED,
151
        HASHMAP_TYPE_SET,
152
        _HASHMAP_TYPE_MAX
153
};
154

155
struct _packed_ indirect_storage {
156
        void *storage;                     /* where buckets and DIBs are stored */
157
        uint8_t  hash_key[HASH_KEY_SIZE];  /* hash key; changes during resize */
158

159
        unsigned n_entries;                /* number of stored entries */
160
        unsigned n_buckets;                /* number of buckets */
161

162
        unsigned idx_lowest_entry;         /* Index below which all buckets are free.
163
                                              Makes "while (hashmap_steal_first())" loops
164
                                              O(n) instead of O(n^2) for unordered hashmaps. */
165
        uint8_t  _pad[3];                  /* padding for the whole HashmapBase */
166
        /* The bitfields in HashmapBase complete the alignment of the whole thing. */
167
};
168

169
struct direct_storage {
170
        /* This gives us 39 bytes on 64-bit, or 35 bytes on 32-bit.
171
         * That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64-bit,
172
         *              or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32-bit. */
173
        uint8_t storage[sizeof(struct indirect_storage)];
174
};
175

176
#define DIRECT_BUCKETS(entry_t) \
177
        (sizeof(struct direct_storage) / (sizeof(entry_t) + sizeof(dib_raw_t)))
178

179
/* We should be able to store at least one entry directly. */
180
assert_cc(DIRECT_BUCKETS(struct ordered_hashmap_entry) >= 1);
181

182
/* We have 3 bits for n_direct_entries. */
183
assert_cc(DIRECT_BUCKETS(struct set_entry) < (1 << 3));
184

185
/* Hashmaps with directly stored entries all use this shared hash key.
186
 * It's no big deal if the key is guessed, because there can be only
187
 * a handful of directly stored entries in a hashmap. When a hashmap
188
 * outgrows direct storage, it gets its own key for indirect storage. */
189
static uint8_t shared_hash_key[HASH_KEY_SIZE];
190

191
/* Fields that all hashmap/set types must have */
192
struct HashmapBase {
193
        const struct hash_ops *hash_ops;  /* hash and compare ops to use */
194

195
        union _packed_ {
196
                struct indirect_storage indirect; /* if  has_indirect */
197
                struct direct_storage direct;     /* if !has_indirect */
198
        };
199

200
        enum HashmapType type:2;     /* HASHMAP_TYPE_* */
201
        bool has_indirect:1;         /* whether indirect storage is used */
202
        unsigned n_direct_entries:3; /* Number of entries in direct storage.
203
                                      * Only valid if !has_indirect. */
204
        bool from_pool:1;            /* whether was allocated from mempool */
205
        bool dirty:1;                /* whether dirtied since last iterated_cache_get() */
206
        bool cached:1;               /* whether this hashmap is being cached */
207

208
#if ENABLE_DEBUG_HASHMAP
209
        struct hashmap_debug_info debug;
210
#endif
211
};
212

213
/* Specific hash types
214
 * HashmapBase must be at the beginning of each hashmap struct. */
215

216
struct Hashmap {
217
        struct HashmapBase b;
218
};
219

220
struct OrderedHashmap {
221
        struct HashmapBase b;
222
        unsigned iterate_list_head, iterate_list_tail;
223
};
224

225
struct Set {
226
        struct HashmapBase b;
227
};
228

229
typedef struct CacheMem {
230
        const void **ptr;
231
        size_t n_populated;
232
        bool active:1;
233
} CacheMem;
234

235
struct IteratedCache {
236
        HashmapBase *hashmap;
237
        CacheMem keys, values;
238
};
239

240
DEFINE_MEMPOOL(hashmap_pool,         Hashmap,        8);
241
DEFINE_MEMPOOL(ordered_hashmap_pool, OrderedHashmap, 8);
242
/* No need for a separate Set pool */
243
assert_cc(sizeof(Hashmap) == sizeof(Set));
244

245
struct hashmap_type_info {
246
        size_t head_size;
247
        size_t entry_size;
248
        struct mempool *mempool;
249
        unsigned n_direct_buckets;
250
};
251

252
static _used_ const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = {
253
        [HASHMAP_TYPE_PLAIN] = {
254
                .head_size        = sizeof(Hashmap),
255
                .entry_size       = sizeof(struct plain_hashmap_entry),
256
                .mempool          = &hashmap_pool,
257
                .n_direct_buckets = DIRECT_BUCKETS(struct plain_hashmap_entry),
258
        },
259
        [HASHMAP_TYPE_ORDERED] = {
260
                .head_size        = sizeof(OrderedHashmap),
261
                .entry_size       = sizeof(struct ordered_hashmap_entry),
262
                .mempool          = &ordered_hashmap_pool,
263
                .n_direct_buckets = DIRECT_BUCKETS(struct ordered_hashmap_entry),
264
        },
265
        [HASHMAP_TYPE_SET] = {
266
                .head_size        = sizeof(Set),
267
                .entry_size       = sizeof(struct set_entry),
268
                .mempool          = &hashmap_pool,
269
                .n_direct_buckets = DIRECT_BUCKETS(struct set_entry),
270
        },
271
};
272

273
void hashmap_trim_pools(void) {
2✔
274
        int r;
2✔
275

276
        /* The pool is only allocated by the main thread, but the memory can be passed to other
277
         * threads. Let's clean up if we are the main thread and no other threads are live. */
278

279
        /* We build our own is_main_thread() here, which doesn't use C11 TLS based caching of the
280
         * result. That's because valgrind apparently doesn't like TLS to be used from a GCC destructor. */
281
        if (getpid() != gettid())
2✔
282
                return (void) log_debug("Not cleaning up memory pools, not in main thread.");
×
283

284
        r = get_process_threads(0);
2✔
285
        if (r < 0)
2✔
286
                return (void) log_debug_errno(r, "Failed to determine number of threads, not cleaning up memory pools: %m");
×
287
        if (r != 1)
2✔
UNCOV
288
                return (void) log_debug("Not cleaning up memory pools, running in multi-threaded process.");
×
289

290
        mempool_trim(&hashmap_pool);
2✔
291
        mempool_trim(&ordered_hashmap_pool);
2✔
292
}
293

294
#if HAVE_VALGRIND_VALGRIND_H
295
_destructor_ static void cleanup_pools(void) {
296
        /* Be nice to valgrind */
297
        if (RUNNING_ON_VALGRIND)
298
                hashmap_trim_pools();
299
}
300
#endif
301

302
static unsigned n_buckets(HashmapBase *h) {
1,999,884,705✔
303
        assert(h);
1,999,884,705✔
304
        return h->has_indirect ? h->indirect.n_buckets
1,999,884,705✔
305
                               : hashmap_type_info[h->type].n_direct_buckets;
1,999,884,705✔
306
}
307

308
static unsigned n_entries(HashmapBase *h) {
191,333,260✔
309
        assert(h);
191,333,260✔
310
        return h->has_indirect ? h->indirect.n_entries
191,333,260✔
311
                               : h->n_direct_entries;
191,333,260✔
312
}
313

314
static void n_entries_inc(HashmapBase *h) {
48,947,824✔
315
        assert(h);
48,947,824✔
316

317
        if (h->has_indirect)
48,947,824✔
318
                h->indirect.n_entries++;
40,278,294✔
319
        else
320
                h->n_direct_entries++;
8,669,530✔
321
}
48,947,824✔
322

323
static void n_entries_dec(HashmapBase *h) {
44,251,013✔
324
        assert(h);
44,251,013✔
325

326
        if (h->has_indirect)
44,251,013✔
327
                h->indirect.n_entries--;
38,115,641✔
328
        else
329
                h->n_direct_entries--;
6,135,372✔
330
}
44,251,013✔
331

332
static void* storage_ptr(HashmapBase *h) {
1,823,435,968✔
333
        assert(h);
1,823,435,968✔
334
        return h->has_indirect ? h->indirect.storage
1,823,435,968✔
335
                               : h->direct.storage;
1,823,435,968✔
336
}
337

338
static uint8_t* hash_key(HashmapBase *h) {
311,662,301✔
339
        assert(h);
311,662,301✔
340
        return h->has_indirect ? h->indirect.hash_key
311,662,301✔
341
                               : shared_hash_key;
311,662,301✔
342
}
343

344
static unsigned base_bucket_hash(HashmapBase *h, const void *p) {
311,662,301✔
345
        struct siphash state;
311,662,301✔
346
        uint64_t hash;
311,662,301✔
347

348
        assert(h);
311,662,301✔
349

350
        siphash24_init(&state, hash_key(h));
311,662,301✔
351

352
        h->hash_ops->hash(p, &state);
311,662,301✔
353

354
        hash = siphash24_finalize(&state);
311,662,301✔
355

356
        return (unsigned) (hash % n_buckets(h));
311,662,301✔
357
}
358
#define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p)
359

360
static void base_set_dirty(HashmapBase *h) {
98,891,374✔
361
        assert(h);
98,891,374✔
362

363
        h->dirty = true;
98,891,374✔
364
}
98,891,374✔
365
#define hashmap_set_dirty(h) base_set_dirty(HASHMAP_BASE(h))
366

367
static void get_hash_key(uint8_t hash_key[HASH_KEY_SIZE], bool reuse_is_ok) {
3,818,631✔
368
        static uint8_t current[HASH_KEY_SIZE];
3,818,631✔
369
        static bool current_initialized = false;
3,818,631✔
370

371
        /* Returns a hash function key to use. In order to keep things
372
         * fast we will not generate a new key each time we allocate a
373
         * new hash table. Instead, we'll just reuse the most recently
374
         * generated one, except if we never generated one or when we
375
         * are rehashing an entire hash table because we reached a
376
         * fill level */
377

378
        if (!current_initialized || !reuse_is_ok) {
3,818,631✔
379
                random_bytes(current, sizeof(current));
2,323,179✔
380
                current_initialized = true;
2,323,179✔
381
        }
382

383
        memcpy(hash_key, current, sizeof(current));
3,818,631✔
384
}
3,818,631✔
385

386
static struct hashmap_base_entry* bucket_at(HashmapBase *h, unsigned idx) {
1,118,154,908✔
387
        assert(h);
1,118,154,908✔
388
        return CAST_ALIGN_PTR(
1,118,154,908✔
389
                        struct hashmap_base_entry,
390
                        (uint8_t *) storage_ptr(h) + idx * hashmap_type_info[h->type].entry_size);
391
}
392

393
static struct plain_hashmap_entry* plain_bucket_at(Hashmap *h, unsigned idx) {
2,646,557✔
394
        return (struct plain_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
2,646,557✔
395
}
396

397
static struct ordered_hashmap_entry* ordered_bucket_at(OrderedHashmap *h, unsigned idx) {
88,780,844✔
398
        return (struct ordered_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
88,780,844✔
399
}
400

401
static struct set_entry *set_bucket_at(Set *h, unsigned idx) {
4✔
402
        return (struct set_entry*) bucket_at(HASHMAP_BASE(h), idx);
4✔
403
}
404

405
static struct ordered_hashmap_entry* bucket_at_swap(struct swap_entries *swap, unsigned idx) {
451,183,290✔
406
        assert(swap);
451,183,290✔
407
        return &swap->e[idx - _IDX_SWAP_BEGIN];
451,183,290✔
408
}
409

410
/* Returns a pointer to the bucket at index idx.
411
 * Understands real indexes and swap indexes, hence "_virtual". */
412
static struct hashmap_base_entry* bucket_at_virtual(HashmapBase *h, struct swap_entries *swap,
735,228,931✔
413
                                                    unsigned idx) {
414
        if (idx < _IDX_SWAP_BEGIN)
735,228,931✔
415
                return bucket_at(h, idx);
393,232,611✔
416

417
        if (idx < _IDX_SWAP_END)
341,996,320✔
418
                return &bucket_at_swap(swap, idx)->p.b;
341,996,320✔
419

420
        assert_not_reached();
×
421
}
422

423
static dib_raw_t* dib_raw_ptr(HashmapBase *h) {
705,281,060✔
424
        assert(h);
705,281,060✔
425
        return (dib_raw_t*)
1,410,562,120✔
426
                ((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h));
705,281,060✔
427
}
428

429
static unsigned bucket_distance(HashmapBase *h, unsigned idx, unsigned from) {
×
430
        return idx >= from ? idx - from
×
431
                           : n_buckets(h) + idx - from;
×
432
}
433

434
static unsigned bucket_calculate_dib(HashmapBase *h, unsigned idx, dib_raw_t raw_dib) {
437,578,589✔
435
        unsigned initial_bucket;
437,578,589✔
436

437
        if (raw_dib == DIB_RAW_FREE)
437,578,589✔
438
                return DIB_FREE;
439

440
        if (_likely_(raw_dib < DIB_RAW_OVERFLOW))
437,578,589✔
441
                return raw_dib;
437,578,589✔
442

443
        /*
444
         * Having an overflow DIB value is very unlikely. The hash function
445
         * would have to be bad. For example, in a table of size 2^24 filled
446
         * to load factor 0.9 the maximum observed DIB is only about 60.
447
         * In theory (assuming I used Maxima correctly), for an infinite size
448
         * hash table with load factor 0.8 the probability of a given entry
449
         * having DIB > 40 is 1.9e-8.
450
         * This returns the correct DIB value by recomputing the hash value in
451
         * the unlikely case. XXX Hitting this case could be a hint to rehash.
452
         */
453
        initial_bucket = bucket_hash(h, bucket_at(h, idx)->key);
×
454
        return bucket_distance(h, idx, initial_bucket);
×
455
}
456

457
static void bucket_set_dib(HashmapBase *h, unsigned idx, unsigned dib) {
203,600,464✔
458
        dib_raw_ptr(h)[idx] = dib != DIB_FREE ? MIN(dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE;
203,600,464✔
459
}
203,600,464✔
460

461
static unsigned skip_free_buckets(HashmapBase *h, unsigned idx) {
97,900,465✔
462
        dib_raw_t *dibs;
97,900,465✔
463

464
        dibs = dib_raw_ptr(h);
97,900,465✔
465

466
        for ( ; idx < n_buckets(h); idx++)
297,428,073✔
467
                if (dibs[idx] != DIB_RAW_FREE)
180,254,359✔
468
                        return idx;
469

470
        return IDX_NIL;
471
}
472

473
static void bucket_mark_free(HashmapBase *h, unsigned idx) {
44,251,013✔
474
        assert(h);
44,251,013✔
475

476
        memzero(bucket_at(h, idx), hashmap_type_info[h->type].entry_size);
44,251,013✔
477
        bucket_set_dib(h, idx, DIB_FREE);
44,251,013✔
478
}
44,251,013✔
479

480
static void bucket_move_entry(HashmapBase *h, struct swap_entries *swap,
304,363,314✔
481
                              unsigned from, unsigned to) {
482
        struct hashmap_base_entry *e_from, *e_to;
304,363,314✔
483

484
        assert(h);
304,363,314✔
485
        assert(from != to);
304,363,314✔
486

487
        e_from = bucket_at_virtual(h, swap, from);
304,363,314✔
488
        e_to   = bucket_at_virtual(h, swap, to);
304,363,314✔
489

490
        memcpy(e_to, e_from, hashmap_type_info[h->type].entry_size);
304,363,314✔
491

492
        if (h->type == HASHMAP_TYPE_ORDERED) {
304,363,314✔
493
                OrderedHashmap *lh = (OrderedHashmap*) h;
78,574,851✔
494
                struct ordered_hashmap_entry *le, *le_to;
78,574,851✔
495

496
                le_to = (struct ordered_hashmap_entry*) e_to;
78,574,851✔
497

498
                if (le_to->iterate_next != IDX_NIL) {
78,574,851✔
499
                        le = (struct ordered_hashmap_entry*)
56,829,043✔
500
                             bucket_at_virtual(h, swap, le_to->iterate_next);
56,829,043✔
501
                        le->iterate_previous = to;
56,829,043✔
502
                }
503

504
                if (le_to->iterate_previous != IDX_NIL) {
78,574,851✔
505
                        le = (struct ordered_hashmap_entry*)
69,673,260✔
506
                             bucket_at_virtual(h, swap, le_to->iterate_previous);
69,673,260✔
507
                        le->iterate_next = to;
69,673,260✔
508
                }
509

510
                if (lh->iterate_list_head == from)
78,574,851✔
511
                        lh->iterate_list_head = to;
8,901,591✔
512
                if (lh->iterate_list_tail == from)
78,574,851✔
513
                        lh->iterate_list_tail = to;
21,745,808✔
514
        }
515
}
304,363,314✔
516

517
static unsigned next_idx(HashmapBase *h, unsigned idx) {
382,989,788✔
518
        return (idx + 1U) % n_buckets(h);
382,989,788✔
519
}
520

521
static unsigned prev_idx(HashmapBase *h, unsigned idx) {
105✔
522
        return (n_buckets(h) + idx - 1U) % n_buckets(h);
105✔
523
}
524

525
static void* entry_value(HashmapBase *h, struct hashmap_base_entry *e) {
202,623,745✔
526
        assert(h);
202,623,745✔
527
        assert(e);
202,623,745✔
528

529
        switch (h->type) {
202,623,745✔
530

531
        case HASHMAP_TYPE_PLAIN:
180,624,248✔
532
        case HASHMAP_TYPE_ORDERED:
533
                return ((struct plain_hashmap_entry*)e)->value;
180,624,248✔
534

535
        case HASHMAP_TYPE_SET:
21,999,497✔
536
                return (void*) e->key;
21,999,497✔
537

538
        default:
×
539
                assert_not_reached();
×
540
        }
541
}
542

543
static void base_remove_entry(HashmapBase *h, unsigned idx) {
44,251,013✔
544
        unsigned left, right, prev, dib;
44,251,013✔
545
        dib_raw_t raw_dib, *dibs;
44,251,013✔
546

547
        dibs = dib_raw_ptr(h);
44,251,013✔
548
        assert(dibs[idx] != DIB_RAW_FREE);
44,251,013✔
549

550
#if ENABLE_DEBUG_HASHMAP
551
        assert(h);
552
        h->debug.rem_count++;
553
        h->debug.last_rem_idx = idx;
554
#endif
555

556
        left = idx;
44,251,013✔
557
        /* Find the stop bucket ("right"). It is either free or has DIB == 0. */
558
        for (right = next_idx(h, left); ; right = next_idx(h, right)) {
44,251,013✔
559
                raw_dib = dibs[right];
61,711,193✔
560
                if (IN_SET(raw_dib, 0, DIB_RAW_FREE))
61,711,193✔
561
                        break;
562

563
                /* The buckets are not supposed to be all occupied and with DIB > 0.
564
                 * That would mean we could make everyone better off by shifting them
565
                 * backward. This scenario is impossible. */
566
                assert(left != right);
17,460,180✔
567
        }
568

569
        if (h->type == HASHMAP_TYPE_ORDERED) {
44,251,013✔
570
                OrderedHashmap *lh = (OrderedHashmap*) h;
15,702,952✔
571
                struct ordered_hashmap_entry *le = ordered_bucket_at(lh, idx);
15,702,952✔
572

573
                if (le->iterate_next != IDX_NIL)
15,702,952✔
574
                        ordered_bucket_at(lh, le->iterate_next)->iterate_previous = le->iterate_previous;
14,255,307✔
575
                else
576
                        lh->iterate_list_tail = le->iterate_previous;
1,447,645✔
577

578
                if (le->iterate_previous != IDX_NIL)
15,702,952✔
579
                        ordered_bucket_at(lh, le->iterate_previous)->iterate_next = le->iterate_next;
14,083✔
580
                else
581
                        lh->iterate_list_head = le->iterate_next;
15,688,869✔
582
        }
583

584
        /* Now shift all buckets in the interval (left, right) one step backwards */
585
        for (prev = left, left = next_idx(h, left); left != right;
61,711,193✔
586
             prev = left, left = next_idx(h, left)) {
17,460,180✔
587
                dib = bucket_calculate_dib(h, left, dibs[left]);
17,460,180✔
588
                assert(dib != 0);
17,460,180✔
589
                bucket_move_entry(h, NULL, left, prev);
17,460,180✔
590
                bucket_set_dib(h, prev, dib - 1);
17,460,180✔
591
        }
592

593
        bucket_mark_free(h, prev);
44,251,013✔
594
        n_entries_dec(h);
44,251,013✔
595
        base_set_dirty(h);
44,251,013✔
596
}
44,251,013✔
597
#define remove_entry(h, idx) base_remove_entry(HASHMAP_BASE(h), idx)
598

599
static unsigned hashmap_iterate_in_insertion_order(OrderedHashmap *h, Iterator *i) {
24,849,088✔
600
        struct ordered_hashmap_entry *e;
24,849,088✔
601
        unsigned idx;
24,849,088✔
602

603
        assert(h);
24,849,088✔
604
        assert(i);
24,849,088✔
605

606
        if (i->idx == IDX_NIL)
24,849,088✔
607
                goto at_end;
763,279✔
608

609
        if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL)
24,085,809✔
610
                goto at_end;
863,237✔
611

612
        if (i->idx == IDX_FIRST) {
23,222,572✔
613
                idx = h->iterate_list_head;
16,438,861✔
614
                e = ordered_bucket_at(h, idx);
16,438,861✔
615
        } else {
616
                idx = i->idx;
6,783,711✔
617
                e = ordered_bucket_at(h, idx);
6,783,711✔
618
                /*
619
                 * We allow removing the current entry while iterating, but removal may cause
620
                 * a backward shift. The next entry may thus move one bucket to the left.
621
                 * To detect when it happens, we remember the key pointer of the entry we were
622
                 * going to iterate next. If it does not match, there was a backward shift.
623
                 */
624
                if (e->p.b.key != i->next_key) {
6,783,711✔
625
                        idx = prev_idx(HASHMAP_BASE(h), idx);
97✔
626
                        e = ordered_bucket_at(h, idx);
97✔
627
                }
628
                assert(e->p.b.key == i->next_key);
6,783,711✔
629
        }
630

631
#if ENABLE_DEBUG_HASHMAP
632
        i->prev_idx = idx;
633
#endif
634

635
        if (e->iterate_next != IDX_NIL) {
23,222,572✔
636
                struct ordered_hashmap_entry *n;
21,049,626✔
637
                i->idx = e->iterate_next;
21,049,626✔
638
                n = ordered_bucket_at(h, i->idx);
21,049,626✔
639
                i->next_key = n->p.b.key;
21,049,626✔
640
        } else
641
                i->idx = IDX_NIL;
2,172,946✔
642

643
        return idx;
644

645
at_end:
1,626,516✔
646
        i->idx = IDX_NIL;
1,626,516✔
647
        return IDX_NIL;
1,626,516✔
648
}
649

650
static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) {
75,889,463✔
651
        unsigned idx;
75,889,463✔
652

653
        assert(h);
75,889,463✔
654
        assert(i);
75,889,463✔
655

656
        if (i->idx == IDX_NIL)
75,889,463✔
657
                goto at_end;
5,021,881✔
658

659
        if (i->idx == IDX_FIRST) {
70,867,582✔
660
                /* fast forward to the first occupied bucket */
661
                if (h->has_indirect) {
27,769,864✔
662
                        i->idx = skip_free_buckets(h, h->indirect.idx_lowest_entry);
10,461,820✔
663
                        h->indirect.idx_lowest_entry = i->idx;
10,461,820✔
664
                } else
665
                        i->idx = skip_free_buckets(h, 0);
17,308,044✔
666

667
                if (i->idx == IDX_NIL)
27,769,864✔
668
                        goto at_end;
736,981✔
669
        } else {
670
                struct hashmap_base_entry *e;
43,097,718✔
671

672
                assert(i->idx > 0);
43,097,718✔
673

674
                e = bucket_at(h, i->idx);
43,097,718✔
675
                /*
676
                 * We allow removing the current entry while iterating, but removal may cause
677
                 * a backward shift. The next entry may thus move one bucket to the left.
678
                 * To detect when it happens, we remember the key pointer of the entry we were
679
                 * going to iterate next. If it does not match, there was a backward shift.
680
                 */
681
                if (e->key != i->next_key)
43,097,718✔
682
                        e = bucket_at(h, --i->idx);
32,088✔
683

684
                assert(e->key == i->next_key);
43,097,718✔
685
        }
686

687
        idx = i->idx;
70,130,601✔
688
#if ENABLE_DEBUG_HASHMAP
689
        i->prev_idx = idx;
690
#endif
691

692
        i->idx = skip_free_buckets(h, i->idx + 1);
70,130,601✔
693
        if (i->idx != IDX_NIL)
70,130,601✔
694
                i->next_key = bucket_at(h, i->idx)->key;
51,594,333✔
695
        else
696
                i->idx = IDX_NIL;
18,536,268✔
697

698
        return idx;
699

700
at_end:
5,758,862✔
701
        i->idx = IDX_NIL;
5,758,862✔
702
        return IDX_NIL;
5,758,862✔
703
}
704

705
static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
118,322,958✔
706
        if (!h) {
118,322,958✔
707
                i->idx = IDX_NIL;
17,584,407✔
708
                return IDX_NIL;
17,584,407✔
709
        }
710

711
#if ENABLE_DEBUG_HASHMAP
712
        if (i->idx == IDX_FIRST) {
713
                i->put_count = h->debug.put_count;
714
                i->rem_count = h->debug.rem_count;
715
        } else {
716
                /* While iterating, must not add any new entries */
717
                assert(i->put_count == h->debug.put_count);
718
                /* ... or remove entries other than the current one */
719
                assert(i->rem_count == h->debug.rem_count ||
720
                       (i->rem_count == h->debug.rem_count - 1 &&
721
                        i->prev_idx == h->debug.last_rem_idx));
722
                /* Reset our removals counter */
723
                i->rem_count = h->debug.rem_count;
724
        }
725
#endif
726

727
        return h->type == HASHMAP_TYPE_ORDERED ? hashmap_iterate_in_insertion_order((OrderedHashmap*) h, i)
24,849,088✔
728
                                               : hashmap_iterate_in_internal_order(h, i);
100,738,551✔
729
}
730

731
bool _hashmap_iterate(HashmapBase *h, Iterator *i, void **value, const void **key) {
91,128,642✔
732
        struct hashmap_base_entry *e;
91,128,642✔
733
        void *data;
91,128,642✔
734
        unsigned idx;
91,128,642✔
735

736
        idx = hashmap_iterate_entry(h, i);
91,128,642✔
737
        if (idx == IDX_NIL) {
91,128,642✔
738
                if (value)
24,904,162✔
739
                        *value = NULL;
23,573,819✔
740
                if (key)
24,904,162✔
741
                        *key = NULL;
6,036,584✔
742

743
                return false;
744
        }
745

746
        e = bucket_at(h, idx);
66,224,480✔
747
        data = entry_value(h, e);
66,224,480✔
748
        if (value)
66,224,480✔
749
                *value = data;
45,362,920✔
750
        if (key)
66,224,480✔
751
                *key = e->key;
38,366,969✔
752

753
        return true;
754
}
755

756
#define HASHMAP_FOREACH_IDX(idx, h, i) \
757
        for ((i) = ITERATOR_FIRST, (idx) = hashmap_iterate_entry((h), &(i)); \
758
             (idx != IDX_NIL); \
759
             (idx) = hashmap_iterate_entry((h), &(i)))
760

761
IteratedCache* _hashmap_iterated_cache_new(HashmapBase *h) {
7,532✔
762
        IteratedCache *cache;
7,532✔
763

764
        assert(h);
7,532✔
765
        assert(!h->cached);
7,532✔
766

767
        if (h->cached)
7,532✔
768
                return NULL;
769

770
        cache = new0(IteratedCache, 1);
7,532✔
771
        if (!cache)
7,532✔
772
                return NULL;
773

774
        cache->hashmap = h;
7,532✔
775
        h->cached = true;
7,532✔
776

777
        return cache;
7,532✔
778
}
779

780
static void reset_direct_storage(HashmapBase *h) {
8,999,439✔
781
        const struct hashmap_type_info *hi = &hashmap_type_info[h->type];
8,999,439✔
782
        void *p;
8,999,439✔
783

784
        assert(!h->has_indirect);
8,999,439✔
785

786
        p = mempset(h->direct.storage, 0, hi->entry_size * hi->n_direct_buckets);
8,999,439✔
787
        memset(p, DIB_RAW_INIT, sizeof(dib_raw_t) * hi->n_direct_buckets);
8,999,439✔
788
}
8,999,439✔
789

790
static void shared_hash_key_initialize(void) {
72,868✔
791
        random_bytes(shared_hash_key, sizeof(shared_hash_key));
72,868✔
792
}
72,868✔
793

794
static struct HashmapBase* hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type) {
4,512,971✔
795
        HashmapBase *h;
4,512,971✔
796
        const struct hashmap_type_info *hi = &hashmap_type_info[type];
4,512,971✔
797

798
        bool use_pool = mempool_enabled && mempool_enabled();  /* mempool_enabled is a weak symbol */
4,512,971✔
799

800
        h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
4,598,331✔
801
        if (!h)
4,512,971✔
802
                return NULL;
803

804
        h->type = type;
4,512,971✔
805
        h->from_pool = use_pool;
4,512,971✔
806
        h->hash_ops = hash_ops ?: &trivial_hash_ops;
4,512,971✔
807

808
        if (type == HASHMAP_TYPE_ORDERED) {
4,512,971✔
809
                OrderedHashmap *lh = (OrderedHashmap*)h;
1,181,864✔
810
                lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
1,181,864✔
811
        }
812

813
        reset_direct_storage(h);
4,512,971✔
814

815
        static pthread_once_t once = PTHREAD_ONCE_INIT;
4,512,971✔
816
        assert_se(pthread_once(&once, shared_hash_key_initialize) == 0);
4,512,971✔
817

818
#if ENABLE_DEBUG_HASHMAP
819
        assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
820
        LIST_PREPEND(debug_list, hashmap_debug_list, &h->debug);
821
        assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
822
#endif
823

824
        return h;
825
}
826

827
Hashmap *hashmap_new(const struct hash_ops *hash_ops) {
912,601✔
828
        return (Hashmap*)        hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN);
912,601✔
829
}
830

831
OrderedHashmap *ordered_hashmap_new(const struct hash_ops *hash_ops) {
55,873✔
832
        return (OrderedHashmap*) hashmap_base_new(hash_ops, HASHMAP_TYPE_ORDERED);
55,873✔
833
}
834

835
Set *set_new(const struct hash_ops *hash_ops) {
148,207✔
836
        return (Set*)            hashmap_base_new(hash_ops, HASHMAP_TYPE_SET);
148,207✔
837
}
838

839
static int hashmap_base_ensure_allocated(HashmapBase **h, const struct hash_ops *hash_ops,
42,753,767✔
840
                                         enum HashmapType type) {
841
        HashmapBase *q;
42,753,767✔
842

843
        assert(h);
42,753,767✔
844

845
        if (*h) {
42,753,767✔
846
                assert((*h)->hash_ops == (hash_ops ?: &trivial_hash_ops));
42,714,126✔
847
                return 0;
848
        }
849

850
        q = hashmap_base_new(hash_ops, type);
3,396,287✔
851
        if (!q)
3,396,287✔
852
                return -ENOMEM;
853

854
        *h = q;
3,396,287✔
855
        return 1;
3,396,287✔
856
}
857

858
int hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops) {
7,839,350✔
859
        return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_PLAIN);
7,839,350✔
860
}
861

862
int ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops) {
16,665,446✔
863
        return hashmap_base_ensure_allocated((HashmapBase**)h, hash_ops, HASHMAP_TYPE_ORDERED);
16,665,446✔
864
}
865

866
int set_ensure_allocated(Set **s, const struct hash_ops *hash_ops) {
18,248,971✔
867
        return hashmap_base_ensure_allocated((HashmapBase**)s, hash_ops, HASHMAP_TYPE_SET);
18,248,971✔
868
}
869

870
int hashmap_ensure_put(Hashmap **h, const struct hash_ops *hash_ops, const void *key, void *value) {
6,337,584✔
871
        int r;
6,337,584✔
872

873
        assert(h);
6,337,584✔
874

875
        r = hashmap_ensure_allocated(h, hash_ops);
6,337,584✔
876
        if (r < 0)
6,337,584✔
877
                return r;
878

879
        return hashmap_put(*h, key, value);
6,337,584✔
880
}
881

882
int ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value) {
3,448,360✔
883
        int r;
3,448,360✔
884

885
        assert(h);
3,448,360✔
886

887
        r = ordered_hashmap_ensure_allocated(h, hash_ops);
3,448,360✔
888
        if (r < 0)
3,448,360✔
889
                return r;
890

891
        return ordered_hashmap_put(*h, key, value);
3,448,360✔
892
}
893

894
int ordered_hashmap_ensure_replace(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value) {
6,259✔
895
        int r;
6,259✔
896

897
        assert(h);
6,259✔
898

899
        r = ordered_hashmap_ensure_allocated(h, hash_ops);
6,259✔
900
        if (r < 0)
6,259✔
901
                return r;
902

903
        return ordered_hashmap_replace(*h, key, value);
6,259✔
904
}
905

906
int hashmap_ensure_replace(Hashmap **h, const struct hash_ops *hash_ops, const void *key, void *value) {
81,111✔
907
        int r;
81,111✔
908

909
        assert(h);
81,111✔
910

911
        r = hashmap_ensure_allocated(h, hash_ops);
81,111✔
912
        if (r < 0)
81,111✔
913
                return r;
914

915
        return hashmap_replace(*h, key, value);
81,111✔
916
}
917

918
static void hashmap_free_no_clear(HashmapBase *h) {
4,462,720✔
919
        assert(!h->has_indirect);
4,462,720✔
920
        assert(h->n_direct_entries == 0);
4,462,720✔
921

922
#if ENABLE_DEBUG_HASHMAP
923
        assert_se(pthread_mutex_lock(&hashmap_debug_list_mutex) == 0);
924
        LIST_REMOVE(debug_list, hashmap_debug_list, &h->debug);
925
        assert_se(pthread_mutex_unlock(&hashmap_debug_list_mutex) == 0);
926
#endif
927

928
        if (h->from_pool) {
4,462,720✔
929
                /* Ensure that the object didn't get migrated between threads. */
930
                assert_se(is_main_thread());
4,378,084✔
931
                mempool_free_tile(hashmap_type_info[h->type].mempool, h);
4,378,084✔
932
        } else
933
                free(h);
84,636✔
934
}
4,462,720✔
935

936
HashmapBase* _hashmap_free(HashmapBase *h) {
17,202,868✔
937
        if (h) {
17,202,868✔
938
                _hashmap_clear(h);
4,462,720✔
939
                hashmap_free_no_clear(h);
4,462,720✔
940
        }
941

942
        return NULL;
17,202,868✔
943
}
944

945
void _hashmap_clear(HashmapBase *h) {
4,640,469✔
946
        if (!h)
4,640,469✔
947
                return;
948

949
        if (h->hash_ops->free_key || h->hash_ops->free_value) {
4,486,468✔
950

951
                /* If destructor calls are defined, let's destroy things defensively: let's take the item out of the
952
                 * hash table, and only then call the destructor functions. If these destructors then try to unregister
953
                 * themselves from our hash table a second time, the entry is already gone. */
954

955
                while (_hashmap_size(h) > 0) {
23,637,466✔
956
                        void *k = NULL;
20,469,614✔
957
                        void *v;
20,469,614✔
958

959
                        v = _hashmap_first_key_and_value(h, true, &k);
20,469,614✔
960

961
                        if (h->hash_ops->free_key)
20,469,614✔
962
                                h->hash_ops->free_key(k);
15,929,894✔
963

964
                        if (h->hash_ops->free_value)
20,469,614✔
965
                                h->hash_ops->free_value(v);
17,895,095✔
966
                }
967
        }
968

969
        if (h->has_indirect) {
4,486,468✔
970
                free(h->indirect.storage);
1,518,512✔
971
                h->has_indirect = false;
1,518,512✔
972
        }
973

974
        h->n_direct_entries = 0;
4,486,468✔
975
        reset_direct_storage(h);
4,486,468✔
976

977
        if (h->type == HASHMAP_TYPE_ORDERED) {
4,486,468✔
978
                OrderedHashmap *lh = (OrderedHashmap*) h;
1,177,289✔
979
                lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
1,177,289✔
980
        }
981

982
        base_set_dirty(h);
4,486,468✔
983
}
984

985
static int resize_buckets(HashmapBase *h, unsigned entries_add);
986

987
/*
988
 * Finds an empty bucket to put an entry into, starting the scan at 'idx'.
989
 * Performs Robin Hood swaps as it goes. The entry to put must be placed
990
 * by the caller into swap slot IDX_PUT.
991
 * If used for in-place resizing, may leave a displaced entry in swap slot
992
 * IDX_PUT. Caller must rehash it next.
993
 * Returns: true if it left a displaced entry to rehash next in IDX_PUT,
994
 *          false otherwise.
995
 */
996
static bool hashmap_put_robin_hood(HashmapBase *h, unsigned idx,
101,108,177✔
997
                                   struct swap_entries *swap) {
998
        dib_raw_t raw_dib, *dibs;
101,108,177✔
999
        unsigned dib, distance;
101,108,177✔
1000

1001
#if ENABLE_DEBUG_HASHMAP
1002
        assert(h);
1003
        h->debug.put_count++;
1004
#endif
1005

1006
        dibs = dib_raw_ptr(h);
101,108,177✔
1007

1008
        for (distance = 0; ; distance++) {
101,108,177✔
1009
                raw_dib = dibs[idx];
202,694,196✔
1010
                if (IN_SET(raw_dib, DIB_RAW_FREE, DIB_RAW_REHASH)) {
202,694,196✔
1011
                        if (raw_dib == DIB_RAW_REHASH)
101,108,177✔
1012
                                bucket_move_entry(h, swap, idx, IDX_TMP);
11,291,322✔
1013

1014
                        if (h->has_indirect && h->indirect.idx_lowest_entry > idx)
101,108,177✔
1015
                                h->indirect.idx_lowest_entry = idx;
37,116✔
1016

1017
                        bucket_set_dib(h, idx, distance);
101,108,177✔
1018
                        bucket_move_entry(h, swap, IDX_PUT, idx);
101,108,177✔
1019
                        if (raw_dib == DIB_RAW_REHASH) {
101,108,177✔
1020
                                bucket_move_entry(h, swap, IDX_TMP, IDX_PUT);
11,291,322✔
1021
                                return true;
11,291,322✔
1022
                        }
1023

1024
                        return false;
1025
                }
1026

1027
                dib = bucket_calculate_dib(h, idx, raw_dib);
101,586,019✔
1028

1029
                if (dib < distance) {
101,586,019✔
1030
                        /* Found a wealthier entry. Go Robin Hood! */
1031
                        bucket_set_dib(h, idx, distance);
40,781,094✔
1032

1033
                        /* swap the entries */
1034
                        bucket_move_entry(h, swap, idx, IDX_TMP);
40,781,094✔
1035
                        bucket_move_entry(h, swap, IDX_PUT, idx);
40,781,094✔
1036
                        bucket_move_entry(h, swap, IDX_TMP, IDX_PUT);
40,781,094✔
1037

1038
                        distance = dib;
40,781,094✔
1039
                }
1040

1041
                idx = next_idx(h, idx);
101,586,019✔
1042
        }
1043
}
1044

1045
/*
1046
 * Puts an entry into a hashmap, boldly - no check whether key already exists.
1047
 * The caller must place the entry (only its key and value, not link indexes)
1048
 * in swap slot IDX_PUT.
1049
 * Caller must ensure: the key does not exist yet in the hashmap.
1050
 *                     that resize is not needed if !may_resize.
1051
 * Returns: 1 if entry was put successfully.
1052
 *          -ENOMEM if may_resize==true and resize failed with -ENOMEM.
1053
 *          Cannot return -ENOMEM if !may_resize.
1054
 */
1055
static int hashmap_base_put_boldly(HashmapBase *h, unsigned idx,
48,947,824✔
1056
                                   struct swap_entries *swap, bool may_resize) {
1057
        struct ordered_hashmap_entry *new_entry;
48,947,824✔
1058
        int r;
48,947,824✔
1059

1060
        assert(idx < n_buckets(h));
48,947,824✔
1061

1062
        new_entry = bucket_at_swap(swap, IDX_PUT);
48,947,824✔
1063

1064
        if (may_resize) {
48,947,824✔
1065
                r = resize_buckets(h, 1);
48,942,948✔
1066
                if (r < 0)
48,942,948✔
1067
                        return r;
1068
                if (r > 0)
48,942,948✔
1069
                        idx = bucket_hash(h, new_entry->p.b.key);
3,814,930✔
1070
        }
1071
        assert(n_entries(h) < n_buckets(h));
48,947,824✔
1072

1073
        if (h->type == HASHMAP_TYPE_ORDERED) {
48,947,824✔
1074
                OrderedHashmap *lh = (OrderedHashmap*) h;
15,994,994✔
1075

1076
                new_entry->iterate_next = IDX_NIL;
15,994,994✔
1077
                new_entry->iterate_previous = lh->iterate_list_tail;
15,994,994✔
1078

1079
                if (lh->iterate_list_tail != IDX_NIL) {
15,994,994✔
1080
                        struct ordered_hashmap_entry *old_tail;
14,535,507✔
1081

1082
                        old_tail = ordered_bucket_at(lh, lh->iterate_list_tail);
14,535,507✔
1083
                        assert(old_tail->iterate_next == IDX_NIL);
14,535,507✔
1084
                        old_tail->iterate_next = IDX_PUT;
14,535,507✔
1085
                }
1086

1087
                lh->iterate_list_tail = IDX_PUT;
15,994,994✔
1088
                if (lh->iterate_list_head == IDX_NIL)
15,994,994✔
1089
                        lh->iterate_list_head = IDX_PUT;
1,459,487✔
1090
        }
1091

1092
        assert_se(hashmap_put_robin_hood(h, idx, swap) == false);
48,947,824✔
1093

1094
        n_entries_inc(h);
48,947,824✔
1095
#if ENABLE_DEBUG_HASHMAP
1096
        h->debug.max_entries = MAX(h->debug.max_entries, n_entries(h));
1097
#endif
1098

1099
        base_set_dirty(h);
48,947,824✔
1100

1101
        return 1;
48,947,824✔
1102
}
1103
#define hashmap_put_boldly(h, idx, swap, may_resize) \
1104
        hashmap_base_put_boldly(HASHMAP_BASE(h), idx, swap, may_resize)
1105

1106
/*
1107
 * Returns 0 if resize is not needed.
1108
 *         1 if successfully resized.
1109
 *         -ENOMEM on allocation failure.
1110
 */
1111
static int resize_buckets(HashmapBase *h, unsigned entries_add) {
48,957,134✔
1112
        struct swap_entries swap;
48,957,134✔
1113
        void *new_storage;
48,957,134✔
1114
        dib_raw_t *old_dibs, *new_dibs;
48,957,134✔
1115
        const struct hashmap_type_info *hi;
48,957,134✔
1116
        unsigned idx, optimal_idx;
48,957,134✔
1117
        unsigned old_n_buckets, new_n_buckets, n_rehashed, new_n_entries;
48,957,134✔
1118
        uint8_t new_shift;
48,957,134✔
1119
        bool rehash_next;
48,957,134✔
1120

1121
        assert(h);
48,957,134✔
1122

1123
        hi = &hashmap_type_info[h->type];
48,957,134✔
1124
        new_n_entries = n_entries(h) + entries_add;
48,957,134✔
1125

1126
        /* overflow? */
1127
        if (_unlikely_(new_n_entries < entries_add))
48,957,134✔
1128
                return -ENOMEM;
48,957,134✔
1129

1130
        /* For direct storage we allow 100% load, because it's tiny. */
1131
        if (!h->has_indirect && new_n_entries <= hi->n_direct_buckets)
48,957,132✔
1132
                return 0;
1133

1134
        /*
1135
         * Load factor = n/m = 1 - (1/INV_KEEP_FREE).
1136
         * From it follows: m = n + n/(INV_KEEP_FREE - 1)
1137
         */
1138
        new_n_buckets = new_n_entries + new_n_entries / (INV_KEEP_FREE - 1);
40,287,835✔
1139
        /* overflow? */
1140
        if (_unlikely_(new_n_buckets < new_n_entries))
40,287,835✔
1141
                return -ENOMEM;
1142

1143
        if (_unlikely_(new_n_buckets > UINT_MAX / (hi->entry_size + sizeof(dib_raw_t))))
40,287,833✔
1144
                return -ENOMEM;
1145

1146
        old_n_buckets = n_buckets(h);
40,287,833✔
1147

1148
        if (_likely_(new_n_buckets <= old_n_buckets))
40,287,833✔
1149
                return 0;
1150

1151
        new_shift = log2u_round_up(MAX(
3,818,631✔
1152
                        new_n_buckets * (hi->entry_size + sizeof(dib_raw_t)),
1153
                        2 * sizeof(struct direct_storage)));
1154

1155
        /* Realloc storage (buckets and DIB array). */
1156
        new_storage = realloc(h->has_indirect ? h->indirect.storage : NULL,
2,281,428✔
1157
                              1U << new_shift);
3,818,631✔
1158
        if (!new_storage)
3,818,631✔
1159
                return -ENOMEM;
1160

1161
        /* Must upgrade direct to indirect storage. */
1162
        if (!h->has_indirect) {
3,818,631✔
1163
                memcpy(new_storage, h->direct.storage,
1,537,203✔
1164
                       old_n_buckets * (hi->entry_size + sizeof(dib_raw_t)));
1,537,203✔
1165
                h->indirect.n_entries = h->n_direct_entries;
1,537,203✔
1166
                h->indirect.idx_lowest_entry = 0;
1,537,203✔
1167
                h->n_direct_entries = 0;
1,537,203✔
1168
        }
1169

1170
        /* Get a new hash key. If we've just upgraded to indirect storage,
1171
         * allow reusing a previously generated key. It's still a different key
1172
         * from the shared one that we used for direct storage. */
1173
        get_hash_key(h->indirect.hash_key, !h->has_indirect);
3,818,631✔
1174

1175
        h->has_indirect = true;
3,818,631✔
1176
        h->indirect.storage = new_storage;
3,818,631✔
1177
        h->indirect.n_buckets = (1U << new_shift) /
3,818,631✔
1178
                                (hi->entry_size + sizeof(dib_raw_t));
1179

1180
        old_dibs = (dib_raw_t*)((uint8_t*) new_storage + hi->entry_size * old_n_buckets);
3,818,631✔
1181
        new_dibs = dib_raw_ptr(h);
3,818,631✔
1182

1183
        /*
1184
         * Move the DIB array to the new place, replacing valid DIB values with
1185
         * DIB_RAW_REHASH to indicate all of the used buckets need rehashing.
1186
         * Note: Overlap is not possible, because we have at least doubled the
1187
         * number of buckets and dib_raw_t is smaller than any entry type.
1188
         */
1189
        for (idx = 0; idx < old_n_buckets; idx++) {
69,648,593✔
1190
                assert(old_dibs[idx] != DIB_RAW_REHASH);
65,829,962✔
1191
                new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE
119,075,023✔
1192
                                                              : DIB_RAW_REHASH;
1193
        }
1194

1195
        /* Zero the area of newly added entries (including the old DIB area) */
1196
        memzero(bucket_at(h, old_n_buckets),
3,818,631✔
1197
               (n_buckets(h) - old_n_buckets) * hi->entry_size);
1198

1199
        /* The upper half of the new DIB array needs initialization */
1200
        memset(&new_dibs[old_n_buckets], DIB_RAW_INIT,
7,637,262✔
1201
               (n_buckets(h) - old_n_buckets) * sizeof(dib_raw_t));
3,818,631✔
1202

1203
        /* Rehash entries that need it */
1204
        n_rehashed = 0;
3,818,631✔
1205
        for (idx = 0; idx < old_n_buckets; idx++) {
69,648,593✔
1206
                if (new_dibs[idx] != DIB_RAW_REHASH)
65,829,962✔
1207
                        continue;
23,876,223✔
1208

1209
                optimal_idx = bucket_hash(h, bucket_at(h, idx)->key);
41,953,739✔
1210

1211
                /*
1212
                 * Not much to do if by luck the entry hashes to its current
1213
                 * location. Just set its DIB.
1214
                 */
1215
                if (optimal_idx == idx) {
41,953,739✔
1216
                        new_dibs[idx] = 0;
1,084,708✔
1217
                        n_rehashed++;
1,084,708✔
1218
                        continue;
1,084,708✔
1219
                }
1220

1221
                new_dibs[idx] = DIB_RAW_FREE;
40,869,031✔
1222
                bucket_move_entry(h, &swap, idx, IDX_PUT);
40,869,031✔
1223
                /* bucket_move_entry does not clear the source */
1224
                memzero(bucket_at(h, idx), hi->entry_size);
40,869,031✔
1225

1226
                do {
52,160,353✔
1227
                        /*
1228
                         * Find the new bucket for the current entry. This may make
1229
                         * another entry homeless and load it into IDX_PUT.
1230
                         */
1231
                        rehash_next = hashmap_put_robin_hood(h, optimal_idx, &swap);
52,160,353✔
1232
                        n_rehashed++;
52,160,353✔
1233

1234
                        /* Did the current entry displace another one? */
1235
                        if (rehash_next)
52,160,353✔
1236
                                optimal_idx = bucket_hash(h, bucket_at_swap(&swap, IDX_PUT)->p.b.key);
11,291,322✔
1237
                } while (rehash_next);
52,160,353✔
1238
        }
1239

1240
        assert_se(n_rehashed == n_entries(h));
3,818,631✔
1241

1242
        return 1;
1243
}
1244

1245
/*
1246
 * Finds an entry with a matching key
1247
 * Returns: index of the found entry, or IDX_NIL if not found.
1248
 */
1249
static unsigned base_bucket_scan(HashmapBase *h, unsigned idx, const void *key) {
254,602,310✔
1250
        struct hashmap_base_entry *e;
254,602,310✔
1251
        unsigned dib, distance;
254,602,310✔
1252
        dib_raw_t *dibs = dib_raw_ptr(h);
254,602,310✔
1253

1254
        assert(idx < n_buckets(h));
254,602,310✔
1255

1256
        for (distance = 0; ; distance++) {
157,981,383✔
1257
                if (dibs[idx] == DIB_RAW_FREE)
412,583,693✔
1258
                        return IDX_NIL;
1259

1260
                dib = bucket_calculate_dib(h, idx, dibs[idx]);
318,532,390✔
1261

1262
                if (dib < distance)
318,532,390✔
1263
                        return IDX_NIL;
1264
                if (dib == distance) {
271,638,564✔
1265
                        e = bucket_at(h, idx);
205,242,930✔
1266
                        if (h->hash_ops->compare(e->key, key) == 0)
205,242,930✔
1267
                                return idx;
1268
                }
1269

1270
                idx = next_idx(h, idx);
157,981,383✔
1271
        }
1272
}
1273
#define bucket_scan(h, idx, key) base_bucket_scan(HASHMAP_BASE(h), idx, key)
1274

1275
int hashmap_put(Hashmap *h, const void *key, void *value) {
15,683,525✔
1276
        struct swap_entries swap;
15,683,525✔
1277
        struct plain_hashmap_entry *e;
15,683,525✔
1278
        unsigned hash, idx;
15,683,525✔
1279

1280
        assert(h);
15,683,525✔
1281

1282
        hash = bucket_hash(h, key);
15,683,525✔
1283
        idx = bucket_scan(h, hash, key);
15,683,525✔
1284
        if (idx != IDX_NIL) {
15,683,525✔
1285
                e = plain_bucket_at(h, idx);
342,966✔
1286
                if (e->value == value)
342,966✔
1287
                        return 0;
15,683,525✔
1288
                return -EEXIST;
39,180✔
1289
        }
1290

1291
        e = &bucket_at_swap(&swap, IDX_PUT)->p;
15,340,559✔
1292
        e->b.key = key;
15,340,559✔
1293
        e->value = value;
15,340,559✔
1294
        return hashmap_put_boldly(h, hash, &swap, true);
15,340,559✔
1295
}
1296

1297
int set_put(Set *s, const void *key) {
18,805,333✔
1298
        struct swap_entries swap;
18,805,333✔
1299
        struct hashmap_base_entry *e;
18,805,333✔
1300
        unsigned hash, idx;
18,805,333✔
1301

1302
        assert(s);
18,805,333✔
1303

1304
        hash = bucket_hash(s, key);
18,805,333✔
1305
        idx = bucket_scan(s, hash, key);
18,805,333✔
1306
        if (idx != IDX_NIL)
18,805,333✔
1307
                return 0;
18,805,333✔
1308

1309
        e = &bucket_at_swap(&swap, IDX_PUT)->p.b;
18,786,236✔
1310
        e->key = key;
18,786,236✔
1311
        return hashmap_put_boldly(s, hash, &swap, true);
18,786,236✔
1312
}
1313

1314
int set_ensure_put(Set **s, const struct hash_ops *hash_ops, const void *key) {
16,867,842✔
1315
        int r;
16,867,842✔
1316

1317
        assert(s);
16,867,842✔
1318

1319
        r = set_ensure_allocated(s, hash_ops);
16,867,842✔
1320
        if (r < 0)
16,867,842✔
1321
                return r;
1322

1323
        return set_put(*s, key);
16,867,842✔
1324
}
1325

1326
int set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key) {
1,448,236✔
1327
        int r;
1,448,236✔
1328

1329
        r = set_ensure_put(s, hash_ops, key);
1,448,236✔
1330
        if (r <= 0) {
1,448,236✔
1331
                if (hash_ops && hash_ops->free_key)
1,056✔
1332
                        hash_ops->free_key(key);
1,055✔
1333
                else if (hash_ops && hash_ops->free_value)
1✔
1334
                        /* Sets store their element in the key slot but may carry a value destructor. */
1335
                        hash_ops->free_value(key);
1✔
1336
                else
1337
                        free(key);
×
1338
        }
1339

1340
        return r;
1,448,236✔
1341
}
1342

1343
int hashmap_replace(Hashmap *h, const void *key, void *value) {
15,986,754✔
1344
        struct swap_entries swap;
15,986,754✔
1345
        struct plain_hashmap_entry *e;
15,986,754✔
1346
        unsigned hash, idx;
15,986,754✔
1347

1348
        assert(h);
15,986,754✔
1349

1350
        hash = bucket_hash(h, key);
15,986,754✔
1351
        idx = bucket_scan(h, hash, key);
15,986,754✔
1352
        if (idx != IDX_NIL) {
15,986,754✔
1353
                e = plain_bucket_at(h, idx);
1,174,176✔
1354
#if ENABLE_DEBUG_HASHMAP
1355
                /* Although the key is equal, the key pointer may have changed,
1356
                 * and this would break our assumption for iterating. So count
1357
                 * this operation as incompatible with iteration. */
1358
                if (e->b.key != key) {
1359
                        h->b.debug.put_count++;
1360
                        h->b.debug.rem_count++;
1361
                        h->b.debug.last_rem_idx = idx;
1362
                }
1363
#endif
1364
                e->b.key = key;
1,174,176✔
1365
                e->value = value;
1,174,176✔
1366
                hashmap_set_dirty(h);
1,174,176✔
1367

1368
                return 0;
1,174,176✔
1369
        }
1370

1371
        e = &bucket_at_swap(&swap, IDX_PUT)->p;
14,812,578✔
1372
        e->b.key = key;
14,812,578✔
1373
        e->value = value;
14,812,578✔
1374
        return hashmap_put_boldly(h, hash, &swap, true);
14,812,578✔
1375
}
1376

1377
int hashmap_update(Hashmap *h, const void *key, void *value) {
31,895✔
1378
        struct plain_hashmap_entry *e;
31,895✔
1379
        unsigned hash, idx;
31,895✔
1380

1381
        assert(h);
31,895✔
1382

1383
        hash = bucket_hash(h, key);
31,895✔
1384
        idx = bucket_scan(h, hash, key);
31,895✔
1385
        if (idx == IDX_NIL)
31,895✔
1386
                return -ENOENT;
1387

1388
        e = plain_bucket_at(h, idx);
31,893✔
1389
        e->value = value;
31,893✔
1390
        hashmap_set_dirty(h);
31,893✔
1391

1392
        return 0;
31,893✔
1393
}
1394

1395
void* _hashmap_get(HashmapBase *h, const void *key) {
129,834,829✔
1396
        struct hashmap_base_entry *e;
129,834,829✔
1397
        unsigned hash, idx;
129,834,829✔
1398

1399
        if (!h)
129,834,829✔
1400
                return NULL;
1401

1402
        hash = bucket_hash(h, key);
120,647,537✔
1403
        idx = bucket_scan(h, hash, key);
120,647,537✔
1404
        if (idx == IDX_NIL)
120,647,537✔
1405
                return NULL;
1406

1407
        e = bucket_at(h, idx);
90,966,409✔
1408
        return entry_value(h, e);
90,966,409✔
1409
}
1410

1411
void* hashmap_get2(Hashmap *h, const void *key, void **ret) {
13,412,031✔
1412
        struct plain_hashmap_entry *e;
13,412,031✔
1413
        unsigned hash, idx;
13,412,031✔
1414

1415
        if (!h)
13,412,031✔
1416
                return NULL;
1417

1418
        hash = bucket_hash(h, key);
13,412,000✔
1419
        idx = bucket_scan(h, hash, key);
13,412,000✔
1420
        if (idx == IDX_NIL)
13,412,000✔
1421
                return NULL;
1422

1423
        e = plain_bucket_at(h, idx);
1,086,224✔
1424
        if (ret)
1,086,224✔
1425
                *ret = (void*) e->b.key;
1,086,224✔
1426

1427
        return e->value;
1,086,224✔
1428
}
1429

1430
bool _hashmap_contains(HashmapBase *h, const void *key) {
44,138,257✔
1431
        unsigned hash;
44,138,257✔
1432

1433
        if (!h)
44,138,257✔
1434
                return false;
1435

1436
        hash = bucket_hash(h, key);
42,882,817✔
1437
        return bucket_scan(h, hash, key) != IDX_NIL;
42,882,817✔
1438
}
1439

1440
void* _hashmap_remove(HashmapBase *h, const void *key) {
26,972,503✔
1441
        struct hashmap_base_entry *e;
26,972,503✔
1442
        unsigned hash, idx;
26,972,503✔
1443
        void *data;
26,972,503✔
1444

1445
        if (!h)
26,972,503✔
1446
                return NULL;
1447

1448
        hash = bucket_hash(h, key);
25,721,714✔
1449
        idx = bucket_scan(h, hash, key);
25,721,714✔
1450
        if (idx == IDX_NIL)
25,721,714✔
1451
                return NULL;
1452

1453
        e = bucket_at(h, idx);
17,528,957✔
1454
        data = entry_value(h, e);
17,528,957✔
1455
        remove_entry(h, idx);
17,528,957✔
1456

1457
        return data;
17,528,957✔
1458
}
1459

1460
void* hashmap_remove2(Hashmap *h, const void *key, void **ret) {
607,844✔
1461
        struct plain_hashmap_entry *e;
607,844✔
1462
        unsigned hash, idx;
607,844✔
1463
        void *data;
607,844✔
1464

1465
        if (!h) {
607,844✔
1466
                if (ret)
92,693✔
1467
                        *ret = NULL;
92,693✔
1468
                return NULL;
1469
        }
1470

1471
        hash = bucket_hash(h, key);
515,151✔
1472
        idx = bucket_scan(h, hash, key);
515,151✔
1473
        if (idx == IDX_NIL) {
515,151✔
1474
                if (ret)
503,865✔
1475
                        *ret = NULL;
503,865✔
1476
                return NULL;
1477
        }
1478

1479
        e = plain_bucket_at(h, idx);
11,286✔
1480
        data = e->value;
11,286✔
1481
        if (ret)
11,286✔
1482
                *ret = (void*) e->b.key;
11,286✔
1483

1484
        remove_entry(h, idx);
11,286✔
1485

1486
        return data;
11,286✔
1487
}
1488

1489
int hashmap_remove_and_put(Hashmap *h, const void *old_key, const void *new_key, void *value) {
10✔
1490
        struct swap_entries swap;
10✔
1491
        struct plain_hashmap_entry *e;
10✔
1492
        unsigned old_hash, new_hash, idx;
10✔
1493

1494
        if (!h)
10✔
1495
                return -ENOENT;
10✔
1496

1497
        old_hash = bucket_hash(h, old_key);
8✔
1498
        idx = bucket_scan(h, old_hash, old_key);
8✔
1499
        if (idx == IDX_NIL)
8✔
1500
                return -ENOENT;
1501

1502
        new_hash = bucket_hash(h, new_key);
6✔
1503
        if (bucket_scan(h, new_hash, new_key) != IDX_NIL)
6✔
1504
                return -EEXIST;
1505

1506
        remove_entry(h, idx);
4✔
1507

1508
        e = &bucket_at_swap(&swap, IDX_PUT)->p;
4✔
1509
        e->b.key = new_key;
4✔
1510
        e->value = value;
4✔
1511
        assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1);
4✔
1512

1513
        return 0;
1514
}
1515

1516
int set_remove_and_put(Set *s, const void *old_key, const void *new_key) {
1,291✔
1517
        struct swap_entries swap;
1,291✔
1518
        struct hashmap_base_entry *e;
1,291✔
1519
        unsigned old_hash, new_hash, idx;
1,291✔
1520

1521
        if (!s)
1,291✔
1522
                return -ENOENT;
1,291✔
1523

1524
        old_hash = bucket_hash(s, old_key);
1,291✔
1525
        idx = bucket_scan(s, old_hash, old_key);
1,291✔
1526
        if (idx == IDX_NIL)
1,291✔
1527
                return -ENOENT;
1528

1529
        new_hash = bucket_hash(s, new_key);
1,291✔
1530
        if (bucket_scan(s, new_hash, new_key) != IDX_NIL)
1,291✔
1531
                return -EEXIST;
1532

1533
        remove_entry(s, idx);
1,291✔
1534

1535
        e = &bucket_at_swap(&swap, IDX_PUT)->p.b;
1,291✔
1536
        e->key = new_key;
1,291✔
1537
        assert_se(hashmap_put_boldly(s, new_hash, &swap, false) == 1);
1,291✔
1538

1539
        return 0;
1540
}
1541

1542
int hashmap_remove_and_replace(Hashmap *h, const void *old_key, const void *new_key, void *value) {
48✔
1543
        struct swap_entries swap;
48✔
1544
        struct plain_hashmap_entry *e;
48✔
1545
        unsigned old_hash, new_hash, idx_old, idx_new;
48✔
1546

1547
        if (!h)
48✔
1548
                return -ENOENT;
48✔
1549

1550
        old_hash = bucket_hash(h, old_key);
46✔
1551
        idx_old = bucket_scan(h, old_hash, old_key);
46✔
1552
        if (idx_old == IDX_NIL)
46✔
1553
                return -ENOENT;
1554

1555
        old_key = bucket_at(HASHMAP_BASE(h), idx_old)->key;
44✔
1556

1557
        new_hash = bucket_hash(h, new_key);
44✔
1558
        idx_new = bucket_scan(h, new_hash, new_key);
44✔
1559
        if (idx_new != IDX_NIL)
44✔
1560
                if (idx_old != idx_new) {
42✔
1561
                        remove_entry(h, idx_new);
42✔
1562
                        /* Compensate for a possible backward shift. */
1563
                        if (old_key != bucket_at(HASHMAP_BASE(h), idx_old)->key)
42✔
1564
                                idx_old = prev_idx(HASHMAP_BASE(h), idx_old);
8✔
1565
                        assert(old_key == bucket_at(HASHMAP_BASE(h), idx_old)->key);
42✔
1566
                }
1567

1568
        remove_entry(h, idx_old);
44✔
1569

1570
        e = &bucket_at_swap(&swap, IDX_PUT)->p;
44✔
1571
        e->b.key = new_key;
44✔
1572
        e->value = value;
44✔
1573
        assert_se(hashmap_put_boldly(h, new_hash, &swap, false) == 1);
44✔
1574

1575
        return 0;
1576
}
1577

1578
void* _hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
901,904✔
1579
        struct hashmap_base_entry *e;
901,904✔
1580
        unsigned hash, idx;
901,904✔
1581

1582
        if (!h)
901,904✔
1583
                return NULL;
1584

1585
        hash = bucket_hash(h, key);
901,775✔
1586
        idx = bucket_scan(h, hash, key);
901,775✔
1587
        if (idx == IDX_NIL)
901,775✔
1588
                return NULL;
1589

1590
        e = bucket_at(h, idx);
783,183✔
1591
        if (entry_value(h, e) != value)
783,183✔
1592
                return NULL;
1593

1594
        remove_entry(h, idx);
782,806✔
1595

1596
        return value;
782,806✔
1597
}
1598

1599
static unsigned find_first_entry(HashmapBase *h) {
28,316,353✔
1600
        Iterator i = ITERATOR_FIRST;
28,316,353✔
1601

1602
        if (!h || !n_entries(h))
28,316,353✔
1603
                return IDX_NIL;
28,316,353✔
1604

1605
        return hashmap_iterate_entry(h, &i);
26,361,006✔
1606
}
1607

1608
void* _hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) {
28,316,353✔
1609
        struct hashmap_base_entry *e;
28,316,353✔
1610
        void *key, *data;
28,316,353✔
1611
        unsigned idx;
28,316,353✔
1612

1613
        idx = find_first_entry(h);
28,316,353✔
1614
        if (idx == IDX_NIL) {
28,316,353✔
1615
                if (ret_key)
1,955,347✔
1616
                        *ret_key = NULL;
1,032,015✔
1617
                return NULL;
1618
        }
1619

1620
        e = bucket_at(h, idx);
26,361,006✔
1621
        key = (void*) e->key;
26,361,006✔
1622
        data = entry_value(h, e);
26,361,006✔
1623

1624
        if (remove)
26,361,006✔
1625
                remove_entry(h, idx);
25,919,471✔
1626

1627
        if (ret_key)
26,361,006✔
1628
                *ret_key = key;
21,722,212✔
1629

1630
        return data;
1631
}
1632

1633
unsigned _hashmap_size(HashmapBase *h) {
67,511,911✔
1634
        if (!h)
67,511,911✔
1635
                return 0;
1636

1637
        return n_entries(h);
32,896,790✔
1638
}
1639

1640
unsigned _hashmap_buckets(HashmapBase *h) {
688✔
1641
        if (!h)
688✔
1642
                return 0;
1643

1644
        return n_buckets(h);
685✔
1645
}
1646

1647
int _hashmap_merge(Hashmap *h, Hashmap *other) {
4✔
1648
        Iterator i;
4✔
1649
        unsigned idx;
4✔
1650

1651
        assert(h);
4✔
1652

1653
        HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) {
16✔
1654
                struct plain_hashmap_entry *pe = plain_bucket_at(other, idx);
12✔
1655
                int r;
12✔
1656

1657
                r = hashmap_put(h, pe->b.key, pe->value);
12✔
1658
                if (r < 0 && r != -EEXIST)
12✔
1659
                        return r;
1660
        }
1661

1662
        return 0;
1663
}
1664

1665
int set_merge(Set *s, Set *other) {
1✔
1666
        Iterator i;
1✔
1667
        unsigned idx;
1✔
1668

1669
        assert(s);
1✔
1670

1671
        HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) {
5✔
1672
                struct set_entry *se = set_bucket_at(other, idx);
4✔
1673
                int r;
4✔
1674

1675
                r = set_put(s, se->b.key);
4✔
1676
                if (r < 0)
4✔
1677
                        return r;
1678
        }
1679

1680
        return 0;
1681
}
1682

1683
int _hashmap_reserve(HashmapBase *h, unsigned entries_add) {
10,669✔
1684
        int r;
10,669✔
1685

1686
        assert(h);
10,669✔
1687

1688
        r = resize_buckets(h, entries_add);
10,669✔
1689
        if (r < 0)
10,669✔
1690
                return r;
4✔
1691

1692
        return 0;
1693
}
1694

1695
/*
1696
 * The same as hashmap_merge(), but every new item from other is moved to h.
1697
 * Keys already in h are skipped and stay in other.
1698
 * Returns: 0 on success.
1699
 *          -ENOMEM on alloc failure, in which case no move has been done.
1700
 */
1701
int _hashmap_move(HashmapBase *h, HashmapBase *other) {
3,520✔
1702
        struct swap_entries swap;
3,520✔
1703
        struct hashmap_base_entry *e, *n;
3,520✔
1704
        Iterator i;
3,520✔
1705
        unsigned idx;
3,520✔
1706
        int r;
3,520✔
1707

1708
        assert(h);
3,520✔
1709

1710
        if (!other)
3,520✔
1711
                return 0;
3,520✔
1712

1713
        assert(other->type == h->type);
3,517✔
1714

1715
        /*
1716
         * This reserves buckets for the worst case, where none of other's
1717
         * entries are yet present in h. This is preferable to risking
1718
         * an allocation failure in the middle of the moving and having to
1719
         * rollback or return a partial result.
1720
         */
1721
        r = resize_buckets(h, n_entries(other));
3,517✔
1722
        if (r < 0)
3,517✔
1723
                return r;
1724

1725
        HASHMAP_FOREACH_IDX(idx, other, i) {
7,056✔
1726
                unsigned h_hash;
3,539✔
1727

1728
                e = bucket_at(other, idx);
3,539✔
1729
                h_hash = bucket_hash(h, e->key);
3,539✔
1730
                if (bucket_scan(h, h_hash, e->key) != IDX_NIL)
3,539✔
1731
                        continue;
2✔
1732

1733
                n = &bucket_at_swap(&swap, IDX_PUT)->p.b;
3,537✔
1734
                n->key = e->key;
3,537✔
1735
                if (h->type != HASHMAP_TYPE_SET)
3,537✔
1736
                        ((struct plain_hashmap_entry*) n)->value =
3,402✔
1737
                                ((struct plain_hashmap_entry*) e)->value;
3,402✔
1738
                assert_se(hashmap_put_boldly(h, h_hash, &swap, false) == 1);
3,537✔
1739

1740
                remove_entry(other, idx);
3,537✔
1741
        }
1742

1743
        return 0;
1744
}
1745

1746
int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
3,581✔
1747
        struct swap_entries swap;
3,581✔
1748
        unsigned h_hash, other_hash, idx;
3,581✔
1749
        struct hashmap_base_entry *e, *n;
3,581✔
1750
        int r;
3,581✔
1751

1752
        assert(h);
3,581✔
1753

1754
        h_hash = bucket_hash(h, key);
3,581✔
1755
        if (bucket_scan(h, h_hash, key) != IDX_NIL)
3,581✔
1756
                return -EEXIST;
3,581✔
1757

1758
        if (!other)
3,579✔
1759
                return -ENOENT;
1760

1761
        assert(other->type == h->type);
3,577✔
1762

1763
        other_hash = bucket_hash(other, key);
3,577✔
1764
        idx = bucket_scan(other, other_hash, key);
3,577✔
1765
        if (idx == IDX_NIL)
3,577✔
1766
                return -ENOENT;
1767

1768
        e = bucket_at(other, idx);
3,575✔
1769

1770
        n = &bucket_at_swap(&swap, IDX_PUT)->p.b;
3,575✔
1771
        n->key = e->key;
3,575✔
1772
        if (h->type != HASHMAP_TYPE_SET)
3,575✔
1773
                ((struct plain_hashmap_entry*) n)->value =
949✔
1774
                        ((struct plain_hashmap_entry*) e)->value;
949✔
1775
        r = hashmap_put_boldly(h, h_hash, &swap, true);
3,575✔
1776
        if (r < 0)
3,575✔
1777
                return r;
1778

1779
        remove_entry(other, idx);
3,575✔
1780
        return 0;
1781
}
1782

1783
HashmapBase* _hashmap_copy(HashmapBase *h) {
3✔
1784
        HashmapBase *copy;
3✔
1785
        int r;
3✔
1786

1787
        assert(h);
3✔
1788

1789
        copy = hashmap_base_new(h->hash_ops, h->type);
3✔
1790
        if (!copy)
3✔
1791
                return NULL;
1792

1793
        switch (h->type) {
3✔
1794
        case HASHMAP_TYPE_PLAIN:
2✔
1795
        case HASHMAP_TYPE_ORDERED:
1796
                r = hashmap_merge((Hashmap*)copy, (Hashmap*)h);
2✔
1797
                break;
2✔
1798
        case HASHMAP_TYPE_SET:
1✔
1799
                r = set_merge((Set*)copy, (Set*)h);
1✔
1800
                break;
1✔
1801
        default:
×
1802
                assert_not_reached();
×
1803
        }
1804

1805
        if (r < 0)
3✔
1806
                return _hashmap_free(copy);
×
1807

1808
        return copy;
1809
}
1810

1811
char** _hashmap_get_strv(HashmapBase *h) {
8,094✔
1812
        char **sv;
8,094✔
1813
        Iterator i;
8,094✔
1814
        unsigned idx, n;
8,094✔
1815

1816
        if (!h)
8,094✔
1817
                return new0(char*, 1);
8,050✔
1818

1819
        sv = new(char*, n_entries(h)+1);
44✔
1820
        if (!sv)
44✔
1821
                return NULL;
1822

1823
        n = 0;
44✔
1824
        HASHMAP_FOREACH_IDX(idx, h, i)
664✔
1825
                sv[n++] = entry_value(h, bucket_at(h, idx));
620✔
1826
        sv[n] = NULL;
44✔
1827

1828
        return sv;
44✔
1829
}
1830

1831
char** set_to_strv(Set **s) {
224✔
1832
        assert(s);
224✔
1833

1834
        /* This is similar to set_get_strv(), but invalidates the set on success. */
1835

1836
        char **v = new(char*, set_size(*s) + 1);
224✔
1837
        if (!v)
224✔
1838
                return NULL;
1839

1840
        for (char **p = v; (*p = set_steal_first(*s)); p++)
2,356✔
1841
                ;
1842

1843
        assert(set_isempty(*s));
224✔
1844
        *s = set_free(*s);
224✔
1845
        return v;
224✔
1846
}
1847

1848
void* ordered_hashmap_next(OrderedHashmap *h, const void *key) {
427✔
1849
        struct ordered_hashmap_entry *e;
427✔
1850
        unsigned hash, idx;
427✔
1851

1852
        if (!h)
427✔
1853
                return NULL;
1854

1855
        hash = bucket_hash(h, key);
426✔
1856
        idx = bucket_scan(h, hash, key);
426✔
1857
        if (idx == IDX_NIL)
426✔
1858
                return NULL;
1859

1860
        e = ordered_bucket_at(h, idx);
425✔
1861
        if (e->iterate_next == IDX_NIL)
425✔
1862
                return NULL;
1863
        return ordered_bucket_at(h, e->iterate_next)->p.value;
275✔
1864
}
1865

1866
int set_consume(Set *s, void *value) {
926,658✔
1867
        int r;
926,658✔
1868

1869
        assert(s);
926,658✔
1870
        assert(value);
926,658✔
1871

1872
        r = set_put(s, value);
926,658✔
1873
        if (r <= 0)
926,658✔
1874
                free(value);
1✔
1875

1876
        return r;
926,658✔
1877
}
1878

1879
int hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v) {
1,967✔
1880
        int r;
1,967✔
1881

1882
        assert(h);
1,967✔
1883

1884
        r = hashmap_ensure_allocated(h, hash_ops);
1,967✔
1885
        if (r < 0)
1,967✔
1886
                return r;
1,967✔
1887

1888
        _cleanup_free_ char *kdup = NULL, *vdup = NULL;
1,967✔
1889

1890
        kdup = strdup(k);
1,967✔
1891
        if (!kdup)
1,967✔
1892
                return -ENOMEM;
1893

1894
        if (v) {
1,967✔
1895
                vdup = strdup(v);
55✔
1896
                if (!vdup)
55✔
1897
                        return -ENOMEM;
1898
        }
1899

1900
        r = hashmap_put(*h, kdup, vdup);
1,967✔
1901
        if (r < 0) {
1,967✔
1902
                if (r == -EEXIST && streq_ptr(v, hashmap_get(*h, kdup)))
10✔
1903
                        return 0;
1904
                return r;
4✔
1905
        }
1906

1907
        /* 0 with non-null vdup would mean vdup is already in the hashmap, which cannot be */
1908
        assert(vdup == NULL || r > 0);
1,957✔
1909
        if (r > 0)
1,911✔
1910
                kdup = vdup = NULL;
1,956✔
1911

1912
        return r;
1913
}
1914

1915
int set_put_strndup_full(Set **s, const struct hash_ops *hash_ops, const char *p, size_t n) {
1,359,917✔
1916
        char *c;
1,359,917✔
1917
        int r;
1,359,917✔
1918

1919
        assert(s);
1,359,917✔
1920
        assert(p);
1,359,917✔
1921

1922
        r = set_ensure_allocated(s, hash_ops);
1,359,917✔
1923
        if (r < 0)
1,359,917✔
1924
                return r;
1925

1926
        if (n == SIZE_MAX) {
1,359,917✔
1927
                if (set_contains(*s, (char*) p))
1,335,016✔
1928
                        return 0;
1929

1930
                c = strdup(p);
893,496✔
1931
        } else
1932
                c = strndup(p, n);
24,901✔
1933
        if (!c)
918,397✔
1934
                return -ENOMEM;
1935

1936
        return set_consume(*s, c);
918,397✔
1937
}
1938

1939
int set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l) {
2,187✔
1940
        int n = 0, r;
2,187✔
1941

1942
        assert(s);
2,187✔
1943

1944
        STRV_FOREACH(i, l) {
2,249✔
1945
                r = set_put_strndup_full(s, hash_ops, *i, SIZE_MAX);
62✔
1946
                if (r < 0)
62✔
1947
                        return r;
1948

1949
                n += r;
62✔
1950
        }
1951

1952
        return n;
1953
}
1954

1955
int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) {
1✔
1956
        const char *p = ASSERT_PTR(v);
1✔
1957
        int r;
1✔
1958

1959
        assert(s);
1✔
1960

1961
        for (;;) {
2✔
1962
                char *word;
3✔
1963

1964
                r = extract_first_word(&p, &word, separators, flags);
3✔
1965
                if (r <= 0)
3✔
1966
                        return r;
1✔
1967

1968
                r = set_consume(s, word);
2✔
1969
                if (r < 0)
2✔
1970
                        return r;
1971
        }
1972
}
1973

1974
/* expand the cachemem if needed, return true if newly (re)activated. */
1975
static int cachemem_maintain(CacheMem *mem, size_t size) {
29,015,105✔
1976
        assert(mem);
29,015,105✔
1977

1978
        if (!GREEDY_REALLOC(mem->ptr, size)) {
29,015,105✔
1979
                if (size > 0)
×
1980
                        return -ENOMEM;
1981
        }
1982

1983
        if (!mem->active) {
29,015,105✔
1984
                mem->active = true;
2,905✔
1985
                return true;
2,905✔
1986
        }
1987

1988
        return false;
1989
}
1990

1991
int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries) {
29,014,993✔
1992
        bool sync_keys = false, sync_values = false;
29,014,993✔
1993
        size_t size;
29,014,993✔
1994
        int r;
29,014,993✔
1995

1996
        assert(cache);
29,014,993✔
1997
        assert(cache->hashmap);
29,014,993✔
1998

1999
        size = n_entries(cache->hashmap);
29,014,993✔
2000

2001
        if (res_keys) {
29,014,993✔
2002
                r = cachemem_maintain(&cache->keys, size);
112✔
2003
                if (r < 0)
112✔
2004
                        return r;
2005

2006
                sync_keys = r;
112✔
2007
        } else
2008
                cache->keys.active = false;
29,014,881✔
2009

2010
        if (res_values) {
29,014,993✔
2011
                r = cachemem_maintain(&cache->values, size);
29,014,993✔
2012
                if (r < 0)
29,014,993✔
2013
                        return r;
2014

2015
                sync_values = r;
29,014,993✔
2016
        } else
2017
                cache->values.active = false;
×
2018

2019
        if (cache->hashmap->dirty) {
29,014,993✔
2020
                if (cache->keys.active)
3,009✔
2021
                        sync_keys = true;
111✔
2022
                if (cache->values.active)
3,009✔
2023
                        sync_values = true;
3,009✔
2024

2025
                cache->hashmap->dirty = false;
3,009✔
2026
        }
2027

2028
        if (sync_keys || sync_values) {
29,014,993✔
2029
                unsigned i, idx;
3,015✔
2030
                Iterator iter;
3,015✔
2031

2032
                i = 0;
3,015✔
2033
                HASHMAP_FOREACH_IDX(idx, cache->hashmap, iter) {
508,888✔
2034
                        struct hashmap_base_entry *e;
505,873✔
2035

2036
                        e = bucket_at(cache->hashmap, idx);
505,873✔
2037

2038
                        if (sync_keys)
505,873✔
2039
                                cache->keys.ptr[i] = e->key;
491,500✔
2040
                        if (sync_values)
505,873✔
2041
                                cache->values.ptr[i] = entry_value(cache->hashmap, e);
505,873✔
2042
                        i++;
505,873✔
2043
                }
2044
        }
2045

2046
        if (res_keys)
29,014,993✔
2047
                *res_keys = cache->keys.ptr;
112✔
2048
        if (res_values)
29,014,993✔
2049
                *res_values = cache->values.ptr;
29,014,993✔
2050
        if (res_n_entries)
29,014,993✔
2051
                *res_n_entries = size;
29,014,993✔
2052

2053
        return 0;
2054
}
2055

2056
IteratedCache* iterated_cache_free(IteratedCache *cache) {
7,532✔
2057
        if (cache) {
7,532✔
2058
                free(cache->keys.ptr);
7,532✔
2059
                free(cache->values.ptr);
7,532✔
2060
        }
2061

2062
        return mfree(cache);
7,532✔
2063
}
2064

2065
int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret) {
706,682✔
2066
        _cleanup_free_ char *str = NULL;
706,682✔
2067
        size_t separator_len, len = 0;
706,682✔
2068
        const char *value;
706,682✔
2069
        bool first;
706,682✔
2070

2071
        assert(ret);
706,682✔
2072

2073
        if (set_isempty(s)) {
706,682✔
2074
                *ret = NULL;
21,513✔
2075
                return 0;
21,513✔
2076
        }
2077

2078
        separator_len = strlen_ptr(separator);
685,169✔
2079

2080
        if (separator_len == 0)
685,165✔
2081
                wrap_with_separator = false;
2082

2083
        first = !wrap_with_separator;
685,169✔
2084

2085
        SET_FOREACH(value, s) {
2,179,827✔
2086
                size_t l = strlen_ptr(value);
1,494,658✔
2087

2088
                if (l == 0)
1,494,658✔
2089
                        continue;
×
2090

2091
                if (!GREEDY_REALLOC(str, len + l + (first ? 0 : separator_len) + (wrap_with_separator ? separator_len : 0) + 1))
3,794,688✔
2092
                        return -ENOMEM;
×
2093

2094
                if (separator_len > 0 && !first) {
1,494,658✔
2095
                        memcpy(str + len, separator, separator_len);
1,229,064✔
2096
                        len += separator_len;
1,229,064✔
2097
                }
2098

2099
                memcpy(str + len, value, l);
1,494,658✔
2100
                len += l;
1,494,658✔
2101
                first = false;
1,494,658✔
2102
        }
2103

2104
        if (wrap_with_separator) {
685,169✔
2105
                memcpy(str + len, separator, separator_len);
419,579✔
2106
                len += separator_len;
419,579✔
2107
        }
2108

2109
        str[len] = '\0';
685,169✔
2110

2111
        *ret = TAKE_PTR(str);
685,169✔
2112
        return 0;
685,169✔
2113
}
2114

2115
bool set_equal(Set *a, Set *b) {
265✔
2116
        void *p;
265✔
2117

2118
        /* Checks whether each entry of 'a' is also in 'b' and vice versa, i.e. the two sets contain the same
2119
         * entries */
2120

2121
        if (a == b)
265✔
2122
                return true;
265✔
2123

2124
        if (set_isempty(a) && set_isempty(b))
49✔
2125
                return true;
2126

2127
        if (set_size(a) != set_size(b)) /* Cheap check that hopefully catches a lot of inequality cases
31✔
2128
                                         * already */
2129
                return false;
2130

2131
        SET_FOREACH(p, a)
2,535✔
2132
                if (!set_contains(b, p))
2,515✔
2133
                        return false;
×
2134

2135
        /* If we have the same hashops, then we don't need to check things backwards given we compared the
2136
         * size and that all of a is in b. */
2137
        if (a->b.hash_ops == b->b.hash_ops)
20✔
2138
                return true;
2139

2140
        SET_FOREACH(p, b)
×
2141
                if (!set_contains(a, p))
×
2142
                        return false;
×
2143

2144
        return true;
×
2145
}
2146

2147
static bool set_fnmatch_one(Set *patterns, const char *needle) {
741,970✔
2148
        const char *p;
741,970✔
2149

2150
        assert(needle);
741,970✔
2151

2152
        /* Any failure of fnmatch() is treated as equivalent to FNM_NOMATCH, i.e. as non-matching pattern */
2153

2154
        SET_FOREACH(p, patterns)
955,537✔
2155
                if (fnmatch(p, needle, 0) == 0)
261,752✔
2156
                        return true;
48,185✔
2157

2158
        return false;
693,785✔
2159
}
2160

2161
bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle) {
518,417✔
2162
        assert(needle);
518,417✔
2163

2164
        if (set_fnmatch_one(exclude_patterns, needle))
518,417✔
2165
                return false;
2166

2167
        if (set_isempty(include_patterns))
518,093✔
2168
                return true;
2169

2170
        return set_fnmatch_one(include_patterns, needle);
223,553✔
2171
}
2172

2173
static int hashmap_entry_compare(
770,750✔
2174
                struct hashmap_base_entry * const *a,
2175
                struct hashmap_base_entry * const *b,
2176
                compare_func_t compare) {
2177

2178
        assert(a && *a);
770,750✔
2179
        assert(b && *b);
770,750✔
2180
        assert(compare);
770,750✔
2181

2182
        return compare((*a)->key, (*b)->key);
770,750✔
2183
}
2184

2185
static int _hashmap_dump_entries_sorted(
156,035✔
2186
                HashmapBase *h,
2187
                void ***ret,
2188
                size_t *ret_n) {
2189
        _cleanup_free_ void **entries = NULL;
156,035✔
2190
        Iterator iter;
156,035✔
2191
        unsigned idx;
156,035✔
2192
        size_t n = 0;
156,035✔
2193

2194
        assert(ret);
156,035✔
2195
        assert(ret_n);
156,035✔
2196

2197
        if (_hashmap_size(h) == 0) {
156,035✔
2198
                *ret = NULL;
96,993✔
2199
                *ret_n = 0;
96,993✔
2200
                return 0;
96,993✔
2201
        }
2202

2203
        /* We append one more element than needed so that the resulting array can be used as a strv. We
2204
         * don't count this entry in the returned size. */
2205
        entries = new(void*, _hashmap_size(h) + 1);
59,042✔
2206
        if (!entries)
59,042✔
2207
                return -ENOMEM;
2208

2209
        HASHMAP_FOREACH_IDX(idx, h, iter)
316,681✔
2210
                entries[n++] = bucket_at(h, idx);
257,639✔
2211

2212
        assert(n == _hashmap_size(h));
59,042✔
2213
        entries[n] = NULL;
59,042✔
2214

2215
        typesafe_qsort_r((struct hashmap_base_entry**) entries, n,
59,042✔
2216
                         hashmap_entry_compare, h->hash_ops->compare);
2217

2218
        *ret = TAKE_PTR(entries);
59,042✔
2219
        *ret_n = n;
59,042✔
2220
        return 0;
59,042✔
2221
}
2222

2223
int _hashmap_dump_keys_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
741✔
2224
        _cleanup_free_ void **entries = NULL;
741✔
2225
        size_t n;
741✔
2226
        int r;
741✔
2227

2228
        assert(ret);
741✔
2229

2230
        r = _hashmap_dump_entries_sorted(h, &entries, &n);
741✔
2231
        if (r < 0)
741✔
2232
                return r;
2233

2234
        /* Reuse the array. */
2235
        FOREACH_ARRAY(e, entries, n)
5,163✔
2236
                *e = (void*) (*(struct hashmap_base_entry**) e)->key;
4,422✔
2237

2238
        *ret = TAKE_PTR(entries);
741✔
2239
        if (ret_n)
741✔
2240
                *ret_n = n;
741✔
2241
        return 0;
2242
}
2243

2244
int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
155,294✔
2245
        _cleanup_free_ void **entries = NULL;
155,294✔
2246
        size_t n;
155,294✔
2247
        int r;
155,294✔
2248

2249
        assert(ret);
155,294✔
2250

2251
        r = _hashmap_dump_entries_sorted(h, &entries, &n);
155,294✔
2252
        if (r < 0)
155,294✔
2253
                return r;
2254

2255
        /* Reuse the array. */
2256
        FOREACH_ARRAY(e, entries, n)
408,511✔
2257
                *e = entry_value(h, *(struct hashmap_base_entry**) e);
253,217✔
2258

2259
        *ret = TAKE_PTR(entries);
155,294✔
2260
        if (ret_n)
155,294✔
2261
                *ret_n = n;
152,604✔
2262
        return 0;
2263
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc