00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "curl_setup.h"
00024
00025 #include <curl/curl.h>
00026
00027 #include "hash.h"
00028 #include "llist.h"
00029 #include "curl_memory.h"
00030
00031
00032 #include "memdebug.h"
00033
00034 static void
00035 hash_element_dtor(void *user, void *element)
00036 {
00037 struct curl_hash *h = (struct curl_hash *) user;
00038 struct curl_hash_element *e = (struct curl_hash_element *) element;
00039
00040 Curl_safefree(e->key);
00041
00042 if(e->ptr) {
00043 h->dtor(e->ptr);
00044 e->ptr = NULL;
00045 }
00046
00047 e->key_len = 0;
00048
00049 free(e);
00050 }
00051
00052
00053
00054
00055
00056
00057
00058 int
00059 Curl_hash_init(struct curl_hash *h,
00060 int slots,
00061 hash_function hfunc,
00062 comp_function comparator,
00063 curl_hash_dtor dtor)
00064 {
00065 int i;
00066
00067 if(!slots || !hfunc || !comparator ||!dtor) {
00068 return 1;
00069 }
00070
00071 h->hash_func = hfunc;
00072 h->comp_func = comparator;
00073 h->dtor = dtor;
00074 h->size = 0;
00075 h->slots = slots;
00076
00077 h->table = malloc(slots * sizeof(struct curl_llist *));
00078 if(h->table) {
00079 for(i = 0; i < slots; ++i) {
00080 h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor);
00081 if(!h->table[i]) {
00082 while(i--) {
00083 Curl_llist_destroy(h->table[i], NULL);
00084 h->table[i] = NULL;
00085 }
00086 free(h->table);
00087 h->table = NULL;
00088 h->slots = 0;
00089 return 1;
00090 }
00091 }
00092 return 0;
00093 }
00094 else {
00095 h->slots = 0;
00096 return 1;
00097 }
00098 }
00099
00100 static struct curl_hash_element *
00101 mk_hash_element(const void *key, size_t key_len, const void *p)
00102 {
00103 struct curl_hash_element *he = malloc(sizeof(struct curl_hash_element));
00104
00105 if(he) {
00106 void *dupkey = malloc(key_len);
00107 if(dupkey) {
00108
00109 memcpy(dupkey, key, key_len);
00110
00111 he->key = dupkey;
00112 he->key_len = key_len;
00113 he->ptr = (void *) p;
00114 }
00115 else {
00116
00117 free(he);
00118 he = NULL;
00119 }
00120 }
00121 return he;
00122 }
00123
00124 #define FETCH_LIST(x,y,z) x->table[x->hash_func(y, z, x->slots)]
00125
00126
00127
00128
00129
00130
00131
00132
00133 void *
00134 Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p)
00135 {
00136 struct curl_hash_element *he;
00137 struct curl_llist_element *le;
00138 struct curl_llist *l = FETCH_LIST(h, key, key_len);
00139
00140 for(le = l->head; le; le = le->next) {
00141 he = (struct curl_hash_element *) le->ptr;
00142 if(h->comp_func(he->key, he->key_len, key, key_len)) {
00143 Curl_llist_remove(l, le, (void *)h);
00144 --h->size;
00145 break;
00146 }
00147 }
00148
00149 he = mk_hash_element(key, key_len, p);
00150 if(he) {
00151 if(Curl_llist_insert_next(l, l->tail, he)) {
00152 ++h->size;
00153 return p;
00154 }
00155
00156
00157
00158
00159
00160
00161 free(he->key);
00162 free(he);
00163 }
00164
00165 return NULL;
00166 }
00167
00168
00169
00170
00171
00172
00173 int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len)
00174 {
00175 struct curl_llist_element *le;
00176 struct curl_hash_element *he;
00177 struct curl_llist *l = FETCH_LIST(h, key, key_len);
00178
00179 for(le = l->head; le; le = le->next) {
00180 he = le->ptr;
00181 if(h->comp_func(he->key, he->key_len, key, key_len)) {
00182 Curl_llist_remove(l, le, (void *) h);
00183 --h->size;
00184 return 0;
00185 }
00186 }
00187 return 1;
00188 }
00189
00190
00191
00192
00193
00194 void *
00195 Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len)
00196 {
00197 struct curl_llist_element *le;
00198 struct curl_hash_element *he;
00199 struct curl_llist *l;
00200
00201 if(h) {
00202 l = FETCH_LIST(h, key, key_len);
00203 for(le = l->head; le; le = le->next) {
00204 he = le->ptr;
00205 if(h->comp_func(he->key, he->key_len, key, key_len)) {
00206 return he->ptr;
00207 }
00208 }
00209 }
00210
00211 return NULL;
00212 }
00213
00214 #if defined(DEBUGBUILD) && defined(AGGRESIVE_TEST)
00215 void
00216 Curl_hash_apply(curl_hash *h, void *user,
00217 void (*cb)(void *user, void *ptr))
00218 {
00219 struct curl_llist_element *le;
00220 int i;
00221
00222 for(i = 0; i < h->slots; ++i) {
00223 for(le = (h->table[i])->head;
00224 le;
00225 le = le->next) {
00226 curl_hash_element *el = le->ptr;
00227 cb(user, el->ptr);
00228 }
00229 }
00230 }
00231 #endif
00232
00233
00234
00235
00236
00237
00238
00239
00240 void
00241 Curl_hash_destroy(struct curl_hash *h)
00242 {
00243 int i;
00244
00245 for(i = 0; i < h->slots; ++i) {
00246 Curl_llist_destroy(h->table[i], (void *) h);
00247 h->table[i] = NULL;
00248 }
00249
00250 Curl_safefree(h->table);
00251 h->size = 0;
00252 h->slots = 0;
00253 }
00254
00255
00256
00257
00258
00259 void
00260 Curl_hash_clean(struct curl_hash *h)
00261 {
00262 Curl_hash_clean_with_criterium(h, NULL, NULL);
00263 }
00264
00265
00266 void
00267 Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
00268 int (*comp)(void *, void *))
00269 {
00270 struct curl_llist_element *le;
00271 struct curl_llist_element *lnext;
00272 struct curl_llist *list;
00273 int i;
00274
00275 if(!h)
00276 return;
00277
00278 for(i = 0; i < h->slots; ++i) {
00279 list = h->table[i];
00280 le = list->head;
00281 while(le) {
00282 struct curl_hash_element *he = le->ptr;
00283 lnext = le->next;
00284
00285 if(comp == NULL || comp(user, he->ptr)) {
00286 Curl_llist_remove(list, le, (void *) h);
00287 --h->size;
00288 }
00289 le = lnext;
00290 }
00291 }
00292 }
00293
00294 size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num)
00295 {
00296 const char *key_str = (const char *) key;
00297 const char *end = key_str + key_length;
00298 unsigned long h = 5381;
00299
00300 while(key_str < end) {
00301 h += h << 5;
00302 h ^= (unsigned long) *key_str++;
00303 }
00304
00305 return (h % slots_num);
00306 }
00307
00308 size_t Curl_str_key_compare(void *k1, size_t key1_len,
00309 void *k2, size_t key2_len)
00310 {
00311 if((key1_len == key2_len) && !memcmp(k1, k2, key1_len))
00312 return 1;
00313
00314 return 0;
00315 }
00316
00317 void Curl_hash_start_iterate(struct curl_hash *hash,
00318 struct curl_hash_iterator *iter)
00319 {
00320 iter->hash = hash;
00321 iter->slot_index = 0;
00322 iter->current_element = NULL;
00323 }
00324
00325 struct curl_hash_element *
00326 Curl_hash_next_element(struct curl_hash_iterator *iter)
00327 {
00328 int i;
00329 struct curl_hash *h = iter->hash;
00330
00331
00332 if(iter->current_element)
00333 iter->current_element = iter->current_element->next;
00334
00335
00336 if(!iter->current_element) {
00337 for(i = iter->slot_index;i < h->slots;i++) {
00338 if(h->table[i]->head) {
00339 iter->current_element = h->table[i]->head;
00340 iter->slot_index = i+1;
00341 break;
00342 }
00343 }
00344 }
00345
00346 if(iter->current_element) {
00347 struct curl_hash_element *he = iter->current_element->ptr;
00348 return he;
00349 }
00350 else {
00351 iter->current_element = NULL;
00352 return NULL;
00353 }
00354 }
00355
00356 #if 0
00357 void Curl_hash_print(struct curl_hash *h,
00358 void (*func)(void *))
00359 {
00360 struct curl_hash_iterator iter;
00361 struct curl_hash_element *he;
00362 int last_index = -1;
00363
00364 if(!h)
00365 return;
00366
00367 fprintf(stderr, "=Hash dump=\n");
00368
00369 Curl_hash_start_iterate(h, &iter);
00370
00371 he = Curl_hash_next_element(&iter);
00372 while(he) {
00373 if(iter.slot_index != last_index) {
00374 fprintf(stderr, "index %d:", iter.slot_index);
00375 if(last_index >= 0) {
00376 fprintf(stderr, "\n");
00377 }
00378 last_index = iter.slot_index;
00379 }
00380
00381 if(func)
00382 func(he->ptr);
00383 else
00384 fprintf(stderr, " [%p]", (void *)he->ptr);
00385
00386 he = Curl_hash_next_element(&iter);
00387 }
00388 fprintf(stderr, "\n");
00389 }
00390 #endif