File Coverage

ptable.h
Criterion Covered Total %
statement 54 77 70.1
branch 18 36 50.0
condition n/a
subroutine n/a
pod n/a
total 72 113 63.7


line stmt bran cond sub pod time code
1             /*
2             * This is a customized version of the pointer table implementation in sv.c
3             */
4              
5             #include "ppport.h"
6              
7             #if PTRSIZE == 8
8             /*
9             * This is one of Thomas Wang's hash functions for 64-bit integers from:
10             * http://www.concentric.net/~Ttwang/tech/inthash.htm
11             */
12 1871           U32 ptr_hash(PTRV u) {
13 1871           u = (~u) + (u << 18);
14 1871           u = u ^ (u >> 31);
15 1871           u = u * 21;
16 1871           u = u ^ (u >> 11);
17 1871           u = u + (u << 6);
18 1871           u = u ^ (u >> 22);
19 1871           return (U32)u;
20             }
21             #else
22             /*
23             * This is one of Bob Jenkins' hash functions for 32-bit integers
24             * from: http://burtleburtle.net/bob/hash/integer.html
25             */
26             U32 ptr_hash(PTRV u) {
27             u = (u + 0x7ed55d16) + (u << 12);
28             u = (u ^ 0xc761c23c) ^ (u >> 19);
29             u = (u + 0x165667b1) + (u << 5);
30             u = (u + 0xd3a2646c) ^ (u << 9);
31             u = (u + 0xfd7046c5) + (u << 3);
32             u = (u ^ 0xb55a4f09) ^ (u >> 16);
33             return u;
34             }
35             #endif
36              
37             #define PTABLE_HASH(ptr) ptr_hash(PTR2nat(ptr))
38              
39             struct PTABLE_entry {
40             struct PTABLE_entry *next;
41             void *key;
42             void *value;
43             };
44              
45             struct PTABLE {
46             struct PTABLE_entry **tbl_ary;
47             UV tbl_max;
48             UV tbl_items;
49             };
50              
51             typedef struct PTABLE_entry PTABLE_ENTRY_t;
52             typedef struct PTABLE PTABLE_t;
53              
54             static PTABLE_t * PTABLE_new(void);
55             static PTABLE_ENTRY_t * PTABLE_find(PTABLE_t *tbl, const void *key);
56             static void * PTABLE_fetch(PTABLE_t *tbl, const void *key);
57             static void PTABLE_store(PTABLE_t *tbl, void *key, void *value);
58             static void PTABLE_grow(PTABLE_t *tbl);
59             static void PTABLE_clear(PTABLE_t *tbl);
60             static void PTABLE_free(PTABLE_t *tbl);
61              
62             /* create a new pointer => pointer table */
63              
64             static PTABLE_t *
65 20           PTABLE_new(void)
66             {
67             PTABLE_t *tbl;
68 20           Newxz(tbl, 1, PTABLE_t);
69 20           tbl->tbl_max = 511;
70 20           tbl->tbl_items = 0;
71 20 50         Newxz(tbl->tbl_ary, tbl->tbl_max + 1, PTABLE_ENTRY_t*);
72 20           return tbl;
73             }
74              
75             /* map an existing pointer using a table */
76              
77             static PTABLE_ENTRY_t *
78 1238           PTABLE_find(PTABLE_t *tbl, const void *key) {
79             PTABLE_ENTRY_t *tblent;
80 1238           const UV hash = PTABLE_HASH(key);
81 1238           tblent = tbl->tbl_ary[hash & tbl->tbl_max];
82 1549 100         for (; tblent; tblent = tblent->next) {
83 916 100         if (tblent->key == key)
84 605           return tblent;
85             }
86 633           return NULL;
87             }
88              
89             static void *
90 605           PTABLE_fetch(PTABLE_t *tbl, const void *key)
91             {
92 605           PTABLE_ENTRY_t const *const tblent = PTABLE_find(tbl, key);
93 605 50         return tblent ? tblent->value : NULL;
94             }
95              
96             /* add a new entry to a pointer => pointer table */
97              
98             static void
99 633           PTABLE_store(PTABLE_t *tbl, void *key, void *value)
100             {
101 633           PTABLE_ENTRY_t *tblent = PTABLE_find(tbl, key);
102              
103 633 50         if (tblent) {
104 0           tblent->value = value;
105             } else {
106 633           const UV entry = PTABLE_HASH(key) & tbl->tbl_max;
107 633           Newx(tblent, 1, PTABLE_ENTRY_t);
108              
109 633           tblent->key = key;
110 633           tblent->value = value;
111 633           tblent->next = tbl->tbl_ary[entry];
112 633           tbl->tbl_ary[entry] = tblent;
113 633           tbl->tbl_items++;
114 633 100         if (tblent->next && (tbl->tbl_items > tbl->tbl_max))
    50          
115 0           PTABLE_grow(tbl);
116             }
117 633           }
118              
119             /* double the hash bucket size of an existing ptr table */
120              
121             static void
122 0           PTABLE_grow(PTABLE_t *tbl)
123             {
124 0           PTABLE_ENTRY_t **ary = tbl->tbl_ary;
125 0           const UV oldsize = tbl->tbl_max + 1;
126 0           UV newsize = oldsize * 2;
127             UV i;
128              
129 0 0         Renew(ary, newsize, PTABLE_ENTRY_t*);
130 0 0         Zero(&ary[oldsize], newsize - oldsize, PTABLE_ENTRY_t*);
131 0           tbl->tbl_max = --newsize;
132 0           tbl->tbl_ary = ary;
133              
134 0 0         for (i = 0; i < oldsize; i++, ary++) {
135             PTABLE_ENTRY_t **curentp, **entp, *ent;
136 0 0         if (!*ary)
137 0           continue;
138 0           curentp = ary + oldsize;
139 0 0         for (entp = ary, ent = *ary; ent; ent = *entp) {
140 0 0         if ((newsize & PTABLE_HASH(ent->key)) != i) {
141 0           *entp = ent->next;
142 0           ent->next = *curentp;
143 0           *curentp = ent;
144 0           continue;
145             } else {
146 0           entp = &ent->next;
147             }
148             }
149             }
150 0           }
151              
152             /* remove all the entries from a ptr table */
153              
154             static void
155 20           PTABLE_clear(PTABLE_t *tbl)
156             {
157 20 50         if (tbl && tbl->tbl_items) {
    100          
158 14           register PTABLE_ENTRY_t * * const array = tbl->tbl_ary;
159 14           UV riter = tbl->tbl_max;
160              
161             do {
162 7168           PTABLE_ENTRY_t *entry = array[riter];
163              
164 7801 100         while (entry) {
165 633           PTABLE_ENTRY_t * const oentry = entry;
166 633           entry = entry->next;
167 633           Safefree(oentry);
168             }
169              
170             /* chocolateboy 2008-01-08
171             *
172             * make sure we clear the array entry, so that subsequent probes fail
173             */
174              
175 7168           array[riter] = NULL;
176 7168 100         } while (riter--);
177              
178 14           tbl->tbl_items = 0;
179             }
180 20           }
181              
182             /* clear and free a ptr table */
183              
184             static void
185 20           PTABLE_free(PTABLE_t *tbl)
186             {
187 20 50         if (!tbl) {
188 0           return;
189             }
190 20           PTABLE_clear(tbl);
191 20           Safefree(tbl->tbl_ary);
192 20           Safefree(tbl);
193             }