X-Git-Url: https://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fhtable%2Ftest%2Frun.c;fp=ccan%2Fhtable%2Ftest%2Frun.c;h=27f744c52cbd05c857e9b5298f2df471f6f8d451;hp=0000000000000000000000000000000000000000;hb=198d85adf5e8d9a44b7436bdd046dbffce66b23a;hpb=b84d624ed4593887c98a0c2994f844970dde7f9b diff --git a/ccan/htable/test/run.c b/ccan/htable/test/run.c new file mode 100644 index 00000000..27f744c5 --- /dev/null +++ b/ccan/htable/test/run.c @@ -0,0 +1,155 @@ +#include +#include +#include +#include +#include + +#define NUM_VALS (1 << HTABLE_BASE_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) +{ + size_t h = *(uint64_t *)elem / 2; + h |= -1UL << HTABLE_BASE_BITS; + return h; +} + +static bool objcmp(const void *htelem, void *cmpdata) +{ + return *(uint64_t *)htelem == *(uint64_t *)cmpdata; +} + +static void add_vals(struct htable *ht, + const uint64_t val[], unsigned int num) +{ + uint64_t i; + + for (i = 0; i < num; i++) { + if (htable_get(ht, hash(&i, NULL), objcmp, &i)) { + fail("%llu already in hash", (long long)i); + return; + } + htable_add(ht, hash(&val[i], NULL), &val[i]); + if (htable_get(ht, hash(&i, NULL), objcmp, &i) != &val[i]) { + fail("%llu not added to hash", (long long)i); + return; + } + } + pass("Added %llu numbers to hash", (long long)i); +} + +#if 0 +static void refill_vals(struct htable *ht, + const uint64_t val[], unsigned int num) +{ + uint64_t i; + + for (i = 0; i < num; i++) { + if (htable_get(ht, hash(&i, NULL), objcmp, &i)) + continue; + htable_add(ht, hash(&val[i], NULL), &val[i]); + } +} +#endif + +static void find_vals(struct htable *ht, + const uint64_t val[], unsigned int num) +{ + uint64_t i; + + for (i = 0; i < num; i++) { + if (htable_get(ht, hash(&i, NULL), objcmp, &i) != &val[i]) { + fail("%llu not found in hash", (long long)i); + return; + } + } + pass("Found %llu numbers in hash", (long long)i); +} + +static void del_vals(struct htable *ht, + const uint64_t val[], unsigned int num) +{ + uint64_t i; + + for (i = 0; i < num; i++) { + if (!htable_del(ht, hash(&val[i], NULL), &val[i])) { + fail("%llu not deleted from hash", (long long)i); + return; + } + } + pass("Deleted %llu numbers in hash", (long long)i); +} + +static bool check_mask(struct htable *ht, uint64_t val[], unsigned num) +{ + uint64_t i; + + for (i = 0; i < num; i++) { + if (((uintptr_t)&val[i] & ht->common_mask) != ht->common_bits) + return false; + } + return true; +} + +int main(int argc, char *argv[]) +{ + unsigned int i; + struct htable *ht; + uint64_t val[NUM_VALS]; + uint64_t dne; + void *p; + struct htable_iter iter; + + plan_tests(19); + 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); + + /* We cannot find an entry which doesn't exist. */ + ok1(!htable_get(ht, hash(&dne, NULL), objcmp, &dne)); + + /* 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)); + + /* Mask should be set. */ + ok1(ht->common_mask != 0); + ok1(ht->common_mask != -1); + ok1(check_mask(ht, val, NUM_VALS)); + + /* Find all. */ + 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)) + i++; + ok1(i == NUM_VALS); + + /* Delete all. */ + 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); + + /* Add the rest. */ + add_vals(ht, val, NUM_VALS-1); + + /* Check we can find them all. */ + find_vals(ht, val, NUM_VALS); + ok1(!htable_get(ht, hash(&dne, NULL), objcmp, &dne)); + + return exit_status(); +}