Annotation of embedaddon/curl/lib/hash.c, revision 1.1.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>