LCOV - code coverage report
Current view: top level - basic - hashmap.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 743 823 90.3 %
Date: 2019-08-23 13:36:53 Functions: 76 81 93.8 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 384 512 75.0 %

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

Generated by: LCOV version 1.14