1 /*
2  * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org>
3  *
4  * This library is free software; you can redistribute it and/or modify
5  * it under the terms of the MIT license. See LICENSE for details.
6  */
7 
8 #if HAVE_CONFIG_H
9 #include <jansson_private_config.h>
10 #endif
11 
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #if HAVE_STDINT_H
16 #include <stdint.h>
17 #endif
18 
19 #include "hashtable.h"
20 #include "jansson_private.h" /* for container_of() */
21 #include <jansson_config.h>  /* for JSON_INLINE */
22 
23 #ifndef INITIAL_HASHTABLE_ORDER
24 #define INITIAL_HASHTABLE_ORDER 3
25 #endif
26 
27 typedef struct hashtable_list list_t;
28 typedef struct hashtable_pair pair_t;
29 typedef struct hashtable_bucket bucket_t;
30 
31 extern volatile uint32_t hashtable_seed;
32 
33 /* Implementation of the hash function */
34 #include "lookup3.h"
35 
36 #define list_to_pair(list_)         container_of(list_, pair_t, list)
37 #define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list)
38 #define hash_str(key, len)          ((size_t)hashlittle((key), len, hashtable_seed))
39 
list_init(list_t * list)40 static JSON_INLINE void list_init(list_t *list) {
41     list->next = list;
42     list->prev = list;
43 }
44 
list_insert(list_t * list,list_t * node)45 static JSON_INLINE void list_insert(list_t *list, list_t *node) {
46     node->next = list;
47     node->prev = list->prev;
48     list->prev->next = node;
49     list->prev = node;
50 }
51 
list_remove(list_t * list)52 static JSON_INLINE void list_remove(list_t *list) {
53     list->prev->next = list->next;
54     list->next->prev = list->prev;
55 }
56 
bucket_is_empty(hashtable_t * hashtable,bucket_t * bucket)57 static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) {
58     return bucket->first == &hashtable->list && bucket->first == bucket->last;
59 }
60 
insert_to_bucket(hashtable_t * hashtable,bucket_t * bucket,list_t * list)61 static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, list_t *list) {
62     if (bucket_is_empty(hashtable, bucket)) {
63         list_insert(&hashtable->list, list);
64         bucket->first = bucket->last = list;
65     } else {
66         list_insert(bucket->first, list);
67         bucket->first = list;
68     }
69 }
70 
hashtable_find_pair(hashtable_t * hashtable,bucket_t * bucket,const char * key,size_t key_len,size_t hash)71 static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
72                                    const char *key, size_t key_len, size_t hash) {
73     list_t *list;
74     pair_t *pair;
75 
76     if (bucket_is_empty(hashtable, bucket))
77         return NULL;
78 
79     list = bucket->first;
80     while (1) {
81         pair = list_to_pair(list);
82         if (pair->hash == hash && pair->key_len == key_len &&
83             memcmp(pair->key, key, key_len) == 0)
84             return pair;
85 
86         if (list == bucket->last)
87             break;
88 
89         list = list->next;
90     }
91 
92     return NULL;
93 }
94 
95 /* returns 0 on success, -1 if key was not found */
hashtable_do_del(hashtable_t * hashtable,const char * key,size_t key_len,size_t hash)96 static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t key_len,
97                             size_t hash) {
98     pair_t *pair;
99     bucket_t *bucket;
100     size_t index;
101 
102     index = hash & hashmask(hashtable->order);
103     bucket = &hashtable->buckets[index];
104 
105     pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
106     if (!pair)
107         return -1;
108 
109     if (&pair->list == bucket->first && &pair->list == bucket->last)
110         bucket->first = bucket->last = &hashtable->list;
111 
112     else if (&pair->list == bucket->first)
113         bucket->first = pair->list.next;
114 
115     else if (&pair->list == bucket->last)
116         bucket->last = pair->list.prev;
117 
118     list_remove(&pair->list);
119     list_remove(&pair->ordered_list);
120     json_decref(pair->value);
121 
122     jsonp_free(pair);
123     hashtable->size--;
124 
125     return 0;
126 }
127 
hashtable_do_clear(hashtable_t * hashtable)128 static void hashtable_do_clear(hashtable_t *hashtable) {
129     list_t *list, *next;
130     pair_t *pair;
131 
132     for (list = hashtable->list.next; list != &hashtable->list; list = next) {
133         next = list->next;
134         pair = list_to_pair(list);
135         json_decref(pair->value);
136         jsonp_free(pair);
137     }
138 }
139 
hashtable_do_rehash(hashtable_t * hashtable)140 static int hashtable_do_rehash(hashtable_t *hashtable) {
141     list_t *list, *next;
142     pair_t *pair;
143     size_t i, index, new_size, new_order;
144     struct hashtable_bucket *new_buckets;
145 
146     new_order = hashtable->order + 1;
147     new_size = hashsize(new_order);
148 
149     new_buckets = jsonp_malloc(new_size * sizeof(bucket_t));
150     if (!new_buckets)
151         return -1;
152 
153     jsonp_free(hashtable->buckets);
154     hashtable->buckets = new_buckets;
155     hashtable->order = new_order;
156 
157     for (i = 0; i < hashsize(hashtable->order); i++) {
158         hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list;
159     }
160 
161     list = hashtable->list.next;
162     list_init(&hashtable->list);
163 
164     for (; list != &hashtable->list; list = next) {
165         next = list->next;
166         pair = list_to_pair(list);
167         index = pair->hash % new_size;
168         insert_to_bucket(hashtable, &hashtable->buckets[index], &pair->list);
169     }
170 
171     return 0;
172 }
173 
hashtable_init(hashtable_t * hashtable)174 int hashtable_init(hashtable_t *hashtable) {
175     size_t i;
176 
177     hashtable->size = 0;
178     hashtable->order = INITIAL_HASHTABLE_ORDER;
179     hashtable->buckets = jsonp_malloc(hashsize(hashtable->order) * sizeof(bucket_t));
180     if (!hashtable->buckets)
181         return -1;
182 
183     list_init(&hashtable->list);
184     list_init(&hashtable->ordered_list);
185 
186     for (i = 0; i < hashsize(hashtable->order); i++) {
187         hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list;
188     }
189 
190     return 0;
191 }
192 
hashtable_close(hashtable_t * hashtable)193 void hashtable_close(hashtable_t *hashtable) {
194     hashtable_do_clear(hashtable);
195     jsonp_free(hashtable->buckets);
196 }
197 
init_pair(json_t * value,const char * key,size_t key_len,size_t hash)198 static pair_t *init_pair(json_t *value, const char *key, size_t key_len, size_t hash) {
199     pair_t *pair;
200 
201     /* offsetof(...) returns the size of pair_t without the last,
202    flexible member. This way, the correct amount is
203    allocated. */
204 
205     if (key_len >= (size_t)-1 - offsetof(pair_t, key)) {
206         /* Avoid an overflow if the key is very long */
207         return NULL;
208     }
209 
210     pair = jsonp_malloc(offsetof(pair_t, key) + key_len + 1);
211 
212     if (!pair)
213         return NULL;
214 
215     pair->hash = hash;
216     memcpy(pair->key, key, key_len);
217     pair->key[key_len] = '\0';
218     pair->key_len = key_len;
219     pair->value = value;
220 
221     list_init(&pair->list);
222     list_init(&pair->ordered_list);
223 
224     return pair;
225 }
226 
hashtable_set(hashtable_t * hashtable,const char * key,size_t key_len,json_t * value)227 int hashtable_set(hashtable_t *hashtable, const char *key, size_t key_len,
228                   json_t *value) {
229     pair_t *pair;
230     bucket_t *bucket;
231     size_t hash, index;
232 
233     /* rehash if the load ratio exceeds 1 */
234     if (hashtable->size >= hashsize(hashtable->order))
235         if (hashtable_do_rehash(hashtable))
236             return -1;
237 
238     hash = hash_str(key, key_len);
239     index = hash & hashmask(hashtable->order);
240     bucket = &hashtable->buckets[index];
241     pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
242 
243     if (pair) {
244         json_decref(pair->value);
245         pair->value = value;
246     } else {
247         pair = init_pair(value, key, key_len, hash);
248 
249         if (!pair)
250             return -1;
251 
252         insert_to_bucket(hashtable, bucket, &pair->list);
253         list_insert(&hashtable->ordered_list, &pair->ordered_list);
254 
255         hashtable->size++;
256     }
257     return 0;
258 }
259 
hashtable_get(hashtable_t * hashtable,const char * key,size_t key_len)260 void *hashtable_get(hashtable_t *hashtable, const char *key, size_t key_len) {
261     pair_t *pair;
262     size_t hash;
263     bucket_t *bucket;
264 
265     hash = hash_str(key, key_len);
266     bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
267 
268     pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
269     if (!pair)
270         return NULL;
271 
272     return pair->value;
273 }
274 
hashtable_del(hashtable_t * hashtable,const char * key,size_t key_len)275 int hashtable_del(hashtable_t *hashtable, const char *key, size_t key_len) {
276     size_t hash = hash_str(key, key_len);
277     return hashtable_do_del(hashtable, key, key_len, hash);
278 }
279 
hashtable_clear(hashtable_t * hashtable)280 void hashtable_clear(hashtable_t *hashtable) {
281     size_t i;
282 
283     hashtable_do_clear(hashtable);
284 
285     for (i = 0; i < hashsize(hashtable->order); i++) {
286         hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list;
287     }
288 
289     list_init(&hashtable->list);
290     list_init(&hashtable->ordered_list);
291     hashtable->size = 0;
292 }
293 
hashtable_iter(hashtable_t * hashtable)294 void *hashtable_iter(hashtable_t *hashtable) {
295     return hashtable_iter_next(hashtable, &hashtable->ordered_list);
296 }
297 
hashtable_iter_at(hashtable_t * hashtable,const char * key,size_t key_len)298 void *hashtable_iter_at(hashtable_t *hashtable, const char *key, size_t key_len) {
299     pair_t *pair;
300     size_t hash;
301     bucket_t *bucket;
302 
303     hash = hash_str(key, key_len);
304     bucket = &hashtable->buckets[hash & hashmask(hashtable->order)];
305 
306     pair = hashtable_find_pair(hashtable, bucket, key, key_len, hash);
307     if (!pair)
308         return NULL;
309 
310     return &pair->ordered_list;
311 }
312 
hashtable_iter_next(hashtable_t * hashtable,void * iter)313 void *hashtable_iter_next(hashtable_t *hashtable, void *iter) {
314     list_t *list = (list_t *)iter;
315     if (list->next == &hashtable->ordered_list)
316         return NULL;
317     return list->next;
318 }
319 
hashtable_iter_key(void * iter)320 void *hashtable_iter_key(void *iter) {
321     pair_t *pair = ordered_list_to_pair((list_t *)iter);
322     return pair->key;
323 }
324 
hashtable_iter_key_len(void * iter)325 size_t hashtable_iter_key_len(void *iter) {
326     pair_t *pair = ordered_list_to_pair((list_t *)iter);
327     return pair->key_len;
328 }
329 
hashtable_iter_value(void * iter)330 void *hashtable_iter_value(void *iter) {
331     pair_t *pair = ordered_list_to_pair((list_t *)iter);
332     return pair->value;
333 }
334 
hashtable_iter_set(void * iter,json_t * value)335 void hashtable_iter_set(void *iter, json_t *value) {
336     pair_t *pair = ordered_list_to_pair((list_t *)iter);
337 
338     json_decref(pair->value);
339     pair->value = value;
340 }
341