File: | home/avsej/code/libcouchbase/contrib/genhash/genhash.c |
Warning: | line 184, column 13 Value stored to 'rv' is never read |
1 | /* |
2 | * Copyright (c) 2006 Dustin Sallings <dustin@spy.net> |
3 | */ |
4 | |
5 | #include <math.h> |
6 | #include "internal.h" |
7 | #include "genhash.h" |
8 | |
9 | /* Table of 32 primes by their distance from the nearest power of two */ |
10 | static lcb_size_t prime_size_table[] = { |
11 | 3, 7, 13, 23, 47, 97, 193, 383, 769, 1531, 3067, 6143, 12289, 24571, 49157, |
12 | 98299, 196613, 393209, 786433, 1572869, 3145721, 6291449, 12582917, |
13 | 25165813, 50331653, 100663291, 201326611, 402653189, 805306357, |
14 | 1610612741 |
15 | }; |
16 | |
17 | #define TABLE_SIZE((int)(sizeof(prime_size_table) / sizeof(int))) ((int)(sizeof(prime_size_table) / sizeof(int))) |
18 | |
19 | struct genhash_entry_t { |
20 | /** The key for this entry */ |
21 | void *key; |
22 | /** Size of the key */ |
23 | lcb_size_t nkey; |
24 | /** The value for this entry */ |
25 | void *value; |
26 | /** Size of the value */ |
27 | lcb_size_t nvalue; |
28 | /** Pointer to the next entry */ |
29 | struct genhash_entry_t *next; |
30 | }; |
31 | |
32 | struct _genhash { |
33 | lcb_size_t size; |
34 | struct lcb_hash_ops ops; |
35 | struct genhash_entry_t *buckets[1]; |
36 | }; |
37 | |
38 | static lcb_size_t estimate_table_size(lcb_size_t est); |
39 | |
40 | |
41 | static void *dup_key(genhash_t *h, const void *key, lcb_size_t klen) |
42 | { |
43 | if (h->ops.dup_key != NULL((void*)0)) { |
44 | return h->ops.dup_key(key, klen); |
45 | } else { |
46 | return (void *)key; |
47 | } |
48 | } |
49 | |
50 | static void *dup_value(genhash_t *h, const void *value, lcb_size_t vlen) |
51 | { |
52 | if (h->ops.dup_value != NULL((void*)0)) { |
53 | return h->ops.dup_value(value, vlen); |
54 | } else { |
55 | return (void *)value; |
56 | } |
57 | } |
58 | |
59 | static void free_key(genhash_t *h, void *key) |
60 | { |
61 | if (h->ops.free_key != NULL((void*)0)) { |
62 | h->ops.free_key(key); |
63 | } |
64 | } |
65 | |
66 | static void free_value(genhash_t *h, void *value) |
67 | { |
68 | if (h->ops.free_value != NULL((void*)0)) { |
69 | h->ops.free_value(value); |
70 | } |
71 | } |
72 | |
73 | static lcb_size_t estimate_table_size(lcb_size_t est) |
74 | { |
75 | lcb_size_t rv = 0; |
76 | while (prime_size_table[rv] < est && rv + 1 < TABLE_SIZE((int)(sizeof(prime_size_table) / sizeof(int)))) { |
77 | rv++; |
78 | } |
79 | return prime_size_table[rv]; |
80 | } |
81 | |
82 | genhash_t *genhash_init(lcb_size_t est, struct lcb_hash_ops ops) |
83 | { |
84 | genhash_t *rv = NULL((void*)0); |
85 | lcb_size_t size = 0; |
86 | if (est < 1) { |
87 | return NULL((void*)0); |
88 | } |
89 | |
90 | lcb_assert(ops.hashfunc != NULL)((void) sizeof ((ops.hashfunc != ((void*)0)) ? 1 : 0), __extension__ ({ if (ops.hashfunc != ((void*)0)) ; else __assert_fail ("ops.hashfunc != ((void*)0)" , "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c", 90 , __extension__ __PRETTY_FUNCTION__); })); |
91 | lcb_assert(ops.hasheq != NULL)((void) sizeof ((ops.hasheq != ((void*)0)) ? 1 : 0), __extension__ ({ if (ops.hasheq != ((void*)0)) ; else __assert_fail ("ops.hasheq != ((void*)0)" , "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c", 91 , __extension__ __PRETTY_FUNCTION__); })); |
92 | lcb_assert((ops.dup_key != NULL && ops.free_key != NULL) || ops.free_key == NULL)((void) sizeof (((ops.dup_key != ((void*)0) && ops.free_key != ((void*)0)) || ops.free_key == ((void*)0)) ? 1 : 0), __extension__ ({ if ((ops.dup_key != ((void*)0) && ops.free_key != ((void*)0)) || ops.free_key == ((void*)0)) ; else __assert_fail ("(ops.dup_key != ((void*)0) && ops.free_key != ((void*)0)) || ops.free_key == ((void*)0)" , "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c", 92 , __extension__ __PRETTY_FUNCTION__); })); |
93 | lcb_assert((ops.dup_value != NULL && ops.free_value != NULL) || ops.free_value == NULL)((void) sizeof (((ops.dup_value != ((void*)0) && ops. free_value != ((void*)0)) || ops.free_value == ((void*)0)) ? 1 : 0), __extension__ ({ if ((ops.dup_value != ((void*)0) && ops.free_value != ((void*)0)) || ops.free_value == ((void*)0 )) ; else __assert_fail ("(ops.dup_value != ((void*)0) && ops.free_value != ((void*)0)) || ops.free_value == ((void*)0)" , "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c", 93 , __extension__ __PRETTY_FUNCTION__); })); |
94 | |
95 | size = estimate_table_size(est); |
96 | rv = calloc(1, sizeof(genhash_t) |
97 | + (size * sizeof(struct genhash_entry_t *))); |
98 | if (rv == NULL((void*)0)) { |
99 | return NULL((void*)0); |
100 | } |
101 | rv->size = size; |
102 | rv->ops = ops; |
103 | |
104 | return rv; |
105 | } |
106 | |
107 | void genhash_free(genhash_t *h) |
108 | { |
109 | if (h != NULL((void*)0)) { |
110 | genhash_clear(h); |
111 | free(h); |
112 | } |
113 | } |
114 | |
115 | int genhash_store(genhash_t *h, const void *k, lcb_size_t klen, |
116 | const void *v, lcb_size_t vlen) |
117 | { |
118 | lcb_size_t n = 0; |
119 | struct genhash_entry_t *p; |
120 | |
121 | lcb_assert(h != NULL)((void) sizeof ((h != ((void*)0)) ? 1 : 0), __extension__ ({ if (h != ((void*)0)) ; else __assert_fail ("h != ((void*)0)", "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c" , 121, __extension__ __PRETTY_FUNCTION__); })); |
122 | |
123 | n = h->ops.hashfunc(k, klen) % h->size; |
124 | lcb_assert(n < h->size)((void) sizeof ((n < h->size) ? 1 : 0), __extension__ ( { if (n < h->size) ; else __assert_fail ("n < h->size" , "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c", 124 , __extension__ __PRETTY_FUNCTION__); })); |
125 | |
126 | p = calloc(1, sizeof(struct genhash_entry_t)); |
127 | if (!p) { |
128 | return -1; |
129 | } |
130 | |
131 | p->key = dup_key(h, k, klen); |
132 | p->nkey = klen; |
133 | p->value = dup_value(h, v, vlen); |
134 | p->nvalue = vlen; |
135 | |
136 | p->next = h->buckets[n]; |
137 | h->buckets[n] = p; |
138 | return 0; |
139 | } |
140 | |
141 | static struct genhash_entry_t *genhash_find_entry(genhash_t *h, |
142 | const void *k, |
143 | lcb_size_t klen) |
144 | { |
145 | lcb_size_t n = 0; |
146 | struct genhash_entry_t *p; |
147 | |
148 | lcb_assert(h != NULL)((void) sizeof ((h != ((void*)0)) ? 1 : 0), __extension__ ({ if (h != ((void*)0)) ; else __assert_fail ("h != ((void*)0)", "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c" , 148, __extension__ __PRETTY_FUNCTION__); })); |
149 | n = h->ops.hashfunc(k, klen) % h->size; |
150 | lcb_assert(n < h->size)((void) sizeof ((n < h->size) ? 1 : 0), __extension__ ( { if (n < h->size) ; else __assert_fail ("n < h->size" , "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c", 150 , __extension__ __PRETTY_FUNCTION__); })); |
151 | |
152 | p = h->buckets[n]; |
153 | for (p = h->buckets[n]; p && !h->ops.hasheq(k, klen, p->key, p->nkey); p = p->next); |
154 | return p; |
155 | } |
156 | |
157 | void *genhash_find(genhash_t *h, const void *k, lcb_size_t klen) |
158 | { |
159 | struct genhash_entry_t *p; |
160 | void *rv = NULL((void*)0); |
161 | |
162 | p = genhash_find_entry(h, k, klen); |
163 | |
164 | if (p) { |
165 | rv = p->value; |
166 | } |
167 | return rv; |
168 | } |
169 | |
170 | enum update_type genhash_update(genhash_t *h, const void *k, lcb_size_t klen, |
171 | const void *v, lcb_size_t vlen) |
172 | { |
173 | struct genhash_entry_t *p; |
174 | enum update_type rv = 0; |
175 | |
176 | p = genhash_find_entry(h, k, klen); |
177 | |
178 | if (p) { |
179 | free_value(h, p->value); |
180 | p->value = dup_value(h, v, vlen); |
181 | rv = MODIFICATION; |
182 | } else { |
183 | if (-1 == genhash_store(h, k, klen, v, vlen)) { |
184 | rv = ALLOC_FAILURE; |
Value stored to 'rv' is never read | |
185 | } |
186 | rv = NEW; |
187 | } |
188 | |
189 | return rv; |
190 | } |
191 | |
192 | enum update_type genhash_fun_update(genhash_t *h, |
193 | const void *k, |
194 | lcb_size_t klen, |
195 | void * (*upd)(const void *, |
196 | const void *, |
197 | lcb_size_t *, |
198 | void *), |
199 | void (*fr)(void *), |
200 | void *arg, |
201 | const void *def, |
202 | lcb_size_t deflen) |
203 | { |
204 | struct genhash_entry_t *p; |
205 | enum update_type rv = 0; |
206 | lcb_size_t newSize = 0; |
207 | |
208 | p = genhash_find_entry(h, k, klen); |
209 | |
210 | if (p) { |
211 | void *newValue = upd(k, p->value, &newSize, arg); |
212 | free_value(h, p->value); |
213 | p->value = dup_value(h, newValue, newSize); |
214 | fr(newValue); |
215 | rv = MODIFICATION; |
216 | } else { |
217 | void *newValue = upd(k, def, &newSize, arg); |
218 | genhash_store(h, k, klen, newValue, newSize); |
219 | fr(newValue); |
220 | rv = NEW; |
221 | } |
222 | |
223 | (void)deflen; |
224 | return rv; |
225 | } |
226 | |
227 | static void free_item(genhash_t *h, struct genhash_entry_t *i) |
228 | { |
229 | lcb_assert(i)((void) sizeof ((i) ? 1 : 0), __extension__ ({ if (i) ; else __assert_fail ("i", "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c" , 229, __extension__ __PRETTY_FUNCTION__); })); |
230 | free_key(h, i->key); |
231 | free_value(h, i->value); |
232 | free(i); |
233 | } |
234 | |
235 | int genhash_delete(genhash_t *h, const void *k, lcb_size_t klen) |
236 | { |
237 | struct genhash_entry_t *deleteme = NULL((void*)0); |
238 | lcb_size_t n = 0; |
239 | int rv = 0; |
240 | |
241 | lcb_assert(h != NULL)((void) sizeof ((h != ((void*)0)) ? 1 : 0), __extension__ ({ if (h != ((void*)0)) ; else __assert_fail ("h != ((void*)0)", "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c" , 241, __extension__ __PRETTY_FUNCTION__); })); |
242 | n = h->ops.hashfunc(k, klen) % h->size; |
243 | lcb_assert(n < h->size)((void) sizeof ((n < h->size) ? 1 : 0), __extension__ ( { if (n < h->size) ; else __assert_fail ("n < h->size" , "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c", 243 , __extension__ __PRETTY_FUNCTION__); })); |
244 | |
245 | if (h->buckets[n] != NULL((void*)0)) { |
246 | /* Special case the first one */ |
247 | if (h->ops.hasheq(h->buckets[n]->key, h->buckets[n]->nkey, k, klen)) { |
248 | deleteme = h->buckets[n]; |
249 | h->buckets[n] = deleteme->next; |
250 | } else { |
251 | struct genhash_entry_t *p = NULL((void*)0); |
252 | for (p = h->buckets[n]; deleteme == NULL((void*)0) && p->next != NULL((void*)0); p = p->next) { |
253 | if (h->ops.hasheq(p->next->key, p->next->nkey, k, klen)) { |
254 | deleteme = p->next; |
255 | p->next = deleteme->next; |
256 | } |
257 | } |
258 | } |
259 | } |
260 | if (deleteme != NULL((void*)0)) { |
261 | free_item(h, deleteme); |
262 | rv++; |
263 | } |
264 | |
265 | return rv; |
266 | } |
267 | |
268 | int genhash_delete_all(genhash_t *h, const void *k, lcb_size_t klen) |
269 | { |
270 | int rv = 0; |
271 | while (genhash_delete(h, k, klen) == 1) { |
272 | rv++; |
273 | } |
274 | return rv; |
275 | } |
276 | |
277 | void genhash_iter(genhash_t *h, |
278 | void (*iterfunc)(const void *key, lcb_size_t nkey, |
279 | const void *val, lcb_size_t nval, |
280 | void *arg), void *arg) |
281 | { |
282 | lcb_size_t i = 0; |
283 | struct genhash_entry_t *p = NULL((void*)0); |
284 | lcb_assert(h != NULL)((void) sizeof ((h != ((void*)0)) ? 1 : 0), __extension__ ({ if (h != ((void*)0)) ; else __assert_fail ("h != ((void*)0)", "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c" , 284, __extension__ __PRETTY_FUNCTION__); })); |
285 | |
286 | for (i = 0; i < h->size; i++) { |
287 | for (p = h->buckets[i]; p != NULL((void*)0); p = p->next) { |
288 | iterfunc(p->key, p->nkey, p->value, p->nvalue, arg); |
289 | } |
290 | } |
291 | } |
292 | |
293 | int genhash_clear(genhash_t *h) |
294 | { |
295 | lcb_size_t i = 0; |
296 | int rv = 0; |
297 | lcb_assert(h != NULL)((void) sizeof ((h != ((void*)0)) ? 1 : 0), __extension__ ({ if (h != ((void*)0)) ; else __assert_fail ("h != ((void*)0)", "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c" , 297, __extension__ __PRETTY_FUNCTION__); })); |
298 | |
299 | for (i = 0; i < h->size; i++) { |
300 | while (h->buckets[i]) { |
301 | struct genhash_entry_t *p = NULL((void*)0); |
302 | p = h->buckets[i]; |
303 | h->buckets[i] = p->next; |
304 | free_item(h, p); |
305 | } |
306 | } |
307 | |
308 | return rv; |
309 | } |
310 | |
311 | static void count_entries(const void *key, |
312 | lcb_size_t klen, |
313 | const void *val, |
314 | lcb_size_t vlen, |
315 | void *arg) |
316 | { |
317 | int *count = (int *)arg; |
318 | (*count)++; |
319 | (void)key; |
320 | (void)klen; |
321 | (void)val; |
322 | (void)vlen; |
323 | } |
324 | |
325 | int genhash_size(genhash_t *h) |
326 | { |
327 | int rv = 0; |
328 | lcb_assert(h != NULL)((void) sizeof ((h != ((void*)0)) ? 1 : 0), __extension__ ({ if (h != ((void*)0)) ; else __assert_fail ("h != ((void*)0)", "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c" , 328, __extension__ __PRETTY_FUNCTION__); })); |
329 | genhash_iter(h, count_entries, &rv); |
330 | return rv; |
331 | } |
332 | |
333 | int genhash_size_for_key(genhash_t *h, const void *k, lcb_size_t klen) |
334 | { |
335 | int rv = 0; |
336 | lcb_assert(h != NULL)((void) sizeof ((h != ((void*)0)) ? 1 : 0), __extension__ ({ if (h != ((void*)0)) ; else __assert_fail ("h != ((void*)0)", "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c" , 336, __extension__ __PRETTY_FUNCTION__); })); |
337 | genhash_iter_key(h, k, klen, count_entries, &rv); |
338 | return rv; |
339 | } |
340 | |
341 | void genhash_iter_key(genhash_t *h, const void *key, lcb_size_t klen, |
342 | void (*iterfunc)(const void *key, lcb_size_t klen, |
343 | const void *val, lcb_size_t vlen, |
344 | void *arg), void *arg) |
345 | { |
346 | lcb_size_t n = 0; |
347 | struct genhash_entry_t *p = NULL((void*)0); |
348 | |
349 | lcb_assert(h != NULL)((void) sizeof ((h != ((void*)0)) ? 1 : 0), __extension__ ({ if (h != ((void*)0)) ; else __assert_fail ("h != ((void*)0)", "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c" , 349, __extension__ __PRETTY_FUNCTION__); })); |
350 | n = h->ops.hashfunc(key, klen) % h->size; |
351 | lcb_assert(n < h->size)((void) sizeof ((n < h->size) ? 1 : 0), __extension__ ( { if (n < h->size) ; else __assert_fail ("n < h->size" , "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c", 351 , __extension__ __PRETTY_FUNCTION__); })); |
352 | |
353 | for (p = h->buckets[n]; p != NULL((void*)0); p = p->next) { |
354 | if (h->ops.hasheq(key, klen, p->key, p->nkey)) { |
355 | iterfunc(p->key, p->nkey, p->value, p->nvalue, arg); |
356 | } |
357 | } |
358 | } |
359 | |
360 | int genhash_string_hash(const void *p, lcb_size_t nkey) |
361 | { |
362 | int rv = 5381; |
363 | int i = 0; |
364 | char *str = (char *)p; |
365 | |
366 | for (i = 0; i < (int)nkey; i++) { |
367 | lcb_assert(str[i])((void) sizeof ((str[i]) ? 1 : 0), __extension__ ({ if (str[i ]) ; else __assert_fail ("str[i]", "/home/avsej/code/libcouchbase/contrib/genhash/genhash.c" , 367, __extension__ __PRETTY_FUNCTION__); })); |
368 | rv = ((rv << 5) + rv) ^ str[i]; |
369 | } |
370 | |
371 | return rv; |
372 | } |