1
/* Taken from Chocolateboy's autobox module. License same as perl's and
2
* this same as this module's license.
6
* This is a customized version of the pointer table implementation in sv.c
17
* This is one of Thomas Wang's hash functions for 64-bit integers from:
18
* http://www.concentric.net/~Ttwang/tech/inthash.htm
20
STATIC U32 ptr_hash(PTRV u) {
31
* This is one of Bob Jenkins' hash functions for 32-bit integers
32
* from: http://burtleburtle.net/bob/hash/integer.html
34
STATIC U32 ptr_hash(PTRV u) {
35
u = (u + 0x7ed55d16) + (u << 12);
36
u = (u ^ 0xc761c23c) ^ (u >> 19);
37
u = (u + 0x165667b1) + (u << 5);
38
u = (u + 0xd3a2646c) ^ (u << 9);
39
u = (u + 0xfd7046c5) + (u << 3);
40
u = (u ^ 0xb55a4f09) ^ (u >> 16);
45
#define PTABLE_HASH(ptr) ptr_hash(PTR2nat(ptr))
48
struct PTABLE_entry *next;
54
struct PTABLE_entry **tbl_ary;
62
struct PTABLE_entry *cur_entry;
65
typedef struct PTABLE_entry PTABLE_ENTRY_t;
66
typedef struct PTABLE PTABLE_t;
67
typedef struct PTABLE_iter PTABLE_ITER_t;
70
STATIC PTABLE_t * PTABLE_new(void);
71
STATIC PTABLE_t * PTABLE_new_size(const U8 size_base2_exponent);
72
STATIC PTABLE_ENTRY_t * PTABLE_find(PTABLE_t *tbl, const void *key);
73
STATIC void * PTABLE_fetch(PTABLE_t *tbl, const void *key);
74
STATIC void PTABLE_store(PTABLE_t *tbl, void *key, void *value);
75
STATIC void PTABLE_delete(PTABLE_t *tbl, void *key);
76
STATIC void PTABLE_grow(PTABLE_t *tbl);
77
STATIC void PTABLE_clear(PTABLE_t *tbl);
78
STATIC void PTABLE_free(PTABLE_t *tbl);
80
STATIC PTABLE_ITER_t * PTABLE_iter_new(PTABLE_t *tbl);
81
STATIC PTABLE_ENTRY_t * PTABLE_iter_next(PTABLE_ITER_t *iter);
82
STATIC void PTABLE_iter_free(PTABLE_ITER_t *iter);
84
/* create a new pointer => pointer table */
85
SRL_STATIC_INLINE PTABLE_t *
88
return PTABLE_new_size(9);
92
PTABLE_new_size(const U8 size_base2_exponent)
95
Newxz(tbl, 1, PTABLE_t);
96
tbl->tbl_max = (1 << size_base2_exponent) - 1;
98
Newxz(tbl->tbl_ary, tbl->tbl_max + 1, PTABLE_ENTRY_t*);
102
/* map an existing pointer using a table */
103
STATIC PTABLE_ENTRY_t *
104
PTABLE_find(PTABLE_t *tbl, const void *key) {
105
PTABLE_ENTRY_t *tblent;
106
const UV hash = PTABLE_HASH(key);
107
tblent = tbl->tbl_ary[hash & tbl->tbl_max];
108
for (; tblent; tblent = tblent->next) {
109
if (tblent->key == key)
115
SRL_STATIC_INLINE void *
116
PTABLE_fetch(PTABLE_t *tbl, const void *key)
118
PTABLE_ENTRY_t const *const tblent = PTABLE_find(tbl, key);
119
return tblent ? tblent->value : NULL;
122
/* add a new entry to a pointer => pointer table */
125
PTABLE_store(PTABLE_t *tbl, void *key, void *value)
127
PTABLE_ENTRY_t *tblent = PTABLE_find(tbl, key);
130
tblent->value = value;
132
const UV entry = PTABLE_HASH(key) & tbl->tbl_max;
133
Newx(tblent, 1, PTABLE_ENTRY_t);
136
tblent->value = value;
137
tblent->next = tbl->tbl_ary[entry];
138
tbl->tbl_ary[entry] = tblent;
140
if (tblent->next && (tbl->tbl_items > tbl->tbl_max))
146
/* double the hash bucket size of an existing ptr table */
149
PTABLE_grow(PTABLE_t *tbl)
151
PTABLE_ENTRY_t **ary = tbl->tbl_ary;
152
const UV oldsize = tbl->tbl_max + 1;
153
UV newsize = oldsize * 2;
156
Renew(ary, newsize, PTABLE_ENTRY_t*);
157
Zero(&ary[oldsize], newsize - oldsize, PTABLE_ENTRY_t*);
158
tbl->tbl_max = --newsize;
161
for (i = 0; i < oldsize; i++, ary++) {
162
PTABLE_ENTRY_t **curentp, **entp, *ent;
165
curentp = ary + oldsize;
166
for (entp = ary, ent = *ary; ent; ent = *entp) {
167
if ((newsize & PTABLE_HASH(ent->key)) != i) {
169
ent->next = *curentp;
179
/* remove all the entries from a ptr table */
182
PTABLE_clear(PTABLE_t *tbl)
184
if (tbl && tbl->tbl_items) {
185
register PTABLE_ENTRY_t * * const array = tbl->tbl_ary;
186
UV riter = tbl->tbl_max;
189
PTABLE_ENTRY_t *entry = array[riter];
192
PTABLE_ENTRY_t * const oentry = entry;
197
/* chocolateboy 2008-01-08
199
* make sure we clear the array entry, so that subsequent probes fail
209
/* remove one entry from a ptr table */
212
PTABLE_delete(PTABLE_t *tbl, void *key)
214
PTABLE_ENTRY_t *tblent;
215
PTABLE_ENTRY_t *tblent_prev;
217
if (!tbl || !tbl->tbl_items) {
220
const UV hash = PTABLE_HASH(key);
222
tblent = tbl->tbl_ary[hash & tbl->tbl_max];
224
for (; tblent; tblent_prev = tblent, tblent = tblent->next) {
225
if (tblent->key == key) {
226
if (tblent_prev != NULL) {
227
tblent_prev->next = tblent->next;
230
/* First entry in chain */
231
tbl->tbl_ary[hash & tbl->tbl_max] = tblent->next;
240
/* clear and free a ptr table */
243
PTABLE_free(PTABLE_t *tbl)
249
Safefree(tbl->tbl_ary);
254
#define PTABLE_ITER_NEXT_ELEM(iter, tbl) \
256
if ((iter)->cur_entry && (iter)->cur_entry->next) { \
257
(iter)->cur_entry = (iter)->cur_entry->next; \
261
if ((iter)->bucket_num > (tbl)->tbl_max) { \
262
(iter)->cur_entry = NULL; \
265
(iter)->cur_entry = (tbl)->tbl_ary[(iter)->bucket_num++]; \
266
} while ((iter)->cur_entry == NULL); \
270
/* Create new iterator object */
271
STATIC PTABLE_ITER_t *
272
PTABLE_iter_new(PTABLE_t *tbl)
275
Newx(iter, 1, PTABLE_ITER_t);
277
iter->bucket_num = 0;
278
iter->cur_entry = NULL;
279
if (tbl->tbl_items == 0) {
280
/* Prevent hash bucket scanning.
281
* This can be a significant optimization on large, empty hashes. */
282
iter->bucket_num = INT_MAX;
285
PTABLE_ITER_NEXT_ELEM(iter, tbl);
286
assert(iter->cur_entry != NULL);
290
/* Return next item from hash, NULL if at end */
291
STATIC PTABLE_ENTRY_t *
292
PTABLE_iter_next(PTABLE_ITER_t *iter)
294
PTABLE_ENTRY_t *retval = iter->cur_entry;
295
PTABLE_t *tbl = iter->table;
296
PTABLE_ITER_NEXT_ELEM(iter, tbl);
300
/* Free iterator object */
302
PTABLE_iter_free(PTABLE_ITER_t *iter)