Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
test_cow_iterator_01.cpp
Go to the documentation of this file.
1 /*
2  * Author: Sven Gothel <sgothel@jausoft.com>
3  * Copyright (c) 2020 Gothel Software e.K.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include <iostream>
25 #include <cassert>
26 #include <cinttypes>
27 #include <cstring>
28 #include <random>
29 #include <vector>
30 #include <type_traits>
31 
32 #define CATCH_CONFIG_RUNNER
33 // #define CATCH_CONFIG_MAIN
34 #include <catch2/catch_amalgamated.hpp>
35 #include <jau/test/catch2_ext.hpp>
36 
37 #include <jau/basic_algos.hpp>
38 #include <jau/basic_types.hpp>
39 #include <jau/darray.hpp>
40 #include <jau/cow_darray.hpp>
41 #include <jau/cow_vector.hpp>
43 #include <jau/callocator.hpp>
45 
46 /**
47  * Test jau:cow_[ro|rw]_iterator special properties from jau::cow_darray and jau::cow_vector in detail.
48  * <p>
49  * Normal random-access iterator operations are also tested from std::vector, jau::darray, jau::cow_darray and jau::cow_vector in detail,
50  * which either use the std::iterator (1s two container) or jau:cow_[ro|rw]_iterator (latter two cow-container).
51  * </p>
52  */
53 using namespace jau;
54 
55 typedef std::vector<uint64_t, counting_allocator<uint64_t>> std_vector_uint64_t;
59 
64 
65 template<class T>
66 static void print_list(T& data) {
67  printf("list: %d { ", (int)data.size());
68  jau::for_each_const(data, [](const uint64_t & e) {
69  printf("%s, ", to_decstring(e, ',', 2).c_str());
70  } );
71  printf("}\n");
72 }
73 
74 template<class T>
75 static void print_list(const std::string& pre, T& data) {
76  printf("%s: %d { ", pre.c_str(), (int)data.size());
77  jau::for_each_const(data, [](const uint64_t & e) {
78  printf("%s, ", to_decstring(e, ',', 2).c_str());
79  } );
80  printf("}\n");
81 }
82 
83 template<class T>
84 static void fill_list(T& data, const std::size_t size) {
85  std::size_t i=0;
86 
87  for(; i<size; i++) {
88  data.emplace_back( static_cast<uint64_t>(i+1) );
89  }
90  REQUIRE(i == data.size());
91 }
92 
93 /****************************************************************************************
94  ****************************************************************************************/
95 
96 template< class Iter >
97 static void print_iterator_info(const std::string& typedefname,
98  typename std::enable_if<
99  std::is_class<Iter>::value
100  >::type* = 0
101 ) {
102  jau::type_cue<Iter>::print(typedefname);
103  jau::type_cue<typename Iter::iterator_category>::print(typedefname+"::iterator_category");
104  jau::type_cue<typename Iter::iterator_type>::print(typedefname+"::iterator_type");
105  jau::type_cue<typename Iter::value_type>::print(typedefname+"::value_type");
106  jau::type_cue<typename Iter::reference>::print(typedefname+"::reference");
107  jau::type_cue<typename Iter::pointer>::print(typedefname+"::pointer");
108 }
109 
110 template<class Iter>
111 static void print_iterator_info(const std::string& typedefname,
112  typename std::enable_if<
113  !std::is_class<Iter>::value
114  >::type* = 0
115 ) {
116  jau::type_cue<Iter>::print(typedefname);
117 }
118 
119 template<class T>
120 static bool test_00_inspect_iterator_types(const std::string& type_id) {
121  typedef typename T::size_type size_type;
122  typedef typename T::iterator iter_type;
123  typedef typename T::difference_type diff_type;
124  typedef typename T::const_iterator citer_type;
125 
126  printf("**** Type Info: %s\n", type_id.c_str());
129  jau::type_cue<size_type>::print("T::size_type");
130  jau::type_cue<diff_type>::print("T::difference_type");
133  print_iterator_info<iter_type>("T::iterator");
134  print_iterator_info<citer_type>("T::citer_type");
135  printf("\n\n");
136 
137  return true;
138 }
139 
140 /****************************************************************************************
141  ****************************************************************************************/
142 
143 template<class T, typename iterator_type1, typename iterator_type2>
144 static void test_iterator_equal(iterator_type1& citer1, iterator_type2& citer2)
145 {
146  // Adding redundant switched operands comparison
147  // to test all relational combination of the overloading. (Leave it as is)
148 
149  REQUIRE( citer1 == citer2 ); // iter op==(iter1, iter2)
150  REQUIRE( citer2 == citer1 ); // iter op==(iter1, iter2)
151  REQUIRE( !( citer1 != citer2 ) ); // iter op!=(iter1, iter2)
152  REQUIRE( !( citer2 != citer1 ) ); // iter op!=(iter1, iter2)
153  REQUIRE( *citer1 == *citer2 ); // iter op*() and value_type ==
154  REQUIRE( *citer2 == *citer1 ); // iter op*() and value_type ==
155  REQUIRE( !( *citer1 != *citer2 ) ); // iter op*() and value_type !=
156  REQUIRE( !( *citer2 != *citer1 ) ); // iter op*() and value_type !=
157 }
158 template<class T, typename iterator_type1, typename iterator_type2>
159 static void test_iterator_notequal(iterator_type1& citer1, iterator_type2& citer2)
160 {
161  // Adding redundant switched operands comparison
162  // to test all relational combination of the overloading. (Leave it as is)
163 
164  REQUIRE( citer1 != citer2 ); // iter op==(iter1, iter2)
165  REQUIRE( citer2 != citer1 ); // iter op==(iter1, iter2)
166  REQUIRE( !( citer1 == citer2 ) ); // iter op!=(iter1, iter2)
167  REQUIRE( !( citer2 == citer1 ) ); // iter op!=(iter1, iter2)
168  REQUIRE( *citer1 != *citer2 ); // iter op*() and value_type ==
169  REQUIRE( *citer2 != *citer1 ); // iter op*() and value_type ==
170  REQUIRE( !( *citer1 == *citer2 ) ); // iter op*() and value_type !=
171  REQUIRE( !( *citer2 == *citer1 ) ); // iter op*() and value_type !=
172 }
173 
174 // iterator_type1 .. can be all the same, but leave it to the caller which is which
175 template<class T, typename iterator_type1, typename iterator_type2, typename iterator_type3, typename iterator_type4>
176 static void test_iterator_compare(const typename T::size_type size,
177  iterator_type1& begin,
178  iterator_type2& end,
179  iterator_type3& citer1, iterator_type4& citer2,
180  const typename T::difference_type citer1_idx,
181  const typename T::difference_type citer2_idx)
182 {
183  typedef typename T::difference_type diff_type;
184 
185  diff_type d_size = static_cast<diff_type>(size);
186  diff_type distance = citer2_idx - citer1_idx;
187 
188  // iter op-(iter1, iter2)
189  REQUIRE( ( end - begin ) == d_size);
190  REQUIRE( ( citer2 - begin ) == citer2_idx);
191  REQUIRE( ( citer1 - begin ) == citer1_idx);
192  REQUIRE( ( end - citer1 ) == d_size - citer1_idx);
193  REQUIRE( ( end - citer2 ) == d_size - citer2_idx);
194  REQUIRE( ( citer2 - citer1 ) == distance);
195 
196  // iter op-(iter, difference_type) and iter op==(iter1, iter2)
197  REQUIRE( ( citer1 - citer1_idx ) == begin);
198  REQUIRE( ( citer2 - citer2_idx ) == begin);
199  REQUIRE( ( citer2 - distance ) == citer1);
200 
201  // iter op+(iter, difference_type) and iter op==(iter1, iter2)
202  {
203  diff_type d_citer1_end = end - citer1;
204  diff_type d_citer2_end = end - citer2;
205  REQUIRE( ( citer1_idx + d_citer1_end ) == d_size); // validate op-(iter1, iter2)
206  REQUIRE( ( citer2_idx + d_citer2_end ) == d_size); // validate op-(iter1, iter2)
207 
208  REQUIRE( ( citer1 + d_citer1_end ) == end);
209  REQUIRE( ( citer2 + d_citer2_end ) == end);
210  }
211 
212  // Adding redundant switched operands comparison
213  // to test all relational combination of the overloading. (Leave it as is)
214 
215  if( 0 == distance ) {
216  test_iterator_equal<T>(citer1, citer2);
217  REQUIRE( !( citer2 > citer1 ) ); // iter op>(iter1, iter2)
218  REQUIRE( citer2 >= citer1 ); // iter op>=(iter1, iter2)
219  REQUIRE( !( citer2 < citer1 ) ); // iter op<(iter1, iter2)
220  REQUIRE( citer2 <= citer1 ); // iter op<=(iter1, iter2)
221  REQUIRE( citer1 <= citer2 ); // iter op>=(iter1, iter2)
222  REQUIRE( citer1 >= citer2 ); // iter op>=(iter1, iter2)
223  } else if( distance > 0 ) { // citer2 > citer1
224  test_iterator_notequal<T>(citer1, citer2);
225  REQUIRE( citer2 > citer1 ); // iter op>(iter1, iter2)
226  REQUIRE( citer2 >= citer1 ); // iter op>=(iter1, iter2)
227  REQUIRE( !( citer2 < citer1 ) ); // iter op<(iter1, iter2)
228  REQUIRE( !( citer2 <= citer1 ) ); // iter op<=(iter1, iter2)
229  REQUIRE( citer1 <= citer2 ); // iter op>(iter1, iter2)
230  REQUIRE( citer1 < citer2 ); // iter op>=(iter1, iter2)
231  } else { // distance < 0: citer2 < citer1
232  test_iterator_notequal<T>(citer1, citer2);
233  REQUIRE( !( citer2 > citer1 ) ); // iter op>(iter1, iter2)
234  REQUIRE( !( citer2 >= citer1 ) ); // iter op>=(iter1, iter2)
235  REQUIRE( citer2 < citer1 ); // iter op<(iter1, iter2)
236  REQUIRE( citer2 <= citer1 ); // iter op<=(iter1, iter2)
237  REQUIRE( citer1 > citer2 ); // iter op<(iter1, iter2)
238  REQUIRE( citer1 >= citer2 ); // iter op<=(iter1, iter2)
239  }
240 }
241 
242 template<class T, typename iterator_type1, typename iterator_type2>
243 static void test_iterator_dereference(const typename T::size_type size,
244  iterator_type1& begin, iterator_type2& end)
245 {
246  printf("**** test_iterator_dereference:\n");
247  print_iterator_info<iterator_type1>("iterator_type1");
248  print_iterator_info<iterator_type2>("iterator_type2");
249 
250  {
251  T data_exp = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
252  T data_has( begin, end );
253  REQUIRE(data_has == data_exp);
254  }
255 
256  // dereferencing, pointer, equality
257  iterator_type1 citer1 = begin;
258  iterator_type2 citer2 = begin;
259 
260  REQUIRE( citer1 == begin ); // iter op==()
261  REQUIRE( citer2 == begin ); // iter op==()
262  REQUIRE( citer1 == citer1 ); // iter op==()
263  REQUIRE( citer2 == citer1 ); // iter op==()
264 
265  REQUIRE( *citer1 == *begin ); // iter op*(), and value_type ==
266  REQUIRE( *citer2 == *begin ); // iter op*(), and value_type ==
267  REQUIRE( *citer1 == *citer1 ); // iter op*(), and value_type ==
268  REQUIRE( *citer2 == *citer1 ); // iter op*(), and value_type ==
269 
270  REQUIRE( citer1[1] == *(begin+1) ); // iter op[](diff), op+(iter, diff), iter op*(), and value_type ==
271  REQUIRE( citer2[1] == *(begin+1) ); // iter op[](diff), op+(iter, diff), iter op*(), and value_type ==
272  REQUIRE( citer1[1] == *(citer2+1) ); // iter op[](diff), op+(iter, diff), iter op*(), and value_type ==
273 
274  REQUIRE( citer1 != end-1 ); // iter op!=()
275  REQUIRE( citer2 != end-1 ); // iter op!=()
276  REQUIRE( *citer1 != *(end-1) ); // iter op*(), and value_type ==
277  REQUIRE( *citer2 != *(end-1) ); // iter op*(), and value_type ==
278  REQUIRE( citer1[1] != *(end-2) ); // iter op[](diff), op+(iter, diff), iter op*(), and value_type ==
279  REQUIRE( citer2[1] != *(end-2) ); // iter op[](diff), op+(iter, diff), iter op*(), and value_type ==
280 
281  REQUIRE( citer2+size-1 == end -1 );
282  REQUIRE( *(citer2+size-1) == *(end -1) );
283  REQUIRE( citer2[size-1] == end[-1] );
284 
285  REQUIRE( *(citer2+0) == begin[0] );
286  REQUIRE( *(citer2+1) == begin[1] );
287  REQUIRE( *(citer2+2) == begin[2] );
288  REQUIRE( *(citer2+3) == begin[3] );
289  REQUIRE( *(citer2+size-1) == end[-1] );
290 
291  test_iterator_compare<T>(size, begin, end, citer1, citer2, 0, 0);
292 }
293 
294 template<class T, typename iterator_type1, typename iterator_type2>
295 static void test_iterator_arithmetic(const typename T::size_type size,
296  iterator_type1& begin, iterator_type2& end)
297 {
298  printf("**** test_iterator_arithmetic:\n");
299  print_iterator_info<iterator_type1>("iterator_type1");
300  print_iterator_info<iterator_type2>("iterator_type2");
301 
302  // citer_type operations
303  // op++(), op--(), op++(int), op--(int),
304  // op+=(difference_type), op+(iter a, difference_type) ..
305  {
306  iterator_type1 citer1 = begin;
307  iterator_type1 citer2 = begin;
308  test_iterator_compare<T>(size, begin, end, citer1, citer2, 0, 0);
309 
310  // iter op++(int)
311  citer2++;
312  test_iterator_compare<T>(size, begin, end, citer1, citer2, 0, 1);
313 
314  // iter op++(int)
315  citer1++;
316  test_iterator_compare<T>(size, begin, end, citer1, citer2, 1, 1);
317 
318  // iter op--(int)
319  citer2--;
320  test_iterator_compare<T>(size, begin, end, citer1, citer2, 1, 0);
321 
322  // iter op--(int)
323  citer1--;
324  test_iterator_compare<T>(size, begin, end, citer1, citer2, 0, 0);
325  REQUIRE( *citer2 == begin[0] );
326 
327  // iter op++(int)
328  citer2++;
329  test_iterator_compare<T>(size, begin, end, citer1, citer2, 0, 1);
330  REQUIRE( *citer2 == *(begin+1) ); // iter op*(), op+(iter, difference_type) and value_type ==
331  REQUIRE( *citer2 == begin[1] ); // iter op*(), op[](difference_type) and value_type ==
332 
333  // iter op++(int)
334  citer2++;
335  test_iterator_compare<T>(size, begin, end, citer1, citer2, 0, 2);
336  REQUIRE( *citer2 == *(begin+2) ); // iter op*(), op+(iter, difference_type) and value_type ==
337  REQUIRE( *citer2 == begin[2] ); // iter op*(), op[](difference_type) and value_type ==
338 
339  // iter op++(int)
340  citer2++;
341  test_iterator_compare<T>(size, begin, end, citer1, citer2, 0, 3);
342  REQUIRE( *citer2 == *(begin+3) ); // iter op*(), op+(iter, difference_type) and value_type ==
343  REQUIRE( *citer2 == begin[3] ); // iter op*(), op[](difference_type) and value_type ==
344 
345  // iter op++()
346  --citer2;
347  --citer2;
348  --citer2;
349  test_iterator_compare<T>(size, begin, end, citer1, citer2, 0, 0);
350  REQUIRE( *citer2 == *(begin+0) ); // iter op*(), op+(iter, difference_type) and value_type ==
351  REQUIRE( *citer2 == begin[0] ); // iter op*(), op[](difference_type) and value_type ==
352 
353  // iter +=(diff)
354  citer2 += 3;
355  test_iterator_compare<T>(size, begin, end, citer1, citer2, 0, 3);
356 
357  // iter +=(diff)
358  citer2 += 6;
359  test_iterator_compare<T>(size, begin, end, citer1, citer2, 0, 9);
360 
361  // iter -=(diff)
362  citer2 -= 9;
363  test_iterator_compare<T>(size, begin, end, citer1, citer2, 0, 0);
364  }
365  {
366  // Adding redundant switched operands comparison
367  // to test all relational combination of the overloading. (Leave it as is)
368 
369  iterator_type1 citer1 = begin;
370  iterator_type1 citer2 = begin;
371 
372  REQUIRE( citer1 == citer1 ); // iter op==()
373  REQUIRE( citer2 == citer1 ); // iter op==()
374 
375  ++citer2;
376  REQUIRE( citer2 != citer1 ); // iter op==()
377  REQUIRE( citer1 != citer2 ); // iter op==()
378  REQUIRE( citer2 > citer1 ); // iter op==()
379  REQUIRE( citer2 >= citer1 ); // iter op==()
380  REQUIRE( citer1 < citer2 ); // iter op==()
381  REQUIRE( citer1 <= citer2 ); // iter op==()
382  REQUIRE( ( citer2 - citer1 ) == 1); // iter op==()
383  REQUIRE( ( citer1 - citer2 ) == -1); // iter op==()
384  }
385 
386 }
387 
388 template<class T>
389 static bool test_citer_type_ops(const std::string& type_id,
390  std::enable_if_t< is_cow_type<T>::value, bool> = true )
391 {
392  typedef typename T::const_iterator citer_type;
393  typedef typename T::difference_type diff_type;
394 
395  T data;
396  fill_list(data, 10);
397 
398  printf("**** test_citer_type_ops(CoW): %s\n", type_id.c_str());
399  {
400  citer_type begin = data.cbegin(); // immutable new_store non-const iterator, gets held until destruction
401  citer_type end = begin.cend(); // no new store iterator, on same store as begin, obtained from begin
402  diff_type data_size = static_cast<diff_type>(data.size());
403  diff_type begin_size = static_cast<diff_type>(begin.size());
404  diff_type end_size = static_cast<diff_type>(end.size());
405  REQUIRE( begin_size == data_size );
406  REQUIRE( end_size == data_size );
407  REQUIRE( end - begin == data_size );
408  REQUIRE( end - end_size == begin );
409  REQUIRE( begin + begin_size == end );
410  REQUIRE( *( end - end_size ) == *begin );
411  REQUIRE( *( begin + begin_size ) == *end );
412  test_iterator_dereference<T, citer_type>(begin.size(), begin, end);
413  }
414 
415  {
416  citer_type begin = data.cbegin(); // no new store citer_type
417  citer_type end = begin.cend(); // no new store citer_type, on same store as begin, obtained from begin
418  test_iterator_arithmetic<T, citer_type>(data.size(), begin, end);
419  }
420  {
421  T data2 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
422  print_list("work", data);
423  print_list("expt", data2);
424  REQUIRE(data == data2);
425  }
426  return true;
427 }
428 template<class T>
429 static bool test_citer_type_ops(const std::string& type_id,
430  std::enable_if_t< !is_cow_type<T>::value, bool> = true )
431 {
432  typedef typename T::const_iterator citer_type;
433  typedef typename T::difference_type diff_type;
434  T data;
435  fill_list(data, 10);
436 
437  printf("**** test_citer_type_ops: %s\n", type_id.c_str());
438  {
439  citer_type begin = data.cbegin(); // mutable new_store non-const iterator, gets held until destruction
440  citer_type end = data.cend(); // no new store iterator, on same store as begin and from begin
441  diff_type data_size = static_cast<diff_type>(data.size());
442  REQUIRE( end - begin == data_size );
443  REQUIRE( end - data_size == begin );
444  REQUIRE( begin + data_size == end );
445  REQUIRE( *( end - data_size ) == *begin );
446  REQUIRE( *( begin + data_size - 1 ) == *( end - 1 ) );
447  REQUIRE( end[-data_size] == begin[0] );
448  REQUIRE( begin[data_size - 1] == end[-1] );
449  test_iterator_dereference<T, citer_type>(data.size(), begin, end);
450  }
451 
452  {
453  citer_type begin = data.cbegin(); // no new store citer_type
454  citer_type end = data.cend(); // no new store citer_type, on same store as begin
455  test_iterator_arithmetic<T, citer_type, citer_type>(data.size(), begin, end);
456  }
457  {
458  T data2 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
459  REQUIRE(data == data2);
460  }
461  return true;
462 }
463 
464 template<class T>
465 static bool test_mutable_iterator_ops(const std::string& type_id,
466  std::enable_if_t< is_cow_type<T>::value, bool> = true )
467 {
468  typedef typename T::size_type size_type;
469  typedef typename T::const_iterator citer_type;
470  typedef typename T::iterator iter_type;
471  typedef typename T::difference_type diff_type;
472  typedef typename T::value_type value_type;
473  typedef typename T::storage_t storage_t;
474 
475  printf("**** test_mutable_iterator_ops(CoW): %s\n", type_id.c_str());
476  {
477  T data;
478  fill_list(data, 10);
479  iter_type begin = data.begin(); // mutable new_store non-const iterator, gets held until destruction
480  iter_type end = begin.end(); // no new store iterator, on same store as begin and from begin
481  diff_type data_size = static_cast<diff_type>(data.size());
482  diff_type begin_size = static_cast<diff_type>(begin.size());
483  diff_type end_size = static_cast<diff_type>(end.size());
484  REQUIRE( begin_size == data_size );
485  REQUIRE( end_size == data_size );
486  REQUIRE( end - begin == data_size );
487  REQUIRE( end - end_size == begin );
488  REQUIRE( begin + begin_size == end );
489  REQUIRE( *( end - end_size ) == *begin );
490  REQUIRE( *( begin + begin_size - 1 ) == *( end - 1 ) );
491  REQUIRE( end[-end_size] == begin[0] );
492  REQUIRE( begin[begin_size - 1] == end[-1] );
493  test_iterator_dereference<T, iter_type>(begin.size(), begin, end);
494  }
495 
496  {
497  T data;
498  fill_list(data, 10);
499 
500  // all 4 combinations of iter, citer:
501  iter_type begin = data.begin(); // mutable new_store non-const iterator, gets held until destruction
502  iter_type end = begin.end();
503  citer_type cbegin = begin.immutable();
504  citer_type cend = cbegin.cend();
505 
506  test_iterator_arithmetic<T>(data.size(), begin, end);
507  test_iterator_arithmetic<T>(data.size(), cbegin, cend);
508  test_iterator_arithmetic<T>(data.size(), begin, cend);
509  test_iterator_arithmetic<T>(data.size(), cbegin, end);
510  }
511 
512  // iterator-op: darray/vector-op
513  // -------------------------------------------
514  // 1 pop_back()
515  // 1 erase (): erase (citer_type pos)
516  // 3 erase (count): erase (iterator first, citer_type last)
517  // 1 insert(const value_type& x): iterator insert(citer_type pos, const value_type& x)
518  // 0 insert(value_type&& x): iterator insert(citer_type pos, value_type&& x)
519  // 1 emplace(Args&&... args): emplace(citer_type pos, Args&&... args)
520  // 2 insert(InputIt first, InputIt last ): insert( citer_type pos, InputIt first, InputIt last )
521  // 1 void push_back(value_type& x)
522  // 1 void push_back(value_type&& x)
523  // 1 reference emplace_back(Args&&... args)
524  // 0 [void push_back( InputIt first, InputIt last )]
525  // 1 to_begin()
526  {
527  T data;
528  fill_list(data, 10);
529  citer_type citer0 = data.cbegin(); // immutable orig store iterator
530  {
531  T data_exp = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
532  REQUIRE(data == data_exp);
533  }
534  REQUIRE( *data.snapshot() == citer0.storage() );
535 
536  iter_type iter = data.begin(); // mutable new_store non-const iterator, gets held until destruction
537  size_type size_pre = iter.size();
538  value_type elem = iter.end()[-2];
539 
540  REQUIRE( iter != citer0 );
541  REQUIRE( iter.storage() == citer0.storage() );
542  REQUIRE( iter.storage() == *data.snapshot() );
543 
544  REQUIRE( iter.dist_begin() == 0 );
545  REQUIRE( iter.dist_end() == static_cast<diff_type>(size_pre));
546 
547  int i;
548  (void)i;
549  // pop_back()
550  iter.pop_back();
551  REQUIRE( iter.size() == size_pre-1 );
552  REQUIRE( iter == iter.end() );
553  REQUIRE( iter == iter.begin()+size_pre-1 );
554  REQUIRE( iter.dist_begin() == static_cast<diff_type>(size_pre)-1 );
555  REQUIRE( iter.dist_end() == 0 );
556  REQUIRE( iter[-1] == elem );
557  {
558  storage_t data_exp = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
559  REQUIRE(iter.storage() == data_exp);
560  }
561  REQUIRE(iter.storage() != citer0.storage());
562  REQUIRE(iter.storage() != *data.snapshot());
563 
564  // insert( citer_type pos, InputIt first, InputIt last )
565  REQUIRE( iter == iter.end() );
566  size_pre = iter.size();
567  REQUIRE( iter.dist_begin() == static_cast<diff_type>(size_pre));
568  REQUIRE( iter.dist_end() == 0);
569  {
570  T data2;
571  fill_list(data2, 10);
572  // iter.push_back(data2.cbegin(), data2.cend()); // FIXME: Only in jau::darray not stl::vector
573  iter.insert(data2.cbegin(), data2.cbegin()+data2.size()); // same as push_pack(..) since pointing to end() - but iter points here to first new elem
574  }
575  REQUIRE( iter.size() == size_pre+10 );
576  REQUIRE( iter == iter.end()-10 );
577  REQUIRE( iter.dist_begin() == static_cast<diff_type>(size_pre));
578  REQUIRE( iter.dist_end() == 10);
579  {
580  storage_t data_exp = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
581  REQUIRE(iter.storage() == data_exp);
582  }
583 
584  // erase (count): erase (iterator first, citer_type last)
585  REQUIRE( iter == iter.end()-10 );
586  size_pre = iter.size();
587  // std::cout << "iter.5" << iter << (iter - iter.begin()) << "/" << iter.size() << ", size2 " << size2 << std::endl;
588  iter.erase(10);
589  // std::cout << "iter.6" << iter << (iter - iter.begin()) << "/" << iter.size() << std::endl;
590  REQUIRE( iter.size() == size_pre-10 );
591  REQUIRE( iter == iter.end() );
592  {
593  storage_t data_exp = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
594  REQUIRE(iter.storage() == data_exp);
595  }
596 
597  // erase ()
598  size_pre = iter.size();
599  iter.to_begin();
600  REQUIRE( iter == iter.begin() );
601  elem = iter.begin()[1];
602  iter.erase();
603  REQUIRE( iter.size() == size_pre-1 );
604  REQUIRE( iter == iter.begin() );
605  REQUIRE( *iter == elem );
606  {
607  storage_t data_exp = { 2, 3, 4, 5, 6, 7, 8, 9 };
608  REQUIRE(iter.storage() == data_exp);
609  }
610 
611  // void push_back(value_type& x)
612  size_pre = iter.size();
613  REQUIRE( iter == iter.begin() );
614  elem = iter.end()[-1];
615  {
616  T data2;
617  fill_list(data2, 10);
618  citer_type data2_iter = data2.cbegin();
619  iter.push_back(data2_iter[0]);
620  iter.push_back(data2_iter[1]);
621  iter.push_back(data2_iter[2]);
622  REQUIRE( iter.size() == size_pre+3 );
623  REQUIRE( iter == iter.end() );
624  REQUIRE( iter[-3] == data2_iter[0] );
625  REQUIRE( iter[-2] == data2_iter[1] );
626  REQUIRE( iter[-1] == data2_iter[2] );
627  }
628  {
629  storage_t data_exp = { 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3 };
630  REQUIRE(iter.storage() == data_exp);
631  }
632 
633  // erase (count): erase (iterator first, citer_type last)
634  size_pre = iter.size();
635  REQUIRE( iter == iter.end() );
636  iter -= 3;
637  iter.erase(3);
638  REQUIRE( iter.size() == size_pre-3 );
639  REQUIRE( iter == iter.end() );
640  {
641  storage_t data_exp = { 2, 3, 4, 5, 6, 7, 8, 9 };
642  REQUIRE(iter.storage() == data_exp);
643  }
644 
645  // void push_back(value_type&& x)
646  size_pre = iter.size();
647  REQUIRE( iter == iter.end() );
648  {
649  value_type elem0 = iter.begin()[0];
650  iter.push_back( std::move(elem0));
651  }
652  {
653  value_type elem0 = iter.begin()[1];
654  iter.push_back( std::move(elem0));
655  }
656  {
657  value_type elem0 = iter.begin()[2];
658  iter.push_back( std::move(elem0));
659  }
660  REQUIRE( iter.size() == size_pre+3 );
661  REQUIRE( iter == iter.end() );
662  REQUIRE( iter[-3] == iter.begin()[0] );
663  REQUIRE( iter[-2] == iter.begin()[1] );
664  REQUIRE( iter[-1] == iter.begin()[2] );
665  {
666  storage_t data_exp = { 2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4 };
667  REQUIRE(iter.storage() == data_exp);
668  }
669 
670  // erase last three
671  REQUIRE( iter == iter.end() );
672  iter -= 3;
673  iter.erase();
674  iter.erase();
675  iter.erase();
676  REQUIRE( iter == iter.end() );
677  {
678  storage_t data_exp = { 2, 3, 4, 5, 6, 7, 8, 9 };
679  REQUIRE(iter.storage() == data_exp);
680  }
681 
682  // iterator insert(citer_type pos, const value_type& x)
683  iter.to_begin();
684  iter += 5;
685  REQUIRE( iter == iter.begin()+5 );
686  REQUIRE( iter.dist_begin() == 5 );
687 
688  size_pre = iter.size();
689  {
690  T data2;
691  fill_list(data2, 10);
692  citer_type data2_iter = data2.cbegin();
693  iter.insert(data2_iter[0]);
694  iter.insert(data2_iter[1]);
695  iter.insert(data2_iter[2]);
696  REQUIRE( iter.size() == size_pre+3 );
697  REQUIRE( iter == iter.begin()+5 );
698  iter.to_begin();
699  REQUIRE( iter[5] == data2_iter[2] );
700  REQUIRE( iter[6] == data2_iter[1] );
701  REQUIRE( iter[7] == data2_iter[0] );
702  }
703  {
704  storage_t data_exp = { 2, 3, 4, 5, 6, 3, 2, 1, 7, 8, 9 };
705  REQUIRE(iter.storage() == data_exp);
706  }
707 
708  // insert( citer_type pos, InputIt first, InputIt last )
709  iter += 5;
710  REQUIRE( iter == iter.begin()+5 );
711  size_pre = iter.size();
712  {
713  T data2;
714  fill_list(data2, 10);
715  iter.insert(data2.cbegin(), data2.cbegin()+3);
716  }
717  REQUIRE( iter.size() == size_pre+3 );
718  REQUIRE( iter == iter.begin()+5 );
719  {
720  storage_t data_exp = { 2, 3, 4, 5, 6, 1, 2, 3, 3, 2, 1, 7, 8, 9 };
721  REQUIRE(iter.storage() == data_exp);
722  }
723 
724  // erase (count): erase (iterator first, citer_type last)
725  REQUIRE( iter == iter.begin()+5 );
726  size_pre = iter.size();
727  iter.erase(6);
728  REQUIRE( iter.size() == size_pre-6 );
729  REQUIRE( iter == iter.begin()+5 );
730  {
731  storage_t data_exp = { 2, 3, 4, 5, 6, 7, 8, 9 };
732  REQUIRE(iter.storage() == data_exp);
733  }
734 
735  // 1 emplace(Args&&... args): emplace(citer_type pos, Args&&... args)
736  size_pre = iter.size();
737  REQUIRE( iter == iter.begin()+5 );
738  iter.emplace( static_cast<uint64_t>(2) );
739  iter.emplace( static_cast<uint64_t>(3) );
740  iter.emplace( static_cast<uint64_t>(4) );
741  REQUIRE( iter == iter.begin()+5 );
742  REQUIRE( iter[0] == 4 );
743  REQUIRE( iter[1] == 3 );
744  REQUIRE( iter[2] == 2 );
745  {
746  storage_t data_exp = { 2, 3, 4, 5, 6, 4, 3, 2, 7, 8, 9 };
747  REQUIRE(iter.storage() == data_exp);
748  }
749 
750  // 1 reference emplace_back(Args&&... args)
751  size_pre = iter.size();
752  REQUIRE( iter == iter.begin()+5 );
753  iter.emplace_back( static_cast<uint64_t>(2) );
754  iter.emplace_back( static_cast<uint64_t>(3) );
755  iter.emplace_back( static_cast<uint64_t>(4) );
756  REQUIRE( iter == iter.end() );
757  REQUIRE( iter[-1] == 4 );
758  REQUIRE( iter[-2] == 3 );
759  REQUIRE( iter[-3] == 2 );
760  {
761  storage_t data_exp = { 2, 3, 4, 5, 6, 4, 3, 2, 7, 8, 9, 2, 3, 4 };
762  REQUIRE(iter.storage() == data_exp);
763  }
764 
765  // multiple erase()
766  size_pre = iter.size();
767  REQUIRE( iter == iter.end() );
768  iter -= 10;
769  REQUIRE( iter == iter.end()-10 );
770  {
771  int count = 0;
772  while( iter != iter.end() ) {
773  iter.erase();
774  count++;
775  }
776  REQUIRE( iter.size() == size_pre - 10 );
777  }
778  {
779  storage_t data_exp = { 2, 3, 4, 5 };
780  REQUIRE(iter.storage() == data_exp);
781  }
782  iter.to_begin(); // set to its begin
783 
784  // write back ..
785  REQUIRE( iter != data.cbegin() ); // still not the same
786  REQUIRE( iter.storage() != *data.snapshot() ); // neither content
787  {
788  T data_exp = { 2, 3, 4, 5 };
789  REQUIRE(data != data_exp);
790  }
791  iter.write_back(); // invalidates iter and ...
792  {
793  T data_exp = { 2, 3, 4, 5 };
794  REQUIRE(data == data_exp); // now got the newt content
795  }
796  }
797 
798  return true;
799 }
800 
801 template<class T>
802 static bool test_mutable_iterator_ops(const std::string& type_id,
803  std::enable_if_t< !is_cow_type<T>::value, bool> = true )
804 {
805  typedef typename T::iterator iter_type;
806  typedef typename T::const_iterator citer_type;
807  typedef typename T::difference_type diff_type;
808 
809  printf("**** test_mutable_iterator_ops(___): %s\n", type_id.c_str());
810  {
811  T data;
812  fill_list(data, 10);
813  iter_type begin = data.begin();
814  iter_type end = data.end();
815  diff_type data_size = static_cast<diff_type>(data.size());
816  REQUIRE( end - begin == data_size );
817  REQUIRE( end - data_size == begin );
818  REQUIRE( begin + data_size == end );
819  REQUIRE( *( end - data_size ) == *begin );
820  REQUIRE( *( begin + data_size ) == *end );
821  test_iterator_dereference<T, iter_type>(data.size(), begin, end);
822  }
823 
824  {
825  T data;
826  fill_list(data, 10);
827 
828  // all 4 combinations of iter, citer:
829  iter_type begin = data.begin();
830  iter_type end = data.end();
831  citer_type cend = data.cend();
832  citer_type cbegin = data.cbegin();
833 
834  test_iterator_arithmetic<T>(data.size(), begin, end);
835  test_iterator_arithmetic<T>(data.size(), cbegin, cend);
836  test_iterator_arithmetic<T>(data.size(), begin, cend);
837  test_iterator_arithmetic<T>(data.size(), cbegin, end);
838  }
839 
840  // iterator-op: darray/vector-op
841  // -------------------------------------------
842  // 1 pop_back()
843  // 1 erase (citer_type pos)
844  // 3 erase (iterator first, citer_type last)
845  // 1 iterator insert(citer_type pos, const value_type& x)
846  // 0 iterator insert(citer_type pos, value_type&& x)
847  // 1 emplace(citer_type pos, Args&&... args)
848  // 2 insert( citer_type pos, InputIt first, InputIt last )
849  // 1 void push_back(value_type& x)
850  // 1 void push_back(value_type&& x)
851  // 1 reference emplace_back(Args&&... args)
852  // 0 [void push_back( InputIt first, InputIt last )]
853  {
854  T data;
855  fill_list(data, 10);
856  {
857  T data_exp = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
858  REQUIRE(data == data_exp);
859  }
860 
861  iter_type iter = data.end();
862  typename T::size_type size_pre = data.size();
863  typename T::value_type elem = iter[-2];
864 
865  // pop_back()
866  int i;
867  (void)i;
868  data.pop_back();
869  iter--;
870  REQUIRE( data.size() == size_pre-1 );
871  REQUIRE( iter == data.end() );
872  REQUIRE( iter == data.begin()+size_pre-1 );
873  REQUIRE( iter[-1] == elem );
874  {
875  T data_exp = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
876  REQUIRE(data == data_exp);
877  }
878 
879  // insert( citer_type pos, InputIt first, InputIt last )
880  REQUIRE( iter == data.end() );
881  size_pre = data.size();
882  {
883  T data2;
884  fill_list(data2, 10);
885  iter = data.insert(iter, data2.cbegin(), data2.cbegin()+data2.size()); // same as push_pack(..) since pointing to end() - but data points here to first new elem
886  }
887  REQUIRE( data.size() == size_pre+10 );
888  REQUIRE( iter == data.end()-10 );
889  {
890  T data_exp = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
891  REQUIRE(data == data_exp);
892  }
893 
894  // erase (count): erase (iterator first, citer_type last)
895  REQUIRE( iter == data.end()-10 );
896  size_pre = data.size();
897  // std::cout << "data.5" << data << (data - data.begin()) << "/" << data.size() << ", size2 " << size2 << std::endl;
898  iter = data.erase(iter, iter+10);
899  // std::cout << "data.6" << data << (data - data.begin()) << "/" << data.size() << std::endl;
900  REQUIRE( data.size() == size_pre-10 );
901  REQUIRE( iter == data.end() );
902  {
903  T data_exp = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
904  REQUIRE(data == data_exp);
905  }
906 
907  // erase ()
908  size_pre = data.size();
909  iter = data.begin();
910  REQUIRE( iter == data.begin() );
911  elem = iter[1];
912  iter = data.erase(iter);
913  REQUIRE( data.size() == size_pre-1 );
914  REQUIRE( iter == data.begin() );
915  REQUIRE( *iter == elem );
916  {
917  T data_exp = { 2, 3, 4, 5, 6, 7, 8, 9 };
918  REQUIRE(data == data_exp);
919  }
920 
921  // void push_back(value_type& x)
922  size_pre = data.size();
923  REQUIRE( iter == data.begin() );
924  elem = data.end()[-1];
925  {
926  T data2;
927  fill_list(data2, 10);
928  data.push_back(data2[0]);
929  data.push_back(data2[1]);
930  data.push_back(data2[2]);
931  iter = data.end();
932  REQUIRE( data.size() == size_pre+3 );
933  REQUIRE( iter == data.end() );
934  REQUIRE( iter[-3] == data2[0] );
935  REQUIRE( iter[-2] == data2[1] );
936  REQUIRE( iter[-1] == data2[2] );
937  }
938  {
939  T data_exp = { 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3 };
940  REQUIRE(data == data_exp);
941  }
942 
943  // erase (count): erase (iterator first, citer_type last)
944  size_pre = data.size();
945  REQUIRE( iter == data.end() );
946  iter -= 3;
947  iter = data.erase(iter, iter+3);
948  REQUIRE( data.size() == size_pre-3 );
949  REQUIRE( iter == data.end() );
950  {
951  T data_exp = { 2, 3, 4, 5, 6, 7, 8, 9 };
952  REQUIRE(data == data_exp);
953  }
954 
955  // void push_back(value_type&& x)
956  size_pre = data.size();
957  REQUIRE( iter == data.end() );
958  {
959  typename T::value_type elem0 = data.begin()[0];
960  data.push_back( std::move(elem0));
961  }
962  {
963  typename T::value_type elem0 = data.begin()[1];
964  data.push_back( std::move(elem0));
965  }
966  {
967  typename T::value_type elem0 = data.begin()[2];
968  data.push_back( std::move(elem0));
969  }
970  iter = data.end();
971  REQUIRE( data.size() == size_pre+3 );
972  REQUIRE( iter == data.end() );
973  REQUIRE( iter[-3] == data.begin()[0] );
974  REQUIRE( iter[-2] == data.begin()[1] );
975  REQUIRE( iter[-1] == data.begin()[2] );
976  {
977  T data_exp = { 2, 3, 4, 5, 6, 7, 8, 9, 2, 3, 4 };
978  REQUIRE(data == data_exp);
979  }
980 
981  // erase last three
982  REQUIRE( iter == data.end() );
983  iter -= 3;
984  iter = data.erase(iter);
985  iter = data.erase(iter);
986  iter = data.erase(iter);
987  REQUIRE( iter == data.end() );
988  {
989  T data_exp = { 2, 3, 4, 5, 6, 7, 8, 9 };
990  REQUIRE(data == data_exp);
991  }
992 
993  // iterator insert(citer_type pos, const value_type& x)
994  iter = data.begin();
995  iter += 5;
996  REQUIRE( iter == data.begin()+5 );
997  size_pre = data.size();
998  {
999  T data2;
1000  fill_list(data2, 10);
1001  iter = data.insert(iter, data2[0]);
1002  iter = data.insert(iter, data2[1]);
1003  iter = data.insert(iter, data2[2]);
1004  REQUIRE( data.size() == size_pre+3 );
1005  REQUIRE( iter == data.begin()+5 );
1006  iter = data.begin();
1007  REQUIRE( iter[5] == data2[2] );
1008  REQUIRE( iter[6] == data2[1] );
1009  REQUIRE( iter[7] == data2[0] );
1010  }
1011  {
1012  T data_exp = { 2, 3, 4, 5, 6, 3, 2, 1, 7, 8, 9 };
1013  REQUIRE(data == data_exp);
1014  }
1015 
1016  // insert( citer_type pos, InputIt first, InputIt last )
1017  iter += 5;
1018  REQUIRE( iter == data.begin()+5 );
1019  size_pre = data.size();
1020  {
1021  T data2;
1022  fill_list(data2, 10);
1023  iter = data.insert(iter, data2.cbegin(), data2.cbegin()+3);
1024  }
1025  REQUIRE( data.size() == size_pre+3 );
1026  REQUIRE( iter == data.begin()+5 );
1027  {
1028  T data_exp = { 2, 3, 4, 5, 6, 1, 2, 3, 3, 2, 1, 7, 8, 9 };
1029  REQUIRE(data == data_exp);
1030  }
1031 
1032  // erase (count): erase (iterator first, citer_type last)
1033  REQUIRE( iter == data.begin()+5 );
1034  size_pre = data.size();
1035  iter = data.erase(iter, iter+6);
1036  REQUIRE( data.size() == size_pre-6 );
1037  REQUIRE( iter == data.begin()+5 );
1038  {
1039  T data_exp = { 2, 3, 4, 5, 6, 7, 8, 9 };
1040  REQUIRE(data == data_exp);
1041  }
1042 
1043  // 1 emplace(Args&&... args): emplace(citer_type pos, Args&&... args)
1044  size_pre = data.size();
1045  REQUIRE( iter == data.begin()+5 );
1046  iter = data.emplace(iter, static_cast<uint64_t>(2) );
1047  iter = data.emplace(iter, static_cast<uint64_t>(3) );
1048  iter = data.emplace(iter, static_cast<uint64_t>(4) );
1049 
1050  REQUIRE( iter == data.begin()+5 );
1051  REQUIRE( iter[0] == 4 );
1052  REQUIRE( iter[1] == 3 );
1053  REQUIRE( iter[2] == 2 );
1054  {
1055  T data_exp = { 2, 3, 4, 5, 6, 4, 3, 2, 7, 8, 9 };
1056  REQUIRE(data == data_exp);
1057  }
1058 
1059  // 1 reference emplace_back(Args&&... args)
1060  size_pre = data.size();
1061  REQUIRE( iter == data.begin()+5 );
1062  data.emplace_back( static_cast<uint64_t>(2) );
1063  data.emplace_back( static_cast<uint64_t>(3) );
1064  data.emplace_back( static_cast<uint64_t>(4) );
1065  iter = data.end();
1066  REQUIRE( iter == data.end() );
1067  REQUIRE( iter[-1] == 4 );
1068  REQUIRE( iter[-2] == 3 );
1069  REQUIRE( iter[-3] == 2 );
1070  {
1071  T data_exp = { 2, 3, 4, 5, 6, 4, 3, 2, 7, 8, 9, 2, 3, 4 };
1072  REQUIRE(data == data_exp);
1073  }
1074 
1075  // multiple erase()
1076  size_pre = data.size();
1077  REQUIRE( iter == data.end() );
1078  iter -= 10;
1079  REQUIRE( iter == data.end()-10 );
1080  {
1081  int count = 0;
1082  while( iter != data.end() ) {
1083  iter = data.erase(iter);
1084  count++;
1085  }
1086  REQUIRE( data.size() == size_pre - 10 );
1087  REQUIRE( iter == data.end() );
1088  }
1089  {
1090  T data_exp = { 2, 3, 4, 5 };
1091  REQUIRE(data == data_exp);
1092  }
1093  }
1094  {
1095  T data;
1096  fill_list(data, 10);
1097  T data2 = data;
1098  T data3(data);
1099  print_list("orig", data2);
1100  print_list("copy1", data2);
1101  print_list("copy2", data3);
1102  REQUIRE(data == data2);
1103  REQUIRE(data == data3);
1104  }
1105  return true;
1106 }
1107 
1108 /****************************************************************************************
1109  ****************************************************************************************/
1110 
1111 template<class T>
1112 static bool test_01_validate_iterator_ops(const std::string& type_id) {
1113 
1114  test_citer_type_ops<T>(type_id);
1115 
1116  test_mutable_iterator_ops<T>(type_id);
1117 
1118  return true;
1119 }
1120 
1121 template<class T>
1122 static bool test_01_cow_iterator_properties(const std::string& type_id) {
1123  typedef typename T::size_type size_type;
1124  typedef typename T::const_iterator citer_type;
1125  typedef typename T::iterator iter_type;
1126 
1127  printf("**** test_cow_iterator_properties: %s\n", type_id.c_str());
1128  print_iterator_info<citer_type>("citer_type");
1129  print_iterator_info<iter_type>("iter_type");
1130 
1131  const size_type size0 = 100;
1132 
1133  T data;
1134  REQUIRE(0 == data.get_allocator().memory_usage);
1135  REQUIRE(data.size() == 0);
1136  REQUIRE(data.capacity() == 0);
1137  REQUIRE(data.empty() == true);
1138 
1139  fill_list(data, size0);
1140  REQUIRE(0 != data.get_allocator().memory_usage);
1141  REQUIRE(data.size() == size0);
1142  REQUIRE(data.size() <= data.capacity());
1143 
1144  // test relationship and distance with mixed iterator and citer_type
1145  // in both direction using the free overloaded operator of cow_ro_* and cow_rw_*
1146  {
1147  iter_type iter1 = data.begin();
1148  citer_type citer2 = iter1.immutable();
1149  citer_type citer3 = iter1.immutable().to_end();
1150 
1151  REQUIRE( iter1.is_begin() );
1152  REQUIRE( citer2.is_begin() );
1153  REQUIRE( citer3.is_end() );
1154 
1155  REQUIRE( iter1.dist_begin() == 0);
1156  REQUIRE( iter1.dist_end() == size0);
1157  REQUIRE( citer2.dist_begin() == 0);
1158  REQUIRE( citer2.dist_end() == size0);
1159  REQUIRE( citer3.dist_begin() == size0);
1160  REQUIRE( citer3.dist_end() == 0);
1161 
1162  REQUIRE( ( iter1 == citer2 ) == true); // iter op==()
1163  REQUIRE( ( citer2 == iter1 ) == true); // iter op==()
1164 
1165  ++citer2;
1166  REQUIRE( ( citer2 != iter1 ) == true); // iter op==()
1167  REQUIRE( ( iter1 != citer2 ) == true); // iter op==()
1168  REQUIRE( ( citer2 > iter1 ) == true); // iter op==()
1169  REQUIRE( ( citer2 >= iter1 ) == true); // iter op==()
1170  REQUIRE( ( iter1 < citer2 ) == true); // iter op==()
1171  REQUIRE( ( iter1 <= citer2 ) == true); // iter op==()
1172  REQUIRE( ( citer2 - iter1 ) == 1); // iter op==()
1173  REQUIRE( ( iter1 - citer2 ) == -1); // iter op==()
1174  REQUIRE( citer2.dist_begin() == 1);
1175  REQUIRE( citer2.dist_end() == size0-1);
1176 
1177  --citer2;
1178  ++iter1;
1179  REQUIRE( ( iter1 != citer2 ) == true); // iter op==()
1180  REQUIRE( ( citer2 != iter1 ) == true); // iter op==()
1181  REQUIRE( ( iter1 > citer2 ) == true); // iter op==()
1182  REQUIRE( ( iter1 >= citer2 ) == true); // iter op==()
1183  REQUIRE( ( citer2 < iter1 ) == true); // iter op==()
1184  REQUIRE( ( citer2 <= iter1 ) == true); // iter op==()
1185  REQUIRE( ( iter1 - citer2 ) == 1); // iter op==()
1186  REQUIRE( ( citer2 - iter1 ) == -1); // iter op==()
1187  REQUIRE( iter1.dist_begin() == 1);
1188  REQUIRE( iter1.dist_end() == size0-1);
1189  REQUIRE( citer2.dist_begin() == 0);
1190  REQUIRE( citer2.dist_end() == size0);
1191 
1192  REQUIRE( ( iter1.end() == citer3 ) == true); // iter op==()
1193  REQUIRE( ( iter1.to_end() == citer3 ) == true); // iter op==()
1194  REQUIRE( iter1.is_end() );
1195  REQUIRE( citer3.is_end() );
1196  REQUIRE( iter1.dist_begin() == size0);
1197  REQUIRE( iter1.dist_end() == 0);
1198  }
1199 
1200  // test mutable non-const 'new store' behavior
1201  citer_type c_begin0 = data.cbegin(); // orig store
1202  {
1203  // iterator_type is mutable iterator.
1204  // The cow_rw_iterator is being fetched via data.begin(), which creates a new store and stays.
1205  // The cow_rw_iterator's new store is moved into the cow container via write_back() later.
1206 
1207  printf("testing mutable non-const behavior.\n");
1208  citer_type c_begin1;
1209  {
1210  iter_type m_begin1 = data.begin(); // mutable new_store non-const iterator, gets held until write_back() or destruction
1211  c_begin1 = m_begin1.immutable(); // get immutable citer_type from newly created store
1212 
1213  REQUIRE(*c_begin1 == *m_begin1);
1214  REQUIRE( c_begin1 == m_begin1);
1215  REQUIRE( ( c_begin1 - m_begin1 ) == 0);
1216  printf(" 1st store: %s == %s, dist %u\n",
1217  to_decstring(*c_begin1, ',', 2).c_str(), to_decstring(*m_begin1, ',', 2).c_str(), (unsigned int)(c_begin1 - m_begin1));
1218  citer_type c_begin2;
1219  {
1220  iter_type m_begin2 = data.begin(); // mutable new_store non-const iterator, gets held until write_back() or destruction
1221  c_begin2 = m_begin2.immutable(); // get immutable citer_type from newly created store
1222 
1223  REQUIRE(*c_begin2 == *m_begin2);
1224  REQUIRE( c_begin2 == m_begin2);
1225  REQUIRE( ( c_begin2 - m_begin2 ) == 0);
1226  printf(" 2nd store: %s == %s, dist %u\n",
1227  to_decstring(*c_begin2, ',', 2).c_str(), to_decstring(*m_begin2, ',', 2).c_str(), (unsigned int)(c_begin2 - m_begin2));
1228 
1229  REQUIRE(*c_begin2 == *c_begin1);
1230  REQUIRE( c_begin2 != c_begin1);
1231  REQUIRE( ( c_begin2 - c_begin1 ) != 0);
1232  printf("2nd -> 1st store: %s == %s, dist %u\n",
1233  to_decstring(*c_begin2, ',', 2).c_str(), to_decstring(*c_begin1, ',', 2).c_str(), (unsigned int)(c_begin2 - c_begin1));
1234 
1235  m_begin2.write_back(); // write back storage of m_begin2 to parent CoW and invalidate m_begin2
1236  }
1237  // 2nd store -> cow_xxx
1238  citer_type c_begin2b = data.cbegin();
1239  REQUIRE(*c_begin2 == *c_begin2b);
1240  REQUIRE( c_begin2 == c_begin2b);
1241  REQUIRE( ( c_begin2 - c_begin2b ) == 0);
1242  printf("2nd -> cow == cbegin: %s == %s, dist %u\n",
1243  to_decstring(*c_begin2, ',', 2).c_str(), to_decstring(*c_begin2b, ',', 2).c_str(), (unsigned int)(c_begin2 - c_begin2b));
1244  printf("2nd -> 1st : %s == %s, dist %u\n",
1245  to_decstring(*c_begin1, ',', 2).c_str(), to_decstring(*c_begin2, ',', 2).c_str(), (unsigned int)(c_begin1 - c_begin2));
1246 
1247  m_begin1.write_back(); // write back storage of m_begin1 to parent CoW and invalidate m_begin2
1248  }
1249  // 1st store -> cow_xxx
1250  citer_type c_begin1b = data.cbegin();
1251  printf("1st -> cow == cbegin: %s == %s, dist %u\n",
1252  to_decstring(*c_begin1, ',', 2).c_str(), to_decstring(*c_begin1b, ',', 2).c_str(), (unsigned int)(c_begin1 - c_begin1b));
1253  REQUIRE(*c_begin1 == *c_begin1b);
1254  REQUIRE( c_begin1 == c_begin1b);
1255  REQUIRE( ( c_begin1 - c_begin1b ) == 0);
1256  }
1257  return true;
1258 }
1259 
1260 /****************************************************************************************
1261  ****************************************************************************************/
1262 
1263 TEST_CASE( "Iterator Test 00 - Inspect all Iterator Types", "[datatype][std][vector][darray][cow_vector][cow_darray]" ) {
1264  test_00_inspect_iterator_types< std_vector_uint64_t >("std::vector<T>");
1265  test_00_inspect_iterator_types< jau_darray_uint64_t >("jau::darray<T>");
1266  test_00_inspect_iterator_types< jau_cow_vector_uint64_t >("jau::cow_vector<T>");
1267  test_00_inspect_iterator_types< jau_cow_darray_uint64_t >("jau::cow_darray<T>");
1268 }
1269 
1270 TEST_CASE( "STD Vector Test 01 - Validate Iterator and Index Operations", "[datatype][std][vector]" ) {
1271  test_01_validate_iterator_ops< std_vector_uint64_t >("std::vector<T>");
1272 }
1273 
1274 TEST_CASE( "JAU DArray Test 02 - Validate Iterator and Index Operations", "[datatype][jau][darray]" ) {
1275  test_01_validate_iterator_ops< jau_darray_uint64_t >("jau::darray<T>");
1276 }
1277 
1278 TEST_CASE( "JAU COW_Vector Test 11 - Validate Iterator Operations", "[datatype][jau][cow_vector]" ) {
1279  test_01_validate_iterator_ops< jau_cow_vector_uint64_t >("jau::cow_vector<T>");
1280 
1281  test_01_cow_iterator_properties<jau_cow_vector_uint64_t>("jau::cow_vector<T>");
1282 }
1283 
1284 TEST_CASE( "JAU COW_DArray Test 21 - Validate Iterator Operations", "[datatype][jau][cow_darray]" ) {
1285  test_01_validate_iterator_ops< jau_cow_darray_uint64_t >("jau::cow_darray<T>");
1286 
1287  test_01_cow_iterator_properties<jau_cow_darray_uint64_t>("jau::cow_darray<T>");
1288 }
callocator.hpp
jau::to_decstring
std::string to_decstring(const value_type &v, const char separator=',', const nsize_t width=0) noexcept
Produce a decimal string representation of an integral integer value.
Definition: string_util.hpp:143
darray.hpp
counting_callocator.hpp
basic_algos.hpp
jau::type_cue::print
static void print(const std::string &typedefname, const TypeTraitGroup verbosity=TypeTraitGroup::NONE)
Print information of this type to stdout, potentially with all Type traits known.
Definition: type_traits_queries.hpp:135
test_iterator_compare
static void test_iterator_compare(const typename T::size_type size, iterator_type1 &begin, iterator_type2 &end, iterator_type3 &citer1, iterator_type4 &citer2, const typename T::difference_type citer1_idx, const typename T::difference_type citer2_idx)
Definition: test_cow_iterator_01.cpp:176
print_iterator_info
static void print_iterator_info(const std::string &typedefname, typename std::enable_if< std::is_class< Iter >::value >::type *=0)
Definition: test_cow_iterator_01.cpp:97
test_00_inspect_iterator_types
static bool test_00_inspect_iterator_types(const std::string &type_id)
Definition: test_cow_iterator_01.cpp:120
test_iterator_notequal
static void test_iterator_notequal(iterator_type1 &citer1, iterator_type2 &citer2)
Definition: test_cow_iterator_01.cpp:159
jau
Definition: basic_algos.hpp:34
jau::is_cow_type
template< class T > is_cow_type<T>::value compile-time Type Trait, determining whether the given temp...
Definition: cow_iterator.hpp:1039
jau::darray
Implementation of a dynamic linear array storage, aka vector.
Definition: darray.hpp:102
cow_darray.hpp
jau_cow_darray_uint64_t
jau::cow_darray< uint64_t, counting_callocator< uint64_t > > jau_cow_darray_uint64_t
Definition: test_cow_iterator_01.cpp:58
test_01_cow_iterator_properties
static bool test_01_cow_iterator_properties(const std::string &type_id)
Definition: test_cow_iterator_01.cpp:1122
cow_vector.hpp
jau_cow_vector_uint64_t
jau::cow_vector< uint64_t, counting_allocator< uint64_t > > jau_cow_vector_uint64_t
Definition: test_cow_iterator_01.cpp:57
test_iterator_equal
static void test_iterator_equal(iterator_type1 &citer1, iterator_type2 &citer2)
Definition: test_cow_iterator_01.cpp:144
JAU_TYPENAME_CUE_ALL
#define JAU_TYPENAME_CUE_ALL(A)
Definition: type_traits_queries.hpp:223
test_iterator_arithmetic
static void test_iterator_arithmetic(const typename T::size_type size, iterator_type1 &begin, iterator_type2 &end)
Definition: test_cow_iterator_01.cpp:295
jau::cow_darray
Implementation of a Copy-On-Write (CoW) using jau::darray as the underlying storage,...
Definition: cow_darray.hpp:130
jau::for_each_const
constexpr UnaryFunction for_each_const(T &data, UnaryFunction f, std::enable_if_t< is_cow_type< T >::value, bool >=true) noexcept
Definition: basic_algos.hpp:323
TEST_CASE
TEST_CASE("Iterator Test 00 - Inspect all Iterator Types", "[datatype][std][vector][darray][cow_vector][cow_darray]")
Definition: test_cow_iterator_01.cpp:1263
test_iterator_dereference
static void test_iterator_dereference(const typename T::size_type size, iterator_type1 &begin, iterator_type2 &end)
Definition: test_cow_iterator_01.cpp:243
counting_allocator.hpp
print_list
static void print_list(T &data)
Definition: test_cow_iterator_01.cpp:66
test_mutable_iterator_ops
static bool test_mutable_iterator_ops(const std::string &type_id, std::enable_if_t< is_cow_type< T >::value, bool >=true)
Definition: test_cow_iterator_01.cpp:465
std_vector_uint64_t
std::vector< uint64_t, counting_allocator< uint64_t > > std_vector_uint64_t
Definition: test_cow_iterator_01.cpp:55
test_citer_type_ops
static bool test_citer_type_ops(const std::string &type_id, std::enable_if_t< is_cow_type< T >::value, bool >=true)
Definition: test_cow_iterator_01.cpp:389
basic_types.hpp
jau_darray_uint64_t
jau::darray< uint64_t, counting_callocator< uint64_t > > jau_darray_uint64_t
Definition: test_cow_iterator_01.cpp:56
catch2_ext.hpp
jau::cow_vector
Implementation of a Copy-On-Write (CoW) using std::vector as the underlying storage,...
Definition: cow_vector.hpp:107
test_01_validate_iterator_ops
static bool test_01_validate_iterator_ops(const std::string &type_id)
Definition: test_cow_iterator_01.cpp:1112
fill_list
static void fill_list(T &data, const std::size_t size)
Definition: test_cow_iterator_01.cpp:84