]>
git.ipfire.org Git - thirdparty/kmod.git/blob - shared/hash.c
2 * libkmod - interface to kernel module operations
4 * Copyright (C) 2011-2013 ProFUSION embedded systems
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 #include <shared/hash.h>
26 #include <shared/util.h>
34 struct hash_entry
*entries
;
42 unsigned int n_buckets
;
43 void (*free_value
)(void *value
);
44 struct hash_bucket buckets
[];
47 struct hash
*hash_new(unsigned int n_buckets
,
48 void (*free_value
)(void *value
))
52 n_buckets
= ALIGN_POWER2(n_buckets
);
53 hash
= calloc(1, sizeof(struct hash
) +
54 n_buckets
* sizeof(struct hash_bucket
));
57 hash
->n_buckets
= n_buckets
;
58 hash
->free_value
= free_value
;
59 hash
->step
= n_buckets
/ 32;
62 else if (hash
->step
> 64)
67 void hash_free(struct hash
*hash
)
69 struct hash_bucket
*bucket
, *bucket_end
;
74 bucket
= hash
->buckets
;
75 bucket_end
= bucket
+ hash
->n_buckets
;
76 for (; bucket
< bucket_end
; bucket
++) {
77 if (hash
->free_value
) {
78 struct hash_entry
*entry
, *entry_end
;
79 entry
= bucket
->entries
;
80 entry_end
= entry
+ bucket
->used
;
81 for (; entry
< entry_end
; entry
++)
82 hash
->free_value((void *)entry
->value
);
84 free(bucket
->entries
);
89 static inline unsigned int hash_superfast(const char *key
, unsigned int len
)
91 /* Paul Hsieh (http://www.azillionmonkeys.com/qed/hash.html)
92 * used by WebCore (http://webkit.org/blog/8/hashtables-part-2/)
93 * EFL's eina and possible others.
95 unsigned int tmp
, hash
= len
, rem
= len
& 3;
100 for (; len
> 0; len
--) {
101 hash
+= get_unaligned((uint16_t *) key
);
102 tmp
= (get_unaligned((uint16_t *)(key
+ 2)) << 11) ^ hash
;
103 hash
= (hash
<< 16) ^ tmp
;
108 /* Handle end cases */
111 hash
+= get_unaligned((uint16_t *) key
);
113 hash
^= key
[2] << 18;
118 hash
+= get_unaligned((uint16_t *) key
);
129 /* Force "avalanching" of final 127 bits */
141 * add or replace key in hash map.
143 * none of key or value are copied, just references are remembered as is,
144 * make sure they are live while pair exists in hash!
146 int hash_add(struct hash
*hash
, const char *key
, const void *value
)
148 unsigned int keylen
= strlen(key
);
149 unsigned int hashval
= hash_superfast(key
, keylen
);
150 unsigned int pos
= hashval
& (hash
->n_buckets
- 1);
151 struct hash_bucket
*bucket
= hash
->buckets
+ pos
;
152 struct hash_entry
*entry
, *entry_end
;
154 if (bucket
->used
+ 1 >= bucket
->total
) {
155 unsigned new_total
= bucket
->total
+ hash
->step
;
156 size_t size
= new_total
* sizeof(struct hash_entry
);
157 struct hash_entry
*tmp
= realloc(bucket
->entries
, size
);
160 bucket
->entries
= tmp
;
161 bucket
->total
= new_total
;
164 entry
= bucket
->entries
;
165 entry_end
= entry
+ bucket
->used
;
166 for (; entry
< entry_end
; entry
++) {
167 int c
= strcmp(key
, entry
->key
);
169 if (hash
->free_value
)
170 hash
->free_value((void *)entry
->value
);
172 entry
->value
= value
;
175 memmove(entry
+ 1, entry
,
176 (entry_end
- entry
) * sizeof(struct hash_entry
));
182 entry
->value
= value
;
188 /* similar to hash_add(), but fails if key already exists */
189 int hash_add_unique(struct hash
*hash
, const char *key
, const void *value
)
191 unsigned int keylen
= strlen(key
);
192 unsigned int hashval
= hash_superfast(key
, keylen
);
193 unsigned int pos
= hashval
& (hash
->n_buckets
- 1);
194 struct hash_bucket
*bucket
= hash
->buckets
+ pos
;
195 struct hash_entry
*entry
, *entry_end
;
197 if (bucket
->used
+ 1 >= bucket
->total
) {
198 unsigned new_total
= bucket
->total
+ hash
->step
;
199 size_t size
= new_total
* sizeof(struct hash_entry
);
200 struct hash_entry
*tmp
= realloc(bucket
->entries
, size
);
203 bucket
->entries
= tmp
;
204 bucket
->total
= new_total
;
207 entry
= bucket
->entries
;
208 entry_end
= entry
+ bucket
->used
;
209 for (; entry
< entry_end
; entry
++) {
210 int c
= strcmp(key
, entry
->key
);
214 memmove(entry
+ 1, entry
,
215 (entry_end
- entry
) * sizeof(struct hash_entry
));
221 entry
->value
= value
;
227 static int hash_entry_cmp(const void *pa
, const void *pb
)
229 const struct hash_entry
*a
= pa
;
230 const struct hash_entry
*b
= pb
;
231 return strcmp(a
->key
, b
->key
);
234 void *hash_find(const struct hash
*hash
, const char *key
)
236 unsigned int keylen
= strlen(key
);
237 unsigned int hashval
= hash_superfast(key
, keylen
);
238 unsigned int pos
= hashval
& (hash
->n_buckets
- 1);
239 const struct hash_bucket
*bucket
= hash
->buckets
+ pos
;
240 const struct hash_entry se
= {
244 const struct hash_entry
*entry
= bsearch(
245 &se
, bucket
->entries
, bucket
->used
,
246 sizeof(struct hash_entry
), hash_entry_cmp
);
249 return (void *)entry
->value
;
252 int hash_del(struct hash
*hash
, const char *key
)
254 unsigned int keylen
= strlen(key
);
255 unsigned int hashval
= hash_superfast(key
, keylen
);
256 unsigned int pos
= hashval
& (hash
->n_buckets
- 1);
257 unsigned int steps_used
, steps_total
;
258 struct hash_bucket
*bucket
= hash
->buckets
+ pos
;
259 struct hash_entry
*entry
, *entry_end
;
260 const struct hash_entry se
= {
265 entry
= bsearch(&se
, bucket
->entries
, bucket
->used
,
266 sizeof(struct hash_entry
), hash_entry_cmp
);
270 if (hash
->free_value
)
271 hash
->free_value((void *)entry
->value
);
273 entry_end
= bucket
->entries
+ bucket
->used
;
274 memmove(entry
, entry
+ 1,
275 (entry_end
- entry
) * sizeof(struct hash_entry
));
280 steps_used
= bucket
->used
/ hash
->step
;
281 steps_total
= bucket
->total
/ hash
->step
;
282 if (steps_used
+ 1 < steps_total
) {
283 size_t size
= (steps_used
+ 1) *
284 hash
->step
* sizeof(struct hash_entry
);
285 struct hash_entry
*tmp
= realloc(bucket
->entries
, size
);
287 bucket
->entries
= tmp
;
288 bucket
->total
= (steps_used
+ 1) * hash
->step
;
295 unsigned int hash_get_count(const struct hash
*hash
)
300 void hash_iter_init(const struct hash
*hash
, struct hash_iter
*iter
)
307 bool hash_iter_next(struct hash_iter
*iter
, const char **key
,
310 const struct hash_bucket
*b
= iter
->hash
->buckets
+ iter
->bucket
;
311 const struct hash_entry
*e
;
315 if (iter
->entry
>= b
->used
) {
318 for (iter
->bucket
++; iter
->bucket
< iter
->hash
->n_buckets
;
320 b
= iter
->hash
->buckets
+ iter
->bucket
;
326 if (iter
->bucket
>= iter
->hash
->n_buckets
)
330 e
= b
->entries
+ iter
->entry
;