VirtualBox

source: vbox/trunk/src/libs/curl-8.11.1/lib/hash.c@ 108333

最後變更 在這個檔案從108333是 108048,由 vboxsync 提交於 7 週 前

curl-8.11.1: Applied and adjusted our curl changes to 8.7.1. jiraref:VBP-1535

  • 屬性 svn:eol-style 設為 native
檔案大小: 9.8 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <[email protected]>, 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 "hash.h"
30#include "llist.h"
31#include "curl_memory.h"
32
33/* The last #include file should be: */
34#include "memdebug.h"
35
36/* random patterns for API verification */
37#define HASHINIT 0x7017e781
38#define ITERINIT 0x5FEDCBA9
39
40static void
41hash_element_dtor(void *user, void *element)
42{
43 struct Curl_hash *h = (struct Curl_hash *) user;
44 struct Curl_hash_element *e = (struct Curl_hash_element *) element;
45
46 if(e->ptr) {
47 if(e->dtor)
48 e->dtor(e->key, e->key_len, e->ptr);
49 else
50 h->dtor(e->ptr);
51 e->ptr = NULL;
52 }
53
54 e->key_len = 0;
55
56 free(e);
57}
58
59/* Initializes a hash structure.
60 * Return 1 on error, 0 is fine.
61 *
62 * @unittest: 1602
63 * @unittest: 1603
64 */
65void
66Curl_hash_init(struct Curl_hash *h,
67 size_t slots,
68 hash_function hfunc,
69 comp_function comparator,
70 Curl_hash_dtor dtor)
71{
72 DEBUGASSERT(h);
73 DEBUGASSERT(slots);
74 DEBUGASSERT(hfunc);
75 DEBUGASSERT(comparator);
76 DEBUGASSERT(dtor);
77
78 h->table = NULL;
79 h->hash_func = hfunc;
80 h->comp_func = comparator;
81 h->dtor = dtor;
82 h->size = 0;
83 h->slots = slots;
84#ifdef DEBUGBUILD
85 h->init = HASHINIT;
86#endif
87}
88
89static struct Curl_hash_element *
90mk_hash_element(const void *key, size_t key_len, const void *p,
91 Curl_hash_elem_dtor dtor)
92{
93 /* allocate the struct plus memory after it to store the key */
94 struct Curl_hash_element *he = malloc(sizeof(struct Curl_hash_element) +
95 key_len);
96 if(he) {
97 /* copy the key */
98 memcpy(he->key, key, key_len);
99 he->key_len = key_len;
100 he->ptr = (void *) p;
101 he->dtor = dtor;
102 }
103 return he;
104}
105
106#define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)]
107
108void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
109 Curl_hash_elem_dtor dtor)
110{
111 struct Curl_hash_element *he;
112 struct Curl_llist_node *le;
113 struct Curl_llist *l;
114
115 DEBUGASSERT(h);
116 DEBUGASSERT(h->slots);
117 DEBUGASSERT(h->init == HASHINIT);
118 if(!h->table) {
119 size_t i;
120 h->table = malloc(h->slots * sizeof(struct Curl_llist));
121 if(!h->table)
122 return NULL; /* OOM */
123 for(i = 0; i < h->slots; ++i)
124 Curl_llist_init(&h->table[i], hash_element_dtor);
125 }
126
127 l = FETCH_LIST(h, key, key_len);
128
129 for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
130 he = (struct Curl_hash_element *) Curl_node_elem(le);
131 if(h->comp_func(he->key, he->key_len, key, key_len)) {
132 Curl_node_uremove(le, (void *)h);
133 --h->size;
134 break;
135 }
136 }
137
138 he = mk_hash_element(key, key_len, p, dtor);
139 if(he) {
140 Curl_llist_append(l, he, &he->list);
141 ++h->size;
142 return p; /* return the new entry */
143 }
144
145 return NULL; /* failure */
146}
147
148/* Insert the data in the hash. If there already was a match in the hash, that
149 * data is replaced. This function also "lazily" allocates the table if
150 * needed, as it is not done in the _init function (anymore).
151 *
152 * @unittest: 1305
153 * @unittest: 1602
154 * @unittest: 1603
155 */
156void *
157Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
158{
159 return Curl_hash_add2(h, key, key_len, p, NULL);
160}
161
162/* Remove the identified hash entry.
163 * Returns non-zero on failure.
164 *
165 * @unittest: 1603
166 */
167int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len)
168{
169 DEBUGASSERT(h);
170 DEBUGASSERT(h->slots);
171 DEBUGASSERT(h->init == HASHINIT);
172 if(h->table) {
173 struct Curl_llist_node *le;
174 struct Curl_llist *l = FETCH_LIST(h, key, key_len);
175
176 for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
177 struct Curl_hash_element *he = Curl_node_elem(le);
178 if(h->comp_func(he->key, he->key_len, key, key_len)) {
179 Curl_node_uremove(le, (void *) h);
180 --h->size;
181 return 0;
182 }
183 }
184 }
185 return 1;
186}
187
188/* Retrieves a hash element.
189 *
190 * @unittest: 1603
191 */
192void *
193Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
194{
195 DEBUGASSERT(h);
196 DEBUGASSERT(h->init == HASHINIT);
197 if(h->table) {
198 struct Curl_llist_node *le;
199 struct Curl_llist *l;
200 DEBUGASSERT(h->slots);
201 l = FETCH_LIST(h, key, key_len);
202 for(le = Curl_llist_head(l); le; le = Curl_node_next(le)) {
203 struct Curl_hash_element *he = Curl_node_elem(le);
204 if(h->comp_func(he->key, he->key_len, key, key_len)) {
205 return he->ptr;
206 }
207 }
208 }
209
210 return NULL;
211}
212
213/* Destroys all the entries in the given hash and resets its attributes,
214 * prepping the given hash for [static|dynamic] deallocation.
215 *
216 * @unittest: 1305
217 * @unittest: 1602
218 * @unittest: 1603
219 */
220void
221Curl_hash_destroy(struct Curl_hash *h)
222{
223 DEBUGASSERT(h->init == HASHINIT);
224 if(h->table) {
225 size_t i;
226 for(i = 0; i < h->slots; ++i) {
227 Curl_llist_destroy(&h->table[i], (void *) h);
228 }
229 Curl_safefree(h->table);
230 }
231 h->size = 0;
232 h->slots = 0;
233}
234
235/* Removes all the entries in the given hash.
236 *
237 * @unittest: 1602
238 */
239void
240Curl_hash_clean(struct Curl_hash *h)
241{
242 Curl_hash_clean_with_criterium(h, NULL, NULL);
243}
244
245size_t Curl_hash_count(struct Curl_hash *h)
246{
247 DEBUGASSERT(h->init == HASHINIT);
248 return h->size;
249}
250
251/* Cleans all entries that pass the comp function criteria. */
252void
253Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
254 int (*comp)(void *, void *))
255{
256 size_t i;
257
258 if(!h || !h->table)
259 return;
260
261 DEBUGASSERT(h->init == HASHINIT);
262 for(i = 0; i < h->slots; ++i) {
263 struct Curl_llist *list = &h->table[i];
264 struct Curl_llist_node *le =
265 Curl_llist_head(list); /* get first list entry */
266 while(le) {
267 struct Curl_hash_element *he = Curl_node_elem(le);
268 struct Curl_llist_node *lnext = Curl_node_next(le);
269 /* ask the callback function if we shall remove this entry or not */
270 if(!comp || comp(user, he->ptr)) {
271 Curl_node_uremove(le, (void *) h);
272 --h->size; /* one less entry in the hash now */
273 }
274 le = lnext;
275 }
276 }
277}
278
279size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num)
280{
281 const char *key_str = (const char *) key;
282 const char *end = key_str + key_length;
283 size_t h = 5381;
284
285 while(key_str < end) {
286 size_t j = (size_t)*key_str++;
287 h += h << 5;
288 h ^= j;
289 }
290
291 return (h % slots_num);
292}
293
294size_t Curl_str_key_compare(void *k1, size_t key1_len,
295 void *k2, size_t key2_len)
296{
297 if((key1_len == key2_len) && !memcmp(k1, k2, key1_len))
298 return 1;
299
300 return 0;
301}
302
303void Curl_hash_start_iterate(struct Curl_hash *hash,
304 struct Curl_hash_iterator *iter)
305{
306 DEBUGASSERT(hash->init == HASHINIT);
307 iter->hash = hash;
308 iter->slot_index = 0;
309 iter->current_element = NULL;
310#ifdef DEBUGBUILD
311 iter->init = ITERINIT;
312#endif
313}
314
315struct Curl_hash_element *
316Curl_hash_next_element(struct Curl_hash_iterator *iter)
317{
318 struct Curl_hash *h;
319 DEBUGASSERT(iter->init == ITERINIT);
320 h = iter->hash;
321 if(!h->table)
322 return NULL; /* empty hash, nothing to return */
323
324 /* Get the next element in the current list, if any */
325 if(iter->current_element)
326 iter->current_element = Curl_node_next(iter->current_element);
327
328 /* If we have reached the end of the list, find the next one */
329 if(!iter->current_element) {
330 size_t i;
331 for(i = iter->slot_index; i < h->slots; i++) {
332 if(Curl_llist_head(&h->table[i])) {
333 iter->current_element = Curl_llist_head(&h->table[i]);
334 iter->slot_index = i + 1;
335 break;
336 }
337 }
338 }
339
340 if(iter->current_element) {
341 struct Curl_hash_element *he = Curl_node_elem(iter->current_element);
342 return he;
343 }
344 return NULL;
345}
346
347#if 0 /* useful function for debugging hashes and their contents */
348void Curl_hash_print(struct Curl_hash *h,
349 void (*func)(void *))
350{
351 struct Curl_hash_iterator iter;
352 struct Curl_hash_element *he;
353 size_t last_index = ~0;
354
355 if(!h)
356 return;
357
358 fprintf(stderr, "=Hash dump=\n");
359
360 Curl_hash_start_iterate(h, &iter);
361
362 he = Curl_hash_next_element(&iter);
363 while(he) {
364 if(iter.slot_index != last_index) {
365 fprintf(stderr, "index %d:", iter.slot_index);
366 if(last_index != ~0) {
367 fprintf(stderr, "\n");
368 }
369 last_index = iter.slot_index;
370 }
371
372 if(func)
373 func(he->ptr);
374 else
375 fprintf(stderr, " [%p]", (void *)he->ptr);
376
377 he = Curl_hash_next_element(&iter);
378 }
379 fprintf(stderr, "\n");
380}
381#endif
382
383void Curl_hash_offt_init(struct Curl_hash *h,
384 size_t slots,
385 Curl_hash_dtor dtor)
386{
387 Curl_hash_init(h, slots, Curl_hash_str, Curl_str_key_compare, dtor);
388}
389
390void *Curl_hash_offt_set(struct Curl_hash *h, curl_off_t id, void *elem)
391{
392 return Curl_hash_add(h, &id, sizeof(id), elem);
393}
394
395int Curl_hash_offt_remove(struct Curl_hash *h, curl_off_t id)
396{
397 return Curl_hash_delete(h, &id, sizeof(id));
398}
399
400void *Curl_hash_offt_get(struct Curl_hash *h, curl_off_t id)
401{
402 return Curl_hash_pick(h, &id, sizeof(id));
403}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette