u_hash_table.c revision d26139d6a19aaf8b4dbbaa1ee937fed2283923e4
1/**************************************************************************
2 *
3 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28/**
29 * @file
30 * General purpose hash table implementation.
31 *
32 * Just uses the cso_hash for now, but it might be better switch to a linear
33 * probing hash table implementation at some point -- as it is said they have
34 * better lookup and cache performance and it appears to be possible to write
35 * a lock-free implementation of such hash tables .
36 *
37 * @author José Fonseca <jrfonseca@tungstengraphics.com>
38 */
39
40
41#include "pipe/p_compiler.h"
42#include "pipe/p_debug.h"
43#include "pipe/p_util.h"
44
45#include "cso_cache/cso_hash.h"
46#include "u_hash_table.h"
47
48
49struct hash_table
50{
51   struct cso_hash *cso;
52
53   /** Hash function */
54   unsigned (*hash)(void *key);
55
56   /** Compare two keys */
57   int (*compare)(void *key1, void *key2);
58
59   /* TODO: key, value destructors? */
60};
61
62
63struct hash_table_item
64{
65   void *key;
66   void *value;
67};
68
69
70struct hash_table *
71hash_table_create(unsigned (*hash)(void *key),
72                  int (*compare)(void *key1, void *key2))
73{
74   struct hash_table *ht;
75
76   ht = MALLOC_STRUCT(hash_table);
77   if(!ht)
78      return NULL;
79
80   ht->cso = cso_hash_create();
81   if(!ht->cso) {
82      FREE(ht);
83      return NULL;
84   }
85
86   ht->hash = hash;
87   ht->compare = compare;
88
89   return ht;
90}
91
92
93static struct hash_table_item *
94hash_table_find_item(struct hash_table *ht,
95                     void *key,
96                     unsigned key_hash)
97{
98   struct cso_hash_iter iter;
99   struct hash_table_item *item;
100
101   iter = cso_hash_find(ht->cso, key_hash);
102   while (!cso_hash_iter_is_null(iter)) {
103      item = (struct hash_table_item *)cso_hash_iter_data(iter);
104      if (!ht->compare(item->key, key))
105         return item;
106      iter = cso_hash_iter_next(iter);
107   }
108
109   return NULL;
110}
111
112
113enum pipe_error
114hash_table_set(struct hash_table *ht,
115               void *key,
116               void *value)
117{
118   unsigned key_hash;
119   struct hash_table_item *item;
120
121   assert(ht);
122
123   key_hash = ht->hash(key);
124
125   item = hash_table_find_item(ht, key, key_hash);
126   if(item) {
127      /* TODO: key/value destruction? */
128      item->value = value;
129      return PIPE_OK;
130   }
131
132   item = MALLOC_STRUCT(hash_table_item);
133   if(!item)
134      return PIPE_ERROR_OUT_OF_MEMORY;
135
136   item->key = key;
137   item->value = value;
138
139   cso_hash_insert(ht->cso, key_hash, item);
140   /* FIXME: there is no OOM propagation in cso_hash */
141   if(0) {
142      FREE(item);
143      return PIPE_ERROR_OUT_OF_MEMORY;
144   }
145
146   return PIPE_OK;
147}
148
149
150void *
151hash_table_get(struct hash_table *ht,
152               void *key)
153{
154   unsigned key_hash;
155   struct hash_table_item *item;
156
157   assert(ht);
158
159   key_hash = ht->hash(key);
160
161   item = hash_table_find_item(ht, key, key_hash);
162   if(!item)
163      return NULL;
164
165   return item->value;
166}
167
168
169void
170hash_table_remove(struct hash_table *ht,
171                  void *key)
172{
173   unsigned key_hash;
174   struct hash_table_item *item;
175
176   assert(ht);
177
178   key_hash = ht->hash(key);
179
180   item = hash_table_find_item(ht, key, key_hash);
181   if(!item)
182      return;
183
184   /* FIXME: cso_hash_take takes the first element of the collision list
185    * indiscriminately, so we can not take the item down. */
186   item->value = NULL;
187}
188
189
190enum pipe_error
191hash_table_foreach(struct hash_table *ht,
192                   enum pipe_error (*callback)(void *key, void *value, void *data),
193                   void *data)
194{
195   struct cso_hash_iter iter;
196   struct hash_table_item *item;
197   enum pipe_error result;
198
199   iter = cso_hash_first_node(ht->cso);
200   while (!cso_hash_iter_is_null(iter)) {
201      item = (struct hash_table_item *)cso_hash_iter_data(iter);
202      result = callback(item->key, item->value, data);
203      if(result != PIPE_OK)
204	 return result;
205      iter = cso_hash_iter_next(iter);
206   }
207
208   return PIPE_OK;
209}
210
211
212void
213hash_table_destroy(struct hash_table *ht)
214{
215   assert(ht);
216
217   cso_hash_delete(ht->cso);
218
219   FREE(ht);
220}
221