• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2008 VMware, Inc.
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 VMWARE 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 util_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 <jfonseca@vmware.com>
38  */
39 
40 
41 #include "util_hash_table.h"
42 #include "util_hash.h"
43 
44 #include <stdlib.h>
45 #include <assert.h>
46 
47 struct util_hash_table
48 {
49 	struct util_hash *head;
50 
51 	/** Hash function */
52 	unsigned (*make_hash)(void *key);
53 
54 	/** Compare two keys */
55 	int (*compare)(void *key1, void *key2);
56 };
57 
58 struct util_hash_table_item
59 {
60 	void *key;
61 	void *value;
62 };
63 
64 
65 static struct util_hash_table_item *
util_hash_table_item(struct util_hash_iter iter)66 util_hash_table_item(struct util_hash_iter iter)
67 {
68 	return (struct util_hash_table_item *)util_hash_iter_data(iter);
69 }
70 
71 drm_private struct util_hash_table *
util_hash_table_create(unsigned (* hash)(void * key),int (* compare)(void * key1,void * key2))72 util_hash_table_create(unsigned (*hash)(void *key),
73 		       int (*compare)(void *key1, void *key2))
74 {
75 	struct util_hash_table *ht;
76 
77 	ht = malloc(sizeof(struct util_hash_table));
78 	if(!ht)
79 		return NULL;
80 
81 	ht->head = util_hash_create();
82 	if(!ht->head) {
83 		free(ht);
84 		return NULL;
85 	}
86 
87 	ht->make_hash = hash;
88 	ht->compare = compare;
89 
90 	return ht;
91 }
92 
93 static struct util_hash_iter
util_hash_table_find_iter(struct util_hash_table * ht,void * key,unsigned key_hash)94 util_hash_table_find_iter(struct util_hash_table *ht,
95 			  void *key, unsigned key_hash)
96 {
97 	struct util_hash_iter iter;
98 	struct util_hash_table_item *item;
99 
100 	iter = util_hash_find(ht->head, key_hash);
101 	while (!util_hash_iter_is_null(iter)) {
102 		item = (struct util_hash_table_item *)util_hash_iter_data(iter);
103 		if (!ht->compare(item->key, key))
104 			break;
105 		iter = util_hash_iter_next(iter);
106 	}
107 
108 	return iter;
109 }
110 
111 static struct util_hash_table_item *
util_hash_table_find_item(struct util_hash_table * ht,void * key,unsigned key_hash)112 util_hash_table_find_item(struct util_hash_table *ht,
113                           void *key, unsigned key_hash)
114 {
115 	struct util_hash_iter iter;
116 	struct util_hash_table_item *item;
117 
118 	iter = util_hash_find(ht->head, key_hash);
119 	while (!util_hash_iter_is_null(iter)) {
120 		item = (struct util_hash_table_item *)util_hash_iter_data(iter);
121 		if (!ht->compare(item->key, key))
122 			return item;
123 		iter = util_hash_iter_next(iter);
124 	}
125 
126 	return NULL;
127 }
128 
129 drm_private void
util_hash_table_set(struct util_hash_table * ht,void * key,void * value)130 util_hash_table_set(struct util_hash_table *ht, void *key, void *value)
131 {
132 	unsigned key_hash;
133 	struct util_hash_table_item *item;
134 	struct util_hash_iter iter;
135 
136 	assert(ht);
137 	if (!ht)
138 		return;
139 
140 	key_hash = ht->make_hash(key);
141 
142 	item = util_hash_table_find_item(ht, key, key_hash);
143 	if(item) {
144 		/* TODO: key/value destruction? */
145 		item->value = value;
146 		return;
147 	}
148 
149 	item = malloc(sizeof(struct util_hash_table_item));
150 	if(!item)
151 		return;
152 
153 	item->key = key;
154 	item->value = value;
155 
156 	iter = util_hash_insert(ht->head, key_hash, item);
157 	if(util_hash_iter_is_null(iter)) {
158 		free(item);
159 		return;
160 	}
161 }
162 
util_hash_table_get(struct util_hash_table * ht,void * key)163 drm_private void *util_hash_table_get(struct util_hash_table *ht, void *key)
164 {
165 	unsigned key_hash;
166 	struct util_hash_table_item *item;
167 
168 	assert(ht);
169 	if (!ht)
170 		return NULL;
171 
172 	key_hash = ht->make_hash(key);
173 
174 	item = util_hash_table_find_item(ht, key, key_hash);
175 	if(!item)
176 		return NULL;
177 
178 	return item->value;
179 }
180 
util_hash_table_remove(struct util_hash_table * ht,void * key)181 drm_private void util_hash_table_remove(struct util_hash_table *ht, void *key)
182 {
183 	unsigned key_hash;
184 	struct util_hash_iter iter;
185 	struct util_hash_table_item *item;
186 
187 	assert(ht);
188 	if (!ht)
189 		return;
190 
191 	key_hash = ht->make_hash(key);
192 
193 	iter = util_hash_table_find_iter(ht, key, key_hash);
194 	if(util_hash_iter_is_null(iter))
195 		return;
196 
197 	item = util_hash_table_item(iter);
198 	assert(item);
199 	free(item);
200 
201 	util_hash_erase(ht->head, iter);
202 }
203 
util_hash_table_clear(struct util_hash_table * ht)204 drm_private void util_hash_table_clear(struct util_hash_table *ht)
205 {
206 	struct util_hash_iter iter;
207 	struct util_hash_table_item *item;
208 
209 	assert(ht);
210 	if (!ht)
211 		return;
212 
213 	iter = util_hash_first_node(ht->head);
214 	while (!util_hash_iter_is_null(iter)) {
215 		item = (struct util_hash_table_item *)util_hash_take(ht->head, util_hash_iter_key(iter));
216 		free(item);
217 		iter = util_hash_first_node(ht->head);
218 	}
219 }
220 
util_hash_table_foreach(struct util_hash_table * ht,void (* callback)(void * key,void * value,void * data),void * data)221 drm_private void util_hash_table_foreach(struct util_hash_table *ht,
222 			void (*callback)(void *key, void *value, void *data),
223 			void *data)
224 {
225 	struct util_hash_iter iter;
226 	struct util_hash_table_item *item;
227 
228 	assert(ht);
229 	if (!ht)
230 		return;
231 
232 	iter = util_hash_first_node(ht->head);
233 	while (!util_hash_iter_is_null(iter)) {
234 		item = (struct util_hash_table_item *)util_hash_iter_data(iter);
235 		callback(item->key, item->value, data);
236 		iter = util_hash_iter_next(iter);
237 	}
238 }
239 
util_hash_table_destroy(struct util_hash_table * ht)240 drm_private void util_hash_table_destroy(struct util_hash_table *ht)
241 {
242 	struct util_hash_iter iter;
243 	struct util_hash_table_item *item;
244 
245 	assert(ht);
246 	if (!ht)
247 		return;
248 
249 	iter = util_hash_first_node(ht->head);
250 	while (!util_hash_iter_is_null(iter)) {
251 		item = (struct util_hash_table_item *)util_hash_iter_data(iter);
252 		free(item);
253 		iter = util_hash_iter_next(iter);
254 	}
255 
256 	util_hash_delete(ht->head);
257 	free(ht);
258 }
259