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