Coverage Report

Created: 2025-07-18 07:19

/src/curl/lib/uint-hash.c
Line
Count
Source (jump to first uncovered line)
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
25
#include "curl_setup.h"
26
27
#include <curl/curl.h>
28
29
#include "uint-hash.h"
30
#include "curl_memory.h"
31
32
/* The last #include file should be: */
33
#include "memdebug.h"
34
35
/* random patterns for API verification */
36
#ifdef DEBUGBUILD
37
16.4k
#define CURL_UINTHASHINIT 0x7117e779
38
#endif
39
40
static unsigned int uint_hash_hash(unsigned int id, unsigned int slots)
41
97.4M
{
42
97.4M
  return (id % slots);
43
97.4M
}
44
45
46
struct uint_hash_entry {
47
  struct uint_hash_entry *next;
48
  void   *value;
49
  unsigned int id;
50
};
51
52
void Curl_uint_hash_init(struct uint_hash *h,
53
                         unsigned int slots,
54
                         Curl_uint_hash_dtor *dtor)
55
16.4k
{
56
16.4k
  DEBUGASSERT(h);
57
16.4k
  DEBUGASSERT(slots);
58
59
16.4k
  h->table = NULL;
60
16.4k
  h->dtor = dtor;
61
16.4k
  h->size = 0;
62
16.4k
  h->slots = slots;
63
16.4k
#ifdef DEBUGBUILD
64
16.4k
  h->init = CURL_UINTHASHINIT;
65
16.4k
#endif
66
16.4k
}
67
68
static struct uint_hash_entry *uint_hash_mk_entry(unsigned int id, void *value)
69
16.5k
{
70
16.5k
  struct uint_hash_entry *e;
71
72
  /* allocate the struct for the hash entry */
73
16.5k
  e = malloc(sizeof(*e));
74
16.5k
  if(e) {
75
16.5k
    e->id = id;
76
16.5k
    e->next = NULL;
77
16.5k
    e->value = value;
78
16.5k
  }
79
16.5k
  return e;
80
16.5k
}
81
82
static void uint_hash_entry_clear(struct uint_hash *h,
83
                                  struct uint_hash_entry *e)
84
16.5k
{
85
16.5k
  DEBUGASSERT(h);
86
16.5k
  DEBUGASSERT(e);
87
16.5k
  if(e->value) {
88
16.5k
    if(h->dtor)
89
16.5k
      h->dtor(e->id, e->value);
90
16.5k
    e->value = NULL;
91
16.5k
  }
92
16.5k
}
93
94
static void uint_hash_entry_destroy(struct uint_hash *h,
95
                                    struct uint_hash_entry *e)
96
16.5k
{
97
16.5k
  uint_hash_entry_clear(h, e);
98
16.5k
  free(e);
99
16.5k
}
100
101
static void uint_hash_entry_unlink(struct uint_hash *h,
102
                                   struct uint_hash_entry **he_anchor,
103
                                   struct uint_hash_entry *he)
104
16.5k
{
105
16.5k
  *he_anchor = he->next;
106
16.5k
  --h->size;
107
16.5k
}
108
109
static void uint_hash_elem_link(struct uint_hash *h,
110
                                struct uint_hash_entry **he_anchor,
111
                                struct uint_hash_entry *he)
112
16.5k
{
113
16.5k
  he->next = *he_anchor;
114
16.5k
  *he_anchor = he;
115
16.5k
  ++h->size;
116
16.5k
}
117
118
97.4M
#define CURL_UINT_HASH_SLOT(h,id)  h->table[uint_hash_hash(id, h->slots)]
119
33.1k
#define CURL_UINT_HASH_SLOT_ADDR(h,id) &CURL_UINT_HASH_SLOT(h,id)
120
121
bool Curl_uint_hash_set(struct uint_hash *h, unsigned int id, void *value)
122
16.5k
{
123
16.5k
  struct uint_hash_entry *he, **slot;
124
125
16.5k
  DEBUGASSERT(h);
126
16.5k
  DEBUGASSERT(h->slots);
127
16.5k
  DEBUGASSERT(h->init == CURL_UINTHASHINIT);
128
16.5k
  if(!h->table) {
129
16.4k
    h->table = calloc(h->slots, sizeof(*he));
130
16.4k
    if(!h->table)
131
0
      return FALSE; /* OOM */
132
16.4k
  }
133
134
16.5k
  slot = CURL_UINT_HASH_SLOT_ADDR(h, id);
135
16.5k
  for(he = *slot; he; he = he->next) {
136
0
    if(he->id == id) {
137
      /* existing key entry, overwrite by clearing old pointer */
138
0
      uint_hash_entry_clear(h, he);
139
0
      he->value = value;
140
0
      return TRUE;
141
0
    }
142
0
  }
143
144
16.5k
  he = uint_hash_mk_entry(id, value);
145
16.5k
  if(!he)
146
0
    return FALSE; /* OOM */
147
148
16.5k
  uint_hash_elem_link(h, slot, he);
149
16.5k
  return TRUE;
150
16.5k
}
151
152
bool Curl_uint_hash_remove(struct uint_hash *h, unsigned int id)
153
16.5k
{
154
16.5k
  DEBUGASSERT(h);
155
16.5k
  DEBUGASSERT(h->slots);
156
16.5k
  DEBUGASSERT(h->init == CURL_UINTHASHINIT);
157
16.5k
  if(h->table) {
158
16.5k
    struct uint_hash_entry *he, **he_anchor;
159
160
16.5k
    he_anchor = CURL_UINT_HASH_SLOT_ADDR(h, id);
161
16.5k
    while(*he_anchor) {
162
16.5k
      he = *he_anchor;
163
16.5k
      if(id == he->id) {
164
16.5k
        uint_hash_entry_unlink(h, he_anchor, he);
165
16.5k
        uint_hash_entry_destroy(h, he);
166
16.5k
        return TRUE;
167
16.5k
      }
168
0
      he_anchor = &he->next;
169
0
    }
170
16.5k
  }
171
0
  return FALSE;
172
16.5k
}
173
174
void *Curl_uint_hash_get(struct uint_hash *h, unsigned int id)
175
97.5M
{
176
97.5M
  DEBUGASSERT(h);
177
97.5M
  DEBUGASSERT(h->init == CURL_UINTHASHINIT);
178
97.5M
  if(h->table) {
179
97.4M
    struct uint_hash_entry *he;
180
97.4M
    DEBUGASSERT(h->slots);
181
97.4M
    he = CURL_UINT_HASH_SLOT(h, id);
182
97.4M
    while(he) {
183
97.4M
      if(id == he->id) {
184
97.4M
        return he->value;
185
97.4M
      }
186
0
      he = he->next;
187
0
    }
188
97.4M
  }
189
70.7k
  return NULL;
190
97.5M
}
191
192
static void uint_hash_clear(struct uint_hash *h)
193
16.4k
{
194
16.4k
  if(h && h->table) {
195
16.4k
    struct uint_hash_entry *he, **he_anchor;
196
16.4k
    size_t i;
197
16.4k
    DEBUGASSERT(h->init == CURL_UINTHASHINIT);
198
1.05M
    for(i = 0; i < h->slots; ++i) {
199
1.03M
      he_anchor = &h->table[i];
200
1.03M
      while(*he_anchor) {
201
30
        he = *he_anchor;
202
30
        uint_hash_entry_unlink(h, he_anchor, he);
203
30
        uint_hash_entry_destroy(h, he);
204
30
      }
205
1.03M
    }
206
16.4k
  }
207
16.4k
}
208
209
#ifdef UNITTESTS
210
UNITTEST void Curl_uint_hash_clear(struct uint_hash *h)
211
{
212
  uint_hash_clear(h);
213
}
214
#endif
215
216
void Curl_uint_hash_destroy(struct uint_hash *h)
217
16.4k
{
218
16.4k
  DEBUGASSERT(h->init == CURL_UINTHASHINIT);
219
16.4k
  if(h->table) {
220
16.4k
    uint_hash_clear(h);
221
16.4k
    Curl_safefree(h->table);
222
16.4k
  }
223
16.4k
  DEBUGASSERT(h->size == 0);
224
16.4k
  h->slots = 0;
225
16.4k
}
226
227
unsigned int Curl_uint_hash_count(struct uint_hash *h)
228
0
{
229
0
  DEBUGASSERT(h->init == CURL_UINTHASHINIT);
230
0
  return h->size;
231
0
}
232
233
void Curl_uint_hash_visit(struct uint_hash *h,
234
                          Curl_uint_hash_visit_cb *cb,
235
                          void *user_data)
236
0
{
237
0
  if(h && h->table && cb) {
238
0
    struct uint_hash_entry *he;
239
0
    size_t i;
240
0
    DEBUGASSERT(h->init == CURL_UINTHASHINIT);
241
0
    for(i = 0; i < h->slots; ++i) {
242
0
      for(he = h->table[i]; he; he = he->next) {
243
0
        if(!cb(he->id, he->value, user_data))
244
0
          return;
245
0
      }
246
0
    }
247
0
  }
248
0
}