diff options
author | Sven Gothel <[email protected]> | 2021-01-04 02:43:24 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2021-01-04 02:43:24 +0100 |
commit | cd1ce0ce606a4dd8db3d838cc3d07d5ac8224470 (patch) | |
tree | 867e67a24a12ffdcaa5bbbf81c3daa313e48e4ed /test | |
parent | defb6f4e62e5cc19ffc2353565ff1a546e499296 (diff) |
Reinstate 'test_cow_darray_01' for general test; Add 'test_cow_iterator_01' for full 'cow_[ro|rw]_iterator' test.
Diffstat (limited to 'test')
-rw-r--r-- | test/CMakeLists.txt | 1 | ||||
-rw-r--r-- | test/test_cow_darray_01.cpp | 312 | ||||
-rw-r--r-- | test/test_cow_darray_perf01.cpp | 62 | ||||
-rw-r--r-- | test/test_cow_iterator_01.cpp | 600 |
4 files changed, 759 insertions, 216 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ca3cdcb..c501809 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -23,6 +23,7 @@ set( SOURCES_IDIOMATIC_EXAMPLES test_lfringbuffer11.cpp test_mm_sc_drf_00.cpp test_mm_sc_drf_01.cpp + test_cow_iterator_01.cpp test_cow_darray_01.cpp test_cow_darray_perf01.cpp test_hashset_perf01.cpp diff --git a/test/test_cow_darray_01.cpp b/test/test_cow_darray_01.cpp index 4e01162..b45baa5 100644 --- a/test/test_cow_darray_01.cpp +++ b/test/test_cow_darray_01.cpp @@ -27,7 +27,6 @@ #include <cstring> #include <random> #include <vector> -#include <type_traits> #define CATCH_CONFIG_RUNNER // #define CATCH_CONFIG_MAIN @@ -43,7 +42,7 @@ #include <jau/counting_allocator.hpp> /** - * This unit test module tests jau::darray, jau::cow_darray and jau::cow_vector in detail. + * Test general use of jau::darray, jau::cow_darray and jau::cow_vector. */ using namespace jau; @@ -210,58 +209,43 @@ static void test_00_seq_fill_unique_itr(T& data, const std::size_t size) { /**************************************************************************************** ****************************************************************************************/ -template< class Iter > -static void print_iterator_info(const std::string& typedefname, - typename std::enable_if< - std::is_class<Iter>::value - >::type* = 0 -) { - jau::type_cue<Iter>::print(typedefname); - jau::type_cue<typename Iter::iterator_category>::print(typedefname+"::iterator_category"); - jau::type_cue<typename Iter::iterator_type>::print(typedefname+"::iterator_type"); - jau::type_cue<typename Iter::value_type>::print(typedefname+"::value_type"); - jau::type_cue<typename Iter::reference>::print(typedefname+"::reference"); - jau::type_cue<typename Iter::pointer>::print(typedefname+"::pointer"); -} +template<class T> +static bool test_01_seq_fill_list_idx(const std::string& type_id, const std::size_t size0, const std::size_t reserve0) { + (void)type_id; -template<class Iter> -static void print_iterator_info(const std::string& typedefname, - typename std::enable_if< - !std::is_class<Iter>::value - >::type* = 0 -) { - jau::type_cue<Iter>::print(typedefname); -} + T data; + REQUIRE(0 == data.get_allocator().memory_usage); + REQUIRE(data.size() == 0); + REQUIRE(data.capacity() == 0); -template<class T> -static bool test_00_inspect_iterator_types(const std::string& type_id) { - typedef typename T::size_type T_size_t; - typedef typename T::difference_type T_difference_t; - - printf("**** Type Info: %s\n", type_id.c_str()); - jau::type_cue<T>::print("T"); - jau::type_cue<typename T::value_type>::print("T::value_type"); - jau::type_cue<T_size_t>::print("T::size_type"); - jau::type_cue<T_difference_t>::print("T::difference_type"); - jau::type_cue<typename T::reference>::print("T::reference"); - jau::type_cue<typename T::pointer>::print("T::pointer"); - print_iterator_info<typename T::iterator>("T::iterator"); - print_iterator_info<typename T::const_iterator>("T::const_iterator"); - printf("\n\n"); - - return true; -} + if( 0 < reserve0 ) { + data.reserve(reserve0); + REQUIRE(data.size() == 0); + REQUIRE(0 != data.get_allocator().memory_usage); + REQUIRE(data.capacity() == reserve0); + } -/**************************************************************************************** - ****************************************************************************************/ + test_00_seq_fill(data, size0); + REQUIRE(0 != data.get_allocator().memory_usage); + REQUIRE(data.size() == size0); + test_00_list_idx(data, false); + REQUIRE(0 != data.get_allocator().memory_usage); + REQUIRE(data.size() == size0); + + data.clear(); + REQUIRE(data.size() == 0); + // REQUIRE(0 == data.get_allocator().memory_usage); + return data.size() == 0; +} template<class T> -static bool test_01_validate_index_ops(const std::string& type_id, const std::size_t size0, const std::size_t reserve0) { +static bool test_01_seq_fill_list_itr(const std::string& type_id, const std::size_t size0, const std::size_t reserve0) { (void)type_id; T data; REQUIRE(0 == data.get_allocator().memory_usage); REQUIRE(data.size() == 0); + REQUIRE(data.capacity() == 0); if( 0 < reserve0 ) { data.reserve(reserve0); @@ -274,7 +258,7 @@ static bool test_01_validate_index_ops(const std::string& type_id, const std::si REQUIRE(0 != data.get_allocator().memory_usage); REQUIRE(data.size() == size0); - test_00_list_idx(data, false); + test_00_list_itr(data, false); REQUIRE(0 != data.get_allocator().memory_usage); REQUIRE(data.size() == size0); @@ -285,96 +269,42 @@ static bool test_01_validate_index_ops(const std::string& type_id, const std::si } template<class T> -static void test_const_iterator_equal(typename T::const_iterator& citer1, typename T::const_iterator& citer2) -{ - REQUIRE( ( citer1 == citer2 ) == true); // iter op==(iter1, iter2) - REQUIRE( ( citer1 != citer2 ) == false); // iter op!=(iter1, iter2) - REQUIRE( ( *citer1 == *citer2 ) == true); // iter op*() and value_type == - REQUIRE( ( *citer1 != *citer2 ) == false); // iter op*() and value_type != -} -template<class T> -static void test_const_iterator_notequal(typename T::const_iterator& citer1, typename T::const_iterator& citer2) -{ - REQUIRE( ( citer1 == citer2 ) == false); // iter op==(iter1, iter2) - REQUIRE( ( citer1 != citer2 ) == true); // iter op!=(iter1, iter2) - REQUIRE( ( *citer1 == *citer2 ) == false); // iter op*() and value_type == - REQUIRE( ( *citer1 != *citer2 ) == true); // iter op*() and value_type != -} +static bool test_02_seq_fillunique_find_idx(const std::string& type_id, const std::size_t size0, const std::size_t reserve0) { + (void)type_id; -template<class T> -static void test_const_iterator_compare(const typename T::size_type size, - typename T::const_iterator& cbegin, - typename T::const_iterator& cend, - typename T::const_iterator& citer1, typename T::const_iterator& citer2, - const typename T::difference_type citer1_idx, - const typename T::difference_type citer2_idx) -{ - typename T::difference_type d_size = static_cast<typename T::difference_type>(size); - typename T::difference_type distance = citer2_idx - citer1_idx; - // iter op-(iter1, iter2) - REQUIRE( ( cend - cbegin ) == d_size); - REQUIRE( ( citer2 - cbegin ) == citer2_idx); - REQUIRE( ( citer1 - cbegin ) == citer1_idx); - REQUIRE( ( cend - citer1 ) == d_size - citer1_idx); - REQUIRE( ( cend - citer2 ) == d_size - citer2_idx); - REQUIRE( ( citer2 - citer1 ) == distance); - - // iter op-(iter, difference_type) and iter op==(iter1, iter2) - REQUIRE( ( citer1 - citer1_idx ) == cbegin); - REQUIRE( ( citer2 - citer2_idx ) == cbegin); - REQUIRE( ( citer2 - distance ) == citer1); - - // iter op+(iter, difference_type) and iter op==(iter1, iter2) - { - typename T::difference_type d_citer1_end = cend - citer1; - typename T::difference_type d_citer2_end = cend - citer2; - REQUIRE( ( citer1_idx + d_citer1_end ) == d_size); // validate op-(iter1, iter2) - REQUIRE( ( citer2_idx + d_citer2_end ) == d_size); // validate op-(iter1, iter2) - - REQUIRE( ( citer1 + d_citer1_end ) == cend); - REQUIRE( ( citer2 + d_citer2_end ) == cend); - } + T data; + REQUIRE(0 == data.get_allocator().memory_usage); + REQUIRE(data.size() == 0); + REQUIRE(data.capacity() == 0); - if( 0 == distance ) { - test_const_iterator_equal<T>(citer1, citer2); - REQUIRE( ( citer2 > citer1 ) == false); // iter op>(iter1, iter2) - REQUIRE( ( citer2 >= citer1 ) == true); // iter op>=(iter1, iter2) - REQUIRE( ( citer2 < citer1 ) == false); // iter op<(iter1, iter2) - REQUIRE( ( citer2 <= citer1 ) == true); // iter op<=(iter1, iter2) - } else if( distance > 0 ) { // citer2 > citer1 - test_const_iterator_notequal<T>(citer1, citer2); - REQUIRE( ( citer2 > citer1 ) == true); // iter op>(iter1, iter2) - REQUIRE( ( citer2 >= citer1 ) == true); // iter op>=(iter1, iter2) - REQUIRE( ( citer2 < citer1 ) == false); // iter op<(iter1, iter2) - REQUIRE( ( citer2 <= citer1 ) == false); // iter op<=(iter1, iter2) - } else { // distance < 0: citer2 < citer1 - REQUIRE( ( citer2 > citer1 ) == false); // iter op>(iter1, iter2) - REQUIRE( ( citer2 >= citer1 ) == false); // iter op>=(iter1, iter2) - REQUIRE( ( citer2 < citer1 ) == true); // iter op<(iter1, iter2) - REQUIRE( ( citer2 <= citer1 ) == true); // iter op<=(iter1, iter2) + if( 0 < reserve0 ) { + data.reserve(reserve0); + REQUIRE(data.size() == 0); + REQUIRE(0 != data.get_allocator().memory_usage); + REQUIRE(data.capacity() == reserve0); } -} -template<class T> -static bool test_01_validate_iterator_ops(const std::string& type_id, const std::size_t size0, const std::size_t reserve0) { - typedef typename T::const_iterator T_const_iterator_t; - typedef typename T::size_type T_size_t; + test_00_seq_fill_unique_idx(data, size0); + REQUIRE(0 != data.get_allocator().memory_usage); + REQUIRE(data.size() == size0); - (void) type_id; + test_00_seq_find_idx(data); + REQUIRE(0 != data.get_allocator().memory_usage); + REQUIRE(data.size() == size0); + + data.clear(); + REQUIRE(data.size() == 0); + // REQUIRE(0 == data.get_allocator().memory_usage); + return data.size() == 0; +} +template<class T> +static bool test_02_seq_fillunique_find_itr(const std::string& type_id, const std::size_t size0, const std::size_t reserve0) { + (void)type_id; T data; REQUIRE(0 == data.get_allocator().memory_usage); REQUIRE(data.size() == 0); REQUIRE(data.capacity() == 0); - REQUIRE(data.empty() == true); - - { - // nullptr const_iterator - typename T::const_iterator citer1 = data.cbegin(); - typename T::const_iterator citer2 = data.cbegin(); - REQUIRE(citer1 == citer2); - REQUIRE(citer2 - citer1 == 0); - } if( 0 < reserve0 ) { data.reserve(reserve0); @@ -383,66 +313,11 @@ static bool test_01_validate_iterator_ops(const std::string& type_id, const std: REQUIRE(data.capacity() == reserve0); } - test_00_seq_fill(data, size0); + test_00_seq_fill_unique_itr(data, size0); REQUIRE(0 != data.get_allocator().memory_usage); REQUIRE(data.size() == size0); - REQUIRE(data.size() <= data.capacity()); - - // const_iterator equal - { - T_size_t size = data.size(); - T_const_iterator_t cbegin = data.cbegin(); - T_const_iterator_t cend = data.cend(); - T_const_iterator_t citer1 = data.cbegin(); - T_const_iterator_t citer2 = data.cbegin(); - test_const_iterator_compare<T>(size, cbegin, cend, citer1, citer2, 0, 0); - } - - // const_iterator op++(), op--(), op++(int), op+=(difference_type), op+(iter a, difference_type) .. - { - T_size_t size = data.size(); - T_const_iterator_t cbegin = data.cbegin(); - T_const_iterator_t cend = data.cend(); - T_const_iterator_t citer1 = data.cbegin(); - { - T_const_iterator_t citer2 = data.cbegin(); - test_const_iterator_compare<T>(size, cbegin, cend, citer1, citer2, 0, 0); - - // iter op++() - citer2++; - test_const_iterator_compare<T>(size, cbegin, cend, citer1, citer2, 0, 1); - - citer1++; - test_const_iterator_compare<T>(size, cbegin, cend, citer1, citer2, 1, 1); - - // iter op--() - citer2--; - test_const_iterator_compare<T>(size, cbegin, cend, citer1, citer2, 1, 0); - - citer1--; - test_const_iterator_compare<T>(size, cbegin, cend, citer1, citer2, 0, 0); - - // iter op++() - citer2++; - test_const_iterator_compare<T>(size, cbegin, cend, citer1, citer2, 0, 1); - REQUIRE( ( *citer2 == *(cbegin+1) ) == true); // iter op*(), op+(iter, difference_type) and value_type == - REQUIRE( ( *citer2 == cbegin[1] ) == true); // iter op*(), op[](difference_type) and value_type == - - // iter op++() - citer2++; - test_const_iterator_compare<T>(size, cbegin, cend, citer1, citer2, 0, 2); - REQUIRE( ( *citer2 == *(cbegin+2) ) == true); // iter op*(), op+(iter, difference_type) and value_type == - REQUIRE( ( *citer2 == cbegin[2] ) == true); // iter op*(), op[](difference_type) and value_type == - - // iter op++() - citer2++; - test_const_iterator_compare<T>(size, cbegin, cend, citer1, citer2, 0, 3); - REQUIRE( ( *citer2 == *(cbegin+3) ) == true); // iter op*(), op+(iter, difference_type) and value_type == - REQUIRE( ( *citer2 == cbegin[3] ) == true); // iter op*(), op[](difference_type) and value_type == - } - } - test_00_list_itr(data, false); + test_00_seq_find_itr(data); REQUIRE(0 != data.get_allocator().memory_usage); REQUIRE(data.size() == size0); @@ -455,35 +330,66 @@ static bool test_01_validate_iterator_ops(const std::string& type_id, const std: /**************************************************************************************** ****************************************************************************************/ -TEST_CASE( "Test 00 - Inspect all Iterator Types", "[datatype][std][vector][darray][cow_vector][cow_darray]" ) { - test_00_inspect_iterator_types< std_vector_DataType01 >("std::vector<T>"); - test_00_inspect_iterator_types< jau_darray_DataType01 >("jau::darray<T>"); - test_00_inspect_iterator_types< jau_cow_vector_DataType01 >("jau::cow_vector<T>"); - test_00_inspect_iterator_types< jau_cow_darray_DataType01 >("jau::cow_darray<T>"); +TEST_CASE( "STD Vector Test 01 - Fill Sequential and List", "[datatype][std][vector]" ) { + test_01_seq_fill_list_idx< std::vector<DataType01, counting_allocator<DataType01>> >("stdvec_fillseq_empty__", 100, 0); + test_01_seq_fill_list_idx< std::vector<DataType01, counting_allocator<DataType01>> >("stdvec_fillseq_reserve", 100, 100); + + test_01_seq_fill_list_itr< std::vector<DataType01, counting_allocator<DataType01>> >("stdvec_fillseq_empty__", 100, 0); + test_01_seq_fill_list_itr< std::vector<DataType01, counting_allocator<DataType01>> >("stdvec_fillseq_reserve", 100, 100); +} + +TEST_CASE( "STD Vector Test 02 - Fill Unique and Find-Each", "[datatype][std][vector]" ) { + test_02_seq_fillunique_find_idx< std::vector<DataType01, counting_allocator<DataType01>> >("stdvec_filluni_empty__", 100, 0); + test_02_seq_fillunique_find_idx< std::vector<DataType01, counting_allocator<DataType01>> >("stdvec_filluni_reserve", 100, 100); + + test_02_seq_fillunique_find_itr< std::vector<DataType01, counting_allocator<DataType01>> >("stdvec_filluni_empty__", 100, 0); + test_02_seq_fillunique_find_itr< std::vector<DataType01, counting_allocator<DataType01>> >("stdvec_filluni_reserve", 100, 100); +} + +TEST_CASE( "JAU COW_Vector Test 11 - Fill Sequential and List", "[datatype][jau][cow_vector]" ) { + // test_01_seq_fill_list_idx< jau::cow_vector<DataType01, counting_allocator<DataType01>> >("cowstdvec_fillseq_empty__", 100, 0); + // test_01_seq_fill_list_idx< jau::cow_vector<DataType01, counting_allocator<DataType01>> >("cowstdvec_fillseq_reserve", 100, 100); + + test_01_seq_fill_list_itr< jau::cow_vector<DataType01, counting_allocator<DataType01>> >("cowstdvec_fillseq_empty__", 100, 0); + test_01_seq_fill_list_itr< jau::cow_vector<DataType01, counting_allocator<DataType01>> >("cowstdvec_fillseq_reserve", 100, 100); } -TEST_CASE( "STD Vector Test 01 - Validate Iterator and Index Operations", "[datatype][std][vector]" ) { - // test_01_validate_index_ops< std_vector_DataType01 >("std::vector<T>", 100, 0); - // test_01_validate_index_ops< std_vector_DataType01 >("std::vector<T>", 100, 100); +TEST_CASE( "JAU COW_Vector Test 12 - Fill Unique and Find-Each", "[datatype][jau][cow_vector]" ) { + // test_02_seq_fillunique_find_idx< jau::cow_vector<DataType01, counting_allocator<DataType01>> >("cowstdvec_filluni_empty__", 100, 0); + // test_02_seq_fillunique_find_idx< jau::cow_vector<DataType01, counting_allocator<DataType01>> >("cowstdvec_filluni_reserve", 100, 100); - test_01_validate_iterator_ops< std_vector_DataType01 >("std::vector<T>", 100, 0); - // test_01_validate_iterator_ops< std_vector_DataType01 >("std::vector<T>", 100, 100); + test_02_seq_fillunique_find_itr< jau::cow_vector<DataType01, counting_allocator<DataType01>> >("cowstdvec_filluni_empty__", 100, 0); + test_02_seq_fillunique_find_itr< jau::cow_vector<DataType01, counting_allocator<DataType01>> >("cowstdvec_filluni_reserve", 100, 100); } -TEST_CASE( "JAU DArray Test 02 - Validate Iterator and Index Operations", "[datatype][jau][darray]" ) { - // test_01_validate_index_ops< jau_darray_DataType01 >("jau::darray<T>", 100, 0); - // test_01_validate_index_ops< jau_darray_DataType01 >("jau::darray<T>", 100, 100); +TEST_CASE( "JAU DArray Test 21 - Fill Sequential and List", "[datatype][jau][darray]" ) { + test_01_seq_fill_list_idx< jau::darray<DataType01, counting_allocator<DataType01>> >("darray_fillseq_empty__", 100, 0); + test_01_seq_fill_list_idx< jau::darray<DataType01, counting_allocator<DataType01>> >("darray_fillseq_reserve", 100, 100); - test_01_validate_iterator_ops< jau_darray_DataType01 >("jau::darray<T>", 100, 0); - // test_01_validate_iterator_ops< jau_darray_DataType01 >("jau::darray<T>", 100, 100); + test_01_seq_fill_list_itr< jau::darray<DataType01, counting_allocator<DataType01>> >("darray_fillseq_empty__", 100, 0); + test_01_seq_fill_list_itr< jau::darray<DataType01, counting_allocator<DataType01>> >("darray_fillseq_reserve", 100, 100); } -TEST_CASE( "JAU COW_Vector Test 11 - Validate Iterator Operations", "[datatype][jau][cow_vector]" ) { - test_01_validate_iterator_ops< jau_cow_vector_DataType01 >("jau::cow_vector<T>", 100, 0); - // test_01_validate_iterator_ops< jau_cow_vector_DataType01 >("jau::cow_vector<T>", 100, 100); +TEST_CASE( "JAU DArray Test 22 - Fill Unique and Find-Each", "[datatype][jau][darray]" ) { + test_02_seq_fillunique_find_idx< jau::darray<DataType01, counting_allocator<DataType01>> >("darray_filluni_empty__", 100, 0); + test_02_seq_fillunique_find_idx< jau::darray<DataType01, counting_allocator<DataType01>> >("darray_filluni_reserve", 100, 100); + + test_02_seq_fillunique_find_itr< jau::darray<DataType01, counting_allocator<DataType01>> >("darray_filluni_empty__", 100, 0); + test_02_seq_fillunique_find_itr< jau::darray<DataType01, counting_allocator<DataType01>> >("darray_filluni_reserve", 100, 100); } -TEST_CASE( "JAU COW_DArray Test 21 - Validate Iterator Operations", "[datatype][jau][cow_darray]" ) { - test_01_validate_iterator_ops< jau_cow_darray_DataType01 >("jau::cow_darray<T>", 100, 0); - // test_01_validate_iterator_ops< jau_cow_darray_DataType01 >("jau::cow_darray<T>", 100, 100); +TEST_CASE( "JAU COW_DArray Test 31 - Fill Sequential and List", "[datatype][jau][cow_darray]" ) { + // test_01_seq_fill_list_idx< jau::cow_darray<DataType01, counting_allocator<DataType01>> >("cowdarray_fillseq_empty__", 100, 0); + // test_01_seq_fill_list_idx< jau::cow_darray<DataType01, counting_allocator<DataType01>> >("cowdarray_fillseq_reserve", 100, 100); + + test_01_seq_fill_list_itr< jau::cow_darray<DataType01, counting_allocator<DataType01>> >("cowdarray_fillseq_empty__", 100, 0); + test_01_seq_fill_list_itr< jau::cow_darray<DataType01, counting_allocator<DataType01>> >("cowdarray_fillseq_reserve", 100, 100); +} + +TEST_CASE( "JAU COW_DArray Test 32 - Fill Unique and Find-Each", "[datatype][jau][cow_darray]" ) { + // test_02_seq_fillunique_find_idx< jau::cow_darray<DataType01, counting_allocator<DataType01>> >("cowdarray_filluni_empty__", 100, 0); + // test_02_seq_fillunique_find_idx< jau::cow_darray<DataType01, counting_allocator<DataType01>> >("cowdarray_filluni_reserve", 100, 100); + + test_02_seq_fillunique_find_itr< jau::cow_darray<DataType01, counting_allocator<DataType01>> >("cowdarray_filluni_empty__", 100, 0); + test_02_seq_fillunique_find_itr< jau::cow_darray<DataType01, counting_allocator<DataType01>> >("cowdarray_filluni_reserve", 100, 100); } diff --git a/test/test_cow_darray_perf01.cpp b/test/test_cow_darray_perf01.cpp index 6223395..f4cf758 100644 --- a/test/test_cow_darray_perf01.cpp +++ b/test/test_cow_darray_perf01.cpp @@ -41,11 +41,17 @@ #include <jau/cow_vector.hpp> #include <jau/counting_allocator.hpp> +/** + * Performance test of jau::darray, jau::cow_darray and jau::cow_vector. + */ using namespace jau; static uint8_t start_addr_b[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static Addr48Bit start_addr(start_addr_b); +// #define USE_ITER_ALGO 1 +// #define USE_EMPLACE 1 + /**************************************************************************************** ****************************************************************************************/ @@ -63,6 +69,13 @@ DataType01 * findDataSet01_idx(T& data, DataType01 const & elem) noexcept { template<class T> const DataType01 * findDataSet01_itr(T& data, DataType01 const & elem) noexcept { +#if defined(USE_ITER_ALGO) + typename T::const_iterator end = data.cend(); + auto it = std::find( data.cbegin(), end, elem); + if( it != end ) { + return &(*it); + } +#else typename T::const_iterator iter = data.cbegin(); typename T::const_iterator end = data.cend(); for(; iter != end ; ++iter) { @@ -70,6 +83,7 @@ const DataType01 * findDataSet01_itr(T& data, DataType01 const & elem) noexcept return &(*iter); } } +#endif return nullptr; } @@ -84,12 +98,16 @@ static void test_00_list_idx(T& data) { template<class T> static void test_00_list_itr(T& data) { +#if 0 && defined(USE_ITER_ALGO) + std::for_each(data.cbegin(), data.cend(), [](const DataType01 & e) { e.nop(); }); +#else typename T::const_iterator iter = data.cbegin(); typename T::const_iterator end = data.cend(); for(; iter != end ; ++iter) { const DataType01 & e = *iter; e.nop(); } +#endif } template<class T, typename Size_type> @@ -132,7 +150,11 @@ static void test_00_seq_fill(T& data, const Size_type size) { Size_type i=0; for(; i<size && a0.next(); i++) { +#if defined(USE_EMPLACE) + data.emplace_back( a0, static_cast<uint8_t>(1) ); +#else data.push_back( std::move( DataType01(a0, static_cast<uint8_t>(1)) ) ); +#endif } REQUIRE(i == data.size()); } @@ -146,7 +168,11 @@ static void test_00_seq_fill_unique_idx(T& data, const Size_type size) { DataType01 elem(a0, static_cast<uint8_t>(1)); DataType01* exist = findDataSet01_idx<T, Size_type>(data, elem); if( nullptr == exist ) { - data.push_back( std::move(elem) ); +#if defined(USE_EMPLACE) + data.emplace_back( a0, static_cast<uint8_t>(1) ); +#else + data.push_back( std::move( DataType01(a0, static_cast<uint8_t>(1)) ) ); +#endif fi++; } } @@ -162,7 +188,11 @@ static void test_00_seq_fill_unique_itr(T& data, const Size_type size) { DataType01 elem(a0, static_cast<uint8_t>(1)); const DataType01* exist = findDataSet01_itr<T>(data, elem); if( nullptr == exist ) { - data.push_back( std::move(elem) ); +#if defined(USE_EMPLACE) + data.emplace_back( a0, static_cast<uint8_t>(1) ); +#else + data.push_back( std::move( DataType01(a0, static_cast<uint8_t>(1)) ) ); +#endif fi++; } } @@ -353,7 +383,9 @@ template<class T, typename Size_type> static bool benchmark_fillseq_list_idx(const std::string& title_pre, const std::string& type_id, const bool do_rserv) { if( catch_perf_analysis ) { - test_01_seq_fill_list_idx<T, Size_type>(type_id, 100000, do_rserv? 100000 : 0, false); + BENCHMARK(title_pre+" FillSeq_List 1000") { + return test_01_seq_fill_list_idx<T, Size_type>(type_id, 1000, do_rserv? 1000 : 0, false); + }; return true; } if( catch_auto_run ) { @@ -378,7 +410,9 @@ template<class T, typename Size_type> static bool benchmark_fillseq_list_itr(const std::string& title_pre, const std::string& type_id, const bool do_rserv) { if( catch_perf_analysis ) { - test_01_seq_fill_list_itr<T, Size_type>(type_id, 100000, do_rserv? 100000 : 0, false); + BENCHMARK(title_pre+" FillSeq_List 1000") { + return test_01_seq_fill_list_itr<T, Size_type>(type_id, 1000, do_rserv? 1000 : 0, false); + }; return true; } if( catch_auto_run ) { @@ -404,7 +438,9 @@ template<class T, typename Size_type> static bool benchmark_fillunique_find_idx(const std::string& title_pre, const std::string& type_id, const bool do_rserv) { if( catch_perf_analysis ) { - test_02_seq_fillunique_find_idx<T, Size_type>(type_id, 100000, do_rserv? 100000 : 0, false); + BENCHMARK(title_pre+" FillUni_List 1000") { + return test_02_seq_fillunique_find_idx<T, Size_type>(type_id, 1000, do_rserv? 1000 : 0, false); + }; return true; } if( catch_auto_run ) { @@ -486,6 +522,10 @@ static bool benchmark_fillunique_find_itr_rserv(const std::string& title_pre, co TEST_CASE( "Memory Footprint 01 - Fill Sequential and List", "[datatype][footprint]" ) { if( catch_perf_analysis ) { +#if 1 + footprint_fillseq_list_itr< jau::cow_vector<DataType01, counting_allocator<DataType01>>, std::size_t >("cowstdvec_empty_", false); + footprint_fillseq_list_itr< jau::cow_darray<DataType01, counting_allocator<DataType01>>, jau::nsize_t >("cowdarray_empty_", false); +#endif return; } footprint_fillseq_list_itr< std::vector<DataType01, counting_allocator<DataType01>>, std::size_t >("stdvec_empty_", false); @@ -503,7 +543,7 @@ TEST_CASE( "Memory Footprint 01 - Fill Sequential and List", "[datatype][footpri TEST_CASE( "Perf Test 01 - Fill Sequential and List, empty and reserve", "[datatype][sequential]" ) { if( catch_perf_analysis ) { -#if 0 +#if 1 benchmark_fillseq_list_itr< std::vector<DataType01, counting_allocator<DataType01>>, std::size_t >("STD_Vector_empty_itr", "stdvec_empty_", false); benchmark_fillseq_list_itr< jau::darray<DataType01, counting_allocator<DataType01>, jau::nsize_t>, jau::nsize_t >("JAU_DArray_empty_itr", "darray_empty_", false); #endif @@ -530,15 +570,11 @@ TEST_CASE( "Perf Test 01 - Fill Sequential and List, empty and reserve", "[datat TEST_CASE( "Perf Test 02 - Fill Unique and List, empty and reserve", "[datatype][unique]" ) { if( catch_perf_analysis ) { #if 1 - // benchmark_fillunique_find_itr< jau::cow_vector<DataType01, counting_allocator<DataType01>>, std::size_t >("COW_Vector_empty_itr", "cowstdvec_empty_", false); - // benchmark_fillunique_find_itr< jau::cow_darray<DataType01, counting_allocator<DataType01>>, std::size_t >("COW_DArray_empty_itr", "cowdarray_empty_", false); - - benchmark_fillunique_find_itr_rserv< jau::cow_vector<DataType01, counting_allocator<DataType01>>, std::size_t >("COW_Vector_rserv_itr", "cowstdvec_rserv_"); - benchmark_fillunique_find_itr_rserv< jau::cow_darray<DataType01, counting_allocator<DataType01>>, std::size_t >("COW_DArray_rserv_itr", "cowdarray_rserv_"); + // benchmark_fillunique_find_itr_rserv< jau::cow_vector<DataType01, counting_allocator<DataType01>>, std::size_t >("COW_Vector_rserv_itr", "cowstdvec_rserv_"); + // benchmark_fillunique_find_itr_rserv< jau::cow_darray<DataType01, counting_allocator<DataType01>>, jau::nsize_t >("COW_DArray_rserv_itr", "cowdarray_rserv_"); benchmark_fillunique_find_itr< jau::cow_vector<DataType01, counting_allocator<DataType01>>, std::size_t >("COW_Vector_empty_itr", "cowstdvec_empty_", false); - benchmark_fillunique_find_itr< jau::cow_darray<DataType01, counting_allocator<DataType01>>, std::size_t >("COW_DArray_empty_itr", "cowdarray_empty_", false); - + benchmark_fillunique_find_itr< jau::cow_darray<DataType01, counting_allocator<DataType01>>, jau::nsize_t >("COW_DArray_empty_itr", "cowdarray_empty_", false); #endif return; } diff --git a/test/test_cow_iterator_01.cpp b/test/test_cow_iterator_01.cpp new file mode 100644 index 0000000..7057d51 --- /dev/null +++ b/test/test_cow_iterator_01.cpp @@ -0,0 +1,600 @@ +/* + * Author: Sven Gothel <[email protected]> + * Copyright (c) 2020 Gothel Software e.K. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include <iostream> +#include <cassert> +#include <cinttypes> +#include <cstring> +#include <random> +#include <vector> +#include <type_traits> + +#define CATCH_CONFIG_RUNNER +// #define CATCH_CONFIG_MAIN +#include <catch2/catch_amalgamated.hpp> +#include <jau/test/catch2_ext.hpp> + +#include "test_datatype01.hpp" + +#include <jau/basic_types.hpp> +#include <jau/darray.hpp> +#include <jau/cow_darray.hpp> +#include <jau/cow_vector.hpp> +#include <jau/counting_allocator.hpp> + +/** + * Test jau:cow_[ro|rw]_iterator special properties from jau::cow_darray and jau::cow_vector in detail. + * <p> + * Normal random-access iterator operations are also tested from std::vector, jau::darray, jau::cow_darray and jau::cow_vector in detail, + * which either use the std::iterator (1s two container) or jau:cow_[ro|rw]_iterator (latter two cow-container). + * </p> + */ +using namespace jau; + +static uint8_t start_addr_b[] = {0x20, 0x26, 0x2A, 0x01, 0x20, 0x10}; +static Addr48Bit start_addr(start_addr_b); + +typedef std::vector<DataType01, counting_allocator<DataType01>> std_vector_DataType01; +typedef jau::darray<DataType01, counting_allocator<DataType01>> jau_darray_DataType01; +typedef jau::cow_vector<DataType01, counting_allocator<DataType01>> jau_cow_vector_DataType01; +typedef jau::cow_darray<DataType01, counting_allocator<DataType01>> jau_cow_darray_DataType01; + +JAU_TYPENAME_CUE_ALL(std_vector_DataType01) +JAU_TYPENAME_CUE_ALL(jau_darray_DataType01) +JAU_TYPENAME_CUE_ALL(jau_cow_vector_DataType01) +JAU_TYPENAME_CUE_ALL(jau_cow_darray_DataType01) + +template<class T> +const DataType01 * findDataSet01_itr(T& data, DataType01 const & elem) noexcept { + typename T::const_iterator iter = data.cbegin(); + typename T::const_iterator end = data.cend(); + for(; iter != end ; ++iter) { + if( elem == *iter ) { + return &(*iter); + } + } + return nullptr; +} + +template<class T> +static void test_00_list_itr(T& data, const bool show) { + Addr48Bit a0(start_addr); + typename T::const_iterator iter = data.cbegin(); + typename T::const_iterator end = data.cend(); + for(std::size_t i = 0; iter != end && a0.next(); ++iter, ++i) { + const DataType01 & e = *iter; + e.nop(); + if( show ) { + printf("data[%zu]: %s\n", i, e.toString().c_str()); + } + REQUIRE(e.address == a0); + } +} + +template<class T> +static void test_00_seq_find_itr(T& data) { + Addr48Bit a0(start_addr); + const std::size_t size = data.size(); + std::size_t fi = 0, i=0; + + for(; i<size && a0.next(); i++) { + DataType01 elem(a0, static_cast<uint8_t>(1)); + const DataType01 *found = findDataSet01_itr(data, elem); + if( nullptr != found ) { + fi++; + found->nop(); + } + } + REQUIRE(fi == i); +} + +template<class T> +static void test_00_seq_fill(T& data, const std::size_t size) { + Addr48Bit a0(start_addr); + std::size_t i=0; + + for(; i<size && a0.next(); i++) { + data.emplace_back( a0, static_cast<uint8_t>(1) ); + } + if( i != data.size() ) { + test_00_list_itr(data, true); + printf("a0 %s\n", a0.toString().c_str()); + printf("Size %zu, expected %zu, iter %zu\n", static_cast<std::size_t>(data.size()), size, i); + } + REQUIRE(i == data.size()); +} + +/**************************************************************************************** + ****************************************************************************************/ + +template< class Iter > +static void print_iterator_info(const std::string& typedefname, + typename std::enable_if< + std::is_class<Iter>::value + >::type* = 0 +) { + jau::type_cue<Iter>::print(typedefname); + jau::type_cue<typename Iter::iterator_category>::print(typedefname+"::iterator_category"); + jau::type_cue<typename Iter::iterator_type>::print(typedefname+"::iterator_type"); + jau::type_cue<typename Iter::value_type>::print(typedefname+"::value_type"); + jau::type_cue<typename Iter::reference>::print(typedefname+"::reference"); + jau::type_cue<typename Iter::pointer>::print(typedefname+"::pointer"); +} + +template<class Iter> +static void print_iterator_info(const std::string& typedefname, + typename std::enable_if< + !std::is_class<Iter>::value + >::type* = 0 +) { + jau::type_cue<Iter>::print(typedefname); +} + +template<class T> +static bool test_00_inspect_iterator_types(const std::string& type_id) { + typedef typename T::size_type T_size_t; + typedef typename T::difference_type T_difference_t; + + printf("**** Type Info: %s\n", type_id.c_str()); + jau::type_cue<T>::print("T"); + jau::type_cue<typename T::value_type>::print("T::value_type"); + jau::type_cue<T_size_t>::print("T::size_type"); + jau::type_cue<T_difference_t>::print("T::difference_type"); + jau::type_cue<typename T::reference>::print("T::reference"); + jau::type_cue<typename T::pointer>::print("T::pointer"); + print_iterator_info<typename T::iterator>("T::iterator"); + print_iterator_info<typename T::const_iterator>("T::const_iterator"); + printf("\n\n"); + + return true; +} + +/**************************************************************************************** + ****************************************************************************************/ + +template<class T> +static bool test_01_validate_index_ops(const std::string& type_id, const std::size_t size0, const std::size_t reserve0) { + (void)type_id; + + T data; + REQUIRE(0 == data.get_allocator().memory_usage); + REQUIRE(data.size() == 0); + + if( 0 < reserve0 ) { + data.reserve(reserve0); + REQUIRE(data.size() == 0); + REQUIRE(0 != data.get_allocator().memory_usage); + REQUIRE(data.capacity() == reserve0); + } + + test_00_seq_fill(data, size0); + REQUIRE(0 != data.get_allocator().memory_usage); + REQUIRE(data.size() == size0); + + test_00_list_idx(data, false); + REQUIRE(0 != data.get_allocator().memory_usage); + REQUIRE(data.size() == size0); + + data.clear(); + REQUIRE(data.size() == 0); + // REQUIRE(0 == data.get_allocator().memory_usage); + return data.size() == 0; +} + +template<class T, typename iterator_type> +static void test_iterator_equal(iterator_type& citer1, iterator_type& citer2) +{ + REQUIRE( ( citer1 == citer2 ) == true); // iter op==(iter1, iter2) + REQUIRE( ( citer1 != citer2 ) == false); // iter op!=(iter1, iter2) + REQUIRE( ( *citer1 == *citer2 ) == true); // iter op*() and value_type == + REQUIRE( ( *citer1 != *citer2 ) == false); // iter op*() and value_type != +} +template<class T, typename iterator_type> +static void test_iterator_notequal(iterator_type& citer1, iterator_type& citer2) +{ + REQUIRE( ( citer1 == citer2 ) == false); // iter op==(iter1, iter2) + REQUIRE( ( citer1 != citer2 ) == true); // iter op!=(iter1, iter2) + REQUIRE( ( *citer1 == *citer2 ) == false); // iter op*() and value_type == + REQUIRE( ( *citer1 != *citer2 ) == true); // iter op*() and value_type != +} + +template<class T, typename iterator_type> +static void test_iterator_compare(const typename T::size_type size, + iterator_type& begin, + iterator_type& end, + iterator_type& citer1, typename T::const_iterator& citer2, + const typename T::difference_type citer1_idx, + const typename T::difference_type citer2_idx) +{ + typename T::difference_type d_size = static_cast<typename T::difference_type>(size); + typename T::difference_type distance = citer2_idx - citer1_idx; + // iter op-(iter1, iter2) + REQUIRE( ( end - begin ) == d_size); + REQUIRE( ( citer2 - begin ) == citer2_idx); + REQUIRE( ( citer1 - begin ) == citer1_idx); + REQUIRE( ( end - citer1 ) == d_size - citer1_idx); + REQUIRE( ( end - citer2 ) == d_size - citer2_idx); + REQUIRE( ( citer2 - citer1 ) == distance); + + // iter op-(iter, difference_type) and iter op==(iter1, iter2) + REQUIRE( ( citer1 - citer1_idx ) == begin); + REQUIRE( ( citer2 - citer2_idx ) == begin); + REQUIRE( ( citer2 - distance ) == citer1); + + // iter op+(iter, difference_type) and iter op==(iter1, iter2) + { + typename T::difference_type d_citer1_end = end - citer1; + typename T::difference_type d_citer2_end = end - citer2; + REQUIRE( ( citer1_idx + d_citer1_end ) == d_size); // validate op-(iter1, iter2) + REQUIRE( ( citer2_idx + d_citer2_end ) == d_size); // validate op-(iter1, iter2) + + REQUIRE( ( citer1 + d_citer1_end ) == end); + REQUIRE( ( citer2 + d_citer2_end ) == end); + } + + if( 0 == distance ) { + test_iterator_equal<T, iterator_type>(citer1, citer2); + REQUIRE( ( citer2 > citer1 ) == false); // iter op>(iter1, iter2) + REQUIRE( ( citer2 >= citer1 ) == true); // iter op>=(iter1, iter2) + REQUIRE( ( citer2 < citer1 ) == false); // iter op<(iter1, iter2) + REQUIRE( ( citer2 <= citer1 ) == true); // iter op<=(iter1, iter2) + } else if( distance > 0 ) { // citer2 > citer1 + test_iterator_notequal<T, iterator_type>(citer1, citer2); + REQUIRE( ( citer2 > citer1 ) == true); // iter op>(iter1, iter2) + REQUIRE( ( citer2 >= citer1 ) == true); // iter op>=(iter1, iter2) + REQUIRE( ( citer2 < citer1 ) == false); // iter op<(iter1, iter2) + REQUIRE( ( citer2 <= citer1 ) == false); // iter op<=(iter1, iter2) + } else { // distance < 0: citer2 < citer1 + test_iterator_notequal<T, iterator_type>(citer1, citer2); + REQUIRE( ( citer2 > citer1 ) == false); // iter op>(iter1, iter2) + REQUIRE( ( citer2 >= citer1 ) == false); // iter op>=(iter1, iter2) + REQUIRE( ( citer2 < citer1 ) == true); // iter op<(iter1, iter2) + REQUIRE( ( citer2 <= citer1 ) == true); // iter op<=(iter1, iter2) + } +} + +template<class T, typename iterator_type> +static bool test_iterator_ops(const std::string& type_id, T& data, const bool iterator_is_const) { + typedef typename T::size_type T_size_t; + + printf("**** test_iterator_ops: %s, iterator_is_const %d\n", type_id.c_str(), iterator_is_const); + print_iterator_info<iterator_type>(iterator_is_const ? "const_iterator" : "iterator"); + + { + // if !iterator_is_const, only fetch mutable iterator once -> new_store and lock + iterator_type begin = iterator_is_const ? data.cbegin() : data.begin(); + iterator_type citer1 = iterator_is_const ? data.cbegin() : begin; + iterator_type citer2 = iterator_is_const ? data.cbegin() : begin; + printf("[0]: %s == %s, dist %u\n", citer1->toString().c_str(), citer2->toString().c_str(), (unsigned int)(citer2 - citer1)); + REQUIRE(*citer1 == *citer2); + REQUIRE( citer1 == citer2); + REQUIRE(citer2 - citer1 == 0); + } + + // dereferencing, pointer, equality + { + // if !iterator_is_const, only fetch mutable iterator once -> new_store and lock + T_size_t size = data.size(); + iterator_type begin = iterator_is_const ? data.cbegin() : data.begin(); + iterator_type end = iterator_is_const ? data.cend() : begin + size; + iterator_type citer1 = iterator_is_const ? data.cbegin() : begin; + iterator_type citer2 = iterator_is_const ? data.cbegin() : begin; + + REQUIRE( ( citer1 == begin ) == true); // iter op==() + REQUIRE( ( citer2 == begin ) == true); // iter op==() + REQUIRE( ( citer1 == citer1 ) == true); // iter op==() + + REQUIRE( ( *citer1 == *begin ) == true); // iter op*(), and value_type == + REQUIRE( ( *citer2 == *begin ) == true); // iter op*(), and value_type == + REQUIRE( ( *citer1 == *citer1 ) == true); // iter op*(), and value_type == + + REQUIRE( ( citer1[1] == *(begin+1) ) == true); // iter op[](diff), op+(iter, diff), iter op*(), and value_type == + REQUIRE( ( citer2[1] == *(begin+1) ) == true); // iter op[](diff), op+(iter, diff), iter op*(), and value_type == + REQUIRE( ( citer1[1] == *(citer2+1) ) == true); // iter op[](diff), op+(iter, diff), iter op*(), and value_type == + + REQUIRE( ( citer1 != end ) == true); // iter op!=() + REQUIRE( ( citer2 != end ) == true); // iter op!=() + REQUIRE( ( *citer1 != *end ) == true); // iter op*(), and value_type == + REQUIRE( ( *citer2 != *end ) == true); // iter op*(), and value_type == + REQUIRE( ( citer1[1] != *(end+1) ) == true); // iter op[](diff), op+(iter, diff), iter op*(), and value_type == + REQUIRE( ( citer2[1] != *(end+1) ) == true); // iter op[](diff), op+(iter, diff), iter op*(), and value_type == + + REQUIRE( citer2+size-1 == end -1 ); + REQUIRE( *(citer2+size-1) == *(end -1) ); + REQUIRE( citer2[size-1] == end[-1] ); + + REQUIRE( (citer2+0)->toString() == begin[0].toString() ); + REQUIRE( (citer2+1)->toString() == begin[1].toString() ); + REQUIRE( (citer2+2)->toString() == begin[2].toString() ); + REQUIRE( (citer2+3)->toString() == begin[3].toString() ); + REQUIRE( (citer2+size-1)->toString() == (end-1)->toString() ); + + printf("[0]: %s == %s\n", (citer2+0)->toString().c_str(), begin[3].toString().c_str()); + printf("[1]: %s == %s\n", (citer2+1)->toString().c_str(), begin[3].toString().c_str()); + printf("[2]: %s == %s\n", (citer2+2)->toString().c_str(), begin[3].toString().c_str()); + printf("[3]: %s == %s\n", (citer2+3)->toString().c_str(), begin[3].toString().c_str()); + printf("[E]: %s == %s\n", (citer2+size-1)->toString().c_str(), (end-1)->toString().c_str()); + + test_iterator_compare<T, iterator_type>(size, begin, end, citer1, citer2, 0, 0); + } + + // const_iterator operations + // op++(), op--(), op++(int), op--(int), + // op+=(difference_type), op+(iter a, difference_type) .. + { + // if !iterator_is_const, only fetch mutable iterator once -> new_store and lock + T_size_t size = data.size(); + iterator_type begin = iterator_is_const ? data.cbegin() : data.begin(); + iterator_type end = iterator_is_const ? data.cend() : begin + size; + iterator_type citer1 = iterator_is_const ? data.cbegin() : begin; + { + iterator_type citer2 = iterator_is_const ? data.cbegin() : begin; + test_iterator_compare<T, iterator_type>(size, begin, end, citer1, citer2, 0, 0); + + // iter op++(int) + citer2++; + test_iterator_compare<T, iterator_type>(size, begin, end, citer1, citer2, 0, 1); + + // iter op++(int) + citer1++; + test_iterator_compare<T, iterator_type>(size, begin, end, citer1, citer2, 1, 1); + + // iter op--(int) + citer2--; + test_iterator_compare<T, iterator_type>(size, begin, end, citer1, citer2, 1, 0); + + // iter op--(int) + citer1--; + test_iterator_compare<T, iterator_type>(size, begin, end, citer1, citer2, 0, 0); + REQUIRE( citer2->toString() == begin[0].toString() ); + printf("[0]: %s == %s\n", citer2->toString().c_str(), begin[0].toString().c_str()); + + // iter op++(int) + citer2++; + test_iterator_compare<T, iterator_type>(size, begin, end, citer1, citer2, 0, 1); + REQUIRE( ( *citer2 == *(begin+1) ) == true); // iter op*(), op+(iter, difference_type) and value_type == + REQUIRE( ( *citer2 == begin[1] ) == true); // iter op*(), op[](difference_type) and value_type == + REQUIRE( citer2->toString() == begin[1].toString() ); + + // iter op++(int) + citer2++; + test_iterator_compare<T, iterator_type>(size, begin, end, citer1, citer2, 0, 2); + REQUIRE( ( *citer2 == *(begin+2) ) == true); // iter op*(), op+(iter, difference_type) and value_type == + REQUIRE( ( *citer2 == begin[2] ) == true); // iter op*(), op[](difference_type) and value_type == + REQUIRE( citer2->toString() == begin[2].toString() ); + + // iter op++(int) + citer2++; + test_iterator_compare<T, iterator_type>(size, begin, end, citer1, citer2, 0, 3); + REQUIRE( ( *citer2 == *(begin+3) ) == true); // iter op*(), op+(iter, difference_type) and value_type == + REQUIRE( ( *citer2 == begin[3] ) == true); // iter op*(), op[](difference_type) and value_type == + REQUIRE( citer2->toString() == begin[3].toString() ); + printf("[3]: %s == %s\n", citer2->toString().c_str(), begin[3].toString().c_str()); + + // iter op++() + --citer2; + --citer2; + --citer2; + test_iterator_compare<T, iterator_type>(size, begin, end, citer1, citer2, 0, 0); + REQUIRE( ( *citer2 == *(begin+0) ) == true); // iter op*(), op+(iter, difference_type) and value_type == + REQUIRE( ( *citer2 == begin[0] ) == true); // iter op*(), op[](difference_type) and value_type == + REQUIRE( citer2->toString() == begin[0].toString() ); + printf("[3]: %s == %s\n", citer2->toString().c_str(), begin[3].toString().c_str()); + } + } + return true; +} + +template<class T, typename iterator_type> +static bool test_cow_iterator_properties(const std::string& type_id, T& data, const bool iterator_is_const) { + printf("**** test_cow_iterator_properties: %s, iterator_is_const %d\n", type_id.c_str(), iterator_is_const); + print_iterator_info<iterator_type>(iterator_is_const ? "const_iterator" : "iterator"); + + // test mutable non-const 'new store' behavior + // inclusive 'iterator -> const_iterator' conversion if 'iterator_is_const == true' + typename T::const_iterator c_begin0 = data.cbegin(); // orig store + if( iterator_is_const ) { + // iterator_type is const_iterator. + // The cow_rw_iterator is being fetched via data.begin(), which creates a new store. + // The cow_rw_iterator is converted immediately to cow_ro_iterator and the cow_rw_iterator gets destructed. + // This destruction moves the cow_rw_iterator's new store into the cow container right away. + + printf("testing mutable non-const behavior incl 'iterator -> const_iterator' conversion.\n"); + + typename T::const_iterator c_begin1; + { + iterator_type m_begin1 = data.begin(); // mutable iterator first, converts to const_iterator and + // mutable iterator destructs (new_store -> cow) + c_begin1 = data.cbegin(); + REQUIRE(*c_begin1 == *m_begin1); + REQUIRE( c_begin1 == m_begin1); + REQUIRE( ( c_begin1 - m_begin1 ) == 0); + printf(" 1st store: %s == %s, dist %u\n", + c_begin1->toString().c_str(), m_begin1->toString().c_str(), (unsigned int)(c_begin1 - m_begin1)); + + REQUIRE(*c_begin1 == *c_begin0); + REQUIRE( c_begin1 != c_begin0); + REQUIRE( ( c_begin1 - c_begin0 ) != 0); + printf("1st -> 0st store: %s == %s, dist %u != 0\n", + c_begin1->toString().c_str(), c_begin0->toString().c_str(), (unsigned int)(c_begin1 - c_begin0)); + + typename T::const_iterator c_begin2; + { + iterator_type m_begin2 = data.begin(); // mutable iterator first, converts to const_iterator and + // mutable iterator destructs (new_store -> cow) + c_begin2 = data.cbegin(); + REQUIRE(*c_begin2 == *m_begin2); + REQUIRE( c_begin2 == m_begin2); + REQUIRE( ( c_begin2 - m_begin2 ) == 0); + printf(" 2nd store: %s == %s, dist %u\n", + c_begin2->toString().c_str(), m_begin2->toString().c_str(), (unsigned int)(c_begin2 - m_begin2)); + + REQUIRE(*c_begin2 == *c_begin1); + REQUIRE( c_begin2 != c_begin1); + REQUIRE( ( c_begin2 - c_begin1 ) != 0); + printf("2nd -> 1st store: %s == %s, dist %u != 0\n", + c_begin1->toString().c_str(), c_begin0->toString().c_str(), (unsigned int)(c_begin1 - c_begin0)); + + } + } + } else { + // iterator_type is mutable iterator. + // The cow_rw_iterator is being fetched via data.begin(), which creates a new store. + // The cow_rw_iterator is not converted into cow_ro_iterator. + // The cow_rw_iterator's new store is moved into the cow container + // when the cow_rw_iterator gets destructed later on (out of scope). + + printf("testing mutable non-const behavior.\n"); + typename T::const_iterator c_begin1; + { + iterator_type m_begin1 = data.begin(); // mutable new_store non-const iterator, gets held until destruction + c_begin1 = data.cbegin(); + REQUIRE(*c_begin1 == *m_begin1); + REQUIRE( c_begin1 == m_begin1); + REQUIRE( ( c_begin1 - m_begin1 ) == 0); + printf(" 1st store: %s == %s, dist %u\n", + c_begin1->toString().c_str(), m_begin1->toString().c_str(), (unsigned int)(c_begin1 - m_begin1)); + typename T::const_iterator c_begin2; + { + iterator_type m_begin2 = data.begin(); // mutable new_store non-const iterator, gets held until destruction + c_begin2 = data.cbegin(); + REQUIRE(*c_begin2 == *m_begin2); + REQUIRE( c_begin2 == m_begin2); + REQUIRE( ( c_begin2 - m_begin2 ) == 0); + printf(" 2nd store: %s == %s, dist %u\n", + c_begin2->toString().c_str(), m_begin2->toString().c_str(), (unsigned int)(c_begin2 - m_begin2)); + + REQUIRE(*c_begin2 == *c_begin1); + REQUIRE( c_begin2 != c_begin1); + REQUIRE( ( c_begin2 - c_begin1 ) != 0); + printf("2nd -> 1st store: %s == %s, dist %u\n", + c_begin2->toString().c_str(), c_begin1->toString().c_str(), (unsigned int)(c_begin2 - c_begin1)); + } + // 2nd store -> cow_xxx + typename T::const_iterator c_begin2b = data.cbegin(); + REQUIRE(*c_begin2 == *c_begin2b); + REQUIRE( c_begin2 == c_begin2b); + REQUIRE( ( c_begin2 - c_begin2b ) == 0); + printf("2nd -> cow == cbegin: %s == %s, dist %u\n", + c_begin2->toString().c_str(), c_begin2b->toString().c_str(), (unsigned int)(c_begin2 - c_begin2b)); + printf("2nd -> 1st : %s == %s, dist %u\n", + c_begin1->toString().c_str(), c_begin2->toString().c_str(), (unsigned int)(c_begin1 - c_begin2)); + } + // 1st store -> cow_xxx + typename T::const_iterator c_begin1b = data.cbegin(); + printf("1st -> cow == cbegin: %s == %s, dist %u\n", + c_begin1->toString().c_str(), c_begin1b->toString().c_str(), (unsigned int)(c_begin1 - c_begin1b)); + REQUIRE(*c_begin1 == *c_begin1b); + REQUIRE( c_begin1 == c_begin1b); + REQUIRE( ( c_begin1 - c_begin1b ) == 0); + } + return true; +} + +template<class T> +static bool test_01_validate_iterator_ops(const std::string& type_id, const std::size_t size0, const std::size_t reserve0) { + T data; + REQUIRE(0 == data.get_allocator().memory_usage); + REQUIRE(data.size() == 0); + REQUIRE(data.capacity() == 0); + REQUIRE(data.empty() == true); + + if( 0 < reserve0 ) { + data.reserve(reserve0); + REQUIRE(data.size() == 0); + REQUIRE(0 != data.get_allocator().memory_usage); + REQUIRE(data.capacity() == reserve0); + } + + test_00_seq_fill(data, size0); + REQUIRE(0 != data.get_allocator().memory_usage); + REQUIRE(data.size() == size0); + REQUIRE(data.size() <= data.capacity()); + + test_iterator_ops<T, typename T::const_iterator>(type_id, data, true /* iterator_is_const */); + // test_iterator_ops<T, typename T::iterator>(type_id, data, false /* iterator_is_const */); + + test_00_list_itr(data, false); + REQUIRE(0 != data.get_allocator().memory_usage); + REQUIRE(data.size() == size0); + + data.clear(); + REQUIRE(data.size() == 0); + // REQUIRE(0 == data.get_allocator().memory_usage); + return data.size() == 0; +} + +/**************************************************************************************** + ****************************************************************************************/ + +TEST_CASE( "Iterator Test 00 - Inspect all Iterator Types", "[datatype][std][vector][darray][cow_vector][cow_darray]" ) { + test_00_inspect_iterator_types< std_vector_DataType01 >("std::vector<T>"); + test_00_inspect_iterator_types< jau_darray_DataType01 >("jau::darray<T>"); + test_00_inspect_iterator_types< jau_cow_vector_DataType01 >("jau::cow_vector<T>"); + test_00_inspect_iterator_types< jau_cow_darray_DataType01 >("jau::cow_darray<T>"); +} + +TEST_CASE( "STD Vector Test 01 - Validate Iterator and Index Operations", "[datatype][std][vector]" ) { + // test_01_validate_index_ops< std_vector_DataType01 >("std::vector<T>", 100, 0); + // test_01_validate_index_ops< std_vector_DataType01 >("std::vector<T>", 100, 100); + + test_01_validate_iterator_ops< std_vector_DataType01 >("std::vector<T>", 100, 0); + // test_01_validate_iterator_ops< std_vector_DataType01 >("std::vector<T>", 100, 100); +} + +TEST_CASE( "JAU DArray Test 02 - Validate Iterator and Index Operations", "[datatype][jau][darray]" ) { + // test_01_validate_index_ops< jau_darray_DataType01 >("jau::darray<T>", 100, 0); + // test_01_validate_index_ops< jau_darray_DataType01 >("jau::darray<T>", 100, 100); + + test_01_validate_iterator_ops< jau_darray_DataType01 >("jau::darray<T>", 100, 0); + // test_01_validate_iterator_ops< jau_darray_DataType01 >("jau::darray<T>", 100, 100); +} + +TEST_CASE( "JAU COW_Vector Test 11 - Validate Iterator Operations", "[datatype][jau][cow_vector]" ) { + test_01_validate_iterator_ops< jau_cow_vector_DataType01 >("jau::cow_vector<T>", 100, 0); + // test_01_validate_iterator_ops< jau_cow_vector_DataType01 >("jau::cow_vector<T>", 100, 100); + + { + jau_cow_vector_DataType01 data; + test_00_seq_fill(data, 100); + test_cow_iterator_properties<jau_cow_vector_DataType01, typename jau_cow_vector_DataType01::const_iterator> + ("jau::cow_vector<T>", data, true /* iterator_is_const */); + // test_cow_iterator_properties<jau_cow_vector_DataType01, typename jau_cow_vector_DataType01::iterator> + // ("jau::cow_vector<T>", data, false /* iterator_is_const */); + } +} + +TEST_CASE( "JAU COW_DArray Test 21 - Validate Iterator Operations", "[datatype][jau][cow_darray]" ) { + test_01_validate_iterator_ops< jau_cow_darray_DataType01 >("jau::cow_darray<T>", 100, 0); + // test_01_validate_iterator_ops< jau_cow_darray_DataType01 >("jau::cow_darray<T>", 100, 100); + + { + jau_cow_darray_DataType01 data; + test_00_seq_fill(data, 100); + test_cow_iterator_properties<jau_cow_darray_DataType01, typename jau_cow_darray_DataType01::const_iterator> + ("jau::cow_darray<T>", data, true /* iterator_is_const */); + // test_cow_iterator_properties<jau_cow_darray_DataType01, typename jau_cow_darray_DataType01::iterator> + // ("jau::cow_darray<T>", data, false /* iterator_is_const */); + } + +} |