Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tpruvot
GitHub Repository: tpruvot/cpuminer-multi
Path: blob/linux/compat/jansson/hashtable.c
1201 views
1
/*
2
* Copyright (c) 2009-2013 Petri Lehtinen <[email protected]>
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
#include <stdlib.h>
9
#include <string.h>
10
#include <jansson_config.h> /* for JSON_INLINE */
11
#include "jansson_private.h" /* for container_of() */
12
#include "hashtable.h"
13
14
typedef struct hashtable_list list_t;
15
typedef struct hashtable_pair pair_t;
16
typedef struct hashtable_bucket bucket_t;
17
18
#define list_to_pair(list_) container_of(list_, pair_t, list)
19
20
/* From http://www.cse.yorku.ca/~oz/hash.html */
21
static size_t hash_str(const void *ptr)
22
{
23
const char *str = (const char *)ptr;
24
25
size_t hash = 5381;
26
size_t c;
27
28
while((c = (size_t)*str))
29
{
30
hash = ((hash << 5) + hash) + c;
31
str++;
32
}
33
34
return hash;
35
}
36
37
static JSON_INLINE void list_init(list_t *list)
38
{
39
list->next = list;
40
list->prev = list;
41
}
42
43
static JSON_INLINE void list_insert(list_t *list, list_t *node)
44
{
45
node->next = list;
46
node->prev = list->prev;
47
list->prev->next = node;
48
list->prev = node;
49
}
50
51
static JSON_INLINE void list_remove(list_t *list)
52
{
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
{
59
return bucket->first == &hashtable->list && bucket->first == bucket->last;
60
}
61
62
static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket,
63
list_t *list)
64
{
65
if(bucket_is_empty(hashtable, bucket))
66
{
67
list_insert(&hashtable->list, list);
68
bucket->first = bucket->last = list;
69
}
70
else
71
{
72
list_insert(bucket->first, list);
73
bucket->first = list;
74
}
75
}
76
77
static const size_t primes[] = {
78
5, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
79
49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
80
12582917, 25165843, 50331653, 100663319, 201326611, 402653189,
81
805306457, 1610612741
82
};
83
84
static JSON_INLINE size_t num_buckets(hashtable_t *hashtable)
85
{
86
return primes[hashtable->num_buckets];
87
}
88
89
90
static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket,
91
const char *key, size_t hash)
92
{
93
list_t *list;
94
pair_t *pair;
95
96
if(bucket_is_empty(hashtable, bucket))
97
return NULL;
98
99
list = bucket->first;
100
while(1)
101
{
102
pair = list_to_pair(list);
103
if(pair->hash == hash && strcmp(pair->key, key) == 0)
104
return pair;
105
106
if(list == bucket->last)
107
break;
108
109
list = list->next;
110
}
111
112
return NULL;
113
}
114
115
/* returns 0 on success, -1 if key was not found */
116
static int hashtable_do_del(hashtable_t *hashtable,
117
const char *key, size_t hash)
118
{
119
pair_t *pair;
120
bucket_t *bucket;
121
size_t index;
122
123
index = hash % num_buckets(hashtable);
124
bucket = &hashtable->buckets[index];
125
126
pair = hashtable_find_pair(hashtable, bucket, key, hash);
127
if(!pair)
128
return -1;
129
130
if(&pair->list == bucket->first && &pair->list == bucket->last)
131
bucket->first = bucket->last = &hashtable->list;
132
133
else if(&pair->list == bucket->first)
134
bucket->first = pair->list.next;
135
136
else if(&pair->list == bucket->last)
137
bucket->last = pair->list.prev;
138
139
list_remove(&pair->list);
140
json_decref(pair->value);
141
142
jsonp_free(pair);
143
hashtable->size--;
144
145
return 0;
146
}
147
148
static void hashtable_do_clear(hashtable_t *hashtable)
149
{
150
list_t *list, *next;
151
pair_t *pair;
152
153
for(list = hashtable->list.next; list != &hashtable->list; list = next)
154
{
155
next = list->next;
156
pair = list_to_pair(list);
157
json_decref(pair->value);
158
jsonp_free(pair);
159
}
160
}
161
162
static int hashtable_do_rehash(hashtable_t *hashtable)
163
{
164
list_t *list, *next;
165
pair_t *pair;
166
size_t i, index, new_size;
167
168
jsonp_free(hashtable->buckets);
169
170
hashtable->num_buckets++;
171
new_size = num_buckets(hashtable);
172
173
hashtable->buckets = jsonp_malloc(new_size * sizeof(bucket_t));
174
if(!hashtable->buckets)
175
return -1;
176
177
for(i = 0; i < num_buckets(hashtable); i++)
178
{
179
hashtable->buckets[i].first = hashtable->buckets[i].last =
180
&hashtable->list;
181
}
182
183
list = hashtable->list.next;
184
list_init(&hashtable->list);
185
186
for(; list != &hashtable->list; list = next) {
187
next = list->next;
188
pair = list_to_pair(list);
189
index = pair->hash % new_size;
190
insert_to_bucket(hashtable, &hashtable->buckets[index], &pair->list);
191
}
192
193
return 0;
194
}
195
196
197
int hashtable_init(hashtable_t *hashtable)
198
{
199
size_t i;
200
201
hashtable->size = 0;
202
hashtable->num_buckets = 0; /* index to primes[] */
203
hashtable->buckets = jsonp_malloc(num_buckets(hashtable) * sizeof(bucket_t));
204
if(!hashtable->buckets)
205
return -1;
206
207
list_init(&hashtable->list);
208
209
for(i = 0; i < num_buckets(hashtable); i++)
210
{
211
hashtable->buckets[i].first = hashtable->buckets[i].last =
212
&hashtable->list;
213
}
214
215
return 0;
216
}
217
218
void hashtable_close(hashtable_t *hashtable)
219
{
220
hashtable_do_clear(hashtable);
221
jsonp_free(hashtable->buckets);
222
}
223
224
int hashtable_set(hashtable_t *hashtable,
225
const char *key, size_t serial,
226
json_t *value)
227
{
228
pair_t *pair;
229
bucket_t *bucket;
230
size_t hash, index;
231
232
/* rehash if the load ratio exceeds 1 */
233
if(hashtable->size >= num_buckets(hashtable))
234
if(hashtable_do_rehash(hashtable))
235
return -1;
236
237
hash = hash_str(key);
238
index = hash % num_buckets(hashtable);
239
bucket = &hashtable->buckets[index];
240
pair = hashtable_find_pair(hashtable, bucket, key, hash);
241
242
if(pair)
243
{
244
json_decref(pair->value);
245
pair->value = value;
246
}
247
else
248
{
249
/* offsetof(...) returns the size of pair_t without the last,
250
flexible member. This way, the correct amount is
251
allocated. */
252
pair = jsonp_malloc(offsetof(pair_t, key) + strlen(key) + 1);
253
if(!pair)
254
return -1;
255
256
pair->hash = hash;
257
pair->serial = serial;
258
strcpy(pair->key, key);
259
pair->value = value;
260
list_init(&pair->list);
261
262
insert_to_bucket(hashtable, bucket, &pair->list);
263
264
hashtable->size++;
265
}
266
return 0;
267
}
268
269
void *hashtable_get(hashtable_t *hashtable, const char *key)
270
{
271
pair_t *pair;
272
size_t hash;
273
bucket_t *bucket;
274
275
hash = hash_str(key);
276
bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
277
278
pair = hashtable_find_pair(hashtable, bucket, key, hash);
279
if(!pair)
280
return NULL;
281
282
return pair->value;
283
}
284
285
int hashtable_del(hashtable_t *hashtable, const char *key)
286
{
287
size_t hash = hash_str(key);
288
return hashtable_do_del(hashtable, key, hash);
289
}
290
291
void hashtable_clear(hashtable_t *hashtable)
292
{
293
size_t i;
294
295
hashtable_do_clear(hashtable);
296
297
for(i = 0; i < num_buckets(hashtable); i++)
298
{
299
hashtable->buckets[i].first = hashtable->buckets[i].last =
300
&hashtable->list;
301
}
302
303
list_init(&hashtable->list);
304
hashtable->size = 0;
305
}
306
307
void *hashtable_iter(hashtable_t *hashtable)
308
{
309
return hashtable_iter_next(hashtable, &hashtable->list);
310
}
311
312
void *hashtable_iter_at(hashtable_t *hashtable, const char *key)
313
{
314
pair_t *pair;
315
size_t hash;
316
bucket_t *bucket;
317
318
hash = hash_str(key);
319
bucket = &hashtable->buckets[hash % num_buckets(hashtable)];
320
321
pair = hashtable_find_pair(hashtable, bucket, key, hash);
322
if(!pair)
323
return NULL;
324
325
return &pair->list;
326
}
327
328
void *hashtable_iter_next(hashtable_t *hashtable, void *iter)
329
{
330
list_t *list = (list_t *)iter;
331
if(list->next == &hashtable->list)
332
return NULL;
333
return list->next;
334
}
335
336
void *hashtable_iter_key(void *iter)
337
{
338
pair_t *pair = list_to_pair((list_t *)iter);
339
return pair->key;
340
}
341
342
size_t hashtable_iter_serial(void *iter)
343
{
344
pair_t *pair = list_to_pair((list_t *)iter);
345
return pair->serial;
346
}
347
348
void *hashtable_iter_value(void *iter)
349
{
350
pair_t *pair = list_to_pair((list_t *)iter);
351
return pair->value;
352
}
353
354
void hashtable_iter_set(void *iter, json_t *value)
355
{
356
pair_t *pair = list_to_pair((list_t *)iter);
357
358
json_decref(pair->value);
359
pair->value = value;
360
}
361
362