"Fossies" - the Fresh Open Source Software Archive 
Member "jansson-2.14/src/hashtable.c" (19 Nov 2020, 9028 Bytes) of package /linux/www/jansson-2.14.tar.bz2:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
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
40 static JSON_INLINE void list_init(list_t *list) {
41 list->next = list;
42 list->prev = list;
43 }
44
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
52 static JSON_INLINE void list_remove(list_t *list) {
53 list->prev->next = list->next;
54 list->next->prev = list->prev;
55 }
56
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
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
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 */
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
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
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
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
193 void hashtable_close(hashtable_t *hashtable) {
194 hashtable_do_clear(hashtable);
195 jsonp_free(hashtable->buckets);
196 }
197
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
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
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
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
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
294 void *hashtable_iter(hashtable_t *hashtable) {
295 return hashtable_iter_next(hashtable, &hashtable->ordered_list);
296 }
297
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
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
320 void *hashtable_iter_key(void *iter) {
321 pair_t *pair = ordered_list_to_pair((list_t *)iter);
322 return pair->key;
323 }
324
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
330 void *hashtable_iter_value(void *iter) {
331 pair_t *pair = ordered_list_to_pair((list_t *)iter);
332 return pair->value;
333 }
334
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 }