X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fhtable%2Ftest%2Frun.c;h=85502c4ab1f8d3dbeb6e69cde0ecaa2cb4560b7e;hp=27f744c52cbd05c857e9b5298f2df471f6f8d451;hb=d615e534e870a911f11b7b88021242220ea053bf;hpb=198d85adf5e8d9a44b7436bdd046dbffce66b23a diff --git a/ccan/htable/test/run.c b/ccan/htable/test/run.c index 27f744c5..85502c4a 100644 --- a/ccan/htable/test/run.c +++ b/ccan/htable/test/run.c @@ -4,15 +4,16 @@ #include #include -#define NUM_VALS (1 << HTABLE_BASE_BITS) +#define NUM_BITS 7 +#define NUM_VALS (1 << NUM_BITS) /* We use the number divided by two as the hash (for lots of collisions), plus set all the higher bits so we can detect if they don't get masked out. */ -static size_t hash(const void *elem, void *unused) +static size_t hash(const void *elem, void *unused UNNEEDED) { size_t h = *(uint64_t *)elem / 2; - h |= -1UL << HTABLE_BASE_BITS; + h |= -1UL << NUM_BITS; return h; } @@ -22,11 +23,12 @@ static bool objcmp(const void *htelem, void *cmpdata) } static void add_vals(struct htable *ht, - const uint64_t val[], unsigned int num) + const uint64_t val[], + unsigned int off, unsigned int num) { uint64_t i; - for (i = 0; i < num; i++) { + for (i = off; i < off+num; i++) { if (htable_get(ht, hash(&i, NULL), objcmp, &i)) { fail("%llu already in hash", (long long)i); return; @@ -93,63 +95,118 @@ static bool check_mask(struct htable *ht, uint64_t val[], unsigned num) return true; } -int main(int argc, char *argv[]) +int main(void) { - unsigned int i; - struct htable *ht; + unsigned int i, weight; + uintptr_t perfect_bit; + struct htable ht; uint64_t val[NUM_VALS]; uint64_t dne; void *p; struct htable_iter iter; - plan_tests(19); + plan_tests(36); for (i = 0; i < NUM_VALS; i++) val[i] = i; dne = i; - ht = htable_new(hash, NULL); - ok1(ht->max < (1 << ht->bits)); - ok1(ht->bits == HTABLE_BASE_BITS); + htable_init(&ht, hash, NULL); + ok1(ht_max(&ht) == 0); + ok1(ht.bits == 0); /* We cannot find an entry which doesn't exist. */ - ok1(!htable_get(ht, hash(&dne, NULL), objcmp, &dne)); + ok1(!htable_get(&ht, hash(&dne, NULL), objcmp, &dne)); + + /* This should increase it once. */ + add_vals(&ht, val, 0, 1); + ok1(ht.bits == 1); + ok1(ht_max(&ht) == 1); + weight = 0; + for (i = 0; i < sizeof(ht.common_mask) * CHAR_BIT; i++) { + if (ht.common_mask & ((uintptr_t)1 << i)) { + weight++; + } + } + /* Only one bit should be clear. */ + ok1(weight == i-1); + + /* Mask should be set. */ + ok1(check_mask(&ht, val, 1)); - /* Fill it, it should increase in size (once). */ - add_vals(ht, val, NUM_VALS); - ok1(ht->bits == HTABLE_BASE_BITS + 1); - ok1(ht->max < (1 << ht->bits)); + /* This should increase it again. */ + add_vals(&ht, val, 1, 1); + ok1(ht.bits == 2); + ok1(ht_max(&ht) == 3); /* Mask should be set. */ - ok1(ht->common_mask != 0); - ok1(ht->common_mask != -1); - ok1(check_mask(ht, val, NUM_VALS)); + ok1(ht.common_mask != 0); + ok1(ht.common_mask != -1); + ok1(check_mask(&ht, val, 2)); + + /* Now do the rest. */ + add_vals(&ht, val, 2, NUM_VALS - 2); /* Find all. */ - find_vals(ht, val, NUM_VALS); - ok1(!htable_get(ht, hash(&dne, NULL), objcmp, &dne)); + find_vals(&ht, val, NUM_VALS); + ok1(!htable_get(&ht, hash(&dne, NULL), objcmp, &dne)); /* Walk once, should get them all. */ i = 0; - for (p = htable_first(ht,&iter); p; p = htable_next(ht, &iter)) + for (p = htable_first(&ht,&iter); p; p = htable_next(&ht, &iter)) + i++; + ok1(i == NUM_VALS); + + i = 0; + for (p = htable_prev(&ht, &iter); p; p = htable_prev(&ht, &iter)) i++; ok1(i == NUM_VALS); /* Delete all. */ - del_vals(ht, val, NUM_VALS); - ok1(!htable_get(ht, hash(&val[0], NULL), objcmp, &val[0])); + del_vals(&ht, val, NUM_VALS); + ok1(!htable_get(&ht, hash(&val[0], NULL), objcmp, &val[0])); /* Worst case, a "pointer" which doesn't have any matching bits. */ - htable_add(ht, 0, (void *)~(uintptr_t)&val[NUM_VALS-1]); - htable_add(ht, hash(&val[NUM_VALS-1], NULL), &val[NUM_VALS-1]); - ok1(ht->common_mask == 0); - ok1(ht->common_bits == 0); + htable_add(&ht, 0, (void *)~(uintptr_t)&val[NUM_VALS-1]); + htable_add(&ht, hash(&val[NUM_VALS-1], NULL), &val[NUM_VALS-1]); + ok1(ht.common_mask == 0); + ok1(ht.common_bits == 0); + /* Get rid of bogus pointer before we trip over it! */ + htable_del(&ht, 0, (void *)~(uintptr_t)&val[NUM_VALS-1]); /* Add the rest. */ - add_vals(ht, val, NUM_VALS-1); + add_vals(&ht, val, 0, NUM_VALS-1); /* Check we can find them all. */ - find_vals(ht, val, NUM_VALS); - ok1(!htable_get(ht, hash(&dne, NULL), objcmp, &dne)); - + find_vals(&ht, val, NUM_VALS); + ok1(!htable_get(&ht, hash(&dne, NULL), objcmp, &dne)); + + /* Corner cases: wipe out the perfect bit using bogus pointer. */ + htable_clear(&ht); + htable_add(&ht, 0, (void *)((uintptr_t)&val[NUM_VALS-1])); + ok1(ht_perfect_mask(&ht)); + perfect_bit = ht_perfect_mask(&ht); + htable_add(&ht, 0, (void *)((uintptr_t)&val[NUM_VALS-1] + | perfect_bit)); + ok1(ht_perfect_mask(&ht) == 0); + htable_del(&ht, 0, (void *)((uintptr_t)&val[NUM_VALS-1] | perfect_bit)); + + /* Enlarging should restore it... */ + add_vals(&ht, val, 0, NUM_VALS-1); + + ok1(ht_perfect_mask(&ht) != 0); + htable_clear(&ht); + + ok1(htable_init_sized(&ht, hash, NULL, 1024)); + ok1(ht_max(&ht) >= 1024); + htable_clear(&ht); + + ok1(htable_init_sized(&ht, hash, NULL, 1023)); + ok1(ht_max(&ht) >= 1023); + htable_clear(&ht); + + ok1(htable_init_sized(&ht, hash, NULL, 1025)); + ok1(ht_max(&ht) >= 1025); + htable_clear(&ht); + return exit_status(); }