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