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

systemd / systemd / 29461261567

15 Jul 2026 04:59PM UTC coverage: 72.983% (+0.05%) from 72.936%
29461261567

push

github

yuwata
tpm2-util: keep the measurement log's torn-write marker intact

The userspace measurement log carries a sticky-bit marker while a writer
is between updating a measurement register and appending the matching
record, so that a writer dying in between leaves the log detectably
incomplete.

However, the next successful writer used to clear the marker again after
appending its own record, erasing the evidence that an earlier writer
had died and the log is still missing a record. Keep the marker set in
that case instead; the new record is appended and synced regardless. The
marker likewise stays set if the measurement itself fails, so that any
non-clean completion remains flagged: a spurious flag on a failed but
harmless measurement is preferable to erasing evidence of a real gap,
and PCR replay stays authoritative either way.

Finally, warn when systemd-pcrlock loads a marked log, so the resulting
PCR validation failures come with a hint at their cause.

Signed-off-by: Paul Meyer <katexochen0@gmail.com>

11 of 12 new or added lines in 2 files covered. (91.67%)

2475 existing lines in 54 files now uncovered.

346100 of 474222 relevant lines covered (72.98%)

1321758.71 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,032,893,563✔
303
        assert(h);
2,032,893,563✔
304
        return h->has_indirect ? h->indirect.n_buckets
2,032,893,563✔
305
                               : hashmap_type_info[h->type].n_direct_buckets;
2,032,893,563✔
306
}
307

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

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

317
        if (h->has_indirect)
48,889,454✔
318
                h->indirect.n_entries++;
40,365,015✔
319
        else
320
                h->n_direct_entries++;
8,524,439✔
321
}
48,889,454✔
322

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

326
        if (h->has_indirect)
44,188,863✔
327
                h->indirect.n_entries--;
38,209,798✔
328
        else
329
                h->n_direct_entries--;
5,979,065✔
330
}
44,188,863✔
331

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

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

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

348
        assert(h);
315,816,761✔
349

350
        siphash24_init(&state, hash_key(h));
315,816,761✔
351

352
        h->hash_ops->hash(p, &state);
315,816,761✔
353

354
        hash = siphash24_finalize(&state);
315,816,761✔
355

356
        return (unsigned) (hash % n_buckets(h));
315,816,761✔
357
}
358
#define bucket_hash(h, p) base_bucket_hash(HASHMAP_BASE(h), p)
359

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

363
        h->dirty = true;
98,825,329✔
364
}
98,825,329✔
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,843,647✔
368
        static uint8_t current[HASH_KEY_SIZE];
3,843,647✔
369
        static bool current_initialized = false;
3,843,647✔
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,843,647✔
379
                random_bytes(current, sizeof(current));
2,335,118✔
380
                current_initialized = true;
2,335,118✔
381
        }
382

383
        memcpy(hash_key, current, sizeof(current));
3,843,647✔
384
}
3,843,647✔
385

386
static struct hashmap_base_entry* bucket_at(HashmapBase *h, unsigned idx) {
1,128,993,211✔
387
        assert(h);
1,128,993,211✔
388
        return CAST_ALIGN_PTR(
1,128,993,211✔
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,679,496✔
394
        return (struct plain_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
2,679,496✔
395
}
396

397
static struct ordered_hashmap_entry* ordered_bucket_at(OrderedHashmap *h, unsigned idx) {
89,361,682✔
398
        return (struct ordered_hashmap_entry*) bucket_at(HASHMAP_BASE(h), idx);
89,361,682✔
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) {
450,063,918✔
406
        assert(swap);
450,063,918✔
407
        return &swap->e[idx - _IDX_SWAP_BEGIN];
450,063,918✔
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,
731,108,966✔
413
                                                    unsigned idx) {
414
        if (idx < _IDX_SWAP_BEGIN)
731,108,966✔
415
                return bucket_at(h, idx);
390,134,624✔
416

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

420
        assert_not_reached();
×
421
}
422

423
static dib_raw_t* dib_raw_ptr(HashmapBase *h) {
716,595,333✔
424
        assert(h);
716,595,333✔
425
        return (dib_raw_t*)
1,433,190,666✔
426
                ((uint8_t*) storage_ptr(h) + hashmap_type_info[h->type].entry_size * n_buckets(h));
716,595,333✔
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) {
439,074,936✔
435
        unsigned initial_bucket;
439,074,936✔
436

437
        if (raw_dib == DIB_RAW_FREE)
439,074,936✔
438
                return DIB_FREE;
439

440
        if (_likely_(raw_dib < DIB_RAW_OVERFLOW))
439,074,936✔
441
                return raw_dib;
439,074,936✔
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,935,803✔
458
        dib_raw_ptr(h)[idx] = dib != DIB_FREE ? MIN(dib, DIB_RAW_OVERFLOW) : DIB_RAW_FREE;
202,935,803✔
459
}
202,935,803✔
460

461
static unsigned skip_free_buckets(HashmapBase *h, unsigned idx) {
105,852,741✔
462
        dib_raw_t *dibs;
105,852,741✔
463

464
        dibs = dib_raw_ptr(h);
105,852,741✔
465

466
        for ( ; idx < n_buckets(h); idx++)
320,326,968✔
467
                if (dibs[idx] != DIB_RAW_FREE)
191,988,691✔
468
                        return idx;
469

470
        return IDX_NIL;
471
}
472

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

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

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

484
        assert(h);
303,331,399✔
485
        assert(from != to);
303,331,399✔
486

487
        e_from = bucket_at_virtual(h, swap, from);
303,331,399✔
488
        e_to   = bucket_at_virtual(h, swap, to);
303,331,399✔
489

490
        memcpy(e_to, e_from, hashmap_type_info[h->type].entry_size);
303,331,399✔
491

492
        if (h->type == HASHMAP_TYPE_ORDERED) {
303,331,399✔
493
                OrderedHashmap *lh = (OrderedHashmap*) h;
77,677,391✔
494
                struct ordered_hashmap_entry *le, *le_to;
77,677,391✔
495

496
                le_to = (struct ordered_hashmap_entry*) e_to;
77,677,391✔
497

498
                if (le_to->iterate_next != IDX_NIL) {
77,677,391✔
499
                        le = (struct ordered_hashmap_entry*)
55,783,065✔
500
                             bucket_at_virtual(h, swap, le_to->iterate_next);
55,783,065✔
501
                        le->iterate_previous = to;
55,783,065✔
502
                }
503

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

510
                if (lh->iterate_list_head == from)
77,677,391✔
511
                        lh->iterate_list_head = to;
9,014,288✔
512
                if (lh->iterate_list_tail == from)
77,677,391✔
513
                        lh->iterate_list_tail = to;
21,894,326✔
514
        }
515
}
303,331,399✔
516

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

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

525
static void* entry_value(HashmapBase *h, struct hashmap_base_entry *e) {
210,538,287✔
526
        assert(h);
210,538,287✔
527
        assert(e);
210,538,287✔
528

529
        switch (h->type) {
210,538,287✔
530

531
        case HASHMAP_TYPE_PLAIN:
188,554,367✔
532
        case HASHMAP_TYPE_ORDERED:
533
                return ((struct plain_hashmap_entry*)e)->value;
188,554,367✔
534

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

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

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

547
        dibs = dib_raw_ptr(h);
44,188,863✔
548
        assert(dibs[idx] != DIB_RAW_FREE);
44,188,863✔
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,188,863✔
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,188,863✔
559
                raw_dib = dibs[right];
61,297,003✔
560
                if (IN_SET(raw_dib, 0, DIB_RAW_FREE))
61,297,003✔
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,108,140✔
567
        }
568

569
        if (h->type == HASHMAP_TYPE_ORDERED) {
44,188,863✔
570
                OrderedHashmap *lh = (OrderedHashmap*) h;
15,821,762✔
571
                struct ordered_hashmap_entry *le = ordered_bucket_at(lh, idx);
15,821,762✔
572

573
                if (le->iterate_next != IDX_NIL)
15,821,762✔
574
                        ordered_bucket_at(lh, le->iterate_next)->iterate_previous = le->iterate_previous;
14,322,393✔
575
                else
576
                        lh->iterate_list_tail = le->iterate_previous;
1,499,369✔
577

578
                if (le->iterate_previous != IDX_NIL)
15,821,762✔
579
                        ordered_bucket_at(lh, le->iterate_previous)->iterate_next = le->iterate_next;
14,991✔
580
                else
581
                        lh->iterate_list_head = le->iterate_next;
15,806,771✔
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,297,003✔
586
             prev = left, left = next_idx(h, left)) {
17,108,140✔
587
                dib = bucket_calculate_dib(h, left, dibs[left]);
17,108,140✔
588
                assert(dib != 0);
17,108,140✔
589
                bucket_move_entry(h, NULL, left, prev);
17,108,140✔
590
                bucket_set_dib(h, prev, dib - 1);
17,108,140✔
591
        }
592

593
        bucket_mark_free(h, prev);
44,188,863✔
594
        n_entries_dec(h);
44,188,863✔
595
        base_set_dirty(h);
44,188,863✔
596
}
44,188,863✔
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) {
25,059,346✔
600
        struct ordered_hashmap_entry *e;
25,059,346✔
601
        unsigned idx;
25,059,346✔
602

603
        assert(h);
25,059,346✔
604
        assert(i);
25,059,346✔
605

606
        if (i->idx == IDX_NIL)
25,059,346✔
607
                goto at_end;
774,587✔
608

609
        if (i->idx == IDX_FIRST && h->iterate_list_head == IDX_NIL)
24,284,759✔
610
                goto at_end;
868,242✔
611

612
        if (i->idx == IDX_FIRST) {
23,416,517✔
613
                idx = h->iterate_list_head;
16,568,752✔
614
                e = ordered_bucket_at(h, idx);
16,568,752✔
615
        } else {
616
                idx = i->idx;
6,847,765✔
617
                e = ordered_bucket_at(h, idx);
6,847,765✔
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,847,765✔
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,847,765✔
629
        }
630

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

635
        if (e->iterate_next != IDX_NIL) {
23,416,517✔
636
                struct ordered_hashmap_entry *n;
21,181,022✔
637
                i->idx = e->iterate_next;
21,181,022✔
638
                n = ordered_bucket_at(h, i->idx);
21,181,022✔
639
                i->next_key = n->p.b.key;
21,181,022✔
640
        } else
641
                i->idx = IDX_NIL;
2,235,495✔
642

643
        return idx;
644

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

650
static unsigned hashmap_iterate_in_internal_order(HashmapBase *h, Iterator *i) {
81,069,660✔
651
        unsigned idx;
81,069,660✔
652

653
        assert(h);
81,069,660✔
654
        assert(i);
81,069,660✔
655

656
        if (i->idx == IDX_NIL)
81,069,660✔
657
                goto at_end;
5,050,875✔
658

659
        if (i->idx == IDX_FIRST) {
76,018,785✔
660
                /* fast forward to the first occupied bucket */
661
                if (h->has_indirect) {
30,953,683✔
662
                        i->idx = skip_free_buckets(h, h->indirect.idx_lowest_entry);
10,458,593✔
663
                        h->indirect.idx_lowest_entry = i->idx;
10,458,593✔
664
                } else
665
                        i->idx = skip_free_buckets(h, 0);
20,495,090✔
666

667
                if (i->idx == IDX_NIL)
30,953,683✔
668
                        goto at_end;
1,119,727✔
669
        } else {
670
                struct hashmap_base_entry *e;
45,065,102✔
671

672
                assert(i->idx > 0);
45,065,102✔
673

674
                e = bucket_at(h, i->idx);
45,065,102✔
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)
45,065,102✔
682
                        e = bucket_at(h, --i->idx);
31,968✔
683

684
                assert(e->key == i->next_key);
45,065,102✔
685
        }
686

687
        idx = i->idx;
74,899,058✔
688
#if ENABLE_DEBUG_HASHMAP
689
        i->prev_idx = idx;
690
#endif
691

692
        i->idx = skip_free_buckets(h, i->idx + 1);
74,899,058✔
693
        if (i->idx != IDX_NIL)
74,899,058✔
694
                i->next_key = bucket_at(h, i->idx)->key;
53,533,249✔
695
        else
696
                i->idx = IDX_NIL;
21,365,809✔
697

698
        return idx;
699

700
at_end:
6,170,602✔
701
        i->idx = IDX_NIL;
6,170,602✔
702
        return IDX_NIL;
6,170,602✔
703
}
704

705
static unsigned hashmap_iterate_entry(HashmapBase *h, Iterator *i) {
124,209,859✔
706
        if (!h) {
124,209,859✔
707
                i->idx = IDX_NIL;
18,080,853✔
708
                return IDX_NIL;
18,080,853✔
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)
25,059,346✔
728
                                               : hashmap_iterate_in_internal_order(h, i);
106,129,006✔
729
}
730

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

736
        idx = hashmap_iterate_entry(h, i);
96,877,513✔
737
        if (idx == IDX_NIL) {
96,877,513✔
738
                if (value)
25,828,700✔
739
                        *value = NULL;
24,081,679✔
740
                if (key)
25,828,700✔
741
                        *key = NULL;
6,889,352✔
742

743
                return false;
744
        }
745

746
        e = bucket_at(h, idx);
71,048,813✔
747
        data = entry_value(h, e);
71,048,813✔
748
        if (value)
71,048,813✔
749
                *value = data;
45,324,226✔
750
        if (key)
71,048,813✔
751
                *key = e->key;
43,313,965✔
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,550✔
762
        IteratedCache *cache;
7,550✔
763

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

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

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

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

777
        return cache;
7,550✔
778
}
779

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

784
        assert(!h->has_indirect);
9,077,216✔
785

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

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

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

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

800
        h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size);
4,637,066✔
801
        if (!h)
4,551,841✔
802
                return NULL;
803

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

808
        if (type == HASHMAP_TYPE_ORDERED) {
4,551,841✔
809
                OrderedHashmap *lh = (OrderedHashmap*)h;
1,215,164✔
810
                lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
1,215,164✔
811
        }
812

813
        reset_direct_storage(h);
4,551,841✔
814

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

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

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

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

843
        assert(h);
42,701,548✔
844

845
        if (*h) {
42,701,548✔
846
                assert((*h)->hash_ops == (hash_ops ?: &trivial_hash_ops));
42,411,812✔
847
                return 0;
848
        }
849

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

854
        *h = q;
3,435,491✔
855
        return 1;
3,435,491✔
856
}
857

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

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

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

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

873
        assert(h);
6,154,501✔
874

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

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

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

885
        assert(h);
3,487,829✔
886

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

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

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

897
        assert(h);
6,901✔
898

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

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

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

909
        assert(h);
80,951✔
910

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

915
        return hashmap_replace(*h, key, value);
80,951✔
916
}
917

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

936
HashmapBase* _hashmap_free(HashmapBase *h) {
17,320,298✔
937
        if (h) {
17,320,298✔
938
                _hashmap_clear(h);
4,501,278✔
939
                hashmap_free_no_clear(h);
4,501,278✔
940
        }
941

942
        return NULL;
17,320,298✔
943
}
944

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

949
        if (h->hash_ops->free_key || h->hash_ops->free_value) {
4,525,375✔
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,775,604✔
956
                        void *k = NULL;
20,570,375✔
957
                        void *v;
20,570,375✔
958

959
                        v = _hashmap_first_key_and_value(h, true, &k);
20,570,375✔
960

961
                        if (h->hash_ops->free_key)
20,570,375✔
962
                                h->hash_ops->free_key(k);
15,999,644✔
963

964
                        if (h->hash_ops->free_value)
20,570,375✔
965
                                h->hash_ops->free_value(v);
18,005,161✔
966
                }
967
        }
968

969
        if (h->has_indirect) {
4,525,375✔
970
                free(h->indirect.storage);
1,531,742✔
971
                h->has_indirect = false;
1,531,742✔
972
        }
973

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

977
        if (h->type == HASHMAP_TYPE_ORDERED) {
4,525,375✔
978
                OrderedHashmap *lh = (OrderedHashmap*) h;
1,211,072✔
979
                lh->iterate_list_head = lh->iterate_list_tail = IDX_NIL;
1,211,072✔
980
        }
981

982
        base_set_dirty(h);
4,525,375✔
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,114,355✔
997
                                   struct swap_entries *swap) {
998
        dib_raw_t raw_dib, *dibs;
101,114,355✔
999
        unsigned dib, distance;
101,114,355✔
1000

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

1006
        dibs = dib_raw_ptr(h);
101,114,355✔
1007

1008
        for (distance = 0; ; distance++) {
101,114,355✔
1009
                raw_dib = dibs[idx];
202,134,266✔
1010
                if (IN_SET(raw_dib, DIB_RAW_FREE, DIB_RAW_REHASH)) {
202,134,266✔
1011
                        if (raw_dib == DIB_RAW_REHASH)
101,114,355✔
1012
                                bucket_move_entry(h, swap, idx, IDX_TMP);
11,310,668✔
1013

1014
                        if (h->has_indirect && h->indirect.idx_lowest_entry > idx)
101,114,355✔
1015
                                h->indirect.idx_lowest_entry = idx;
36,621✔
1016

1017
                        bucket_set_dib(h, idx, distance);
101,114,355✔
1018
                        bucket_move_entry(h, swap, IDX_PUT, idx);
101,114,355✔
1019
                        if (raw_dib == DIB_RAW_REHASH) {
101,114,355✔
1020
                                bucket_move_entry(h, swap, IDX_TMP, IDX_PUT);
11,310,668✔
1021
                                return true;
11,310,668✔
1022
                        }
1023

1024
                        return false;
1025
                }
1026

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

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

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

1038
                        distance = dib;
40,524,445✔
1039
                }
1040

1041
                idx = next_idx(h, idx);
101,019,911✔
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,889,454✔
1056
                                   struct swap_entries *swap, bool may_resize) {
1057
        struct ordered_hashmap_entry *new_entry;
48,889,454✔
1058
        int r;
48,889,454✔
1059

1060
        assert(idx < n_buckets(h));
48,889,454✔
1061

1062
        new_entry = bucket_at_swap(swap, IDX_PUT);
48,889,454✔
1063

1064
        if (may_resize) {
48,889,454✔
1065
                r = resize_buckets(h, 1);
48,884,729✔
1066
                if (r < 0)
48,884,729✔
1067
                        return r;
1068
                if (r > 0)
48,884,729✔
1069
                        idx = bucket_hash(h, new_entry->p.b.key);
3,839,954✔
1070
        }
1071
        assert(n_entries(h) < n_buckets(h));
48,889,454✔
1072

1073
        if (h->type == HASHMAP_TYPE_ORDERED) {
48,889,454✔
1074
                OrderedHashmap *lh = (OrderedHashmap*) h;
16,115,177✔
1075

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

1079
                if (lh->iterate_list_tail != IDX_NIL) {
16,115,177✔
1080
                        struct ordered_hashmap_entry *old_tail;
14,604,217✔
1081

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

1087
                lh->iterate_list_tail = IDX_PUT;
16,115,177✔
1088
                if (lh->iterate_list_head == IDX_NIL)
16,115,177✔
1089
                        lh->iterate_list_head = IDX_PUT;
1,510,960✔
1090
        }
1091

1092
        assert_se(hashmap_put_robin_hood(h, idx, swap) == false);
48,889,454✔
1093

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

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

1121
        assert(h);
48,898,668✔
1122

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

1126
        /* overflow? */
1127
        if (_unlikely_(new_n_entries < entries_add))
48,898,668✔
1128
                return -ENOMEM;
48,898,668✔
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,898,666✔
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,374,427✔
1139
        /* overflow? */
1140
        if (_unlikely_(new_n_buckets < new_n_entries))
40,374,427✔
1141
                return -ENOMEM;
1142

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

1146
        old_n_buckets = n_buckets(h);
40,374,425✔
1147

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

1151
        new_shift = log2u_round_up(MAX(
3,843,647✔
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,293,417✔
1157
                              1U << new_shift);
3,843,647✔
1158
        if (!new_storage)
3,843,647✔
1159
                return -ENOMEM;
1160

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

1175
        h->has_indirect = true;
3,843,647✔
1176
        h->indirect.storage = new_storage;
3,843,647✔
1177
        h->indirect.n_buckets = (1U << new_shift) /
3,843,647✔
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,843,647✔
1181
        new_dibs = dib_raw_ptr(h);
3,843,647✔
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,760,169✔
1190
                assert(old_dibs[idx] != DIB_RAW_REHASH);
65,916,522✔
1191
                new_dibs[idx] = old_dibs[idx] == DIB_RAW_FREE ? DIB_RAW_FREE
119,233,405✔
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,843,647✔
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,687,294✔
1201
               (n_buckets(h) - old_n_buckets) * sizeof(dib_raw_t));
3,843,647✔
1202

1203
        /* Rehash entries that need it */
1204
        n_rehashed = 0;
3,843,647✔
1205
        for (idx = 0; idx < old_n_buckets; idx++) {
69,760,169✔
1206
                if (new_dibs[idx] != DIB_RAW_REHASH)
65,916,522✔
1207
                        continue;
23,910,307✔
1208

1209
                optimal_idx = bucket_hash(h, bucket_at(h, idx)->key);
42,006,215✔
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) {
42,006,215✔
1216
                        new_dibs[idx] = 0;
1,091,982✔
1217
                        n_rehashed++;
1,091,982✔
1218
                        continue;
1,091,982✔
1219
                }
1220

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

1226
                do {
52,224,901✔
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,224,901✔
1232
                        n_rehashed++;
52,224,901✔
1233

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

1240
        assert_se(n_rehashed == n_entries(h));
3,843,647✔
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) {
258,659,924✔
1250
        struct hashmap_base_entry *e;
258,659,924✔
1251
        unsigned dib, distance;
258,659,924✔
1252
        dib_raw_t *dibs = dib_raw_ptr(h);
258,659,924✔
1253

1254
        assert(idx < n_buckets(h));
258,659,924✔
1255

1256
        for (distance = 0; ; distance++) {
157,891,911✔
1257
                if (dibs[idx] == DIB_RAW_FREE)
416,551,835✔
1258
                        return IDX_NIL;
1259

1260
                dib = bucket_calculate_dib(h, idx, dibs[idx]);
320,946,885✔
1261

1262
                if (dib < distance)
320,946,885✔
1263
                        return IDX_NIL;
1264
                if (dib == distance) {
274,527,826✔
1265
                        e = bucket_at(h, idx);
206,684,288✔
1266
                        if (h->hash_ops->compare(e->key, key) == 0)
206,684,288✔
1267
                                return idx;
1268
                }
1269

1270
                idx = next_idx(h, idx);
157,891,911✔
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,545,325✔
1276
        struct swap_entries swap;
15,545,325✔
1277
        struct plain_hashmap_entry *e;
15,545,325✔
1278
        unsigned hash, idx;
15,545,325✔
1279

1280
        assert(h);
15,545,325✔
1281

1282
        hash = bucket_hash(h, key);
15,545,325✔
1283
        idx = bucket_scan(h, hash, key);
15,545,325✔
1284
        if (idx != IDX_NIL) {
15,545,325✔
1285
                e = plain_bucket_at(h, idx);
343,062✔
1286
                if (e->value == value)
343,062✔
1287
                        return 0;
15,545,325✔
1288
                return -EEXIST;
39,283✔
1289
        }
1290

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

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

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

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

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

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

1317
        assert(s);
16,873,319✔
1318

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

1323
        return set_put(*s, key);
16,873,319✔
1324
}
1325

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

1329
        r = set_ensure_put(s, hash_ops, key);
1,441,655✔
1330
        if (r <= 0) {
1,441,655✔
1331
                if (hash_ops && hash_ops->free_key)
1,049✔
1332
                        hash_ops->free_key(key);
1,048✔
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,441,655✔
1341
}
1342

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

1348
        assert(h);
16,081,969✔
1349

1350
        hash = bucket_hash(h, key);
16,081,969✔
1351
        idx = bucket_scan(h, hash, key);
16,081,969✔
1352
        if (idx != IDX_NIL) {
16,081,969✔
1353
                e = plain_bucket_at(h, idx);
1,189,755✔
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,189,755✔
1365
                e->value = value;
1,189,755✔
1366
                hashmap_set_dirty(h);
1,189,755✔
1367

1368
                return 0;
1,189,755✔
1369
        }
1370

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

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

1381
        assert(h);
31,884✔
1382

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

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

1392
        return 0;
31,882✔
1393
}
1394

1395
void* _hashmap_get(HashmapBase *h, const void *key) {
134,513,188✔
1396
        struct hashmap_base_entry *e;
134,513,188✔
1397
        unsigned hash, idx;
134,513,188✔
1398

1399
        if (!h)
134,513,188✔
1400
                return NULL;
1401

1402
        hash = bucket_hash(h, key);
125,063,597✔
1403
        idx = bucket_scan(h, hash, key);
125,063,597✔
1404
        if (idx == IDX_NIL)
125,063,597✔
1405
                return NULL;
1406

1407
        e = bucket_at(h, idx);
94,099,486✔
1408
        return entry_value(h, e);
94,099,486✔
1409
}
1410

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

1415
        if (!h)
13,507,901✔
1416
                return NULL;
1417

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

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

1427
        return e->value;
1,102,679✔
1428
}
1429

1430
bool _hashmap_contains(HashmapBase *h, const void *key) {
43,993,591✔
1431
        unsigned hash;
43,993,591✔
1432

1433
        if (!h)
43,993,591✔
1434
                return false;
1435

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

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

1445
        if (!h)
26,679,976✔
1446
                return NULL;
1447

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

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

1457
        return data;
17,330,152✔
1458
}
1459

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

1465
        if (!h) {
635,321✔
1466
                if (ret)
102,598✔
1467
                        *ret = NULL;
102,598✔
1468
                return NULL;
1469
        }
1470

1471
        hash = bucket_hash(h, key);
532,723✔
1472
        idx = bucket_scan(h, hash, key);
532,723✔
1473
        if (idx == IDX_NIL) {
532,723✔
1474
                if (ret)
520,617✔
1475
                        *ret = NULL;
520,617✔
1476
                return NULL;
1477
        }
1478

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

1484
        remove_entry(h, idx);
12,106✔
1485

1486
        return data;
12,106✔
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,289✔
1517
        struct swap_entries swap;
1,289✔
1518
        struct hashmap_base_entry *e;
1,289✔
1519
        unsigned old_hash, new_hash, idx;
1,289✔
1520

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

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

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

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

1535
        e = &bucket_at_swap(&swap, IDX_PUT)->p.b;
1,289✔
1536
        e->key = new_key;
1,289✔
1537
        assert_se(hashmap_put_boldly(s, new_hash, &swap, false) == 1);
1,289✔
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) {
919,607✔
1579
        struct hashmap_base_entry *e;
919,607✔
1580
        unsigned hash, idx;
919,607✔
1581

1582
        if (!h)
919,607✔
1583
                return NULL;
1584

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

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

1594
        remove_entry(h, idx);
800,567✔
1595

1596
        return value;
800,567✔
1597
}
1598

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

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

1605
        return hashmap_iterate_entry(h, &i);
26,496,826✔
1606
}
1607

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

1613
        idx = find_first_entry(h);
28,466,714✔
1614
        if (idx == IDX_NIL) {
28,466,714✔
1615
                if (ret_key)
1,969,888✔
1616
                        *ret_key = NULL;
1,029,834✔
1617
                return NULL;
1618
        }
1619

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

1624
        if (remove)
26,496,826✔
1625
                remove_entry(h, idx);
26,037,643✔
1626

1627
        if (ret_key)
26,496,826✔
1628
                *ret_key = key;
21,822,307✔
1629

1630
        return data;
1631
}
1632

1633
unsigned _hashmap_size(HashmapBase *h) {
75,488,648✔
1634
        if (!h)
75,488,648✔
1635
                return 0;
1636

1637
        return n_entries(h);
33,113,743✔
1638
}
1639

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

1644
        return n_buckets(h);
687✔
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,571✔
1684
        int r;
10,571✔
1685

1686
        assert(h);
10,571✔
1687

1688
        r = resize_buckets(h, entries_add);
10,571✔
1689
        if (r < 0)
10,571✔
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,371✔
1702
        struct swap_entries swap;
3,371✔
1703
        struct hashmap_base_entry *e, *n;
3,371✔
1704
        Iterator i;
3,371✔
1705
        unsigned idx;
3,371✔
1706
        int r;
3,371✔
1707

1708
        assert(h);
3,371✔
1709

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

1713
        assert(other->type == h->type);
3,368✔
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,368✔
1722
        if (r < 0)
3,368✔
1723
                return r;
1724

1725
        HASHMAP_FOREACH_IDX(idx, other, i) {
6,758✔
1726
                unsigned h_hash;
3,390✔
1727

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

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

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

1743
        return 0;
1744
}
1745

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

1752
        assert(h);
3,634✔
1753

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

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

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

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

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

1770
        n = &bucket_at_swap(&swap, IDX_PUT)->p.b;
3,628✔
1771
        n->key = e->key;
3,628✔
1772
        if (h->type != HASHMAP_TYPE_SET)
3,628✔
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,628✔
1776
        if (r < 0)
3,628✔
1777
                return r;
1778

1779
        remove_entry(other, idx);
3,628✔
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) {
207✔
1832
        assert(s);
207✔
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);
207✔
1837
        if (!v)
207✔
1838
                return NULL;
1839

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

1843
        assert(set_isempty(*s));
207✔
1844
        *s = set_free(*s);
207✔
1845
        return v;
207✔
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) {
923,051✔
1867
        int r;
923,051✔
1868

1869
        assert(s);
923,051✔
1870
        assert(value);
923,051✔
1871

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

1876
        return r;
923,051✔
1877
}
1878

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

1882
        assert(h);
1,974✔
1883

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

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

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

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

1900
        r = hashmap_put(*h, kdup, vdup);
1,974✔
1901
        if (r < 0) {
1,974✔
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,964✔
1909
        if (r > 0)
1,913✔
1910
                kdup = vdup = NULL;
1,963✔
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,352,178✔
1916
        char *c;
1,352,178✔
1917
        int r;
1,352,178✔
1918

1919
        assert(s);
1,352,178✔
1920
        assert(p);
1,352,178✔
1921

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

1926
        if (n == SIZE_MAX) {
1,352,178✔
1927
                if (set_contains(*s, (char*) p))
1,327,277✔
1928
                        return 0;
1929

1930
                c = strdup(p);
889,889✔
1931
        } else
1932
                c = strndup(p, n);
24,901✔
1933
        if (!c)
914,790✔
1934
                return -ENOMEM;
1935

1936
        return set_consume(*s, c);
914,790✔
1937
}
1938

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

1942
        assert(s);
2,181✔
1943

1944
        STRV_FOREACH(i, l) {
2,243✔
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) {
28,988,422✔
1976
        assert(mem);
28,988,422✔
1977

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

1983
        if (!mem->active) {
28,988,422✔
1984
                mem->active = true;
2,923✔
1985
                return true;
2,923✔
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) {
28,988,310✔
1992
        bool sync_keys = false, sync_values = false;
28,988,310✔
1993
        size_t size;
28,988,310✔
1994
        int r;
28,988,310✔
1995

1996
        assert(cache);
28,988,310✔
1997
        assert(cache->hashmap);
28,988,310✔
1998

1999
        size = n_entries(cache->hashmap);
28,988,310✔
2000

2001
        if (res_keys) {
28,988,310✔
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;
28,988,198✔
2009

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

2015
                sync_values = r;
28,988,310✔
2016
        } else
2017
                cache->values.active = false;
×
2018

2019
        if (cache->hashmap->dirty) {
28,988,310✔
2020
                if (cache->keys.active)
3,031✔
2021
                        sync_keys = true;
111✔
2022
                if (cache->values.active)
3,031✔
2023
                        sync_values = true;
3,031✔
2024

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

2028
        if (sync_keys || sync_values) {
28,988,310✔
2029
                unsigned i, idx;
3,033✔
2030
                Iterator iter;
3,033✔
2031

2032
                i = 0;
3,033✔
2033
                HASHMAP_FOREACH_IDX(idx, cache->hashmap, iter) {
509,139✔
2034
                        struct hashmap_base_entry *e;
506,106✔
2035

2036
                        e = bucket_at(cache->hashmap, idx);
506,106✔
2037

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

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

2053
        return 0;
2054
}
2055

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

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

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

2071
        assert(ret);
702,501✔
2072

2073
        if (set_isempty(s)) {
702,501✔
2074
                *ret = NULL;
21,410✔
2075
                return 0;
21,410✔
2076
        }
2077

2078
        separator_len = strlen_ptr(separator);
681,091✔
2079

2080
        if (separator_len == 0)
681,087✔
2081
                wrap_with_separator = false;
2082

2083
        first = !wrap_with_separator;
681,091✔
2084

2085
        SET_FOREACH(value, s) {
2,169,383✔
2086
                size_t l = strlen_ptr(value);
1,488,292✔
2087

2088
                if (l == 0)
1,488,292✔
2089
                        continue;
×
2090

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

2094
                if (separator_len > 0 && !first) {
1,488,292✔
2095
                        memcpy(str + len, separator, separator_len);
1,224,385✔
2096
                        len += separator_len;
1,224,385✔
2097
                }
2098

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

2104
        if (wrap_with_separator) {
681,091✔
2105
                memcpy(str + len, separator, separator_len);
417,188✔
2106
                len += separator_len;
417,188✔
2107
        }
2108

2109
        str[len] = '\0';
681,091✔
2110

2111
        *ret = TAKE_PTR(str);
681,091✔
2112
        return 0;
681,091✔
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,510✔
2132
                if (!set_contains(b, p))
2,490✔
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) {
735,365✔
2148
        const char *p;
735,365✔
2149

2150
        assert(needle);
735,365✔
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)
946,447✔
2155
                if (fnmatch(p, needle, 0) == 0)
258,546✔
2156
                        return true;
47,464✔
2157

2158
        return false;
687,901✔
2159
}
2160

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

2164
        if (set_fnmatch_one(exclude_patterns, needle))
515,121✔
2165
                return false;
2166

2167
        if (set_isempty(include_patterns))
514,797✔
2168
                return true;
2169

2170
        return set_fnmatch_one(include_patterns, needle);
220,244✔
2171
}
2172

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

2178
        assert(a && *a);
782,052✔
2179
        assert(b && *b);
782,052✔
2180
        assert(compare);
782,052✔
2181

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

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

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

2197
        if (_hashmap_size(h) == 0) {
156,303✔
2198
                *ret = NULL;
97,169✔
2199
                *ret_n = 0;
97,169✔
2200
                return 0;
97,169✔
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,134✔
2206
        if (!entries)
59,134✔
2207
                return -ENOMEM;
2208

2209
        HASHMAP_FOREACH_IDX(idx, h, iter)
318,938✔
2210
                entries[n++] = bucket_at(h, idx);
259,804✔
2211

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

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

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

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

2228
        assert(ret);
738✔
2229

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

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

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

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

2249
        assert(ret);
155,565✔
2250

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

2255
        /* Reuse the array. */
2256
        FOREACH_ARRAY(e, entries, n)
410,962✔
2257
                *e = entry_value(h, *(struct hashmap_base_entry**) e);
255,397✔
2258

2259
        *ret = TAKE_PTR(entries);
155,565✔
2260
        if (ret_n)
155,565✔
2261
                *ret_n = n;
152,894✔
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