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