Home | History | Annotate | Download | only in program
      1 /*
      2  * Copyright  2008 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
     21  * DEALINGS IN THE SOFTWARE.
     22  */
     23 
     24 /**
     25  * \file hash_table.h
     26  * \brief Implementation of a generic, opaque hash table data type.
     27  *
     28  * \author Ian Romanick <ian.d.romanick (at) intel.com>
     29  */
     30 
     31 #ifndef HASH_TABLE_H
     32 #define HASH_TABLE_H
     33 
     34 #include <string.h>
     35 #include <stdbool.h>
     36 #include <stdlib.h>
     37 #include <stdint.h>
     38 #include <limits.h>
     39 #include <assert.h>
     40 
     41 struct string_to_uint_map;
     42 
     43 #ifdef __cplusplus
     44 extern "C" {
     45 #endif
     46 
     47 struct hash_table;
     48 
     49 typedef unsigned (*hash_func_t)(const void *key);
     50 typedef int (*hash_compare_func_t)(const void *key1, const void *key2);
     51 
     52 /**
     53  * Hash table constructor
     54  *
     55  * Creates a hash table with the specified number of buckets.  The supplied
     56  * \c hash and \c compare routines are used when adding elements to the table
     57  * and when searching for elements in the table.
     58  *
     59  * \param num_buckets  Number of buckets (bins) in the hash table.
     60  * \param hash         Function used to compute hash value of input keys.
     61  * \param compare      Function used to compare keys.
     62  */
     63 extern struct hash_table *hash_table_ctor(unsigned num_buckets,
     64     hash_func_t hash, hash_compare_func_t compare);
     65 
     66 
     67 /**
     68  * Release all memory associated with a hash table
     69  *
     70  * \warning
     71  * This function cannot release memory occupied either by keys or data.
     72  */
     73 extern void hash_table_dtor(struct hash_table *ht);
     74 
     75 
     76 /**
     77  * Flush all entries from a hash table
     78  *
     79  * \param ht  Table to be cleared of its entries.
     80  */
     81 extern void hash_table_clear(struct hash_table *ht);
     82 
     83 
     84 /**
     85  * Search a hash table for a specific element
     86  *
     87  * \param ht   Table to be searched
     88  * \param key  Key of the desired element
     89  *
     90  * \return
     91  * The \c data value supplied to \c hash_table_insert when the element with
     92  * the matching key was added.  If no matching key exists in the table,
     93  * \c NULL is returned.
     94  */
     95 extern void *hash_table_find(struct hash_table *ht, const void *key);
     96 
     97 
     98 /**
     99  * Add an element to a hash table
    100  *
    101  * \warning
    102  * If \c key is already in the hash table, it will be added again.  Future
    103  * calls to \c hash_table_find and \c hash_table_remove will return or remove,
    104  * repsectively, the most recently added instance of \c key.
    105  *
    106  * \warning
    107  * The value passed by \c key is kept in the hash table and is used by later
    108  * calls to \c hash_table_find.
    109  *
    110  * \sa hash_table_replace
    111  */
    112 extern void hash_table_insert(struct hash_table *ht, void *data,
    113     const void *key);
    114 
    115 /**
    116  * Add an element to a hash table with replacement
    117  *
    118  * \return
    119  * 1 if it did replace the the value (in which case the old key is kept), 0 if
    120  * it did not replace the value (in which case the new key is kept).
    121  *
    122  * \warning
    123  * If \c key is already in the hash table, \c data will \b replace the most
    124  * recently inserted \c data (see the warning in \c hash_table_insert) for
    125  * that key.
    126  *
    127  * \sa hash_table_insert
    128  */
    129 extern bool hash_table_replace(struct hash_table *ht, void *data,
    130     const void *key);
    131 
    132 /**
    133  * Remove a specific element from a hash table.
    134  */
    135 extern void hash_table_remove(struct hash_table *ht, const void *key);
    136 
    137 /**
    138  * Compute hash value of a string
    139  *
    140  * Computes the hash value of a string using the DJB2 algorithm developed by
    141  * Professor Daniel J. Bernstein.  It was published on comp.lang.c once upon
    142  * a time.  I was unable to find the original posting in the archives.
    143  *
    144  * \param key  Pointer to a NUL terminated string to be hashed.
    145  *
    146  * \sa hash_table_string_compare
    147  */
    148 extern unsigned hash_table_string_hash(const void *key);
    149 
    150 
    151 /**
    152  * Compare two strings used as keys
    153  *
    154  * This is just a macro wrapper around \c strcmp.
    155  *
    156  * \sa hash_table_string_hash
    157  */
    158 #define hash_table_string_compare ((hash_compare_func_t) strcmp)
    159 
    160 
    161 /**
    162  * Compute hash value of a pointer
    163  *
    164  * \param key  Pointer to be used as a hash key
    165  *
    166  * \note
    167  * The memory pointed to by \c key is \b never accessed.  The value of \c key
    168  * itself is used as the hash key
    169  *
    170  * \sa hash_table_pointer_compare
    171  */
    172 unsigned
    173 hash_table_pointer_hash(const void *key);
    174 
    175 
    176 /**
    177  * Compare two pointers used as keys
    178  *
    179  * \sa hash_table_pointer_hash
    180  */
    181 int
    182 hash_table_pointer_compare(const void *key1, const void *key2);
    183 
    184 void
    185 hash_table_call_foreach(struct hash_table *ht,
    186 			void (*callback)(const void *key,
    187 					 void *data,
    188 					 void *closure),
    189 			void *closure);
    190 
    191 struct string_to_uint_map *
    192 string_to_uint_map_ctor();
    193 
    194 void
    195 string_to_uint_map_dtor(struct string_to_uint_map *);
    196 
    197 
    198 #ifdef __cplusplus
    199 }
    200 
    201 /**
    202  * Map from a string (name) to an unsigned integer value
    203  *
    204  * \note
    205  * Because of the way this class interacts with the \c hash_table
    206  * implementation, values of \c UINT_MAX cannot be stored in the map.
    207  */
    208 struct string_to_uint_map {
    209 public:
    210    string_to_uint_map()
    211    {
    212       this->ht = hash_table_ctor(0, hash_table_string_hash,
    213 				 hash_table_string_compare);
    214    }
    215 
    216    ~string_to_uint_map()
    217    {
    218       hash_table_call_foreach(this->ht, delete_key, NULL);
    219       hash_table_dtor(this->ht);
    220    }
    221 
    222    /**
    223     * Remove all mappings from this map.
    224     */
    225    void clear()
    226    {
    227       hash_table_call_foreach(this->ht, delete_key, NULL);
    228       hash_table_clear(this->ht);
    229    }
    230 
    231    /**
    232     * Get the value associated with a particular key
    233     *
    234     * \return
    235     * If \c key is found in the map, \c true is returned.  Otherwise \c false
    236     * is returned.
    237     *
    238     * \note
    239     * If \c key is not found in the table, \c value is not modified.
    240     */
    241    bool get(unsigned &value, const char *key)
    242    {
    243       const intptr_t v =
    244 	 (intptr_t) hash_table_find(this->ht, (const void *) key);
    245 
    246       if (v == 0)
    247 	 return false;
    248 
    249       value = (unsigned)(v - 1);
    250       return true;
    251    }
    252 
    253    void put(unsigned value, const char *key)
    254    {
    255       /* The low-level hash table structure returns NULL if key is not in the
    256        * hash table.  However, users of this map might want to store zero as a
    257        * valid value in the table.  Bias the value by +1 so that a
    258        * user-specified zero is stored as 1.  This enables ::get to tell the
    259        * difference between a user-specified zero (returned as 1 by
    260        * hash_table_find) and the key not in the table (returned as 0 by
    261        * hash_table_find).
    262        *
    263        * The net effect is that we can't store UINT_MAX in the table.  This is
    264        * because UINT_MAX+1 = 0.
    265        */
    266       assert(value != UINT_MAX);
    267       char *dup_key = strdup(key);
    268       bool result = hash_table_replace(this->ht,
    269 				       (void *) (intptr_t) (value + 1),
    270 				       dup_key);
    271       if (result)
    272 	 free(dup_key);
    273    }
    274 
    275 private:
    276    static void delete_key(const void *key, void *data, void *closure)
    277    {
    278       (void) data;
    279       (void) closure;
    280 
    281       free((char *)key);
    282    }
    283 
    284    struct hash_table *ht;
    285 };
    286 
    287 #endif /* __cplusplus */
    288 #endif /* HASH_TABLE_H */
    289