aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2021-01-04 02:43:24 +0100
committerSven Gothel <[email protected]>2021-01-04 02:43:24 +0100
commitcd1ce0ce606a4dd8db3d838cc3d07d5ac8224470 (patch)
tree867e67a24a12ffdcaa5bbbf81c3daa313e48e4ed /test
parentdefb6f4e62e5cc19ffc2353565ff1a546e499296 (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.txt1
-rw-r--r--test/test_cow_darray_01.cpp312
-rw-r--r--test/test_cow_darray_perf01.cpp62
-rw-r--r--test/test_cow_iterator_01.cpp600
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 */);
+ }
+
+}