1 /* Copyright (c) 2013, Vsevolod Stakhov
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
12 * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
13 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
16 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
19 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 #include "ucl_internal.h"
30 const ucl_object_t *obj;
34 struct ucl_hash_struct {
36 kvec_t(const ucl_object_t *) ar;
40 static inline uint32_t
41 ucl_hash_func (const ucl_object_t *o)
43 return XXH32 (o->key, o->keylen, 0xdeadbeef);
47 ucl_hash_equal (const ucl_object_t *k1, const ucl_object_t *k2)
49 if (k1->keylen == k2->keylen) {
50 return strncmp (k1->key, k2->key, k1->keylen) == 0;
56 KHASH_INIT (ucl_hash_node, const ucl_object_t *, struct ucl_hash_elt, 1,
57 ucl_hash_func, ucl_hash_equal)
59 static inline uint32_t
60 ucl_hash_caseless_func (const ucl_object_t *o)
62 void *xxh = XXH32_init (0xdeadbeef);
63 char hash_buf[64], *c;
65 ssize_t remain = o->keylen;
71 *c++ = tolower (*p++);
73 if (c - &hash_buf[0] == sizeof (hash_buf)) {
74 XXH32_update (xxh, hash_buf, sizeof (hash_buf));
80 if (c - &hash_buf[0] != 0) {
81 XXH32_update (xxh, hash_buf, c - &hash_buf[0]);
84 return XXH32_digest (xxh);
88 ucl_hash_caseless_equal (const ucl_object_t *k1, const ucl_object_t *k2)
90 if (k1->keylen == k2->keylen) {
91 return strncasecmp (k1->key, k2->key, k1->keylen) == 0;
97 KHASH_INIT (ucl_hash_caseless_node, const ucl_object_t *, struct ucl_hash_elt, 1,
98 ucl_hash_caseless_func, ucl_hash_caseless_equal)
101 ucl_hash_create (bool ignore_case)
105 new = UCL_ALLOC (sizeof (ucl_hash_t));
109 new->caseless = ignore_case;
111 khash_t(ucl_hash_caseless_node) *h = kh_init (ucl_hash_caseless_node);
112 new->hash = (void *)h;
115 khash_t(ucl_hash_node) *h = kh_init (ucl_hash_node);
116 new->hash = (void *)h;
122 void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func)
124 const ucl_object_t *cur, *tmp;
126 if (hashlin == NULL) {
131 /* Iterate over the hash first */
132 khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
136 for (k = kh_begin (h); k != kh_end (h); ++k) {
137 if (kh_exist (h, k)) {
138 cur = (kh_value (h, k)).obj;
139 while (cur != NULL) {
141 func (__DECONST (ucl_object_t *, cur));
148 if (hashlin->caseless) {
149 khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
151 kh_destroy (ucl_hash_caseless_node, h);
154 khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
156 kh_destroy (ucl_hash_node, h);
159 kv_destroy (hashlin->ar);
160 UCL_FREE (sizeof (*hashlin), hashlin);
164 ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
165 const char *key, unsigned keylen)
169 struct ucl_hash_elt *elt;
171 if (hashlin == NULL) {
175 if (hashlin->caseless) {
176 khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
178 k = kh_put (ucl_hash_caseless_node, h, obj, &ret);
180 elt = &kh_value (h, k);
181 kv_push (const ucl_object_t *, hashlin->ar, obj);
183 elt->ar_idx = kv_size (hashlin->ar) - 1;
187 khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
189 k = kh_put (ucl_hash_node, h, obj, &ret);
191 elt = &kh_value (h, k);
192 kv_push (const ucl_object_t *, hashlin->ar, obj);
194 elt->ar_idx = kv_size (hashlin->ar) - 1;
199 void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,
200 const ucl_object_t *new)
204 struct ucl_hash_elt elt, *pelt;
206 if (hashlin == NULL) {
210 if (hashlin->caseless) {
211 khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
213 k = kh_put (ucl_hash_caseless_node, h, old, &ret);
215 elt = kh_value (h, k);
216 kh_del (ucl_hash_caseless_node, h, k);
217 k = kh_put (ucl_hash_caseless_node, h, new, &ret);
218 pelt = &kh_value (h, k);
220 pelt->ar_idx = elt.ar_idx;
221 kv_A (hashlin->ar, elt.ar_idx) = new;
225 khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
227 k = kh_put (ucl_hash_node, h, old, &ret);
229 elt = kh_value (h, k);
230 kh_del (ucl_hash_node, h, k);
231 k = kh_put (ucl_hash_node, h, new, &ret);
232 pelt = &kh_value (h, k);
234 pelt->ar_idx = elt.ar_idx;
235 kv_A (hashlin->ar, elt.ar_idx) = new;
240 struct ucl_hash_real_iter {
241 const ucl_object_t **cur;
242 const ucl_object_t **end;
246 ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
248 struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(*iter);
249 const ucl_object_t *ret = NULL;
251 if (hashlin == NULL) {
256 it = UCL_ALLOC (sizeof (*it));
257 it->cur = &hashlin->ar.a[0];
258 it->end = it->cur + hashlin->ar.n;
261 if (it->cur < it->end) {
265 UCL_FREE (sizeof (*it), it);
276 ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter)
278 struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(iter);
280 return it->cur < it->end - 1;
285 ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen)
288 const ucl_object_t *ret = NULL;
290 struct ucl_hash_elt *elt;
293 search.keylen = keylen;
295 if (hashlin == NULL) {
299 if (hashlin->caseless) {
300 khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
303 k = kh_get (ucl_hash_caseless_node, h, &search);
304 if (k != kh_end (h)) {
305 elt = &kh_value (h, k);
310 khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
312 k = kh_get (ucl_hash_node, h, &search);
313 if (k != kh_end (h)) {
314 elt = &kh_value (h, k);
323 ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
326 struct ucl_hash_elt *elt;
328 if (hashlin == NULL) {
332 if (hashlin->caseless) {
333 khash_t(ucl_hash_caseless_node) *h = (khash_t(ucl_hash_caseless_node) *)
336 k = kh_get (ucl_hash_caseless_node, h, obj);
337 if (k != kh_end (h)) {
338 elt = &kh_value (h, k);
339 kv_A (hashlin->ar, elt->ar_idx) = NULL;
340 kh_del (ucl_hash_caseless_node, h, k);
344 khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
346 k = kh_get (ucl_hash_node, h, obj);
347 if (k != kh_end (h)) {
348 elt = &kh_value (h, k);
349 kv_A (hashlin->ar, elt->ar_idx) = NULL;
350 kh_del (ucl_hash_node, h, k);