Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-zip-utils_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
47#include <gtest/gtest.h>
48#include <ah-zip-utils.H>
49
50// Aleph containers
51#include <htlist.H>
52#include <tpl_dynArray.H>
53#include <tpl_dynDlist.H>
54#include <tpl_dynSetTree.H>
55#include <tpl_dynSetHash.H>
56#include <tpl_arrayStack.H>
57#include <tpl_dynListStack.H>
58#include <tpl_arrayQueue.H>
59#include <tpl_dynListQueue.H>
60
61// STL containers
62#include <vector>
63#include <list>
64#include <deque>
65#include <set>
66#include <unordered_set>
67#include <array>
68#include <string>
69#include <forward_list>
70
71using namespace Aleph;
72
73//==============================================================================
74// STL-only Tests
75//==============================================================================
76
78{
79 std::vector<int> v1 = {1, 2, 3};
80 std::vector<std::string> v2 = {"a", "b", "c"};
81
82 int count = 0;
83 for (auto [num, str] : uni_zip(v1, v2))
84 {
85 EXPECT_EQ(num, v1[count]);
86 EXPECT_EQ(str, v2[count]);
87 ++count;
88 }
89 EXPECT_EQ(count, 3);
90}
91
93{
94 std::vector<int> v = {1, 2, 3};
95 std::list<double> l = {1.1, 2.2, 3.3};
96
97 auto sums = uni_zip_map([](auto t) {
98 return std::get<0>(t) + std::get<1>(t);
99 }, v, l);
100
101 EXPECT_EQ(sums.size(), 3);
102 EXPECT_DOUBLE_EQ(sums[0], 2.1);
103}
104
106{
107 std::vector<int> v1 = {1, 2};
108 std::vector<int> v2 = {10, 20};
109 std::vector<int> v3 = {100, 200};
110
111 int count = 0;
112 for (auto [a, b, c] : uni_zip(v1, v2, v3))
113 {
114 if (count == 0)
115 {
116 EXPECT_EQ(a, 1);
117 EXPECT_EQ(b, 10);
118 EXPECT_EQ(c, 100);
119 }
120 ++count;
121 }
122 EXPECT_EQ(count, 2);
123}
124
125//==============================================================================
126// Aleph-only Tests
127//==============================================================================
128
130{
131 DynList<int> l1 = {1, 2, 3};
132 DynList<std::string> l2 = {"a", "b", "c"};
133
134 std::vector<int> nums;
135 std::vector<std::string> strs;
136
137 for (auto [num, str] : uni_zip(l1, l2))
138 {
139 nums.push_back(num);
140 strs.push_back(str);
141 }
142
143 EXPECT_EQ(nums.size(), 3);
144 EXPECT_EQ(nums[0], 1);
145 EXPECT_EQ(strs[2], "c");
146}
147
149{
150 DynList<int> list = {10, 20, 30};
152 arr.append("x");
153 arr.append("y");
154 arr.append("z");
155
156 int count = 0;
157 for (auto [num, str] : uni_zip(list, arr))
158 ++count;
159
160 EXPECT_EQ(count, 3);
161}
162
163//==============================================================================
164// Mixed STL + Aleph Tests
165//==============================================================================
166
168{
169 std::vector<int> stl_vec = {1, 2, 3, 4, 5};
170 DynList<std::string> aleph_list = {"a", "b", "c", "d", "e"};
171
172 std::vector<std::string> results;
173 for (auto [num, str] : uni_zip(stl_vec, aleph_list))
174 results.push_back(std::to_string(num) + str);
175
176 EXPECT_EQ(results.size(), 5);
177 EXPECT_EQ(results[0], "1a");
178 EXPECT_EQ(results[4], "5e");
179}
180
182{
183 DynList<int> aleph_list = {100, 200, 300};
184 std::vector<double> stl_vec = {1.5, 2.5, 3.5};
185
186 auto products = uni_zip_map([](auto t) {
187 return std::get<0>(t) * std::get<1>(t);
188 }, aleph_list, stl_vec);
189
190 EXPECT_EQ(products.size(), 3);
191 EXPECT_DOUBLE_EQ(products[0], 150.0);
192 EXPECT_DOUBLE_EQ(products[1], 500.0);
193}
194
196{
197 std::vector<int> stl_vec = {1, 2, 3};
198 DynList<double> aleph_list = {1.1, 2.2, 3.3};
199 std::list<std::string> stl_list = {"a", "b", "c"};
200
201 int count = 0;
202 for (auto [i, d, s] : uni_zip(stl_vec, aleph_list, stl_list))
203 {
204 EXPECT_EQ(i, count + 1);
205 ++count;
206 }
207 EXPECT_EQ(count, 3);
208}
209
211{
212 std::vector<int> short_vec = {1, 2};
213 DynList<std::string> long_list = {"a", "b", "c", "d", "e"};
214
216}
217
218//==============================================================================
219// Functional Operations - Mixed
220//==============================================================================
221
223{
224 std::vector<int> stl_vec = {1, 2, 3};
225 DynList<int> aleph_list = {10, 20, 30};
226
227 bool result = uni_zip_all([](auto t) {
228 return std::get<0>(t) < std::get<1>(t);
229 }, stl_vec, aleph_list);
230
231 EXPECT_TRUE(result);
232}
233
235{
236 std::vector<int> stl_vec = {1, 2, 3};
237 DynList<std::string> aleph_list = {"short", "medium", "verylongstring"};
238
239 bool result = uni_zip_exists([](auto t) {
240 return std::get<1>(t).length() > 10;
241 }, stl_vec, aleph_list);
242
243 EXPECT_TRUE(result);
244}
245
247{
248 std::vector<int> stl_vec = {1, 2, 3};
249 DynList<int> aleph_list = {10, 20, 30};
250
251 std::vector<int> sums;
252 uni_zip_for_each([&sums](auto t) {
253 sums.push_back(std::get<0>(t) + std::get<1>(t));
254 }, stl_vec, aleph_list);
255
256 EXPECT_EQ(sums.size(), 3);
257 EXPECT_EQ(sums[0], 11);
258 EXPECT_EQ(sums[2], 33);
259}
260
262{
263 std::vector<int> prices = {10, 20, 30};
264 DynList<int> quantities = {2, 3, 1};
265
266 int total = uni_zip_foldl(0, [](int acc, auto t) {
267 return acc + std::get<0>(t) * std::get<1>(t);
268 }, prices, quantities);
269
270 EXPECT_EQ(total, 110); // 10*2 + 20*3 + 30*1
271}
272
274{
275 std::vector<int> xs = {1, 2, 3};
276 DynList<int> ys = {10, 20, 30};
277
278 auto sums = uni_zip_map([](auto t) {
279 return std::get<0>(t) + std::get<1>(t);
280 }, xs, ys);
281
282 EXPECT_EQ(sums.size(), 3);
283 EXPECT_EQ(sums[0], 11);
284}
285
287{
288 std::vector<int> xs = {1, 2, 3, 4, 5};
289 DynList<int> ys = {10, 20, 30, 40, 50};
290
291 auto evens = uni_zip_filter([](auto t) {
292 return std::get<0>(t) % 2 == 0;
293 }, xs, ys);
294
295 EXPECT_EQ(evens.size(), 2);
296}
297
299{
300 std::vector<int> xs = {1, 2, 3, 4, 5};
301 DynList<std::string> ys = {"a", "b", "c", "d", "e"};
302
303 auto result = uni_zip_find_first([](auto t) {
304 return std::get<0>(t) == 3;
305 }, xs, ys);
306
307 ASSERT_TRUE(result.has_value());
308 EXPECT_EQ(std::get<0>(*result), 3);
309 EXPECT_EQ(std::get<1>(*result), "c");
310}
311
313{
314 std::vector<int> xs = {1, 2, 3, 4, 5};
315 DynList<int> ys = {10, 20, 30, 40, 50};
316
317 size_t count = uni_zip_count([](auto t) {
318 return std::get<0>(t) % 2 == 0;
319 }, xs, ys);
320
321 EXPECT_EQ(count, 2);
322}
323
325{
326 std::vector<int> xs = {1, 2, 3, 4, 5};
327 DynList<std::string> ys = {"a", "b", "c", "d", "e"};
328
329 auto result = uni_zip_nth(2, xs, ys);
330
331 ASSERT_TRUE(result.has_value());
332 EXPECT_EQ(std::get<0>(*result), 3);
333 EXPECT_EQ(std::get<1>(*result), "c");
334}
335
337{
338 std::vector<int> xs = {1, 2, 3, 4, 5};
339 DynList<int> ys = {10, 20, 30, 40, 50};
340
341 auto result = uni_zip_take(3, xs, ys);
342
343 EXPECT_EQ(result.size(), 3);
344 EXPECT_EQ(std::get<0>(result[2]), 3);
345}
346
348{
349 std::vector<int> xs = {1, 2, 3, 4, 5};
350 DynList<int> ys = {10, 20, 30, 40, 50};
351
352 auto result = uni_zip_drop(2, xs, ys);
353
354 EXPECT_EQ(result.size(), 3);
355 EXPECT_EQ(std::get<0>(result[0]), 3);
356}
357
359{
360 std::vector<int> xs = {1, 2, 3, 10, 4, 5};
361 DynList<int> ys = {10, 20, 30, 100, 40, 50};
362
363 auto result = uni_zip_take_while([](auto t) {
364 return std::get<0>(t) < 10;
365 }, xs, ys);
366
367 EXPECT_EQ(result.size(), 3);
368}
369
371{
372 std::vector<int> xs = {1, 2, 3, 10, 4, 5};
373 DynList<int> ys = {10, 20, 30, 100, 40, 50};
374
375 auto result = uni_zip_drop_while([](auto t) {
376 return std::get<0>(t) < 10;
377 }, xs, ys);
378
379 EXPECT_EQ(result.size(), 3);
380 EXPECT_EQ(std::get<0>(result[0]), 10);
381}
382
384{
385 std::vector<int> xs = {1, 2, 3};
386 DynList<std::string> ys = {"a", "b", "c"};
387
388 auto first = uni_zip_first(xs, ys);
389 auto last = uni_zip_last(xs, ys);
390
391 ASSERT_TRUE(first.has_value());
392 ASSERT_TRUE(last.has_value());
393
394 EXPECT_EQ(std::get<0>(*first), 1);
395 EXPECT_EQ(std::get<0>(*last), 3);
396 EXPECT_EQ(std::get<1>(*last), "c");
397}
398
400{
401 std::vector<int> xs = {1, 2, 3, 4, 5};
402 DynList<std::string> ys = {"a", "b", "c", "d", "e"};
403
404 auto [evens, odds] = uni_zip_partition([](auto t) {
405 return std::get<0>(t) % 2 == 0;
406 }, xs, ys);
407
408 EXPECT_EQ(evens.size(), 2);
409 EXPECT_EQ(odds.size(), 3);
410}
411
413{
414 std::vector<int> xs = {1, 2, 3};
415 DynList<std::string> ys = {"a", "b", "c"};
416
417 auto result = uni_zip_to_vector(xs, ys);
418
419 EXPECT_EQ(result.size(), 3);
420}
421
423{
424 std::vector<int> xs = {1, 2, 3};
425 DynList<int> ys_same = {10, 20, 30};
426 DynList<int> ys_diff = {10, 20};
427
430}
431
432//==============================================================================
433// Edge Cases
434//==============================================================================
435
437{
438 std::vector<int> empty_stl;
440
443 EXPECT_EQ(view.size(), 0);
444}
445
453
455{
456 std::vector<int> single_stl = {42};
458
459 auto result = uni_zip_first(single_stl, single_aleph);
460
461 ASSERT_TRUE(result.has_value());
462 EXPECT_EQ(std::get<0>(*result), 42);
463 EXPECT_EQ(std::get<1>(*result), "answer");
464}
465
466//==============================================================================
467// EXHAUSTIVE TESTS - All Container Combinations
468//==============================================================================
469
470// Helper to populate Aleph containers
471template <typename T>
472void populate_dynlist(DynList<T>& l, std::initializer_list<T> values)
473{
474 for (const auto& v : values)
475 l.append(v);
476}
477
478template <typename T>
479void populate_dyndlist(DynDlist<T>& l, std::initializer_list<T> values)
480{
481 for (const auto& v : values)
482 l.append(v);
483}
484
485template <typename T>
486void populate_dynarray(DynArray<T>& arr, std::initializer_list<T> values)
487{
488 for (const auto& v : values)
489 arr.append(v);
490}
491
492//------------------------------------------------------------------------------
493// Test: STL vector + All Aleph containers
494//------------------------------------------------------------------------------
495
497{
498 std::vector<int> stl = {1, 2, 3, 4, 5};
499 DynList<int> aleph = {10, 20, 30, 40, 50};
500
501 auto sums = uni_zip_map([](auto t) {
502 return std::get<0>(t) + std::get<1>(t);
503 }, stl, aleph);
504
505 EXPECT_EQ(sums.size(), 5);
506 EXPECT_EQ(sums[0], 11);
507 EXPECT_EQ(sums[4], 55);
508}
509
511{
512 std::vector<int> stl = {1, 2, 3, 4, 5};
514 populate_dyndlist(aleph, {10, 20, 30, 40, 50});
515
516 int sum = uni_zip_foldl(0, [](int acc, auto t) {
517 return acc + std::get<0>(t) * std::get<1>(t);
518 }, stl, aleph);
519
520 // 1*10 + 2*20 + 3*30 + 4*40 + 5*50 = 10+40+90+160+250 = 550
521 EXPECT_EQ(sum, 550);
522}
523
525{
526 std::vector<std::string> stl = {"a", "b", "c"};
528 populate_dynarray(aleph, {1, 2, 3});
529
530 auto results = uni_zip_map([](auto t) {
531 return std::get<0>(t) + std::to_string(std::get<1>(t));
532 }, stl, aleph);
533
534 EXPECT_EQ(results[0], "a1");
535 EXPECT_EQ(results[2], "c3");
536}
537
539{
540 std::vector<int> stl = {100, 200, 300};
542 aleph.insert(1);
543 aleph.insert(2);
544 aleph.insert(3);
545
546 int count = 0;
547 for (auto [s, a] : uni_zip(stl, aleph))
548 {
549 EXPECT_GT(s, a); // STL values > Aleph values
550 ++count;
551 }
552 EXPECT_EQ(count, 3);
553}
554
555//------------------------------------------------------------------------------
556// Test: STL list + Aleph containers
557//------------------------------------------------------------------------------
558
560{
561 std::list<double> stl = {1.1, 2.2, 3.3};
562 DynList<double> aleph = {10.0, 20.0, 30.0};
563
564 auto products = uni_zip_map([](auto t) {
565 return std::get<0>(t) * std::get<1>(t);
566 }, stl, aleph);
567
568 EXPECT_EQ(products.size(), 3);
569 EXPECT_DOUBLE_EQ(products[0], 11.0);
570}
571
573{
574 std::list<int> stl = {1, 2, 3, 4};
576 aleph.append("one");
577 aleph.append("two");
578 aleph.append("three");
579 aleph.append("four");
580
581 std::vector<std::string> results;
582 uni_zip_for_each([&results](auto t) {
583 results.push_back(std::to_string(std::get<0>(t)) + "-" + std::get<1>(t));
584 }, stl, aleph);
585
586 EXPECT_EQ(results.size(), 4);
587 EXPECT_EQ(results[0], "1-one");
588 EXPECT_EQ(results[3], "4-four");
589}
590
591//------------------------------------------------------------------------------
592// Test: STL deque + Aleph containers
593//------------------------------------------------------------------------------
594
596{
597 std::deque<int> stl = {5, 10, 15, 20};
598 DynList<int> aleph = {1, 2, 3, 4};
599
600 bool all_greater = uni_zip_all([](auto t) {
601 return std::get<0>(t) > std::get<1>(t);
602 }, stl, aleph);
603
605}
606
608{
609 std::deque<char> stl = {'a', 'b', 'c'};
611 populate_dyndlist(aleph, {1, 2, 3});
612
613 auto results = uni_zip_map([](auto t) {
614 return std::string(1, std::get<0>(t)) + std::to_string(std::get<1>(t));
615 }, stl, aleph);
616
617 EXPECT_EQ(results[0], "a1");
618 EXPECT_EQ(results[2], "c3");
619}
620
621//------------------------------------------------------------------------------
622// Test: STL set + Aleph containers
623//------------------------------------------------------------------------------
624
626{
627 std::set<int> stl = {10, 20, 30}; // Ordered: 10, 20, 30
628 DynList<std::string> aleph = {"x", "y", "z"};
629
630 std::vector<int> nums;
631 std::vector<std::string> strs;
632
633 for (auto [n, s] : uni_zip(stl, aleph))
634 {
635 nums.push_back(n);
636 strs.push_back(s);
637 }
638
639 EXPECT_EQ(nums.size(), 3);
640 EXPECT_EQ(nums[0], 10);
641 EXPECT_EQ(strs[2], "z");
642}
643
645{
646 std::set<int> stl = {100, 200, 300};
648 populate_dynarray(aleph, {1.5, 2.5, 3.5});
649
650 auto products = uni_zip_map([](auto t) {
651 return std::get<0>(t) * std::get<1>(t);
652 }, stl, aleph);
653
654 EXPECT_DOUBLE_EQ(products[0], 150.0);
655}
656
657//------------------------------------------------------------------------------
658// Test: STL array + Aleph containers
659//------------------------------------------------------------------------------
660
662{
663 std::array<int, 4> stl = {1, 2, 3, 4};
664 DynList<int> aleph = {10, 20, 30, 40};
665
666 int sum = uni_zip_foldl(0, [](int acc, auto t) {
667 return acc + std::get<0>(t) + std::get<1>(t);
668 }, stl, aleph);
669
670 EXPECT_EQ(sum, 110); // (1+10) + (2+20) + (3+30) + (4+40)
671}
672
674{
675 std::array<std::string, 3> stl = {"hello", "world", "test"};
677 populate_dyndlist(aleph, {1, 2, 3});
678
679 auto results = uni_zip_map([](auto t) {
680 return std::get<0>(t) + ":" + std::to_string(std::get<1>(t));
681 }, stl, aleph);
682
683 EXPECT_EQ(results[0], "hello:1");
684 EXPECT_EQ(results[1], "world:2");
685}
686
687//------------------------------------------------------------------------------
688// Test: Multiple containers (3+)
689//------------------------------------------------------------------------------
690
692{
693 std::vector<int> v = {1, 2, 3};
694 DynList<int> l = {10, 20, 30};
695 std::deque<int> d = {100, 200, 300};
696
697 auto sums = uni_zip_map([](auto t) {
698 return std::get<0>(t) + std::get<1>(t) + std::get<2>(t);
699 }, v, l, d);
700
701 EXPECT_EQ(sums[0], 111);
702 EXPECT_EQ(sums[1], 222);
703 EXPECT_EQ(sums[2], 333);
704}
705
707{
708 DynList<int> l = {1, 2, 3};
709 std::vector<std::string> v = {"a", "b", "c"};
711 populate_dynarray(a, {1.1, 2.2, 3.3});
712
713 int count = 0;
714 for (auto [num, str, dbl] : uni_zip(l, v, a))
715 {
716 EXPECT_EQ(num, count + 1);
717 ++count;
718 }
719 EXPECT_EQ(count, 3);
720}
721
723{
724 std::vector<int> v1 = {1, 2};
725 DynList<int> l = {10, 20};
726 std::list<int> v2 = {100, 200};
728 populate_dynarray(a, {1000, 2000});
729
730 auto sums = uni_zip_map([](auto t) {
731 return std::get<0>(t) + std::get<1>(t) + std::get<2>(t) + std::get<3>(t);
732 }, v1, l, v2, a);
733
734 EXPECT_EQ(sums[0], 1111);
735 EXPECT_EQ(sums[1], 2222);
736}
737
738//------------------------------------------------------------------------------
739// Test: Aleph-only combinations
740//------------------------------------------------------------------------------
741
743{
744 DynList<int> l1 = {1, 2, 3};
745 DynDlist<int> l2;
746 populate_dyndlist(l2, {10, 20, 30});
747
748 auto products = uni_zip_map([](auto t) {
749 return std::get<0>(t) * std::get<1>(t);
750 }, l1, l2);
751
752 EXPECT_EQ(products[0], 10);
753 EXPECT_EQ(products[1], 40);
754 EXPECT_EQ(products[2], 90);
755}
756
758{
760 arr.append("first");
761 arr.append("second");
762 arr.append("third");
763
764 DynSetTree<int> tree;
765 tree.insert(1);
766 tree.insert(2);
767 tree.insert(3);
768
769 std::vector<std::string> results;
770 uni_zip_for_each([&results](auto t) {
771 results.push_back(std::get<0>(t) + "=" + std::to_string(std::get<1>(t)));
772 }, arr, tree);
773
774 EXPECT_EQ(results.size(), 3);
775}
776
778{
779 DynList<int> l = {1, 2, 3};
781 populate_dyndlist(d, {10, 20, 30});
783 populate_dynarray(a, {100, 200, 300});
784
785 int total = uni_zip_foldl(0, [](int acc, auto t) {
786 return acc + std::get<0>(t) + std::get<1>(t) + std::get<2>(t);
787 }, l, d, a);
788
789 EXPECT_EQ(total, 666); // (1+10+100) + (2+20+200) + (3+30+300)
790}
791
792//------------------------------------------------------------------------------
793// Test: Different lengths (should stop at shortest)
794//------------------------------------------------------------------------------
795
797{
798 std::vector<int> stl = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
799 DynList<int> aleph = {100, 200, 300};
800
802}
803
805{
806 std::vector<int> stl = {1, 2};
807 DynList<int> aleph = {10, 20, 30, 40, 50, 60, 70};
808
810}
811
813{
814 std::vector<int> v = {1, 2, 3, 4, 5};
815 DynList<int> l = {10, 20};
816 std::deque<int> d = {100, 200, 300, 400};
817
818 EXPECT_EQ(uni_zip_length(v, l, d), 2); // Shortest is DynList with 2
819}
820
821//------------------------------------------------------------------------------
822// Test: Functional operations with mixed containers
823//------------------------------------------------------------------------------
824
826{
827 std::vector<int> stl = {1, 2, 3, 4, 5, 6};
828 DynList<int> aleph = {10, 20, 30, 40, 50, 60};
829
830 // Filter where STL element is even
831 auto evens = uni_zip_filter([](auto t) {
832 return std::get<0>(t) % 2 == 0;
833 }, stl, aleph);
834
835 EXPECT_EQ(evens.size(), 3);
836 EXPECT_EQ(std::get<0>(evens[0]), 2);
837 EXPECT_EQ(std::get<1>(evens[0]), 20);
838}
839
841{
842 std::vector<int> stl = {1, 2, 3, 4, 5};
844 aleph.append("one");
845 aleph.append("two");
846 aleph.append("three");
847 aleph.append("four");
848 aleph.append("five");
849
850 auto [odds, evens] = uni_zip_partition([](auto t) {
851 return std::get<0>(t) % 2 == 1;
852 }, stl, aleph);
853
854 EXPECT_EQ(odds.size(), 3); // 1, 3, 5
855 EXPECT_EQ(evens.size(), 2); // 2, 4
856}
857
859{
860 DynList<int> aleph = {1, 2, 3, 4, 5};
861 std::vector<std::string> stl = {"a", "b", "c", "d", "e"};
862
863 auto first_three = uni_zip_take(3, aleph, stl);
864 auto last_two = uni_zip_drop(3, aleph, stl);
865
867 EXPECT_EQ(last_two.size(), 2);
868
869 EXPECT_EQ(std::get<0>(first_three[0]), 1);
870 EXPECT_EQ(std::get<0>(last_two[0]), 4);
871}
872
874{
875 std::deque<int> stl = {1, 2, 3, 10, 11, 12};
877 populate_dyndlist(aleph, {100, 200, 300, 1000, 1100, 1200});
878
879 auto small = uni_zip_take_while([](auto t) {
880 return std::get<0>(t) < 10;
881 }, stl, aleph);
882
883 auto large = uni_zip_drop_while([](auto t) {
884 return std::get<0>(t) < 10;
885 }, stl, aleph);
886
887 EXPECT_EQ(small.size(), 3);
888 EXPECT_EQ(large.size(), 3);
889}
890
891//------------------------------------------------------------------------------
892// Test: String as container (sequence of chars)
893//------------------------------------------------------------------------------
894
896{
897 std::string stl = "ABC";
898 DynList<int> aleph = {1, 2, 3};
899
900 auto results = uni_zip_map([](auto t) {
901 return std::string(1, std::get<0>(t)) + std::to_string(std::get<1>(t));
902 }, stl, aleph);
903
904 EXPECT_EQ(results[0], "A1");
905 EXPECT_EQ(results[1], "B2");
906 EXPECT_EQ(results[2], "C3");
907}
908
909//==============================================================================
910// ML-style Operations Tests (Mixed STL + Aleph)
911//==============================================================================
912
914{
915 std::vector<int> stl = {10, 20, 30};
916 DynList<int> aleph = {1, 2, 3};
917
918 auto results = uni_zip_mapi([](size_t i, auto t) {
919 return std::to_string(i) + ":" + std::to_string(std::get<0>(t) + std::get<1>(t));
920 }, stl, aleph);
921
922 EXPECT_EQ(results.size(), 3);
923 EXPECT_EQ(results[0], "0:11");
924 EXPECT_EQ(results[2], "2:33");
925}
926
928{
929 DynList<int> aleph = {10, 20, 30, 40, 50};
930 std::vector<std::string> stl = {"a", "b", "c", "d", "e"};
931
932 auto evens = uni_zip_filteri([](size_t i, auto) {
933 return i % 2 == 0;
934 }, aleph, stl);
935
936 EXPECT_EQ(evens.size(), 3);
937 EXPECT_EQ(std::get<0>(evens[0]), 10);
938 EXPECT_EQ(std::get<0>(evens[2]), 50);
939}
940
942{
943 std::vector<int> stl = {1, 2, 3, 4};
944 DynList<int> aleph = {10, 20, 30, 40};
945
946 auto sums = uni_zip_scan_left(0, [](int acc, auto t) {
947 return acc + std::get<0>(t);
948 }, stl, aleph);
949
950 EXPECT_EQ(sums.size(), 5);
951 EXPECT_EQ(sums[0], 0); // init
952 EXPECT_EQ(sums[1], 1); // 0 + 1
953 EXPECT_EQ(sums[2], 3); // 1 + 2
954 EXPECT_EQ(sums[3], 6); // 3 + 3
955 EXPECT_EQ(sums[4], 10); // 6 + 4
956}
957
959{
960 DynList<int> aleph = {1, 2, 3, 4, 5};
961 std::vector<std::string> stl = {"a", "b", "c", "d", "e"};
962
963 auto result = uni_zip_find_mapi([](size_t i, auto t) -> std::optional<std::string> {
964 if (std::get<0>(t) == 3)
965 return "found at " + std::to_string(i);
966 return std::nullopt;
967 }, aleph, stl);
968
969 ASSERT_TRUE(result.has_value());
970 EXPECT_EQ(*result, "found at 2");
971}
972
974{
975 std::vector<int> stl = {1, 2, 3};
976 DynList<int> aleph = {10, 20, 30};
977
978 bool result = uni_zip_equal_by([](auto t) {
979 return std::get<0>(t) * 10 == std::get<1>(t);
980 }, stl, aleph);
981
982 EXPECT_TRUE(result);
983}
984
986{
987 std::vector<int> stl = {1, 2, 3};
988 DynList<std::string> aleph = {"a", "b", "c"};
989
990 EXPECT_TRUE(uni_zip_mem(std::make_tuple(2, std::string("b")), stl, aleph));
991 EXPECT_FALSE(uni_zip_mem(std::make_tuple(2, std::string("x")), stl, aleph));
992}
993
995{
996 DynList<std::string> keys = {"one", "two", "three"};
997 std::vector<int> values = {1, 2, 3};
998
999 auto result = uni_zip_assoc(std::string("two"), keys, values);
1000
1001 ASSERT_TRUE(result.has_value());
1002 EXPECT_EQ(std::get<0>(*result), "two");
1003 EXPECT_EQ(std::get<1>(*result), 2);
1004}
1005
1007{
1008 std::vector<int> stl = {3, 1, 4, 1, 5};
1009 DynList<int> aleph = {30, 10, 40, 10, 50};
1010
1011 auto result = uni_zip_min(stl, aleph);
1012
1013 ASSERT_TRUE(result.has_value());
1014 EXPECT_EQ(std::get<0>(*result), 1);
1015}
1016
1018{
1019 std::vector<int> stl = {3, 1, 4, 1, 5};
1020 DynList<int> aleph = {30, 10, 40, 10, 50};
1021
1022 auto result = uni_zip_max(stl, aleph);
1023
1024 ASSERT_TRUE(result.has_value());
1025 EXPECT_EQ(std::get<0>(*result), 5);
1026}
1027
1029{
1030 DynList<int> aleph = {3, 1, 4, 1, 5};
1031 std::vector<int> stl = {30, 10, 40, 10, 50};
1032
1033 auto result = uni_zip_min_max(aleph, stl);
1034
1035 ASSERT_TRUE(result.has_value());
1036 EXPECT_EQ(std::get<0>(result->first), 1); // min
1037 EXPECT_EQ(std::get<0>(result->second), 5); // max
1038}
1039
1040//==============================================================================
1041// Unzip Operations Tests
1042//==============================================================================
1043
1045{
1046 std::vector<std::pair<int, std::string>> pairs = {
1047 {1, "a"}, {2, "b"}, {3, "c"}
1048 };
1049
1050 auto [nums, strs] = uni_unzip(pairs);
1051
1052 EXPECT_EQ(nums.size(), 3);
1053 EXPECT_EQ(strs.size(), 3);
1054
1055 auto num_it = nums.get_it();
1056 EXPECT_EQ(num_it.get_curr(), 1);
1057 num_it.next();
1058 EXPECT_EQ(num_it.get_curr(), 2);
1059
1060 auto str_it = strs.get_it();
1061 EXPECT_EQ(str_it.get_curr(), "a");
1062}
1063
1065{
1067 pairs.append({1, 1.1});
1068 pairs.append({2, 2.2});
1069 pairs.append({3, 3.3});
1070
1071 auto [ints, doubles] = uni_unzip(pairs);
1072
1073 EXPECT_EQ(ints.size(), 3);
1074 EXPECT_EQ(doubles.size(), 3);
1075}
1076
1078{
1079 std::vector<std::tuple<int, double, char>> tuples = {
1080 {1, 1.1, 'a'},
1081 {2, 2.2, 'b'},
1082 {3, 3.3, 'c'}
1083 };
1084
1085 auto [ints, doubles, chars] = uni_unzip_tuple(tuples);
1086
1087 EXPECT_EQ(ints.size(), 3);
1088 EXPECT_EQ(doubles.size(), 3);
1089 EXPECT_EQ(chars.size(), 3);
1090
1091 auto int_it = ints.get_it();
1092 EXPECT_EQ(int_it.get_curr(), 1);
1093
1094 auto char_it = chars.get_it();
1095 EXPECT_EQ(char_it.get_curr(), 'a');
1096}
1097
1099{
1101 tuples.append({1, "one"});
1102 tuples.append({2, "two"});
1103 tuples.append({3, "three"});
1104
1105 auto [ints, strs] = uni_unzip_tuple(tuples);
1106
1107 EXPECT_EQ(ints.size(), 3);
1108 EXPECT_EQ(strs.size(), 3);
1109}
1110
1112{
1113 std::vector<int> stl = {1, 2, 3};
1114 DynList<std::string> aleph = {"a", "b", "c"};
1115
1116 auto result = uni_zip_to_dynlist(stl, aleph);
1117
1118 EXPECT_EQ(result.size(), 3);
1119
1120 auto it = result.get_it();
1121 EXPECT_EQ(std::get<0>(it.get_curr()), 1);
1122 EXPECT_EQ(std::get<1>(it.get_curr()), "a");
1123}
1124
1125//==============================================================================
1126// Bug Fix Tests - Stateful Callables
1127//==============================================================================
1128
1129// Test that stateful callables work correctly (std::forward bug fix)
1131{
1132 mutable int count = 0;
1133 bool operator()(auto) const { ++count; return true; }
1134};
1135
1137{
1138 mutable int sum = 0;
1139 void operator()(auto t) const { sum += std::get<0>(t); }
1140};
1141
1143{
1144 std::vector<int> v1 = {1, 2, 3, 4, 5};
1145 std::vector<int> v2 = {10, 20, 30, 40, 50};
1146
1148 uni_zip_for_each(std::ref(acc), v1, v2);
1149
1150 EXPECT_EQ(acc.sum, 15); // 1+2+3+4+5
1151}
1152
1154{
1155 std::vector<int> v1 = {1, 2, 3, 4, 5};
1156 std::vector<int> v2 = {10, 20, 30, 40, 50};
1157
1158 StatefulCounter counter;
1159 uni_zip_all(std::ref(counter), v1, v2);
1160
1161 EXPECT_EQ(counter.count, 5); // Called 5 times
1162}
1163
1165{
1166 std::vector<int> v1 = {1, 2, 3};
1167 std::vector<int> v2 = {10, 20, 30};
1168
1169 int call_count = 0;
1170 auto result = uni_zip_map([&call_count](auto t) {
1171 ++call_count;
1172 return std::get<0>(t) + std::get<1>(t);
1173 }, v1, v2);
1174
1175 EXPECT_EQ(call_count, 3);
1176 EXPECT_EQ(result.size(), 3);
1177}
1178
1180{
1181 std::vector<int> v1 = {1, 2, 3, 4, 5};
1182 std::vector<int> v2 = {10, 20, 30, 40, 50};
1183
1184 int call_count = 0;
1185 auto result = uni_zip_filter([&call_count](auto t) {
1186 ++call_count;
1187 return std::get<0>(t) % 2 == 0;
1188 }, v1, v2);
1189
1190 EXPECT_EQ(call_count, 5); // Predicate called for all elements
1191 EXPECT_EQ(result.size(), 2); // Only evens pass
1192}
1193
1195{
1196 std::vector<int> v1 = {1, 2, 3};
1197 std::vector<int> v2 = {10, 20, 30};
1198
1199 int call_count = 0;
1200 auto result = uni_zip_foldl(0, [&call_count](int acc, auto t) {
1201 ++call_count;
1202 return acc + std::get<0>(t);
1203 }, v1, v2);
1204
1205 EXPECT_EQ(call_count, 3);
1206 EXPECT_EQ(result, 6); // 1+2+3
1207}
1208
1209//==============================================================================
1210// Bug Fix Tests - Equal Length Semantics
1211//==============================================================================
1212
1214{
1215 std::vector<int> v1 = {1, 2, 3};
1216 std::vector<int> v2 = {10, 20, 30};
1217 std::vector<int> v3 = {100, 200}; // Shorter
1218
1219 // Same length containers
1221
1222 // Different length containers
1225}
1226
1228{
1229 std::vector<int> v1 = {1, 2, 3};
1230 std::vector<int> v2 = {10, 20, 30};
1231 std::vector<int> v3 = {100, 200}; // Shorter
1232
1233 // All true + equal length = true
1234 EXPECT_TRUE(uni_zip_all_eq([](auto) { return true; }, v1, v2));
1235
1236 // All true but different length = false
1237 EXPECT_FALSE(uni_zip_all_eq([](auto) { return true; }, v1, v3));
1238
1239 // One false + equal length = false
1240 EXPECT_FALSE(uni_zip_all_eq([](auto t) {
1241 return std::get<0>(t) != 2;
1242 }, v1, v2));
1243}
1244
1246{
1247 std::vector<int> v1 = {1, 2, 3};
1248 std::vector<int> v2 = {10, 20, 30};
1249 std::vector<int> v3 = {10, 20}; // Shorter
1250
1251 // Condition passes, equal length
1252 EXPECT_TRUE(uni_zip_equal_by([](auto t) {
1253 return std::get<0>(t) < std::get<1>(t);
1254 }, v1, v2));
1255
1256 // Condition passes but different length
1257 EXPECT_FALSE(uni_zip_equal_by([](auto t) {
1258 return std::get<0>(t) < std::get<1>(t);
1259 }, v1, v3));
1260}
1261
1262//==============================================================================
1263// Bug Fix Tests - Sentinel End() O(1)
1264//==============================================================================
1265
1267{
1268 std::vector<int> v1 = {1, 2, 3, 4, 5};
1269 std::vector<int> v2 = {10, 20, 30, 40, 50};
1270
1271 auto view = uni_zip(v1, v2);
1272
1273 // end() should return sentinel immediately (O(1))
1274 auto sentinel = view.end();
1275 (void)sentinel; // Just verify it compiles and returns
1276
1277 // Iteration should work
1278 int count = 0;
1279 for (auto [a, b] : view)
1280 {
1281 (void)a; (void)b;
1282 ++count;
1283 }
1284 EXPECT_EQ(count, 5);
1285}
1286
1288{
1289 std::vector<int> v1 = {1, 2, 3};
1290 std::vector<int> v2 = {10, 20, 30};
1291
1292 auto view = uni_zip(v1, v2);
1293 auto it = view.begin();
1294 auto end = view.end();
1295
1296 // Iterator not at end initially
1297 EXPECT_NE(it, end);
1298 EXPECT_TRUE(it.has_curr());
1299
1300 // Advance to end
1301 ++it; ++it; ++it;
1302
1303 // Now at end
1304 EXPECT_EQ(it, end);
1305 EXPECT_FALSE(it.has_curr());
1306}
1307
1308//==============================================================================
1309// New API Tests - any_has_curr and all_completed
1310//==============================================================================
1311
1313{
1314 std::vector<int> v1 = {1, 2, 3};
1315 std::vector<int> v2 = {10, 20}; // Shorter
1316
1317 auto it = uni_zip_it(v1, v2);
1318
1319 // Both have elements initially
1320 EXPECT_TRUE(it.has_curr());
1321 EXPECT_TRUE(it.any_has_curr());
1322
1323 it.next();
1324 it.next();
1325
1326 // v2 exhausted, v1 still has one more
1327 EXPECT_FALSE(it.has_curr()); // Not ALL have elements
1328 EXPECT_TRUE(it.any_has_curr()); // But SOME still have
1329
1330 // all_completed is false because v1 still has elements
1331 EXPECT_FALSE(it.all_completed());
1332}
1333
1335{
1336 std::vector<int> v1 = {1, 2, 3};
1337 std::vector<int> v2 = {10, 20, 30};
1338
1339 auto it = uni_zip_it(v1, v2);
1340
1341 // Exhaust iterator
1342 while (it.has_curr())
1343 it.next();
1344
1345 // Both containers exhausted at same time
1346 EXPECT_TRUE(it.all_completed());
1347 EXPECT_TRUE(it.completed()); // Backward compatible
1348}
1349
1350//==============================================================================
1351// Edge Cases for Fixes
1352//==============================================================================
1353
1355{
1356 std::vector<int> empty1;
1357 std::vector<int> empty2;
1358
1359 // Should handle empty gracefully with stateful callables
1360 int call_count = 0;
1361 uni_zip_for_each([&call_count](auto) { ++call_count; }, empty1, empty2);
1362 EXPECT_EQ(call_count, 0);
1363
1364 auto result = uni_zip_map([&call_count](auto t) {
1365 ++call_count;
1366 return std::get<0>(t);
1367 }, empty1, empty2);
1368 EXPECT_EQ(call_count, 0);
1369 EXPECT_TRUE(result.empty());
1370}
1371
1373{
1374 std::vector<int> v1 = {42};
1375 std::vector<std::string> v2 = {"answer"};
1376
1377 int call_count = 0;
1378 auto result = uni_zip_map([&call_count](auto t) {
1379 ++call_count;
1380 return std::to_string(std::get<0>(t)) + ":" + std::get<1>(t);
1381 }, v1, v2);
1382
1383 EXPECT_EQ(call_count, 1);
1384 EXPECT_EQ(result.size(), 1);
1385 EXPECT_EQ(result[0], "42:answer");
1386}
1387
1388// Main
1389int main(int argc, char **argv)
1390{
1391 ::testing::InitGoogleTest(&argc, argv);
1392 return RUN_ALL_TESTS();
1393}
Unified zip operations for both STL and Aleph containers.
void populate_dyndlist(DynDlist< T > &l, std::initializer_list< T > values)
void populate_dynarray(DynArray< T > &arr, std::initializer_list< T > values)
void populate_dynlist(DynList< T > &l, std::initializer_list< T > values)
int main()
T & append()
Allocate a new entry to the end of array.
Dynamic doubly linked list with O(1) size and bidirectional access.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & insert(const T &item)
Insert a new item by copy.
Definition htlist.H:1502
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
void empty() noexcept
empty the list
Definition htlist.H:1689
Dynamic set backed by balanced binary search trees with automatic memory management.
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:1319
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:190
iterator end() noexcept
Return an STL-compatible end iterator.
iterator begin() noexcept
Return an STL-compatible iterator to the first element.
#define TEST(name)
Singly linked list implementations with head-tail access.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
auto uni_zip_scan_left(T init, Op &&op, const Containers &... cs)
Scan left - fold with intermediate results.
auto uni_zip(const Containers &... cs)
Create a lazy zip view over any combination of STL/Aleph containers.
auto uni_zip_take(size_t n, const Containers &... cs)
Take first n tuples.
bool uni_zip_equal_length(const Containers &... cs)
Check if all containers have equal length.
bool uni_zip_exists(Pred &&pred, const Containers &... cs)
Check if predicate holds for any zipped tuple.
auto uni_zip_to_vector(const Containers &... cs)
Materialize zipped tuples into a vector.
auto uni_zip_min_max(const Containers &... cs)
Get both min and max in a single pass.
auto uni_zip_filteri(Pred &&pred, const Containers &... cs)
Filter with index (filteri in ML).
T uni_zip_foldl(T init, Op &&op, const Containers &... cs)
Left fold over zipped tuples.
size_t uni_zip_length(const Containers &... cs)
Get zip length (minimum of all container sizes).
auto uni_unzip_tuple(const Container &c)
Unzip a container of tuples into a tuple of DynLists.
auto uni_zip_mapi(Op &&op, const Containers &... cs)
Map with index (mapi in ML).
bool uni_zip_equal_by(Eq &&eq, const Containers &... cs)
Check equality with custom comparator.
auto uni_zip_last(const Containers &... cs)
Get last tuple.
auto uni_zip_partition(Pred &&pred, const Containers &... cs)
Partition tuples by predicate.
auto uni_zip_nth(size_t n, const Containers &... cs)
Get n-th tuple from zipped containers.
auto uni_zip_min(const Containers &... cs)
Get minimum tuple.
auto uni_unzip(const Container &c)
Unzip a container of pairs into two DynLists.
auto uni_zip_to_dynlist(const Containers &... cs)
Materialize a zipped view into a DynList of tuples.
void uni_zip_for_each(Op &&op, const Containers &... cs)
Apply operation to each zipped tuple.
auto uni_zip_max(const Containers &... cs)
Get maximum tuple.
auto uni_zip_assoc(const Key &key, const Containers &... cs)
Find value associated with key in zipped pairs (assoc in ML).
auto uni_zip_it(const Containers &... cs)
Get a unified zip iterator.
bool uni_zip_all(Pred &&pred, const Containers &... cs)
Check if predicate holds for all zipped tuples.
size_t uni_zip_count(Pred &&pred, const Containers &... cs)
Count tuples satisfying predicate.
auto uni_zip_first(const Containers &... cs)
Get first tuple.
auto uni_zip_drop_while(Pred &&pred, const Containers &... cs)
Skip tuples while predicate is true, return the rest.
auto uni_zip_find_mapi(Op &&op, const Containers &... cs)
Find and map with index (find_mapi in ML).
auto uni_zip_filter(Pred &&pred, const Containers &... cs)
Filter zipped tuples by predicate.
auto uni_zip_map(Op &&op, const Containers &... cs)
Map operation over zipped tuples.
auto uni_zip_take_while(Pred &&pred, const Containers &... cs)
Take tuples while predicate is true.
auto uni_zip_drop(size_t n, const Containers &... cs)
Skip first n tuples, return the rest.
bool uni_zip_all_eq(Pred &&pred, const Containers &... cs)
Check if all tuples satisfy predicate AND containers have equal length.
auto uni_zip_find_first(Pred &&pred, const Containers &... cs)
Find first tuple satisfying predicate.
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
bool uni_zip_mem(const Tuple &target, const Containers &... cs)
Check if a tuple exists in the zipped sequence (mem in ML).
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
Sentinel type for UniZipIterator end comparison.
void operator()(auto t) const
bool operator()(auto) const
Circular queue implementations backed by arrays.
Stack implementations backed by dynamic or fixed arrays.
Lazy and scalable dynamic array implementation.
Dynamic doubly linked list implementation.
Dynamic queue implementation based on linked lists.
Dynamic stack implementation based on linked lists.
Dynamic set implementations based on hash tables.
Dynamic set implementations based on balanced binary search trees.
DynList< int > l