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