Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ranges_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
55#include <gtest/gtest.h>
56#include <algorithm>
57
58#include <ah-ranges.H>
59#include <tpl_dynDlist.H>
60#include <tpl_dynArray.H>
61#include <tpl_dynSetTree.H>
62
63using namespace Aleph;
64
65#if ALEPH_HAS_RANGES
66
67//============================================================================
68// Concept Verification Tests
69//============================================================================
70
71// Test that iterator types satisfy the required concepts
73{
75
76 // Check individual concept requirements
77 static_assert(std::movable<Iter>, "Iterator must be movable");
78 static_assert(std::copyable<Iter>, "Iterator must be copyable");
79 static_assert(std::default_initializable<Iter>, "Iterator must be default initializable");
80 static_assert(std::weakly_incrementable<Iter>, "Iterator must be weakly incrementable");
81
82 // Check that dereferencing a const iterator works
83 static_assert(requires(const Iter it) { *it; },
84 "Must be able to dereference const iterator");
85
86 // The main requirement: iter_reference_t must be same for const and non-const
87 static_assert(std::same_as<std::iter_reference_t<Iter>,
88 std::iter_reference_t<const Iter>>,
89 "iter_reference_t<I> must equal iter_reference_t<const I>");
90
91 // Check indirectly_readable (this is what was failing before)
92 static_assert(std::indirectly_readable<Iter>,
93 "Iterator must satisfy indirectly_readable");
94
95 // Check input_iterator
96 static_assert(std::input_iterator<Iter>,
97 "Iterator must satisfy input_iterator");
98
99 // Check forward_iterator (Aleph claims forward_iterator_tag)
100 static_assert(std::forward_iterator<Iter>,
101 "Iterator must satisfy forward_iterator");
102
103 SUCCEED();
104}
105
107{
109
110 static_assert(std::indirectly_readable<Iter>,
111 "Const iterator must satisfy indirectly_readable");
112 static_assert(std::input_iterator<Iter>,
113 "Const iterator must satisfy input_iterator");
114 static_assert(std::forward_iterator<Iter>,
115 "Const iterator must satisfy forward_iterator");
116
117 SUCCEED();
118}
119
121{
123
124 static_assert(std::same_as<std::iter_reference_t<Iter>,
125 std::iter_reference_t<const Iter>>,
126 "iter_reference_t<I> must equal iter_reference_t<const I>");
127 static_assert(std::indirectly_readable<Iter>,
128 "Iterator must satisfy indirectly_readable");
129 static_assert(std::input_iterator<Iter>,
130 "Iterator must satisfy input_iterator");
131
132 SUCCEED();
133}
134
136{
137 using Set = DynSetTree<int>;
138 using Iter = Set::iterator;
139
140 static_assert(std::same_as<std::iter_reference_t<Iter>,
141 std::iter_reference_t<const Iter>>,
142 "iter_reference_t<I> must equal iter_reference_t<const I>");
143 static_assert(std::indirectly_readable<Iter>,
144 "Iterator must satisfy indirectly_readable");
145 static_assert(std::input_iterator<Iter>,
146 "Iterator must satisfy input_iterator");
147
148 SUCCEED();
149}
150
151//============================================================================
152// Range Concept Tests
153//============================================================================
154
156{
157 static_assert(std::ranges::range<DynDlist<int>>,
158 "DynDlist must satisfy std::ranges::range");
159 static_assert(std::ranges::input_range<DynDlist<int>>,
160 "DynDlist must satisfy std::ranges::input_range");
161 static_assert(std::ranges::forward_range<DynDlist<int>>,
162 "DynDlist must satisfy std::ranges::forward_range");
163
164 SUCCEED();
165}
166
168{
169 static_assert(std::ranges::range<const DynDlist<int>>,
170 "const DynDlist must satisfy std::ranges::range");
171 static_assert(std::ranges::input_range<const DynDlist<int>>,
172 "const DynDlist must satisfy std::ranges::input_range");
173
174 SUCCEED();
175}
176
177//============================================================================
178// Functional Tests with std::ranges Algorithms
179//============================================================================
180
181class RangesAlgorithmTest : public ::testing::Test
182{
183protected:
184 DynDlist<int> list;
185
186 void SetUp() override
187 {
188 list.append(1);
189 list.append(2);
190 list.append(3);
191 list.append(4);
192 list.append(5);
193 }
194};
195
197{
198 EXPECT_TRUE(std::ranges::all_of(list, [](int x) { return x > 0; }));
199 EXPECT_FALSE(std::ranges::all_of(list, [](int x) { return x > 3; }));
200}
201
203{
204 EXPECT_TRUE(std::ranges::any_of(list, [](int x) { return x == 3; }));
205 EXPECT_FALSE(std::ranges::any_of(list, [](int x) { return x == 10; }));
206}
207
209{
210 EXPECT_TRUE(std::ranges::none_of(list, [](int x) { return x < 0; }));
211 EXPECT_FALSE(std::ranges::none_of(list, [](int x) { return x == 3; }));
212}
213
215{
216 auto it = std::ranges::find(list, 3);
217 EXPECT_NE(it, list.end());
218 EXPECT_EQ(*it, 3);
219
220 auto not_found = std::ranges::find(list, 10);
221 EXPECT_EQ(not_found, list.end());
222}
223
225{
226 auto it = std::ranges::find_if(list, [](int x) { return x % 2 == 0; });
227 EXPECT_NE(it, list.end());
228 EXPECT_EQ(*it, 2); // First even number
229}
230
232{
233 list.append(3); // Add another 3
234 auto count = std::ranges::count(list, 3);
235 EXPECT_EQ(count, 2);
236}
237
239{
240 auto count = std::ranges::count_if(list, [](int x) { return x % 2 == 0; });
241 EXPECT_EQ(count, 2); // 2 and 4
242}
243
245{
246 auto it = std::ranges::min_element(list);
247 EXPECT_NE(it, list.end());
248 EXPECT_EQ(*it, 1);
249}
250
252{
253 auto it = std::ranges::max_element(list);
254 EXPECT_NE(it, list.end());
255 EXPECT_EQ(*it, 5);
256}
257
259{
260 int sum = 0;
261 std::ranges::for_each(list, [&sum](int x) { sum += x; });
262 EXPECT_EQ(sum, 15); // 1+2+3+4+5
263}
264
266{
267 int sum = 0;
268 std::ranges::for_each(list, [&sum](int x) { sum += x; },
269 [](int x) { return x * 2; }); // Project: double each
270 EXPECT_EQ(sum, 30); // (1+2+3+4+5)*2
271}
272
273//============================================================================
274// Tests with const containers
275//============================================================================
276
278{
283
285
286 EXPECT_TRUE(std::ranges::all_of(const_list, [](int x) { return x > 0; }));
287}
288
290{
295
297
298 auto it = std::ranges::find(const_list, 2);
299 EXPECT_NE(it, const_list.end());
300 EXPECT_EQ(*it, 2);
301}
302
303//============================================================================
304// Tests with range adaptors (views)
305//============================================================================
306
308{
309 auto evens = list | std::views::filter([](int x) { return x % 2 == 0; });
310
311 std::vector<int> result;
312 for (int x : evens)
313 result.push_back(x);
314
315 ASSERT_EQ(result.size(), 2u);
316 EXPECT_EQ(result[0], 2);
317 EXPECT_EQ(result[1], 4);
318}
319
321{
322 auto doubled = list | std::views::transform([](int x) { return x * 2; });
323
324 std::vector<int> result;
325 for (int x : doubled)
326 result.push_back(x);
327
328 ASSERT_EQ(result.size(), 5u);
329 EXPECT_EQ(result[0], 2);
330 EXPECT_EQ(result[1], 4);
331 EXPECT_EQ(result[2], 6);
332 EXPECT_EQ(result[3], 8);
333 EXPECT_EQ(result[4], 10);
334}
335
337{
338 auto first_three = list | std::views::take(3);
339
340 std::vector<int> result;
341 for (int x : first_three)
342 result.push_back(x);
343
344 ASSERT_EQ(result.size(), 3u);
345 EXPECT_EQ(result[0], 1);
346 EXPECT_EQ(result[1], 2);
347 EXPECT_EQ(result[2], 3);
348}
349
351{
352 // Filter evens, then double them
353 auto result_view = list
354 | std::views::filter([](int x) { return x % 2 == 0; })
355 | std::views::transform([](int x) { return x * 2; });
356
357 std::vector<int> result;
358 for (int x : result_view)
359 result.push_back(x);
360
361 ASSERT_EQ(result.size(), 2u);
362 EXPECT_EQ(result[0], 4); // 2 * 2
363 EXPECT_EQ(result[1], 8); // 4 * 2
364}
365
366//============================================================================
367// Tests with DynArray
368//============================================================================
369
371{
372 DynArray<int> arr;
373 arr.append(10);
374 arr.append(20);
375 arr.append(30);
376
377 EXPECT_TRUE(std::ranges::all_of(arr, [](int x) { return x >= 10; }));
378
379 auto it = std::ranges::find(arr, 20);
380 EXPECT_NE(it, arr.end());
381 EXPECT_EQ(*it, 20);
382
383 auto max_it = std::ranges::max_element(arr);
384 EXPECT_EQ(*max_it, 30);
385}
386
387//============================================================================
388// Tests with DynSetTree
389//============================================================================
390
392{
393 DynSetTree<int> set;
394 set.insert(5);
395 set.insert(2);
396 set.insert(8);
397 set.insert(1);
398 set.insert(9);
399
400 // All elements positive
401 EXPECT_TRUE(std::ranges::all_of(set, [](int x) { return x > 0; }));
402
403 // Find element
404 auto it = std::ranges::find(set, 5);
405 EXPECT_NE(it, set.end());
406 EXPECT_EQ(*it, 5);
407
408 // Count elements > 5
409 auto count = std::ranges::count_if(set, [](int x) { return x > 5; });
410 EXPECT_EQ(count, 2); // 8 and 9
411
412 // Min element (sets are ordered)
413 auto min_it = std::ranges::min_element(set);
414 EXPECT_EQ(*min_it, 1);
415}
416
417#else // !ALEPH_HAS_RANGES
418
419// Dummy test when ranges are not available
421{
422 GTEST_SKIP() << "std::ranges not fully supported on this platform";
423}
424
425#endif // ALEPH_HAS_RANGES
426
427//============================================================================
428// Main
429//============================================================================
430
431int main(int argc, char **argv)
432{
433 testing::InitGoogleTest(&argc, argv);
434 return RUN_ALL_TESTS();
435}
TEST_F(StaticArenaFixture, simple_fail)
Definition ah-arena.cc:59
C++20 Ranges support and adaptors for Aleph-w containers.
int main()
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.
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
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.
#define TEST(name)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
DynList< T > maps(const C &c, Op op)
Classic map operation.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Lazy and scalable dynamic array implementation.
Dynamic doubly linked list implementation.
Dynamic set implementations based on balanced binary search trees.