1 /*
2  * Copyright (c) 2016-2018, NVIDIA CORPORATION.  All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 #include "flang/ADT/hash.h"
19 #include "flang/Error/pgerror.h"
20 #include <stdlib.h>
21 #include <string.h>
22 
23 #if UNIT_TESTING
24 #include <stdarg.h>
25 #include <stddef.h>
26 #include <setjmp.h>
27 #include "cmockery.h"
28 #endif /* UNIT_TESTING */
29 
30 /** \file
31  * \brief Open addressing, quadratically probed hash tables.
32  *
33  * All keys are kept in a single array with 2^n entries. A key is first looked
34  * up at index hash(k) mod 2^k, then following a quadratic sequence of offsets.
35  * The quadratic probing has decent locality of reference for the first few
36  * probes.
37  *
38  * The search terminates when the key is found or a NULL is encountered. A
39  * special ERASED marker is used to avoid severing probe sequences when erasing
40  * keys.
41  */
42 
43 #define ERASED (hash_key_t) ~0UL
44 #define ISKEY(k) ((k) != NULL && (k) != ERASED)
45 
46 struct hashset_ {
47   hash_functions_t func;
48   hash_key_t *table;
49 
50   /** Table size minus 1 is a bit mask. */
51   unsigned mask;
52 
53   /** Number of ISKEY() entries in table. */
54   unsigned entries;
55 
56   /** Number of ERASED entries in table. */
57   unsigned erased;
58 };
59 
60 /** \brief A hashmap adds a table of data pointers after the hashset table. */
61 struct hashmap_ {
62   struct hashset_ set;
63 };
64 
65 #define DTABLE(h) (((h)->table + 1) + (h)->mask)
66 
67 /*
68    Quadrating probing sequence.
69 
70    Given an initial hash value h, we probe at table indices
71 
72        h, h+1, h+1+2, h+1+2+3, ... ( mod 2^n ), or
73 
74        h+(i+1)i/2 ( mod 2^n ), for i = 0 .. 2^n.
75 
76    This sequence visits the entire table without duplicates. Suppose two
77    indexes in the sequence are the same entry:
78 
79                 (i+1)i/2 = (j+1)j/2  ( mod 2^n )
80    ==>           i^2 + i = j^2 + j   ( mod 2^(n+1) )
81    ==>  (i+j)(i-j) + i-j = 0         ( mod 2^(n+1) )
82    ==>      (i+j+1)(i-j) = 0         ( mod 2^(n+1) )
83 
84    Look at the difference of the factors on the left-hand side:
85 
86          (i+j+1) - (i-j) = 2j + 1
87 
88    This is an odd number, so one of the factors must be odd and thus coprime
89    with 2^(n+1). Therefore, 2^(n+1) must divide the other factor. The range of
90    the factors can be determined from the ranges of i and j:
91 
92               1 <= i+j+1 <= 2^(n+1)-1, and
93        -(2^n-1) <=  i-j  <= 2^n-1.
94 
95    The only way 2^(n+1) can divide one of the two factors is if i = j.
96 
97    q.e.d.
98 */
99 
100 /** \brief Search for key, return index that terminated the search. */
101 static unsigned
search(hashset_t h,hash_key_t key)102 search(hashset_t h, hash_key_t key)
103 {
104   unsigned p, s = 1;
105   hash_equality_t eq = h->func.equals;
106 
107   assert(ISKEY(key), "Invalid key for hash", HKEY2INT(key), ERR_Fatal);
108 
109   p = h->func.hash(key) & h->mask;
110   if (eq) {
111     /* General case where we have to call eq() to determine if keys are
112      * equivalent. */
113     while (h->table[p]) {
114       if (h->table[p] != ERASED && eq(key, h->table[p]))
115         break;
116       p = (p + s++) & h->mask;
117     }
118   } else {
119     /* Optimized case when eq is NULL and we simply test for pointer
120      * equality. */
121     while (h->table[p]) {
122       if (key == h->table[p])
123         break;
124       p = (p + s++) & h->mask;
125     }
126   }
127   return p;
128 }
129 
130 /** \brief Find insertion point for key. */
131 static unsigned
insertion_point(hashset_t h,hash_key_t key)132 insertion_point(hashset_t h, hash_key_t key)
133 {
134   unsigned p, s = 1;
135 
136   assert(ISKEY(key), "Invalid key for hash", HKEY2INT(key), ERR_Fatal);
137 
138   p = h->func.hash(key) & h->mask;
139   while (ISKEY(h->table[p])) {
140     p = (p + s++) & h->mask;
141   }
142   return p;
143 }
144 
145 /*
146    The number of NULL entries is kept above 1/8th of the whole table to avoid
147    too long probe sequences. The table is rehashed before the NULL entries drop
148    below that.
149 
150    The ideal table size is the smallest power of two that keeps the load factor
151    below 2/3.
152 */
153 
154 #define NEED_REHASH(h) ((h)->entries + (h)->erased >= (h)->mask - (h)->mask / 8)
155 #define MINSIZE 16
156 
157 static unsigned
mask_for_entries(unsigned n)158 mask_for_entries(unsigned n)
159 {
160   unsigned m = (n + n / 2) | (MINSIZE - 1);
161 
162   /* Arithmetic overflow happens after we have billions of entries. */
163   assert(m > n, "Hash table full", n, ERR_Fatal);
164 
165   /* Round up to the next power of two minus one. */
166   m |= m >> 1;
167   m |= m >> 2;
168   m |= m >> 4;
169   m |= m >> 8;
170   m |= m >> 16;
171 
172   return m;
173 }
174 
175 /* Compute h->mask from h->entries and allocate table and dtable. */
176 static void
alloc_tables(hashset_t h,int with_dtable)177 alloc_tables(hashset_t h, int with_dtable)
178 {
179   h->mask = mask_for_entries(h->entries);
180 
181   /* Allocate table + dtable in one calloc(). */
182   if (with_dtable)
183     h->table = (const void**) calloc(
184         1 + (size_t)h->mask, sizeof(hash_key_t) + sizeof(hash_data_t));
185   else
186     h->table = (const void**) calloc(
187         1 + (size_t)h->mask, sizeof(hash_key_t));
188 }
189 
190 /* Resize and rehash table to get rid of ERASED entries.
191 
192    If not NULL, dtable points to a table of data entries that should be
193    rearranged the same way as h->table.
194  */
195 static void
rehash(hashset_t h,int with_dtable)196 rehash(hashset_t h, int with_dtable)
197 {
198   hash_key_t *old_table = h->table;
199   hash_data_t *old_dtable = DTABLE(h);
200   size_t n, old_size = 1 + (size_t)h->mask;
201   hash_data_t *new_dtable = NULL;
202 
203   alloc_tables(h, with_dtable);
204   new_dtable = DTABLE(h);
205 
206   /* There will be no ERASED markers after the rehash. */
207   h->erased = 0;
208 
209   for (n = 0; n < old_size; n++) {
210     hash_key_t key = old_table[n];
211     if (ISKEY(key)) {
212       unsigned i = insertion_point(h, key);
213       h->table[i] = key;
214       if (with_dtable)
215         new_dtable[i] = old_dtable[n];
216     }
217   }
218 
219   free(old_table);
220 }
221 
222 hashset_t
hashset_alloc(hash_functions_t f)223 hashset_alloc(hash_functions_t f)
224 {
225   hashset_t h = (hashset_t) calloc(1, sizeof(struct hashset_));
226   h->func = f;
227   alloc_tables(h, 0);
228   return h;
229 }
230 
231 hashmap_t
hashmap_alloc(hash_functions_t f)232 hashmap_alloc(hash_functions_t f)
233 {
234   hashmap_t h = (hashmap_t) calloc(1, sizeof(struct hashmap_));
235   h->set.func = f;
236   alloc_tables(&h->set, 1);
237   return h;
238 }
239 
240 void
hashset_free(hashset_t h)241 hashset_free(hashset_t h)
242 {
243   free(h->table);
244   memset(h, 0, sizeof(*h));
245   free(h);
246 }
247 
248 void
hashmap_free(hashmap_t h)249 hashmap_free(hashmap_t h)
250 {
251   free(h->set.table);
252   memset(h, 0, sizeof(*h));
253   free(h);
254 }
255 
256 void
hashset_clear(hashset_t h)257 hashset_clear(hashset_t h)
258 {
259   free(h->table);
260   h->entries = h->erased = 0;
261   alloc_tables(h, 0);
262 }
263 
264 void
hashmap_clear(hashmap_t h)265 hashmap_clear(hashmap_t h)
266 {
267   free(h->set.table);
268   h->set.entries = h->set.erased = 0;
269   alloc_tables(&h->set, 1);
270 }
271 
272 unsigned
hashset_size(hashset_t h)273 hashset_size(hashset_t h)
274 {
275   return h->entries;
276 }
277 
278 unsigned
hashmap_size(hashmap_t h)279 hashmap_size(hashmap_t h)
280 {
281   return h->set.entries;
282 }
283 
284 hash_key_t
hashset_lookup(hashset_t h,hash_key_t key)285 hashset_lookup(hashset_t h, hash_key_t key)
286 {
287   return h->table[search(h, key)];
288 }
289 
290 hash_key_t
hashmap_lookup(hashmap_t h,hash_key_t key,hash_data_t * data)291 hashmap_lookup(hashmap_t h, hash_key_t key, hash_data_t *data)
292 {
293   unsigned i = search(&h->set, key);
294   hash_key_t k = h->set.table[i];
295   if (data && k)
296     *data = DTABLE(&h->set)[i];
297   return k;
298 }
299 
300 void
hashset_insert(hashset_t h,hash_key_t key)301 hashset_insert(hashset_t h, hash_key_t key)
302 {
303   unsigned i;
304 
305 #if DEBUG
306   assert(hashset_lookup(h, key) == NULL, "Duplicate hash key", 0, ERR_Fatal);
307 #endif
308 
309   if (NEED_REHASH(h))
310     rehash(h, 0);
311 
312   i = insertion_point(h, key);
313   if (h->table[i] == ERASED)
314     h->erased--;
315   h->table[i] = key;
316   h->entries++;
317 }
318 
319 void
hashmap_insert(hashmap_t h,hash_key_t key,hash_data_t data)320 hashmap_insert(hashmap_t h, hash_key_t key, hash_data_t data)
321 {
322   unsigned i;
323 
324 #if DEBUG
325   assert(hashmap_lookup(h, key, NULL) == NULL, "Duplicate hash key", 0, ERR_Fatal);
326 #endif
327 
328   if (NEED_REHASH(&h->set))
329     rehash(&h->set, 1);
330 
331   i = insertion_point(&h->set, key);
332   if (h->set.table[i] == ERASED)
333     h->set.erased--;
334   h->set.table[i] = key;
335   DTABLE(&h->set)[i] = data;
336   h->set.entries++;
337 }
338 
339 hash_key_t
hashset_replace(hashset_t h,hash_key_t key)340 hashset_replace(hashset_t h, hash_key_t key)
341 {
342   unsigned i = search(h, key);
343   hash_key_t old = h->table[i];
344 
345   if (ISKEY(old)) {
346     h->table[i] = key;
347     return old;
348   }
349 
350   hashset_insert(h, key);
351   return NULL;
352 }
353 
354 hash_key_t
hashmap_replace(hashmap_t h,hash_key_t key,hash_data_t * data)355 hashmap_replace(hashmap_t h, hash_key_t key, hash_data_t *data)
356 {
357   unsigned i = search(&h->set, key);
358   hash_key_t old = h->set.table[i];
359 
360   if (ISKEY(old)) {
361     hash_data_t old_data = DTABLE(&h->set)[i];
362     h->set.table[i] = key;
363     DTABLE(&h->set)[i] = *data;
364     *data = old_data;
365     return old;
366   }
367 
368   hashmap_insert(h, key, *data);
369   return NULL;
370 }
371 
372 /* We never rehash while erasing elements. The rehash() at insertion can also
373  * shrink the table. */
374 hash_key_t
hashset_erase(hashset_t h,hash_key_t key)375 hashset_erase(hashset_t h, hash_key_t key)
376 {
377   unsigned i = search(h, key);
378   hash_key_t old = h->table[i];
379 
380   if (!old)
381     return NULL;
382 
383   h->table[i] = ERASED;
384   h->erased++;
385   h->entries--;
386   return old;
387 }
388 
389 hash_key_t
hashmap_erase(hashmap_t h,hash_key_t key,hash_data_t * data)390 hashmap_erase(hashmap_t h, hash_key_t key, hash_data_t *data)
391 {
392   unsigned i = search(&h->set, key);
393   hash_key_t old = h->set.table[i];
394 
395   if (!old)
396     return NULL;
397 
398   h->set.table[i] = ERASED;
399   h->set.erased++;
400   h->set.entries--;
401   if (data)
402     *data = DTABLE(&h->set)[i];
403   return old;
404 }
405 
406 void
hashset_iterate(hashset_t h,void (* f)(hash_key_t,void * context),void * context)407 hashset_iterate(hashset_t h, void (*f)(hash_key_t, void *context),
408                 void *context)
409 {
410   size_t n, size = 1 + (size_t)h->mask;
411 
412   for (n = 0; n < size; n++) {
413     hash_key_t key = h->table[n];
414     if (ISKEY(key))
415       f(key, context);
416   }
417 }
418 
419 void
hashmap_iterate(hashmap_t h,void (* f)(hash_key_t,hash_data_t,void * context),void * context)420 hashmap_iterate(hashmap_t h, void (*f)(hash_key_t, hash_data_t, void *context),
421                 void *context)
422 {
423   size_t n, size = 1 + (size_t)h->set.mask;
424   hash_data_t *dtable = DTABLE(&h->set);
425 
426   for (n = 0; n < size; n++) {
427     hash_key_t key = h->set.table[n];
428     if (ISKEY(key))
429       f(key, dtable[n], context);
430   }
431 }
432 
433 /* String hashing */
434 static hash_value_t
string_hash(hash_key_t key)435 string_hash(hash_key_t key)
436 {
437   const unsigned char *p = (const unsigned char *)key;
438   hash_accu_t hacc = HASH_ACCU_INIT;
439   for (; *p; p++)
440     HASH_ACCU_ADD(hacc, *p);
441   HASH_ACCU_FINISH(hacc);
442   return HASH_ACCU_VALUE(hacc);
443 }
444 
445 static int
string_equals(hash_key_t a,hash_key_t b)446 string_equals(hash_key_t a, hash_key_t b)
447 {
448   return strcmp((const char *)a, (const char *)b) == 0;
449 }
450 
451 const hash_functions_t hash_functions_strings = {string_hash, string_equals};
452 
453 /* Direct hashing. */
454 static hash_value_t
direct_hash(hash_key_t key)455 direct_hash(hash_key_t key)
456 {
457   unsigned long k = (unsigned long)key;
458   hash_accu_t hacc = HASH_ACCU_INIT;
459   HASH_ACCU_ADD(hacc, k);
460   /* On an LP64 system, this ignores the high 8 bits of k. That's OK if k
461    * represents a pointer, since current 64-bit systems don't use the high
462    * bits of addresses. A shift by 32 would be undefined when long is a
463    * 32-bit type. */
464   HASH_ACCU_ADD(hacc, k >> 24);
465   HASH_ACCU_FINISH(hacc);
466   return HASH_ACCU_VALUE(hacc);
467 }
468 
469 const hash_functions_t hash_functions_direct = {direct_hash, NULL};
470 
471 /* Everything below is only for testing the implementation. */
472 #if UNIT_TESTING
473 
474 #include <stdio.h>
475 
476 static void
table_size(void ** state)477 table_size(void **state)
478 {
479   assert_int_equal(mask_for_entries(0), 15);
480   assert_int_equal(mask_for_entries(1), 15);
481   assert_int_equal(mask_for_entries(10), 15);
482   assert_int_equal(mask_for_entries(11), 31);
483   assert_int_equal(mask_for_entries(20), 31);
484   assert_int_equal(mask_for_entries(21), 31);
485   assert_int_equal(mask_for_entries(22), 63);
486   assert_int_equal(mask_for_entries(0x80000000), 0xffffffff);
487   assert_int_equal(mask_for_entries(0xa0000000), 0xffffffff);
488   /* 0xb0000000 will overflow and assert, but expect_assert_failure()
489    * segfaults... */
490 }
491 
492 static void
hash_funcs(void ** state)493 hash_funcs(void **state)
494 {
495   assert_int_equal(string_hash(""), 0);
496   assert_int_equal(string_hash("a"), 0xca2e9442);
497   assert_int_equal(string_hash("A"), 0x820103f0);
498   assert_int_equal(string_hash("foo"), 0x238678dd);
499 
500   assert_int_equal(direct_hash((hash_key_t)0), 0);
501   assert_int_equal(direct_hash((hash_key_t)1), 0x20e9c0b3);
502   assert_int_equal(direct_hash((hash_key_t)2), 0x41d38166);
503 }
504 
505 static void
basic_direct(void ** state)506 basic_direct(void **state)
507 {
508   unsigned long i;
509   hashset_t h = hashset_alloc(hash_functions_direct);
510   assert_true(h != NULL);
511   assert_int_equal(hashset_size(h), 0);
512   assert_int_equal(h->mask, MINSIZE - 1);
513 
514   assert_int_equal(hashset_lookup(h, (hash_key_t)1), 0);
515   assert_int_equal(hashset_lookup(h, (hash_key_t)2), 0);
516 
517   hashset_insert(h, (hash_key_t)1);
518   assert_int_equal(hashset_lookup(h, (hash_key_t)1), 1);
519   assert_int_equal(hashset_lookup(h, (hash_key_t)2), 0);
520 
521   assert_int_equal(hashset_replace(h, (hash_key_t)1), 1);
522   assert_int_equal(hashset_replace(h, (hash_key_t)2), 0);
523 
524   for (i = 3; i <= 14; i++)
525     hashset_insert(h, (hash_key_t)i);
526 
527   /* Table has 16 entries, 2 are NULL for exactly 7/8 load factor. */
528   assert_int_equal(hashset_size(h), 14);
529   assert_int_equal(h->mask, MINSIZE - 1);
530 
531   /* Trigger a rehash when we add the 15th element. */
532   hashset_insert(h, (hash_key_t)15);
533   assert_int_equal(hashset_size(h), 15);
534   assert_int_equal(h->mask, 2 * MINSIZE - 1);
535 
536   /* Remove odd entries. */
537   for (i = 1; i <= 15; i += 2)
538     assert_int_equal(hashset_erase(h, (hash_key_t)i), i);
539   assert_int_equal(hashset_size(h), 7);
540   assert_int_equal(h->mask, 2 * MINSIZE - 1);
541   assert_int_equal(h->erased, 8);
542 
543   /* Remove everything. */
544   for (i = 1; i <= 15; i++)
545     assert_int_equal(hashset_erase(h, (hash_key_t)i), i % 2 ? 0 : i);
546 
547   /* Set is empty, but hasn't rehashed yet. */
548   assert_int_equal(hashset_size(h), 0);
549   assert_int_equal(h->mask, 2 * MINSIZE - 1);
550   assert_int_equal(h->erased, 15);
551 
552   for (i = 1; i <= 20; i++)
553     assert_int_equal(hashset_erase(h, (hash_key_t)i), 0);
554   assert_int_equal(hashset_size(h), 0);
555   assert_int_equal(h->mask, 2 * MINSIZE - 1);
556 
557   /* Insert triggers a table shrink. Eventually. The exact timing depends on
558    * the hash function behavior. */
559   for (i = 1; i <= 10; i++)
560     hashset_insert(h, (hash_key_t)(100 + i));
561   assert_int_equal(h->mask, 2 * MINSIZE - 1);
562   for (i = 1; i <= 10; i++)
563     hashset_erase(h, (hash_key_t)(100 + i));
564   assert_int_equal(h->mask, 2 * MINSIZE - 1);
565   for (i = 1; i <= 10; i++)
566     hashset_insert(h, (hash_key_t)(200 + i));
567   assert_int_equal(h->mask, 2 * MINSIZE - 1);
568   for (i = 1; i <= 10; i++)
569     hashset_erase(h, (hash_key_t)(200 + i));
570   assert_int_equal(h->mask, 2 * MINSIZE - 1);
571   for (i = 1; i <= 10; i++)
572     hashset_insert(h, (hash_key_t)(300 + i));
573   assert_int_equal(h->mask, 2 * MINSIZE - 1);
574   for (i = 1; i <= 10; i++)
575     hashset_erase(h, (hash_key_t)(300 + i));
576   assert_int_equal(h->mask, 2 * MINSIZE - 1);
577   for (i = 1; i <= 10; i++)
578     hashset_insert(h, (hash_key_t)(400 + i));
579   assert_int_equal(h->erased, 0);
580   assert_int_equal(h->mask, MINSIZE - 1);
581 
582   hashset_free(h);
583 }
584 
585 static void
free_iterator(hash_key_t key,void * context)586 free_iterator(hash_key_t key, void *context)
587 {
588   ++*(unsigned *)context;
589   free((void *)key);
590 }
591 
592 static void
basic_string(void ** state)593 basic_string(void **state)
594 {
595   unsigned i;
596   hashset_t h = hashset_alloc(hash_functions_strings);
597   const char *strs[] = {"foo", "bar", "baz", "quux"};
598   char buf[20];
599 
600   for (i = 0; i != 4; i++)
601     hashset_insert(h, (hash_key_t)strs[i]);
602 
603   strcpy(buf, "foo");
604   assert_int_equal(hashset_lookup(h, buf), strs[0]);
605   strcpy(buf, "fooo");
606   assert_int_not_equal(hashset_lookup(h, buf), strs[0]);
607 
608   for (i = 0; i < 1000; i++) {
609     char *x = malloc(10);
610     sprintf(x, "x%d", i);
611     hashset_insert(h, x);
612   }
613 
614   for (i = 0; i != 4; i++)
615     hashset_erase(h, (hash_key_t)strs[i]);
616 
617   i = 0;
618   assert_int_equal(hashset_size(h), 1000);
619   hashset_iterate(h, free_iterator, &i);
620   assert_int_equal(i, 1000);
621 
622   hashset_free(h);
623 }
624 
625 static hash_value_t
worst_hash_ever(hash_key_t key)626 worst_hash_ever(hash_key_t key)
627 {
628   return 42;
629 }
630 
631 static const hash_functions_t hash_functions_worst = {worst_hash_ever, NULL};
632 
633 static void
worst_case(void ** state)634 worst_case(void **state)
635 {
636   unsigned long i;
637   hashset_t h = hashset_alloc(hash_functions_worst);
638 
639   for (i = 1; i <= 14; i++)
640     hashset_insert(h, (hash_key_t)i);
641 
642   /* Table has 16 entries, 2 are NULL for exactly 7/8 load factor. */
643   assert_int_equal(hashset_size(h), 14);
644   assert_int_equal(h->mask, MINSIZE - 1);
645 
646   /* The bad hash function stresses the probing sequence to find the NULLS.
647    * The insert and the lookup can both loop infinitely if their probing
648    * sequence doesn't completely cover the table. */
649   for (i = 15; i <= 1000; i++)
650     hashset_insert(h, (hash_key_t)i);
651 
652   for (i = 1; i <= 2000; i += 100)
653     assert_int_equal(hashset_lookup(h, (hash_key_t)i), i <= 1000 ? i : 0);
654 
655   hashset_free(h);
656 }
657 
658 static void
basic_map(void ** state)659 basic_map(void **state)
660 {
661   hashmap_t h = hashmap_alloc(hash_functions_direct);
662   hash_data_t datum;
663   const char *s1 = "foo", *s2 = "bar";
664   unsigned long i;
665 
666   assert_int_equal(hashmap_size(h), 0);
667 
668   /* Lookup nonexistent data with NULL data pointer. */
669   assert_int_equal(hashmap_lookup(h, (hash_key_t)1, NULL), 0);
670 
671   /* Lookup nonexistent data with non-NULL data pointer. */
672   datum = &h;
673   assert_int_equal(hashmap_lookup(h, (hash_key_t)1, &datum), 0);
674   assert_int_equal(datum, &h);
675 
676   hashmap_insert(h, (hash_key_t)1, (hash_data_t)s1);
677   hashmap_insert(h, (hash_key_t)2, (hash_data_t)s2);
678 
679   /* We support lookup with NULL data pointer. */
680   assert_int_equal(hashmap_lookup(h, (hash_key_t)1, NULL), 1);
681 
682   datum = (hash_data_t)s2;
683   assert_int_equal(hashmap_lookup(h, (hash_key_t)1, &datum), 1);
684   assert_int_equal(datum, s1);
685 
686   /* Replace where no previous key existed. */
687   datum = (hash_data_t)s2;
688   assert_int_equal(hashmap_replace(h, (hash_key_t)3, &datum), 0);
689   assert_int_equal(datum, s2);
690 
691   /* Replace previous key. Should return previous data. */
692   datum = (hash_data_t)s1;
693   assert_int_equal(hashmap_replace(h, (hash_key_t)3, &datum), 3);
694   assert_int_equal(datum, s2);
695 
696   /* Force rehash. Verify that data entries are copied correctly. */
697   for (i = 1; i < 100; i++) {
698     datum = (hash_data_t)(i % 7);
699     hashmap_replace(h, (hash_key_t)i, &datum);
700   }
701   for (i = 1; i < 100; i++) {
702     assert_int_equal(hashmap_lookup(h, (hash_key_t)i, &datum), i);
703     assert_int_equal(datum, i % 7);
704   }
705 
706   hashmap_free(h);
707 }
708 
709 int
main()710 main()
711 {
712   const UnitTest tests[] = {
713       unit_test(table_size),   unit_test(hash_funcs), unit_test(basic_direct),
714       unit_test(basic_string), unit_test(worst_case), unit_test(basic_map),
715   };
716   return run_tests(tests);
717 }
718 
719 #endif /* UNIT_TESTING */
720