]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/ck/src/ck_rhs.c
Import Concurrency Kit in the kernel.
[FreeBSD/FreeBSD.git] / sys / contrib / ck / src / ck_rhs.c
1 /*
2  * Copyright 2014-2015 Olivier Houchard.
3  * Copyright 2012-2015 Samy Al Bahra.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <ck_cc.h>
29 #include <ck_rhs.h>
30 #include <ck_limits.h>
31 #include <ck_md.h>
32 #include <ck_pr.h>
33 #include <ck_stdint.h>
34 #include <ck_stdbool.h>
35 #include <ck_string.h>
36
37 #include "ck_internal.h"
38
39 #ifndef CK_RHS_PROBE_L1_SHIFT
40 #define CK_RHS_PROBE_L1_SHIFT 3ULL
41 #endif /* CK_RHS_PROBE_L1_SHIFT */
42
43 #define CK_RHS_PROBE_L1 (1 << CK_RHS_PROBE_L1_SHIFT)
44 #define CK_RHS_PROBE_L1_MASK (CK_RHS_PROBE_L1 - 1)
45
46 #ifndef CK_RHS_PROBE_L1_DEFAULT
47 #define CK_RHS_PROBE_L1_DEFAULT CK_MD_CACHELINE
48 #endif
49
50 #define CK_RHS_VMA_MASK ((uintptr_t)((1ULL << CK_MD_VMA_BITS) - 1))
51 #define CK_RHS_VMA(x)   \
52         ((void *)((uintptr_t)(x) & CK_RHS_VMA_MASK))
53
54 #define CK_RHS_EMPTY     NULL
55 #define CK_RHS_G                (1024)
56 #define CK_RHS_G_MASK   (CK_RHS_G - 1)
57
58 #if defined(CK_F_PR_LOAD_8) && defined(CK_F_PR_STORE_8)
59 #define CK_RHS_WORD          uint8_t
60 #define CK_RHS_WORD_MAX     UINT8_MAX
61 #define CK_RHS_STORE(x, y)   ck_pr_store_8(x, y)
62 #define CK_RHS_LOAD(x)       ck_pr_load_8(x)
63 #elif defined(CK_F_PR_LOAD_16) && defined(CK_F_PR_STORE_16)
64 #define CK_RHS_WORD          uint16_t
65 #define CK_RHS_WORD_MAX     UINT16_MAX
66 #define CK_RHS_STORE(x, y)   ck_pr_store_16(x, y)
67 #define CK_RHS_LOAD(x)       ck_pr_load_16(x)
68 #elif defined(CK_F_PR_LOAD_32) && defined(CK_F_PR_STORE_32)
69 #define CK_RHS_WORD          uint32_t
70 #define CK_RHS_WORD_MAX     UINT32_MAX
71 #define CK_RHS_STORE(x, y)   ck_pr_store_32(x, y)
72 #define CK_RHS_LOAD(x)       ck_pr_load_32(x)
73 #else
74 #error "ck_rhs is not supported on your platform."
75 #endif
76
77 #define CK_RHS_MAX_WANTED       0xffff
78
79 enum ck_rhs_probe_behavior {
80         CK_RHS_PROBE = 0,       /* Default behavior. */
81         CK_RHS_PROBE_RH,        /* Short-circuit if RH slot found. */
82         CK_RHS_PROBE_INSERT,    /* Short-circuit on probe bound if tombstone found. */
83
84         CK_RHS_PROBE_ROBIN_HOOD,/* Look for the first slot available for the entry we are about to replace, only used to internally implement Robin Hood */
85         CK_RHS_PROBE_NO_RH,     /* Don't do the RH dance */
86 };
87 struct ck_rhs_entry_desc {
88         unsigned int probes;
89         unsigned short wanted;
90         CK_RHS_WORD probe_bound;
91         bool in_rh;
92         const void *entry;
93 } CK_CC_ALIGN(16);
94
95 struct ck_rhs_no_entry_desc {
96         unsigned int probes;
97         unsigned short wanted;
98         CK_RHS_WORD probe_bound;
99         bool in_rh;
100 } CK_CC_ALIGN(8);
101
102 typedef long ck_rhs_probe_cb_t(struct ck_rhs *hs,
103     struct ck_rhs_map *map,
104     unsigned long *n_probes,
105     long *priority,
106     unsigned long h,
107     const void *key,
108     const void **object,
109     unsigned long probe_limit,
110     enum ck_rhs_probe_behavior behavior);
111
112 struct ck_rhs_map {
113         unsigned int generation[CK_RHS_G];
114         unsigned int probe_maximum;
115         unsigned long mask;
116         unsigned long step;
117         unsigned int probe_limit;
118         unsigned long n_entries;
119         unsigned long capacity;
120         unsigned long size;
121         unsigned long max_entries;
122         char offset_mask;
123         union {
124                 struct ck_rhs_entry_desc *descs;
125                 struct ck_rhs_no_entry {
126                         const void **entries;
127                         struct ck_rhs_no_entry_desc *descs;
128                 } no_entries;
129         } entries;
130         bool read_mostly;
131         ck_rhs_probe_cb_t *probe_func;
132 };
133
134 static CK_CC_INLINE const void *
135 ck_rhs_entry(struct ck_rhs_map *map, long offset)
136 {
137
138         if (map->read_mostly)
139                 return (map->entries.no_entries.entries[offset]);
140         else
141                 return (map->entries.descs[offset].entry);
142 }
143
144 static CK_CC_INLINE const void **
145 ck_rhs_entry_addr(struct ck_rhs_map *map, long offset)
146 {
147
148         if (map->read_mostly)
149                 return (&map->entries.no_entries.entries[offset]);
150         else
151                 return (&map->entries.descs[offset].entry);
152 }
153
154 static CK_CC_INLINE struct ck_rhs_entry_desc *
155 ck_rhs_desc(struct ck_rhs_map *map, long offset)
156 {
157
158         if (CK_CC_UNLIKELY(map->read_mostly))
159                 return ((struct ck_rhs_entry_desc *)(void *)&map->entries.no_entries.descs[offset]);
160         else
161                 return (&map->entries.descs[offset]);
162 }
163
164 static CK_CC_INLINE void
165 ck_rhs_wanted_inc(struct ck_rhs_map *map, long offset)
166 {
167
168         if (CK_CC_UNLIKELY(map->read_mostly))
169                 map->entries.no_entries.descs[offset].wanted++;
170         else
171                 map->entries.descs[offset].wanted++;
172 }
173
174 static CK_CC_INLINE unsigned int
175 ck_rhs_probes(struct ck_rhs_map *map, long offset)
176 {
177
178         if (CK_CC_UNLIKELY(map->read_mostly))
179                 return (map->entries.no_entries.descs[offset].probes);
180         else
181                 return (map->entries.descs[offset].probes);
182 }
183
184 static CK_CC_INLINE void
185 ck_rhs_set_probes(struct ck_rhs_map *map, long offset, unsigned int value)
186 {
187
188         if (CK_CC_UNLIKELY(map->read_mostly))
189                 map->entries.no_entries.descs[offset].probes = value;
190         else
191                 map->entries.descs[offset].probes = value;
192 }
193
194 static CK_CC_INLINE CK_RHS_WORD
195 ck_rhs_probe_bound(struct ck_rhs_map *map, long offset)
196 {
197
198         if (CK_CC_UNLIKELY(map->read_mostly))
199                 return (map->entries.no_entries.descs[offset].probe_bound);
200         else
201                 return (map->entries.descs[offset].probe_bound);
202 }
203
204 static CK_CC_INLINE CK_RHS_WORD *
205 ck_rhs_probe_bound_addr(struct ck_rhs_map *map, long offset)
206 {
207
208         if (CK_CC_UNLIKELY(map->read_mostly))
209                 return (&map->entries.no_entries.descs[offset].probe_bound);
210         else
211                 return (&map->entries.descs[offset].probe_bound);
212 }
213
214
215 static CK_CC_INLINE bool
216 ck_rhs_in_rh(struct ck_rhs_map *map, long offset)
217 {
218
219         if (CK_CC_UNLIKELY(map->read_mostly))
220                 return (map->entries.no_entries.descs[offset].in_rh);
221         else
222                 return (map->entries.descs[offset].in_rh);
223 }
224
225 static CK_CC_INLINE void
226 ck_rhs_set_rh(struct ck_rhs_map *map, long offset)
227 {
228
229         if (CK_CC_UNLIKELY(map->read_mostly))
230                 map->entries.no_entries.descs[offset].in_rh = true;
231         else
232                 map->entries.descs[offset].in_rh = true;
233 }
234
235 static CK_CC_INLINE void
236 ck_rhs_unset_rh(struct ck_rhs_map *map, long offset)
237 {
238
239         if (CK_CC_UNLIKELY(map->read_mostly))
240                 map->entries.no_entries.descs[offset].in_rh = false;
241         else
242                 map->entries.descs[offset].in_rh = false;
243 }
244
245
246 #define CK_RHS_DEFAULT_LOAD_FACTOR      50
247
248 static ck_rhs_probe_cb_t ck_rhs_map_probe;
249 static ck_rhs_probe_cb_t ck_rhs_map_probe_rm;
250
251 bool
252 ck_rhs_set_load_factor(struct ck_rhs *hs, unsigned int load_factor)
253 {
254         struct ck_rhs_map *map = hs->map;
255
256         if (load_factor == 0 || load_factor > 100)
257                 return false;
258
259         hs->load_factor = load_factor;
260         map->max_entries = (map->capacity * (unsigned long)hs->load_factor) / 100;
261         while (map->n_entries > map->max_entries) {
262                 if (ck_rhs_grow(hs, map->capacity << 1) == false)
263                         return false;
264                 map = hs->map;
265         }
266         return true;
267 }
268
269 void
270 ck_rhs_iterator_init(struct ck_rhs_iterator *iterator)
271 {
272
273         iterator->cursor = NULL;
274         iterator->offset = 0;
275         return;
276 }
277
278 bool
279 ck_rhs_next(struct ck_rhs *hs, struct ck_rhs_iterator *i, void **key)
280 {
281         struct ck_rhs_map *map = hs->map;
282         void *value;
283
284         if (i->offset >= map->capacity)
285                 return false;
286
287         do {
288                 value = CK_CC_DECONST_PTR(ck_rhs_entry(map, i->offset));
289                 if (value != CK_RHS_EMPTY) {
290 #ifdef CK_RHS_PP
291                         if (hs->mode & CK_RHS_MODE_OBJECT)
292                                 value = CK_RHS_VMA(value);
293 #endif
294                         i->offset++;
295                         *key = value;
296                         return true;
297                 }
298         } while (++i->offset < map->capacity);
299
300         return false;
301 }
302
303 void
304 ck_rhs_stat(struct ck_rhs *hs, struct ck_rhs_stat *st)
305 {
306         struct ck_rhs_map *map = hs->map;
307
308         st->n_entries = map->n_entries;
309         st->probe_maximum = map->probe_maximum;
310         return;
311 }
312
313 unsigned long
314 ck_rhs_count(struct ck_rhs *hs)
315 {
316
317         return hs->map->n_entries;
318 }
319
320 static void
321 ck_rhs_map_destroy(struct ck_malloc *m, struct ck_rhs_map *map, bool defer)
322 {
323
324         m->free(map, map->size, defer);
325         return;
326 }
327
328 void
329 ck_rhs_destroy(struct ck_rhs *hs)
330 {
331
332         ck_rhs_map_destroy(hs->m, hs->map, false);
333         return;
334 }
335
336 static struct ck_rhs_map *
337 ck_rhs_map_create(struct ck_rhs *hs, unsigned long entries)
338 {
339         struct ck_rhs_map *map;
340         unsigned long size, n_entries, limit;
341
342         n_entries = ck_internal_power_2(entries);
343         if (n_entries < CK_RHS_PROBE_L1)
344                 n_entries = CK_RHS_PROBE_L1;
345
346         if (hs->mode & CK_RHS_MODE_READ_MOSTLY)
347                 size = sizeof(struct ck_rhs_map) +
348                     (sizeof(void *) * n_entries +
349                      sizeof(struct ck_rhs_no_entry_desc) * n_entries +
350                      2 * CK_MD_CACHELINE - 1);
351         else
352                 size = sizeof(struct ck_rhs_map) +
353                     (sizeof(struct ck_rhs_entry_desc) * n_entries +
354                      CK_MD_CACHELINE - 1);
355         map = hs->m->malloc(size);
356         if (map == NULL)
357                 return NULL;
358         map->read_mostly = !!(hs->mode & CK_RHS_MODE_READ_MOSTLY);
359
360         map->size = size;
361         /* We should probably use a more intelligent heuristic for default probe length. */
362         limit = ck_internal_max(n_entries >> (CK_RHS_PROBE_L1_SHIFT + 2), CK_RHS_PROBE_L1_DEFAULT);
363         if (limit > UINT_MAX)
364                 limit = UINT_MAX;
365
366         map->probe_limit = (unsigned int)limit;
367         map->probe_maximum = 0;
368         map->capacity = n_entries;
369         map->step = ck_internal_bsf(n_entries);
370         map->mask = n_entries - 1;
371         map->n_entries = 0;
372
373         map->max_entries = (map->capacity * (unsigned long)hs->load_factor) / 100;
374         /* Align map allocation to cache line. */
375         if (map->read_mostly) {
376                 map->entries.no_entries.entries = (void *)(((uintptr_t)&map[1] +
377                     CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1));
378                 map->entries.no_entries.descs = (void *)(((uintptr_t)map->entries.no_entries.entries + (sizeof(void *) * n_entries) + CK_MD_CACHELINE - 1) &~ (CK_MD_CACHELINE - 1));
379                 memset(map->entries.no_entries.entries, 0,
380                     sizeof(void *) * n_entries);
381                 memset(map->entries.no_entries.descs, 0,
382                     sizeof(struct ck_rhs_no_entry_desc) * n_entries);
383                 map->offset_mask = (CK_MD_CACHELINE / sizeof(void *)) - 1;
384                 map->probe_func = ck_rhs_map_probe_rm;
385
386         } else {
387                 map->entries.descs = (void *)(((uintptr_t)&map[1] +
388                     CK_MD_CACHELINE - 1) & ~(CK_MD_CACHELINE - 1));
389                 memset(map->entries.descs, 0, sizeof(struct ck_rhs_entry_desc) * n_entries);
390                 map->offset_mask = (CK_MD_CACHELINE / sizeof(struct ck_rhs_entry_desc)) - 1;
391                 map->probe_func = ck_rhs_map_probe;
392         }
393         memset(map->generation, 0, sizeof map->generation);
394
395         /* Commit entries purge with respect to map publication. */
396         ck_pr_fence_store();
397         return map;
398 }
399
400 bool
401 ck_rhs_reset_size(struct ck_rhs *hs, unsigned long capacity)
402 {
403         struct ck_rhs_map *map, *previous;
404
405         previous = hs->map;
406         map = ck_rhs_map_create(hs, capacity);
407         if (map == NULL)
408                 return false;
409
410         ck_pr_store_ptr(&hs->map, map);
411         ck_rhs_map_destroy(hs->m, previous, true);
412         return true;
413 }
414
415 bool
416 ck_rhs_reset(struct ck_rhs *hs)
417 {
418         struct ck_rhs_map *previous;
419
420         previous = hs->map;
421         return ck_rhs_reset_size(hs, previous->capacity);
422 }
423
424 static inline unsigned long
425 ck_rhs_map_probe_next(struct ck_rhs_map *map,
426     unsigned long offset,
427     unsigned long probes)
428 {
429
430         if (probes & map->offset_mask) {
431                 offset = (offset &~ map->offset_mask) +
432                     ((offset + 1) & map->offset_mask);
433                 return offset;
434         } else
435                 return (offset + probes) & map->mask;
436 }
437
438 static inline unsigned long
439 ck_rhs_map_probe_prev(struct ck_rhs_map *map, unsigned long offset,
440     unsigned long probes)
441 {
442
443         if (probes & map->offset_mask) {
444                 offset = (offset &~ map->offset_mask) + ((offset - 1) &
445                     map->offset_mask);
446                 return offset;
447         } else
448                 return ((offset - probes) & map->mask);
449 }
450
451
452 static inline void
453 ck_rhs_map_bound_set(struct ck_rhs_map *m,
454     unsigned long h,
455     unsigned long n_probes)
456 {
457         unsigned long offset = h & m->mask;
458         struct ck_rhs_entry_desc *desc;
459
460         if (n_probes > m->probe_maximum)
461                 ck_pr_store_uint(&m->probe_maximum, n_probes);
462         if (!(m->read_mostly)) {
463                 desc = &m->entries.descs[offset];
464
465                 if (desc->probe_bound < n_probes) {
466                         if (n_probes > CK_RHS_WORD_MAX)
467                                 n_probes = CK_RHS_WORD_MAX;
468
469                         CK_RHS_STORE(&desc->probe_bound, n_probes);
470                         ck_pr_fence_store();
471                 }
472         }
473
474         return;
475 }
476
477 static inline unsigned int
478 ck_rhs_map_bound_get(struct ck_rhs_map *m, unsigned long h)
479 {
480         unsigned long offset = h & m->mask;
481         unsigned int r = CK_RHS_WORD_MAX;
482
483         if (m->read_mostly)
484                 r = ck_pr_load_uint(&m->probe_maximum);
485         else {
486                 r = CK_RHS_LOAD(&m->entries.descs[offset].probe_bound);
487                 if (r == CK_RHS_WORD_MAX)
488                         r = ck_pr_load_uint(&m->probe_maximum);
489         }
490         return r;
491 }
492
493 bool
494 ck_rhs_grow(struct ck_rhs *hs,
495     unsigned long capacity)
496 {
497         struct ck_rhs_map *map, *update;
498         const void *previous, *prev_saved;
499         unsigned long k, offset, probes;
500
501 restart:
502         map = hs->map;
503         if (map->capacity > capacity)
504                 return false;
505
506         update = ck_rhs_map_create(hs, capacity);
507         if (update == NULL)
508                 return false;
509
510         for (k = 0; k < map->capacity; k++) {
511                 unsigned long h;
512
513                 prev_saved = previous = ck_rhs_entry(map, k);
514                 if (previous == CK_RHS_EMPTY)
515                         continue;
516
517 #ifdef CK_RHS_PP
518                 if (hs->mode & CK_RHS_MODE_OBJECT)
519                         previous = CK_RHS_VMA(previous);
520 #endif
521
522                 h = hs->hf(previous, hs->seed);
523                 offset = h & update->mask;
524                 probes = 0;
525
526                 for (;;) {
527                         const void **cursor = ck_rhs_entry_addr(update, offset);
528
529                         if (probes++ == update->probe_limit) {
530                                 /*
531                                  * We have hit the probe limit, map needs to be even larger.
532                                  */
533                                 ck_rhs_map_destroy(hs->m, update, false);
534                                 capacity <<= 1;
535                                 goto restart;
536                         }
537
538                         if (CK_CC_LIKELY(*cursor == CK_RHS_EMPTY)) {
539                                 *cursor = prev_saved;
540                                 update->n_entries++;
541                                 ck_rhs_set_probes(update, offset, probes);
542                                 ck_rhs_map_bound_set(update, h, probes);
543                                 break;
544                         } else if (ck_rhs_probes(update, offset) < probes) {
545                                 const void *tmp = prev_saved;
546                                 unsigned int old_probes;
547                                 prev_saved = previous = *cursor;
548 #ifdef CK_RHS_PP
549                                 if (hs->mode & CK_RHS_MODE_OBJECT)
550                                         previous = CK_RHS_VMA(previous);
551 #endif
552                                 *cursor = tmp;
553                                 ck_rhs_map_bound_set(update, h, probes);
554                                 h = hs->hf(previous, hs->seed);
555                                 old_probes = ck_rhs_probes(update, offset);
556                                 ck_rhs_set_probes(update, offset, probes);
557                                 probes = old_probes - 1;
558                                 continue;
559                         }
560                         ck_rhs_wanted_inc(update, offset);
561                         offset = ck_rhs_map_probe_next(update, offset,  probes);
562                 }
563
564         }
565
566         ck_pr_fence_store();
567         ck_pr_store_ptr(&hs->map, update);
568         ck_rhs_map_destroy(hs->m, map, true);
569         return true;
570 }
571
572 bool
573 ck_rhs_rebuild(struct ck_rhs *hs)
574 {
575
576         return ck_rhs_grow(hs, hs->map->capacity);
577 }
578
579 static long
580 ck_rhs_map_probe_rm(struct ck_rhs *hs,
581     struct ck_rhs_map *map,
582     unsigned long *n_probes,
583     long *priority,
584     unsigned long h,
585     const void *key,
586     const void **object,
587     unsigned long probe_limit,
588     enum ck_rhs_probe_behavior behavior)
589 {
590         const void *k;
591         const void *compare;
592         long pr = -1;
593         unsigned long offset, probes, opl;
594
595 #ifdef CK_RHS_PP
596         /* If we are storing object pointers, then we may leverage pointer packing. */
597         unsigned long hv = 0;
598
599         if (hs->mode & CK_RHS_MODE_OBJECT) {
600                 hv = (h >> 25) & CK_RHS_KEY_MASK;
601                 compare = CK_RHS_VMA(key);
602         } else {
603                 compare = key;
604         }
605 #else
606         compare = key;
607 #endif
608         *object = NULL;
609         if (behavior != CK_RHS_PROBE_ROBIN_HOOD) {
610                 probes = 0;
611                 offset = h & map->mask;
612         } else {
613                 /* Restart from the bucket we were previously in */
614                 probes = *n_probes;
615                 offset = ck_rhs_map_probe_next(map, *priority,
616                     probes);
617         }
618         opl = probe_limit;
619
620         for (;;) {
621                 if (probes++ == probe_limit) {
622                         if (probe_limit == opl || pr != -1) {
623                                 k = CK_RHS_EMPTY;
624                                 goto leave;
625                         }
626                         /*
627                          * If no eligible slot has been found yet, continue probe
628                          * sequence with original probe limit.
629                          */
630                         probe_limit = opl;
631                 }
632                 k = ck_pr_load_ptr(&map->entries.no_entries.entries[offset]);
633                 if (k == CK_RHS_EMPTY)
634                         goto leave;
635
636                 if (behavior != CK_RHS_PROBE_NO_RH) {
637                         struct ck_rhs_entry_desc *desc = (void *)&map->entries.no_entries.descs[offset];
638
639                         if (pr == -1 &&
640                             desc->in_rh == false && desc->probes < probes) {
641                                 pr = offset;
642                                 *n_probes = probes;
643
644                                 if (behavior == CK_RHS_PROBE_RH ||
645                                     behavior == CK_RHS_PROBE_ROBIN_HOOD) {
646                                         k = CK_RHS_EMPTY;
647                                         goto leave;
648                                 }
649                         }
650                 }
651
652                 if (behavior != CK_RHS_PROBE_ROBIN_HOOD) {
653 #ifdef CK_RHS_PP
654                         if (hs->mode & CK_RHS_MODE_OBJECT) {
655                                 if (((uintptr_t)k >> CK_MD_VMA_BITS) != hv) {
656                                         offset = ck_rhs_map_probe_next(map, offset, probes);
657                                         continue;
658                                 }
659
660                                 k = CK_RHS_VMA(k);
661                         }
662 #endif
663
664                         if (k == compare)
665                                 goto leave;
666
667                         if (hs->compare == NULL) {
668                                 offset = ck_rhs_map_probe_next(map, offset, probes);
669                                 continue;
670                         }
671
672                         if (hs->compare(k, key) == true)
673                                 goto leave;
674                 }
675                 offset = ck_rhs_map_probe_next(map, offset, probes);
676         }
677 leave:
678         if (probes > probe_limit) {
679                 offset = -1;
680         } else {
681                 *object = k;
682         }
683
684         if (pr == -1)
685                 *n_probes = probes;
686
687         *priority = pr;
688         return offset;
689 }
690
691 static long
692 ck_rhs_map_probe(struct ck_rhs *hs,
693     struct ck_rhs_map *map,
694     unsigned long *n_probes,
695     long *priority,
696     unsigned long h,
697     const void *key,
698     const void **object,
699     unsigned long probe_limit,
700     enum ck_rhs_probe_behavior behavior)
701 {
702         const void *k;
703         const void *compare;
704         long pr = -1;
705         unsigned long offset, probes, opl;
706
707 #ifdef CK_RHS_PP
708         /* If we are storing object pointers, then we may leverage pointer packing. */
709         unsigned long hv = 0;
710
711         if (hs->mode & CK_RHS_MODE_OBJECT) {
712                 hv = (h >> 25) & CK_RHS_KEY_MASK;
713                 compare = CK_RHS_VMA(key);
714         } else {
715                 compare = key;
716         }
717 #else
718         compare = key;
719 #endif
720
721         *object = NULL;
722         if (behavior != CK_RHS_PROBE_ROBIN_HOOD) {
723                 probes = 0;
724                 offset = h & map->mask;
725         } else {
726                 /* Restart from the bucket we were previously in */
727                 probes = *n_probes;
728                 offset = ck_rhs_map_probe_next(map, *priority,
729                     probes);
730         }
731         opl = probe_limit;
732         if (behavior == CK_RHS_PROBE_INSERT)
733                 probe_limit = ck_rhs_map_bound_get(map, h);
734
735         for (;;) {
736                 if (probes++ == probe_limit) {
737                         if (probe_limit == opl || pr != -1) {
738                                 k = CK_RHS_EMPTY;
739                                 goto leave;
740                         }
741                         /*
742                          * If no eligible slot has been found yet, continue probe
743                          * sequence with original probe limit.
744                          */
745                         probe_limit = opl;
746                 }
747                 k = ck_pr_load_ptr(&map->entries.descs[offset].entry);
748                 if (k == CK_RHS_EMPTY)
749                         goto leave;
750                 if ((behavior != CK_RHS_PROBE_NO_RH)) {
751                         struct ck_rhs_entry_desc *desc = &map->entries.descs[offset];
752
753                         if (pr == -1 &&
754                             desc->in_rh == false && desc->probes < probes) {
755                                 pr = offset;
756                                 *n_probes = probes;
757
758                                 if (behavior == CK_RHS_PROBE_RH ||
759                                     behavior == CK_RHS_PROBE_ROBIN_HOOD) {
760                                         k = CK_RHS_EMPTY;
761                                         goto leave;
762                                 }
763                         }
764                 }
765
766                 if (behavior != CK_RHS_PROBE_ROBIN_HOOD) {
767 #ifdef CK_RHS_PP
768                         if (hs->mode & CK_RHS_MODE_OBJECT) {
769                                 if (((uintptr_t)k >> CK_MD_VMA_BITS) != hv) {
770                                         offset = ck_rhs_map_probe_next(map, offset, probes);
771                                         continue;
772                                 }
773
774                                 k = CK_RHS_VMA(k);
775                         }
776 #endif
777
778                         if (k == compare)
779                                 goto leave;
780
781                         if (hs->compare == NULL) {
782                                 offset = ck_rhs_map_probe_next(map, offset, probes);
783                                 continue;
784                         }
785
786                         if (hs->compare(k, key) == true)
787                                 goto leave;
788                 }
789                 offset = ck_rhs_map_probe_next(map, offset, probes);
790         }
791 leave:
792         if (probes > probe_limit) {
793                 offset = -1;
794         } else {
795                 *object = k;
796         }
797
798         if (pr == -1)
799                 *n_probes = probes;
800
801         *priority = pr;
802         return offset;
803 }
804
805 static inline const void *
806 ck_rhs_marshal(unsigned int mode, const void *key, unsigned long h)
807 {
808 #ifdef CK_RHS_PP
809         const void *insert;
810
811         if (mode & CK_RHS_MODE_OBJECT) {
812                 insert = (void *)((uintptr_t)CK_RHS_VMA(key) | ((h >> 25) << CK_MD_VMA_BITS));
813         } else {
814                 insert = key;
815         }
816
817         return insert;
818 #else
819         (void)mode;
820         (void)h;
821
822         return key;
823 #endif
824 }
825
826 bool
827 ck_rhs_gc(struct ck_rhs *hs)
828 {
829         unsigned long i;
830         struct ck_rhs_map *map = hs->map;
831
832         unsigned int max_probes = 0;
833         for (i = 0; i < map->capacity; i++) {
834                 if (ck_rhs_probes(map, i) > max_probes)
835                         max_probes = ck_rhs_probes(map, i);
836         }
837         map->probe_maximum = max_probes;
838         return true;
839 }
840
841 static void
842 ck_rhs_add_wanted(struct ck_rhs *hs, long end_offset, long old_slot,
843         unsigned long h)
844 {
845         struct ck_rhs_map *map = hs->map;
846         long offset;
847         unsigned int probes = 1;
848         bool found_slot = false;
849         struct ck_rhs_entry_desc *desc;
850
851         offset = h & map->mask;
852
853         if (old_slot == -1)
854                 found_slot = true;
855         while (offset != end_offset) {
856                 if (offset == old_slot)
857                         found_slot = true;
858                 if (found_slot) {
859                         desc = ck_rhs_desc(map, offset);
860                         if (desc->wanted < CK_RHS_MAX_WANTED)
861                                 desc->wanted++;
862                 }
863                 offset = ck_rhs_map_probe_next(map, offset, probes);
864                 probes++;
865         }
866 }
867
868 static unsigned long
869 ck_rhs_remove_wanted(struct ck_rhs *hs, long offset, long limit)
870 {
871         struct ck_rhs_map *map = hs->map;
872         int probes = ck_rhs_probes(map, offset);
873         bool do_remove = true;
874         struct ck_rhs_entry_desc *desc;
875
876         while (probes > 1) {
877                 probes--;
878                 offset = ck_rhs_map_probe_prev(map, offset, probes);
879                 if (offset == limit)
880                         do_remove = false;
881                 if (do_remove) {
882                         desc = ck_rhs_desc(map, offset);
883                         if (desc->wanted != CK_RHS_MAX_WANTED)
884                                 desc->wanted--;
885                 }
886         }
887         return offset;
888 }
889
890 static long
891 ck_rhs_get_first_offset(struct ck_rhs_map *map, unsigned long offset, unsigned int probes)
892 {
893         while (probes > (unsigned long)map->offset_mask + 1) {
894                 offset -= ((probes - 1) &~ map->offset_mask);
895                 offset &= map->mask;
896                 offset = (offset &~ map->offset_mask) +
897                     ((offset - map->offset_mask) & map->offset_mask);
898                 probes -= map->offset_mask + 1;
899         }
900         return ((offset &~ map->offset_mask) + ((offset - (probes - 1)) & map->offset_mask));
901 }
902
903 #define CK_RHS_MAX_RH   512
904
905 static int
906 ck_rhs_put_robin_hood(struct ck_rhs *hs,
907     long orig_slot, struct ck_rhs_entry_desc *desc)
908 {
909         long slot, first;
910         const void *object, *insert;
911         unsigned long n_probes;
912         struct ck_rhs_map *map;
913         unsigned long h = 0;
914         long prev;
915         void *key;
916         long prevs[CK_RHS_MAX_RH];
917         unsigned int prevs_nb = 0;
918         unsigned int i;
919
920         map = hs->map;
921         first = orig_slot;
922         n_probes = desc->probes;
923 restart:
924         key = CK_CC_DECONST_PTR(ck_rhs_entry(map, first));
925         insert = key;
926 #ifdef CK_RHS_PP
927         if (hs->mode & CK_RHS_MODE_OBJECT)
928             key = CK_RHS_VMA(key);
929 #endif
930         orig_slot = first;
931         ck_rhs_set_rh(map, orig_slot);
932
933         slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object,
934             map->probe_limit, prevs_nb == CK_RHS_MAX_RH ?
935             CK_RHS_PROBE_NO_RH : CK_RHS_PROBE_ROBIN_HOOD);
936
937         if (slot == -1 && first == -1) {
938                 if (ck_rhs_grow(hs, map->capacity << 1) == false) {
939                         desc->in_rh = false;
940
941                         for (i = 0; i < prevs_nb; i++)
942                                 ck_rhs_unset_rh(map, prevs[i]);
943
944                         return -1;
945                 }
946
947                 return 1;
948         }
949
950         if (first != -1) {
951                 desc = ck_rhs_desc(map, first);
952                 int old_probes = desc->probes;
953
954                 desc->probes = n_probes;
955                 h = ck_rhs_get_first_offset(map, first, n_probes);
956                 ck_rhs_map_bound_set(map, h, n_probes);
957                 prev = orig_slot;
958                 prevs[prevs_nb++] = prev;
959                 n_probes = old_probes;
960                 goto restart;
961         } else {
962                 /* An empty slot was found. */
963                 h =  ck_rhs_get_first_offset(map, slot, n_probes);
964                 ck_rhs_map_bound_set(map, h, n_probes);
965                 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert);
966                 ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]);
967                 ck_pr_fence_atomic_store();
968                 ck_rhs_set_probes(map, slot, n_probes);
969                 desc->in_rh = 0;
970                 ck_rhs_add_wanted(hs, slot, orig_slot, h);
971         }
972         while (prevs_nb > 0) {
973                 prev = prevs[--prevs_nb];
974                 ck_pr_store_ptr(ck_rhs_entry_addr(map, orig_slot),
975                     ck_rhs_entry(map, prev));
976                 h = ck_rhs_get_first_offset(map, orig_slot,
977                     desc->probes);
978                 ck_rhs_add_wanted(hs, orig_slot, prev, h);
979                 ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]);
980                 ck_pr_fence_atomic_store();
981                 orig_slot = prev;
982                 desc->in_rh = false;
983                 desc = ck_rhs_desc(map, orig_slot);
984         }
985         return 0;
986 }
987
988 static void
989 ck_rhs_do_backward_shift_delete(struct ck_rhs *hs, long slot)
990 {
991         struct ck_rhs_map *map = hs->map;
992         struct ck_rhs_entry_desc *desc, *new_desc = NULL;
993         unsigned long h;
994
995         desc = ck_rhs_desc(map, slot);
996         h = ck_rhs_remove_wanted(hs, slot, -1);
997         while (desc->wanted > 0) {
998                 unsigned long offset = 0, tmp_offset;
999                 unsigned long wanted_probes = 1;
1000                 unsigned int probe = 0;
1001                 unsigned int max_probes;
1002
1003                 /* Find a successor */
1004                 while (wanted_probes < map->probe_maximum) {
1005                         probe = wanted_probes;
1006                         offset = ck_rhs_map_probe_next(map, slot, probe);
1007                         while (probe < map->probe_maximum) {
1008                                 new_desc = ck_rhs_desc(map, offset);
1009                                 if (new_desc->probes == probe + 1)
1010                                         break;
1011                                 probe++;
1012                                 offset = ck_rhs_map_probe_next(map, offset,
1013                                     probe);
1014                         }
1015                         if (probe < map->probe_maximum)
1016                                 break;
1017                         wanted_probes++;
1018                 }
1019                 if (!(wanted_probes < map->probe_maximum)) {
1020                         desc->wanted = 0;
1021                         break;
1022                 }
1023                 desc->probes = wanted_probes;
1024                 h = ck_rhs_remove_wanted(hs, offset, slot);
1025                 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot),
1026                     ck_rhs_entry(map, offset));
1027                 ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]);
1028                 ck_pr_fence_atomic_store();
1029                 if (wanted_probes < CK_RHS_WORD_MAX) {
1030                         struct ck_rhs_entry_desc *hdesc = ck_rhs_desc(map, h);
1031                         if (hdesc->wanted == 1)
1032                                 CK_RHS_STORE(&hdesc->probe_bound,
1033                                     wanted_probes);
1034                         else if (hdesc->probe_bound == CK_RHS_WORD_MAX ||
1035                             hdesc->probe_bound == new_desc->probes) {
1036                                 probe++;
1037                                 if (hdesc->probe_bound == CK_RHS_WORD_MAX)
1038                                         max_probes = map->probe_maximum;
1039                                 else {
1040                                         max_probes = hdesc->probe_bound;
1041                                         max_probes--;
1042                                 }
1043                                 tmp_offset = ck_rhs_map_probe_next(map, offset,
1044                                     probe);
1045                                 while (probe < max_probes) {
1046                                         if (h == (unsigned long)ck_rhs_get_first_offset(map, tmp_offset, probe))
1047                                                 break;
1048                                         probe++;
1049                                         tmp_offset = ck_rhs_map_probe_next(map, tmp_offset, probe);
1050                                 }
1051                                 if (probe == max_probes)
1052                                         CK_RHS_STORE(&hdesc->probe_bound,
1053                                             wanted_probes);
1054                         }
1055                 }
1056                 if (desc->wanted < CK_RHS_MAX_WANTED)
1057                         desc->wanted--;
1058                 slot = offset;
1059                 desc = new_desc;
1060         }
1061         ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), CK_RHS_EMPTY);
1062         if ((desc->probes - 1) < CK_RHS_WORD_MAX)
1063                 CK_RHS_STORE(ck_rhs_probe_bound_addr(map, h),
1064                     desc->probes - 1);
1065         desc->probes = 0;
1066 }
1067
1068 bool
1069 ck_rhs_fas(struct ck_rhs *hs,
1070     unsigned long h,
1071     const void *key,
1072     void **previous)
1073 {
1074         long slot, first;
1075         const void *object;
1076         const void *insert;
1077         unsigned long n_probes;
1078         struct ck_rhs_map *map = hs->map;
1079         struct ck_rhs_entry_desc *desc, *desc2;
1080
1081         *previous = NULL;
1082 restart:
1083         slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object,
1084             ck_rhs_map_bound_get(map, h), CK_RHS_PROBE);
1085
1086         /* Replacement semantics presume existence. */
1087         if (object == NULL)
1088                 return false;
1089
1090         insert = ck_rhs_marshal(hs->mode, key, h);
1091
1092         if (first != -1) {
1093                 int ret;
1094
1095                 desc = ck_rhs_desc(map, slot);
1096                 desc2 = ck_rhs_desc(map, first);
1097                 desc->in_rh = true;
1098                 ret = ck_rhs_put_robin_hood(hs, first, desc2);
1099                 desc->in_rh = false;
1100                 if (CK_CC_UNLIKELY(ret == 1))
1101                         goto restart;
1102                 else if (CK_CC_UNLIKELY(ret != 0))
1103                         return false;
1104                 ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert);
1105                 ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]);
1106                 ck_pr_fence_atomic_store();
1107                 desc2->probes = n_probes;
1108                 ck_rhs_add_wanted(hs, first, -1, h);
1109                 ck_rhs_do_backward_shift_delete(hs, slot);
1110         } else {
1111                 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert);
1112                 ck_rhs_set_probes(map, slot, n_probes);
1113         }
1114         *previous = CK_CC_DECONST_PTR(object);
1115         return true;
1116 }
1117
1118 /*
1119  * An apply function takes two arguments. The first argument is a pointer to a
1120  * pre-existing object. The second argument is a pointer to the fifth argument
1121  * passed to ck_hs_apply. If a non-NULL pointer is passed to the first argument
1122  * and the return value of the apply function is NULL, then the pre-existing
1123  * value is deleted. If the return pointer is the same as the one passed to the
1124  * apply function then no changes are made to the hash table.  If the first
1125  * argument is non-NULL and the return pointer is different than that passed to
1126  * the apply function, then the pre-existing value is replaced. For
1127  * replacement, it is required that the value itself is identical to the
1128  * previous value.
1129  */
1130 bool
1131 ck_rhs_apply(struct ck_rhs *hs,
1132     unsigned long h,
1133     const void *key,
1134     ck_rhs_apply_fn_t *fn,
1135     void *cl)
1136 {
1137         const void *insert;
1138         const void  *object, *delta = false;
1139         unsigned long n_probes;
1140         long slot, first;
1141         struct ck_rhs_map *map;
1142         bool delta_set = false;
1143
1144 restart:
1145         map = hs->map;
1146
1147         slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_RHS_PROBE_INSERT);
1148         if (slot == -1 && first == -1) {
1149                 if (ck_rhs_grow(hs, map->capacity << 1) == false)
1150                         return false;
1151
1152                 goto restart;
1153         }
1154         if (!delta_set) {
1155                 delta = fn(CK_CC_DECONST_PTR(object), cl);
1156                 delta_set = true;
1157         }
1158
1159         if (delta == NULL) {
1160                 /*
1161                  * The apply function has requested deletion. If the object doesn't exist,
1162                  * then exit early.
1163                  */
1164                 if (CK_CC_UNLIKELY(object == NULL))
1165                         return true;
1166
1167                 /* Otherwise, delete it. */
1168                 ck_rhs_do_backward_shift_delete(hs, slot);
1169                 return true;
1170         }
1171
1172         /* The apply function has not requested hash set modification so exit early. */
1173         if (delta == object)
1174                 return true;
1175
1176         /* A modification or insertion has been requested. */
1177         ck_rhs_map_bound_set(map, h, n_probes);
1178
1179         insert = ck_rhs_marshal(hs->mode, delta, h);
1180         if (first != -1) {
1181                 /*
1182                  * This follows the same semantics as ck_hs_set, please refer to that
1183                  * function for documentation.
1184                  */
1185                 struct ck_rhs_entry_desc *desc = NULL, *desc2;
1186                 if (slot != -1) {
1187                         desc = ck_rhs_desc(map, slot);
1188                         desc->in_rh = true;
1189                 }
1190                 desc2 = ck_rhs_desc(map, first);
1191                 int ret = ck_rhs_put_robin_hood(hs, first, desc2);
1192                 if (slot != -1)
1193                         desc->in_rh = false;
1194
1195                 if (CK_CC_UNLIKELY(ret == 1))
1196                         goto restart;
1197                 if (CK_CC_UNLIKELY(ret == -1))
1198                         return false;
1199                 /* If an earlier bucket was found, then store entry there. */
1200                 ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert);
1201                 desc2->probes = n_probes;
1202                 /*
1203                  * If a duplicate key was found, then delete it after
1204                  * signaling concurrent probes to restart. Optionally,
1205                  * it is possible to install tombstone after grace
1206                  * period if we can guarantee earlier position of
1207                  * duplicate key.
1208                  */
1209                 ck_rhs_add_wanted(hs, first, -1, h);
1210                 if (object != NULL) {
1211                         ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]);
1212                         ck_pr_fence_atomic_store();
1213                         ck_rhs_do_backward_shift_delete(hs, slot);
1214                 }
1215         } else {
1216                 /*
1217                  * If we are storing into same slot, then atomic store is sufficient
1218                  * for replacement.
1219                  */
1220                 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert);
1221                 ck_rhs_set_probes(map, slot, n_probes);
1222                 if (object == NULL)
1223                         ck_rhs_add_wanted(hs, slot, -1, h);
1224         }
1225
1226         if (object == NULL) {
1227                 map->n_entries++;
1228                 if ((map->n_entries ) > map->max_entries)
1229                         ck_rhs_grow(hs, map->capacity << 1);
1230         }
1231         return true;
1232 }
1233
1234 bool
1235 ck_rhs_set(struct ck_rhs *hs,
1236     unsigned long h,
1237     const void *key,
1238     void **previous)
1239 {
1240         long slot, first;
1241         const void *object;
1242         const void *insert;
1243         unsigned long n_probes;
1244         struct ck_rhs_map *map;
1245
1246         *previous = NULL;
1247
1248 restart:
1249         map = hs->map;
1250
1251         slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object, map->probe_limit, CK_RHS_PROBE_INSERT);
1252         if (slot == -1 && first == -1) {
1253                 if (ck_rhs_grow(hs, map->capacity << 1) == false)
1254                         return false;
1255
1256                 goto restart;
1257         }
1258         ck_rhs_map_bound_set(map, h, n_probes);
1259         insert = ck_rhs_marshal(hs->mode, key, h);
1260
1261         if (first != -1) {
1262                 struct ck_rhs_entry_desc *desc = NULL, *desc2;
1263                 if (slot != -1) {
1264                         desc = ck_rhs_desc(map, slot);
1265                         desc->in_rh = true;
1266                 }
1267                 desc2 = ck_rhs_desc(map, first);
1268                 int ret = ck_rhs_put_robin_hood(hs, first, desc2);
1269                 if (slot != -1)
1270                         desc->in_rh = false;
1271
1272                 if (CK_CC_UNLIKELY(ret == 1))
1273                         goto restart;
1274                 if (CK_CC_UNLIKELY(ret == -1))
1275                         return false;
1276                 /* If an earlier bucket was found, then store entry there. */
1277                 ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert);
1278                 desc2->probes = n_probes;
1279                 /*
1280                  * If a duplicate key was found, then delete it after
1281                  * signaling concurrent probes to restart. Optionally,
1282                  * it is possible to install tombstone after grace
1283                  * period if we can guarantee earlier position of
1284                  * duplicate key.
1285                  */
1286                 ck_rhs_add_wanted(hs, first, -1, h);
1287                 if (object != NULL) {
1288                         ck_pr_inc_uint(&map->generation[h & CK_RHS_G_MASK]);
1289                         ck_pr_fence_atomic_store();
1290                         ck_rhs_do_backward_shift_delete(hs, slot);
1291                 }
1292
1293         } else {
1294                 /*
1295                  * If we are storing into same slot, then atomic store is sufficient
1296                  * for replacement.
1297                  */
1298                 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert);
1299                 ck_rhs_set_probes(map, slot, n_probes);
1300                 if (object == NULL)
1301                         ck_rhs_add_wanted(hs, slot, -1, h);
1302         }
1303
1304         if (object == NULL) {
1305                 map->n_entries++;
1306                 if ((map->n_entries ) > map->max_entries)
1307                         ck_rhs_grow(hs, map->capacity << 1);
1308         }
1309
1310         *previous = CK_CC_DECONST_PTR(object);
1311         return true;
1312 }
1313
1314 static bool
1315 ck_rhs_put_internal(struct ck_rhs *hs,
1316     unsigned long h,
1317     const void *key,
1318     enum ck_rhs_probe_behavior behavior)
1319 {
1320         long slot, first;
1321         const void *object;
1322         const void *insert;
1323         unsigned long n_probes;
1324         struct ck_rhs_map *map;
1325
1326 restart:
1327         map = hs->map;
1328
1329         slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object,
1330             map->probe_limit, behavior);
1331
1332         if (slot == -1 && first == -1) {
1333                 if (ck_rhs_grow(hs, map->capacity << 1) == false)
1334                         return false;
1335
1336                 goto restart;
1337         }
1338
1339         /* Fail operation if a match was found. */
1340         if (object != NULL)
1341                 return false;
1342
1343         ck_rhs_map_bound_set(map, h, n_probes);
1344         insert = ck_rhs_marshal(hs->mode, key, h);
1345
1346         if (first != -1) {
1347                 struct ck_rhs_entry_desc *desc = ck_rhs_desc(map, first);
1348                 int ret = ck_rhs_put_robin_hood(hs, first, desc);
1349                 if (CK_CC_UNLIKELY(ret == 1))
1350                         return ck_rhs_put_internal(hs, h, key, behavior);
1351                 else if (CK_CC_UNLIKELY(ret == -1))
1352                         return false;
1353                 /* Insert key into first bucket in probe sequence. */
1354                 ck_pr_store_ptr(ck_rhs_entry_addr(map, first), insert);
1355                 desc->probes = n_probes;
1356                 ck_rhs_add_wanted(hs, first, -1, h);
1357         } else {
1358                 /* An empty slot was found. */
1359                 ck_pr_store_ptr(ck_rhs_entry_addr(map, slot), insert);
1360                 ck_rhs_set_probes(map, slot, n_probes);
1361                 ck_rhs_add_wanted(hs, slot, -1, h);
1362         }
1363
1364         map->n_entries++;
1365         if ((map->n_entries ) > map->max_entries)
1366                 ck_rhs_grow(hs, map->capacity << 1);
1367         return true;
1368 }
1369
1370 bool
1371 ck_rhs_put(struct ck_rhs *hs,
1372     unsigned long h,
1373     const void *key)
1374 {
1375
1376         return ck_rhs_put_internal(hs, h, key, CK_RHS_PROBE_INSERT);
1377 }
1378
1379 bool
1380 ck_rhs_put_unique(struct ck_rhs *hs,
1381     unsigned long h,
1382     const void *key)
1383 {
1384
1385         return ck_rhs_put_internal(hs, h, key, CK_RHS_PROBE_RH);
1386 }
1387
1388 void *
1389 ck_rhs_get(struct ck_rhs *hs,
1390     unsigned long h,
1391     const void *key)
1392 {
1393         long first;
1394         const void *object;
1395         struct ck_rhs_map *map;
1396         unsigned long n_probes;
1397         unsigned int g, g_p, probe;
1398         unsigned int *generation;
1399
1400         do {
1401                 map = ck_pr_load_ptr(&hs->map);
1402                 generation = &map->generation[h & CK_RHS_G_MASK];
1403                 g = ck_pr_load_uint(generation);
1404                 probe  = ck_rhs_map_bound_get(map, h);
1405                 ck_pr_fence_load();
1406
1407                 first = -1;
1408                 map->probe_func(hs, map, &n_probes, &first, h, key, &object, probe, CK_RHS_PROBE_NO_RH);
1409
1410                 ck_pr_fence_load();
1411                 g_p = ck_pr_load_uint(generation);
1412         } while (g != g_p);
1413
1414         return CK_CC_DECONST_PTR(object);
1415 }
1416
1417 void *
1418 ck_rhs_remove(struct ck_rhs *hs,
1419     unsigned long h,
1420     const void *key)
1421 {
1422         long slot, first;
1423         const void *object;
1424         struct ck_rhs_map *map = hs->map;
1425         unsigned long n_probes;
1426
1427         slot = map->probe_func(hs, map, &n_probes, &first, h, key, &object,
1428             ck_rhs_map_bound_get(map, h), CK_RHS_PROBE_NO_RH);
1429         if (object == NULL)
1430                 return NULL;
1431
1432         map->n_entries--;
1433         ck_rhs_do_backward_shift_delete(hs, slot);
1434         return CK_CC_DECONST_PTR(object);
1435 }
1436
1437 bool
1438 ck_rhs_move(struct ck_rhs *hs,
1439     struct ck_rhs *source,
1440     ck_rhs_hash_cb_t *hf,
1441     ck_rhs_compare_cb_t *compare,
1442     struct ck_malloc *m)
1443 {
1444
1445         if (m == NULL || m->malloc == NULL || m->free == NULL || hf == NULL)
1446                 return false;
1447
1448         hs->mode = source->mode;
1449         hs->seed = source->seed;
1450         hs->map = source->map;
1451         hs->load_factor = source->load_factor;
1452         hs->m = m;
1453         hs->hf = hf;
1454         hs->compare = compare;
1455         return true;
1456 }
1457
1458 bool
1459 ck_rhs_init(struct ck_rhs *hs,
1460     unsigned int mode,
1461     ck_rhs_hash_cb_t *hf,
1462     ck_rhs_compare_cb_t *compare,
1463     struct ck_malloc *m,
1464     unsigned long n_entries,
1465     unsigned long seed)
1466 {
1467
1468         if (m == NULL || m->malloc == NULL || m->free == NULL || hf == NULL)
1469                 return false;
1470
1471         hs->m = m;
1472         hs->mode = mode;
1473         hs->seed = seed;
1474         hs->hf = hf;
1475         hs->compare = compare;
1476         hs->load_factor = CK_RHS_DEFAULT_LOAD_FACTOR;
1477
1478         hs->map = ck_rhs_map_create(hs, n_entries);
1479         return hs->map != NULL;
1480 }