LCOV - code coverage report
Current view: top level - lib/container - map.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 70 70 100.0 %
Date: 2021-11-24 03:28:48 Functions: 83 87 95.4 %

          Line data    Source code
       1             : /* Copyright (c) 2003-2004, Roger Dingledine
       2             :  * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
       3             :  * Copyright (c) 2007-2021, The Tor Project, Inc. */
       4             : /* See LICENSE for licensing information */
       5             : 
       6             : /**
       7             :  * \file map.c
       8             :  *
       9             :  * \brief Hash-table implementations of a string-to-void* map, and of
      10             :  * a digest-to-void* map.
      11             :  **/
      12             : 
      13             : #include "lib/container/map.h"
      14             : #include "lib/ctime/di_ops.h"
      15             : #include "lib/defs/digest_sizes.h"
      16             : #include "lib/string/util_string.h"
      17             : #include "lib/malloc/malloc.h"
      18             : 
      19             : #include "lib/log/util_bug.h"
      20             : 
      21             : #include <stdlib.h>
      22             : #include <string.h>
      23             : 
      24             : #include "ext/ht.h"
      25             : 
      26             : /** Helper: Declare an entry type and a map type to implement a mapping using
      27             :  * ht.h.  The map type will be called <b>maptype</b>.  The key part of each
      28             :  * entry is declared using the C declaration <b>keydecl</b>.  All functions
      29             :  * and types associated with the map get prefixed with <b>prefix</b> */
      30             : #define DEFINE_MAP_STRUCTS(maptype, keydecl, prefix)      \
      31             :   typedef struct prefix ## entry_t {                      \
      32             :     HT_ENTRY(prefix ## entry_t) node;                     \
      33             :     void *val;                                            \
      34             :     keydecl;                                              \
      35             :   } prefix ## entry_t;                                    \
      36             :   struct maptype {                                        \
      37             :     HT_HEAD(prefix ## impl, prefix ## entry_t) head;      \
      38             :   }
      39             : 
      40             : DEFINE_MAP_STRUCTS(strmap_t, char *key, strmap_);
      41             : DEFINE_MAP_STRUCTS(digestmap_t, char key[DIGEST_LEN], digestmap_);
      42             : DEFINE_MAP_STRUCTS(digest256map_t, uint8_t key[DIGEST256_LEN], digest256map_);
      43             : 
      44             : /** Helper: compare strmap_entry_t objects by key value. */
      45             : static inline int
      46       23279 : strmap_entries_eq(const strmap_entry_t *a, const strmap_entry_t *b)
      47             : {
      48       23279 :   return !strcmp(a->key, b->key);
      49             : }
      50             : 
      51             : /** Helper: return a hash value for a strmap_entry_t. */
      52             : static inline unsigned int
      53       27416 : strmap_entry_hash(const strmap_entry_t *a)
      54             : {
      55       27416 :   return (unsigned) siphash24g(a->key, strlen(a->key));
      56             : }
      57             : 
      58             : /** Helper: compare digestmap_entry_t objects by key value. */
      59             : static inline int
      60       12325 : digestmap_entries_eq(const digestmap_entry_t *a, const digestmap_entry_t *b)
      61             : {
      62       12325 :   return tor_memeq(a->key, b->key, DIGEST_LEN);
      63             : }
      64             : 
      65             : /** Helper: return a hash value for a digest_map_t. */
      66             : static inline unsigned int
      67       19126 : digestmap_entry_hash(const digestmap_entry_t *a)
      68             : {
      69       19126 :   return (unsigned) siphash24g(a->key, DIGEST_LEN);
      70             : }
      71             : 
      72             : /** Helper: compare digestmap_entry_t objects by key value. */
      73             : static inline int
      74         596 : digest256map_entries_eq(const digest256map_entry_t *a,
      75             :                         const digest256map_entry_t *b)
      76             : {
      77         596 :   return tor_memeq(a->key, b->key, DIGEST256_LEN);
      78             : }
      79             : 
      80             : /** Helper: return a hash value for a digest_map_t. */
      81             : static inline unsigned int
      82         983 : digest256map_entry_hash(const digest256map_entry_t *a)
      83             : {
      84         983 :   return (unsigned) siphash24g(a->key, DIGEST256_LEN);
      85             : }
      86             : 
      87       50300 : HT_PROTOTYPE(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
      88             :              strmap_entries_eq);
      89        1987 : HT_GENERATE2(strmap_impl, strmap_entry_t, node, strmap_entry_hash,
      90             :              strmap_entries_eq, 0.6, tor_reallocarray_, tor_free_);
      91             : 
      92       90225 : HT_PROTOTYPE(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
      93             :              digestmap_entries_eq);
      94       29434 : HT_GENERATE2(digestmap_impl, digestmap_entry_t, node, digestmap_entry_hash,
      95             :              digestmap_entries_eq, 0.6, tor_reallocarray_, tor_free_);
      96             : 
      97       19547 : HT_PROTOTYPE(digest256map_impl, digest256map_entry_t, node,
      98             :              digest256map_entry_hash,
      99             :              digest256map_entries_eq);
     100        1689 : HT_GENERATE2(digest256map_impl, digest256map_entry_t, node,
     101             :              digest256map_entry_hash,
     102             :              digest256map_entries_eq, 0.6, tor_reallocarray_, tor_free_);
     103             : 
     104             : #define strmap_entry_free(ent) \
     105             :   FREE_AND_NULL(strmap_entry_t, strmap_entry_free_, (ent))
     106             : #define digestmap_entry_free(ent) \
     107             :   FREE_AND_NULL(digestmap_entry_t, digestmap_entry_free_, (ent))
     108             : #define digest256map_entry_free(ent) \
     109             :   FREE_AND_NULL(digest256map_entry_t, digest256map_entry_free_, (ent))
     110             : 
     111             : static inline void
     112        1327 : strmap_entry_free_(strmap_entry_t *ent)
     113             : {
     114        1327 :   tor_free(ent->key);
     115        1327 :   tor_free(ent);
     116        1327 : }
     117             : static inline void
     118        7508 : digestmap_entry_free_(digestmap_entry_t *ent)
     119             : {
     120        7508 :   tor_free(ent);
     121        7508 : }
     122             : static inline void
     123          97 : digest256map_entry_free_(digest256map_entry_t *ent)
     124             : {
     125          97 :   tor_free(ent);
     126          97 : }
     127             : 
     128             : static inline void
     129       27394 : strmap_assign_tmp_key(strmap_entry_t *ent, const char *key)
     130             : {
     131       27394 :   ent->key = (char*)key;
     132       27394 : }
     133             : static inline void
     134       19126 : digestmap_assign_tmp_key(digestmap_entry_t *ent, const char *key)
     135             : {
     136       19126 :   memcpy(ent->key, key, DIGEST_LEN);
     137       19126 : }
     138             : static inline void
     139         983 : digest256map_assign_tmp_key(digest256map_entry_t *ent, const uint8_t *key)
     140             : {
     141         983 :   memcpy(ent->key, key, DIGEST256_LEN);
     142         983 : }
     143             : static inline void
     144        1484 : strmap_assign_key(strmap_entry_t *ent, const char *key)
     145             : {
     146        1484 :   ent->key = tor_strdup(key);
     147        1484 : }
     148             : static inline void
     149        7712 : digestmap_assign_key(digestmap_entry_t *ent, const char *key)
     150             : {
     151        7712 :   memcpy(ent->key, key, DIGEST_LEN);
     152        7712 : }
     153             : static inline void
     154         108 : digest256map_assign_key(digest256map_entry_t *ent, const uint8_t *key)
     155             : {
     156         108 :   memcpy(ent->key, key, DIGEST256_LEN);
     157         108 : }
     158             : 
     159             : /**
     160             :  * Macro: implement all the functions for a map that are declared in
     161             :  * map.h by the DECLARE_MAP_FNS() macro.  You must additionally define a
     162             :  * prefix_entry_free_() function to free entries (and their keys), a
     163             :  * prefix_assign_tmp_key() function to temporarily set a stack-allocated
     164             :  * entry to hold a key, and a prefix_assign_key() function to set a
     165             :  * heap-allocated entry to hold a key.
     166             :  */
     167             : #define IMPLEMENT_MAP_FNS(maptype, keytype, prefix)                     \
     168             :   /** Create and return a new empty map. */                             \
     169             :   MOCK_IMPL(maptype *,                                                  \
     170             :   prefix##_new,(void))                                                  \
     171             :   {                                                                     \
     172             :     maptype *result;                                                    \
     173             :     result = tor_malloc(sizeof(maptype));                               \
     174             :     HT_INIT(prefix##_impl, &result->head);                              \
     175             :     return result;                                                      \
     176             :   }                                                                     \
     177             :                                                                         \
     178             :   /** Return the item from <b>map</b> whose key matches <b>key</b>, or  \
     179             :    * NULL if no such value exists. */                                   \
     180             :   void *                                                                \
     181             :   prefix##_get(const maptype *map, const keytype key)                   \
     182             :   {                                                                     \
     183             :     prefix ##_entry_t *resolve;                                         \
     184             :     prefix ##_entry_t search;                                           \
     185             :     tor_assert(map);                                                    \
     186             :     tor_assert(key);                                                    \
     187             :     prefix ##_assign_tmp_key(&search, key);                             \
     188             :     resolve = HT_FIND(prefix ##_impl, &map->head, &search);             \
     189             :     if (resolve) {                                                      \
     190             :       return resolve->val;                                              \
     191             :     } else {                                                            \
     192             :       return NULL;                                                      \
     193             :     }                                                                   \
     194             :   }                                                                     \
     195             :                                                                         \
     196             :   /** Add an entry to <b>map</b> mapping <b>key</b> to <b>val</b>;      \
     197             :    * return the previous value, or NULL if no such value existed. */     \
     198             :   void *                                                                \
     199             :   prefix##_set(maptype *map, const keytype key, void *val)              \
     200             :   {                                                                     \
     201             :     prefix##_entry_t search;                                            \
     202             :     void *oldval;                                                       \
     203             :     tor_assert(map);                                                    \
     204             :     tor_assert(key);                                                    \
     205             :     tor_assert(val);                                                    \
     206             :     prefix##_assign_tmp_key(&search, key);                              \
     207             :     /* We a lot of our time in this function, so the code below is */   \
     208             :     /* meant to optimize the check/alloc/set cycle by avoiding the two */\
     209             :     /* trips to the hash table that we would do in the unoptimized */   \
     210             :     /* version of this code. (Each of HT_INSERT and HT_FIND calls */     \
     211             :     /* HT_SET_HASH and HT_FIND_P.) */                                   \
     212             :     HT_FIND_OR_INSERT_(prefix##_impl, node, prefix##_entry_hash,        \
     213             :                        &(map->head),                                    \
     214             :                        prefix##_entry_t, &search, ptr,                  \
     215             :                        {                                                \
     216             :                          /* we found an entry. */                       \
     217             :                          oldval = (*ptr)->val;                          \
     218             :                          (*ptr)->val = val;                             \
     219             :                          return oldval;                                 \
     220             :                        },                                               \
     221             :                        {                                                \
     222             :                          /* We didn't find the entry. */                \
     223             :                          prefix##_entry_t *newent =                     \
     224             :                            tor_malloc_zero(sizeof(prefix##_entry_t));   \
     225             :                          prefix##_assign_key(newent, key);              \
     226             :                          newent->val = val;                             \
     227             :                          HT_FOI_INSERT_(node, &(map->head),             \
     228             :                             &search, newent, ptr);                      \
     229             :                          return NULL;                                   \
     230             :     });                                                                 \
     231             :   }                                                                     \
     232             :                                                                         \
     233             :   /** Remove the value currently associated with <b>key</b> from the map. \
     234             :    * Return the value if one was set, or NULL if there was no entry for \
     235             :    * <b>key</b>.                                                        \
     236             :    *                                                                    \
     237             :    * Note: you must free any storage associated with the returned value. \
     238             :    */                                                                   \
     239             :   void *                                                                \
     240             :   prefix##_remove(maptype *map, const keytype key)                      \
     241             :   {                                                                     \
     242             :     prefix##_entry_t *resolve;                                          \
     243             :     prefix##_entry_t search;                                            \
     244             :     void *oldval;                                                       \
     245             :     tor_assert(map);                                                    \
     246             :     tor_assert(key);                                                    \
     247             :     prefix##_assign_tmp_key(&search, key);                              \
     248             :     resolve = HT_REMOVE(prefix##_impl, &map->head, &search);            \
     249             :     if (resolve) {                                                      \
     250             :       oldval = resolve->val;                                            \
     251             :       prefix##_entry_free(resolve);                                     \
     252             :       return oldval;                                                    \
     253             :     } else {                                                            \
     254             :       return NULL;                                                      \
     255             :     }                                                                   \
     256             :   }                                                                     \
     257             :                                                                         \
     258             :   /** Return the number of elements in <b>map</b>. */                   \
     259             :   int                                                                   \
     260             :   prefix##_size(const maptype *map)                                     \
     261             :   {                                                                     \
     262             :     return HT_SIZE(&map->head);                                         \
     263             :   }                                                                     \
     264             :                                                                         \
     265             :   /** Return true iff <b>map</b> has no entries. */                     \
     266             :   int                                                                   \
     267             :   prefix##_isempty(const maptype *map)                                  \
     268             :   {                                                                     \
     269             :     return HT_EMPTY(&map->head);                                        \
     270             :   }                                                                     \
     271             :                                                                         \
     272             :   /** Assert that <b>map</b> is not corrupt. */                         \
     273             :   void                                                                  \
     274             :   prefix##_assert_ok(const maptype *map)                                \
     275             :   {                                                                     \
     276             :     tor_assert(!prefix##_impl_HT_REP_IS_BAD_(&map->head));              \
     277             :   }                                                                     \
     278             :                                                                         \
     279             :   /** Remove all entries from <b>map</b>, and deallocate storage for    \
     280             :    * those entries.  If free_val is provided, invoked it every value in \
     281             :    * <b>map</b>. */                                                     \
     282             :   MOCK_IMPL(void,                                                       \
     283             :   prefix##_free_, (maptype *map, void (*free_val)(void*)))              \
     284             :   {                                                                     \
     285             :     prefix##_entry_t **ent, **next, *this;                              \
     286             :     if (!map)                                                           \
     287             :       return;                                                           \
     288             :     for (ent = HT_START(prefix##_impl, &map->head); ent != NULL;        \
     289             :          ent = next) {                                                  \
     290             :       this = *ent;                                                      \
     291             :       next = HT_NEXT_RMV(prefix##_impl, &map->head, ent);               \
     292             :       if (free_val)                                                     \
     293             :         free_val(this->val);                                            \
     294             :       prefix##_entry_free(this);                                        \
     295             :     }                                                                   \
     296             :     tor_assert(HT_EMPTY(&map->head));                                   \
     297             :     HT_CLEAR(prefix##_impl, &map->head);                                \
     298             :     tor_free(map);                                                      \
     299             :   }                                                                     \
     300             :                                                                         \
     301             :   /** return an <b>iterator</b> pointer to the front of a map.          \
     302             :    *                                                                    \
     303             :    * Iterator example:                                                  \
     304             :    *                                                                    \
     305             :    * \code                                                              \
     306             :    * // uppercase values in "map", removing empty values.               \
     307             :    *                                                                    \
     308             :    * strmap_iter_t *iter;                                               \
     309             :    * const char *key;                                                   \
     310             :    * void *val;                                                         \
     311             :    * char *cp;                                                          \
     312             :    *                                                                    \
     313             :    * for (iter = strmap_iter_init(map); !strmap_iter_done(iter); ) {    \
     314             :    *    strmap_iter_get(iter, &key, &val);                              \
     315             :    *    cp = (char*)val;                                                \
     316             :    *    if (!*cp) {                                                     \
     317             :    *       iter = strmap_iter_next_rmv(map,iter);                       \
     318             :    *       free(val);                                                   \
     319             :    *    } else {                                                        \
     320             :    *       for (;*cp;cp++) *cp = TOR_TOUPPER(*cp);                      \
     321             :    */                                                                   \
     322             :   prefix##_iter_t *                                                     \
     323             :   prefix##_iter_init(maptype *map)                                      \
     324             :   {                                                                     \
     325             :     tor_assert(map);                                                    \
     326             :     return HT_START(prefix##_impl, &map->head);                         \
     327             :   }                                                                     \
     328             :                                                                         \
     329             :   /** Advance <b>iter</b> a single step to the next entry, and return   \
     330             :    * its new value. */                                                  \
     331             :   prefix##_iter_t *                                                     \
     332             :   prefix##_iter_next(maptype *map, prefix##_iter_t *iter)               \
     333             :   {                                                                     \
     334             :     tor_assert(map);                                                    \
     335             :     tor_assert(iter);                                                   \
     336             :     return HT_NEXT(prefix##_impl, &map->head, iter);                    \
     337             :   }                                                                     \
     338             :   /** Advance <b>iter</b> a single step to the next entry, removing the \
     339             :    * current entry, and return its new value. */                        \
     340             :   prefix##_iter_t *                                                     \
     341             :   prefix##_iter_next_rmv(maptype *map, prefix##_iter_t *iter)           \
     342             :   {                                                                     \
     343             :     prefix##_entry_t *rmv;                                              \
     344             :     tor_assert(map);                                                    \
     345             :     tor_assert(iter);                                                   \
     346             :     tor_assert(*iter);                                                  \
     347             :     rmv = *iter;                                                        \
     348             :     iter = HT_NEXT_RMV(prefix##_impl, &map->head, iter);                \
     349             :     prefix##_entry_free(rmv);                                           \
     350             :     return iter;                                                        \
     351             :   }                                                                     \
     352             :   /** Set *<b>keyp</b> and *<b>valp</b> to the current entry pointed    \
     353             :    * to by iter. */                                                     \
     354             :   void                                                                  \
     355             :   prefix##_iter_get(prefix##_iter_t *iter, const keytype *keyp,         \
     356             :                     void **valp)                                        \
     357             :   {                                                                     \
     358             :     tor_assert(iter);                                                   \
     359             :     tor_assert(*iter);                                                  \
     360             :     tor_assert(keyp);                                                   \
     361             :     tor_assert(valp);                                                   \
     362             :     *keyp = (*iter)->key;                                               \
     363             :     *valp = (*iter)->val;                                               \
     364             :   }                                                                     \
     365             :   /** Return true iff <b>iter</b> has advanced past the last entry of   \
     366             :    * <b>map</b>. */                                                     \
     367             :   int                                                                   \
     368             :   prefix##_iter_done(prefix##_iter_t *iter)                             \
     369             :   {                                                                     \
     370             :     return iter == NULL;                                                \
     371             :   }
     372             : 
     373       35362 : IMPLEMENT_MAP_FNS(strmap_t, char *, strmap)
     374       33806 : IMPLEMENT_MAP_FNS(digestmap_t, char *, digestmap)
     375        5336 : IMPLEMENT_MAP_FNS(digest256map_t, uint8_t *, digest256map)
     376             : 
     377             : /** Same as strmap_set, but first converts <b>key</b> to lowercase. */
     378             : void *
     379         249 : strmap_set_lc(strmap_t *map, const char *key, void *val)
     380             : {
     381             :   /* We could be a little faster by using strcasecmp instead, and a separate
     382             :    * type, but I don't think it matters. */
     383         249 :   void *v;
     384         249 :   char *lc_key = tor_strdup(key);
     385         249 :   tor_strlower(lc_key);
     386         249 :   v = strmap_set(map,lc_key,val);
     387         249 :   tor_free(lc_key);
     388         249 :   return v;
     389             : }
     390             : 
     391             : /** Same as strmap_get, but first converts <b>key</b> to lowercase. */
     392             : void *
     393        2504 : strmap_get_lc(const strmap_t *map, const char *key)
     394             : {
     395        2504 :   void *v;
     396        2504 :   char *lc_key = tor_strdup(key);
     397        2504 :   tor_strlower(lc_key);
     398        2504 :   v = strmap_get(map,lc_key);
     399        2504 :   tor_free(lc_key);
     400        2504 :   return v;
     401             : }
     402             : 
     403             : /** Same as strmap_remove, but first converts <b>key</b> to lowercase */
     404             : void *
     405           1 : strmap_remove_lc(strmap_t *map, const char *key)
     406             : {
     407           1 :   void *v;
     408           1 :   char *lc_key = tor_strdup(key);
     409           1 :   tor_strlower(lc_key);
     410           1 :   v = strmap_remove(map,lc_key);
     411           1 :   tor_free(lc_key);
     412           1 :   return v;
     413             : }

Generated by: LCOV version 1.14