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

systemd / systemd / 28306446002

27 Jun 2026 06:45PM UTC coverage: 72.925% (+0.03%) from 72.893%
28306446002

push

github

web-flow
journal: replace libgcrypt with openssl (#42695)

800 of 835 new or added lines in 16 files covered. (95.81%)

1519 existing lines in 40 files now uncovered.

341631 of 468466 relevant lines covered (72.93%)

1329899.91 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) {
2,008,179,983✔
303
        assert(h);
2,008,179,983✔
304
        return h->has_indirect ? h->indirect.n_buckets
2,008,179,983✔
305
                               : hashmap_type_info[h->type].n_direct_buckets;
2,008,179,983✔
306
}
307

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

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

317
        if (h->has_indirect)
48,827,027✔
318
                h->indirect.n_entries++;
40,202,651✔
319
        else
320
                h->n_direct_entries++;
8,624,376✔
321
}
48,827,027✔
322

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

326
        if (h->has_indirect)
44,167,616✔
327
                h->indirect.n_entries--;
38,054,997✔
328
        else
329
                h->n_direct_entries--;
6,112,619✔
330
}
44,167,616✔
331

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

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

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

348
        assert(h);
313,505,593✔
349

350
        siphash24_init(&state, hash_key(h));
313,505,593✔
351

352
        h->hash_ops->hash(p, &state);
313,505,593✔
353

354
        hash = siphash24_finalize(&state);
313,505,593✔
355

356
        return (unsigned) (hash % n_buckets(h));
313,505,593✔
357
}
358
#define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p)
359

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

363
        h->dirty = true;
98,656,135✔
364
}
98,656,135✔
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,794,091✔
368
        static uint8_t current[HASH_KEY_SIZE];
3,794,091✔
369
        static bool current_initialized = false;
3,794,091✔
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,794,091✔
379
                random_bytes(current, sizeof(current));
2,311,869✔
380
                current_initialized = true;
2,311,869✔
381
        }
382

383
        memcpy(hash_key, current, sizeof(current));
3,794,091✔
384
}
3,794,091✔
385

386
static struct hashmap_base_entry* bucket_at(HashmapBase *h, unsigned idx) {
1,120,741,666✔
387
        assert(h);
1,120,741,666✔
388
        return CAST_ALIGN_PTR(
1,120,741,666✔
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,648,146✔
394
        return (struct plain_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
2,648,146✔
395
}
396

397
static struct ordered_hashmap_entry* ordered_bucket_at(OrderedHashmap *h, unsigned idx) {
89,059,376✔
398
        return (struct ordered_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
89,059,376✔
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) {
449,022,106✔
406
        assert(swap);
449,022,106✔
407
        return &swap->e[idx - _IDX_SWAP_BEGIN];
449,022,106✔
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,
729,738,448✔
413
                                                    unsigned idx) {
414
        if (idx < _IDX_SWAP_BEGIN)
729,738,448✔
415
                return bucket_at(h, idx);
389,613,439✔
416

417
        if (idx < _IDX_SWAP_END)
340,125,009✔
418
                return &bucket_at_swap(swap, idx)->p.b;
340,125,009✔
419

420
        assert_not_reached();
×
421
}
422

423
static dib_raw_t* dib_raw_ptr(HashmapBase *h) {
709,166,264✔
424
        assert(h);
709,166,264✔
425
        return (dib_raw_t*)
1,418,332,528✔
426
                ((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h));
709,166,264✔
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) {
434,832,226✔
435
        unsigned initial_bucket;
434,832,226✔
436

437
        if (raw_dib == DIB_RAW_FREE)
434,832,226✔
438
                return DIB_FREE;
439

440
        if (_likely_(raw_dib < DIB_RAW_OVERFLOW))
434,832,226✔
441
                return raw_dib;
434,832,226✔
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) {
202,479,154✔
458
        dib_raw_ptr(h)[idx] = dib != DIB_FREE ? MIN(dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE;
202,479,154✔
459
}
202,479,154✔
460

461
static unsigned skip_free_buckets(HashmapBase *h, unsigned idx) {
101,260,204✔
462
        dib_raw_t *dibs;
101,260,204✔
463

464
        dibs = dib_raw_ptr(h);
101,260,204✔
465

466
        for ( ; idx < n_buckets(h); idx++)
306,152,035✔
467
                if (dibs[idx] != DIB_RAW_FREE)
184,314,009✔
468
                        return idx;
469

470
        return IDX_NIL;
471
}
472

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

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

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

484
        assert(h);
302,434,681✔
485
        assert(from != to);
302,434,681✔
486

487
        e_from = bucket_at_virtual(h, swap, from);
302,434,681✔
488
        e_to   = bucket_at_virtual(h, swap, to);
302,434,681✔
489

490
        memcpy(e_to, e_from, hashmap_type_info[h->type].entry_size);
302,434,681✔
491

492
        if (h->type == HASHMAP_TYPE_ORDERED) {
302,434,681✔
493
                OrderedHashmap *lh = (OrderedHashmap*) h;
77,747,797✔
494
                struct ordered_hashmap_entry *le, *le_to;
77,747,797✔
495

496
                le_to = (struct ordered_hashmap_entry*) e_to;
77,747,797✔
497

498
                if (le_to->iterate_next != IDX_NIL) {
77,747,797✔
499
                        le = (struct ordered_hashmap_entry*)
56,016,186✔
500
                             bucket_at_virtual(h, swap, le_to->iterate_next);
56,016,186✔
501
                        le->iterate_previous = to;
56,016,186✔
502
                }
503

504
                if (le_to->iterate_previous != IDX_NIL) {
77,747,797✔
505
                        le = (struct ordered_hashmap_entry*)
68,852,900✔
506
                             bucket_at_virtual(h, swap, le_to->iterate_previous);
68,852,900✔
507
                        le->iterate_next = to;
68,852,900✔
508
                }
509

510
                if (lh->iterate_list_head == from)
77,747,797✔
511
                        lh->iterate_list_head = to;
8,894,897✔
512
                if (lh->iterate_list_tail == from)
77,747,797✔
513
                        lh->iterate_list_tail = to;
21,731,611✔
514
        }
515
}
302,434,681✔
516

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

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

525
static void* entry_value(HashmapBase *h, struct hashmap_base_entry *e) {
206,838,363✔
526
        assert(h);
206,838,363✔
527
        assert(e);
206,838,363✔
528

529
        switch (h->type) {
206,838,363✔
530

531
        case HASHMAP_TYPE_PLAIN:
184,968,724✔
532
        case HASHMAP_TYPE_ORDERED:
533
                return ((struct plain_hashmap_entry*)e)->value;
184,968,724✔
534

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

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

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

547
        dibs = dib_raw_ptr(h);
44,167,616✔
548
        assert(dibs[idx] != DIB_RAW_FREE);
44,167,616✔
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,167,616✔
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,167,616✔
559
                raw_dib = dibs[right];
61,257,849✔
560
                if (IN_SET(raw_dib, 0, DIB_RAW_FREE))
61,257,849✔
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,090,233✔
567
        }
568

569
        if (h->type == HASHMAP_TYPE_ORDERED) {
44,167,616✔
570
                OrderedHashmap *lh = (OrderedHashmap*) h;
15,780,136✔
571
                struct ordered_hashmap_entry *le = ordered_bucket_at(lh, idx);
15,780,136✔
572

573
                if (le->iterate_next != IDX_NIL)
15,780,136✔
574
                        ordered_bucket_at(lh, le->iterate_next)->iterate_previous = le->iterate_previous;
14,321,053✔
575
                else
576
                        lh->iterate_list_tail = le->iterate_previous;
1,459,083✔
577

578
                if (le->iterate_previous != IDX_NIL)
15,780,136✔
579
                        ordered_bucket_at(lh, le->iterate_previous)->iterate_next = le->iterate_next;
14,053✔
580
                else
581
                        lh->iterate_list_head = le->iterate_next;
15,766,083✔
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,257,849✔
586
             prev = left, left = next_idx(h, left)) {
17,090,233✔
587
                dib = bucket_calculate_dib(h, left, dibs[left]);
17,090,233✔
588
                assert(dib != 0);
17,090,233✔
589
                bucket_move_entry(h, NULL, left, prev);
17,090,233✔
590
                bucket_set_dib(h, prev, dib - 1);
17,090,233✔
591
        }
592

593
        bucket_mark_free(h, prev);
44,167,616✔
594
        n_entries_dec(h);
44,167,616✔
595
        base_set_dirty(h);
44,167,616✔
596
}
44,167,616✔
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,859,986✔
600
        struct ordered_hashmap_entry *e;
24,859,986✔
601
        unsigned idx;
24,859,986✔
602

603
        assert(h);
24,859,986✔
604
        assert(i);
24,859,986✔
605

606
        if (i->idx == IDX_NIL)
24,859,986✔
607
                goto at_end;
743,887✔
608

609
        if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL)
24,116,099✔
610
                goto at_end;
860,331✔
611

612
        if (i->idx == IDX_FIRST) {
23,255,768✔
613
                idx = h->iterate_list_head;
16,496,309✔
614
                e = ordered_bucket_at(h, idx);
16,496,309✔
615
        } else {
616
                idx = i->idx;
6,759,459✔
617
                e = ordered_bucket_at(h, idx);
6,759,459✔
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,759,459✔
625
                        idx = prev_idx(HASHMAP_BASE(h), idx);
80✔
626
                        e = ordered_bucket_at(h, idx);
80✔
627
                }
628
                assert(e->p.b.key == i->next_key);
6,759,459✔
629
        }
630

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

635
        if (e->iterate_next != IDX_NIL) {
23,255,768✔
636
                struct ordered_hashmap_entry *n;
21,090,666✔
637
                i->idx = e->iterate_next;
21,090,666✔
638
                n = ordered_bucket_at(h, i->idx);
21,090,666✔
639
                i->next_key = n->p.b.key;
21,090,666✔
640
        } else
641
                i->idx = IDX_NIL;
2,165,102✔
642

643
        return idx;
644

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

650
static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) {
77,846,953✔
651
        unsigned idx;
77,846,953✔
652

653
        assert(h);
77,846,953✔
654
        assert(i);
77,846,953✔
655

656
        if (i->idx == IDX_NIL)
77,846,953✔
657
                goto at_end;
4,982,240✔
658

659
        if (i->idx == IDX_FIRST) {
72,864,713✔
660
                /* fast forward to the first occupied bucket */
661
                if (h->has_indirect) {
29,057,478✔
662
                        i->idx = skip_free_buckets(h, h->indirect.idx_lowest_entry);
10,417,498✔
663
                        h->indirect.idx_lowest_entry = i->idx;
10,417,498✔
664
                } else
665
                        i->idx = skip_free_buckets(h, 0);
18,639,980✔
666

667
                if (i->idx == IDX_NIL)
29,057,478✔
668
                        goto at_end;
661,987✔
669
        } else {
670
                struct hashmap_base_entry *e;
43,807,235✔
671

672
                assert(i->idx > 0);
43,807,235✔
673

674
                e = bucket_at(h, i->idx);
43,807,235✔
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,807,235✔
682
                        e = bucket_at(h, --i->idx);
31,927✔
683

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

687
        idx = i->idx;
72,202,726✔
688
#if ENABLE_DEBUG_HASHMAP
689
        i->prev_idx = idx;
690
#endif
691

692
        i->idx = skip_free_buckets(h, i->idx + 1);
72,202,726✔
693
        if (i->idx != IDX_NIL)
72,202,726✔
694
                i->next_key = bucket_at(h, i->idx)->key;
52,286,891✔
695
        else
696
                i->idx = IDX_NIL;
19,915,835✔
697

698
        return idx;
699

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

705
static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
120,903,779✔
706
        if (!h) {
120,903,779✔
707
                i->idx = IDX_NIL;
18,196,840✔
708
                return IDX_NIL;
18,196,840✔
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,859,986✔
728
                                               : hashmap_iterate_in_internal_order(h, i);
102,706,939✔
729
}
730

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

736
        idx = hashmap_iterate_entry(h, i);
93,667,566✔
737
        if (idx == IDX_NIL) {
93,667,566✔
738
                if (value)
25,379,910✔
739
                        *value = NULL;
24,125,195✔
740
                if (key)
25,379,910✔
741
                        *key = NULL;
5,846,299✔
742

743
                return false;
744
        }
745

746
        e = bucket_at(h, idx);
68,287,656✔
747
        data = entry_value(h, e);
68,287,656✔
748
        if (value)
68,287,656✔
749
                *value = data;
45,181,996✔
750
        if (key)
68,287,656✔
751
                *key = e->key;
40,395,824✔
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,526✔
762
        IteratedCache *cache;
7,526✔
763

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

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

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

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

777
        return cache;
7,526✔
778
}
779

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

784
        assert(!h->has_indirect);
8,922,798✔
785

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

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

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

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

800
        h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
4,559,594✔
801
        if (!h)
4,474,439✔
802
                return NULL;
803

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

808
        if (type == HASHMAP_TYPE_ORDERED) {
4,474,439✔
809
                OrderedHashmap *lh = (OrderedHashmap*)h;
1,171,939✔
810
                lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
1,171,939✔
811
        }
812

813
        reset_direct_storage(h);
4,474,439✔
814

815
        static pthread_once_t once = PTHREAD_ONCE_INIT;
4,474,439✔
816
        assert_se(pthread_once(&once, shared_hash_key_initialize) == 0);
4,474,439✔
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) {
901,378✔
828
        return (Hashmap*)        hashmap_base_new(hash_ops, HASHMAP_TYPE_PLAIN);
901,378✔
829
}
830

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

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

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

843
        assert(h);
42,640,008✔
844

845
        if (*h) {
42,640,008✔
846
                assert((*h)->hash_ops == (hash_ops ?: &trivial_hash_ops));
42,561,688✔
847
                return 0;
848
        }
849

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

854
        *h = q;
3,373,786✔
855
        return 1;
3,373,786✔
856
}
857

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

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

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

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

873
        assert(h);
6,304,868✔
874

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

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

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

885
        assert(h);
3,653,261✔
886

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

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

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

897
        assert(h);
6,256✔
898

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

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

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

909
        assert(h);
26,979✔
910

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

915
        return hashmap_replace(*h, key, value);
26,979✔
916
}
917

918
static void hashmap_free_no_clear(HashmapBase *h) {
4,425,319✔
919
        assert(!h->has_indirect);
4,425,319✔
920
        assert(h->n_direct_entries == 0);
4,425,319✔
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,425,319✔
929
                /* Ensure that the object didn't get migrated between threads. */
930
                assert_se(is_main_thread());
4,340,772✔
931
                mempool_free_tile(hashmap_type_info[h->type].mempool, h);
4,340,772✔
932
        } else
933
                free(h);
84,547✔
934
}
4,425,319✔
935

936
HashmapBase* _hashmap_free(HashmapBase *h) {
17,134,689✔
937
        if (h) {
17,134,689✔
938
                _hashmap_clear(h);
4,425,319✔
939
                hashmap_free_no_clear(h);
4,425,319✔
940
        }
941

942
        return NULL;
17,134,689✔
943
}
944

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

949
        if (h->hash_ops->free_key || h->hash_ops->free_value) {
4,448,359✔
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,495,857✔
956
                        void *k = NULL;
20,347,405✔
957
                        void *v;
20,347,405✔
958

959
                        v = _hashmap_first_key_and_value(h, true, &k);
20,347,405✔
960

961
                        if (h->hash_ops->free_key)
20,347,405✔
962
                                h->hash_ops->free_key(k);
15,770,871✔
963

964
                        if (h->hash_ops->free_value)
20,347,405✔
965
                                h->hash_ops->free_value(v);
17,795,773✔
966
                }
967
        }
968

969
        if (h->has_indirect) {
4,448,359✔
970
                free(h->indirect.storage);
1,506,269✔
971
                h->has_indirect = false;
1,506,269✔
972
        }
973

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

977
        if (h->type == HASHMAP_TYPE_ORDERED) {
4,448,359✔
978
                OrderedHashmap *lh = (OrderedHashmap*) h;
1,167,564✔
979
                lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
1,167,564✔
980
        }
981

982
        base_set_dirty(h);
4,448,359✔
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,
100,735,483✔
997
                                   struct swap_entries *swap) {
998
        dib_raw_t raw_dib, *dibs;
100,735,483✔
999
        unsigned dib, distance;
100,735,483✔
1000

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

1006
        dibs = dib_raw_ptr(h);
100,735,483✔
1007

1008
        for (distance = 0; ; distance++) {
100,735,483✔
1009
                raw_dib = dibs[idx];
201,169,725✔
1010
                if (IN_SET(raw_dib, DIB_RAW_FREE, DIB_RAW_REHASH)) {
201,169,725✔
1011
                        if (raw_dib == DIB_RAW_REHASH)
100,735,483✔
1012
                                bucket_move_entry(h, swap, idx, IDX_TMP);
11,243,043✔
1013

1014
                        if (h->has_indirect && h->indirect.idx_lowest_entry > idx)
100,735,483✔
1015
                                h->indirect.idx_lowest_entry = idx;
36,139✔
1016

1017
                        bucket_set_dib(h, idx, distance);
100,735,483✔
1018
                        bucket_move_entry(h, swap, IDX_PUT, idx);
100,735,483✔
1019
                        if (raw_dib == DIB_RAW_REHASH) {
100,735,483✔
1020
                                bucket_move_entry(h, swap, IDX_TMP, IDX_PUT);
11,243,043✔
1021
                                return true;
11,243,043✔
1022
                        }
1023

1024
                        return false;
1025
                }
1026

1027
                dib = bucket_calculate_dib(h, idx, raw_dib);
100,434,242✔
1028

1029
                if (dib < distance) {
100,434,242✔
1030
                        /* Found a wealthier entry. Go Robin Hood! */
1031
                        bucket_set_dib(h, idx, distance);
40,485,822✔
1032

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

1038
                        distance = dib;
40,485,822✔
1039
                }
1040

1041
                idx = next_idx(h, idx);
100,434,242✔
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,827,027✔
1056
                                   struct swap_entries *swap, bool may_resize) {
1057
        struct ordered_hashmap_entry *new_entry;
48,827,027✔
1058
        int r;
48,827,027✔
1059

1060
        assert(idx < n_buckets(h));
48,827,027✔
1061

1062
        new_entry = bucket_at_swap(swap, IDX_PUT);
48,827,027✔
1063

1064
        if (may_resize) {
48,827,027✔
1065
                r = resize_buckets(h, 1);
48,822,322✔
1066
                if (r < 0)
48,822,322✔
1067
                        return r;
1068
                if (r > 0)
48,822,322✔
1069
                        idx = bucket_hash(h, new_entry->p.b.key);
3,790,623✔
1070
        }
1071
        assert(n_entries(h) < n_buckets(h));
48,827,027✔
1072

1073
        if (h->type == HASHMAP_TYPE_ORDERED) {
48,827,027✔
1074
                OrderedHashmap *lh = (OrderedHashmap*) h;
16,067,256✔
1075

1076
                new_entry->iterate_next = IDX_NIL;
16,067,256✔
1077
                new_entry->iterate_previous = lh->iterate_list_tail;
16,067,256✔
1078

1079
                if (lh->iterate_list_tail != IDX_NIL) {
16,067,256✔
1080
                        struct ordered_hashmap_entry *old_tail;
14,596,923✔
1081

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

1087
                lh->iterate_list_tail = IDX_PUT;
16,067,256✔
1088
                if (lh->iterate_list_head == IDX_NIL)
16,067,256✔
1089
                        lh->iterate_list_head = IDX_PUT;
1,470,333✔
1090
        }
1091

1092
        assert_se(hashmap_put_robin_hood(h, idx, swap) == false);
48,827,027✔
1093

1094
        n_entries_inc(h);
48,827,027✔
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,827,027✔
1100

1101
        return 1;
48,827,027✔
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,835,139✔
1112
        struct swap_entries swap;
48,835,139✔
1113
        void *new_storage;
48,835,139✔
1114
        dib_raw_t *old_dibs, *new_dibs;
48,835,139✔
1115
        const struct hashmap_type_info *hi;
48,835,139✔
1116
        unsigned idx, optimal_idx;
48,835,139✔
1117
        unsigned old_n_buckets, new_n_buckets, n_rehashed, new_n_entries;
48,835,139✔
1118
        uint8_t new_shift;
48,835,139✔
1119
        bool rehash_next;
48,835,139✔
1120

1121
        assert(h);
48,835,139✔
1122

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

1126
        /* overflow? */
1127
        if (_unlikely_(new_n_entries < entries_add))
48,835,139✔
1128
                return -ENOMEM;
48,835,139✔
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,835,137✔
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,210,981✔
1139
        /* overflow? */
1140
        if (_unlikely_(new_n_buckets < new_n_entries))
40,210,981✔
1141
                return -ENOMEM;
1142

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

1146
        old_n_buckets = n_buckets(h);
40,210,979✔
1147

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

1151
        new_shift = log2u_round_up(MAX(
3,794,091✔
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,269,857✔
1157
                              1U << new_shift);
3,794,091✔
1158
        if (!new_storage)
3,794,091✔
1159
                return -ENOMEM;
1160

1161
        /* Must upgrade direct to indirect storage. */
1162
        if (!h->has_indirect) {
3,794,091✔
1163
                memcpy(new_storage, h->direct.storage,
1,524,234✔
1164
                       old_n_buckets * (hi->entry_size + sizeof(dib_raw_t)));
1,524,234✔
1165
                h->indirect.n_entries = h->n_direct_entries;
1,524,234✔
1166
                h->indirect.idx_lowest_entry = 0;
1,524,234✔
1167
                h->n_direct_entries = 0;
1,524,234✔
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,794,091✔
1174

1175
        h->has_indirect = true;
3,794,091✔
1176
        h->indirect.storage = new_storage;
3,794,091✔
1177
        h->indirect.n_buckets = (1U << new_shift) /
3,794,091✔
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,794,091✔
1181
        new_dibs = dib_raw_ptr(h);
3,794,091✔
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,301,404✔
1190
                assert(old_dibs[idx] != DIB_RAW_REHASH);
65,507,313✔
1191
                new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE
118,492,567✔
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,794,091✔
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,588,182✔
1201
               (n_buckets(h) - old_n_buckets) * sizeof(dib_raw_t));
3,794,091✔
1202

1203
        /* Rehash entries that need it */
1204
        n_rehashed = 0;
3,794,091✔
1205
        for (idx = 0; idx < old_n_buckets; idx++) {
69,301,404✔
1206
                if (new_dibs[idx] != DIB_RAW_REHASH)
65,507,313✔
1207
                        continue;
23,765,102✔
1208

1209
                optimal_idx = bucket_hash(h, bucket_at(h, idx)->key);
41,742,211✔
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,742,211✔
1216
                        new_dibs[idx] = 0;
1,076,798✔
1217
                        n_rehashed++;
1,076,798✔
1218
                        continue;
1,076,798✔
1219
                }
1220

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

1226
                do {
51,908,456✔
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);
51,908,456✔
1232
                        n_rehashed++;
51,908,456✔
1233

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

1240
        assert_se(n_rehashed == n_entries(h));
3,794,091✔
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) {
256,729,716✔
1250
        struct hashmap_base_entry *e;
256,729,716✔
1251
        unsigned dib, distance;
256,729,716✔
1252
        dib_raw_t *dibs = dib_raw_ptr(h);
256,729,716✔
1253

1254
        assert(idx < n_buckets(h));
256,729,716✔
1255

1256
        for (distance = 0; ; distance++) {
155,482,584✔
1257
                if (dibs[idx] == DIB_RAW_FREE)
412,212,300✔
1258
                        return IDX_NIL;
1259

1260
                dib = bucket_calculate_dib(h, idx, dibs[idx]);
317,307,751✔
1261

1262
                if (dib < distance)
317,307,751✔
1263
                        return IDX_NIL;
1264
                if (dib == distance) {
271,221,673✔
1265
                        e = bucket_at(h, idx);
206,075,426✔
1266
                        if (h->hash_ops->compare(e->key, key) == 0)
206,075,426✔
1267
                                return idx;
1268
                }
1269

1270
                idx = next_idx(h, idx);
155,482,584✔
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,878,980✔
1276
        struct swap_entries swap;
15,878,980✔
1277
        struct plain_hashmap_entry *e;
15,878,980✔
1278
        unsigned hash, idx;
15,878,980✔
1279

1280
        assert(h);
15,878,980✔
1281

1282
        hash = bucket_hash(h, key);
15,878,980✔
1283
        idx = bucket_scan(h, hash, key);
15,878,980✔
1284
        if (idx != IDX_NIL) {
15,878,980✔
1285
                e = plain_bucket_at(h, idx);
340,950✔
1286
                if (e->value == value)
340,950✔
1287
                        return 0;
15,878,980✔
1288
                return -EEXIST;
38,530✔
1289
        }
1290

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

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

1302
        assert(s);
18,700,529✔
1303

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

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

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

1317
        assert(s);
16,780,798✔
1318

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

1323
        return set_put(*s, key);
16,780,798✔
1324
}
1325

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

1329
        r = set_ensure_put(s, hash_ops, key);
1,465,430✔
1330
        if (r <= 0) {
1,465,430✔
1331
                if (hash_ops && hash_ops->free_key)
1,042✔
1332
                        hash_ops->free_key(key);
1,042✔
1333
                else
1334
                        free(key);
×
1335
        }
1336

1337
        return r;
1,465,430✔
1338
}
1339

1340
int hashmap_replace(Hashmap *h, const void *key, void *value) {
15,773,510✔
1341
        struct swap_entries swap;
15,773,510✔
1342
        struct plain_hashmap_entry *e;
15,773,510✔
1343
        unsigned hash, idx;
15,773,510✔
1344

1345
        assert(h);
15,773,510✔
1346

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

1365
                return 0;
1,174,303✔
1366
        }
1367

1368
        e = &bucket_at_swap(&swap, IDX_PUT)->p;
14,599,207✔
1369
        e->b.key = key;
14,599,207✔
1370
        e->value = value;
14,599,207✔
1371
        return hashmap_put_boldly(h, hash, &swap, true);
14,599,207✔
1372
}
1373

1374
int hashmap_update(Hashmap *h, const void *key, void *value) {
38,832✔
1375
        struct plain_hashmap_entry *e;
38,832✔
1376
        unsigned hash, idx;
38,832✔
1377

1378
        assert(h);
38,832✔
1379

1380
        hash = bucket_hash(h, key);
38,832✔
1381
        idx = bucket_scan(h, hash, key);
38,832✔
1382
        if (idx == IDX_NIL)
38,832✔
1383
                return -ENOENT;
1384

1385
        e = plain_bucket_at(h, idx);
38,830✔
1386
        e->value = value;
38,830✔
1387
        hashmap_set_dirty(h);
38,830✔
1388

1389
        return 0;
38,830✔
1390
}
1391

1392
void* _hashmap_get(HashmapBase *h, const void *key) {
132,950,407✔
1393
        struct hashmap_base_entry *e;
132,950,407✔
1394
        unsigned hash, idx;
132,950,407✔
1395

1396
        if (!h)
132,950,407✔
1397
                return NULL;
1398

1399
        hash = bucket_hash(h, key);
123,741,344✔
1400
        idx = bucket_scan(h, hash, key);
123,741,344✔
1401
        if (idx == IDX_NIL)
123,741,344✔
1402
                return NULL;
1403

1404
        e = bucket_at(h, idx);
93,186,632✔
1405
        return entry_value(h, e);
93,186,632✔
1406
}
1407

1408
void* hashmap_get2(Hashmap *h, const void *key, void **ret) {
13,280,914✔
1409
        struct plain_hashmap_entry *e;
13,280,914✔
1410
        unsigned hash, idx;
13,280,914✔
1411

1412
        if (!h)
13,280,914✔
1413
                return NULL;
1414

1415
        hash = bucket_hash(h, key);
13,280,883✔
1416
        idx = bucket_scan(h, hash, key);
13,280,883✔
1417
        if (idx == IDX_NIL)
13,280,883✔
1418
                return NULL;
1419

1420
        e = plain_bucket_at(h, idx);
1,082,802✔
1421
        if (ret)
1,082,802✔
1422
                *ret = (void*) e->b.key;
1,082,802✔
1423

1424
        return e->value;
1,082,802✔
1425
}
1426

1427
bool _hashmap_contains(HashmapBase *h, const void *key) {
43,651,535✔
1428
        unsigned hash;
43,651,535✔
1429

1430
        if (!h)
43,651,535✔
1431
                return false;
1432

1433
        hash = bucket_hash(h, key);
42,416,615✔
1434
        return bucket_scan(h, hash, key) != IDX_NIL;
42,416,615✔
1435
}
1436

1437
void* _hashmap_remove(HashmapBase *h, const void *key) {
26,746,051✔
1438
        struct hashmap_base_entry *e;
26,746,051✔
1439
        unsigned hash, idx;
26,746,051✔
1440
        void *data;
26,746,051✔
1441

1442
        if (!h)
26,746,051✔
1443
                return NULL;
1444

1445
        hash = bucket_hash(h, key);
25,508,503✔
1446
        idx = bucket_scan(h, hash, key);
25,508,503✔
1447
        if (idx == IDX_NIL)
25,508,503✔
1448
                return NULL;
1449

1450
        e = bucket_at(h, idx);
17,405,407✔
1451
        data = entry_value(h, e);
17,405,407✔
1452
        remove_entry(h, idx);
17,405,407✔
1453

1454
        return data;
17,405,407✔
1455
}
1456

1457
void* hashmap_remove2(Hashmap *h, const void *key, void **ret) {
608,932✔
1458
        struct plain_hashmap_entry *e;
608,932✔
1459
        unsigned hash, idx;
608,932✔
1460
        void *data;
608,932✔
1461

1462
        if (!h) {
608,932✔
1463
                if (ret)
92,805✔
1464
                        *ret = NULL;
92,805✔
1465
                return NULL;
1466
        }
1467

1468
        hash = bucket_hash(h, key);
516,127✔
1469
        idx = bucket_scan(h, hash, key);
516,127✔
1470
        if (idx == IDX_NIL) {
516,127✔
1471
                if (ret)
504,878✔
1472
                        *ret = NULL;
504,878✔
1473
                return NULL;
1474
        }
1475

1476
        e = plain_bucket_at(h, idx);
11,249✔
1477
        data = e->value;
11,249✔
1478
        if (ret)
11,249✔
1479
                *ret = (void*) e->b.key;
11,249✔
1480

1481
        remove_entry(h, idx);
11,249✔
1482

1483
        return data;
11,249✔
1484
}
1485

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

1491
        if (!h)
10✔
1492
                return -ENOENT;
10✔
1493

1494
        old_hash = bucket_hash(h, old_key);
8✔
1495
        idx = bucket_scan(h, old_hash, old_key);
8✔
1496
        if (idx == IDX_NIL)
8✔
1497
                return -ENOENT;
1498

1499
        new_hash = bucket_hash(h, new_key);
6✔
1500
        if (bucket_scan(h, new_hash, new_key) != IDX_NIL)
6✔
1501
                return -EEXIST;
1502

1503
        remove_entry(h, idx);
4✔
1504

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

1510
        return 0;
1511
}
1512

1513
int set_remove_and_put(Set *s, const void *old_key, const void *new_key) {
1,294✔
1514
        struct swap_entries swap;
1,294✔
1515
        struct hashmap_base_entry *e;
1,294✔
1516
        unsigned old_hash, new_hash, idx;
1,294✔
1517

1518
        if (!s)
1,294✔
1519
                return -ENOENT;
1,294✔
1520

1521
        old_hash = bucket_hash(s, old_key);
1,294✔
1522
        idx = bucket_scan(s, old_hash, old_key);
1,294✔
1523
        if (idx == IDX_NIL)
1,294✔
1524
                return -ENOENT;
1525

1526
        new_hash = bucket_hash(s, new_key);
1,294✔
1527
        if (bucket_scan(s, new_hash, new_key) != IDX_NIL)
1,294✔
1528
                return -EEXIST;
1529

1530
        remove_entry(s, idx);
1,294✔
1531

1532
        e = &bucket_at_swap(&swap, IDX_PUT)->p.b;
1,294✔
1533
        e->key = new_key;
1,294✔
1534
        assert_se(hashmap_put_boldly(s, new_hash, &swap, false) == 1);
1,294✔
1535

1536
        return 0;
1537
}
1538

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

1544
        if (!h)
48✔
1545
                return -ENOENT;
48✔
1546

1547
        old_hash = bucket_hash(h, old_key);
46✔
1548
        idx_old = bucket_scan(h, old_hash, old_key);
46✔
1549
        if (idx_old == IDX_NIL)
46✔
1550
                return -ENOENT;
1551

1552
        old_key = bucket_at(HASHMAP_BASE(h), idx_old)->key;
44✔
1553

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

1565
        remove_entry(h, idx_old);
44✔
1566

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

1572
        return 0;
1573
}
1574

1575
void* _hashmap_remove_value(HashmapBase *h, const void *key, void *value) {
860,835✔
1576
        struct hashmap_base_entry *e;
860,835✔
1577
        unsigned hash, idx;
860,835✔
1578

1579
        if (!h)
860,835✔
1580
                return NULL;
1581

1582
        hash = bucket_hash(h, key);
860,708✔
1583
        idx = bucket_scan(h, hash, key);
860,708✔
1584
        if (idx == IDX_NIL)
860,708✔
1585
                return NULL;
1586

1587
        e = bucket_at(h, idx);
795,648✔
1588
        if (entry_value(h, e) != value)
795,648✔
1589
                return NULL;
1590

1591
        remove_entry(h, idx);
795,327✔
1592

1593
        return value;
795,327✔
1594
}
1595

1596
static unsigned find_first_entry(HashmapBase *h) {
28,360,405✔
1597
        Iterator i = ITERATOR_FIRST;
28,360,405✔
1598

1599
        if (!h || !n_entries(h))
28,360,405✔
1600
                return IDX_NIL;
28,360,405✔
1601

1602
        return hashmap_iterate_entry(h, &i);
26,404,052✔
1603
}
1604

1605
void* _hashmap_first_key_and_value(HashmapBase *h, bool remove, void **ret_key) {
28,360,405✔
1606
        struct hashmap_base_entry *e;
28,360,405✔
1607
        void *key, *data;
28,360,405✔
1608
        unsigned idx;
28,360,405✔
1609

1610
        idx = find_first_entry(h);
28,360,405✔
1611
        if (idx == IDX_NIL) {
28,360,405✔
1612
                if (ret_key)
1,956,353✔
1613
                        *ret_key = NULL;
1,018,887✔
1614
                return NULL;
1615
        }
1616

1617
        e = bucket_at(h, idx);
26,404,052✔
1618
        key = (void*) e->key;
26,404,052✔
1619
        data = entry_value(h, e);
26,404,052✔
1620

1621
        if (remove)
26,404,052✔
1622
                remove_entry(h, idx);
25,947,288✔
1623

1624
        if (ret_key)
26,404,052✔
1625
                *ret_key = key;
21,579,555✔
1626

1627
        return data;
1628
}
1629

1630
unsigned _hashmap_size(HashmapBase *h) {
71,318,399✔
1631
        if (!h)
71,318,399✔
1632
                return 0;
1633

1634
        return n_entries(h);
33,139,711✔
1635
}
1636

1637
unsigned _hashmap_buckets(HashmapBase *h) {
661✔
1638
        if (!h)
661✔
1639
                return 0;
1640

1641
        return n_buckets(h);
658✔
1642
}
1643

1644
int _hashmap_merge(Hashmap *h, Hashmap *other) {
4✔
1645
        Iterator i;
4✔
1646
        unsigned idx;
4✔
1647

1648
        assert(h);
4✔
1649

1650
        HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) {
16✔
1651
                struct plain_hashmap_entry *pe = plain_bucket_at(other, idx);
12✔
1652
                int r;
12✔
1653

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

1659
        return 0;
1660
}
1661

1662
int set_merge(Set *s, Set *other) {
1✔
1663
        Iterator i;
1✔
1664
        unsigned idx;
1✔
1665

1666
        assert(s);
1✔
1667

1668
        HASHMAP_FOREACH_IDX(idx, HASHMAP_BASE(other), i) {
5✔
1669
                struct set_entry *se = set_bucket_at(other, idx);
4✔
1670
                int r;
4✔
1671

1672
                r = set_put(s, se->b.key);
4✔
1673
                if (r < 0)
4✔
1674
                        return r;
1675
        }
1676

1677
        return 0;
1678
}
1679

1680
int _hashmap_reserve(HashmapBase *h, unsigned entries_add) {
9,472✔
1681
        int r;
9,472✔
1682

1683
        assert(h);
9,472✔
1684

1685
        r = resize_buckets(h, entries_add);
9,472✔
1686
        if (r < 0)
9,472✔
1687
                return r;
4✔
1688

1689
        return 0;
1690
}
1691

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

1705
        assert(h);
3,348✔
1706

1707
        if (!other)
3,348✔
1708
                return 0;
3,348✔
1709

1710
        assert(other->type == h->type);
3,345✔
1711

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

1722
        HASHMAP_FOREACH_IDX(idx, other, i) {
6,710✔
1723
                unsigned h_hash;
3,365✔
1724

1725
                e = bucket_at(other, idx);
3,365✔
1726
                h_hash = bucket_hash(h, e->key);
3,365✔
1727
                if (bucket_scan(h, h_hash, e->key) != IDX_NIL)
3,365✔
1728
                        continue;
2✔
1729

1730
                n = &bucket_at_swap(&swap, IDX_PUT)->p.b;
3,363✔
1731
                n->key = e->key;
3,363✔
1732
                if (h->type != HASHMAP_TYPE_SET)
3,363✔
1733
                        ((struct plain_hashmap_entry*) n)->value =
3,232✔
1734
                                ((struct plain_hashmap_entry*) e)->value;
3,232✔
1735
                assert_se(hashmap_put_boldly(h, h_hash, &swap, false) == 1);
3,363✔
1736

1737
                remove_entry(other, idx);
3,363✔
1738
        }
1739

1740
        return 0;
1741
}
1742

1743
int _hashmap_move_one(HashmapBase *h, HashmapBase *other, const void *key) {
3,604✔
1744
        struct swap_entries swap;
3,604✔
1745
        unsigned h_hash, other_hash, idx;
3,604✔
1746
        struct hashmap_base_entry *e, *n;
3,604✔
1747
        int r;
3,604✔
1748

1749
        assert(h);
3,604✔
1750

1751
        h_hash = bucket_hash(h, key);
3,604✔
1752
        if (bucket_scan(h, h_hash, key) != IDX_NIL)
3,604✔
1753
                return -EEXIST;
3,604✔
1754

1755
        if (!other)
3,602✔
1756
                return -ENOENT;
1757

1758
        assert(other->type == h->type);
3,600✔
1759

1760
        other_hash = bucket_hash(other, key);
3,600✔
1761
        idx = bucket_scan(other, other_hash, key);
3,600✔
1762
        if (idx == IDX_NIL)
3,600✔
1763
                return -ENOENT;
1764

1765
        e = bucket_at(other, idx);
3,598✔
1766

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

1776
        remove_entry(other, idx);
3,598✔
1777
        return 0;
1778
}
1779

1780
HashmapBase* _hashmap_copy(HashmapBase *h) {
3✔
1781
        HashmapBase *copy;
3✔
1782
        int r;
3✔
1783

1784
        assert(h);
3✔
1785

1786
        copy = hashmap_base_new(h->hash_ops, h->type);
3✔
1787
        if (!copy)
3✔
1788
                return NULL;
1789

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

1802
        if (r < 0)
3✔
1803
                return _hashmap_free(copy);
×
1804

1805
        return copy;
1806
}
1807

1808
char** _hashmap_get_strv(HashmapBase *h) {
7,996✔
1809
        char **sv;
7,996✔
1810
        Iterator i;
7,996✔
1811
        unsigned idx, n;
7,996✔
1812

1813
        if (!h)
7,996✔
1814
                return new0(char*, 1);
7,952✔
1815

1816
        sv = new(char*, n_entries(h)+1);
44✔
1817
        if (!sv)
44✔
1818
                return NULL;
1819

1820
        n = 0;
44✔
1821
        HASHMAP_FOREACH_IDX(idx, h, i)
660✔
1822
                sv[n++] = entry_value(h, bucket_at(h, idx));
616✔
1823
        sv[n] = NULL;
44✔
1824

1825
        return sv;
44✔
1826
}
1827

1828
char** set_to_strv(Set **s) {
202✔
1829
        assert(s);
202✔
1830

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

1833
        char **v = new(char*, set_size(*s) + 1);
202✔
1834
        if (!v)
202✔
1835
                return NULL;
1836

1837
        for (char **p = v; (*p = set_steal_first(*s)); p++)
2,306✔
1838
                ;
1839

1840
        assert(set_isempty(*s));
202✔
1841
        *s = set_free(*s);
202✔
1842
        return v;
202✔
1843
}
1844

1845
void* ordered_hashmap_next(OrderedHashmap *h, const void *key) {
425✔
1846
        struct ordered_hashmap_entry *e;
425✔
1847
        unsigned hash, idx;
425✔
1848

1849
        if (!h)
425✔
1850
                return NULL;
1851

1852
        hash = bucket_hash(h, key);
424✔
1853
        idx = bucket_scan(h, hash, key);
424✔
1854
        if (idx == IDX_NIL)
424✔
1855
                return NULL;
1856

1857
        e = ordered_bucket_at(h, idx);
423✔
1858
        if (e->iterate_next == IDX_NIL)
423✔
1859
                return NULL;
1860
        return ordered_bucket_at(h, e->iterate_next)->p.value;
274✔
1861
}
1862

1863
int set_consume(Set *s, void *value) {
917,286✔
1864
        int r;
917,286✔
1865

1866
        assert(s);
917,286✔
1867
        assert(value);
917,286✔
1868

1869
        r = set_put(s, value);
917,286✔
1870
        if (r <= 0)
917,286✔
1871
                free(value);
1✔
1872

1873
        return r;
917,286✔
1874
}
1875

1876
int hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const char *k, const char *v) {
1,953✔
1877
        int r;
1,953✔
1878

1879
        assert(h);
1,953✔
1880

1881
        r = hashmap_ensure_allocated(h, hash_ops);
1,953✔
1882
        if (r < 0)
1,953✔
1883
                return r;
1,953✔
1884

1885
        _cleanup_free_ char *kdup = NULL, *vdup = NULL;
1,953✔
1886

1887
        kdup = strdup(k);
1,953✔
1888
        if (!kdup)
1,953✔
1889
                return -ENOMEM;
1890

1891
        if (v) {
1,953✔
1892
                vdup = strdup(v);
54✔
1893
                if (!vdup)
54✔
1894
                        return -ENOMEM;
1895
        }
1896

1897
        r = hashmap_put(*h, kdup, vdup);
1,953✔
1898
        if (r < 0) {
1,953✔
1899
                if (r == -EEXIST && streq_ptr(v, hashmap_get(*h, kdup)))
10✔
1900
                        return 0;
1901
                return r;
4✔
1902
        }
1903

1904
        /* 0 with non-null vdup would mean vdup is already in the hashmap, which cannot be */
1905
        assert(vdup == NULL || r > 0);
1,943✔
1906
        if (r > 0)
1,898✔
1907
                kdup = vdup = NULL;
1,942✔
1908

1909
        return r;
1910
}
1911

1912
int set_put_strndup_full(Set **s, const struct hash_ops *hash_ops, const char *p, size_t n) {
1,342,854✔
1913
        char *c;
1,342,854✔
1914
        int r;
1,342,854✔
1915

1916
        assert(s);
1,342,854✔
1917
        assert(p);
1,342,854✔
1918

1919
        r = set_ensure_allocated(s, hash_ops);
1,342,854✔
1920
        if (r < 0)
1,342,854✔
1921
                return r;
1922

1923
        if (n == SIZE_MAX) {
1,342,854✔
1924
                if (set_contains(*s, (char*) p))
1,317,953✔
1925
                        return 0;
1926

1927
                c = strdup(p);
884,200✔
1928
        } else
1929
                c = strndup(p, n);
24,901✔
1930
        if (!c)
909,101✔
1931
                return -ENOMEM;
1932

1933
        return set_consume(*s, c);
909,101✔
1934
}
1935

1936
int set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l) {
2,138✔
1937
        int n = 0, r;
2,138✔
1938

1939
        assert(s);
2,138✔
1940

1941
        STRV_FOREACH(i, l) {
2,181✔
1942
                r = set_put_strndup_full(s, hash_ops, *i, SIZE_MAX);
43✔
1943
                if (r < 0)
43✔
1944
                        return r;
1945

1946
                n += r;
43✔
1947
        }
1948

1949
        return n;
1950
}
1951

1952
int set_put_strsplit(Set *s, const char *v, const char *separators, ExtractFlags flags) {
1✔
1953
        const char *p = ASSERT_PTR(v);
1✔
1954
        int r;
1✔
1955

1956
        assert(s);
1✔
1957

1958
        for (;;) {
2✔
1959
                char *word;
3✔
1960

1961
                r = extract_first_word(&p, &word, separators, flags);
3✔
1962
                if (r <= 0)
3✔
1963
                        return r;
1✔
1964

1965
                r = set_consume(s, word);
2✔
1966
                if (r < 0)
2✔
1967
                        return r;
1968
        }
1969
}
1970

1971
/* expand the cachemem if needed, return true if newly (re)activated. */
1972
static int cachemem_maintain(CacheMem *mem, size_t size) {
29,294,334✔
1973
        assert(mem);
29,294,334✔
1974

1975
        if (!GREEDY_REALLOC(mem->ptr, size)) {
29,294,334✔
1976
                if (size > 0)
×
1977
                        return -ENOMEM;
1978
        }
1979

1980
        if (!mem->active) {
29,294,334✔
1981
                mem->active = true;
2,900✔
1982
                return true;
2,900✔
1983
        }
1984

1985
        return false;
1986
}
1987

1988
int iterated_cache_get(IteratedCache *cache, const void ***res_keys, const void ***res_values, unsigned *res_n_entries) {
29,294,222✔
1989
        bool sync_keys = false, sync_values = false;
29,294,222✔
1990
        size_t size;
29,294,222✔
1991
        int r;
29,294,222✔
1992

1993
        assert(cache);
29,294,222✔
1994
        assert(cache->hashmap);
29,294,222✔
1995

1996
        size = n_entries(cache->hashmap);
29,294,222✔
1997

1998
        if (res_keys) {
29,294,222✔
1999
                r = cachemem_maintain(&cache->keys, size);
112✔
2000
                if (r < 0)
112✔
2001
                        return r;
2002

2003
                sync_keys = r;
112✔
2004
        } else
2005
                cache->keys.active = false;
29,294,110✔
2006

2007
        if (res_values) {
29,294,222✔
2008
                r = cachemem_maintain(&cache->values, size);
29,294,222✔
2009
                if (r < 0)
29,294,222✔
2010
                        return r;
2011

2012
                sync_values = r;
29,294,222✔
2013
        } else
2014
                cache->values.active = false;
×
2015

2016
        if (cache->hashmap->dirty) {
29,294,222✔
2017
                if (cache->keys.active)
3,007✔
2018
                        sync_keys = true;
111✔
2019
                if (cache->values.active)
3,007✔
2020
                        sync_values = true;
3,007✔
2021

2022
                cache->hashmap->dirty = false;
3,007✔
2023
        }
2024

2025
        if (sync_keys || sync_values) {
29,294,222✔
2026
                unsigned i, idx;
3,010✔
2027
                Iterator iter;
3,010✔
2028

2029
                i = 0;
3,010✔
2030
                HASHMAP_FOREACH_IDX(idx, cache->hashmap, iter) {
509,031✔
2031
                        struct hashmap_base_entry *e;
506,021✔
2032

2033
                        e = bucket_at(cache->hashmap, idx);
506,021✔
2034

2035
                        if (sync_keys)
506,021✔
2036
                                cache->keys.ptr[i] = e->key;
491,500✔
2037
                        if (sync_values)
506,021✔
2038
                                cache->values.ptr[i] = entry_value(cache->hashmap, e);
506,021✔
2039
                        i++;
506,021✔
2040
                }
2041
        }
2042

2043
        if (res_keys)
29,294,222✔
2044
                *res_keys = cache->keys.ptr;
112✔
2045
        if (res_values)
29,294,222✔
2046
                *res_values = cache->values.ptr;
29,294,222✔
2047
        if (res_n_entries)
29,294,222✔
2048
                *res_n_entries = size;
29,294,222✔
2049

2050
        return 0;
2051
}
2052

2053
IteratedCache* iterated_cache_free(IteratedCache *cache) {
7,526✔
2054
        if (cache) {
7,526✔
2055
                free(cache->keys.ptr);
7,526✔
2056
                free(cache->values.ptr);
7,526✔
2057
        }
2058

2059
        return mfree(cache);
7,526✔
2060
}
2061

2062
int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret) {
700,254✔
2063
        _cleanup_free_ char *str = NULL;
700,254✔
2064
        size_t separator_len, len = 0;
700,254✔
2065
        const char *value;
700,254✔
2066
        bool first;
700,254✔
2067

2068
        assert(ret);
700,254✔
2069

2070
        if (set_isempty(s)) {
700,254✔
2071
                *ret = NULL;
21,643✔
2072
                return 0;
21,643✔
2073
        }
2074

2075
        separator_len = strlen_ptr(separator);
678,611✔
2076

2077
        if (separator_len == 0)
678,607✔
2078
                wrap_with_separator = false;
2079

2080
        first = !wrap_with_separator;
678,611✔
2081

2082
        SET_FOREACH(value, s) {
2,152,767✔
2083
                size_t l = strlen_ptr(value);
1,474,156✔
2084

2085
                if (l == 0)
1,474,156✔
2086
                        continue;
×
2087

2088
                if (!GREEDY_REALLOC(str, len + l + (first ? 0 : separator_len) + (wrap_with_separator ? separator_len : 0) + 1))
3,739,621✔
2089
                        return -ENOMEM;
×
2090

2091
                if (separator_len > 0 && !first) {
1,474,156✔
2092
                        memcpy(str + len, separator, separator_len);
1,211,388✔
2093
                        len += separator_len;
1,211,388✔
2094
                }
2095

2096
                memcpy(str + len, value, l);
1,474,156✔
2097
                len += l;
1,474,156✔
2098
                first = false;
1,474,156✔
2099
        }
2100

2101
        if (wrap_with_separator) {
678,611✔
2102
                memcpy(str + len, separator, separator_len);
415,847✔
2103
                len += separator_len;
415,847✔
2104
        }
2105

2106
        str[len] = '\0';
678,611✔
2107

2108
        *ret = TAKE_PTR(str);
678,611✔
2109
        return 0;
678,611✔
2110
}
2111

2112
bool set_equal(Set *a, Set *b) {
265✔
2113
        void *p;
265✔
2114

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

2118
        if (a == b)
265✔
2119
                return true;
265✔
2120

2121
        if (set_isempty(a) && set_isempty(b))
49✔
2122
                return true;
2123

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

2128
        SET_FOREACH(p, a)
2,584✔
2129
                if (!set_contains(b, p))
2,564✔
2130
                        return false;
×
2131

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

2137
        SET_FOREACH(p, b)
×
2138
                if (!set_contains(a, p))
×
2139
                        return false;
×
2140

2141
        return true;
×
2142
}
2143

2144
static bool set_fnmatch_one(Set *patterns, const char *needle) {
733,657✔
2145
        const char *p;
733,657✔
2146

2147
        assert(needle);
733,657✔
2148

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

2151
        SET_FOREACH(p, patterns)
946,584✔
2152
                if (fnmatch(p, needle, 0) == 0)
260,889✔
2153
                        return true;
47,962✔
2154

2155
        return false;
685,695✔
2156
}
2157

2158
bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle) {
510,937✔
2159
        assert(needle);
510,937✔
2160

2161
        if (set_fnmatch_one(exclude_patterns, needle))
510,937✔
2162
                return false;
2163

2164
        if (set_isempty(include_patterns))
510,613✔
2165
                return true;
2166

2167
        return set_fnmatch_one(include_patterns, needle);
222,720✔
2168
}
2169

2170
static int hashmap_entry_compare(
766,892✔
2171
                struct hashmap_base_entry * const *a,
2172
                struct hashmap_base_entry * const *b,
2173
                compare_func_t compare) {
2174

2175
        assert(a && *a);
766,892✔
2176
        assert(b && *b);
766,892✔
2177
        assert(compare);
766,892✔
2178

2179
        return compare((*a)->key, (*b)->key);
766,892✔
2180
}
2181

2182
static int _hashmap_dump_entries_sorted(
154,850✔
2183
                HashmapBase *h,
2184
                void ***ret,
2185
                size_t *ret_n) {
2186
        _cleanup_free_ void **entries = NULL;
154,850✔
2187
        Iterator iter;
154,850✔
2188
        unsigned idx;
154,850✔
2189
        size_t n = 0;
154,850✔
2190

2191
        assert(ret);
154,850✔
2192
        assert(ret_n);
154,850✔
2193

2194
        if (_hashmap_size(h) == 0) {
154,850✔
2195
                *ret = NULL;
95,879✔
2196
                *ret_n = 0;
95,879✔
2197
                return 0;
95,879✔
2198
        }
2199

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

2206
        HASHMAP_FOREACH_IDX(idx, h, iter)
315,739✔
2207
                entries[n++] = bucket_at(h, idx);
256,768✔
2208

2209
        assert(n == _hashmap_size(h));
58,971✔
2210
        entries[n] = NULL;
58,971✔
2211

2212
        typesafe_qsort_r((struct hashmap_base_entry**) entries, n,
58,971✔
2213
                         hashmap_entry_compare, h->hash_ops->compare);
2214

2215
        *ret = TAKE_PTR(entries);
58,971✔
2216
        *ret_n = n;
58,971✔
2217
        return 0;
58,971✔
2218
}
2219

2220
int _hashmap_dump_keys_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
742✔
2221
        _cleanup_free_ void **entries = NULL;
742✔
2222
        size_t n;
742✔
2223
        int r;
742✔
2224

2225
        assert(ret);
742✔
2226

2227
        r = _hashmap_dump_entries_sorted(h, &entries, &n);
742✔
2228
        if (r < 0)
742✔
2229
                return r;
2230

2231
        /* Reuse the array. */
2232
        FOREACH_ARRAY(e, entries, n)
5,179✔
2233
                *e = (void*) (*(struct hashmap_base_entry**) e)->key;
4,437✔
2234

2235
        *ret = TAKE_PTR(entries);
742✔
2236
        if (ret_n)
742✔
2237
                *ret_n = n;
742✔
2238
        return 0;
2239
}
2240

2241
int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
154,108✔
2242
        _cleanup_free_ void **entries = NULL;
154,108✔
2243
        size_t n;
154,108✔
2244
        int r;
154,108✔
2245

2246
        assert(ret);
154,108✔
2247

2248
        r = _hashmap_dump_entries_sorted(h, &entries, &n);
154,108✔
2249
        if (r < 0)
154,108✔
2250
                return r;
2251

2252
        /* Reuse the array. */
2253
        FOREACH_ARRAY(e, entries, n)
406,439✔
2254
                *e = entry_value(h, *(struct hashmap_base_entry**) e);
252,331✔
2255

2256
        *ret = TAKE_PTR(entries);
154,108✔
2257
        if (ret_n)
154,108✔
2258
                *ret_n = n;
151,423✔
2259
        return 0;
2260
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc