VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/hash.c@ 97138

最後變更 在這個檔案從97138是 95312,由 vboxsync 提交於 3 年 前

libs/{curl,libxml2}: OSE export fixes, bugref:8515

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

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