/** * @file cavl_test.c * @author Ambroz Bizjak * * @section LICENSE * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #define USE_COUNTS 0 #define USE_ASSOC 1 typedef size_t entry_index; #define MAX_INDICES SIZE_MAX typedef uint32_t entry_key; typedef uint8_t assoc_value; typedef uint64_t assoc_sum; struct entry { entry_index tree_child[2]; entry_index tree_parent; int8_t tree_balance; #if USE_COUNTS size_t tree_count; #endif #if USE_ASSOC assoc_value assoc_value; assoc_sum assoc_sum; #endif entry_key key; }; typedef struct entry *entry_ptr; #include "cavl_test_tree.h" #include #include "cavl_test_tree.h" #include static void random_bytes (char *buf, size_t len) { while (len > 0) { *((unsigned char *)buf) = rand(); buf++; len--; } } static int uint64_less (void *user, uint64_t a, uint64_t b) { return (a < b); } #if USE_ASSOC static MyTreeRef assoc_continue_last_lesser_equal (MyTree *tree, struct entry *arg, MyTreeRef ref, assoc_sum target_sum) { assoc_sum cur_sum = MyTree_ExclusiveAssocPrefixSum(tree, arg, ref); ASSERT(target_sum >= cur_sum) while (cur_sum + ref.ptr->assoc_value <= target_sum) { MyTreeRef next_ref = MyTree_GetNext(tree, arg, ref); if (next_ref.link == -1) { break; } cur_sum += ref.ptr->assoc_value; ref = next_ref; } return ref; } #endif static void test_assoc (MyTree *tree, struct entry *arg) { #if USE_ASSOC assoc_sum sum = 0; for (MyTreeRef ref = MyTree_GetFirst(tree, arg); ref.link != -1; ref = MyTree_GetNext(tree, arg, ref)) { assoc_sum tree_sum = MyTree_ExclusiveAssocPrefixSum(tree, arg, ref); ASSERT_FORCE(tree_sum == sum); ASSERT_FORCE(MyTree_FindLastExclusiveAssocPrefixSumLesserEqual(tree, arg, sum, uint64_less, NULL).link == assoc_continue_last_lesser_equal(tree, arg, ref, sum).link); ASSERT_FORCE(MyTree_FindLastExclusiveAssocPrefixSumLesserEqual(tree, arg, sum + 1, uint64_less, NULL).link == assoc_continue_last_lesser_equal(tree, arg, ref, sum + 1).link); sum += ref.ptr->assoc_value; } ASSERT_FORCE(sum == MyTree_AssocSum(tree, arg)); #endif } int main (int argc, char *argv[]) { //srand(time(NULL)); printf("sizeof(struct entry)=%" PRIsz "\n", sizeof(struct entry)); if (argc != 6) { fprintf(stderr, "Usage: %s \n", (argc > 0 ? argv[0] : "")); return 1; } size_t num_keys = atoi(argv[1]); size_t num_lookups = atoi(argv[2]); size_t num_remove = atoi(argv[3]); size_t do_remove = atoi(argv[4]); size_t do_verify = atoi(argv[5]); printf("Allocating keys...\n"); entry_key *keys = (entry_key *)BAllocArray(num_keys, sizeof(keys[0])); ASSERT_FORCE(keys); printf("Generating random keys...\n"); random_bytes((char *)keys, num_keys * sizeof(keys[0])); printf("Allocating lookup indices...\n"); uint64_t *lookup_indices = (uint64_t *)BAllocArray(num_lookups, sizeof(lookup_indices[0])); ASSERT_FORCE(lookup_indices); printf("Generating random lookup indices...\n"); random_bytes((char *)lookup_indices, num_lookups * sizeof(lookup_indices[0])); printf("Allocating remove indices...\n"); uint64_t *remove_indices = (uint64_t *)BAllocArray(num_remove, sizeof(remove_indices[0])); ASSERT_FORCE(remove_indices); printf("Generating random remove indices...\n"); random_bytes((char *)remove_indices, num_remove * sizeof(remove_indices[0])); #if USE_ASSOC printf("Allocating assoc values...\n"); assoc_value *assoc_values = (assoc_value *)BAllocArray(num_keys, sizeof(assoc_values[0])); ASSERT_FORCE(assoc_values); printf("Generating random assoc values...\n"); random_bytes((char *)assoc_values, num_keys * sizeof(assoc_values[0])); #endif printf("Allocating entries...\n"); ASSERT_FORCE(num_keys <= MAX_INDICES); struct entry *entries = (struct entry *)BAllocArray(num_keys, sizeof(*entries)); ASSERT_FORCE(entries); entry_index num_used_entries = 0; MyTree tree; MyTree_Init(&tree); struct entry *arg = entries; ASSERT_FORCE(MyTree_IsEmpty(&tree)); #if USE_COUNTS ASSERT_FORCE(MyTree_Count(&tree, arg) == 0); #endif test_assoc(&tree, arg); size_t num; #if USE_COUNTS size_t prevNum; #endif printf("Inserting random numbers...\n"); num = 0; for (size_t i = 0; i < num_keys; i++) { entries[num_used_entries].key = keys[i]; #if USE_ASSOC entries[num_used_entries].assoc_value = assoc_values[i]; #endif MyTreeRef ref = {&entries[num_used_entries], num_used_entries}; if (!MyTree_Insert(&tree, arg, ref, NULL)) { //printf("Insert collision!\n"); continue; } num_used_entries++; num++; } printf("Inserted %" PRIsz ".\n", num); #if USE_COUNTS ASSERT_FORCE(MyTree_Count(&tree, arg) == num); #endif if (do_verify) { printf("Verifying...\n"); MyTree_Verify(&tree, arg); test_assoc(&tree, arg); } printf("Looking up random inserted keys...\n"); for (size_t i = 0; i < num_lookups; i++) { entry_index idx = lookup_indices[i] % num_keys; MyTreeRef entry = MyTree_LookupExact(&tree, arg, keys[idx]); ASSERT_FORCE(!MyTreeIsNullRef(entry)); } #if USE_COUNTS prevNum = MyTree_Count(&tree, arg); #endif num = 0; printf("Looking up and removing random inserted keys...\n"); for (size_t i = 0; i < num_remove; i++) { entry_index idx = remove_indices[i] % num_keys; MyTreeRef entry = MyTree_LookupExact(&tree, arg, keys[idx]); if (MyTreeIsNullRef(entry)) { //printf("Remove collision!\n"); continue; } ASSERT_FORCE(entry.ptr->key == keys[idx]); MyTree_Remove(&tree, arg, entry); num++; } printf("Removed %" PRIsz ".\n", num); #if USE_COUNTS ASSERT_FORCE(MyTree_Count(&tree, arg) == prevNum - num); #endif if (do_verify) { printf("Verifying...\n"); MyTree_Verify(&tree, arg); test_assoc(&tree, arg); } if (do_remove) { #if USE_COUNTS prevNum = MyTree_Count(&tree, arg); #endif num = 0; printf("Removing remaining...\n"); MyTreeRef cur = MyTree_GetFirst(&tree, arg); while (!MyTreeIsNullRef(cur)) { MyTreeRef prev = cur; cur = MyTree_GetNext(&tree, arg, cur); MyTree_Remove(&tree, arg, prev); num++; } printf("Removed %" PRIsz ".\n", num); ASSERT_FORCE(MyTree_IsEmpty(&tree)); #if USE_COUNTS ASSERT_FORCE(MyTree_Count(&tree, arg) == 0); ASSERT_FORCE(num == prevNum); #endif if (do_verify) { printf("Verifying...\n"); MyTree_Verify(&tree, arg); } } printf("Freeing...\n"); BFree(keys); BFree(lookup_indices); BFree(remove_indices); #if USE_ASSOC BFree(assoc_values); #endif BFree(entries); return 0; }