/* * 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 "test-obj.h" #include "m-array.h" #include "m-string.h" #include "coverage.h" START_COVERAGE ARRAY_DEF(array_uint, unsigned int) ARRAY_DEF(array_mpz, testobj_t, TESTOBJ_OPLIST) END_COVERAGE #define ARRAY_UINT_OPLIST ARRAY_OPLIST(array_uint) // Array with the minimum number of methods. ARRAY_DEF(array_min_z, testobj_t, (INIT_SET(testobj_init_set), SET(testobj_set), CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT) )) ARRAY_DEF(array_min2_z, testobj_t, (INIT(testobj_init), CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT) ) ) ARRAY_DEF(array_min3_z, testobj_t, (CLEAR(testobj_clear), INIT_MOVE(M_COPY_A1_DEFAULT))) ARRAY_DEF(array_ulong, uint64_t) ARRAY_DEF(array_string, string_t) ARRAY_DEF_AS(array_double, ArrayDouble, ArrayDoubleIt, double) #define M_OPL_ArrayDouble() ARRAY_OPLIST(array_double, M_BASIC_OPLIST) ArrayDouble g_array = ARRAY_INIT_VALUE(); static void test_uint(void) { array_uint_t v; array_uint_init(v); assert (array_uint_empty_p(v) == true); array_uint_push_back(v, 2); assert (array_uint_empty_p(v) == false); unsigned int x; array_uint_pop_back(&x, v); assert( x == 2); for(unsigned int i = 0; i < 100; i++) array_uint_push_back(v, i); unsigned int s = 0; for(size_t i = 0; i < array_uint_size(v) ; i++) s += *array_uint_cget(v, i); assert( s == 100 * 99 /2); s = 0; for M_EACH(item, v, ARRAY_UINT_OPLIST) { s += *item; } assert( s == 100 * 99 /2); array_uint_pop_at(&s, v, 49); assert (s == 49); array_uint_push_at(v, 49, 49); array_uint_pop_at (NULL, v, 0); assert(array_uint_size(v) == 99); s= 0; for(size_t i = 0; i < array_uint_size(v) ; i++) s += *array_uint_cget(v, i); assert( s == 100 * 99 /2); unsigned int *p = array_uint_get(v, 1); *p += 999; s= 0; for(size_t i = 0; i < array_uint_size(v) ; i++) s += *array_uint_cget(v, i); assert( s == 100 * 99 /2 + 999); array_uint_swap_at(v, 2, 3); assert(*array_uint_cget(v, 2) == 4); assert(*array_uint_cget(v, 3) == 3); array_uint_reserve(v, 0); assert(array_uint_capacity(v) == array_uint_size(v)); const unsigned int *src = array_uint_cget(v, 4); assert (*src == 5); array_uint_remove_v(v, 1, array_uint_size(v) -1); assert(array_uint_size(v) == 2); assert(*array_uint_cget(v, 0) == 1); assert(*array_uint_cget(v, 1) == 99); for(unsigned int i = 3; i < 100; i++) array_uint_push_back(v, i); array_uint_resize(v, 10); assert(array_uint_size(v) == 10); assert(*array_uint_cget(v, 9) == 10); array_uint_resize(v, 1000); assert(array_uint_size(v) == 1000); assert(*array_uint_cget(v, 999) == 0); array_uint_t v2, v3; array_uint_init_set(v2,v); array_uint_init(v3); array_uint_push_back(v3, 459320); array_uint_set(v3, v); assert (array_uint_equal_p(v3, v)); array_uint_push_back(v3, 459320); array_uint_set(v3, v); assert (array_uint_equal_p(v3, v)); array_uint_clear(v); array_uint_clear(v3); assert(array_uint_size(v2) == 1000); assert(*array_uint_cget(v2, 999) == 0); array_uint_push_at (v2, 0, 1742); assert (array_uint_size(v2) == 1001); assert(*array_uint_cget(v2, 0) == 1742); assert(*array_uint_cget(v2, 1000) == 0); array_uint_insert_v (v2, 500, 4); assert (array_uint_size(v2) == 1005); assert(*array_uint_cget(v2, 0) == 1742); assert(*array_uint_cget(v2, 500) == 0); assert(array_uint_size(v2) == 1005); assert(*array_uint_cget(v2, 1004) == 0); array_uint_set_at(v2, 1004, 465487); array_uint_insert_v (v2, 500, 0); assert(array_uint_size(v2) == 1005); assert(*array_uint_cget(v2, 1004) == 465487); array_uint_insert_v (v2, 1004, 10000); assert(array_uint_size(v2) == 11005); assert(*array_uint_cget(v2, 11004) == 465487); array_uint_resize(v2, 1005); array_uint_init(v); array_uint_swap(v,v2); assert(array_uint_size(v) == 1005); assert(array_uint_size(v2) == 0); array_uint_reserve(v, 100); assert(array_uint_size(v) == 1005); assert(array_uint_capacity(v) == 1005); array_uint_reserve(v, 10000); assert(array_uint_size(v) == 1005); assert(array_uint_capacity(v) == 10000); array_uint_set (v, v); array_uint_set (v2, v); assert(array_uint_size(v2) == 1005); array_uint_reset(v); assert (array_uint_capacity(v) > 0); array_uint_reserve(v, 0); assert (array_uint_capacity(v) == 0); array_uint_reset(v2); array_uint_splice(v, v2); assert (array_uint_size(v) == 0); assert (array_uint_size(v2) == 0); for(unsigned i = 0; i < 100; i++) { array_uint_push_back(v, i); array_uint_push_back(v2, 100+i); } array_uint_splice(v, v2); assert (array_uint_size(v) == 200); assert (array_uint_size(v2) == 0); for(unsigned i = 0; i < 200; i++) { assert (i == *array_uint_get(v, i)); } x = 1478963; s = *array_uint_back(v); array_uint_push_move(v, &x); assert (*array_uint_back(v) == 1478963); x = 0; array_uint_pop_move(&x, v); assert (x == 1478963); assert (s == *array_uint_back(v)); s = (unsigned int) array_uint_size (v); bool b = array_uint_erase (v, 12459); assert (b == false); assert (s == array_uint_size (v)); b = array_uint_erase (v, 0); assert (b == true); assert (s == array_uint_size (v)+1); array_uint_clear(v); array_uint_clear(v2); } static void test_mpz(void) { array_mpz_t array1, array2; testobj_t z; array_mpz_init (array1); array_mpz_init (array2); testobj_init (z); // Test empty FILE *f = m_core_fopen ("a-marray.dat", "wt"); if (!f) abort(); array_mpz_out_str(f, array1); fclose (f); f = m_core_fopen ("a-marray.dat", "rt"); if (!f) abort(); bool b = array_mpz_in_str (array2, f); assert (b == true); assert (array_mpz_equal_p (array1, array2)); fclose(f); // Test non empty for(int n = 0; n < 1000; n++) { testobj_set_ui (z, (unsigned int) n); array_mpz_push_back (array1, z); } f = m_core_fopen ("a-marray.dat", "wt"); if (!f) abort(); array_mpz_out_str(f, array1); fclose (f); f = m_core_fopen ("a-marray.dat", "rt"); if (!f) abort(); b = array_mpz_in_str (array2, f); assert (b == true); assert (array_mpz_equal_p (array1, array2)); fclose(f); f = m_core_fopen ("a-marray.dat", "wt"); if (!f) abort(); fprintf(f, "array"); fclose (f); f = m_core_fopen ("a-marray.dat", "rt"); if (!f) abort(); b = array_mpz_in_str (array2, f); assert (b == false); fclose(f); f = m_core_fopen ("a-marray.dat", "wt"); if (!f) abort(); fprintf(f, "["); fclose (f); f = m_core_fopen ("a-marray.dat", "rt"); if (!f) abort(); b = array_mpz_in_str (array2, f); assert (b == false); fclose(f); f = m_core_fopen ("a-marray.dat", "wt"); if (!f) abort(); fprintf(f, "[17"); fclose (f); f = m_core_fopen ("a-marray.dat", "rt"); if (!f) abort(); b = array_mpz_in_str (array2, f); assert (b == false); fclose(f); f = m_core_fopen ("a-marray.dat", "wt"); if (!f) abort(); fprintf(f, "[17,"); fclose (f); f = m_core_fopen ("a-marray.dat", "rt"); if (!f) abort(); b = array_mpz_in_str (array2, f); assert (b == false); fclose(f); f = m_core_fopen ("a-marray.dat", "wt"); if (!f) abort(); fprintf(f, "[17,18"); fclose (f); f = m_core_fopen ("a-marray.dat", "rt"); if (!f) abort(); b = array_mpz_in_str (array2, f); assert (b == false); fclose(f); f = m_core_fopen ("a-marray.dat", "wt"); if (!f) abort(); fprintf(f, "[]"); fclose (f); f = m_core_fopen ("a-marray.dat", "rt"); if (!f) abort(); b = array_mpz_in_str (array2, f); assert (b == true); fclose(f); assert(array_mpz_empty_p(array2)); array_mpz_reset(array1); M_LET(str, STRING_OPLIST) { array_mpz_get_str(str, array1, false); assert (string_cmp_str (str, "[]") == 0); const char *sp; b = array_mpz_parse_str(array2, string_get_cstr(str), &sp); assert(b); assert(*sp == 0); assert(array_mpz_equal_p(array1, array2)); testobj_set_ui (z, 17); array_mpz_push_back (array1, z); array_mpz_get_str(str, array1, false); assert (string_cmp_str (str, "[17]") == 0); b = array_mpz_parse_str(array2, string_get_cstr(str), &sp); assert(b); assert(*sp == 0); assert(array_mpz_equal_p(array1, array2)); testobj_set_ui (z, 42); array_mpz_push_back (array1, z); array_mpz_get_str(str, array1, true); assert (string_cmp_str (str, "[17][17,42]") == 0); b = array_mpz_parse_str(array2, string_get_cstr(str), &sp); assert(b); assert(strcmp(sp, "[17,42]") == 0); assert(!array_mpz_equal_p(array1, array2)); b = array_mpz_parse_str(array2, sp, &sp); assert(b); assert(strcmp(sp, "") == 0); assert(array_mpz_equal_p(array1, array2)); array_mpz_push_back(array1, z); assert(!array_mpz_equal_p(array1, array2)); testobj_set_ui (z, 43); array_mpz_push_back(array2, z); assert(!array_mpz_equal_p(array1, array2)); b = array_mpz_parse_str(array2, "[", &sp); assert(!b); b = array_mpz_parse_str(array2, "[17,", &sp); assert(!b); b = array_mpz_parse_str(array2, "[17,18", &sp); assert(!b); // NOTE: Not the same order than list... } array_mpz_clear(array2); array_mpz_reset(array1); /* Test of the emplace functions. * 3 functions have been generated for testobj: * one from unsigned int (suffix _ui) * one from C string (suffix _str) * one from testobj_t itself (no suffix) */ array_mpz_emplace_back_ui(array1, 42); assert(testobj_cmp_ui(*array_mpz_back(array1), 42) == 0); array_mpz_emplace_back_ui(array1, 426); assert(testobj_cmp_ui(*array_mpz_back(array1), 426) == 0); array_mpz_emplace_back_str(array1, "458"); assert(testobj_cmp_ui(*array_mpz_back(array1), 458) == 0); testobj_set_ui(z, 789); array_mpz_emplace_back(array1, z); assert(testobj_cmp_ui(*array_mpz_back(array1), 789) == 0); testobj_clear (z); array_mpz_clear(array1); } static void test_str(void) { array_string_t a; array_string_init(a); // Test of emplace with const char * ==> string_t array_string_emplace_back(a, "Hello"); assert(string_equal_str_p(*array_string_back(a), "Hello")); array_string_emplace_back(a, "world"); assert(string_equal_str_p(*array_string_back(a), "world")); array_string_emplace_back(a, "How"); assert(string_equal_str_p(*array_string_back(a), "How")); array_string_emplace_back(a, "are"); assert(string_equal_str_p(*array_string_back(a), "are")); array_string_emplace_back(a, "you"); assert(string_equal_str_p(*array_string_back(a), "you")); // Test stable sort with string_t array_string_special_stable_sort(a); // Test INIT_WITH of array of string_t wihtin M_LET M_LET( (b, ("Hello"), ("How"), ("are"), ("world"), ("you")), ARRAY_OPLIST(array_string, STRING_OPLIST)){ assert( array_string_equal_p(a, b)); } array_string_clear(a); } static void test_d(void) { array_uint_t a1, a2; array_uint_init(a1); array_uint_init_move(a2, a1); assert (array_uint_empty_p (a2)); array_uint_init(a1); array_uint_move(a1, a2); assert (array_uint_empty_p (a1)); for(int i = 0; i < 10; i++) array_uint_push_back (a1, (unsigned int) i); array_uint_set_at (a1, 0, 17); assert (*array_uint_get (a1, 0) == 17); assert (*array_uint_back(a1) == 9); unsigned int *p = array_uint_push_new(a1); assert (*p == 0); *p = 10; assert (*array_uint_back(a1) == 10); for(int i = 0; i < 10; i++) array_uint_push_at (a1, 9, (unsigned int) i); assert (*array_uint_back(a1) == 10); for(int i = 9; i < 19; i++) assert (*array_uint_get (a1, (size_t) i) == 18U -(unsigned int) i); *array_uint_safe_get(a1, 100) = 100; assert (*array_uint_back(a1) == 100); assert (array_uint_size(a1) == 101); array_uint_pop_back (NULL, a1); assert (*array_uint_back(a1) == 0); assert (array_uint_size(a1) == 100); array_uint_insert_v (a1, 10, 200); assert (array_uint_size(a1) == 300); for(int i = 10; i < 210; i++) { assert (*array_uint_get (a1, (size_t)i) == 0); } array_uint_it_t it; array_uint_it(it, a1); array_uint_remove (a1, it); assert (array_uint_size(a1) == 299); array_uint_it_last (it, a1); assert (array_uint_last_p(it)); array_uint_it_end (it, a1); assert (array_uint_end_p(it)); array_uint_previous (it); assert (array_uint_last_p(it)); array_uint_it_t it2; array_uint_it_set (it2, it); assert (array_uint_it_equal_p(it2, it)); assert (*array_uint_ref(it2) == 0); array_uint_insert(a1, it2, 17); assert (array_uint_size(a1) == 300); assert (*array_uint_ref(it2) == 17); array_uint_it_end(it2, a1); array_uint_insert(a1, it2, 17789); assert (array_uint_size(a1) == 301); assert (*array_uint_ref(it2) == 17789); array_uint_it(it, a1); assert (array_uint_it_equal_p (it, it2)); array_uint_init_set (a2, a1); assert (array_uint_equal_p (a2, a1)); array_uint_push_back(a2, 890); assert (!array_uint_equal_p (a2, a1)); array_uint_push_back(a1, 891); assert (!array_uint_equal_p (a2, a1)); size_t h = array_uint_hash(a2); assert (h != 0); array_uint_reset(a1); array_uint_it(it, a1); assert (array_uint_end_p (it)); assert (array_uint_last_p (it)); array_uint_clear(a1); array_uint_clear(a2); } static void test_double(void) { M_LET( (tab, 0.0, 1.0, 2.0, 3.0), ArrayDouble) { double ref = 0.0; for M_EACH(i, tab, ArrayDouble) { assert (*i == ref); ref += 1.0; } // Test of buffer overflow (with address sanitizer) // _init_set provides an allocated buffer of the exact needed size ArrayDouble tab1; array_double_init_set(tab1, tab); array_double_pop_at(NULL, tab1, 0); array_double_clear(tab1); array_double_init_set(tab1, tab); array_double_insert_v(tab1, 0, 2); array_double_clear(tab1); array_double_init_set(tab1, tab); array_double_remove_v(tab1, 0, 1); array_double_clear(tab1); array_double_init_set(tab1, tab); array_double_push_at(tab1, 0, 2.); array_double_clear(tab1); } assert( array_double_empty_p(g_array)); array_double_push_back(g_array, 34.); assert( array_double_size(g_array) == 1); array_double_clear(g_array); } // Test support of M*LIB for C++ class #if defined(__cplusplus) /* For this, we need new placement support */ #include /* For std::move */ #include /* Some Simple Oplist for a C++ class (using new placement feature) Some features may not be always available (like comparison or I/O). It isn't exported, since there is no meaning to support for M*LIB C++ class officialy (use the STL instead!) */ #define M_CLASS_CPP_INIT(opl,x) (new (&(x)) (M_GET_NAME opl)) #define M_CLASS_CPP_INIT_SET(opl,x, y) (new (&(x)) M_GET_NAME opl(y)) #define M_CLASS_CPP_SET(opl, x, y) ((x) = (y)) #define M_CLASS_CPP_CLEAR(opl, x) ((&(x))->~M_GET_NAME opl()) #define M_CLASS_CPP_CLEAR2(x) ((&(x))->~opl()) #define M_CLASS_CPP_INIT_MOVE(opl,x,y) (new (&(x)) M_GET_NAME opl(std::move(y)), ((&(y))->~M_GET_NAME opl())) #define M_CLASS_CPP_CMP(opl, x, y) ((x) < (y) ? -1 : (y) < (x) ? 1 : 0) #define M_CLASS_CPP_HASH(opl, x) (std::hash(x)) #define M_CLASS_OPLIST(_class) \ (NAME(_class), \ TYPE(_class), \ INIT(API_1(M_CLASS_CPP_INIT)), \ INIT_SET(API_1(M_CLASS_CPP_INIT_SET)), \ SET(API_1(M_CLASS_CPP_SET)), \ CLEAR(API_1(M_CLASS_CPP_CLEAR)), \ INIT_MOVE(API_1(M_CLASS_CPP_INIT_MOVE)) ) // Define a basic C++ class class Foo { int *x; public: Foo() { x = new (int); }; Foo(int n) { x = new (int) ; *x = n; } Foo(const Foo &y) {x = new (int) ; *x = *y.x;}; ~Foo() { delete x; } void operator=(const Foo &y) { *x = *y.x; }; void operator=(int n) { *x = n; } bool operator<(const Foo &y) const { return *x < *y.x; } bool operator==(int n) const { return *x == n; } }; // Disable the warning due to using memcpy/memmove with this C++ class #if defined(__GNUC__) && __GNUC__ >= 8 _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wclass-memaccess\"") #endif // Define a M*LIB array of such class ARRAY_DEF_AS(array_foo, array_foo_t, array_foo_it_t, Foo, M_CLASS_OPLIST(Foo)) #define M_OPL_array_foo_t() ARRAY_OPLIST(array_foo, M_CLASS_OPLIST(Foo)) #if defined(__GNUC__) && __GNUC__ >= 8 _Pragma("GCC diagnostic pop") #endif static void test_cplusplus(void) { int n = 100; M_LET(a, array_foo_t) { Foo b; for(int i = 0; i < n; i++) { b = i; array_foo_push_back(a, b); } array_foo_it_t it; int j = 0; for(array_foo_it(it, a); !array_foo_end_p(it); array_foo_next(it)) { assert( *array_foo_cref(it) == j); j++; } assert(j == n); } } #else static void test_cplusplus(void) { // Nothing to do } #endif int main(void) { test_uint(); test_mpz(); test_d(); test_str(); test_double(); test_cplusplus(); testobj_final_check(); exit(0); }