Coverage Report

Created: 2026-09-14 07:05

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
2.90k
#define CURL_UINT32_HASHINIT 0x7117e779
31
#endif
32
33
static uint32_t uint32_hash_hash(uint32_t id, uint32_t slots)
34
134k
{
35
134k
  return (id % slots);
36
134k
}
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
2.90k
{
48
2.90k
  DEBUGASSERT(h);
49
2.90k
  DEBUGASSERT(slots);
50
51
2.90k
  h->table = NULL;
52
2.90k
  h->dtor = dtor;
53
2.90k
  h->size = 0;
54
2.90k
  h->slots = slots;
55
2.90k
#ifdef DEBUGBUILD
56
2.90k
  h->init = CURL_UINT32_HASHINIT;
57
2.90k
#endif
58
2.90k
}
59
60
static struct uint_hash_entry *uint32_hash_mk_entry(uint32_t id, void *value)
61
4.45k
{
62
4.45k
  struct uint_hash_entry *e;
63
64
  /* allocate the struct for the hash entry */
65
4.45k
  e = curlx_malloc(sizeof(*e));
66
4.45k
  if(e) {
67
4.45k
    e->id = id;
68
4.45k
    e->next = NULL;
69
4.45k
    e->value = value;
70
4.45k
  }
71
4.45k
  return e;
72
4.45k
}
73
74
static void uint32_hash_entry_clear(struct uint_hash *h,
75
                                    struct uint_hash_entry *e)
76
4.45k
{
77
4.45k
  DEBUGASSERT(h);
78
4.45k
  DEBUGASSERT(e);
79
4.45k
  if(e->value) {
80
4.45k
    if(h->dtor)
81
4.45k
      h->dtor(e->id, e->value);
82
4.45k
    e->value = NULL;
83
4.45k
  }
84
4.45k
}
85
86
static void uint32_hash_entry_destroy(struct uint_hash *h,
87
                                      struct uint_hash_entry *e)
88
4.45k
{
89
4.45k
  uint32_hash_entry_clear(h, e);
90
4.45k
  curlx_free(e);
91
4.45k
}
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
4.45k
{
97
4.45k
  *he_anchor = he->next;
98
4.45k
  --h->size;
99
4.45k
}
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
4.45k
{
105
4.45k
  he->next = *he_anchor;
106
4.45k
  *he_anchor = he;
107
4.45k
  ++h->size;
108
4.45k
}
109
110
134k
#define CURL_UINT32_HASH_SLOT(h, id) h->table[uint32_hash_hash(id, (h)->slots)]
111
8.89k
#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
4.45k
{
115
4.45k
  struct uint_hash_entry *he, **slot;
116
117
4.45k
  DEBUGASSERT(h);
118
4.45k
  DEBUGASSERT(h->slots);
119
4.45k
  DEBUGASSERT(h->init == CURL_UINT32_HASHINIT);
120
4.45k
  if(!h->table) {
121
2.90k
    h->table = curlx_calloc(h->slots, sizeof(*he));
122
2.90k
    if(!h->table)
123
0
      return FALSE; /* OOM */
124
2.90k
  }
125
126
4.45k
  slot = CURL_UINT32_HASH_SLOT_ADDR(h, id);
127
4.45k
  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
4.45k
  he = uint32_hash_mk_entry(id, value);
137
4.45k
  if(!he)
138
0
    return FALSE; /* OOM */
139
140
4.45k
  uint32_hash_elem_link(h, slot, he);
141
4.45k
  return TRUE;
142
4.45k
}
143
144
bool Curl_uint32_hash_remove(struct uint_hash *h, uint32_t id)
145
4.44k
{
146
4.44k
  DEBUGASSERT(h);
147
4.44k
  DEBUGASSERT(h->slots);
148
4.44k
  DEBUGASSERT(h->init == CURL_UINT32_HASHINIT);
149
4.44k
  if(h->table) {
150
4.44k
    struct uint_hash_entry *he, **he_anchor;
151
152
4.44k
    he_anchor = CURL_UINT32_HASH_SLOT_ADDR(h, id);
153
4.44k
    while(*he_anchor) {
154
4.44k
      he = *he_anchor;
155
4.44k
      if(id == he->id) {
156
4.44k
        uint32_hash_entry_unlink(h, he_anchor, he);
157
4.44k
        uint32_hash_entry_destroy(h, he);
158
4.44k
        return TRUE;
159
4.44k
      }
160
0
      he_anchor = &he->next;
161
0
    }
162
4.44k
  }
163
0
  return FALSE;
164
4.44k
}
165
166
void *Curl_uint32_hash_get(struct uint_hash *h, uint32_t id)
167
128k
{
168
128k
  DEBUGASSERT(h);
169
128k
  DEBUGASSERT(h->init == CURL_UINT32_HASHINIT);
170
128k
  if(h->table) {
171
126k
    struct uint_hash_entry *he;
172
126k
    DEBUGASSERT(h->slots);
173
126k
    he = CURL_UINT32_HASH_SLOT(h, id);
174
126k
    while(he) {
175
120k
      if(id == he->id) {
176
120k
        return he->value;
177
120k
      }
178
0
      he = he->next;
179
0
    }
180
126k
  }
181
8.20k
  return NULL;
182
128k
}
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
2.90k
{
188
2.90k
  if(h && h->table) {
189
2.90k
    struct uint_hash_entry *he, **he_anchor;
190
2.90k
    size_t i;
191
2.90k
    DEBUGASSERT(h->init == CURL_UINT32_HASHINIT);
192
185k
    for(i = 0; i < h->slots; ++i) {
193
182k
      he_anchor = &h->table[i];
194
182k
      while(*he_anchor) {
195
6
        he = *he_anchor;
196
6
        uint32_hash_entry_unlink(h, he_anchor, he);
197
6
        uint32_hash_entry_destroy(h, he);
198
6
      }
199
182k
    }
200
2.90k
  }
201
2.90k
}
202
203
void Curl_uint32_hash_destroy(struct uint_hash *h)
204
2.90k
{
205
2.90k
  DEBUGASSERT(h->init == CURL_UINT32_HASHINIT);
206
2.90k
  if(h->table) {
207
2.90k
    uint_hash_clear(h);
208
2.90k
    curlx_safefree(h->table);
209
2.90k
  }
210
2.90k
  DEBUGASSERT(h->size == 0);
211
2.90k
  h->slots = 0;
212
2.90k
}
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
}