"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.
For more information about "hashtable.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.13.1_vs_2.14.
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 }