Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah_iterator_test.cc
Go to the documentation of this file.
1
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
38#include <gtest/gtest.h>
39
40#include <algorithm>
41#include <type_traits>
42#include <utility>
43#include <vector>
44
45#include <ah-ranges.H>
46#include <array_it.H>
47#include <tpl_array.H>
48#include <tpl_dynArray.H>
49#include <tpl_dynArrayHeap.H>
50#include <tpl_dynDlist.H>
51#include <tpl_dynSetTree.H>
52
53using namespace Aleph;
54
55#if ALEPH_HAS_RANGES
56
57#include <concepts>
58#include <iterator>
59
60namespace
61{
62
63template <class C>
64concept HasBeginEnd = requires(C & c) {
65 c.begin();
66 c.end();
67};
68
69} // namespace
70
72{
75
76 static_assert(std::forward_iterator<Iter>);
77 static_assert(std::forward_iterator<CIter>);
78
79 static_assert(std::same_as<std::iter_reference_t<Iter>, std::iter_reference_t<const Iter>>);
80 static_assert(std::same_as<std::iter_reference_t<CIter>, std::iter_reference_t<const CIter>>);
81
82 SUCCEED();
83}
84
86{
87 using Set = DynSetTree<int>;
88 using Iter = Set::iterator;
89 using CIter = Set::const_iterator;
90
91 static_assert(std::forward_iterator<Iter>);
92 static_assert(std::forward_iterator<CIter>);
93
94 static_assert(std::same_as<std::iter_reference_t<Iter>, std::iter_reference_t<const Iter>>);
95 static_assert(std::same_as<std::iter_reference_t<CIter>, std::iter_reference_t<const CIter>>);
96
97 using Ref = std::iter_reference_t<Iter>;
98 using Ptr = std::add_pointer_t<std::remove_reference_t<Ref>>;
99 static_assert(std::same_as<decltype(std::declval<const Iter &>().operator->()), Ptr>,
100 "operator-> must return a pointer consistent with operator*");
101
102 SUCCEED();
103}
104
106{
107 DynDlist<int> list;
108 list.append(1);
109 list.append(2);
110
111 const DynDlist<int> & clist = list;
112
113 static_assert(std::same_as<decltype(clist.begin()), DynDlist<int>::const_iterator>);
114 static_assert(std::same_as<decltype(begin(clist)), DynDlist<int>::const_iterator>);
115
116 SUCCEED();
117}
118
120{
121 using C = const DynDlist<int>;
122
123 static_assert(std::same_as<decltype(std::declval<C &>().begin()), DynDlist<int>::const_iterator>);
124 static_assert(std::same_as<decltype(begin(std::declval<C &>())), DynDlist<int>::const_iterator>);
125
126 SUCCEED();
127}
128
130{
131 DynDlist<int> list;
132 for (int i = 1; i <= 5; ++i)
133 list.append(i);
134
135 std::vector<int> v;
136 for (int & x : list)
137 v.push_back(x);
138
139 ASSERT_EQ(v.size(), 5u);
140 EXPECT_EQ(v[0], 1);
141 EXPECT_EQ(v[4], 5);
142
143 const DynDlist<int> & clist = list;
144 int sum = 0;
145 for (const int & x : clist)
146 sum += x;
147
148 EXPECT_EQ(sum, 15);
149}
150
152{
153 DynDlist<int> list;
154 list.append(1);
155 list.append(2);
156
157 auto it = list.begin();
158 ASSERT_NE(it, list.end());
159
160 *it = 10;
161 EXPECT_EQ(*list.begin(), 10);
162}
163
165{
166 DynSetTree<int> set;
167 set.insert(5);
168 set.insert(2);
169 set.insert(8);
170 set.insert(1);
171 set.insert(9);
172
173 EXPECT_TRUE(std::ranges::all_of(set, [](int x) { return x > 0; }));
174
175 auto it = std::ranges::find(set, 5);
176 ASSERT_NE(it, set.end());
177 EXPECT_EQ(*it, 5);
178
179 auto min_it = std::ranges::min_element(set);
180 ASSERT_NE(min_it, set.end());
181 EXPECT_EQ(*min_it, 1);
182}
183
185{
187
188 Iter a;
189 Iter b;
190 EXPECT_TRUE(a == b);
191 EXPECT_FALSE(a != b);
192}
193
195{
196 DynDlist<int> list;
197 list.append(1);
198 list.append(2);
199
200 auto it = list.begin();
201 auto old = it++;
202
203 EXPECT_EQ(*old, 1);
204 EXPECT_EQ(*it, 2);
205}
206
208{
210
211 static_assert(std::random_access_iterator<Iter>);
212 static_assert(std::same_as<
213 typename std::iterator_traits<Iter>::iterator_category,
214 std::random_access_iterator_tag>);
215
216 SUCCEED();
217}
218
220{
222
223 static_assert(std::random_access_iterator<Iter>);
224
225 SUCCEED();
226}
227
229{
230 static_assert(std::random_access_iterator<DynArray<int>::const_iterator>);
231 static_assert(std::random_access_iterator<Array<int>::const_iterator>);
232
233 // Non-opted-in containers must keep their forward category.
234 static_assert(std::forward_iterator<DynDlist<int>::const_iterator>);
235 static_assert(not std::random_access_iterator<DynDlist<int>::const_iterator>);
236
237 SUCCEED();
238}
239
241{
242 // The heap reuses DynArray::Iterator as a base but redefines get_pos() with
243 // an offset. The self-referential marker prevents inheriting the
244 // random-access promotion, so it must NOT be a random_access_iterator.
246
247 static_assert(std::forward_iterator<Iter>);
248 static_assert(not std::random_access_iterator<Iter>);
249
250 SUCCEED();
251}
252
254{
256 for (int i = 0; i < 10; ++i)
257 a.append(i);
258
259 auto first = a.begin();
260
261 EXPECT_EQ(a.end() - first, 10);
262 EXPECT_EQ(*(first + 3), 3);
263 EXPECT_EQ(*(3 + first), 3); // symmetric operator+
264 EXPECT_EQ(first[7], 7);
265
266 auto it = first;
267 it += 5;
268 EXPECT_EQ(*it, 5);
269 it -= 2;
270 EXPECT_EQ(*it, 3);
271 EXPECT_EQ(it - first, 3);
272
273 EXPECT_TRUE(first < it);
274 EXPECT_TRUE(it > first);
275 EXPECT_TRUE(first <= first);
276 EXPECT_TRUE(first >= first);
277
278 --it;
279 EXPECT_EQ(*it, 2);
280 auto prev = it--;
281 EXPECT_EQ(*prev, 2);
282 EXPECT_EQ(*it, 1);
283}
284
286{
288 for (int v : {5, 2, 8, 1, 9, 3, 7, 4, 6, 0})
289 a.append(v);
290
291 std::sort(a.begin(), a.end());
292
293 std::vector<int> v;
294 for (int x : a)
295 v.push_back(x);
296 EXPECT_TRUE(std::is_sorted(v.begin(), v.end()));
297 EXPECT_EQ(v.front(), 0);
298 EXPECT_EQ(v.back(), 9);
299
300 std::ranges::sort(a, std::ranges::greater{});
301 v.clear();
302 for (int x : a)
303 v.push_back(x);
304 EXPECT_EQ(v.front(), 9);
305 EXPECT_EQ(v.back(), 0);
306}
307
309{
310 Array<int> a;
311 for (int v : {3, 1, 2, 5, 4})
312 a.append(v);
313
314 std::sort(a.begin(), a.end());
315
316 std::vector<int> v;
317 for (int x : a)
318 v.push_back(x);
319 EXPECT_TRUE(std::is_sorted(v.begin(), v.end()));
320 EXPECT_EQ(v.front(), 1);
321 EXPECT_EQ(v.back(), 5);
322}
323
325{
326 // std::regular (required by std::random_access_iterator) demands that two
327 // value-initialized iterators compare equal. DynArray::Iterator::has_curr()
328 // must therefore be null-safe on singular iterators.
330 EXPECT_TRUE(a == b);
331 EXPECT_FALSE(a != b);
332
334 EXPECT_TRUE(c == d);
335 EXPECT_FALSE(c != d);
336}
337
339{
341 for (int i = 0; i < 10; ++i)
342 a.append(i);
343
344 const DynArray<int> &ca = a;
345 auto first = ca.begin();
346
347 EXPECT_EQ(ca.end() - first, 10);
348 EXPECT_EQ(*(first + 3), 3);
349 EXPECT_EQ(*(3 + first), 3);
350 EXPECT_EQ(first[7], 7);
351 EXPECT_TRUE(first < ca.end());
352
353 auto it = first;
354 it += 5;
355 EXPECT_EQ(*it, 5);
356 --it;
357 EXPECT_EQ(*it, 4);
358 it -= 2;
359 EXPECT_EQ(*it, 2);
360 EXPECT_EQ(it - first, 2);
361
362 // O(log n) algorithms require random access on the const view.
363 EXPECT_TRUE(std::binary_search(ca.begin(), ca.end(), 5));
364 auto lb = std::lower_bound(ca.begin(), ca.end(), 7);
365 ASSERT_NE(lb, ca.end());
366 EXPECT_EQ(*lb, 7);
367
368 Array<int> arr;
369 for (int v : {1, 2, 3})
370 arr.append(v);
371 const Array<int> &carr = arr;
372 EXPECT_EQ(carr.end() - carr.begin(), 3);
373 EXPECT_EQ(carr.begin()[2], 3);
374}
375
377{
378 // Regression: Array_Iterator::end() used to leave pos == -1 on empty
379 // containers (reset_last() with num_items == 0), so end() - begin() was -1
380 // and begin() > end() while begin() == end() also held. The end state must
381 // be position num_items (0 when empty).
382 Array<int> a;
383 EXPECT_EQ(a.end() - a.begin(), 0);
384 EXPECT_TRUE(a.begin() == a.end());
385 EXPECT_FALSE(a.begin() < a.end());
386 EXPECT_FALSE(a.begin() > a.end());
387 EXPECT_EQ(std::distance(a.begin(), a.end()), 0);
388 std::sort(a.begin(), a.end()); // must be a harmless no-op
389 EXPECT_EQ(a.size(), 0u);
390
391 const Array<int> &ca = a;
392 EXPECT_EQ(ca.end() - ca.begin(), 0);
393 EXPECT_TRUE(ca.begin() == ca.end());
394
396 EXPECT_EQ(d.end() - d.begin(), 0);
397 EXPECT_TRUE(d.begin() == d.end());
398}
399
401{
402 // Physical buffer of size 5; logical sequence of 4 items starting at physical
403 // index 3 and wrapping around: logical [0..3] -> physical [3, 4, 0, 1].
404 int buf[5] = {20, 30, 999, 0, 10};
405 Array_Iterator<int> it(buf, 5, 4, 3, 1); // ptr, dim, num_items, first, last
406
407 it.set_pos(0);
408 EXPECT_EQ(it.get_curr(), 0); // buf[3]
409 it.set_pos(1);
410 EXPECT_EQ(it.get_curr(), 10); // buf[4]
411 it.set_pos(2);
412 EXPECT_EQ(it.get_curr(), 20); // buf[0]
413 it.set_pos(3);
414 EXPECT_EQ(it.get_curr(), 30); // buf[1]
415
416 // set_pos(num_items) must reproduce the exact end() state.
417 Array_Iterator<int> at_end(buf, 5, 4, 3, 1);
418 at_end.end();
419
420 it.set_pos(4);
421 EXPECT_FALSE(it.has_curr());
422 EXPECT_EQ(it.get_pos(), at_end.get_pos());
423}
424
425#else // !ALEPH_HAS_RANGES
426
427// Dummy test when ranges/concepts are not available
429{
430 GTEST_SKIP() << "C++20 concepts not fully supported on this platform";
431}
432
433#endif // ALEPH_HAS_RANGES
C++20 Ranges support and adaptors for Aleph-w containers.
Iterator wrapper for C++ raw arrays and circular buffers.
Iterator wrapper for C++ raw arrays.
Definition array_it.H:85
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
constexpr size_t size() const noexcept
Return the number of elements stored in the stack.
Definition tpl_array.H:365
T & append(const T &data)
Append a copy of data
Definition tpl_array.H:250
Dynamic heap (priority queue) backed by DynArray.
T & append()
Allocate a new entry to the end of array.
Dynamic doubly linked list with O(1) size and bidirectional access.
T & append(const T &item)
Append a copied item at the end of the list.
Dynamic set backed by balanced binary search trees with automatic memory management.
Key * insert(const Key &key)
Inserts a key into the dynamic set.
iterator end() noexcept
Return an STL-compatible end iterator.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
#define TEST(name)
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Dynamic array container with automatic resizing.
Array-based dynamic binary heap.
Lazy and scalable dynamic array implementation.
Dynamic doubly linked list implementation.
Dynamic set implementations based on balanced binary search trees.