Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-functional.cc
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
32
37# include <gtest/gtest.h>
38# include <cctype>
39# include <cmath>
40
41# include <ah-zip.H>
42# include <ahFunctional.H>
43# include <ah-string-utils.H>
44# include <tpl_dynSetTree.H>
45# include <tpl_dynSetHash.H>
46# include <tpl_odhash.H>
47# include <tpl_dynArray.H>
48
49using namespace std;
50using namespace Aleph;
51
53{
54 EXPECT_EQ(range(0, 10), build_dynlist<int>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
55 EXPECT_EQ(range(0, 10, 2), build_dynlist<int>(0, 2, 4, 6, 8, 10));
56 EXPECT_EQ(nrange(2, 5, 3), build_dynlist<int>(2, 3, 5));
57 EXPECT_EQ(contiguous_range(1, 5), build_dynlist<int>(1, 2, 3, 4, 5));
58 EXPECT_EQ(range(5), build_dynlist<int>(0, 1, 2, 3, 4));
59}
60
62{
63 EXPECT_EQ(rep(5, 0), build_dynlist<int>(0, 0, 0, 0, 0));
64 EXPECT_EQ(rep(3), build_dynlist<int>(0, 0, 0));
65}
66
68{
69 auto sq = [] (int x) { return x * x; };
70 auto r = set_range<int, DynList>(0, 4, 1, sq);
71 EXPECT_EQ(r, build_dynlist<int>(0, 1, 4, 9, 16));
72
73 auto r2 = set_range<int, DynList>(0, 6, 2, sq);
74 EXPECT_EQ(r2, build_dynlist<int>(0, 4, 16, 36));
75}
76
78{
79 size_t count = 0;
80 each(5, [&count] () { ++count; });
81 EXPECT_EQ(count, 5);
82
83 count = 0;
84 each(2, 5, [&count] () { ++count; });
85 EXPECT_EQ(count, 4);
86}
87
88struct TreeContainer : testing::Test
89{
90 static constexpr size_t N = 10;
93 {
94 tbl = range<size_t>(0, N - 1);
95 }
96};
97
99{
100 auto l = pointers_list(tbl);
101
102 size_t i = 0;
103 for (auto it = l.get_it(); it.has_curr(); it.next_ne(), ++i)
104 EXPECT_EQ(*it.get_curr_ne(), i);
105
106 EXPECT_TRUE(zip_all([] (auto t) { return *get<0>(t) == get<1>(t); }, l, tbl));
107}
108
114
116{
117 size_t i = 0;
118 for_each(tbl, [&i] (auto & k)
119 {
120 EXPECT_EQ(i++, k);
121 });
122
123 enum_for_each(tbl, ([] (auto & k, auto & i)
124 {
125 EXPECT_EQ(i, k);
126 }));
127
128 i = 0;
129 EXPECT_TRUE(all(tbl, [&i] (auto & k) { return k == i++; }));
130
131 EXPECT_TRUE(exists(tbl, [] (auto & i) { return i == 3; }));
132 EXPECT_FALSE(exists(tbl, [] (auto & i) { return i == N; }));
133
134 auto lfilt = filter(tbl, [] (auto & i) { return i <= 3; });
136
137 auto lp = maps<string>(tbl, [] (const auto & i) { return to_string(i); });
139 ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"));
140
141 auto lf = foldl<size_t>(tbl, 0, [] (auto & a, auto & i) { return a + i; });
142 EXPECT_EQ(lf, N*(N - 1)/2);
143}
144
146{
147 auto l = gen_seq_list_tuples(tbl, 7);
149 ( build_dynlist<size_t>(0, 1, 2, 3, 4, 5, 6),
150 build_dynlist<size_t>(1, 2, 3, 4, 5, 6, 7),
151 build_dynlist<size_t>(2, 3, 4, 5, 6, 7, 8),
152 build_dynlist<size_t>(3, 4, 5, 6, 7, 8, 9) ));
153}
154
156{
157 auto l = enumerate(tbl);
158 EXPECT_TRUE(l.all([] (auto & p) { return p.first == p.second; }));
159}
160
162{
163 auto idx = indexes(tbl);
164 size_t i = 0;
165 for (auto it = idx.get_it(); it.has_curr(); it.next_ne(), ++i)
166 {
167 auto & p = it.get_curr();
168 EXPECT_EQ(p.first, i);
169 EXPECT_EQ(p.second, i);
170 }
171
172 auto tidx = tindexes(tbl);
173 i = 0;
174 for (auto it = tidx.get_it(); it.has_curr(); it.next_ne(), ++i)
175 {
176 auto & t = it.get_curr();
177 EXPECT_EQ(get<0>(t), i);
178 EXPECT_EQ(get<1>(t), i);
179 }
180}
181
183{
185 auto rev = reverse(l);
186 EXPECT_EQ(rev, build_dynlist<size_t>(9, 8, 7, 6, 5, 4, 3, 2, 1, 0));
187}
188
190{
191 auto p = partition(tbl, [] (const size_t & i) { return i < 5; });
192 EXPECT_EQ(p.first, build_dynlist<size_t>(0, 1, 2, 3, 4));
193 EXPECT_EQ(p.second, build_dynlist<size_t>(5, 6, 7, 8, 9));
194}
195
197{
201
202 l2.get_last() = 100;
204}
205
207{
209 EXPECT_TRUE(containers_eq(tbl, l, std::equal_to<size_t>()));
210}
211
213{
214 constexpr size_t N = 20;
216 DynList<size_t> l2 = range(N + 1);
219
220 EXPECT_TRUE(eq(l1, s1));
225
226 auto d = are_eq(l1, s1);
228 EXPECT_EQ(get<1>(d), N);
229
230 // Now we modify the last item of l1
231 l1.get_last() = N - 2;
232 EXPECT_FALSE(eq(l1, s1));
234
235 d = are_eq(l1, s1);
237 EXPECT_EQ(get<1>(d), N - 1);
238 EXPECT_EQ(get<2>(d), N - 2);
239 EXPECT_EQ(get<3>(d), N - 1);
240}
241
243{
244 {
245 auto z = zip(tbl, range(N));
246 EXPECT_TRUE(z.all([] (auto & p) { return p.first == p.second; }));
247
248 auto p = unzip(z);
249 EXPECT_TRUE(zip_all([] (auto p) { return get<0>(p) == get<1>(p); },
250 p.first, p.second));
251 }
252 {
253 auto z = tzip(tbl, range(N));
254 EXPECT_TRUE(z.all([] (auto & p) { return get<0>(p) == get<1>(p); }));
255
256 auto p = tunzip(z);
257 EXPECT_TRUE(zip_all([] (auto p) { return get<0>(p) == get<1>(p); },
258 get<0>(p), get<1>(p)));
259 }
260 {
261 auto z = zipEq(tbl, range(N));
262 EXPECT_TRUE(z.all([] (auto & p) { return p.first == p.second; }));
263
264 EXPECT_THROW(zipEq(tbl, range(N + 1)), length_error);
265
266 auto p = unzip(z);
267 EXPECT_TRUE(zip_all([] (auto p) { return get<0>(p) == get<1>(p); },
268 p.first, p.second));
269 }
270 {
271 auto z = tzipEq(tbl, range(N));
272 EXPECT_TRUE(z.all([] (auto & p) { return get<0>(p) == get<1>(p); }));
273
274 EXPECT_THROW(tzipEq(tbl, range(N + 1)), length_error);
275
276 auto p = tunzip(z);
277 EXPECT_TRUE(zip_all([] (auto p) { return get<0>(p) == get<1>(p); },
278 get<0>(p), get<1>(p)));
279 }
280}
281
283{
284 DynList<int> l = build_dynlist<int>(1, 1, 2, 2, 2, 4, 4, 0, 0, 1);
285 auto result = sequential_groups(l);
286 EXPECT_EQ(result.second, 5);
287 auto & groups = result.first;
288
289 auto it = groups.get_it();
290 EXPECT_EQ(it.get_curr(), build_dynlist<int>(1, 1)); it.next();
291 EXPECT_EQ(it.get_curr(), build_dynlist<int>(2, 2, 2)); it.next();
292 EXPECT_EQ(it.get_curr(), build_dynlist<int>(4, 4)); it.next();
293 EXPECT_EQ(it.get_curr(), build_dynlist<int>(0, 0)); it.next();
294 EXPECT_EQ(it.get_curr(), build_dynlist<int>(1));
295
296 // Empty container
297 DynList<int> empty;
298 auto empty_result = sequential_groups(empty);
299 EXPECT_EQ(empty_result.second, 0);
300 EXPECT_TRUE(empty_result.first.is_empty());
301}
302
304{
305 DynList<int> l = build_dynlist<int>(1, 1, 2, 2, 2, 4, 4, 0, 0, 1);
306 auto result = unique_sequential(l);
307 EXPECT_EQ(result.second, 5);
308 EXPECT_EQ(result.first, build_dynlist<int>(1, 2, 4, 0, 1));
309
310 // Empty container
311 DynList<int> empty;
312 auto empty_result = unique_sequential(empty);
313 EXPECT_EQ(empty_result.second, 0);
314 EXPECT_TRUE(empty_result.first.is_empty());
315}
316
318{
319 DynList<int> l1 = range(5);
320 DynList<int> l2 = range(5);
321
322 auto pit = get_pair_it(l1, l2);
323 size_t i = 0;
324 while (pit.has_curr())
325 {
326 auto p = pit.get_curr();
327 EXPECT_EQ(p.first, i);
328 EXPECT_EQ(p.second, i);
329 pit.next();
330 ++i;
331 }
332 EXPECT_EQ(i, 5);
333 EXPECT_TRUE(pit.was_traversed());
334
335 // Test with position
336 auto pit2 = get_pair_it(l1, l2, 2);
337 auto p = pit2.get_curr();
338 EXPECT_EQ(p.first, 2);
339 EXPECT_EQ(p.second, 2);
340}
341
343{
344 DynList<int> c;
345 size_t n = append_in_container(c, 1, 2, 3);
346 EXPECT_EQ(n, 3);
347 EXPECT_EQ(c, build_dynlist<int>(1, 2, 3));
348
350 n = insert_in_container(s, 5, 3, 1, 4, 2);
351 EXPECT_EQ(n, 5);
352 EXPECT_EQ(s.size(), 5);
353
354 n = remove_from_container(s, 1, 2, 3);
355 EXPECT_EQ(n, 3);
356 EXPECT_EQ(s.size(), 2);
357}
358
365
367{
369 ll.append(build_dynlist<int>(1, 2, 3));
370 ll.append(build_dynlist<int>(4, 5));
371 ll.append(build_dynlist<int>(6, 7, 8, 9));
372
373 auto flat = flatten(ll);
374 EXPECT_EQ(flat, build_dynlist<int>(1, 2, 3, 4, 5, 6, 7, 8, 9));
375}
376
385
387{
388 EXPECT_TRUE(is_equal(5, 3, 5, 7));
389 EXPECT_TRUE(is_equal(5, 5));
390 EXPECT_FALSE(is_equal(5, 1, 2, 3, 4));
392
393 // Mixed types
394 EXPECT_TRUE(is_equal(5, 5.0));
395 EXPECT_TRUE(is_equal(5, 3, 5.0, 7));
396}
397
399{
400 int val = 42;
401 Some<int> s(val);
403 EXPECT_EQ(s.get_item(), 42);
404 s.get_item() = 43;
405 EXPECT_EQ(val, 43);
406
407 None<int> n;
409 EXPECT_THROW(n.get_item(), std::logic_error);
410
411 const None<int> cn;
412 EXPECT_THROW(cn.get_item(), std::logic_error);
413
414 const Some<int> cs(val);
415 EXPECT_EQ(cs.get_item(), 43);
416}
417
419{
420 // Floating point nrange
421 auto r = nrange<double, DynList>(0.0, 1.0, 11);
422 EXPECT_EQ(r.size(), 11u);
423 EXPECT_DOUBLE_EQ(r.get_first(), 0.0);
424 EXPECT_DOUBLE_EQ(r.get_last(), 1.0);
425 EXPECT_DOUBLE_EQ(r.nth(5), 0.5);
426
427 // n=1 case
428 auto r1 = nrange<int, DynList>(10, 20, 1);
429 ASSERT_EQ(r1.size(), 1u);
430 EXPECT_EQ(r1.get_first(), 10);
431
432 // n=0 case
433 EXPECT_THROW(nrange(0, 10, 0), std::domain_error);
434}
435
450
452{
453 size_t count = 0;
454 each(0, [&count] () { ++count; });
455 EXPECT_EQ(count, 0);
456
457 count = 0;
458 each(1, [&count] () { ++count; });
459 EXPECT_EQ(count, 1);
460}
461
462// Tests for new functions
463
465{
466 DynList<int> l = build_dynlist<int>(1, 2, 3, 4, 5);
467 EXPECT_TRUE(none(l, [] (int x) { return x > 10; }));
468 EXPECT_FALSE(none(l, [] (int x) { return x == 3; }));
469
470 DynList<int> empty;
471 EXPECT_TRUE(none(empty, [] (int) { return true; }));
472}
473
475{
476 DynList<int> l = build_dynlist<int>(1, 2, 3, 4, 5);
477
478 auto * p = find_ptr(l, [] (int x) { return x == 3; });
479 ASSERT_NE(p, nullptr);
480 EXPECT_EQ(*p, 3);
481
482 // Modify through pointer
483 *p = 30;
484 EXPECT_EQ(l.nth(2), 30);
485
486 auto * not_found = find_ptr(l, [] (int x) { return x == 100; });
487 EXPECT_EQ(not_found, nullptr);
488
489 // const version
490 const DynList<int> cl = build_dynlist<int>(10, 20, 30);
491 const int * cp = find_ptr(cl, [] (int x) { return x == 20; });
492 ASSERT_NE(cp, nullptr);
493 EXPECT_EQ(*cp, 20);
494}
495
497{
498 DynList<int> l = build_dynlist<int>(1, 2, 3, 4);
499
500 // foldr with subtraction: 1 - (2 - (3 - (4 - 0))) = 1 - (2 - (3 - 4)) = 1 - (2 - (-1)) = 1 - 3 = -2
501 auto result = foldr<int>(l, 0, [] (int a, int b) { return a - b; });
502 EXPECT_EQ(result, -2);
503
504 // Compare with foldl: ((((0 - 1) - 2) - 3) - 4) = -10
505 auto result_l = foldl<int>(l, 0, [] (int a, int b) { return a - b; });
506 EXPECT_EQ(result_l, -10);
507}
508
510{
511 DynList<int> l = build_dynlist<int>(1, 2, 3, 4, 5);
512 EXPECT_EQ(sum(l), 15);
513 EXPECT_EQ(sum(l, 10), 25);
514
515 EXPECT_EQ(product(l), 120);
516 EXPECT_EQ(product(l, 2), 240);
517
518 DynList<int> empty;
519 EXPECT_EQ(sum(empty), 0);
520 EXPECT_EQ(product(empty), 1);
521
522 DynList<double> ld = build_dynlist<double>(1.5, 2.5, 3.0);
523 EXPECT_DOUBLE_EQ(sum(ld), 7.0);
524}
525
527{
530
531 auto c = concat(l1, l2);
532 EXPECT_EQ(c, build_dynlist<int>(1, 2, 3, 4, 5, 6));
533
534 DynList<int> empty;
535 EXPECT_EQ(concat(empty, l1), l1);
536 EXPECT_EQ(concat(l1, empty), l1);
537}
538
540{
541 DynList<int> l = build_dynlist<int>(1, 2, 3, 10, 5, 6);
542
543 auto result = take_while(l, [] (int x) { return x < 5; });
544 EXPECT_EQ(result, build_dynlist<int>(1, 2, 3));
545
546 // All elements satisfy
547 auto all = take_while(l, [] (int) { return true; });
548 EXPECT_EQ(all, l);
549
550 // No elements satisfy
551 auto none_result = take_while(l, [] (int x) { return x > 100; });
552 EXPECT_TRUE(none_result.is_empty());
553}
554
556{
557 DynList<int> l = build_dynlist<int>(1, 2, 3, 10, 5, 6);
558
559 auto result = drop_while(l, [] (int x) { return x < 5; });
560 EXPECT_EQ(result, build_dynlist<int>(10, 5, 6));
561
562 // All elements satisfy - drop all
563 auto all_dropped = drop_while(l, [] (int) { return true; });
564 EXPECT_TRUE(all_dropped.is_empty());
565
566 // No elements satisfy - keep all
567 auto none_dropped = drop_while(l, [] (int x) { return x > 100; });
569}
570
572{
574
575 // Duplicate each element
576 auto result = flat_map(l, [] (int x) {
577 return build_dynlist<int>(x, x);
578 });
579 EXPECT_EQ(result, build_dynlist<int>(1, 1, 2, 2, 3, 3));
580
581 // Create range for each
582 auto ranges = flat_map(l, [] (int x) {
583 return range(x);
584 });
585 EXPECT_EQ(ranges, build_dynlist<int>(0, 0, 1, 0, 1, 2));
586}
587
589{
590 DynList<int> l = build_dynlist<int>(1, 2, 3, 4);
591
592 auto sums = scanl<int>(l, 0, [] (int a, int b) { return a + b; });
593 EXPECT_EQ(sums, build_dynlist<int>(0, 1, 3, 6, 10));
594
595 auto sums2 = scanl_sum(l, 0);
596 EXPECT_EQ(sums2, build_dynlist<int>(0, 1, 3, 6, 10));
597
598 DynList<int> empty;
599 auto empty_scan = scanl<int>(empty, 100, [] (int a, int b) { return a + b; });
601}
602
604{
605 DynList<int> l = build_dynlist<int>(5, 2, 8, 1, 9, 3);
606
607 auto * min_p = min_ptr(l);
608 ASSERT_NE(min_p, nullptr);
609 EXPECT_EQ(*min_p, 1);
610
611 auto * max_p = max_ptr(l);
612 ASSERT_NE(max_p, nullptr);
613 EXPECT_EQ(*max_p, 9);
614
615 auto [minp, maxp] = minmax_ptr(l);
616 ASSERT_NE(minp, nullptr);
617 ASSERT_NE(maxp, nullptr);
618 EXPECT_EQ(*minp, 1);
619 EXPECT_EQ(*maxp, 9);
620
621 // Empty container
622 DynList<int> empty;
623 EXPECT_EQ(min_ptr(empty), nullptr);
624 EXPECT_EQ(max_ptr(empty), nullptr);
625 auto [emp_min, emp_max] = minmax_ptr(empty);
626 EXPECT_EQ(emp_min, nullptr);
627 EXPECT_EQ(emp_max, nullptr);
628
629 // Single element
631 auto [s_min, s_max] = minmax_ptr(single);
632 EXPECT_EQ(*s_min, 42);
633 EXPECT_EQ(*s_max, 42);
634
635 // Custom comparator
636 DynList<int> abs_list = build_dynlist<int>(-10, 5, -20, 3);
637 auto * max_abs = max_ptr(abs_list,
638 [] (const int a, const int b) { return std::abs(a) < std::abs(b); });
639 EXPECT_EQ(*max_abs, -20);
640}
641
643{
644 DynList<int> l = build_dynlist<int>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
645
646 EXPECT_EQ(count_if(l, [] (int x) { return x % 2 == 0; }), 5);
647 EXPECT_EQ(count_if(l, [] (int x) { return x > 5; }), 5);
648 EXPECT_EQ(count_if(l, [] (int x) { return x > 100; }), 0);
649
650 DynList<int> empty;
651 EXPECT_EQ(count_if(empty, [] (int) { return true; }), 0);
652}
653
655{
656 DynList<int> l = build_dynlist<int>(1, 2, 3, 4, 5);
657
663
664 DynList<int> empty;
665 EXPECT_FALSE(contains(empty, 1));
666}
667
669{
670 DynList<string> l = build_dynlist<string>("a", "b", "c");
671
672 auto result = enumerate_tuple(l);
673 EXPECT_EQ(result.size(), 3);
674
675 auto it = result.get_it();
676 EXPECT_EQ(get<0>(it.get_curr()), 0);
677 EXPECT_EQ(get<1>(it.get_curr()), "a");
678 it.next();
679 EXPECT_EQ(get<0>(it.get_curr()), 1);
680 EXPECT_EQ(get<1>(it.get_curr()), "b");
681 it.next();
682 EXPECT_EQ(get<0>(it.get_curr()), 2);
683 EXPECT_EQ(get<1>(it.get_curr()), "c");
684}
685
686// =============================================================================
687// COMPREHENSIVE TESTS FOR ahFunctional.H
688// =============================================================================
689
690// --- zip_longest tests ---
691
693{
694 DynList<int> l1 = build_dynlist<int>(1, 2, 3, 4, 5);
695 DynList<int> l2 = build_dynlist<int>(10, 20, 30);
696
697 auto result = zip_longest(l1, l2, -1, -1);
698 EXPECT_EQ(result.size(), 5);
699
700 auto it = result.get_it();
701 EXPECT_EQ(it.get_curr(), make_pair(1, 10)); it.next();
702 EXPECT_EQ(it.get_curr(), make_pair(2, 20)); it.next();
703 EXPECT_EQ(it.get_curr(), make_pair(3, 30)); it.next();
704 EXPECT_EQ(it.get_curr(), make_pair(4, -1)); it.next();
705 EXPECT_EQ(it.get_curr(), make_pair(5, -1));
706}
707
709{
711 DynList<int> l2 = build_dynlist<int>(10, 20, 30, 40);
712
713 auto result = zip_longest(l1, l2, 0, 0);
714 EXPECT_EQ(result.size(), 4);
715
716 auto it = result.get_it();
717 EXPECT_EQ(it.get_curr(), make_pair(1, 10)); it.next();
718 EXPECT_EQ(it.get_curr(), make_pair(2, 20)); it.next();
719 EXPECT_EQ(it.get_curr(), make_pair(0, 30)); it.next();
720 EXPECT_EQ(it.get_curr(), make_pair(0, 40));
721}
722
724{
727
728 auto result = zip_longest(l1, l2, -1, -1);
729 EXPECT_EQ(result.size(), 3);
730
731 EXPECT_TRUE(result.all([] (auto & p) {
732 return p.first + 3 == p.second;
733 }));
734}
735
737{
740
741 auto r1 = zip_longest(empty1, empty2, 0, 0);
742 EXPECT_TRUE(r1.is_empty());
743
744 auto r2 = zip_longest(l, empty2, 0, -1);
745 EXPECT_EQ(r2.size(), 3);
746 EXPECT_TRUE(r2.all([] (auto & p) { return p.second == -1; }));
747
748 auto r3 = zip_longest(empty1, l, -1, 0);
749 EXPECT_EQ(r3.size(), 3);
750 EXPECT_TRUE(r3.all([] (auto & p) { return p.first == -1; }));
751}
752
753// --- tzip_longest tests ---
754
756{
759
760 auto result = tzip_longest(l1, l2, 0, string("X"));
761 EXPECT_EQ(result.size(), 3);
762
763 auto it = result.get_it();
764 EXPECT_EQ(get<0>(it.get_curr()), 1);
765 EXPECT_EQ(get<1>(it.get_curr()), "a");
766 it.next();
767 EXPECT_EQ(get<0>(it.get_curr()), 2);
768 EXPECT_EQ(get<1>(it.get_curr()), "b");
769 it.next();
770 EXPECT_EQ(get<0>(it.get_curr()), 3);
771 EXPECT_EQ(get<1>(it.get_curr()), "X");
772}
773
774// --- zip_longest_opt tests ---
775
777{
778 DynList<int> l1 = build_dynlist<int>(1, 2, 3, 4);
780
781 auto result = zip_longest_opt(l1, l2);
782 EXPECT_EQ(result.size(), 4);
783
784 auto it = result.get_it();
785 auto p1 = it.get_curr();
786 EXPECT_TRUE(p1.first.has_value());
787 EXPECT_TRUE(p1.second.has_value());
788 EXPECT_EQ(p1.first.value(), 1);
789 EXPECT_EQ(p1.second.value(), 10);
790
791 it.next(); it.next(); it.next();
792 auto p4 = it.get_curr();
793 EXPECT_TRUE(p4.first.has_value());
794 EXPECT_FALSE(p4.second.has_value());
795 EXPECT_EQ(p4.first.value(), 4);
796}
797
798// --- group_by tests ---
799
801{
802 DynList<int> l = build_dynlist<int>(1, 1, 2, 2, 2, 3, 1, 1);
803
804 // group_by takes a key function that extracts the grouping key
805 auto result = group_by(l, [] (int x) { return x; });
806 EXPECT_EQ(result.size(), 4);
807
808 auto it = result.get_it();
809 // Each element is pair<key, DynList<T>>
810 EXPECT_EQ(it.get_curr().first, 1);
811 EXPECT_EQ(it.get_curr().second, build_dynlist<int>(1, 1));
812 it.next();
813 EXPECT_EQ(it.get_curr().first, 2);
814 EXPECT_EQ(it.get_curr().second, build_dynlist<int>(2, 2, 2));
815 it.next();
816 EXPECT_EQ(it.get_curr().first, 3);
817 EXPECT_EQ(it.get_curr().second, build_dynlist<int>(3));
818 it.next();
819 EXPECT_EQ(it.get_curr().first, 1);
820 EXPECT_EQ(it.get_curr().second, build_dynlist<int>(1, 1));
821}
822
824{
825 DynList<int> l = build_dynlist<int>(1, 3, 5, 2, 4, 6, 7, 9);
826
827 // Group by parity (consecutive groups with same parity)
828 auto result = group_by(l, [] (int x) { return x % 2; });
829 EXPECT_EQ(result.size(), 3);
830
831 auto it = result.get_it();
832 EXPECT_EQ(it.get_curr().first, 1); // odd
833 EXPECT_EQ(it.get_curr().second, build_dynlist<int>(1, 3, 5));
834 it.next();
835 EXPECT_EQ(it.get_curr().first, 0); // even
836 EXPECT_EQ(it.get_curr().second, build_dynlist<int>(2, 4, 6));
837 it.next();
838 EXPECT_EQ(it.get_curr().first, 1); // odd again
839 EXPECT_EQ(it.get_curr().second, build_dynlist<int>(7, 9));
840}
841
843{
844 DynList<int> empty;
845 auto result = group_by(empty, [] (int x) { return x; });
846 EXPECT_TRUE(result.is_empty());
847}
848
850{
852 auto result = group_by(single, [] (int x) { return x; });
853 EXPECT_EQ(result.size(), 1);
854 EXPECT_EQ(result.get_first().first, 42);
855 EXPECT_EQ(result.get_first().second, build_dynlist<int>(42));
856}
857
858// --- group_by_reduce tests ---
859
861{
862 DynList<int> l = build_dynlist<int>(1, 1, 2, 2, 2, 3);
863
864 auto result = group_by_reduce(l,
865 [] (int x) { return x; }, // key function
866 [] (const DynList<int> & g) { return sum(g); } // reducer (takes group)
867 );
868
869 // Result should be list of (key, reduced_value) pairs
870 EXPECT_EQ(result.size(), 3);
871
872 auto it = result.get_it();
873 // First group: key=1, sum=1+1=2
874 EXPECT_EQ(it.get_curr().first, 1);
875 EXPECT_EQ(it.get_curr().second, 2);
876 it.next();
877 // Second group: key=2, sum=2+2+2=6
878 EXPECT_EQ(it.get_curr().first, 2);
879 EXPECT_EQ(it.get_curr().second, 6);
880 it.next();
881 // Third group: key=3, sum=3
882 EXPECT_EQ(it.get_curr().first, 3);
883 EXPECT_EQ(it.get_curr().second, 3);
884}
885
886// --- maps and maps_if tests ---
887
889{
890 DynList<int> l = build_dynlist<int>(1, 2, 3, 4, 5);
891
892 auto result = maps<int>(l, [] (int x) { return x * x; });
893 EXPECT_EQ(result, build_dynlist<int>(1, 4, 9, 16, 25));
894}
895
897{
899
900 auto result = maps<string>(l, [] (int x) { return to_string(x); });
901 EXPECT_EQ(result, build_dynlist<string>("1", "2", "3"));
902}
903
905{
906 DynList<int> l = build_dynlist<int>(1, 2, 3, 4, 5, 6);
907
908 // Filter then map: square only even numbers
909 auto filtered = filter(l, [] (int x) { return x % 2 == 0; });
910 auto result = maps<int>(filtered, [] (int x) { return x * x; });
911
912 EXPECT_EQ(result, build_dynlist<int>(4, 16, 36));
913}
914
916{
917 DynList<int> l = build_dynlist<int>(1, 3, 5, 7);
918
919 auto filtered = filter(l, [] (int x) { return x % 2 == 0; });
920 auto result = maps<int>(filtered, [] (int x) { return x * 2; });
921
922 EXPECT_TRUE(result.is_empty());
923}
924
925// --- split tests using DynList split method ---
926
928{
929 DynList<int> l = build_dynlist<int>(1, 2, 3, 4, 5, 6);
930
931 // Use take and drop to simulate split at position 3
932 auto left = l.take(3);
933 auto right = l.drop(3);
934
935 EXPECT_EQ(left, build_dynlist<int>(1, 2, 3));
936 EXPECT_EQ(right, build_dynlist<int>(4, 5, 6));
937}
938
939// --- take and drop comprehensive tests ---
940
942{
943 DynList<int> l = build_dynlist<int>(1, 2, 3, 4, 5);
944
945 EXPECT_EQ(l.take(3), build_dynlist<int>(1, 2, 3));
947 EXPECT_EQ(l.take(10), l);
948}
949
951{
952 DynList<int> l = build_dynlist<int>(1, 2, 3, 4, 5);
953
954 EXPECT_EQ(l.drop(2), build_dynlist<int>(3, 4, 5));
955 EXPECT_EQ(l.drop(0), l);
957}
958
960{
961 DynList<int> l = build_dynlist<int>(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
962
963 // Take elements from position 3 to 7
964 auto result = l.take(3, 7);
965 EXPECT_EQ(result, build_dynlist<int>(3, 4, 5, 6, 7));
966}
967
968// --- to_dynlist tests ---
969
971{
972 DynSetTree<int> tree;
973 for (int i = 0; i < 5; ++i)
974 tree.insert(i);
975
976 auto list = to_dynlist(tree);
977 EXPECT_EQ(list.size(), 5);
978 EXPECT_EQ(list, build_dynlist<int>(0, 1, 2, 3, 4));
979}
980
982{
983 DynArray<int> arr;
984 for (int i = 0; i < 5; ++i)
985 arr.append(i * 2);
986
987 auto list = to_dynlist(arr);
988 EXPECT_EQ(list.size(), 5);
989 EXPECT_EQ(list, build_dynlist<int>(0, 2, 4, 6, 8));
990}
991
992// --- traverse with filter test ---
993
995{
996 DynList<int> l = build_dynlist<int>(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
997
998 size_t count = 0;
999 l.traverse([&count] (int x) {
1000 if (x % 2 == 0) ++count;
1001 return true;
1002 });
1003
1004 EXPECT_EQ(count, 5);
1005}
1006
1007// --- Edge cases and stress tests ---
1008
1010{
1011 constexpr size_t N = 10000;
1013
1014 // Test foldl on large container
1015 auto sum = foldl<size_t>(l, 0, [] (size_t a, size_t b) { return a + b; });
1016 EXPECT_EQ(sum, N * (N - 1) / 2);
1017
1018 // Test filter on large container
1019 auto evens = filter(l, [] (size_t x) { return x % 2 == 0; });
1020 EXPECT_EQ(evens.size(), N / 2);
1021
1022 // Test maps on large container
1023 auto doubled = maps<size_t>(l, [] (size_t x) { return x * 2; });
1024 EXPECT_EQ(doubled.size(), N);
1025 EXPECT_EQ(doubled.get_first(), 0);
1026 EXPECT_EQ(doubled.get_last(), (N - 1) * 2);
1027}
1028
1030{
1031 DynList<int> l = range(100);
1032
1033 // Chain: filter even -> map square -> take first 5 -> sum
1034 auto result = filter(l, [] (int x) { return x % 2 == 0; }); // 50 evens
1035 auto squared = maps<int>(result, [] (int x) { return x * x; });
1036 auto first5 = squared.take(5); // 0, 4, 16, 36, 64
1037 auto total = sum(first5);
1038
1039 EXPECT_EQ(total, 0 + 4 + 16 + 36 + 64);
1040}
1041
1043{
1044 DynList<int> empty;
1045
1046 // All these should handle empty containers gracefully
1047 EXPECT_TRUE(filter(empty, [] (int) { return true; }).is_empty());
1048 EXPECT_TRUE(maps<int>(empty, [] (int x) { return x; }).is_empty());
1049 EXPECT_EQ(foldl<int>(empty, 42, [] (int a, int b) { return a + b; }), 42);
1050 EXPECT_TRUE(all(empty, [] (int) { return false; })); // vacuously true
1051 EXPECT_FALSE(exists(empty, [] (int) { return true; }));
1052 EXPECT_TRUE(none(empty, [] (int) { return true; }));
1053 EXPECT_EQ(sum(empty), 0);
1054 EXPECT_EQ(product(empty), 1);
1055 EXPECT_TRUE(reverse(empty).is_empty());
1056}
1057
1059{
1061
1062 EXPECT_EQ(filter(single, [] (int x) { return x > 0; }).size(), 1);
1063 EXPECT_EQ(maps<int>(single, [] (int x) { return x * 2; }).get_first(), 84);
1064 EXPECT_EQ(sum(single), 42);
1065 EXPECT_EQ(product(single), 42);
1066 EXPECT_EQ(reverse(single).get_first(), 42);
1067 EXPECT_EQ(*min_ptr(single), 42);
1068 EXPECT_EQ(*max_ptr(single), 42);
1069}
1070
1071// --- Complex type tests ---
1072
1073struct Person
1074{
1075 string name;
1076 int age;
1077
1078 bool operator==(const Person & other) const
1079 {
1080 return name == other.name && age == other.age;
1081 }
1082};
1083
1085{
1087 people.append({"Alice", 30});
1088 people.append({"Bob", 25});
1089 people.append({"Charlie", 35});
1090 people.append({"Diana", 28});
1091
1092 // Filter by age
1093 auto over28 = filter(people, [] (const Person & p) { return p.age > 28; });
1094 EXPECT_EQ(over28.size(), 2);
1095
1096 // Map to names
1097 auto names = maps<string>(people, [] (const Person & p) { return p.name; });
1098 EXPECT_EQ(names, build_dynlist<string>("Alice", "Bob", "Charlie", "Diana"));
1099
1100 // Find oldest
1101 auto * oldest = max_ptr(people, [] (const Person & a, const Person & b) {
1102 return a.age < b.age;
1103 });
1104 ASSERT_NE(oldest, nullptr);
1105 EXPECT_EQ(oldest->name, "Charlie");
1106
1107 // Sum of ages
1108 auto total_age = foldl<int>(people, 0, [] (int acc, const Person & p) {
1109 return acc + p.age;
1110 });
1111 EXPECT_EQ(total_age, 30 + 25 + 35 + 28);
1112}
1113
1114// --- Lazy evaluation / composition tests ---
1115
1117{
1119
1120 // map twice
1121 auto result = maps<int>(maps<int>(l, [] (int x) { return x + 1; }),
1122 [] (int x) { return x * x; });
1123 EXPECT_EQ(result, build_dynlist<int>(4, 9, 16)); // (1+1)^2, (2+1)^2, (3+1)^2
1124}
1125
1127{
1128 DynList<int> l = range(10);
1129
1130 auto result = maps<string>(
1131 filter(l, [] (int x) { return x % 3 == 0; }),
1132 [] (int x) { return "val" + to_string(x); }
1133 );
1134
1135 EXPECT_EQ(result, build_dynlist<string>("val0", "val3", "val6", "val9"));
1136}
1137
1138// --- Quantifier tests ---
1139
1141{
1142 DynList<int> l = build_dynlist<int>(2, 4, 6, 8, 10);
1143
1144 EXPECT_TRUE(all(l, [] (int x) { return x % 2 == 0; })); // all even
1145 EXPECT_TRUE(all(l, [] (int x) { return x > 0; })); // all positive
1146 EXPECT_FALSE(all(l, [] (int x) { return x > 5; })); // not all > 5
1147
1148 // Empty container - vacuously true
1149 DynList<int> empty;
1150 EXPECT_TRUE(all(empty, [] (int) { return false; }));
1151}
1152
1154{
1155 DynList<int> l = build_dynlist<int>(1, 3, 5, 6, 7);
1156
1157 EXPECT_TRUE(exists(l, [] (int x) { return x % 2 == 0; })); // 6 is even
1158 EXPECT_TRUE(exists(l, [] (int x) { return x == 7; })); // 7 exists
1159 EXPECT_FALSE(exists(l, [] (int x) { return x > 100; })); // none > 100
1160
1161 // Empty container - false
1162 DynList<int> empty;
1163 EXPECT_FALSE(exists(empty, [] (int) { return true; }));
1164}
1165
1167{
1168 DynList<int> l = build_dynlist<int>(1, 3, 5, 7, 9);
1169
1170 EXPECT_TRUE(none(l, [] (int x) { return x % 2 == 0; })); // no even
1171 EXPECT_TRUE(none(l, [] (int x) { return x > 100; })); // none > 100
1172 EXPECT_FALSE(none(l, [] (int x) { return x == 5; })); // 5 exists
1173
1174 // Empty container - vacuously true
1175 DynList<int> empty;
1176 EXPECT_TRUE(none(empty, [] (int) { return true; }));
1177}
1178
1179// =============================================================================
1180// Additional comprehensive tests
1181// =============================================================================
1182
1183// --- scanl comprehensive tests ---
1184
1186{
1187 DynList<int> l = build_dynlist<int>(1, 2, 3, 4, 5);
1188
1189 // Basic scanl_sum starting from 0
1190 auto sums = scanl_sum(l, 0);
1191 EXPECT_EQ(sums, build_dynlist<int>(0, 1, 3, 6, 10, 15));
1192
1193 // scanl_sum with non-zero init
1194 auto sums2 = scanl_sum(l, 100);
1195 EXPECT_EQ(sums2, build_dynlist<int>(100, 101, 103, 106, 110, 115));
1196
1197 // Empty container
1198 DynList<int> empty;
1199 auto empty_scan = scanl_sum(empty, 42);
1200 EXPECT_EQ(empty_scan.size(), 1);
1201 EXPECT_EQ(empty_scan.get_first(), 42);
1202}
1203
1205{
1207
1208 // Product scan
1209 auto products = scanl<int>(l, 1, [] (int acc, int x) { return acc * x; });
1210 EXPECT_EQ(products, build_dynlist<int>(1, 2, 6, 24));
1211
1212 // Max scan
1213 auto maxes = scanl<int>(l, 0, [] (int acc, int x) { return std::max(acc, x); });
1214 EXPECT_EQ(maxes, build_dynlist<int>(0, 2, 3, 4));
1215}
1216
1217// --- flat_map comprehensive tests ---
1218
1220{
1222
1223 // Expand each number to a range
1224 auto result = flat_map(l, [] (int x) {
1225 return range(x); // 0..x-1
1226 });
1227 // 1 -> {0}, 2 -> {0,1}, 3 -> {0,1,2}
1228 EXPECT_EQ(result, build_dynlist<int>(0, 0, 1, 0, 1, 2));
1229}
1230
1232{
1234
1235 // Replicate each element by its value
1236 auto result = flat_map(l, [] (int x) -> DynList<int> {
1238 for (int i = 0; i < x; ++i)
1239 res.append(x);
1240 return res;
1241 });
1242 EXPECT_EQ(result, build_dynlist<int>(1, 2, 2, 3, 3, 3));
1243}
1244
1246{
1248
1249 // Some inner results are empty
1250 auto result = flat_map(l, [] (int x) {
1251 if (x % 2 == 0)
1252 return DynList<int>();
1253 return build_dynlist<int>(x);
1254 });
1255 EXPECT_EQ(result, build_dynlist<int>(1, 3));
1256}
1257
1258// --- concat comprehensive tests ---
1259
1261{
1263 DynList<int> b = build_dynlist<int>(3, 4, 5);
1264 DynList<int> empty;
1265
1266 EXPECT_EQ(concat(a, b), build_dynlist<int>(1, 2, 3, 4, 5));
1267 EXPECT_EQ(concat(empty, b), build_dynlist<int>(3, 4, 5));
1268 EXPECT_EQ(concat(a, empty), build_dynlist<int>(1, 2));
1269 EXPECT_EQ(concat(empty, empty), DynList<int>());
1270}
1271
1272// --- take_while / drop_while comprehensive tests ---
1273
1275{
1276 DynList<int> l = build_dynlist<int>(2, 4, 6, 7, 8, 10);
1277
1278 // Take while even
1279 auto evens = take_while(l, [] (int x) { return x % 2 == 0; });
1281
1282 // Take while < 5
1283 auto small = take_while(l, [] (int x) { return x < 5; });
1285
1286 // Take nothing (first element fails)
1287 auto none_taken = take_while(l, [] (int x) { return x > 100; });
1288 EXPECT_TRUE(none_taken.is_empty());
1289
1290 // Take all
1291 auto all_taken = take_while(l, [] (int) { return true; });
1292 EXPECT_EQ(all_taken.size(), l.size());
1293}
1294
1296{
1297 DynList<int> l = build_dynlist<int>(2, 4, 6, 7, 8, 10);
1298
1299 // Drop while even
1300 auto after_evens = drop_while(l, [] (int x) { return x % 2 == 0; });
1302
1303 // Drop while < 5
1304 auto after_small = drop_while(l, [] (int x) { return x < 5; });
1306
1307 // Drop nothing (first element fails)
1308 auto none_dropped = drop_while(l, [] (int x) { return x > 100; });
1309 EXPECT_EQ(none_dropped.size(), l.size());
1310
1311 // Drop all
1312 auto all_dropped = drop_while(l, [] (int) { return true; });
1313 EXPECT_TRUE(all_dropped.is_empty());
1314}
1315
1316// --- reverse comprehensive tests ---
1317
1319{
1323
1324 DynList<int> empty;
1325 EXPECT_TRUE(reverse(empty).is_empty());
1326
1327 // Reverse twice = original
1328 DynList<int> l = range(10);
1330}
1331
1332// --- min/max pointer comprehensive tests ---
1333
1335{
1337 names.append("Bob");
1338 names.append("Alice");
1339 names.append("Charlie");
1340
1341 // By length
1342 auto * shortest = min_ptr(names, [] (const string & a, const string & b) {
1343 return a.length() < b.length();
1344 });
1345 ASSERT_NE(shortest, nullptr);
1346 EXPECT_EQ(*shortest, "Bob");
1347
1348 auto * longest = max_ptr(names, [] (const string & a, const string & b) {
1349 return a.length() < b.length();
1350 });
1351 ASSERT_NE(longest, nullptr);
1352 EXPECT_EQ(*longest, "Charlie");
1353}
1354
1356{
1357 DynList<int> l = build_dynlist<int>(3, 1, 4, 1, 5, 9, 2, 6);
1358
1359 auto [min_p, max_p] = minmax_ptr(l);
1360 ASSERT_NE(min_p, nullptr);
1361 ASSERT_NE(max_p, nullptr);
1362 EXPECT_EQ(*min_p, 1);
1363 EXPECT_EQ(*max_p, 9);
1364}
1365
1366// --- foldl/foldr comprehensive tests ---
1367
1369{
1370 DynList<string> words;
1371 words.append("a");
1372 words.append("b");
1373 words.append("c");
1374
1375 // foldl is left-associative: ((init op a) op b) op c
1376 auto result = foldl<string>(words, "START", [] (const string & acc, const string & x) {
1377 return "(" + acc + "+" + x + ")";
1378 });
1379 EXPECT_EQ(result, "(((START+a)+b)+c)");
1380}
1381
1383{
1384 DynList<string> words;
1385 words.append("a");
1386 words.append("b");
1387 words.append("c");
1388
1389 // foldr is right-associative: a op (b op (c op init))
1390 auto result = foldr<string>(words, "END", [] (const string & x, const string & acc) {
1391 return "(" + x + "+" + acc + ")";
1392 });
1393 EXPECT_EQ(result, "(a+(b+(c+END)))");
1394}
1395
1396// --- zip comprehensive tests ---
1397
1399{
1400 DynList<int> a = build_dynlist<int>(1, 2, 3, 4, 5);
1401 DynList<char> b;
1402 b.append('a');
1403 b.append('b');
1404
1405 // Regular zip stops at shorter
1406 auto zipped = zip(a, b);
1407 EXPECT_EQ(zipped.size(), 2);
1408}
1409
1411{
1412 DynList<int> a = build_dynlist<int>(1, 2, 3);
1413 DynList<int> b = build_dynlist<int>(2, 4, 6);
1414
1415 // Check if b[i] == 2*a[i] for all i
1416 bool all_double = zip_all([] (auto t) { return get<1>(t) == 2 * get<0>(t); }, a, b);
1418
1419 DynList<int> c = build_dynlist<int>(2, 4, 5); // 5 != 2*3
1420 bool not_all = zip_all([] (auto t) { return get<1>(t) == 2 * get<0>(t); }, a, c);
1422}
1423
1424// --- group_by comprehensive tests ---
1425
1427{
1428 DynList<int> l = build_dynlist<int>(1, 3, 5, 2, 4, 6, 7, 9);
1429
1430 // Group by parity (odd=1, even=0)
1431 auto groups = group_by(l, [] (int x) { return x % 2; });
1432
1433 EXPECT_EQ(groups.size(), 3); // odd, even, odd groups
1434
1435 auto it = groups.get_it();
1436 EXPECT_EQ(it.get_curr().first, 1); // odd
1437 EXPECT_EQ(it.get_curr().second.size(), 3); // 1, 3, 5
1438 it.next();
1439 EXPECT_EQ(it.get_curr().first, 0); // even
1440 EXPECT_EQ(it.get_curr().second.size(), 3); // 2, 4, 6
1441 it.next();
1442 EXPECT_EQ(it.get_curr().first, 1); // odd
1443 EXPECT_EQ(it.get_curr().second.size(), 2); // 7, 9
1444}
1445
1446// --- Performance / stress tests ---
1447
1449{
1450 constexpr size_t N = 10000;
1451 auto large = range<int>(0, static_cast<int>(N) - 1);
1452
1453 // Chain: filter -> map -> sum (first 100 evens)
1454 auto evens = filter(large, [] (int x) { return x % 2 == 0; });
1455 auto squared = maps<int>(evens, [] (int x) { return x * x; });
1456
1457 // Take first 100 elements manually
1459 size_t count = 0;
1460 for (auto it = squared.get_it(); it.has_curr() && count < 100; it.next_ne(), ++count)
1461 first100.append(it.get_curr());
1462
1463 // Sum of squares of first 100 even numbers: 0^2 + 2^2 + 4^2 + ... + 198^2
1464 long long expected = 0;
1465 for (int i = 0; i < 100; ++i)
1466 expected += (2LL * i) * (2LL * i);
1467
1468 auto total = foldl<long long>(first100, 0LL, [] (long long acc, int x) {
1469 return acc + x;
1470 });
1472}
1473
1475{
1476 // Deeply nested maps
1477 auto l = range(5);
1478 auto result = maps<int>(
1479 maps<int>(
1480 maps<int>(l, [] (int x) { return x + 1; }),
1481 [] (int x) { return x * 2; }),
1482 [] (int x) { return x - 1; });
1483
1484 // ((x + 1) * 2) - 1 for x in 0..4
1485 EXPECT_EQ(result, build_dynlist<int>(1, 3, 5, 7, 9));
1486}
1487
1488// Custom equality predicates for testing all_unique overloads
1501 bool operator()(const string& a, const string& b) const {
1502 if (a.size() != b.size()) return false;
1503 for (size_t i = 0; i < a.size(); ++i)
1504 {
1505 const auto ca = static_cast<unsigned char>(a[i]);
1506 const auto cb = static_cast<unsigned char>(b[i]);
1507 if (std::tolower(ca) != std::tolower(cb)) return false;
1508 }
1509 return true;
1510 }
1511};
1512
1523 size_t operator()(const string& s) const {
1524 string lower;
1525 lower.reserve(s.size());
1526 for (char c : s)
1527 lower.push_back(static_cast<char>(std::tolower(static_cast<unsigned char>(c))));
1528 return std::hash<string>()(lower);
1529 }
1530};
1531
1545 FloatToleranceEqual(float tol = 0.001f) : tolerance(tol) {}
1553 bool operator()(float a, float b) const {
1554 return std::abs(a - b) <= tolerance;
1555 }
1556};
1557
1559{
1560 // All strings unique when case-insensitive comparison is used
1561 auto strings = build_dynlist<string>("Hello", "World", "Test", "Aleph");
1563}
1564
1566{
1567 // "hello" and "HELLO" should be considered equal with case-insensitive comparison
1568 auto strings = build_dynlist<string>("hello", "World", "HELLO", "Test");
1570}
1571
1573{
1574 // All floats unique within tolerance
1575 auto floats = build_dynlist<float>(1.0f, 1.1f, 1.2f, 1.3f);
1577}
1578
1580{
1581 // 1.0 and 1.01 should be considered equal with tolerance 0.05
1582 auto floats = build_dynlist<float>(1.0f, 1.01f, 1.5f, 2.0f);
1584}
1585
1587{
1588 // Test with default std::equal_to - all unique
1589 auto ints = build_dynlist<int>(1, 2, 3, 4, 5);
1591}
1592
1594{
1595 // Test with default std::equal_to - duplicates present
1596 auto ints = build_dynlist<int>(1, 2, 3, 2, 5);
1598}
1599
1601{
1602 // Exercise overload with temporary container + temporary comparator (false case)
1603 EXPECT_FALSE(all_unique(build_dynlist<string>("Apple", "apple", "Banana"),
1605}
1606
1608{
1609 // Exercise overload with temporary container + temporary comparator (true case)
1610 EXPECT_TRUE(all_unique(build_dynlist<string>("Apple", "Banana", "Cherry"),
1612}
1613
1621
1629
1637
1639{
1640 auto strings = build_dynlist<string>("Alpha", "Bravo", "ALPHA");
1641 size_t hash_calls = 0;
1642
1643 auto hash = [&hash_calls] (const string & s) -> size_t
1644 {
1645 ++hash_calls;
1646 return CaseInsensitiveStringHash()(s);
1647 };
1649
1651 EXPECT_GT(hash_calls, 0u);
1652}
1653
1655{
1656 // Empty container should always return true
1657 DynList<int> empty;
1658 EXPECT_TRUE(all_unique(empty, std::hash<int>(), std::equal_to<int>()));
1659 EXPECT_TRUE(all_unique(empty, std::equal_to<int>()));
1660 EXPECT_TRUE(all_unique(empty));
1661}
1662
1664{
1665 // Single element container should always return true
1666 auto single = build_dynlist<int>(42);
1667 EXPECT_TRUE(all_unique(single, std::hash<int>(), std::equal_to<int>()));
1668 EXPECT_TRUE(all_unique(single, std::equal_to<int>()));
1670}
TEST_F(TreeContainer, pointers)
String manipulation utilities.
Zip iterators and functional operations for multiple containers.
Functional programming utilities for Aleph-w containers.
T & append()
Allocate a new entry to the end of array.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
T & get_last() const
Return the last item of the list.
Definition htlist.H:1363
Dynamic set backed by balanced binary search trees with automatic memory management.
const size_t & size() const
Returns the cardinality of the set.
Key * insert(const Key &key)
Inserts a key into the dynamic set.
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1065
Aleph::DynList< T > take(const size_t n) const
Return a list with the first n elements seen in the container during its traversal.
Definition ah-dry.H:1631
bool all(Operation &operation) const
Check if all the elements of the container satisfy a condition.
Definition ah-dry.H:957
Aleph::DynList< T > drop(const size_t n) const
Drop the first n elements seen in the container during its traversal.
Definition ah-dry.H:1680
Type & nth(const size_t n)
Return the n-th item of the container.
Definition ah-dry.H:299
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:222
#define TEST(name)
#define N
Definition fib.C:294
MapOLhash< int, Foo > tbl
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
std::pair< DynList< T >, size_t > unique_sequential(const Container< T > &c, Equal &eq)
Extract unique consecutive items.
std::tuple< bool, size_t, typename C1::Item_Type, typename C2::Item_Type > are_eq(const C1 &c1, const C2 &c2, Eq e=Eq())
Detailed equality check returning mismatch position and values.
DynList< T > flatten(const C2< C1< T > > &c)
Flatten a nested container of one level.
DynList< typename Container::Item_Type > to_dynlist(const Container &c)
Definition htlist.H:1694
Container< T > nrange(const T start, const T end, const size_t n)
Generate exactly n values evenly spaced between [start, end].
auto group_by_reduce(const Container< T > &c, KeyFunc key_func, Reducer reducer) -> DynList< std::pair< std::invoke_result_t< KeyFunc, const T & >, std::invoke_result_t< Reducer, const DynList< T > & > > >
Group consecutive elements and apply a reducer to each group.
std::pair< const typename Container::Item_Type *, const typename Container::Item_Type * > minmax_ptr(const Container &container, Cmp cmp=Cmp())
Find both min and max elements in a single pass.
const Container::Item_Type * min_ptr(const Container &container, Cmp cmp=Cmp())
Find the minimum element in a container.
DynList< std::pair< std::optional< typename Container1::Item_Type >, std::optional< typename Container2::Item_Type > > > zip_longest_opt(const Container1 &a, const Container2 &b)
Zip two containers using optionals for missing values.
auto unzip(const Container &l)
Separate a list of pairs into two lists.
bool all(Container &container, Operation &operation)
Return true if all elements satisfy a predicate.
void reverse(Itor beg, Itor end)
Reverse elements in a range.
Definition ahAlgo.H:1094
bool eq(const C1 &c1, const C2 &c2, Eq e=Eq())
Check equality of two containers using a predicate.
DynList< typename Container::Item_Type > drop_while(const Container &c, Pred pred)
Skip elements while predicate is true (drop_while).
auto set_range(const T start, const T end, const T step, Op &op) -> Container< std::decay_t< decltype(op(start))> >
Generate a range [start, end] and apply an operation to each value.
DynList< std::pair< typename Container1::Item_Type, typename Container2::Item_Type > > zipEq(const Container1 &a, const Container2 &b)
Zip two containers; throw if lengths differ.
size_t size(Node *root) noexcept
std::pair< TgtContainer< typename SrcContainer::Item_Type >, TgtContainer< typename SrcContainer::Item_Type > > partition(const SrcContainer &c, std::function< bool(const typename SrcContainer::Item_Type &)> operation)
Partition a container into two based on a predicate.
bool containers_eq(const C1 &c1, const C2 &c2, Eq e)
bool all_unique(const Container &container, Equal &eq)
Check if all elements in a container are unique using a comparator.
Container2< typename Container1::Item_Type > filter(Container1 &container, Operation &operation)
Filter elements that satisfy operation.
bool is_inside(const T &val, const DynList< T > &values)
Check if a value is present in a list.
DynList< typename Container::Item_Type > take_while(const Container &c, Pred pred)
Return elements while predicate is true (take_while).
DynList< std::pair< typename Container1::Item_Type, typename Container2::Item_Type > > zip(const Container1 &a, const Container2 &b)
Zip two containers into a list of pairs.
Pair_Iterator< typename C1::Iterator, typename C2::Iterator > get_pair_it(const C1 &c1, const C2 &c2)
Create a Pair_Iterator for two containers.
auto enumerate(const Container &c)
Return pairs of (element, index).
size_t append_in_container(C &c, Args ... args)
Append multiple items into a container.
bool is_equal(const T &val)
Variadic check for equality against multiple values.
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
bool exists(Container &container, Operation &operation)
Return true if at least one element satisfies a predicate.
auto gen_seq_list_tuples(const Container &c, size_t n)
Generate all sequential tuples (sliding windows) of size n.
bool contains(const std::string_view &str, const std::string_view &substr)
Check if substr appears inside str.
DynList< T > build_dynlist(Args ... args)
Build a DynList with the given items.
void each(const size_t start, const size_t end, Op &op)
Execute an operation repeatedly over a range of indices.
DynList< T > rep(const size_t n, const T &item)
Create a sequence of repeated items.
auto flat_map(const Container &container, Op op) -> DynList< typename std::decay_t< decltype(op(std::declval< typename Container::Item_Type >()))>::Item_Type >
Apply operation and flatten results (flatMap/concatMap).
DynList< std::tuple< typename Container1::Item_Type, typename Container2::Item_Type > > tzip(const Container1 &a, const Container2 &b)
Zip two containers into a list of tuples.
bool zip_all(Op &&op, const Cs &...cs)
Return true if op returns true for all tuples and containers have equal length.
Definition ah-zip.H:416
T product(const Container &container, const T &init=T{1})
Compute product of all elements.
bool diff(const C1 &c1, const C2 &c2, Eq e=Eq())
Check if two containers differ.
DynList< typename Container::Item_Type * > pointers_list(Container &c)
Create a list of pointers to items in a container.
DynList< std::pair< size_t, typename Container::Key_Type > > indexes(const Container &c)
Return pairs of (index, key).
bool lesser(const C1 &c1, const C2 &c2, Cmp cmp=Cmp())
Lexicographical comparison between two containers.
TgtC assign_container(const SrcC &srcc)
Convert one container type to another.
DynList< std::tuple< size_t, typename Container::Item_Type > > enumerate_tuple(const Container &container)
Zip containers with an index (enumerate with zip).
const Container::Item_Type * max_ptr(const Container &container, Cmp cmp=Cmp())
Find the maximum element in a container.
DynList< std::tuple< typename Container1::Item_Type, typename Container2::Item_Type > > tzipEq(const Container1 &a, const Container2 &b)
Zip two containers into tuples; throw if lengths differ.
Operation for_each(Itor beg, const Itor &end, Operation op)
Apply an operation to each element in a range.
Definition ahAlgo.H:76
std::pair< DynList< DynList< T > >, size_t > sequential_groups(const Container< T > &c, Equal &eq)
Group consecutive equal elements together.
std::string to_string(const time_t t, const std::string &format)
Format a time_t value into a string using format.
Definition ah-date.H:140
size_t insert_in_container(C &c, Args ... args)
Insert multiple items into a container.
DynList< std::tuple< size_t, typename Container::Key_Type > > tindexes(const Container &c)
Return tuples of (index, key).
Itor::difference_type count_if(Itor beg, const Itor &end, Operation op)
Count elements satisfying a predicate.
Definition ahAlgo.H:100
DynList< T > scanl_sum(const Container &container, const T &init)
Compute running sums (scanl with addition).
DynList< std::tuple< typename Container1::Item_Type, typename Container2::Item_Type > > tzip_longest(const Container1 &a, const Container2 &b, const typename Container1::Item_Type &fill_a=typename Container1::Item_Type(), const typename Container2::Item_Type &fill_b=typename Container2::Item_Type())
Zip two containers into tuples, padding the shorter one.
std::string concat(const Args &... args)
Concatenate multiple arguments into a single std::string.
DynList< std::pair< typename Container1::Item_Type, typename Container2::Item_Type > > zip_longest(const Container1 &a, const Container2 &b, const typename Container1::Item_Type &fill_a=typename Container1::Item_Type(), const typename Container2::Item_Type &fill_b=typename Container2::Item_Type())
Zip two containers, padding the shorter one with a fill value.
DynList< typename Container::Item_Type > sublist(const Container &c, size_t pos, const size_t stride)
Extract a sublist using a stride.
Container::Item_Type * find_ptr(Container &container, Pred &pred)
Find the first element satisfying pred.
Container< T > range(const T start, const T end, const T step=1)
Generate a range of values [start, end] with a given step.
void enum_for_each(const Container &container, Operation &operation)
Apply an operation to each element and its index.
DynList< std::pair< std::invoke_result_t< KeyFunc, const T & >, DynList< T > > > group_by(const Container< T > &c, KeyFunc key_func)
Group consecutive elements by a key function.
Container< T > contiguous_range(T start, const size_t n)
Generate n contiguous values starting from start.
bool none(const Container &container, Operation &operation)
Return true if no element satisfies operation.
size_t remove_from_container(C &c, Args ... args)
Remove multiple items from a container.
std::tuple< Container< T1 >, Container< T2 > > tunzip(const Container< std::tuple< T1, T2 > > &l)
Separate a list of tuples into two containers.
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.
STL namespace.
#define LL
Definition ran_array.c:24
Represents a missing value.
T & get_item() override
bool is_found() const noexcept override
Represents a found value (stored by reference).
bool is_found() const noexcept override
T & get_item() override
bool operator()(const string &a, const string &b) const
Performs a case-insensitive comparison of two strings.
size_t operator()(const string &s) const
Produces a case-insensitive hash for a string by hashing its lowercase form.
Helper for float comparison with tolerance.
bool operator()(float a, float b) const
Compares two floating-point values for equality within the configured tolerance.
FloatToleranceEqual(float tol=0.001f)
Constructs a FloatToleranceEqual comparator with a specified tolerance.
bool traverse(Operation &operation) noexcept(traverse_is_noexcept< Operation >())
Traverse the container via its iterator and performs a conditioned operation on each item.
Definition ah-dry.H:97
bool operator==(const Person &other) const
static constexpr size_t N
DynSetTree< size_t > tbl
DynList< int > l1
DynList< int > l2
static int * k
gsl_rng * r
Lazy and scalable dynamic array implementation.
Dynamic set implementations based on hash tables.
Dynamic set implementations based on balanced binary search trees.
Open addressing hash table with double hashing.
DynList< int > l