From 1b8fbbd843ddeb5fc81c9303db9c590a436d499b Mon Sep 17 00:00:00 2001 From: William Casarin Date: Mon, 9 Jul 2018 12:10:32 -0700 Subject: progress --- ccan/htable/test/run-copy.c | 44 ++++++ ccan/htable/test/run-size.c | 36 +++++ ccan/htable/test/run-type-int.c | 215 +++++++++++++++++++++++++++ ccan/htable/test/run-type.c | 210 ++++++++++++++++++++++++++ ccan/htable/test/run-zero-hash-first-entry.c | 61 ++++++++ ccan/htable/test/run.c | 212 ++++++++++++++++++++++++++ 6 files changed, 778 insertions(+) create mode 100644 ccan/htable/test/run-copy.c create mode 100644 ccan/htable/test/run-size.c create mode 100644 ccan/htable/test/run-type-int.c create mode 100644 ccan/htable/test/run-type.c create mode 100644 ccan/htable/test/run-zero-hash-first-entry.c create mode 100644 ccan/htable/test/run.c (limited to 'ccan/htable/test') diff --git a/ccan/htable/test/run-copy.c b/ccan/htable/test/run-copy.c new file mode 100644 index 0000000..d111495 --- /dev/null +++ b/ccan/htable/test/run-copy.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include + +#define NUM_VALS 512 + +static size_t hash(const void *elem, void *unused UNNEEDED) +{ + size_t h = *(uint64_t *)elem / 2; + return h; +} + +static bool cmp(const void *candidate, void *ptr) +{ + return *(const uint64_t *)candidate == *(const uint64_t *)ptr; +} + +int main(void) +{ + struct htable ht, ht2; + uint64_t val[NUM_VALS], i; + + plan_tests((NUM_VALS) * 3); + for (i = 0; i < NUM_VALS; i++) + val[i] = i; + + htable_init(&ht, hash, NULL); + for (i = 0; i < NUM_VALS; i++) { + ok1(ht.max >= i); + ok1(ht.max <= i * 2); + htable_add(&ht, hash(&val[i], NULL), &val[i]); + } + + htable_copy(&ht2, &ht); + htable_clear(&ht); + + for (i = 0; i < NUM_VALS; i++) + ok1(htable_get(&ht2, hash(&i, NULL), cmp, &i) == &val[i]); + htable_clear(&ht2); + + return exit_status(); +} diff --git a/ccan/htable/test/run-size.c b/ccan/htable/test/run-size.c new file mode 100644 index 0000000..1a2f5cd --- /dev/null +++ b/ccan/htable/test/run-size.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include + +#define NUM_VALS 512 + +/* We use the number divided by two as the hash (for lots of + collisions). */ +static size_t hash(const void *elem, void *unused UNNEEDED) +{ + size_t h = *(uint64_t *)elem / 2; + return h; +} + +int main(void) +{ + struct htable ht; + uint64_t val[NUM_VALS]; + unsigned int i; + + plan_tests((NUM_VALS) * 2); + for (i = 0; i < NUM_VALS; i++) + val[i] = i; + + htable_init(&ht, hash, NULL); + for (i = 0; i < NUM_VALS; i++) { + ok1(ht.max >= i); + ok1(ht.max <= i * 2); + htable_add(&ht, hash(&val[i], NULL), &val[i]); + } + htable_clear(&ht); + + return exit_status(); +} diff --git a/ccan/htable/test/run-type-int.c b/ccan/htable/test/run-type-int.c new file mode 100644 index 0000000..7b71815 --- /dev/null +++ b/ccan/htable/test/run-type-int.c @@ -0,0 +1,215 @@ +/* Key is an unsigned int, not a pointer. */ +#include "config.h" +#if !defined(HAVE_TYPEOF) || !HAVE_TYPEOF +#define HTABLE_KTYPE(keyof, type) unsigned int +#endif +#include +#include +#include +#include +#include + +#define NUM_BITS 7 +#define NUM_VALS (1 << NUM_BITS) + +struct obj { + /* Makes sure we don't try to treat and obj as a key or vice versa */ + unsigned char unused; + unsigned int key; +}; + +static const unsigned int objkey(const struct obj *obj) +{ + return obj->key; +} + +/* 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 objhash(const unsigned int key) +{ + size_t h = key / 2; + h |= -1UL << NUM_BITS; + return h; +} + +static bool cmp(const struct obj *obj, const unsigned int key) +{ + return obj->key == key; +} + +HTABLE_DEFINE_TYPE(struct obj, objkey, objhash, cmp, htable_obj); + +static void add_vals(struct htable_obj *ht, + struct obj val[], unsigned int num) +{ + unsigned int i; + + for (i = 0; i < num; i++) { + if (htable_obj_get(ht, i)) { + fail("%u already in hash", i); + return; + } + htable_obj_add(ht, &val[i]); + if (htable_obj_get(ht, i) != &val[i]) { + fail("%u not added to hash", i); + return; + } + } + pass("Added %u numbers to hash", i); +} + +static void find_vals(const struct htable_obj *ht, + const struct obj val[], unsigned int num) +{ + unsigned int i; + + for (i = 0; i < num; i++) { + if (htable_obj_get(ht, i) != &val[i]) { + fail("%u not found in hash", i); + return; + } + } + pass("Found %u numbers in hash", i); +} + +static void del_vals(struct htable_obj *ht, + const struct obj val[], unsigned int num) +{ + unsigned int i; + + for (i = 0; i < num; i++) { + if (!htable_obj_delkey(ht, val[i].key)) { + fail("%u not deleted from hash", i); + return; + } + } + pass("Deleted %u numbers in hash", i); +} + +static void del_vals_bykey(struct htable_obj *ht, + const struct obj val[] UNNEEDED, unsigned int num) +{ + unsigned int i; + + for (i = 0; i < num; i++) { + if (!htable_obj_delkey(ht, i)) { + fail("%u not deleted by key from hash", i); + return; + } + } + pass("Deleted %u numbers by key from hash", i); +} + +static bool check_mask(struct htable *ht, const struct obj 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(void) +{ + unsigned int i; + struct htable_obj ht, ht2; + struct obj val[NUM_VALS], *result; + unsigned int dne; + void *p; + struct htable_obj_iter iter; + + plan_tests(29); + for (i = 0; i < NUM_VALS; i++) + val[i].key = i; + dne = i; + + htable_obj_init(&ht); + ok1(ht.raw.max == 0); + ok1(ht.raw.bits == 0); + + /* We cannot find an entry which doesn't exist. */ + ok1(!htable_obj_get(&ht, dne)); + + /* Fill it, it should increase in size. */ + add_vals(&ht, val, NUM_VALS); + ok1(ht.raw.bits == NUM_BITS + 1); + ok1(ht.raw.max < (1 << ht.raw.bits)); + + /* Mask should be set. */ + ok1(ht.raw.common_mask != 0); + ok1(ht.raw.common_mask != -1); + ok1(check_mask(&ht.raw, val, NUM_VALS)); + + /* Find all. */ + find_vals(&ht, val, NUM_VALS); + ok1(!htable_obj_get(&ht, dne)); + + /* Walk once, should get them all. */ + i = 0; + for (p = htable_obj_first(&ht,&iter); p; p = htable_obj_next(&ht, &iter)) + i++; + ok1(i == NUM_VALS); + i = 0; + for (p = htable_obj_prev(&ht,&iter); p; p = htable_obj_prev(&ht, &iter)) + i++; + ok1(i == NUM_VALS); + + /* Delete all. */ + del_vals(&ht, val, NUM_VALS); + ok1(!htable_obj_get(&ht, val[0].key)); + + /* Worst case, a "pointer" which doesn't have any matching bits. */ + htable_add(&ht.raw, 0, (void *)~(uintptr_t)&val[NUM_VALS-1]); + htable_obj_add(&ht, &val[NUM_VALS-1]); + ok1(ht.raw.common_mask == 0); + ok1(ht.raw.common_bits == 0); + /* Delete the bogus one before we trip over it. */ + htable_del(&ht.raw, 0, (void *)~(uintptr_t)&val[NUM_VALS-1]); + + /* Add the rest. */ + add_vals(&ht, val, NUM_VALS-1); + + /* Check we can find them all. */ + find_vals(&ht, val, NUM_VALS); + ok1(!htable_obj_get(&ht, dne)); + + /* Check copy. */ + ok1(htable_obj_copy(&ht2, &ht)); + + /* Delete them all by key. */ + del_vals_bykey(&ht, val, NUM_VALS); + del_vals_bykey(&ht2, val, NUM_VALS); + + /* Write two of the same value. */ + val[1] = val[0]; + htable_obj_add(&ht, &val[0]); + htable_obj_add(&ht, &val[1]); + i = 0; + + result = htable_obj_getfirst(&ht, i, &iter); + ok1(result == &val[0] || result == &val[1]); + if (result == &val[0]) { + ok1(htable_obj_getnext(&ht, i, &iter) == &val[1]); + ok1(htable_obj_getnext(&ht, i, &iter) == NULL); + + /* Deleting first should make us iterate over the other. */ + ok1(htable_obj_del(&ht, &val[0])); + ok1(htable_obj_getfirst(&ht, i, &iter) == &val[1]); + ok1(htable_obj_getnext(&ht, i, &iter) == NULL); + } else { + ok1(htable_obj_getnext(&ht, i, &iter) == &val[0]); + ok1(htable_obj_getnext(&ht, i, &iter) == NULL); + + /* Deleting first should make us iterate over the other. */ + ok1(htable_obj_del(&ht, &val[1])); + ok1(htable_obj_getfirst(&ht, i, &iter) == &val[0]); + ok1(htable_obj_getnext(&ht, i, &iter) == NULL); + } + + htable_obj_clear(&ht); + htable_obj_clear(&ht2); + return exit_status(); +} diff --git a/ccan/htable/test/run-type.c b/ccan/htable/test/run-type.c new file mode 100644 index 0000000..a3616a5 --- /dev/null +++ b/ccan/htable/test/run-type.c @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include + +#define NUM_BITS 7 +#define NUM_VALS (1 << NUM_BITS) + +struct obj { + /* Makes sure we don't try to treat and obj as a key or vice versa */ + unsigned char unused; + unsigned int key; +}; + +static const unsigned int *objkey(const struct obj *obj) +{ + return &obj->key; +} + +/* 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 objhash(const unsigned int *key) +{ + size_t h = *key / 2; + h |= -1UL << NUM_BITS; + return h; +} + +static bool cmp(const struct obj *obj, const unsigned int *key) +{ + return obj->key == *key; +} + +HTABLE_DEFINE_TYPE(struct obj, objkey, objhash, cmp, htable_obj); + +static void add_vals(struct htable_obj *ht, + struct obj val[], unsigned int num) +{ + unsigned int i; + + for (i = 0; i < num; i++) { + if (htable_obj_get(ht, &i)) { + fail("%u already in hash", i); + return; + } + htable_obj_add(ht, &val[i]); + if (htable_obj_get(ht, &i) != &val[i]) { + fail("%u not added to hash", i); + return; + } + } + pass("Added %u numbers to hash", i); +} + +static void find_vals(const struct htable_obj *ht, + const struct obj val[], unsigned int num) +{ + unsigned int i; + + for (i = 0; i < num; i++) { + if (htable_obj_get(ht, &i) != &val[i]) { + fail("%u not found in hash", i); + return; + } + } + pass("Found %u numbers in hash", i); +} + +static void del_vals(struct htable_obj *ht, + const struct obj val[], unsigned int num) +{ + unsigned int i; + + for (i = 0; i < num; i++) { + if (!htable_obj_delkey(ht, &val[i].key)) { + fail("%u not deleted from hash", i); + return; + } + } + pass("Deleted %u numbers in hash", i); +} + +static void del_vals_bykey(struct htable_obj *ht, + const struct obj val[] UNNEEDED, unsigned int num) +{ + unsigned int i; + + for (i = 0; i < num; i++) { + if (!htable_obj_delkey(ht, &i)) { + fail("%u not deleted by key from hash", i); + return; + } + } + pass("Deleted %u numbers by key from hash", i); +} + +static bool check_mask(struct htable *ht, const struct obj 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(void) +{ + unsigned int i; + struct htable_obj ht, ht2; + struct obj val[NUM_VALS], *result; + unsigned int dne; + void *p; + struct htable_obj_iter iter; + + plan_tests(29); + for (i = 0; i < NUM_VALS; i++) + val[i].key = i; + dne = i; + + htable_obj_init(&ht); + ok1(ht.raw.max == 0); + ok1(ht.raw.bits == 0); + + /* We cannot find an entry which doesn't exist. */ + ok1(!htable_obj_get(&ht, &dne)); + + /* Fill it, it should increase in size. */ + add_vals(&ht, val, NUM_VALS); + ok1(ht.raw.bits == NUM_BITS + 1); + ok1(ht.raw.max < (1 << ht.raw.bits)); + + /* Mask should be set. */ + ok1(ht.raw.common_mask != 0); + ok1(ht.raw.common_mask != -1); + ok1(check_mask(&ht.raw, val, NUM_VALS)); + + /* Find all. */ + find_vals(&ht, val, NUM_VALS); + ok1(!htable_obj_get(&ht, &dne)); + + /* Walk once, should get them all. */ + i = 0; + for (p = htable_obj_first(&ht,&iter); p; p = htable_obj_next(&ht, &iter)) + i++; + ok1(i == NUM_VALS); + i = 0; + for (p = htable_obj_prev(&ht,&iter); p; p = htable_obj_prev(&ht, &iter)) + i++; + ok1(i == NUM_VALS); + + /* Delete all. */ + del_vals(&ht, val, NUM_VALS); + ok1(!htable_obj_get(&ht, &val[0].key)); + + /* Worst case, a "pointer" which doesn't have any matching bits. */ + htable_add(&ht.raw, 0, (void *)~(uintptr_t)&val[NUM_VALS-1]); + htable_obj_add(&ht, &val[NUM_VALS-1]); + ok1(ht.raw.common_mask == 0); + ok1(ht.raw.common_bits == 0); + /* Delete the bogus one before we trip over it. */ + htable_del(&ht.raw, 0, (void *)~(uintptr_t)&val[NUM_VALS-1]); + + /* Add the rest. */ + add_vals(&ht, val, NUM_VALS-1); + + /* Check we can find them all. */ + find_vals(&ht, val, NUM_VALS); + ok1(!htable_obj_get(&ht, &dne)); + + /* Check copy. */ + ok1(htable_obj_copy(&ht2, &ht)); + + /* Delete them all by key. */ + del_vals_bykey(&ht, val, NUM_VALS); + del_vals_bykey(&ht2, val, NUM_VALS); + + /* Write two of the same value. */ + val[1] = val[0]; + htable_obj_add(&ht, &val[0]); + htable_obj_add(&ht, &val[1]); + i = 0; + + result = htable_obj_getfirst(&ht, &i, &iter); + ok1(result == &val[0] || result == &val[1]); + if (result == &val[0]) { + ok1(htable_obj_getnext(&ht, &i, &iter) == &val[1]); + ok1(htable_obj_getnext(&ht, &i, &iter) == NULL); + + /* Deleting first should make us iterate over the other. */ + ok1(htable_obj_del(&ht, &val[0])); + ok1(htable_obj_getfirst(&ht, &i, &iter) == &val[1]); + ok1(htable_obj_getnext(&ht, &i, &iter) == NULL); + } else { + ok1(htable_obj_getnext(&ht, &i, &iter) == &val[0]); + ok1(htable_obj_getnext(&ht, &i, &iter) == NULL); + + /* Deleting first should make us iterate over the other. */ + ok1(htable_obj_del(&ht, &val[1])); + ok1(htable_obj_getfirst(&ht, &i, &iter) == &val[0]); + ok1(htable_obj_getnext(&ht, &i, &iter) == NULL); + } + + htable_obj_clear(&ht); + htable_obj_clear(&ht2); + return exit_status(); +} diff --git a/ccan/htable/test/run-zero-hash-first-entry.c b/ccan/htable/test/run-zero-hash-first-entry.c new file mode 100644 index 0000000..3a1a939 --- /dev/null +++ b/ccan/htable/test/run-zero-hash-first-entry.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include + +struct data { + size_t key; +}; + +/* Hash is simply key itself. */ +static size_t hash(const void *e, void *unused UNNEEDED) +{ + struct data *d = (struct data *)e; + + return d->key; +} + +static bool eq(const void *e, void *k) +{ + struct data *d = (struct data *)e; + size_t *key = (size_t *)k; + + return (d->key == *key); +} + +int main(void) +{ + struct htable table; + struct data *d0, *d1; + + plan_tests(6); + + d1 = malloc(sizeof(struct data)); + d1->key = 1; + d0 = malloc(sizeof(struct data)); + d0->key = 0; + + htable_init(&table, hash, NULL); + + htable_add(&table, d0->key, d0); + htable_add(&table, d1->key, d1); + + ok1(table.elems == 2); + ok1(htable_get(&table, 1, eq, &d1->key) == d1); + ok1(htable_get(&table, 0, eq, &d0->key) == d0); + htable_clear(&table); + + /* Now add in reverse order, should still be OK. */ + htable_add(&table, d1->key, d1); + htable_add(&table, d0->key, d0); + + ok1(table.elems == 2); + ok1(htable_get(&table, 1, eq, &d1->key) == d1); + ok1(htable_get(&table, 0, eq, &d0->key) == d0); + htable_clear(&table); + + free(d0); + free(d1); + return exit_status(); +} + diff --git a/ccan/htable/test/run.c b/ccan/htable/test/run.c new file mode 100644 index 0000000..46514c7 --- /dev/null +++ b/ccan/htable/test/run.c @@ -0,0 +1,212 @@ +#include +#include +#include +#include +#include + +#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 UNNEEDED) +{ + size_t h = *(uint64_t *)elem / 2; + h |= -1UL << NUM_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 off, unsigned int num) +{ + uint64_t 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; + } + 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(void) +{ + 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(36); + for (i = 0; i < NUM_VALS; i++) + val[i] = i; + dne = i; + + htable_init(&ht, hash, NULL); + ok1(ht.max == 0); + ok1(ht.bits == 0); + + /* We cannot find an entry which doesn't exist. */ + 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 == 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)); + + /* This should increase it again. */ + add_vals(&ht, val, 1, 1); + ok1(ht.bits == 2); + ok1(ht.max == 3); + + /* Mask should be set. */ + 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)); + + /* 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); + + 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])); + + /* 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); + /* 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, 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)); + + /* 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_bit); + perfect_bit = ht.perfect_bit; + htable_add(&ht, 0, (void *)((uintptr_t)&val[NUM_VALS-1] + | perfect_bit)); + ok1(ht.perfect_bit == 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_bit != 0); + htable_clear(&ht); + + ok1(htable_init_sized(&ht, hash, NULL, 1024)); + ok1(ht.max >= 1024); + htable_clear(&ht); + + ok1(htable_init_sized(&ht, hash, NULL, 1023)); + ok1(ht.max >= 1023); + htable_clear(&ht); + + ok1(htable_init_sized(&ht, hash, NULL, 1025)); + ok1(ht.max >= 1025); + htable_clear(&ht); + + return exit_status(); +} -- cgit v1.2.3