Annotation of embedaddon/curl/lib/hash.c, revision 1.1
1.1 ! misho 1: /***************************************************************************
! 2: * _ _ ____ _
! 3: * Project ___| | | | _ \| |
! 4: * / __| | | | |_) | |
! 5: * | (__| |_| | _ <| |___
! 6: * \___|\___/|_| \_\_____|
! 7: *
! 8: * Copyright (C) 1998 - 2018, 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.haxx.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:
! 34: static void
! 35: hash_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: */
! 56: int
! 57: Curl_hash_init(struct curl_hash *h,
! 58: int slots,
! 59: hash_function hfunc,
! 60: comp_function comparator,
! 61: curl_hash_dtor dtor)
! 62: {
! 63: if(!slots || !hfunc || !comparator ||!dtor) {
! 64: return 1; /* failure */
! 65: }
! 66:
! 67: h->hash_func = hfunc;
! 68: h->comp_func = comparator;
! 69: h->dtor = dtor;
! 70: h->size = 0;
! 71: h->slots = slots;
! 72:
! 73: h->table = malloc(slots * sizeof(struct curl_llist));
! 74: if(h->table) {
! 75: int i;
! 76: for(i = 0; i < slots; ++i)
! 77: Curl_llist_init(&h->table[i], (curl_llist_dtor) hash_element_dtor);
! 78: return 0; /* fine */
! 79: }
! 80: h->slots = 0;
! 81: return 1; /* failure */
! 82: }
! 83:
! 84: static struct curl_hash_element *
! 85: mk_hash_element(const void *key, size_t key_len, const void *p)
! 86: {
! 87: /* allocate the struct plus memory after it to store the key */
! 88: struct curl_hash_element *he = malloc(sizeof(struct curl_hash_element) +
! 89: key_len);
! 90: if(he) {
! 91: /* copy the key */
! 92: memcpy(he->key, key, key_len);
! 93: he->key_len = key_len;
! 94: he->ptr = (void *) p;
! 95: }
! 96: return he;
! 97: }
! 98:
! 99: #define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)]
! 100:
! 101: /* Insert the data in the hash. If there already was a match in the hash,
! 102: * that data is replaced.
! 103: *
! 104: * @unittest: 1305
! 105: * @unittest: 1602
! 106: * @unittest: 1603
! 107: */
! 108: void *
! 109: Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p)
! 110: {
! 111: struct curl_hash_element *he;
! 112: struct curl_llist_element *le;
! 113: struct curl_llist *l = FETCH_LIST(h, key, key_len);
! 114:
! 115: for(le = l->head; le; le = le->next) {
! 116: he = (struct curl_hash_element *) le->ptr;
! 117: if(h->comp_func(he->key, he->key_len, key, key_len)) {
! 118: Curl_llist_remove(l, le, (void *)h);
! 119: --h->size;
! 120: break;
! 121: }
! 122: }
! 123:
! 124: he = mk_hash_element(key, key_len, p);
! 125: if(he) {
! 126: Curl_llist_insert_next(l, l->tail, he, &he->list);
! 127: ++h->size;
! 128: return p; /* return the new entry */
! 129: }
! 130:
! 131: return NULL; /* failure */
! 132: }
! 133:
! 134: /* Remove the identified hash entry.
! 135: * Returns non-zero on failure.
! 136: *
! 137: * @unittest: 1603
! 138: */
! 139: int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len)
! 140: {
! 141: struct curl_llist_element *le;
! 142: struct curl_llist *l = FETCH_LIST(h, key, key_len);
! 143:
! 144: for(le = l->head; le; le = le->next) {
! 145: struct curl_hash_element *he = le->ptr;
! 146: if(h->comp_func(he->key, he->key_len, key, key_len)) {
! 147: Curl_llist_remove(l, le, (void *) h);
! 148: --h->size;
! 149: return 0;
! 150: }
! 151: }
! 152: return 1;
! 153: }
! 154:
! 155: /* Retrieves a hash element.
! 156: *
! 157: * @unittest: 1603
! 158: */
! 159: void *
! 160: Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len)
! 161: {
! 162: struct curl_llist_element *le;
! 163: struct curl_llist *l;
! 164:
! 165: if(h) {
! 166: l = FETCH_LIST(h, key, key_len);
! 167: for(le = l->head; le; le = le->next) {
! 168: struct curl_hash_element *he = le->ptr;
! 169: if(h->comp_func(he->key, he->key_len, key, key_len)) {
! 170: return he->ptr;
! 171: }
! 172: }
! 173: }
! 174:
! 175: return NULL;
! 176: }
! 177:
! 178: #if defined(DEBUGBUILD) && defined(AGGRESIVE_TEST)
! 179: void
! 180: Curl_hash_apply(curl_hash *h, void *user,
! 181: void (*cb)(void *user, void *ptr))
! 182: {
! 183: struct curl_llist_element *le;
! 184: int i;
! 185:
! 186: for(i = 0; i < h->slots; ++i) {
! 187: for(le = (h->table[i])->head;
! 188: le;
! 189: le = le->next) {
! 190: curl_hash_element *el = le->ptr;
! 191: cb(user, el->ptr);
! 192: }
! 193: }
! 194: }
! 195: #endif
! 196:
! 197: /* Destroys all the entries in the given hash and resets its attributes,
! 198: * prepping the given hash for [static|dynamic] deallocation.
! 199: *
! 200: * @unittest: 1305
! 201: * @unittest: 1602
! 202: * @unittest: 1603
! 203: */
! 204: void
! 205: Curl_hash_destroy(struct curl_hash *h)
! 206: {
! 207: int i;
! 208:
! 209: for(i = 0; i < h->slots; ++i) {
! 210: Curl_llist_destroy(&h->table[i], (void *) h);
! 211: }
! 212:
! 213: Curl_safefree(h->table);
! 214: h->size = 0;
! 215: h->slots = 0;
! 216: }
! 217:
! 218: /* Removes all the entries in the given hash.
! 219: *
! 220: * @unittest: 1602
! 221: */
! 222: void
! 223: Curl_hash_clean(struct curl_hash *h)
! 224: {
! 225: Curl_hash_clean_with_criterium(h, NULL, NULL);
! 226: }
! 227:
! 228: /* Cleans all entries that pass the comp function criteria. */
! 229: void
! 230: Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
! 231: int (*comp)(void *, void *))
! 232: {
! 233: struct curl_llist_element *le;
! 234: struct curl_llist_element *lnext;
! 235: struct curl_llist *list;
! 236: int i;
! 237:
! 238: if(!h)
! 239: return;
! 240:
! 241: for(i = 0; i < h->slots; ++i) {
! 242: list = &h->table[i];
! 243: le = list->head; /* get first list entry */
! 244: while(le) {
! 245: struct curl_hash_element *he = le->ptr;
! 246: lnext = le->next;
! 247: /* ask the callback function if we shall remove this entry or not */
! 248: if(comp == NULL || comp(user, he->ptr)) {
! 249: Curl_llist_remove(list, le, (void *) h);
! 250: --h->size; /* one less entry in the hash now */
! 251: }
! 252: le = lnext;
! 253: }
! 254: }
! 255: }
! 256:
! 257: size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num)
! 258: {
! 259: const char *key_str = (const char *) key;
! 260: const char *end = key_str + key_length;
! 261: size_t h = 5381;
! 262:
! 263: while(key_str < end) {
! 264: h += h << 5;
! 265: h ^= *key_str++;
! 266: }
! 267:
! 268: return (h % slots_num);
! 269: }
! 270:
! 271: size_t Curl_str_key_compare(void *k1, size_t key1_len,
! 272: void *k2, size_t key2_len)
! 273: {
! 274: if((key1_len == key2_len) && !memcmp(k1, k2, key1_len))
! 275: return 1;
! 276:
! 277: return 0;
! 278: }
! 279:
! 280: void Curl_hash_start_iterate(struct curl_hash *hash,
! 281: struct curl_hash_iterator *iter)
! 282: {
! 283: iter->hash = hash;
! 284: iter->slot_index = 0;
! 285: iter->current_element = NULL;
! 286: }
! 287:
! 288: struct curl_hash_element *
! 289: Curl_hash_next_element(struct curl_hash_iterator *iter)
! 290: {
! 291: struct curl_hash *h = iter->hash;
! 292:
! 293: /* Get the next element in the current list, if any */
! 294: if(iter->current_element)
! 295: iter->current_element = iter->current_element->next;
! 296:
! 297: /* If we have reached the end of the list, find the next one */
! 298: if(!iter->current_element) {
! 299: int i;
! 300: for(i = iter->slot_index; i < h->slots; i++) {
! 301: if(h->table[i].head) {
! 302: iter->current_element = h->table[i].head;
! 303: iter->slot_index = i + 1;
! 304: break;
! 305: }
! 306: }
! 307: }
! 308:
! 309: if(iter->current_element) {
! 310: struct curl_hash_element *he = iter->current_element->ptr;
! 311: return he;
! 312: }
! 313: iter->current_element = NULL;
! 314: return NULL;
! 315: }
! 316:
! 317: #if 0 /* useful function for debugging hashes and their contents */
! 318: void Curl_hash_print(struct curl_hash *h,
! 319: void (*func)(void *))
! 320: {
! 321: struct curl_hash_iterator iter;
! 322: struct curl_hash_element *he;
! 323: int last_index = -1;
! 324:
! 325: if(!h)
! 326: return;
! 327:
! 328: fprintf(stderr, "=Hash dump=\n");
! 329:
! 330: Curl_hash_start_iterate(h, &iter);
! 331:
! 332: he = Curl_hash_next_element(&iter);
! 333: while(he) {
! 334: if(iter.slot_index != last_index) {
! 335: fprintf(stderr, "index %d:", iter.slot_index);
! 336: if(last_index >= 0) {
! 337: fprintf(stderr, "\n");
! 338: }
! 339: last_index = iter.slot_index;
! 340: }
! 341:
! 342: if(func)
! 343: func(he->ptr);
! 344: else
! 345: fprintf(stderr, " [%p]", (void *)he->ptr);
! 346:
! 347: he = Curl_hash_next_element(&iter);
! 348: }
! 349: fprintf(stderr, "\n");
! 350: }
! 351: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>