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.c
     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 #include "main/imports.h"
     32 #include "main/simple_list.h"
     33 #include "hash_table.h"
     34 
     35 struct node {
     36    struct node *next;
     37    struct node *prev;
     38 };
     39 
     40 struct hash_table {
     41     hash_func_t    hash;
     42     hash_compare_func_t  compare;
     43 
     44     unsigned num_buckets;
     45     struct node buckets[1];
     46 };
     47 
     48 
     49 struct hash_node {
     50     struct node link;
     51     const void *key;
     52     void *data;
     53 };
     54 
     55 
     56 struct hash_table *
     57 hash_table_ctor(unsigned num_buckets, hash_func_t hash,
     58                 hash_compare_func_t compare)
     59 {
     60     struct hash_table *ht;
     61     unsigned i;
     62 
     63 
     64     if (num_buckets < 16) {
     65         num_buckets = 16;
     66     }
     67 
     68     ht = malloc(sizeof(*ht) + ((num_buckets - 1)
     69 				     * sizeof(ht->buckets[0])));
     70     if (ht != NULL) {
     71         ht->hash = hash;
     72         ht->compare = compare;
     73         ht->num_buckets = num_buckets;
     74 
     75         for (i = 0; i < num_buckets; i++) {
     76             make_empty_list(& ht->buckets[i]);
     77         }
     78     }
     79 
     80     return ht;
     81 }
     82 
     83 
     84 void
     85 hash_table_dtor(struct hash_table *ht)
     86 {
     87    hash_table_clear(ht);
     88    free(ht);
     89 }
     90 
     91 
     92 void
     93 hash_table_clear(struct hash_table *ht)
     94 {
     95    struct node *node;
     96    struct node *temp;
     97    unsigned i;
     98 
     99 
    100    for (i = 0; i < ht->num_buckets; i++) {
    101       foreach_s(node, temp, & ht->buckets[i]) {
    102 	 remove_from_list(node);
    103 	 free(node);
    104       }
    105 
    106       assert(is_empty_list(& ht->buckets[i]));
    107    }
    108 }
    109 
    110 
    111 static struct hash_node *
    112 get_node(struct hash_table *ht, const void *key)
    113 {
    114     const unsigned hash_value = (*ht->hash)(key);
    115     const unsigned bucket = hash_value % ht->num_buckets;
    116     struct node *node;
    117 
    118     foreach(node, & ht->buckets[bucket]) {
    119        struct hash_node *hn = (struct hash_node *) node;
    120 
    121        if ((*ht->compare)(hn->key, key) == 0) {
    122 	  return hn;
    123        }
    124     }
    125 
    126     return NULL;
    127 }
    128 
    129 void *
    130 hash_table_find(struct hash_table *ht, const void *key)
    131 {
    132    struct hash_node *hn = get_node(ht, key);
    133 
    134    return (hn == NULL) ? NULL : hn->data;
    135 }
    136 
    137 void
    138 hash_table_insert(struct hash_table *ht, void *data, const void *key)
    139 {
    140     const unsigned hash_value = (*ht->hash)(key);
    141     const unsigned bucket = hash_value % ht->num_buckets;
    142     struct hash_node *node;
    143 
    144     node = calloc(1, sizeof(*node));
    145 
    146     node->data = data;
    147     node->key = key;
    148 
    149     insert_at_head(& ht->buckets[bucket], & node->link);
    150 }
    151 
    152 bool
    153 hash_table_replace(struct hash_table *ht, void *data, const void *key)
    154 {
    155     const unsigned hash_value = (*ht->hash)(key);
    156     const unsigned bucket = hash_value % ht->num_buckets;
    157     struct node *node;
    158     struct hash_node *hn;
    159 
    160     foreach(node, & ht->buckets[bucket]) {
    161        hn = (struct hash_node *) node;
    162 
    163        if ((*ht->compare)(hn->key, key) == 0) {
    164 	  hn->data = data;
    165 	  return true;
    166        }
    167     }
    168 
    169     hn = calloc(1, sizeof(*hn));
    170 
    171     hn->data = data;
    172     hn->key = key;
    173 
    174     insert_at_head(& ht->buckets[bucket], & hn->link);
    175     return false;
    176 }
    177 
    178 void
    179 hash_table_remove(struct hash_table *ht, const void *key)
    180 {
    181    struct node *node = (struct node *) get_node(ht, key);
    182    if (node != NULL) {
    183       remove_from_list(node);
    184       free(node);
    185       return;
    186    }
    187 }
    188 
    189 void
    190 hash_table_call_foreach(struct hash_table *ht,
    191 			void (*callback)(const void *key,
    192 					 void *data,
    193 					 void *closure),
    194 			void *closure)
    195 {
    196    int bucket;
    197 
    198    for (bucket = 0; bucket < ht->num_buckets; bucket++) {
    199       struct node *node, *temp;
    200       foreach_s(node, temp, &ht->buckets[bucket]) {
    201 	 struct hash_node *hn = (struct hash_node *) node;
    202 
    203 	 callback(hn->key, hn->data, closure);
    204       }
    205    }
    206 }
    207 
    208 unsigned
    209 hash_table_string_hash(const void *key)
    210 {
    211     const char *str = (const char *) key;
    212     unsigned hash = 5381;
    213 
    214 
    215     while (*str != '\0') {
    216         hash = (hash * 33) + *str;
    217         str++;
    218     }
    219 
    220     return hash;
    221 }
    222 
    223 
    224 unsigned
    225 hash_table_pointer_hash(const void *key)
    226 {
    227    return (unsigned)((uintptr_t) key / sizeof(void *));
    228 }
    229 
    230 
    231 int
    232 hash_table_pointer_compare(const void *key1, const void *key2)
    233 {
    234    return key1 == key2 ? 0 : 1;
    235 }
    236