Coverage Report

Created: 2026-06-01 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/curl/lib/uint-hash.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9
 *
10
 * This software is licensed as described in the file COPYING, which
11
 * you should have received as part of this distribution. The terms
12
 * are also available at https://curl.se/docs/copyright.html.
13
 *
14
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15
 * copies of the Software, and permit persons to whom the Software is
16
 * furnished to do so, under the terms of the COPYING file.
17
 *
18
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19
 * KIND, either express or implied.
20
 *
21
 * SPDX-License-Identifier: curl
22
 *
23
 ***************************************************************************/
24
#include "curl_setup.h"
25
26
#include "uint-hash.h"
27
28
/* random patterns for API verification */
29
#ifdef DEBUGBUILD
30
18.9k
#define CURL_UINT32_HASHINIT 0x7117e779
31
#endif
32
33
static uint32_t uint32_hash_hash(uint32_t id, uint32_t slots)
34
101M
{
35
101M
  return (id % slots);
36
101M
}
37
38
struct uint_hash_entry {
39
  struct uint_hash_entry *next;
40
  void *value;
41
  uint32_t id;
42
};
43
44
void Curl_uint32_hash_init(struct uint_hash *h,
45
                           uint32_t slots,
46
                           Curl_uint32_hash_dtor *dtor)
47
18.9k
{
48
18.9k
  DEBUGASSERT(h);
49
18.9k
  DEBUGASSERT(slots);
50
51
18.9k
  h->table = NULL;
52
18.9k
  h->dtor = dtor;
53
18.9k
  h->size = 0;
54
18.9k
  h->slots = slots;
55
18.9k
#ifdef DEBUGBUILD
56
18.9k
  h->init = CURL_UINT32_HASHINIT;
57
18.9k
#endif
58
18.9k
}
59
60
static struct uint_hash_entry *uint32_hash_mk_entry(uint32_t id, void *value)
61
19.0k
{
62
19.0k
  struct uint_hash_entry *e;
63
64
  /* allocate the struct for the hash entry */
65
19.0k
  e = curlx_malloc(sizeof(*e));
66
19.0k
  if(e) {
67
19.0k
    e->id = id;
68
19.0k
    e->next = NULL;
69
19.0k
    e->value = value;
70
19.0k
  }
71
19.0k
  return e;
72
19.0k
}
73
74
static void uint32_hash_entry_clear(struct uint_hash *h,
75
                                    struct uint_hash_entry *e)
76
19.0k
{
77
19.0k
  DEBUGASSERT(h);
78
19.0k
  DEBUGASSERT(e);
79
19.0k
  if(e->value) {
80
19.0k
    if(h->dtor)
81
19.0k
      h->dtor(e->id, e->value);
82
19.0k
    e->value = NULL;
83
19.0k
  }
84
19.0k
}
85
86
static void uint32_hash_entry_destroy(struct uint_hash *h,
87
                                      struct uint_hash_entry *e)
88
19.0k
{
89
19.0k
  uint32_hash_entry_clear(h, e);
90
19.0k
  curlx_free(e);
91
19.0k
}
92
93
static void uint32_hash_entry_unlink(struct uint_hash *h,
94
                                     struct uint_hash_entry **he_anchor,
95
                                     struct uint_hash_entry *he)
96
19.0k
{
97
19.0k
  *he_anchor = he->next;
98
19.0k
  --h->size;
99
19.0k
}
100
101
static void uint32_hash_elem_link(struct uint_hash *h,
102
                                  struct uint_hash_entry **he_anchor,
103
                                  struct uint_hash_entry *he)
104
19.0k
{
105
19.0k
  he->next = *he_anchor;
106
19.0k
  *he_anchor = he;
107
19.0k
  ++h->size;
108
19.0k
}
109
110
101M
#define CURL_UINT32_HASH_SLOT(h, id) h->table[uint32_hash_hash(id, (h)->slots)]
111
38.1k
#define CURL_UINT32_HASH_SLOT_ADDR(h, id) &CURL_UINT32_HASH_SLOT(h, id)
112
113
bool Curl_uint32_hash_set(struct uint_hash *h, uint32_t id, void *value)
114
19.0k
{
115
19.0k
  struct uint_hash_entry *he, **slot;
116
117
19.0k
  DEBUGASSERT(h);
118
19.0k
  DEBUGASSERT(h->slots);
119
19.0k
  DEBUGASSERT(h->init == CURL_UINT32_HASHINIT);
120
19.0k
  if(!h->table) {
121
18.9k
    h->table = curlx_calloc(h->slots, sizeof(*he));
122
18.9k
    if(!h->table)
123
0
      return FALSE; /* OOM */
124
18.9k
  }
125
126
19.0k
  slot = CURL_UINT32_HASH_SLOT_ADDR(h, id);
127
19.0k
  for(he = *slot; he; he = he->next) {
128
0
    if(he->id == id) {
129
      /* existing key entry, overwrite by clearing old pointer */
130
0
      uint32_hash_entry_clear(h, he);
131
0
      he->value = value;
132
0
      return TRUE;
133
0
    }
134
0
  }
135
136
19.0k
  he = uint32_hash_mk_entry(id, value);
137
19.0k
  if(!he)
138
0
    return FALSE; /* OOM */
139
140
19.0k
  uint32_hash_elem_link(h, slot, he);
141
19.0k
  return TRUE;
142
19.0k
}
143
144
bool Curl_uint32_hash_remove(struct uint_hash *h, uint32_t id)
145
19.0k
{
146
19.0k
  DEBUGASSERT(h);
147
19.0k
  DEBUGASSERT(h->slots);
148
19.0k
  DEBUGASSERT(h->init == CURL_UINT32_HASHINIT);
149
19.0k
  if(h->table) {
150
19.0k
    struct uint_hash_entry *he, **he_anchor;
151
152
19.0k
    he_anchor = CURL_UINT32_HASH_SLOT_ADDR(h, id);
153
19.0k
    while(*he_anchor) {
154
19.0k
      he = *he_anchor;
155
19.0k
      if(id == he->id) {
156
19.0k
        uint32_hash_entry_unlink(h, he_anchor, he);
157
19.0k
        uint32_hash_entry_destroy(h, he);
158
19.0k
        return TRUE;
159
19.0k
      }
160
0
      he_anchor = &he->next;
161
0
    }
162
19.0k
  }
163
0
  return FALSE;
164
19.0k
}
165
166
void *Curl_uint32_hash_get(struct uint_hash *h, uint32_t id)
167
101M
{
168
101M
  DEBUGASSERT(h);
169
101M
  DEBUGASSERT(h->init == CURL_UINT32_HASHINIT);
170
101M
  if(h->table) {
171
101M
    struct uint_hash_entry *he;
172
101M
    DEBUGASSERT(h->slots);
173
101M
    he = CURL_UINT32_HASH_SLOT(h, id);
174
101M
    while(he) {
175
101M
      if(id == he->id) {
176
101M
        return he->value;
177
101M
      }
178
0
      he = he->next;
179
0
    }
180
101M
  }
181
62.2k
  return NULL;
182
101M
}
183
184
/* @unittest 1616 */
185
UNITTEST void uint_hash_clear(struct uint_hash *h);
186
UNITTEST void uint_hash_clear(struct uint_hash *h)
187
18.9k
{
188
18.9k
  if(h && h->table) {
189
18.9k
    struct uint_hash_entry *he, **he_anchor;
190
18.9k
    size_t i;
191
18.9k
    DEBUGASSERT(h->init == CURL_UINT32_HASHINIT);
192
1.21M
    for(i = 0; i < h->slots; ++i) {
193
1.19M
      he_anchor = &h->table[i];
194
1.19M
      while(*he_anchor) {
195
39
        he = *he_anchor;
196
39
        uint32_hash_entry_unlink(h, he_anchor, he);
197
39
        uint32_hash_entry_destroy(h, he);
198
39
      }
199
1.19M
    }
200
18.9k
  }
201
18.9k
}
202
203
void Curl_uint32_hash_destroy(struct uint_hash *h)
204
18.9k
{
205
18.9k
  DEBUGASSERT(h->init == CURL_UINT32_HASHINIT);
206
18.9k
  if(h->table) {
207
18.9k
    uint_hash_clear(h);
208
18.9k
    curlx_safefree(h->table);
209
18.9k
  }
210
18.9k
  DEBUGASSERT(h->size == 0);
211
18.9k
  h->slots = 0;
212
18.9k
}
213
214
uint32_t Curl_uint32_hash_count(struct uint_hash *h)
215
0
{
216
0
  DEBUGASSERT(h->init == CURL_UINT32_HASHINIT);
217
0
  return h->size;
218
0
}
219
220
void Curl_uint32_hash_visit(struct uint_hash *h,
221
                            Curl_uint32_hash_visit_cb *cb,
222
                            void *user_data)
223
0
{
224
0
  if(h && h->table && cb) {
225
0
    struct uint_hash_entry *he;
226
0
    size_t i;
227
0
    DEBUGASSERT(h->init == CURL_UINT32_HASHINIT);
228
0
    for(i = 0; i < h->slots; ++i) {
229
0
      for(he = h->table[i]; he; he = he->next) {
230
0
        if(!cb(he->id, he->value, user_data))
231
0
          return;
232
0
      }
233
0
    }
234
0
  }
235
0
}