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