File Coverage

ptable.h
Criterion Covered Total %
statement 79 106 74.5
branch 32 60 53.3
condition n/a
subroutine n/a
pod n/a
total 111 166 66.8


line stmt bran cond sub pod time code
1             /* Taken from Chocolateboy's autobox module. License same as perl's and
2             * this same as this module's license.
3             */
4              
5             /*
6             * This is a customized version of the pointer table implementation in sv.c
7             */
8              
9             #ifndef PTABLE_H_
10             #define PTABLE_H_
11              
12             #include
13             #include
14             #include "ppport.h"
15              
16             #if PTRSIZE == 8
17             /*
18             * This is one of Thomas Wang's hash functions for 64-bit integers from:
19             * http://www.concentric.net/~Ttwang/tech/inthash.htm
20             */
21 893550           SRL_STATIC_INLINE U32 ptr_hash(PTRV u) {
22 893550           u = (~u) + (u << 18);
23 893550           u = u ^ (u >> 31);
24 893550           u = u * 21;
25 893550           u = u ^ (u >> 11);
26 893550           u = u + (u << 6);
27 893550           u = u ^ (u >> 22);
28 893550           return (U32)u;
29             }
30             #else
31             /*
32             * This is one of Bob Jenkins' hash functions for 32-bit integers
33             * from: http://burtleburtle.net/bob/hash/integer.html
34             */
35             SRL_STATIC_INLINE U32 ptr_hash(PTRV u) {
36             u = (u + 0x7ed55d16) + (u << 12);
37             u = (u ^ 0xc761c23c) ^ (u >> 19);
38             u = (u + 0x165667b1) + (u << 5);
39             u = (u + 0xd3a2646c) ^ (u << 9);
40             u = (u + 0xfd7046c5) + (u << 3);
41             u = (u ^ 0xb55a4f09) ^ (u >> 16);
42             return u;
43             }
44             #endif
45              
46             #define PTABLE_HASH(ptr) ptr_hash(PTR2nat(ptr))
47              
48             #define PTABLE_FLAG_AUTOCLEAN 1
49              
50             typedef struct PTABLE_entry PTABLE_ENTRY_t;
51             typedef struct PTABLE PTABLE_t;
52             typedef struct PTABLE_iter PTABLE_ITER_t;
53              
54             struct PTABLE_entry {
55             struct PTABLE_entry *next;
56             void *key;
57             void *value;
58             };
59              
60             struct PTABLE {
61             struct PTABLE_entry **tbl_ary;
62             UV tbl_max;
63             UV tbl_items;
64             PTABLE_ITER_t *cur_iter; /* one iterator at a time can be auto-freed */
65             };
66              
67             struct PTABLE_iter {
68             struct PTABLE *table;
69             UV bucket_num;
70             struct PTABLE_entry *cur_entry;
71             };
72              
73             /*
74             SRL_STATIC_INLINE PTABLE_t * PTABLE_new(void);
75             SRL_STATIC_INLINE PTABLE_t * PTABLE_new_size(const U8 size_base2_exponent);
76             SRL_STATIC_INLINE PTABLE_ENTRY_t * PTABLE_find(PTABLE_t *tbl, const void *key);
77             SRL_STATIC_INLINE void * PTABLE_fetch(PTABLE_t *tbl, const void *key);
78             SRL_STATIC_INLINE PTABLE_ENTRY_t * PTABLE_store(PTABLE_t *tbl, void *key, void *value);
79             SRL_STATIC_INLINE void PTABLE_delete(PTABLE_t *tbl, void *key);
80             SRL_STATIC_INLINE void PTABLE_grow(PTABLE_t *tbl);
81             SRL_STATIC_INLINE void PTABLE_clear(PTABLE_t *tbl);
82             SRL_STATIC_INLINE void PTABLE_clear_dec(pTHX_ PTABLE_t *tbl);
83             SRL_STATIC_INLINE void PTABLE_free(PTABLE_t *tbl);
84              
85             SRL_STATIC_INLINE PTABLE_ITER_t * PTABLE_iter_new(PTABLE_t *tbl);
86             SRL_STATIC_INLINE PTABLE_ITER_t * PTABLE_iter_new_flags(PTABLE_t *tbl, int flags);
87             SRL_STATIC_INLINE PTABLE_ENTRY_t * PTABLE_iter_next(PTABLE_ITER_t *iter);
88             SRL_STATIC_INLINE void PTABLE_iter_free(PTABLE_ITER_t *iter);
89             */
90              
91             /* create a new pointer => pointer table */
92             SRL_STATIC_INLINE PTABLE_t *
93 189954           PTABLE_new_size(const U8 size_base2_exponent)
94             {
95             PTABLE_t *tbl;
96 189954           Newxz(tbl, 1, PTABLE_t);
97 189954           tbl->tbl_max = (1 << size_base2_exponent) - 1;
98 189954           tbl->tbl_items = 0;
99 189954           tbl->cur_iter = NULL;
100 189954 50         Newxz(tbl->tbl_ary, tbl->tbl_max + 1, PTABLE_ENTRY_t*);
101 189954           return tbl;
102             }
103              
104             SRL_STATIC_INLINE PTABLE_t *
105 189954           PTABLE_new(void)
106             {
107 189954           return PTABLE_new_size(9);
108             }
109              
110             /* map an existing pointer using a table */
111             SRL_STATIC_INLINE PTABLE_ENTRY_t *
112 617264           PTABLE_find(PTABLE_t *tbl, const void *key) {
113             PTABLE_ENTRY_t *tblent;
114 617264           const UV hash = PTABLE_HASH(key);
115 617264           tblent = tbl->tbl_ary[hash & tbl->tbl_max];
116 617264 100         for (; tblent; tblent = tblent->next) {
117 340977 50         if (tblent->key == key)
118 340977           return tblent;
119             }
120 276287           return NULL;
121             }
122              
123             SRL_STATIC_INLINE void *
124 340975           PTABLE_fetch(PTABLE_t *tbl, const void *key)
125             {
126 340975           PTABLE_ENTRY_t const *const tblent = PTABLE_find(tbl, key);
127 340975 100         return tblent ? tblent->value : NULL;
128             }
129              
130             /* double the hash bucket size of an existing ptr table */
131              
132             SRL_STATIC_INLINE void
133 0           PTABLE_grow(PTABLE_t *tbl)
134             {
135 0           PTABLE_ENTRY_t **ary = tbl->tbl_ary;
136 0           const UV oldsize = tbl->tbl_max + 1;
137 0           UV newsize = oldsize * 2;
138             UV i;
139              
140 0 0         Renew(ary, newsize, PTABLE_ENTRY_t*);
141 0 0         Zero(&ary[oldsize], newsize - oldsize, PTABLE_ENTRY_t*);
142 0           tbl->tbl_max = --newsize;
143 0           tbl->tbl_ary = ary;
144              
145 0 0         for (i = 0; i < oldsize; i++, ary++) {
146             PTABLE_ENTRY_t **curentp, **entp, *ent;
147 0 0         if (!*ary)
148 0           continue;
149 0           curentp = ary + oldsize;
150 0 0         for (entp = ary, ent = *ary; ent; ent = *entp) {
151 0 0         if ((newsize & PTABLE_HASH(ent->key)) != i) {
152 0           *entp = ent->next;
153 0           ent->next = *curentp;
154 0           *curentp = ent;
155 0           continue;
156             } else {
157 0           entp = &ent->next;
158             }
159             }
160             }
161 0           }
162              
163             /* add a new entry to a pointer => pointer table */
164              
165             SRL_STATIC_INLINE PTABLE_ENTRY_t *
166 276289           PTABLE_store(PTABLE_t *tbl, void *key, void *value)
167             {
168 276289           PTABLE_ENTRY_t *tblent = PTABLE_find(tbl, key);
169              
170 276289 100         if (tblent) {
171 3           tblent->value = value;
172             } else {
173 276286           const UV entry = PTABLE_HASH(key) & tbl->tbl_max;
174 276286           Newx(tblent, 1, PTABLE_ENTRY_t);
175              
176 276286           tblent->key = key;
177 276286           tblent->value = value;
178 276286           tblent->next = tbl->tbl_ary[entry];
179 276286           tbl->tbl_ary[entry] = tblent;
180 276286           tbl->tbl_items++;
181 276286 50         if (tblent->next && (tbl->tbl_items > tbl->tbl_max))
    0          
182 0           PTABLE_grow(tbl);
183             }
184              
185 276289           return tblent;
186             }
187              
188              
189             /* remove all the entries from a ptr table */
190              
191             SRL_STATIC_INLINE void
192 2774093           PTABLE_clear(PTABLE_t *tbl)
193             {
194 2774093 50         if (tbl && tbl->tbl_items) {
    100          
195 272987           register PTABLE_ENTRY_t * * const array = tbl->tbl_ary;
196 272987           UV riter = tbl->tbl_max;
197              
198             do {
199 139769344           PTABLE_ENTRY_t *entry = array[riter];
200              
201 140045630 100         while (entry) {
202 276286           PTABLE_ENTRY_t * const oentry = entry;
203 276286           entry = entry->next;
204 276286           Safefree(oentry);
205             }
206              
207             /* chocolateboy 2008-01-08
208             *
209             * make sure we clear the array entry, so that subsequent probes fail
210             */
211              
212 139769344           array[riter] = NULL;
213 139769344 100         } while (riter--);
214              
215 272987           tbl->tbl_items = 0;
216             }
217 2774093           }
218              
219             SRL_STATIC_INLINE void
220             PTABLE_clear_dec(pTHX_ PTABLE_t *tbl)
221             {
222             if (tbl && tbl->tbl_items) {
223             register PTABLE_ENTRY_t * * const array = tbl->tbl_ary;
224             UV riter = tbl->tbl_max;
225              
226             do {
227             PTABLE_ENTRY_t *entry = array[riter];
228              
229             while (entry) {
230             PTABLE_ENTRY_t * const oentry = entry;
231             entry = entry->next;
232             if (oentry->value)
233             SvREFCNT_dec((SV*)(oentry->value));
234             Safefree(oentry);
235             }
236              
237             /* chocolateboy 2008-01-08
238             *
239             * make sure we clear the array entry, so that subsequent probes fail
240             */
241              
242             array[riter] = NULL;
243             } while (riter--);
244              
245             tbl->tbl_items = 0;
246             }
247             }
248              
249             /* remove one entry from a ptr table */
250              
251             SRL_STATIC_INLINE void
252             PTABLE_delete(PTABLE_t *tbl, void *key)
253             {
254             PTABLE_ENTRY_t *tblent;
255             PTABLE_ENTRY_t *tblent_prev;
256              
257             if (!tbl || !tbl->tbl_items) {
258             return;
259             } else {
260             const UV hash = PTABLE_HASH(key);
261             tblent_prev = NULL;
262             tblent = tbl->tbl_ary[hash & tbl->tbl_max];
263              
264             for (; tblent; tblent_prev = tblent, tblent = tblent->next) {
265             if (tblent->key == key) {
266             if (tblent_prev != NULL) {
267             tblent_prev->next = tblent->next;
268             }
269             else {
270             /* First entry in chain */
271             tbl->tbl_ary[hash & tbl->tbl_max] = tblent->next;
272             }
273             Safefree(tblent);
274             break;
275             }
276             }
277             }
278             }
279              
280              
281              
282             #define PTABLE_ITER_NEXT_ELEM(iter, tbl) \
283             STMT_START { \
284             if ((iter)->cur_entry && (iter)->cur_entry->next) { \
285             (iter)->cur_entry = (iter)->cur_entry->next; \
286             } \
287             else { \
288             do { \
289             if ((iter)->bucket_num > (tbl)->tbl_max) { \
290             (iter)->cur_entry = NULL; \
291             break; \
292             } \
293             (iter)->cur_entry = (tbl)->tbl_ary[(iter)->bucket_num++]; \
294             } while ((iter)->cur_entry == NULL); \
295             } \
296             } STMT_END
297              
298             /* Create new iterator object */
299             SRL_STATIC_INLINE PTABLE_ITER_t *
300 24841           PTABLE_iter_new_flags(PTABLE_t *tbl, int flags)
301             {
302             PTABLE_ITER_t *iter;
303 24841           Newx(iter, 1, PTABLE_ITER_t);
304 24841           iter->table = tbl;
305 24841           iter->bucket_num = 0;
306 24841           iter->cur_entry = NULL;
307              
308 24841 50         if (flags & PTABLE_FLAG_AUTOCLEAN)
309 24841           tbl->cur_iter = iter;
310 24841 50         if (tbl->tbl_items == 0) {
311             /* Prevent hash bucket scanning.
312             * This can be a significant optimization on large, empty hashes. */
313 0           iter->bucket_num = INT_MAX;
314 0           return iter;
315             }
316 6976810 50         PTABLE_ITER_NEXT_ELEM(iter, tbl);
    0          
    50          
    100          
317             assert(iter->cur_entry != NULL);
318 24841           return iter;
319             }
320              
321             SRL_STATIC_INLINE PTABLE_ITER_t *
322             PTABLE_iter_new(PTABLE_t *tbl)
323             {
324             return PTABLE_iter_new_flags(tbl, 0);
325             }
326              
327              
328             /* Return next item from hash, NULL if at end */
329             SRL_STATIC_INLINE PTABLE_ENTRY_t *
330 50318           PTABLE_iter_next(PTABLE_ITER_t *iter)
331             {
332 50318           PTABLE_ENTRY_t *retval = iter->cur_entry;
333 50318           PTABLE_t *tbl = iter->table;
334 5791464 100         PTABLE_ITER_NEXT_ELEM(iter, tbl);
    50          
    100          
    100          
335 50318           return retval;
336             }
337              
338             /* Free iterator object */
339             SRL_STATIC_INLINE void
340 24841           PTABLE_iter_free(PTABLE_ITER_t *iter)
341             {
342             /* If we're the iterator that can be auto-cleaned by the PTABLE,
343             * then unregister. */
344 24841 50         if (iter->table->cur_iter == iter)
345 24841           iter->table->cur_iter = NULL;
346              
347 24841           Safefree(iter);
348 24841           }
349              
350             SRL_STATIC_INLINE void
351             PTABLE_debug_dump(PTABLE_t *tbl, void (*func)(PTABLE_ENTRY_t *e))
352             {
353             PTABLE_ENTRY_t *e;
354             PTABLE_ITER_t *iter = PTABLE_iter_new(tbl);
355             while (NULL != (e = PTABLE_iter_next(iter))) {
356             func(e);
357             }
358             PTABLE_iter_free(iter);
359             }
360              
361             /* clear and free a ptr table */
362              
363             SRL_STATIC_INLINE void
364 189954           PTABLE_free(PTABLE_t *tbl)
365             {
366 189954 50         if (!tbl)
367 0           return;
368              
369 189954           PTABLE_clear(tbl);
370 189954 50         if (tbl->cur_iter) {
371 0           PTABLE_ITER_t *it = tbl->cur_iter;
372 0           tbl->cur_iter = NULL; /* avoid circular checks */
373 0           PTABLE_iter_free(it);
374             }
375 189954           Safefree(tbl->tbl_ary);
376 189954           Safefree(tbl);
377             }
378              
379             #endif