hash.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
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 /* The last #include file should be: */
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 /* Initializes a hash structure.
00053  * Return 1 on error, 0 is fine.
00054  *
00055  * @unittest: 1602
00056  * @unittest: 1603
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; /* failure */
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; /* failure */
00090       }
00091     }
00092     return 0; /* fine */
00093   }
00094   else {
00095     h->slots = 0;
00096     return 1; /* failure */
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       /* copy the key */
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       /* failed to duplicate the key, free memory and fail */
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 /* Insert the data in the hash. If there already was a match in the hash,
00127  * that data is replaced.
00128  *
00129  * @unittest: 1305
00130  * @unittest: 1602
00131  * @unittest: 1603
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; /* return the new entry */
00154     }
00155     /*
00156      * Couldn't insert it, destroy the 'he' element and the key again. We
00157      * don't call hash_element_dtor() since that would also call the
00158      * "destructor" for the actual data 'p'. When we fail, we shall not touch
00159      * that data.
00160      */
00161     free(he->key);
00162     free(he);
00163   }
00164 
00165   return NULL; /* failure */
00166 }
00167 
00168 /* Remove the identified hash entry.
00169  * Returns non-zero on failure.
00170  *
00171  * @unittest: 1603
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 /* Retrieves a hash element.
00191  *
00192  * @unittest: 1603
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 /* Destroys all the entries in the given hash and resets its attributes,
00234  * prepping the given hash for [static|dynamic] deallocation.
00235  *
00236  * @unittest: 1305
00237  * @unittest: 1602
00238  * @unittest: 1603
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 /* Removes all the entries in the given hash.
00256  *
00257  * @unittest: 1602
00258  */
00259 void
00260 Curl_hash_clean(struct curl_hash *h)
00261 {
00262   Curl_hash_clean_with_criterium(h, NULL, NULL);
00263 }
00264 
00265 /* Cleans all entries that pass the comp function criteria. */
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; /* get first list entry */
00281     while(le) {
00282       struct curl_hash_element *he = le->ptr;
00283       lnext = le->next;
00284       /* ask the callback function if we shall remove this entry or not */
00285       if(comp == NULL || comp(user, he->ptr)) {
00286         Curl_llist_remove(list, le, (void *) h);
00287         --h->size; /* one less entry in the hash now */
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   /* Get the next element in the current list, if any */
00332   if(iter->current_element)
00333     iter->current_element = iter->current_element->next;
00334 
00335   /* If we have reached the end of the list, find the next one */
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 /* useful function for debugging hashes and their contents */
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


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:04