/* * Copyright (c) 2017-2025, Patrick Pelissier * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * + Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * + 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. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS AND CONTRIBUTORS 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 "m-string.h" #include "m-bptree.h" #include "test-obj.h" #include "coverage.h" START_COVERAGE BPTREE_DEF2(btree, 3, int, M_BASIC_OPLIST, int, M_BASIC_OPLIST) END_COVERAGE BPTREE_DEF2(btree_my, 3, testobj_t, TESTOBJ_CMP_OPLIST, testobj_t, TESTOBJ_CMP_OPLIST) BPTREE_DEF2(btree_string, 5, string_t, STRING_OPLIST, string_t, STRING_OPLIST) BPTREE_DEF2(btree_int, 17, int, int) BPTREE_DEF2(btree_mpz, 9, string_t, STRING_OPLIST, testobj_t, TESTOBJ_CMP_OPLIST) BPTREE_DEF(btree_intset, 13, int) BPTREE_DEF(btree_myset, 15, testobj_t, TESTOBJ_CMP_OPLIST) BPTREE_MULTI_DEF2(multimap, 3, int, M_BASIC_OPLIST, int, M_BASIC_OPLIST) BPTREE_MULTI_DEF(multiset, 6, int, M_BASIC_OPLIST) BPTREE_DEF2_AS(MapDouble, MapDouble, MapDoubleIt, MapDoubleItRef, 4, double, double) #define M_OPL_MapDouble() BPTREE_OPLIST2(MapDouble, M_BASIC_OPLIST, M_BASIC_OPLIST) BPTREE_DEF_AS(SetDouble, SetDouble, SetDoubleIt, 7, double) #define M_OPL_SetDouble() BPTREE_OPLIST(SetDouble, M_BASIC_OPLIST) BPTREE_MULTI_DEF2_AS(MultiMapDouble, MultiMapDouble, MultiMapDoubleIt, MultiMapDoubleItRef, 8, double, double) #define M_OPL_MultiMapDouble() BPTREE_OPLIST2(MultiMapDouble, M_BASIC_OPLIST, M_BASIC_OPLIST) BPTREE_MULTI_DEF_AS(MultiSetDouble, MultiSetDouble, MultiSetDoubleIt, 9, double) #define M_OPL_MultiSetDouble() BPTREE_OPLIST(MultiSetDouble, M_BASIC_OPLIST) static void test1(void) { btree_t b; btree_init(b); assert (btree_empty_p(b)); btree_set_at(b, 12, 34); assert (!btree_empty_p(b)); assert (btree_size(b) == 1); assert (btree_get(b, 12) != NULL); assert (*btree_get(b, 12) == 34); btree_set_at(b, 11, 35); assert (!btree_empty_p(b)); assert (btree_size(b) == 2); assert (btree_get(b, 11) != NULL); assert (*btree_get(b, 11) == 35); btree_set_at(b, 1, 36); assert (!btree_empty_p(b)); assert (btree_size(b) == 3); assert (btree_get(b, 1) != NULL); assert (*btree_get(b, 1) == 36); btree_set_at(b, 25, 37); assert (!btree_empty_p(b)); assert (btree_size(b) == 4); assert (btree_get(b, 25) != NULL); assert (*btree_get(b, 25) == 37); btree_set_at(b, -25, 38); assert (btree_size(b) == 5); assert (btree_get(b, -25) != NULL); assert (*btree_get(b, -25) == 38); btree_set_at(b, 5, 39); assert (btree_size(b) == 6); assert (*btree_get(b, -25) == 38); assert (*btree_get(b, 5) == 39); btree_set_at(b, 5, 40); assert (btree_size(b) == 6); assert (*btree_get(b, 5) == 40); btree_set_at(b, -5, 41); assert (*btree_get(b, -5) == 41); for(int i = -1000; i < 1000; i+=3) { btree_set_at(b, i, 2*i); assert (btree_get(b, i) != NULL); assert (*btree_get(b, i) == 2*i); } for(int i = -1000+1; i < 1000; i+=3) { btree_set_at(b, i, 2*i); assert (btree_get(b, i) != NULL); assert (*btree_get(b, i) == 2*i); } for(int i = -1000+2; i < 1000; i+=3) { btree_set_at(b, i, 2*i); assert (btree_get(b, i) != NULL); assert (*btree_get(b, i) == 2*i); } for(int i = -1000; i < 1000; i++) { assert (btree_get(b, i) != NULL); assert (*btree_get(b, i) == 2*i); } assert (btree_size(b) == 2000); bool r = btree_erase(b, 0); assert (r == true); assert (btree_get(b, 0) == NULL); assert (btree_size(b) == 1999); r = btree_erase(b, 1); assert (r == true); assert (btree_get(b, 1) == NULL); assert (btree_size(b) == 1998); r = btree_erase(b, 2); assert (r == true); assert (btree_get(b, 2) == NULL); assert (btree_size(b) == 1997); r = btree_erase(b, 0); assert (r == false); assert (btree_get(b, 0) == NULL); assert (btree_size(b) == 1997); btree_erase(b, -1); assert (btree_get(b, -1) == NULL); btree_erase(b, -2); assert (btree_get(b, -2) == NULL); btree_erase(b, 3); assert (btree_get(b, 3) == NULL); btree_erase(b, 4); assert (btree_get(b, 4) == NULL); btree_erase(b, -3); assert (btree_get(b, -3) == NULL); btree_erase(b, 5); assert (btree_get(b, 5) == NULL); btree_erase(b, -5); assert (btree_get(b, -5) == NULL); btree_erase(b, -4); assert (btree_get(b, -4) == NULL); btree_erase(b, 6); assert (btree_get(b, 6) == NULL); btree_erase(b, 7); assert (btree_get(b, 7) == NULL); for(int i = -1000; i < 0; i++) { btree_erase(b, i); assert (btree_get(b, i) == NULL); } for(int i = 0; i < 1000; i++) { btree_erase(b, i); assert (btree_get(b, i) == NULL); } assert (btree_size(b) == 0); assert (btree_empty_p(b)); int *p = btree_safe_get(b, 1000); assert(p != NULL && *p == 0); *p = 23; p = btree_safe_get(b, 1000); assert(p != NULL && *p == 23); btree_clear(b); } static void test2(void) { btree_t b; btree_init(b); for(int i = 0; i < 100; i++) btree_set_at(b, i, 100*i); for(int i = 0; i < 100; i++) assert (*btree_cget(b, i) == 100*i); assert (btree_size(b) == 100); int k; bool r = btree_pop_at(NULL, b, 0); assert (r == true); assert (btree_size(b) == 99); r = btree_pop_at(&k, b, 1); assert (r == true); assert (btree_size(b) == 98); assert (k == 100); k = -2; r = btree_pop_at(&k, b, 1); assert (r == false); assert (k == -2); r = btree_pop_at(NULL, b, 0); assert (r == false); btree_reset(b); assert (btree_size(b) == 0); assert (btree_empty_p(b)); btree_clear(b); } static void test3(void) { btree_t b; btree_init(b); for(int i = 0; i < 1000; i++) btree_set_at(b, i, 1000*i); assert(btree_size(b) == 1000); for(int i = 0; i < 1000; i++) { bool r = btree_erase(b, i); assert (r == true); } assert(btree_size(b) == 0); for(int i = 1000-1; i >= 0; i--) btree_set_at(b, i, 1000*i); assert(btree_size(b) == 1000); for(int i = 1000-1; i >= 0; i--) { bool r = btree_erase(b, i); assert (r == true); } assert(btree_size(b) == 0); const int prime[5] = { 3, 5, 11, 13, 17}; const int prime_size = 5; for(int k = 0; k < prime_size; k++) { int p = prime[k]; for(int i = 0; i < 1024; i++) { btree_set_at(b, (i*p) % 1024, i); assert(*btree_cget(b, (i*p) % 1024) == i); } assert(btree_size(b) == 1024); for(int i = 0; i < 1024; i++) { assert(*btree_cget(b, (i*p) % 1024) == i); } for(int i = 0; i < 1024; i++) { bool r = btree_erase(b, (i*p) % 1024); assert(r); assert(btree_cget(b, (i*p) % 1024) == NULL); } assert(btree_size(b) == 0); } for(int k = 0; k < prime_size; k++) { int p = prime[k]; for(int i = 0; i < 512; i++) { btree_set_at(b, (i*p) % 1024, i); assert(*btree_cget(b, (i*p) % 1024) == i); } assert(btree_size(b) == 512); for(int i = 256; i < 512; i++) { bool r = btree_erase(b, (i*p) % 1024); assert(r); assert(btree_cget(b, (i*p) % 1024) == NULL); } for(int i = 256; i < 1024; i++) { btree_set_at(b, (i*p) % 1024, i); assert(*btree_cget(b, (i*p) % 1024) == i); } assert(btree_size(b) == 1024); for(int i = 0; i < 1024; i++) { bool r = btree_erase(b, (i*p) % 1024); assert(r); assert(btree_cget(b, (i*p) % 1024) == NULL); } assert(btree_size(b) == 0); } btree_clear(b); } static void test3_string(void) { string_t key, value; string_init(key); string_init(value); btree_string_t b; btree_string_init(b); const int prime[6] = { 1, 3, 5, 11, 13, 17}; const int prime_size = 6; for(int k = 0; k < prime_size; k++) { int p = prime[k]; for(int i = 0; i < 1000; i++) { string_printf(key, "%d", (i*p) % 1024); string_printf(value, "%d", 1000*i); btree_string_set_at(b, key, value); assert(string_equal_p(value, *btree_string_cget(b, key))); } assert(btree_string_size(b) == 1000); for(int i = 0; i < 1000; i++) { string_printf(key, "%d", (i*p) % 1024); string_printf(value, "%d", 1000*i); assert(string_equal_p(value, *btree_string_cget(b, key))); bool r = btree_string_erase(b, key); assert (r == true); } assert(btree_string_size(b) == 0); } btree_string_clear(b); string_clear(key); string_clear(value); } static void test4(void) { btree_t b1, b2; btree_init(b1); for(int i = 0; i < 1000; i++) btree_set_at(b1, i, 1000*i); assert(btree_size(b1) == 1000); btree_init_set(b2, b1); assert (btree_size(b2) == 1000); assert (btree_equal_p(b1, b2)); for(int i = 0; i < 1000; i++) { bool r = btree_erase(b2, i); assert (r == true); assert (!btree_equal_p(b1, b2)); } assert(btree_size(b2) == 0); for(int i = 5000; i < 10000; i++) btree_set_at(b2, i, 1000*i); assert(btree_size(b2) == 5000); btree_set(b2, b1); assert(btree_size(b2) == 1000); assert (btree_equal_p(b1, b2)); for(int i = 0; i < 1000; i++) { bool r = btree_erase(b2, i); assert (r == true); } assert(btree_size(b2) == 0); btree_set(b1, b2); assert(btree_size(b1) == 0); assert (btree_equal_p(b1, b2)); btree_set_at(b1, 0, 1); btree_set_at(b2, 0, 2); assert (!btree_equal_p(b1, b2)); btree_set_at(b1, 0, 1); btree_set_at(b2, 1, 1); bool b = btree_erase(b2, 0); assert( b ); assert (!btree_equal_p(b1, b2)); btree_clear(b1); btree_clear(b2); btree_init(b1); btree_init(b2); for(int i = -50; i < 50; i++) btree_set_at(b1, i, 1000*i); assert (btree_size(b1) == 100); for(int i = -10; i < 10; i++) btree_set_at(b2, i, 1000*i); assert (btree_size(b2) == 20); btree_swap(b1, b2); assert (btree_size(b1) == 20); assert (btree_size(b2) == 100); btree_move(b1, b2); btree_clear(b1); } static void test5(void) { btree_t b; btree_it_t it, it2; btree_init(b); assert (btree_cmin(b) == NULL); assert (btree_cmax(b) == NULL); btree_it(it, b); assert(btree_end_p(it)); btree_it_end(it, b); assert(btree_end_p(it)); for(int i = 0; i < 1000; i+=3) btree_set_at(b, i, 1000*i); for(int i = 1; i < 1000; i+=3) btree_set_at(b, i, 1000*i); for(int i = 2; i < 1000; i+=3) btree_set_at(b, i, 1000*i); assert(btree_size(b) == 1000); assert (*btree_cmin(b) == 0*1000); assert (*btree_cmax(b) == 999*1000); int i = 0; for(btree_it(it, b) ; !btree_end_p(it); btree_it_set(it2, it) , btree_next(it)) { const btree_itref_t *item = btree_cref(it); assert (*item->key_ptr == i); assert (*item->value_ptr == 1000*i); i++; } assert (i == 1000); assert (!btree_it_equal_p(it, it2)); btree_it_end(it2, b); assert (btree_it_equal_p(it, it2)); i = 500; for(btree_it_from(it, b, 500); !btree_it_until_p(it, 600); btree_next(it)) { const btree_itref_t *item = btree_cref(it); assert (*item->key_ptr == i); assert (*item->value_ptr == 1000*i); i++; } assert (i == 600); bool r = btree_erase (b, 500); assert(r); i = 501; for(btree_it_from(it, b, 500); !btree_it_until_p(it, 600); btree_next(it)) { const btree_itref_t *item = btree_cref(it); assert (*item->key_ptr == i); assert (*item->value_ptr == 1000*i); i++; } assert (i == 600); btree_it_from(it, b, 1000); assert (btree_end_p(it)); assert (btree_it_until_p(it, 1001)); // Remove all even integers for(i = 0 ; i < 1000; i+=2) { r = btree_erase(b, i); assert(r || i == 500); } for(i = 0; i < 100; i++) { for(int j = i ; j < 100; j ++) { int k = i; for(btree_it_from(it, b, i); !btree_it_until_p(it, j); btree_next(it)) { const btree_itref_t *item = btree_cref(it); int expect = k/2*2+1; assert (*item->key_ptr == expect); assert (*item->value_ptr == 1000*expect); k+=2; } } } btree_clear(b); } static void test_io(void) { M_LET(mpz1, mpz2, TESTOBJ_CMP_OPLIST) M_LET(str, STRING_OPLIST) M_LET(tree1, tree2, BPTREE_OPLIST2(btree_my, TESTOBJ_CMP_OPLIST, TESTOBJ_CMP_OPLIST)) { btree_my_get_str(str, tree1, false); assert(string_equal_str_p(str, "[]")); const char *endp; bool b = btree_my_parse_str(tree2, string_get_cstr(str), &endp); assert(b); assert(*endp == 0); assert (btree_my_equal_p (tree1, tree2)); FILE *f = m_core_fopen ("a-mbptree.dat", "wt"); if (!f) abort(); btree_my_out_str(f, tree1); fclose (f); f = m_core_fopen ("a-mbptree.dat", "rt"); if (!f) abort(); b = btree_my_in_str (tree2, f); assert (b == true); assert (btree_my_equal_p (tree1, tree2)); fclose(f); testobj_set_ui(mpz1, 67); testobj_set_ui(mpz2, 670); btree_my_set_at(tree1, mpz1, mpz2); testobj_set_ui(mpz1, 17); testobj_set_ui(mpz2, 170); btree_my_set_at(tree1, mpz1, mpz2); btree_my_get_str(str, tree1, false); assert(string_equal_str_p(str, "[17:170,67:670]")); b = btree_my_parse_str(tree2, string_get_cstr(str), &endp); assert(b); assert(*endp == 0); assert (btree_my_equal_p (tree1, tree2)); f = m_core_fopen ("a-mbptree.dat", "wt"); if (!f) abort(); btree_my_out_str(f, tree1); fclose (f); f = m_core_fopen ("a-mbptree.dat", "rt"); if (!f) abort(); b = btree_my_in_str (tree2, f); assert (b == true); assert (btree_my_equal_p (tree1, tree2)); fclose(f); } } static void test_io_set(void) { M_LET(mpz1, TESTOBJ_CMP_OPLIST) M_LET(str, STRING_OPLIST) M_LET(tree1, tree2, BPTREE_OPLIST(btree_myset, TESTOBJ_CMP_OPLIST)) { btree_myset_get_str(str, tree1, false); assert(string_equal_str_p(str, "[]")); const char *endp; bool b = btree_myset_parse_str(tree2, string_get_cstr(str), &endp); assert(b); assert(*endp == 0); assert (btree_myset_equal_p (tree1, tree2)); FILE *f = m_core_fopen ("a-mbptree.dat", "wt"); if (!f) abort(); btree_myset_out_str(f, tree1); fclose (f); f = m_core_fopen ("a-mbptree.dat", "rt"); if (!f) abort(); b = btree_myset_in_str (tree2, f); assert (b == true); assert (btree_myset_equal_p (tree1, tree2)); fclose(f); testobj_set_ui(mpz1, 67); btree_myset_push(tree1, mpz1); testobj_set_ui(mpz1, 670); btree_myset_push(tree1, mpz1); testobj_set_ui(mpz1, 17); btree_myset_push(tree1, mpz1); testobj_set_ui(mpz1, 170); btree_myset_push(tree1, mpz1); btree_myset_get_str(str, tree1, false); assert(string_equal_str_p(str, "[17,67,170,670]")); b = btree_myset_parse_str(tree2, string_get_cstr(str), &endp); assert(b); assert(*endp == 0); assert (btree_myset_equal_p (tree1, tree2)); f = m_core_fopen ("a-mbptree.dat", "wt"); if (!f) abort(); btree_myset_out_str(f, tree1); fclose (f); f = m_core_fopen ("a-mbptree.dat", "rt"); if (!f) abort(); b = btree_myset_in_str (tree2, f); assert (b == true); assert (btree_myset_equal_p (tree1, tree2)); fclose(f); } } static void test_multimap(void) { multimap_t b; multimap_init(b); for (int size = 20; size < 1000; size += 10) { for(int i = 0; i < size; i++) { multimap_set_at(b, i/4, i); } assert(multimap_size(b) == (unsigned) size); for (int k = 0 ; k < size/4; k++) { int j = (4*k+3); multimap_it_t it; for(multimap_it_from(it, b, k); multimap_it_while_p(it, k); multimap_next(it)) { const multimap_itref_t *ref = multimap_cref(it); assert(*ref->key_ptr == k); assert(*ref->value_ptr == j); j--; } assert(j == 4*(k-1)+3); } for(int i = 0; i < size; i++) { bool r = multimap_erase(b, i/4); assert (r == true); } assert(multimap_size(b) == 0); } multimap_clear(b); } static void test_multiset(void) { multiset_t b; multiset_init(b); for (int size = 20; size < 1000; size += 10) { for(int i = 0; i < size; i++) { multiset_push(b, i/4); } assert(multiset_size(b) == (unsigned) size); for (int k = 0 ; k < size/4; k++) { int j = 0; multiset_it_t it; for(multiset_it_from(it, b, k); multiset_it_while_p(it, k); multiset_next(it)) { const int *ref = multiset_cref(it); assert(*ref == k); j++; } assert(j == 4); } for(int i = 0; i < size; i++) { bool r = multiset_erase(b, i/4); assert (r == true); } assert(multiset_size(b) == 0); } multiset_clear(b); } static void test_double(void) { M_LET( (tree, (1.0, 2.0), (3.0, 4.0)), MapDouble) { double *r = MapDouble_get(tree, 1.0); assert( r != NULL); assert( *r == 2.0); r = MapDouble_get(tree, 3.0); assert( r != NULL); assert( *r == 4.0); r = MapDouble_get(tree, 4.0); assert( r == NULL); } M_LET( (tree, 1.0, 3.0), SetDouble) { double *r = SetDouble_get(tree, 1.0); assert( r != NULL); assert( *r == 1.0); r = SetDouble_get(tree, 3.0); assert( r != NULL); assert( *r == 3.0); r = SetDouble_get(tree, 4.0); assert( r == NULL); } M_LET( (tree, (1.0, 2.0), (3.0, 4.0)), MultiMapDouble) { double *r = MultiMapDouble_get(tree, 1.0); assert( r != NULL); assert( *r == 2.0); r = MultiMapDouble_get(tree, 3.0); assert( r != NULL); assert( *r == 4.0); r = MultiMapDouble_get(tree, 4.0); assert( r == NULL); } M_LET( (tree, 1.0, 3.0), MultiSetDouble) { double *r = MultiSetDouble_get(tree, 1.0); assert( r != NULL); assert( *r == 1.0); r = MultiSetDouble_get(tree, 3.0); assert( r != NULL); assert( *r == 3.0); r = MultiSetDouble_get(tree, 4.0); assert( r == NULL); } } static void test_emplace (void) { btree_mpz_t d; btree_mpz_init(d); string_t s; string_init(s); testobj_t o; testobj_init(o); btree_mpz_emplace_key_val_str(d, "HELLO", "14"); string_set_str(s, "HELLO"); testobj_t *ptr = btree_mpz_get(d, s); assert(ptr != NULL); assert(testobj_cmp_ui(*ptr, 14) == 0); btree_mpz_emplace_key_val_ui(d, "HE", 145); string_set_str(s, "HE"); ptr = btree_mpz_get(d, s); assert(ptr != NULL); assert(testobj_cmp_ui(*ptr, 145) == 0); testobj_set(o, *ptr); btree_mpz_emplace_key_val(d, "SHE", o); string_set_str(s, "SHE"); ptr = btree_mpz_get(d, s); assert(ptr != NULL); assert(testobj_cmp_ui(*ptr, 145) == 0); btree_mpz_emplace_key(d, "IT", o); string_set_str(s, "IT"); ptr = btree_mpz_get(d, s); assert(ptr != NULL); assert(testobj_cmp_ui(*ptr, 145) == 0); btree_mpz_emplace_val_ui(d, s, 19); ptr = btree_mpz_get(d, s); assert(ptr != NULL); assert(testobj_cmp_ui(*ptr, 19) == 0); btree_mpz_emplace_val_str(d, s, "190"); ptr = btree_mpz_get(d, s); assert(ptr != NULL); assert(testobj_cmp_ui(*ptr, 190) == 0); testobj_clear(o); string_clear(s); btree_mpz_clear(d); } int main(void) { test1(); test2(); test3(); test3_string(); test4(); test5(); test_io(); test_io_set(); test_multimap(); test_multiset(); test_double(); test_emplace(); testobj_final_check(); exit(0); }