/* Include the main header first, to test it works */ #include /* Include the C files directly. */ #include #include #include #include #include uint32_t rand32_state = 0; /* * Finds a pseudorandom 32-bit number from 0 to 2^32-1 . * Uses the BCPL linear congruential generator method. */ static uint32_t rand32(void) { rand32_state *= (uint32_t)0x7FF8A3ED; rand32_state += (uint32_t)0x2AA01D31; return rand32_state; } static void scramble(void *base, size_t nmemb, size_t size) { char *i = base; char *o; size_t sd; for (;nmemb>1;nmemb--) { o = i + size*(rand32()%nmemb); for (sd=size;sd--;) { char tmp = *o; *o++ = *i; *i++ = tmp; } } } struct test_item { size_t key; uint32_t value; }; /* For ordering a btree of test_item pointers. */ static btree_search_implement ( order_by_key, const struct test_item *, , a == b, a < b ) /* For qsorting an array of test_item pointers. */ static int compare_test_item(const void *ap, const void *bp) { const struct test_item *a = *(const struct test_item * const*)ap; const struct test_item *b = *(const struct test_item * const*)bp; if (a == b) return 0; if (a < b) return -1; return 1; } /* * If lr == 0, make sure iter points to the item given. * If lr == 1, make sure iter points to after the item given. */ static int check_iter(btree_iterator iter_orig, const void *item, int lr) { btree_iterator iter = {*iter_orig}; if (iter->item != item) return 0; if (lr) { if (!btree_prev(iter)) return 0; } else { if (!btree_deref(iter)) return 0; } if (iter->item != item) return 0; if (iter->node->item[iter->k] != iter->item) return 0; return 1; } /* * Returns 1 on insert, 0 on duplicate, * -1 on bad iterator returned by find, and * -2 on bad iterator returned by insert. */ static int insert_test_item(struct btree *btree, struct test_item *item) { btree_iterator iter; int lr; /* Find the first or last matching item, randomly choosing between the two. */ lr = rand32() & 1; if (btree_find_lr(btree, item, iter, lr)) { if (!check_iter(iter, item, lr)) return -1; return 0; } btree_insert_at(iter, item); if (iter->item != item) return -2; return 1; } /* * Returns 1 on remove, 0 on missing, * -1 on bad iterator returned by find, and * -2 on bad iterator returned by remove. */ static int remove_test_item(struct btree *btree, struct test_item *item) { btree_iterator iter; if (!btree_find(btree, item, iter)) return 0; if (!check_iter(iter, item, 0)) return -1; btree_remove_at(iter); if (iter->item != item) return -2; return 1; } static struct { size_t success; size_t excess; size_t duplicate; size_t missing; size_t incorrect; size_t failed; size_t bad_iter_find; size_t bad_iter_insert; size_t bad_iter_remove; size_t bad_iter_next; } stats; static void clear_stats(void) { memset(&stats, 0, sizeof(stats)); } static int print_stats(const char *success_label, size_t expected_success) { int failed = 0; printf(" %s: \t%zu\n", success_label, stats.success); if (stats.success != expected_success) failed = 1; if (stats.excess) failed = 1, printf(" Excess: \t%zu\n", stats.excess); if (stats.duplicate) failed = 1, printf(" Duplicate: \t%zu\n", stats.duplicate); if (stats.missing) failed = 1, printf(" Missing: \t%zu\n", stats.missing); if (stats.incorrect) failed = 1, printf(" Incorrect: \t%zu\n", stats.incorrect); if (stats.failed) failed = 1, printf(" Failed: \t%zu\n", stats.failed); if (stats.bad_iter_find || stats.bad_iter_insert || stats.bad_iter_remove || stats.bad_iter_next) { failed = 1; printf(" Bad iterators yielded by:\n"); if (stats.bad_iter_find) printf(" btree_find_lr(): %zu\n", stats.bad_iter_find); if (stats.bad_iter_insert) printf(" btree_insert_at(): %zu\n", stats.bad_iter_insert); if (stats.bad_iter_remove) printf(" btree_remove_at(): %zu\n", stats.bad_iter_remove); if (stats.bad_iter_next) printf(" btree_next(): %zu\n", stats.bad_iter_next); } return !failed; } static void benchmark(size_t max_per_trial, size_t round_count, int random_counts) { struct test_item **test_item; struct test_item *test_item_array; size_t i, count; size_t round = 0; test_item = malloc(max_per_trial * sizeof(*test_item)); test_item_array = malloc(max_per_trial * sizeof(*test_item_array)); if (!test_item || !test_item_array) { fail("Not enough memory for %zu keys per trial\n", max_per_trial); return; } /* Initialize test_item pointers. */ for (i=0; ikey = i; test_item[i]->value = rand32(); } scramble(test_item, count, sizeof(*test_item)); btree = btree_new(order_by_key); clear_stats(); printf(" Inserting %zu items...\n", count); for (i=0; i= count) { stats.excess++; continue; } if (iter->item == test_item[i]) stats.success++; else stats.incorrect++; i++; } ok1(print_stats("Retrieved", count)); printf(" Traversing backward through %zu items...\n", count); clear_stats(); i = count; for (btree_end(btree, iter); btree_prev(iter);) { if (!i) { stats.excess++; continue; } i--; if (iter->item == test_item[i]) stats.success++; else stats.incorrect++; } ok1(print_stats("Retrieved", count)); ok1(btree->count == count); //static int remove_test_item(struct btree *btree, struct test_item *item); scramble(test_item, count, sizeof(*test_item)); printf(" Deleting %zu items...\n", count); clear_stats(); for (i=0; icount == 0); ok1(print_stats("Deleted", count)); ok1(btree->root->depth == 0 && btree->root->count == 0); btree_delete(btree); } free(test_item); free(test_item_array); } int main(void) { plan_tests(32); benchmark(300000, 4, 0); return exit_status(); }