File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / hash.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>