1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
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 http://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: hash.c,v 1.1.1.1 2008-09-23 16:32:05 hoffman Exp $
22 ***************************************************************************/
33 /* this must be the last include file */
37 hash_element_dtor(void *user
, void *element
)
39 struct curl_hash
*h
= (struct curl_hash
*) user
;
40 struct curl_hash_element
*e
= (struct curl_hash_element
*) element
;
50 /* return 1 on error, 0 is fine */
52 Curl_hash_init(struct curl_hash
*h
,
55 comp_function comparator
,
60 if(!slots
|| !hfunc
|| !comparator
||!dtor
) {
61 return 1; /* failure */
65 h
->comp_func
= comparator
;
70 h
->table
= (struct curl_llist
**) malloc(slots
* sizeof(struct curl_llist
*));
72 for (i
= 0; i
< slots
; ++i
) {
73 h
->table
[i
] = Curl_llist_alloc((curl_llist_dtor
) hash_element_dtor
);
76 Curl_llist_destroy(h
->table
[i
], NULL
);
78 return 1; /* failure */
84 return 1; /* failure */
88 Curl_hash_alloc(int slots
,
90 comp_function comparator
,
95 if(!slots
|| !hfunc
|| !comparator
||!dtor
) {
96 return NULL
; /* failure */
99 h
= (struct curl_hash
*) malloc(sizeof(struct curl_hash
));
101 if(Curl_hash_init(h
, slots
, hfunc
, comparator
, dtor
)) {
113 static struct curl_hash_element
*
114 mk_hash_element(const void *key
, size_t key_len
, const void *p
)
116 struct curl_hash_element
*he
=
117 (struct curl_hash_element
*) malloc(sizeof(struct curl_hash_element
));
120 void *dupkey
= malloc(key_len
);
123 memcpy(dupkey
, key
, key_len
);
126 he
->key_len
= key_len
;
127 he
->ptr
= (void *) p
;
130 /* failed to duplicate the key, free memory and fail */
138 #define FETCH_LIST(x,y,z) x->table[x->hash_func(y, z, x->slots)]
140 /* Return the data in the hash. If there already was a match in the hash,
141 that data is returned. */
143 Curl_hash_add(struct curl_hash
*h
, void *key
, size_t key_len
, void *p
)
145 struct curl_hash_element
*he
;
146 struct curl_llist_element
*le
;
147 struct curl_llist
*l
= FETCH_LIST (h
, key
, key_len
);
149 for (le
= l
->head
; le
; le
= le
->next
) {
150 he
= (struct curl_hash_element
*) le
->ptr
;
151 if(h
->comp_func(he
->key
, he
->key_len
, key
, key_len
)) {
152 h
->dtor(p
); /* remove the NEW entry */
153 return he
->ptr
; /* return the EXISTING entry */
157 he
= mk_hash_element(key
, key_len
, p
);
159 if(Curl_llist_insert_next(l
, l
->tail
, he
)) {
161 return p
; /* return the new entry */
164 * Couldn't insert it, destroy the 'he' element and the key again. We
165 * don't call hash_element_dtor() since that would also call the
166 * "destructor" for the actual data 'p'. When we fail, we shall not touch
173 return NULL
; /* failure */
176 /* remove the identified hash entry, returns non-zero on failure */
177 int Curl_hash_delete(struct curl_hash
*h
, void *key
, size_t key_len
)
179 struct curl_llist_element
*le
;
180 struct curl_hash_element
*he
;
181 struct curl_llist
*l
= FETCH_LIST(h
, key
, key_len
);
183 for (le
= l
->head
; le
; le
= le
->next
) {
185 if(h
->comp_func(he
->key
, he
->key_len
, key
, key_len
)) {
186 Curl_llist_remove(l
, le
, (void *) h
);
194 Curl_hash_pick(struct curl_hash
*h
, void *key
, size_t key_len
)
196 struct curl_llist_element
*le
;
197 struct curl_hash_element
*he
;
198 struct curl_llist
*l
= FETCH_LIST(h
, key
, key_len
);
200 for (le
= l
->head
; le
; le
= le
->next
) {
202 if(h
->comp_func(he
->key
, he
->key_len
, key
, key_len
)) {
210 #if defined(CURLDEBUG) && defined(AGGRESIVE_TEST)
212 Curl_hash_apply(curl_hash
*h
, void *user
,
213 void (*cb
)(void *user
, void *ptr
))
215 struct curl_llist_element
*le
;
218 for (i
= 0; i
< h
->slots
; ++i
) {
219 for (le
= (h
->table
[i
])->head
;
222 curl_hash_element
*el
= le
->ptr
;
230 Curl_hash_clean(struct curl_hash
*h
)
234 for (i
= 0; i
< h
->slots
; ++i
) {
235 Curl_llist_destroy(h
->table
[i
], (void *) h
);
242 Curl_hash_clean_with_criterium(struct curl_hash
*h
, void *user
,
243 int (*comp
)(void *, void *))
245 struct curl_llist_element
*le
;
246 struct curl_llist_element
*lnext
;
247 struct curl_llist
*list
;
250 for (i
= 0; i
< h
->slots
; ++i
) {
252 le
= list
->head
; /* get first list entry */
254 struct curl_hash_element
*he
= le
->ptr
;
256 /* ask the callback function if we shall remove this entry or not */
257 if(comp(user
, he
->ptr
)) {
258 Curl_llist_remove(list
, le
, (void *) h
);
259 --h
->size
; /* one less entry in the hash now */
267 Curl_hash_destroy(struct curl_hash
*h
)
276 size_t Curl_hash_str(void* key
, size_t key_length
, size_t slots_num
)
278 const char* key_str
= (const char *) key
;
279 const char *end
= key_str
+ key_length
;
280 unsigned long h
= 5381;
282 while(key_str
< end
) {
284 h
^= (unsigned long) *key_str
++;
287 return (h
% slots_num
);
290 size_t Curl_str_key_compare(void*k1
, size_t key1_len
, void*k2
, size_t key2_len
)
292 char *key1
= (char *)k1
;
293 char *key2
= (char *)k2
;
295 if(key1_len
== key2_len
&&
297 memcmp(key1
, key2
, key1_len
) == 0) {
304 #if 0 /* useful function for debugging hashes and their contents */
305 void Curl_hash_print(struct curl_hash
*h
,
306 void (*func
)(void *))
309 struct curl_llist_element
*le
;
310 struct curl_llist
*list
;
311 struct curl_hash_element
*he
;
315 fprintf(stderr
, "=Hash dump=\n");
317 for (i
= 0; i
< h
->slots
; i
++) {
319 le
= list
->head
; /* get first list entry */
321 fprintf(stderr
, "index %d:", i
);
327 fprintf(stderr
, " [%p]", he
->ptr
);
330 fprintf(stderr
, "\n");