1 /*****
2 *
3 * Copyright (C) 2003-2015 CS-SI. All Rights Reserved.
4 * Author: Nicolas Delon <nicolas.delon@prelude-ids.com>
5 *
6 * This file is part of the Prelude library.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 *
22 *****/
23
24 #include "config.h"
25
26 #include <string.h>
27 #include <stdlib.h>
28
29 #include "prelude-log.h"
30 #include "prelude-list.h"
31 #include "prelude-error.h"
32 #include "prelude-hash.h"
33
34
35 #define HASH_DEFAULT_SIZE 128
36
37
38
39 typedef struct hash_elem {
40 prelude_list_t list;
41 void *key;
42 void *value;
43 } hash_elem_t;
44
45
46 struct prelude_hash {
47 size_t lists_size;
48 prelude_list_t *lists;
49
50 unsigned int (*hash_func)(const void *key);
51 int (*key_cmp_func)(const void *key1, const void *key2);
52 void (*key_destroy_func)(void *key);
53 void (*value_destroy_func)(void *value);
54 };
55
56
57
58 /*
59 * This function's code was taken from glib
60 */
default_hash_func(const void * key)61 static unsigned int default_hash_func(const void *key)
62 {
63 const char *ptr = key;
64 unsigned int hv = *ptr;
65
66 if ( hv )
67 for ( ptr += 1; *ptr; ptr++ )
68 hv = (hv << 5) - hv + *ptr;
69
70 return hv;
71
72 }
73
74
75
default_key_cmp_func(const void * key1,const void * key2)76 static int default_key_cmp_func(const void *key1, const void *key2)
77 {
78 return strcmp((const char *) key1, (const char *) key2);
79 }
80
81
82
hash_value_calc(prelude_hash_t * hash,const void * key)83 static unsigned int hash_value_calc(prelude_hash_t *hash, const void *key)
84 {
85 return (hash->hash_func(key) % hash->lists_size);
86 }
87
88
89
hash_elem_get(prelude_hash_t * hash,const void * key)90 static hash_elem_t *hash_elem_get(prelude_hash_t *hash, const void *key)
91 {
92 prelude_list_t *list;
93 prelude_list_t *ptr;
94 hash_elem_t *hash_elem;
95
96 list = hash->lists + hash_value_calc(hash, key);
97
98 prelude_list_for_each(list, ptr) {
99 hash_elem = prelude_list_entry(ptr, hash_elem_t, list);
100 if ( hash->key_cmp_func(key, hash_elem->key) == 0 )
101 return hash_elem;
102 }
103
104 return NULL;
105 }
106
107
108
hash_elem_key_destroy(prelude_hash_t * hash,hash_elem_t * hash_elem)109 static void hash_elem_key_destroy(prelude_hash_t *hash, hash_elem_t *hash_elem)
110 {
111 if ( hash->key_destroy_func )
112 hash->key_destroy_func(hash_elem->key);
113 }
114
115
116
hash_elem_value_destroy(prelude_hash_t * hash,hash_elem_t * hash_elem)117 static void hash_elem_value_destroy(prelude_hash_t *hash, hash_elem_t *hash_elem)
118 {
119 if ( hash->value_destroy_func )
120 hash->value_destroy_func(hash_elem->value);
121 }
122
123
124
prelude_hash_new(prelude_hash_t ** nhash,unsigned int (* hash_func)(const void *),int (* key_cmp_func)(const void *,const void *),void (* key_destroy_func)(void *),void (* value_destroy_func)(void *))125 int prelude_hash_new(prelude_hash_t **nhash,
126 unsigned int (*hash_func)(const void *),
127 int (*key_cmp_func)(const void *, const void *),
128 void (*key_destroy_func)(void *),
129 void (*value_destroy_func)(void *))
130 {
131 return prelude_hash_new2(nhash, HASH_DEFAULT_SIZE, hash_func, key_cmp_func, key_destroy_func, value_destroy_func);
132 }
133
134
135
prelude_hash_new2(prelude_hash_t ** nhash,size_t size,unsigned int (* hash_func)(const void *),int (* key_cmp_func)(const void *,const void *),void (* key_destroy_func)(void *),void (* value_destroy_func)(void *))136 int prelude_hash_new2(prelude_hash_t **nhash, size_t size,
137 unsigned int (*hash_func)(const void *),
138 int (*key_cmp_func)(const void *, const void *),
139 void (*key_destroy_func)(void *),
140 void (*value_destroy_func)(void *))
141 {
142 size_t i;
143 prelude_hash_t *hash;
144
145 *nhash = hash = calloc(1, sizeof (*hash));
146 if ( ! hash )
147 return prelude_error_from_errno(errno);
148
149 hash->lists_size = size;
150
151 hash->lists = malloc(hash->lists_size * sizeof(*hash->lists));
152 if ( ! hash->lists ) {
153 free(hash);
154 return prelude_error_from_errno(errno);
155 }
156
157 hash->hash_func = hash_func ? hash_func : default_hash_func;
158 hash->key_cmp_func = key_cmp_func ? key_cmp_func : default_key_cmp_func;
159 hash->key_destroy_func = key_destroy_func;
160 hash->value_destroy_func = value_destroy_func;
161
162 for ( i = 0; i < hash->lists_size; i++ )
163 prelude_list_init(hash->lists + i);
164
165 return 0;
166 }
167
168
169
prelude_hash_destroy(prelude_hash_t * hash)170 void prelude_hash_destroy(prelude_hash_t *hash)
171 {
172 size_t cnt;
173 prelude_list_t *list;
174 prelude_list_t *ptr;
175 prelude_list_t *tmp;
176 hash_elem_t *hash_elem;
177
178 for ( cnt = 0; cnt < hash->lists_size; cnt++ ) {
179 list = hash->lists + cnt;
180
181 prelude_list_for_each_safe(list, ptr, tmp) {
182 hash_elem = prelude_list_entry(ptr, hash_elem_t, list);
183
184 hash_elem_key_destroy(hash, hash_elem);
185 hash_elem_value_destroy(hash, hash_elem);
186 prelude_list_del(&hash_elem->list);
187 free(hash_elem);
188 }
189 }
190
191 free(hash->lists);
192 free(hash);
193 }
194
195
196
prelude_hash_add(prelude_hash_t * hash,void * key,void * value)197 int prelude_hash_add(prelude_hash_t *hash, void *key, void *value)
198 {
199 hash_elem_t *hash_elem;
200 prelude_list_t *list;
201
202 hash_elem = calloc(1, sizeof(*hash_elem));
203 if ( ! hash_elem )
204 return prelude_error_from_errno(errno);
205
206 hash_elem->key = key;
207 hash_elem->value = value;
208
209 list = hash->lists + hash_value_calc(hash, key);
210 prelude_list_add(list, &hash_elem->list);
211
212 return 1;
213 }
214
215
216
prelude_hash_set(prelude_hash_t * hash,void * key,void * value)217 int prelude_hash_set(prelude_hash_t *hash, void *key, void *value)
218 {
219 hash_elem_t *hash_elem = hash_elem_get(hash, key);
220
221 if ( hash_elem ) {
222 hash_elem_key_destroy(hash, hash_elem);
223 hash_elem_value_destroy(hash, hash_elem);
224 hash_elem->key = key;
225 hash_elem->value = value;
226 return 0;
227 }
228
229 return prelude_hash_add(hash, key, value);
230 }
231
232
233
prelude_hash_get(prelude_hash_t * hash,const void * key)234 void *prelude_hash_get(prelude_hash_t *hash, const void *key)
235 {
236 hash_elem_t *hash_elem;
237
238 return (hash_elem = hash_elem_get(hash, key)) ? hash_elem->value : NULL;
239 }
240
241
242
prelude_hash_elem_destroy(prelude_hash_t * hash,const void * key)243 int prelude_hash_elem_destroy(prelude_hash_t *hash, const void *key)
244 {
245 hash_elem_t *hash_elem;
246
247 hash_elem = hash_elem_get(hash, key);
248
249 if ( ! hash_elem )
250 return -1;
251
252 hash_elem_key_destroy(hash, hash_elem);
253 hash_elem_value_destroy(hash, hash_elem);
254 prelude_list_del(&hash_elem->list);
255 free(hash_elem);
256
257 return 0;
258 }
259
260
261
prelude_hash_iterate(prelude_hash_t * hash,void (* cb)(void * data))262 void prelude_hash_iterate(prelude_hash_t *hash, void (*cb)(void *data))
263 {
264 unsigned int i;
265 prelude_list_t *tmp;
266 hash_elem_t *hash_elem;
267
268 for ( i = 0; i < hash->lists_size; i++ ) {
269 prelude_list_for_each(&hash->lists[i], tmp) {
270 hash_elem = prelude_list_entry(tmp, hash_elem_t, list);
271 cb(hash_elem->value);
272 }
273 }
274 }
275