]> git.ozlabs.org Git - ccan/blob - ccan/htable/htable.c
base64: fix for unsigned chars (e.g. ARM).
[ccan] / ccan / htable / htable.c
1 /* Licensed under LGPLv2+ - see LICENSE file for details */
2 #include <ccan/htable/htable.h>
3 #include <ccan/compiler/compiler.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <limits.h>
7 #include <stdbool.h>
8 #include <assert.h>
9 #include <string.h>
10
11 /* We use 0x1 as deleted marker. */
12 #define HTABLE_DELETED (0x1)
13
14 /* perfect_bitnum 63 means there's no perfect bitnum */
15 #define NO_PERFECT_BIT (sizeof(uintptr_t) * CHAR_BIT - 1)
16
17 static void *htable_default_alloc(struct htable *ht, size_t len)
18 {
19         return calloc(len, 1);
20 }
21
22 static void htable_default_free(struct htable *ht, void *p)
23 {
24         free(p);
25 }
26
27 static void *(*htable_alloc)(struct htable *, size_t) = htable_default_alloc;
28 static void (*htable_free)(struct htable *, void *) = htable_default_free;
29
30 void htable_set_allocator(void *(*alloc)(struct htable *, size_t len),
31                           void (*free)(struct htable *, void *p))
32 {
33         if (!alloc)
34                 alloc = htable_default_alloc;
35         if (!free)
36                 free = htable_default_free;
37         htable_alloc = alloc;
38         htable_free = free;
39 }
40
41 /* We clear out the bits which are always the same, and put metadata there. */
42 static inline uintptr_t get_extra_ptr_bits(const struct htable *ht,
43                                            uintptr_t e)
44 {
45         return e & ht->common_mask;
46 }
47
48 static inline void *get_raw_ptr(const struct htable *ht, uintptr_t e)
49 {
50         return (void *)((e & ~ht->common_mask) | ht->common_bits);
51 }
52
53 static inline uintptr_t make_hval(const struct htable *ht,
54                                   const void *p, uintptr_t bits)
55 {
56         return ((uintptr_t)p & ~ht->common_mask) | bits;
57 }
58
59 static inline bool entry_is_valid(uintptr_t e)
60 {
61         return e > HTABLE_DELETED;
62 }
63
64 static inline uintptr_t ht_perfect_mask(const struct htable *ht)
65 {
66         return (uintptr_t)2 << ht->perfect_bitnum;
67 }
68
69 static inline uintptr_t get_hash_ptr_bits(const struct htable *ht,
70                                           size_t hash)
71 {
72         /* Shuffling the extra bits (as specified in mask) down the
73          * end is quite expensive.  But the lower bits are redundant, so
74          * we fold the value first. */
75         return (hash ^ (hash >> ht->bits))
76                 & ht->common_mask & ~ht_perfect_mask(ht);
77 }
78
79 void htable_init(struct htable *ht,
80                  size_t (*rehash)(const void *elem, void *priv), void *priv)
81 {
82         struct htable empty = HTABLE_INITIALIZER(empty, NULL, NULL);
83         *ht = empty;
84         ht->rehash = rehash;
85         ht->priv = priv;
86         ht->table = &ht->common_bits;
87 }
88
89 /* Fill to 87.5% */
90 static inline size_t ht_max(const struct htable *ht)
91 {
92         return ((size_t)7 << ht->bits) / 8;
93 }
94
95 /* Clean deleted if we're full, and more than 12.5% deleted */
96 static inline size_t ht_max_deleted(const struct htable *ht)
97 {
98         return ((size_t)1 << ht->bits) / 8;
99 }
100
101 bool htable_init_sized(struct htable *ht,
102                        size_t (*rehash)(const void *, void *),
103                        void *priv, size_t expect)
104 {
105         htable_init(ht, rehash, priv);
106
107         /* Don't go insane with sizing. */
108         for (ht->bits = 1; ht_max(ht) < expect; ht->bits++) {
109                 if (ht->bits == 30)
110                         break;
111         }
112
113         ht->table = htable_alloc(ht, sizeof(size_t) << ht->bits);
114         if (!ht->table) {
115                 ht->table = &ht->common_bits;
116                 return false;
117         }
118         (void)htable_debug(ht, HTABLE_LOC);
119         return true;
120 }
121         
122 void htable_clear(struct htable *ht)
123 {
124         if (ht->table != &ht->common_bits)
125                 htable_free(ht, (void *)ht->table);
126         htable_init(ht, ht->rehash, ht->priv);
127 }
128
129 bool htable_copy_(struct htable *dst, const struct htable *src)
130 {
131         uintptr_t *htable = htable_alloc(dst, sizeof(size_t) << src->bits);
132
133         if (!htable)
134                 return false;
135
136         *dst = *src;
137         dst->table = htable;
138         memcpy(dst->table, src->table, sizeof(size_t) << src->bits);
139         return true;
140 }
141
142 static size_t hash_bucket(const struct htable *ht, size_t h)
143 {
144         return h & ((1 << ht->bits)-1);
145 }
146
147 static void *htable_val(const struct htable *ht,
148                         struct htable_iter *i, size_t hash, uintptr_t perfect)
149 {
150         uintptr_t h2 = get_hash_ptr_bits(ht, hash) | perfect;
151
152         while (ht->table[i->off]) {
153                 if (ht->table[i->off] != HTABLE_DELETED) {
154                         if (get_extra_ptr_bits(ht, ht->table[i->off]) == h2)
155                                 return get_raw_ptr(ht, ht->table[i->off]);
156                 }
157                 i->off = (i->off + 1) & ((1 << ht->bits)-1);
158                 h2 &= ~perfect;
159         }
160         return NULL;
161 }
162
163 void *htable_firstval_(const struct htable *ht,
164                        struct htable_iter *i, size_t hash)
165 {
166         i->off = hash_bucket(ht, hash);
167         return htable_val(ht, i, hash, ht_perfect_mask(ht));
168 }
169
170 void *htable_nextval_(const struct htable *ht,
171                       struct htable_iter *i, size_t hash)
172 {
173         i->off = (i->off + 1) & ((1 << ht->bits)-1);
174         return htable_val(ht, i, hash, 0);
175 }
176
177 void *htable_first_(const struct htable *ht, struct htable_iter *i)
178 {
179         for (i->off = 0; i->off < (size_t)1 << ht->bits; i->off++) {
180                 if (entry_is_valid(ht->table[i->off]))
181                         return get_raw_ptr(ht, ht->table[i->off]);
182         }
183         return NULL;
184 }
185
186 void *htable_next_(const struct htable *ht, struct htable_iter *i)
187 {
188         for (i->off++; i->off < (size_t)1 << ht->bits; i->off++) {
189                 if (entry_is_valid(ht->table[i->off]))
190                         return get_raw_ptr(ht, ht->table[i->off]);
191         }
192         return NULL;
193 }
194
195 void *htable_prev_(const struct htable *ht, struct htable_iter *i)
196 {
197         for (;;) {
198                 if (!i->off)
199                         return NULL;
200                 i->off--;
201                 if (entry_is_valid(ht->table[i->off]))
202                         return get_raw_ptr(ht, ht->table[i->off]);
203         }
204 }
205
206 /* Another bit currently in mask needs to be exposed, so that a bucket with p in
207  * it won't appear invalid */
208 static COLD void unset_another_common_bit(struct htable *ht,
209                                           uintptr_t *maskdiff,
210                                           const void *p)
211 {
212         size_t i;
213
214         for (i = sizeof(uintptr_t) * CHAR_BIT - 1; i > 0; i--) {
215                 if (((uintptr_t)p & ((uintptr_t)1 << i))
216                     && ht->common_mask & ~*maskdiff & ((uintptr_t)1 << i))
217                         break;
218         }
219         /* There must have been one, right? */
220         assert(i > 0);
221
222         *maskdiff |= ((uintptr_t)1 << i);
223 }
224
225 /* We want to change the common mask: this fixes up the table */
226 static COLD void fixup_table_common(struct htable *ht, uintptr_t maskdiff)
227 {
228         size_t i;
229         uintptr_t bitsdiff;
230
231 again:
232         bitsdiff = ht->common_bits & maskdiff;
233
234         for (i = 0; i < (size_t)1 << ht->bits; i++) {
235                 uintptr_t e;
236                 if (!entry_is_valid(e = ht->table[i]))
237                         continue;
238
239                 /* Clear the bits no longer in the mask, set them as
240                  * expected. */
241                 e &= ~maskdiff;
242                 e |= bitsdiff;
243                 /* If this made it invalid, restart with more exposed */
244                 if (!entry_is_valid(e)) {
245                         unset_another_common_bit(ht, &maskdiff, get_raw_ptr(ht, e));
246                         goto again;
247                 }
248                 ht->table[i] = e;
249         }
250
251         /* Take away those bits from our mask, bits and perfect bit. */
252         ht->common_mask &= ~maskdiff;
253         ht->common_bits &= ~maskdiff;
254         if (ht_perfect_mask(ht) & maskdiff)
255                 ht->perfect_bitnum = NO_PERFECT_BIT;
256 }
257
258 /* Limited recursion */
259 static void ht_add(struct htable *ht, const void *new, size_t h);
260
261 /* We tried to add this entry, but it looked invalid!  We need to
262  * let another pointer bit through mask */
263 static COLD void update_common_fix_invalid(struct htable *ht, const void *p, size_t h)
264 {
265         uintptr_t maskdiff;
266
267         assert(ht->elems != 0);
268
269         maskdiff = 0;
270         unset_another_common_bit(ht, &maskdiff, p);
271         fixup_table_common(ht, maskdiff);
272
273         /* Now won't recurse */
274         ht_add(ht, p, h);
275 }
276
277 /* This does not expand the hash table, that's up to caller. */
278 static void ht_add(struct htable *ht, const void *new, size_t h)
279 {
280         size_t i;
281         uintptr_t perfect = ht_perfect_mask(ht);
282
283         i = hash_bucket(ht, h);
284
285         while (entry_is_valid(ht->table[i])) {
286                 perfect = 0;
287                 i = (i + 1) & ((1 << ht->bits)-1);
288         }
289         ht->table[i] = make_hval(ht, new, get_hash_ptr_bits(ht, h)|perfect);
290         if (!entry_is_valid(ht->table[i]))
291                 update_common_fix_invalid(ht, new, h);
292 }
293
294 static COLD bool double_table(struct htable *ht)
295 {
296         unsigned int i;
297         size_t oldnum = (size_t)1 << ht->bits;
298         uintptr_t *oldtable, e;
299
300         oldtable = ht->table;
301         ht->table = htable_alloc(ht, sizeof(size_t) << (ht->bits+1));
302         if (!ht->table) {
303                 ht->table = oldtable;
304                 return false;
305         }
306         ht->bits++;
307
308         /* If we lost our "perfect bit", get it back now. */
309         if (ht->perfect_bitnum == NO_PERFECT_BIT && ht->common_mask) {
310                 for (i = 0; i < sizeof(ht->common_mask) * CHAR_BIT; i++) {
311                         if (ht->common_mask & ((size_t)2 << i)) {
312                                 ht->perfect_bitnum = i;
313                                 break;
314                         }
315                 }
316         }
317
318         if (oldtable != &ht->common_bits) {
319                 for (i = 0; i < oldnum; i++) {
320                         if (entry_is_valid(e = oldtable[i])) {
321                                 void *p = get_raw_ptr(ht, e);
322                                 ht_add(ht, p, ht->rehash(p, ht->priv));
323                         }
324                 }
325                 htable_free(ht, oldtable);
326         }
327         ht->deleted = 0;
328
329         (void)htable_debug(ht, HTABLE_LOC);
330         return true;
331 }
332
333 static COLD void rehash_table(struct htable *ht)
334 {
335         size_t start, i;
336         uintptr_t e, perfect = ht_perfect_mask(ht);
337
338         /* Beware wrap cases: we need to start from first empty bucket. */
339         for (start = 0; ht->table[start]; start++);
340
341         for (i = 0; i < (size_t)1 << ht->bits; i++) {
342                 size_t h = (i + start) & ((1 << ht->bits)-1);
343                 e = ht->table[h];
344                 if (!e)
345                         continue;
346                 if (e == HTABLE_DELETED)
347                         ht->table[h] = 0;
348                 else if (!(e & perfect)) {
349                         void *p = get_raw_ptr(ht, e);
350                         ht->table[h] = 0;
351                         ht_add(ht, p, ht->rehash(p, ht->priv));
352                 }
353         }
354         ht->deleted = 0;
355         (void)htable_debug(ht, HTABLE_LOC);
356 }
357
358 /* We stole some bits, now we need to put them back... */
359 static COLD void update_common(struct htable *ht, const void *p)
360 {
361         uintptr_t maskdiff;
362
363         if (ht->elems == 0) {
364                 ht->common_mask = -1;
365                 ht->common_bits = ((uintptr_t)p & ht->common_mask);
366                 ht->perfect_bitnum = 0;
367                 (void)htable_debug(ht, HTABLE_LOC);
368                 return;
369         }
370
371         /* Find bits which are unequal to old common set. */
372         maskdiff = ht->common_bits ^ ((uintptr_t)p & ht->common_mask);
373
374         fixup_table_common(ht, maskdiff);
375         (void)htable_debug(ht, HTABLE_LOC);
376 }
377
378 bool htable_add_(struct htable *ht, size_t hash, const void *p)
379 {
380         /* Cannot insert NULL, or (void *)1. */
381         assert(p);
382         assert(entry_is_valid((uintptr_t)p));
383
384         /* Getting too full? */
385         if (ht->elems+1 + ht->deleted > ht_max(ht)) {
386                 /* If we're more than 1/8 deleted, clean those,
387                  * otherwise double table size. */
388                 if (ht->deleted > ht_max_deleted(ht))
389                         rehash_table(ht);
390                 else if (!double_table(ht))
391                         return false;
392         }
393         if (((uintptr_t)p & ht->common_mask) != ht->common_bits)
394                 update_common(ht, p);
395
396         ht_add(ht, p, hash);
397         ht->elems++;
398         return true;
399 }
400
401 bool htable_del_(struct htable *ht, size_t h, const void *p)
402 {
403         struct htable_iter i;
404         void *c;
405
406         for (c = htable_firstval(ht,&i,h); c; c = htable_nextval(ht,&i,h)) {
407                 if (c == p) {
408                         htable_delval(ht, &i);
409                         return true;
410                 }
411         }
412         return false;
413 }
414
415 void htable_delval_(struct htable *ht, struct htable_iter *i)
416 {
417         assert(i->off < (size_t)1 << ht->bits);
418         assert(entry_is_valid(ht->table[i->off]));
419
420         ht->elems--;
421         /* Cheap test: if the next bucket is empty, don't need delete marker */
422         if (ht->table[hash_bucket(ht, i->off+1)] != 0) {
423                 ht->table[i->off] = HTABLE_DELETED;
424                 ht->deleted++;
425         } else
426                 ht->table[i->off] = 0;
427 }
428
429 void *htable_pick_(const struct htable *ht, size_t seed, struct htable_iter *i)
430 {
431         void *e;
432         struct htable_iter unwanted;
433
434         if (!i)
435                 i = &unwanted;
436         i->off = seed % ((size_t)1 << ht->bits);
437         e = htable_next(ht, i);
438         if (!e)
439                 e = htable_first(ht, i);
440         return e;
441 }
442
443 struct htable *htable_check(const struct htable *ht, const char *abortstr)
444 {
445         void *p;
446         struct htable_iter i;
447         size_t n = 0;
448
449         /* Use non-DEBUG versions here, to avoid infinite recursion with
450          * CCAN_HTABLE_DEBUG! */
451         for (p = htable_first_(ht, &i); p; p = htable_next_(ht, &i)) {
452                 struct htable_iter i2;
453                 void *c;
454                 size_t h = ht->rehash(p, ht->priv);
455                 bool found = false;
456
457                 n++;
458
459                 /* Open-code htable_get to avoid CCAN_HTABLE_DEBUG */
460                 for (c = htable_firstval_(ht, &i2, h);
461                      c;
462                      c = htable_nextval_(ht, &i2, h)) {
463                         if (c == p) {
464                                 found = true;
465                                 break;
466                         }
467                 }
468
469                 if (!found) {
470                         if (abortstr) {
471                                 fprintf(stderr,
472                                         "%s: element %p in position %zu"
473                                         " cannot find itself\n",
474                                         abortstr, p, i.off);
475                                 abort();
476                         }
477                         return NULL;
478                 }
479         }
480         if (n != ht->elems) {
481                 if (abortstr) {
482                         fprintf(stderr,
483                                 "%s: found %zu elems, expected %zu\n",
484                                 abortstr, n, ht->elems);
485                         abort();
486                 }
487                 return NULL;
488         }
489
490         return (struct htable *)ht;
491 }