Coverage Report

Created: 2025-07-12 06:28

/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
0
#define CURL_UINTHASHINIT 0x7117e779
38
#endif
39
40
static unsigned int uint_hash_hash(unsigned int id, unsigned int slots)
41
0
{
42
0
  return (id % slots);
43
0
}
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
0
{
56
0
  DEBUGASSERT(h);
57
0
  DEBUGASSERT(slots);
58
59
0
  h->table = NULL;
60
0
  h->dtor = dtor;
61
0
  h->size = 0;
62
0
  h->slots = slots;
63
0
#ifdef DEBUGBUILD
64
0
  h->init = CURL_UINTHASHINIT;
65
0
#endif
66
0
}
67
68
static struct uint_hash_entry *uint_hash_mk_entry(unsigned int id, void *value)
69
0
{
70
0
  struct uint_hash_entry *e;
71
72
  /* allocate the struct for the hash entry */
73
0
  e = malloc(sizeof(*e));
74
0
  if(e) {
75
0
    e->id = id;
76
0
    e->next = NULL;
77
0
    e->value = value;
78
0
  }
79
0
  return e;
80
0
}
81
82
static void uint_hash_entry_clear(struct uint_hash *h,
83
                                  struct uint_hash_entry *e)
84
0
{
85
0
  DEBUGASSERT(h);
86
0
  DEBUGASSERT(e);
87
0
  if(e->value) {
88
0
    if(h->dtor)
89
0
      h->dtor(e->id, e->value);
90
0
    e->value = NULL;
91
0
  }
92
0
}
93
94
static void uint_hash_entry_destroy(struct uint_hash *h,
95
                                    struct uint_hash_entry *e)
96
0
{
97
0
  uint_hash_entry_clear(h, e);
98
0
  free(e);
99
0
}
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
0
{
105
0
  *he_anchor = he->next;
106
0
  --h->size;
107
0
}
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
0
{
113
0
  he->next = *he_anchor;
114
0
  *he_anchor = he;
115
0
  ++h->size;
116
0
}
117
118
0
#define CURL_UINT_HASH_SLOT(h,id)  h->table[uint_hash_hash(id, h->slots)]
119
0
#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
0
{
123
0
  struct uint_hash_entry *he, **slot;
124
125
0
  DEBUGASSERT(h);
126
0
  DEBUGASSERT(h->slots);
127
0
  DEBUGASSERT(h->init == CURL_UINTHASHINIT);
128
0
  if(!h->table) {
129
0
    h->table = calloc(h->slots, sizeof(*he));
130
0
    if(!h->table)
131
0
      return FALSE; /* OOM */
132
0
  }
133
134
0
  slot = CURL_UINT_HASH_SLOT_ADDR(h, id);
135
0
  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
0
  he = uint_hash_mk_entry(id, value);
145
0
  if(!he)
146
0
    return FALSE; /* OOM */
147
148
0
  uint_hash_elem_link(h, slot, he);
149
0
  return TRUE;
150
0
}
151
152
bool Curl_uint_hash_remove(struct uint_hash *h, unsigned int id)
153
0
{
154
0
  DEBUGASSERT(h);
155
0
  DEBUGASSERT(h->slots);
156
0
  DEBUGASSERT(h->init == CURL_UINTHASHINIT);
157
0
  if(h->table) {
158
0
    struct uint_hash_entry *he, **he_anchor;
159
160
0
    he_anchor = CURL_UINT_HASH_SLOT_ADDR(h, id);
161
0
    while(*he_anchor) {
162
0
      he = *he_anchor;
163
0
      if(id == he->id) {
164
0
        uint_hash_entry_unlink(h, he_anchor, he);
165
0
        uint_hash_entry_destroy(h, he);
166
0
        return TRUE;
167
0
      }
168
0
      he_anchor = &he->next;
169
0
    }
170
0
  }
171
0
  return FALSE;
172
0
}
173
174
void *Curl_uint_hash_get(struct uint_hash *h, unsigned int id)
175
0
{
176
0
  DEBUGASSERT(h);
177
0
  DEBUGASSERT(h->init == CURL_UINTHASHINIT);
178
0
  if(h->table) {
179
0
    struct uint_hash_entry *he;
180
0
    DEBUGASSERT(h->slots);
181
0
    he = CURL_UINT_HASH_SLOT(h, id);
182
0
    while(he) {
183
0
      if(id == he->id) {
184
0
        return he->value;
185
0
      }
186
0
      he = he->next;
187
0
    }
188
0
  }
189
0
  return NULL;
190
0
}
191
192
static void uint_hash_clear(struct uint_hash *h)
193
0
{
194
0
  if(h && h->table) {
195
0
    struct uint_hash_entry *he, **he_anchor;
196
0
    size_t i;
197
0
    DEBUGASSERT(h->init == CURL_UINTHASHINIT);
198
0
    for(i = 0; i < h->slots; ++i) {
199
0
      he_anchor = &h->table[i];
200
0
      while(*he_anchor) {
201
0
        he = *he_anchor;
202
0
        uint_hash_entry_unlink(h, he_anchor, he);
203
0
        uint_hash_entry_destroy(h, he);
204
0
      }
205
0
    }
206
0
  }
207
0
}
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
0
{
218
0
  DEBUGASSERT(h->init == CURL_UINTHASHINIT);
219
0
  if(h->table) {
220
0
    uint_hash_clear(h);
221
0
    Curl_safefree(h->table);
222
0
  }
223
0
  DEBUGASSERT(h->size == 0);
224
0
  h->slots = 0;
225
0
}
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
}