1 static char rcsid[] = "$Id: uinttable_rh.c 218147 2019-01-16 21:28:41Z twu $";
2 #ifdef HAVE_CONFIG_H
3 #include <config.h>
4 #endif
5
6 /* #define STANDALONE 1 */
7
8 #include "uinttable_rh.h"
9 #include <stdio.h>
10 #include <limits.h>
11 #include <string.h> /* For memset */
12 #include <stdlib.h> /* For qsort */
13
14 #ifdef STANDALONE
15 #include <stdlib.h>
16 #define CALLOC calloc
17 #define MALLOC malloc
18 #define FREE free
19 #define HAVE_64_BIT 1
20 #define UINT8 unsigned long long
21 #else
22 #include "mem.h"
23 #include "assert.h"
24 #include "list.h"
25 #endif
26
27
28 #ifdef DEBUG
29 #define debug(x) x
30 #else
31 #define debug(x)
32 #endif
33
34
35 /* Implementation of a hash table using open addressing and Robin Hood probing */
36 /* Key may not be -1U, because that value is used to indicate empty */
37
38 #define EMPTY (unsigned int) -1 /* Needed so we can use 0U as a key */
39
40 /* Choose powers of 2 to have a fast hash function */
41 static unsigned int powers_of_2[] = { 2U, 4U, 8U, 16U, 32U, 64U, 128U, 256U, 512U, 1024U,
42 2048U, 4096U, 8192U, 16384U, 32768U, 65536U, 131072U,
43 262144U, 524288U, 1048576U, 2097152U, 4194304U, 8388608U,
44 16777216U, 33554432U, 67108864U, 134217728U,
45 268435456U, 536870912U, 1073741824U, 2147483648U};
46 #define LOAD_FACTOR 3
47
48 #define T Uinttable_T
49 struct T {
50 int size;
51 int longest_dist;
52
53 int nbuckets;
54 unsigned int mask; /* hash by taking the lower order bits */
55
56 unsigned int *keys;
57 void **contents;
58 void **saved_contents; /* Stored in order, to make Uinttable_values faster */
59 };
60
61
62 #if 0
63 /* For arbitrary nbuckets */
64 static inline int
65 reduce (unsigned int x, int nbuckets) {
66 return x % nbuckets;
67 }
68 #else
69
70 /* For powers of 2 */
71 static inline int
reduce(unsigned int x,unsigned int mask)72 reduce (unsigned int x, unsigned int mask) {
73 return x & mask;
74 }
75 #endif
76
77
78 /* n is the number of total elements, although some may be repeated */
79 T
Uinttable_new(int hint,bool save_contents_p)80 Uinttable_new (int hint, bool save_contents_p) {
81 T new = (T) MALLOC(sizeof(*new));
82 int level;
83
84 for (level = 0; powers_of_2[level] < (unsigned int) (hint * LOAD_FACTOR); level++) {
85 }
86 new->nbuckets = powers_of_2[level];
87 new->mask = (unsigned int) (new->nbuckets - 1);
88 debug(printf("Creating table with %d buckets\n",new->nbuckets));
89
90 new->size = 0;
91 new->longest_dist = 0;
92 new->keys = (unsigned int *) MALLOC(new->nbuckets * sizeof(unsigned int));
93 memset(new->keys,0xff,new->nbuckets * sizeof(unsigned int));
94
95 new->contents = (void **) MALLOC(new->nbuckets * sizeof(void *));
96 if (save_contents_p == false) {
97 new->saved_contents = (void **) NULL;
98 } else {
99 new->saved_contents = (void **) MALLOC(new->nbuckets * sizeof(void *));
100 }
101
102 return new;
103 }
104
105 int
Uinttable_length(T this)106 Uinttable_length (T this) {
107 return this->size;
108 }
109
110
111 void *
Uinttable_get(T this,const unsigned int key)112 Uinttable_get (T this, const unsigned int key) {
113 int probe_dist = 0;
114 int bucketi;
115
116 bucketi = reduce(key,this->mask);
117 while (probe_dist <= this->longest_dist && this->keys[bucketi] != EMPTY) {
118 if (this->keys[bucketi] == key) {
119 return this->contents[bucketi];
120 } else {
121 probe_dist++;
122 if (++bucketi >= this->nbuckets) {
123 bucketi = 0;
124 }
125 }
126 }
127
128 /* Unsuccessful search */
129 return (void *) NULL;
130 }
131
132
133 static void
insert_aux(T this,unsigned int probe_key,void * probe_contents)134 insert_aux (T this, unsigned int probe_key, void *probe_contents) {
135 int probe_dist = 0, occupant_dist;
136 int bucketi, occupant_bucketi;
137 unsigned int occupant_key;
138 void *occupant_contents;
139
140 debug(printf("Entered insert_aux with key %u, and contents %p\n",probe_key,probe_contents));
141 bucketi = reduce(probe_key,this->mask);
142 while ((occupant_key = this->keys[bucketi]) != EMPTY) {
143 occupant_bucketi = reduce(occupant_key,this->mask);
144 if ((occupant_dist = bucketi - occupant_bucketi) < 0) {
145 occupant_dist += this->nbuckets;
146 }
147
148 if (occupant_dist < probe_dist) {
149 /* Put probe here and make the occupant move */
150 debug(printf("Putting key %u and contents %p into bucketi\n",
151 probe_key,probe_contents,bucketi));
152
153 occupant_contents = this->contents[bucketi];
154 this->contents[bucketi] = probe_contents;
155 probe_contents = occupant_contents;
156
157 /* occupant_key = this->keys[bucketi]; -- obtained above */
158 this->keys[bucketi] = probe_key;
159 probe_key = occupant_key;
160
161 if (probe_dist > this->longest_dist) {
162 this->longest_dist = probe_dist;
163 }
164 probe_dist = occupant_dist;
165 }
166
167 probe_dist += 1;
168 if (++bucketi >= this->nbuckets) {
169 bucketi = 0;
170 }
171 }
172
173 debug(printf("Putting key %u and contents %p into bucketi\n",
174 probe_key,probe_contents,bucketi));
175 this->contents[bucketi] = probe_contents;
176 this->keys[bucketi] = probe_key;
177
178 if (probe_dist > this->longest_dist) {
179 this->longest_dist = probe_dist;
180 }
181
182 return;
183 }
184
185
186 static void
grow(T this)187 grow (T this) {
188 int old_nbuckets = this->nbuckets, i;
189 unsigned int *old_keys = this->keys;
190 void **old_contents = this->contents, **old_saved_contents;
191
192 this->nbuckets *= 2;
193 this->mask = (unsigned int) (this->nbuckets - 1);
194 debug(printf("Growing hash table to %d buckets\n",this->nbuckets));
195
196 this->keys = (unsigned int *) MALLOC(this->nbuckets * sizeof(unsigned int));
197 memset(this->keys,0xff,this->nbuckets * sizeof(unsigned int));
198
199 this->contents = (void **) MALLOC(this->nbuckets * sizeof(void *));
200 if (this->saved_contents != NULL) {
201 old_saved_contents = this->saved_contents;
202 this->saved_contents = (void **) MALLOC(this->nbuckets * sizeof(void *));
203 memcpy(this->saved_contents,old_saved_contents,this->size * sizeof(void *));
204 FREE(old_saved_contents);
205 }
206
207 this->longest_dist = 0;
208 for (i = 0; i < old_nbuckets; i++) {
209 if (old_keys[i] != EMPTY) {
210 insert_aux(this,old_keys[i],old_contents[i]);
211 }
212 }
213
214 FREE(old_contents);
215 FREE(old_keys);
216 return;
217 }
218
219
220 void
Uinttable_put(T this,unsigned int key,void * contents)221 Uinttable_put (T this, unsigned int key, void *contents) {
222 assert(key != EMPTY);
223
224 if (this->size == this->nbuckets) {
225 grow(this);
226 }
227 insert_aux(this,key,contents);
228 /* this->saved_contents[this->size] = contents; */
229 this->size += 1;
230
231 return;
232 }
233
234 void
Uinttable_put_and_save(T this,unsigned int key,void * contents)235 Uinttable_put_and_save (T this, unsigned int key, void *contents) {
236 assert(key != EMPTY);
237
238 if (this->size == this->nbuckets) {
239 grow(this);
240 }
241 insert_aux(this,key,contents);
242 this->saved_contents[this->size] = contents;
243 this->size += 1;
244
245 return;
246 }
247
248
249 /* Valid only when caller specified save_contents_p and performs Uinttable_put_and_save */
250 void **
Uinttable_saved_values(int * nvalues,T this)251 Uinttable_saved_values (int *nvalues, T this) {
252
253 #if 0
254 void **valuearray;
255 int i, k = 0;
256
257 valuearray = (void **) MALLOC(this->size * sizeof(void *));
258 for (i = 0; i < this->nbuckets; i++) {
259 if (this->keys[i] != EMPTY) {
260 valuearray[k++] = this->contents[i];
261 }
262 }
263 *nvalues = this->size;
264 return valuearray;
265
266 #else
267 /* Faster, since we don't need to scan all buckets */
268 *nvalues = this->size;
269 return this->saved_contents;
270 #endif
271 }
272
273 static int
uint_compare(const void * a,const void * b)274 uint_compare (const void *a, const void *b) {
275 unsigned int x = * (unsigned int *) a;
276 unsigned int y = * (unsigned int *) b;
277
278 if (x < y) {
279 return -1;
280 } else if (y < x) {
281 return 1;
282 } else {
283 return 0;
284 }
285 }
286
287
288 unsigned int *
Uinttable_keys(T this,bool sortp)289 Uinttable_keys (T this, bool sortp) {
290 unsigned int *keyarray, key;
291 int i, k = 0;
292
293 keyarray = (unsigned int *) CALLOC(this->size+1,sizeof(unsigned int));
294 for (i = 0; i < this->nbuckets; i++) {
295 if ((key = this->keys[i]) != EMPTY) {
296 keyarray[k++] = key;
297 }
298 }
299
300 if (sortp == true) {
301 qsort(keyarray,this->size,sizeof(unsigned int),uint_compare);
302 }
303
304 return keyarray;
305 }
306
307 void
Uinttable_free(T * old)308 Uinttable_free (T *old) {
309 debug(printf("Freeing table\n"));
310 FREE((*old)->saved_contents);
311 FREE((*old)->contents);
312 FREE((*old)->keys);
313 FREE(*old);
314 return;
315 }
316
317
318 #ifdef STANDALONE
319 int
main(int argc,char * argv[])320 main (int argc, char *argv[]) {
321 T table = Uinttable_new(10);
322 void *elt;
323 int i;
324
325 printf("First key: %u\n",table->keys[0]);
326
327 for (i = 0; i < 50; i++) {
328 Uinttable_put(table,i,(void *) i);
329 }
330
331 for (i = 0; i < 60; i++) {
332 elt = Uinttable_get(table,i);
333 printf("%d => %d\n",i,(int) elt);
334 }
335
336 Uinttable_free(&table);
337
338 return 0;
339 }
340 #endif
341
342