/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 | } |