Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-zip.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
33
38# include <gtest/gtest.h>
39
40# include <ah-zip.H>
41# include <ahFunctional.H>
42# include <ah-string-utils.H>
43# include <tpl_dynSetTree.H>
44# include <tpl_dynArray.H>
45# include <tpl_array.H>
46# include <tpl_dynSetHash.H>
47
48using namespace std;
49using namespace Aleph;
50
58
59struct CompleteGroup : public testing::Test
60{
61 static constexpr size_t N = 5;
65 range<int>(0, N - 1).maps<string>([] (auto i) { return to_string(i); });
67};
68
69struct InCompleteGroup : public testing::Test
70{
71 DynList<int> l1 = { 0, 1, 2, 3, 4 };
72 DynSetTree<int> l2 = { 0, 1, 2, 3 };
73 DynArray<string> l3 = { "0", "1", "2", "3", "4" };
74 DynSkipList<int> l4 = { 0, 1, 2 }; // Different length
75};
76
78{
79 {
80 auto it = zip_it(l1, l2 , l3);
81 ASSERT_FALSE(it.has_curr());
82 ASSERT_THROW(it.get_curr(), std::overflow_error);
83 ASSERT_THROW(it.next(), std::overflow_error);
84 }
85 {
86 auto it = zip_it(l1, l2, l3, l4);
87 ASSERT_FALSE(it.has_curr());
88 ASSERT_THROW(it.get_curr(), std::overflow_error);
89 ASSERT_THROW(it.next(), std::overflow_error);
90 }
91 {
92 auto it = zip_it(l1);
93 ASSERT_FALSE(it.has_curr());
94 ASSERT_THROW(it.get_curr(), std::overflow_error);
95 ASSERT_THROW(it.next(), std::overflow_error);
96 }
97
98 ASSERT_NO_THROW(zip_it_pos(0, l1, l2, l3));
99 ASSERT_THROW(zip_it_pos(1, l1, l2, l3), std::overflow_error);
100
101 {
102 auto it = enum_zip_it(l1, l2 , l3);
103 ASSERT_FALSE(it.has_curr());
104 ASSERT_THROW(it.get_curr(), std::overflow_error);
105 ASSERT_THROW(it.next(), std::overflow_error);
106 }
107 {
108 auto it = enum_zip_it(l1);
109 ASSERT_FALSE(it.has_curr());
110 ASSERT_THROW(it.get_curr(), std::overflow_error);
111 ASSERT_THROW(it.next(), std::overflow_error);
112 }
113
114 ASSERT_NO_THROW(enum_zip_it_pos(0, l1, l2, l3));
115 ASSERT_THROW(enum_zip_it_pos(1, l1, l2, l3), std::overflow_error);
116}
117
119{
120 size_t i = 0;
121 for (auto it = zip_it(l1, l2, l3); it.has_curr(); it.next_ne(), ++i)
122 {
123 auto t = it.get_curr_ne();
124 EXPECT_EQ(get<0>(t), i);
125 EXPECT_EQ(get<1>(t), i);
126 EXPECT_EQ(get<2>(t), to_string(i));
127 }
128
129 i = 1;
130 for (auto it = zip_it_pos(1, l1, l2, l3); it.has_curr(); it.next_ne(), ++i)
131 {
132 auto t = it.get_curr_ne();
133 EXPECT_EQ(get<0>(t), i);
134 EXPECT_EQ(get<1>(t), i);
135 EXPECT_EQ(get<2>(t), to_string(i));
136 }
137
138 for (auto it = enum_zip_it(l1, l2, l3); it.has_curr(); it.next_ne())
139 {
140 auto t = it.get_curr_ne();
141 auto & i = get<3>(t);
142 EXPECT_EQ(get<0>(t), i);
143 EXPECT_EQ(get<1>(t), i);
144 EXPECT_EQ(get<2>(t), to_string(i));
145 }
146}
147
149{
150 EXPECT_FALSE(equal_length(l1, l2, l3));
151 EXPECT_TRUE(zip_traverse([] (auto t) { return get<0>(t) == get<1>(t)
152 and to_string(get<0>(t)) == get<2>(t); }, l1, l2, l3));
153 EXPECT_FALSE(zip_traverse_eq([] (auto t) { return get<0>(t) == get<1>(t)
154 and to_string(get<0>(t)) == get<2>(t); }, l1, l2, l3));
155 EXPECT_NO_THROW(zip_for_each([] (auto) { return; }, l1, l2, l3));
156 EXPECT_THROW(zip_for_each_eq([] (auto) { return; }, l1, l2, l3),
157 length_error);
158
159 size_t i = 0;
160 zip_for_each([&i] (auto t)
161 {
162 EXPECT_EQ(get<0>(t), i++);
163 EXPECT_EQ(get<0>(t), get<1>(t));
165 }, l1, l2, l3);
166
167 i = 0;
168 EXPECT_THROW(zip_for_each_eq([&i] (auto t)
169 {
170 EXPECT_EQ(get<0>(t), i++);
171 EXPECT_EQ(get<0>(t), get<1>(t));
173 }, l1, l2, l3), length_error);
174
175 EXPECT_FALSE(zip_all([] (auto t) { return get<0>(t) == get<1>(t)
176 and to_string(get<0>(t)) == get<2>(t); }, l1, l2, l3));
177 EXPECT_TRUE(zip_exists([] (auto t) { return get<0>(t) == get<1>(t) and
178 get<2>(t) == "3"; }, l1, l2, l3));
179
180 auto lmap = zip_maps<string>([] (auto t)
181 {
182 return to_string(get<0>(t)) +
183 to_string(get<1>(t)) + get<2>(t);
184 }, l1, l2, l3);
185 EXPECT_EQ(lmap, build_dynlist<string>("000", "111", "222", "333"));
186
187 lmap = zip_maps_if<string>([] (auto t) { return get<0>(t) != 1; },
188 [] (auto t)
189 {
190 return to_string(get<0>(t)) +
191 to_string(get<1>(t)) + get<2>(t);
192 }, l1, l2, l3);
193 EXPECT_EQ(lmap, build_dynlist<string>("000", "222", "333"));
194
195 EXPECT_THROW(t_zip_eq(l1, l2, l3), length_error);
196}
197
199{
200 EXPECT_TRUE(equal_length(l1, l2, l3));
201 EXPECT_TRUE(zip_traverse([] (auto t) { return get<0>(t) == get<1>(t)
202 and to_string(get<0>(t)) == get<2>(t); }, l1, l2, l3));
203 EXPECT_NO_THROW((void)zip_traverse_eq([] (auto t) { return get<0>(t) == get<1>(t)
204 and to_string(get<0>(t)) == get<2>(t); }, l1, l2, l3));
205 zip_for_each([] (auto t)
206 {
207 EXPECT_EQ(get<0>(t), get<1>(t));
209 }, l1, l2, l3);
210 zip_for_each_eq([] (auto t)
211 {
212 EXPECT_EQ(get<0>(t), get<1>(t));
214 }, l1, l2, l3);
215 EXPECT_TRUE(zip_all([] (auto t) { return get<0>(t) == get<1>(t)
216 and to_string(get<0>(t)) == get<2>(t); }, l1, l2, l3));
217 EXPECT_TRUE(zip_exists([] (auto t) { return get<0>(t) == get<1>(t) and
218 get<2>(t) == "3"; }, l1, l2, l3));
219 EXPECT_FALSE(zip_exists([] (auto t) { return get<0>(t) == get<1>(t) and
220 get<2>(t) == "7"; }, l1, l2, l3));
221
222 auto lmap = zip_maps<string>([] (auto t)
223 {
224 return to_string(get<0>(t)) +
225 to_string(get<1>(t)) + get<2>(t);
226 }, l1, l2, l3);
227 EXPECT_EQ(lmap, build_dynlist<string>("000", "111", "222", "333", "444"));
228
229 lmap = zip_maps_if<string>([] (auto t) { return get<0>(t) != 1; },
230 [] (auto t)
231 {
232 return to_string(get<0>(t)) +
233 to_string(get<1>(t)) + get<2>(t);
234 }, l1, l2, l3);
235 EXPECT_EQ(lmap, build_dynlist<string>("000", "222", "333", "444"));
236
237 auto sum = zip_foldl(0, [] (auto a, auto t)
238 { return a + get<0>(t) + get<1>(t); }, l1, l2, l3);
239 EXPECT_EQ(sum, N*(N- 1));
240
241 auto lfilt = zip_filter([] (auto t)
242 { return get<1>(t) != 2; }, l1, l2, l3);
244 { make_tuple(0, 0, "0"), make_tuple(1, 1, "1"),
245 make_tuple(3, 3, "3"), make_tuple(4, 4, "4") };
247
248 EXPECT_TRUE(zip_cmp([] (auto & i1, auto & i2) { return i1 == i2; },
249 l1, l2, l1, l2));
250
251 auto l1_mutated = l1; l1_mutated.nth(3) = 4;
252 EXPECT_FALSE(zip_cmp([] (auto & i1, auto & i2) { return i1 == i2; },
253 l1, l2, l1_mutated, l2));
254
255 auto lzip = t_zip(l1, l2, l3);
256 for (auto it = zip_it(lzip, l1, l2, l3); it.has_curr(); it.next_ne())
257 {
258 auto t = it.get_curr_ne();
259 auto & tz = get<0>(t);
261 }
262
263 auto uzip = t_unzip(lzip);
264 EXPECT_EQ(get<0>(uzip), l1);
265 EXPECT_EQ(get<1>(uzip), l2.keys());
266 EXPECT_TRUE(eq(get<2>(uzip), l3));
267
268 auto idx = zip_find_index([] (auto t)
269 {
270 return get<0>(t) == get<1>(t) and
271 to_string(get<1>(t)) == get<2>(t) and
272 get<0>(t) == N - 1;
273 }, l1, l2, l3);
274 EXPECT_EQ(idx, N - 1);
275
276 idx = zip_find_index([] (auto t)
277 {
278 return get<0>(t) == N;
279 }, l1, l2, l3);
280 EXPECT_EQ(idx, N - 0 /* for avoiding linker error with constant */);
281
282 auto part = zip_partition([] (auto t) { return get<0>(t) < 2; }, l1, l2, l3);
283
284 EXPECT_TRUE(eq(get<0>(part).maps<string>([] (auto & t)
285 {
286 return to_string(get<0>(t)) + to_string(get<1>(t)) + get<2>(t);
287 }), build_dynlist<string>("000", "111")));
288 EXPECT_EQ(get<1>(part), 2);
289 EXPECT_TRUE(eq(get<2>(part).maps<string>([] (auto & t)
290 {
291 return to_string(get<0>(t)) + to_string(get<1>(t)) + get<2>(t);
292 }), build_dynlist<string>("222", "333", "444")));
293 EXPECT_EQ(get<3>(part), N - 2);
294
295 auto l = zip_lists(l1, l2, l1, l2);
296 for (auto it = zip_it(l, l1, l2); it.has_curr(); it.next_ne())
297 {
298 auto c = it.get_curr_ne();
300 get<1>(c), get<2>(c)));
301 }
302}
303
304// ==================== NEW TESTS ====================
305
306// Test zip_lists_eq with equal length containers
308{
309 auto result = zip_lists_eq(l1, l2, l1);
310
311 EXPECT_EQ(result.size(), N);
312
313 size_t i = 0;
314 for (auto it = result.get_it(); it.has_curr(); it.next_ne(), ++i)
315 {
316 auto & inner_list = it.get_curr();
318 auto inner_it = inner_list.get_it();
319 EXPECT_EQ(inner_it.get_curr(), i); // from l1
320 inner_it.next();
321 EXPECT_EQ(inner_it.get_curr(), i); // from l2
322 inner_it.next();
323 EXPECT_EQ(inner_it.get_curr(), i); // from l1 again
324 }
325}
326
327// Test zip_lists_eq with unequal length containers - should throw
329{
330 DynList<int> l_short = { 0, 1, 2 };
331 DynList<int> l_long = { 0, 1, 2, 3, 4 };
332
333 EXPECT_THROW(zip_lists_eq(l_short, l_long), length_error);
334}
335
336// Test t_enum_zip
338{
339 auto result = t_enum_zip(l1, l2);
340
341 EXPECT_EQ(result.size(), N);
342
343 for (auto it = result.get_it(); it.has_curr(); it.next_ne())
344 {
345 auto t = it.get_curr();
346 auto idx = get<2>(t); // Index is last element
347 EXPECT_EQ(get<0>(t), idx); // l1 value should match index
348 EXPECT_EQ(get<1>(t), idx); // l2 value should match index
349 }
350}
351
352// Test t_enum_zip_eq with equal containers
354{
355 auto result = t_enum_zip_eq(l1, l2);
356
357 EXPECT_EQ(result.size(), N);
358
359 size_t expected_idx = 0;
360 for (auto it = result.get_it(); it.has_curr(); it.next_ne(), ++expected_idx)
361 {
362 auto t = it.get_curr();
364 }
365}
366
367// Test t_enum_zip_eq with unequal containers - should throw
372
373// Test std_zip with STL vectors
375{
376 vector<int> v1 = { 1, 2, 3, 4, 5 };
377 vector<string> v2 = { "a", "b", "c", "d", "e" };
378
379 auto result = std_zip(v1, v2);
380
381 EXPECT_EQ(result.size(), 5);
382
383 for (size_t i = 0; i < result.size(); ++i)
384 {
385 EXPECT_EQ(result[i].first, static_cast<int>(i + 1));
386 EXPECT_EQ(result[i].second, string(1, 'a' + i));
387 }
388}
389
390// Test std_zip with unequal length - should stop at shorter
392{
393 vector<int> v1 = { 1, 2, 3 };
394 vector<int> v2 = { 10, 20, 30, 40, 50 };
395
396 auto result = std_zip(v1, v2);
397
398 EXPECT_EQ(result.size(), 3); // Stops at shorter container
399 EXPECT_EQ(result[0].first, 1);
400 EXPECT_EQ(result[0].second, 10);
401 EXPECT_EQ(result[2].first, 3);
402 EXPECT_EQ(result[2].second, 30);
403}
404
405// Test tzip_std with 2 STL containers (variadic version)
407{
408 vector<int> v1 = { 1, 2, 3 };
409 vector<string> v2 = { "a", "b", "c" };
410
411 auto result = tzip_std(v1, v2);
412
413 EXPECT_EQ(result.size(), 3);
414 EXPECT_EQ(get<0>(result[0]), 1);
415 EXPECT_EQ(get<1>(result[0]), "a");
416 EXPECT_EQ(get<0>(result[2]), 3);
417 EXPECT_EQ(get<1>(result[2]), "c");
418}
419
420// Test tzip_std with 3 STL containers
422{
423 vector<int> v1 = { 1, 2, 3 };
424 vector<double> v2 = { 1.1, 2.2, 3.3 };
425 vector<char> v3 = { 'a', 'b', 'c' };
426
427 auto result = tzip_std(v1, v2, v3);
428
429 EXPECT_EQ(result.size(), 3);
430 EXPECT_EQ(get<0>(result[0]), 1);
431 EXPECT_DOUBLE_EQ(get<1>(result[0]), 1.1);
432 EXPECT_EQ(get<2>(result[0]), 'a');
433}
434
435// Test tzip_std with 4 STL containers
437{
438 vector<int> v1 = { 1, 2, 3 };
439 vector<double> v2 = { 1.1, 2.2, 3.3 };
440 vector<char> v3 = { 'a', 'b', 'c' };
441 vector<string> v4 = { "x", "y", "z" };
442
443 auto result = tzip_std(v1, v2, v3, v4);
444
445 EXPECT_EQ(result.size(), 3);
446
447 EXPECT_EQ(get<0>(result[0]), 1);
448 EXPECT_DOUBLE_EQ(get<1>(result[0]), 1.1);
449 EXPECT_EQ(get<2>(result[0]), 'a');
450 EXPECT_EQ(get<3>(result[0]), "x");
451
452 EXPECT_EQ(get<0>(result[2]), 3);
453 EXPECT_DOUBLE_EQ(get<1>(result[2]), 3.3);
454 EXPECT_EQ(get<2>(result[2]), 'c');
455 EXPECT_EQ(get<3>(result[2]), "z");
456}
457
458// Test tzip_std with 5 STL containers
460{
461 vector<int> v1 = { 1, 2 };
462 vector<double> v2 = { 1.1, 2.2 };
463 vector<char> v3 = { 'a', 'b' };
464 vector<string> v4 = { "x", "y" };
465 vector<long> v5 = { 100L, 200L };
466
467 auto result = tzip_std(v1, v2, v3, v4, v5);
468
469 EXPECT_EQ(result.size(), 2);
470 EXPECT_EQ(get<0>(result[0]), 1);
471 EXPECT_DOUBLE_EQ(get<1>(result[0]), 1.1);
472 EXPECT_EQ(get<2>(result[0]), 'a');
473 EXPECT_EQ(get<3>(result[0]), "x");
474 EXPECT_EQ(get<4>(result[0]), 100L);
475}
476
478{
479 vector<int> v1 = { 1, 2, 3 };
480 vector<double> v2 = { 1.1, 2.2, 3.3 };
481 vector<string> v3 = { "a", "b", "c" };
482
483 auto a = tzip_std(v1, v2, v3);
484 auto b = std_zip_n(v1, v2, v3);
485 EXPECT_EQ(a, b);
486}
487
489{
490 vector<int> v1 = { 1, 2 };
491 vector<int> v2 = { 10, 20, 30 };
492 vector<int> v3 = { 100, 200, 300, 400 };
493
494 auto result = std_zip_n(v1, v2, v3);
495 EXPECT_EQ(result.size(), 2);
496 EXPECT_EQ(get<0>(result[0]), 1);
497 EXPECT_EQ(get<1>(result[0]), 10);
498 EXPECT_EQ(get<2>(result[0]), 100);
499}
500
501// Test tzip_std with unequal lengths
503{
504 vector<int> v1 = { 1, 2 };
505 vector<int> v2 = { 10, 20, 30 };
506 vector<int> v3 = { 100, 200, 300, 400 };
507 vector<int> v4 = { 1000, 2000, 3000, 4000, 5000 };
508
509 auto result = tzip_std(v1, v2, v3, v4);
510
511 EXPECT_EQ(result.size(), 2); // Stops at shortest
512}
513
514// Test single container zip
516{
517 DynList<int> l = { 1, 2, 3, 4, 5 };
518
519 auto it = zip_it(l);
520 size_t count = 0;
521 for (; it.has_curr(); it.next_ne(), ++count)
522 {
523 auto t = it.get_curr_ne();
524 EXPECT_EQ(get<0>(t), static_cast<int>(count + 1));
525 }
526 EXPECT_EQ(count, 5);
527}
528
529// Test equal_length with single container
535
536// Test get_curr_list with homogeneous containers - verify correct order
538{
539 DynList<int> a = { 1, 2, 3 };
540 DynList<int> b = { 10, 20, 30 };
541 DynList<int> c = { 100, 200, 300 };
542
543 auto it = zip_it(a, b, c);
544
545 ASSERT_TRUE(it.has_curr());
546 auto curr_list = it.get_curr_list();
547
548 // Should have 3 elements in order: 1 (from a), 10 (from b), 100 (from c)
550 auto list_it = curr_list.get_it();
551 EXPECT_EQ(list_it.get_curr(), 1); // First element from first container
552 list_it.next();
553 EXPECT_EQ(list_it.get_curr(), 10); // Second element from second container
554 list_it.next();
555 EXPECT_EQ(list_it.get_curr(), 100); // Third element from third container
556
557 // Advance and check second position
558 it.next();
559 curr_list = it.get_curr_list();
561 EXPECT_EQ(list_it.get_curr(), 2);
562 list_it.next();
563 EXPECT_EQ(list_it.get_curr(), 20);
564 list_it.next();
565 EXPECT_EQ(list_it.get_curr(), 200);
566}
567
568// Test zip_cmp with different predicates
570{
571 DynList<int> ascending1 = { 1, 2, 3, 4, 5 };
572 DynList<int> ascending2 = { 2, 3, 4, 5, 6 };
573
574 // All elements in ascending1 should be less than corresponding elements in ascending2
575 EXPECT_TRUE(zip_cmp([] (auto & a, auto & b) { return a < b; },
577}
578
579// Test with empty containers
581{
583
585 EXPECT_TRUE(zip_traverse([] (auto) { return true; }, empty1, empty2));
586 EXPECT_TRUE(zip_all([] (auto) { return true; }, empty1, empty2));
587 EXPECT_FALSE(zip_exists([] (auto) { return true; }, empty1, empty2));
588
589 auto mapped = zip_maps<int>([] (auto t) { return get<0>(t); }, empty1, empty2);
591
592 auto filtered = zip_filter([] (auto) { return true; }, empty1, empty2);
594
595 auto zipped = t_zip(empty1, empty2);
597}
598
599// Test noexcept guarantees for _ne methods
601{
602 auto it = zip_it(l1, l2);
603
604 // These should be noexcept
605 EXPECT_TRUE(noexcept(it.get_curr_ne()));
606 EXPECT_TRUE(noexcept(it.next_ne()));
607
608 auto enum_it = enum_zip_it(l1, l2);
609 EXPECT_TRUE(noexcept(enum_it.get_curr_ne()));
610 EXPECT_TRUE(noexcept(enum_it.next_ne()));
611}
612
613// Stress test with larger containers
615{
616 const size_t SIZE = 1000;
617 DynList<int> l1 = range<int>(0, SIZE - 1);
618 DynList<int> l2 = range<int>(0, SIZE - 1);
619
620 EXPECT_TRUE(equal_length(l1, l2));
621
622 auto sum = zip_foldl(0, [] (auto acc, auto t)
623 { return acc + get<0>(t) + get<1>(t); }, l1, l2);
624
625 // Sum of 0..999 is 499500, and we have two lists
626 EXPECT_EQ(sum, 2 * (SIZE * (SIZE - 1) / 2));
627
628 auto zipped = t_zip(l1, l2);
630}
631
632// Test zip_find_index edge cases
634{
635 // Should return N (size of containers) if not found
636 auto idx = zip_find_index([] (auto t) { return get<0>(t) == 999; }, l1, l2);
637 EXPECT_EQ(idx, N);
638}
639
641{
642 auto idx = zip_find_index([] (auto t) { return get<0>(t) == 0; }, l1, l2);
643 EXPECT_EQ(idx, 0);
644}
645
646// Test completed() behavior
648{
649 auto it = zip_it(l1, l2, l3);
650
651 // Iterate to the end
652 while (it.has_curr())
653 it.next_ne();
654
655 // All containers same length, so completed() should be true
656 EXPECT_TRUE(it.completed());
657}
658
660{
661 auto it = zip_it(l1, l2, l3);
662
663 // Iterate to the end (stops at shortest)
664 while (it.has_curr())
665 it.next_ne();
666
667 // l2 is shorter, so not all are completed
668 EXPECT_FALSE(it.completed());
669}
670
671// Test zip with 5 different container types and heterogeneous element types
673{
674 // 5 distinct container types with different element types
675 DynList<int> c1 = { 1, 2, 3 };
676 DynSetTree<double> c2 = { 1.1, 2.2, 3.3 };
677 DynArray<string> c3 = { "a", "b", "c" };
678 Array<char> c4 = { 'x', 'y', 'z' }; // Use initializer list
679 DynList<long> c5 = { 100L, 200L, 300L };
680
681 // Iterate over all 5 containers simultaneously
682 size_t count = 0;
683 for (auto it = zip_it(c1, c2, c3, c4, c5); it.has_curr(); it.next_ne(), ++count)
684 {
685 auto t = it.get_curr_ne();
686 // t is tuple<int, double, string, char, long>
687 EXPECT_EQ(get<0>(t), static_cast<int>(count + 1));
688 EXPECT_DOUBLE_EQ(get<1>(t), (count + 1) * 1.1);
689 EXPECT_EQ(get<2>(t), string(1, 'a' + count));
690 EXPECT_EQ(get<3>(t), 'x' + count);
691 EXPECT_EQ(get<4>(t), (count + 1) * 100L);
692 }
693 EXPECT_EQ(count, 3);
694
695 // Verify equal_length works with 5 containers
697
698 // Test zip_for_each with 5 containers
699 count = 0;
700 zip_for_each([&count](auto t) {
701 ++count;
702 // Verify tuple has correct types
703 static_assert(std::is_same_v<std::decay_t<decltype(get<0>(t))>, int>);
704 static_assert(std::is_same_v<std::decay_t<decltype(get<1>(t))>, double>);
705 static_assert(std::is_same_v<std::decay_t<decltype(get<2>(t))>, string>);
706 static_assert(std::is_same_v<std::decay_t<decltype(get<3>(t))>, char>);
707 static_assert(std::is_same_v<std::decay_t<decltype(get<4>(t))>, long>);
708 }, c1, c2, c3, c4, c5);
709 EXPECT_EQ(count, 3);
710}
711
712// Test with Array container specifically
714{
715 Array<int> arr1 = { 10, 20, 30, 40 }; // Use initializer list
716 Array<string> arr2 = { "ten", "twenty", "thirty", "forty" };
717 DynList<double> list = { 1.0, 2.0, 3.0, 4.0 };
718
719 size_t count = 0;
720 for (auto it = zip_it(arr1, arr2, list); it.has_curr(); it.next_ne(), ++count)
721 {
722 auto t = it.get_curr_ne();
723 EXPECT_EQ(get<0>(t), (count + 1) * 10);
724 EXPECT_EQ(get<2>(t), count + 1.0);
725 }
726 EXPECT_EQ(count, 4);
727
729}
730
731// Test with hash table containers
733{
734 // DynSetHash - hash set with linear probing
735 DynSetLhash<int> hash_set = { 10, 20, 30, 40, 50 };
736 DynList<int> list = { 1, 2, 3, 4, 5 };
737
738 // Both have 5 elements
739 EXPECT_EQ(hash_set.size(), 5);
740 EXPECT_EQ(list.size(), 5);
742
743 // Iterate and count (hash order is not deterministic, so just check count)
744 size_t count = 0;
745 for (auto it = zip_it(hash_set, list); it.has_curr(); it.next_ne(), ++count)
746 {
747 auto t = it.get_curr_ne();
748 // get<0>(t) is from hash_set (some int in {10,20,30,40,50})
749 // get<1>(t) is from list (sequential 1,2,3,4,5)
750 EXPECT_TRUE(hash_set.contains(get<0>(t)));
751 }
752 EXPECT_EQ(count, 5);
753
754 // Test with multiple hash containers
755 DynSetLhash<string> hash_strings = { "a", "b", "c" };
756 DynSetLhash<double> hash_doubles = { 1.1, 2.2, 3.3 };
757 DynList<int> indices = { 0, 1, 2 };
758
760
761 count = 0;
762 zip_for_each([&count](auto t) {
763 ++count;
764 // Verify types are correct
765 static_assert(std::is_same_v<std::decay_t<decltype(get<0>(t))>, string>);
766 static_assert(std::is_same_v<std::decay_t<decltype(get<1>(t))>, double>);
767 static_assert(std::is_same_v<std::decay_t<decltype(get<2>(t))>, int>);
769 EXPECT_EQ(count, 3);
770}
771
772// Test mixing hash containers with tree and list containers
774{
775 DynSetLhash<int> hash = { 1, 2, 3, 4 };
776 DynSetTree<int> tree = { 10, 20, 30, 40 };
777 DynList<string> list = { "a", "b", "c", "d" };
778 Array<double> arr = { 1.1, 2.2, 3.3, 4.4 };
779
780 EXPECT_TRUE(equal_length(hash, tree, list, arr));
781
782 size_t count = 0;
783 for (auto it = zip_it(hash, tree, list, arr); it.has_curr(); it.next_ne(), ++count)
784 {
785 auto t = it.get_curr_ne();
786 // Just verify we can access all elements
787 EXPECT_TRUE(hash.contains(get<0>(t)));
788 EXPECT_TRUE(tree.contains(get<1>(t)));
789 }
790 EXPECT_EQ(count, 4);
791}
792
793// ============================================================================
794// Tests for new features (issues 16, 17, 19, 20)
795// ============================================================================
796
797// ---------- Issue 16: zip_transform ----------
798
800{
801 // Transform tuples into concatenated strings
802 auto result = zip_transform([](auto t) {
803 return to_string(get<0>(t)) + "-" + to_string(get<1>(t)) + "-" + get<2>(t);
804 }, l1, l2, l3);
805
806 EXPECT_EQ(result.size(), N);
807 EXPECT_EQ(result[0], "0-0-0");
808 EXPECT_EQ(result[1], "1-1-1");
809 EXPECT_EQ(result[N-1], to_string(N-1) + "-" + to_string(N-1) + "-" + to_string(N-1));
810}
811
813{
814 // Transform to sum of elements
815 auto result = zip_transform([](auto t) {
816 return get<0>(t) + get<1>(t);
817 }, l1, l2);
818
819 EXPECT_EQ(result.size(), N);
820 for (size_t i = 0; i < N; ++i)
821 EXPECT_EQ(result[i], static_cast<int>(2 * i));
822}
823
825{
826 auto result = zip_transform_eq([](auto t) {
827 return get<0>(t) * get<1>(t);
828 }, l1, l2);
829
830 EXPECT_EQ(result.size(), N);
831 for (size_t i = 0; i < N; ++i)
832 EXPECT_EQ(result[i], static_cast<int>(i * i));
833}
834
836{
838 zip_transform_eq([](auto t) { return get<0>(t); }, l1, l2),
839 length_error
840 );
841}
842
844{
846 auto result = zip_transform([](auto t) { return get<0>(t); }, empty1, empty2);
847 EXPECT_TRUE(result.empty());
848}
849
850// ---------- Issue 17: zip_for_each_indexed ----------
851
853{
854 vector<size_t> indices;
855 vector<int> values;
856
857 zip_for_each_indexed([&](size_t idx, auto t) {
858 indices.push_back(idx);
859 values.push_back(get<0>(t));
860 }, l1, l2);
861
863 EXPECT_EQ(values.size(), N);
864
865 for (size_t i = 0; i < N; ++i)
866 {
867 EXPECT_EQ(indices[i], i);
868 EXPECT_EQ(values[i], static_cast<int>(i));
869 }
870}
871
873{
874 zip_for_each_indexed([](size_t idx, auto t) {
875 EXPECT_EQ(get<0>(t), static_cast<int>(idx));
876 EXPECT_EQ(get<1>(t), static_cast<int>(idx));
877 EXPECT_EQ(get<2>(t), to_string(idx));
878 }, l1, l2, l3);
879}
880
882{
883 size_t count = 0;
885 zip_for_each_indexed_eq([&count](size_t idx, [[maybe_unused]] auto t) {
886 EXPECT_EQ(idx, count);
887 ++count;
888 }, l1, l2, l3)
889 );
890 EXPECT_EQ(count, N);
891}
892
894{
896 zip_for_each_indexed_eq([](size_t, auto) {}, l1, l2),
897 length_error
898 );
899}
900
902{
904 size_t count = 0;
905 zip_for_each_indexed([&count](size_t, auto) { ++count; }, empty1, empty2);
906 EXPECT_EQ(count, 0);
907}
908
909// ---------- Issue 19: zip_take / zip_drop ----------
910
912{
913 auto result = zip_take(3, l1, l2, l3);
914
915 EXPECT_EQ(result.size(), 3);
916
917 size_t i = 0;
918 for (auto it = result.get_it(); it.has_curr(); it.next_ne(), ++i)
919 {
920 auto t = it.get_curr();
921 EXPECT_EQ(get<0>(t), static_cast<int>(i));
922 EXPECT_EQ(get<1>(t), static_cast<int>(i));
923 EXPECT_EQ(get<2>(t), to_string(i));
924 }
925}
926
928{
929 auto result = zip_take(100, l1, l2); // Request more than N elements
930 EXPECT_EQ(result.size(), N); // Should only get N
931}
932
934{
935 auto result = zip_take(0, l1, l2);
936 EXPECT_TRUE(result.is_empty());
937}
938
940{
941 auto result = zip_drop(2, l1, l2, l3);
942
943 EXPECT_EQ(result.size(), N - 2);
944
945 size_t i = 2; // Start from index 2
946 for (auto it = result.get_it(); it.has_curr(); it.next_ne(), ++i)
947 {
948 auto t = it.get_curr();
949 EXPECT_EQ(get<0>(t), static_cast<int>(i));
950 EXPECT_EQ(get<1>(t), static_cast<int>(i));
951 EXPECT_EQ(get<2>(t), to_string(i));
952 }
953}
954
956{
957 auto result = zip_drop(N, l1, l2);
958 EXPECT_TRUE(result.is_empty());
959}
960
962{
963 auto result = zip_drop(100, l1, l2);
964 EXPECT_TRUE(result.is_empty());
965}
966
968{
969 auto result = zip_drop(0, l1, l2);
970 EXPECT_EQ(result.size(), N);
971}
972
974{
975 // Take while first element < 3
976 auto result = zip_take_while([](auto t) { return get<0>(t) < 3; }, l1, l2, l3);
977
978 EXPECT_EQ(result.size(), 3); // Elements 0, 1, 2
979
980 size_t i = 0;
981 for (auto it = result.get_it(); it.has_curr(); it.next_ne(), ++i)
982 {
983 auto t = it.get_curr();
984 EXPECT_EQ(get<0>(t), static_cast<int>(i));
985 EXPECT_LT(get<0>(t), 3);
986 }
987}
988
990{
991 // Predicate immediately false
992 auto result = zip_take_while([](auto t) { return get<0>(t) < 0; }, l1, l2);
993 EXPECT_TRUE(result.is_empty());
994}
995
997{
998 // Predicate always true
999 auto result = zip_take_while([](auto t) { return get<0>(t) < 100; }, l1, l2);
1000 EXPECT_EQ(result.size(), N);
1001}
1002
1004{
1005 // Drop while first element < 3, then collect the rest
1006 auto result = zip_drop_while([](auto t) { return get<0>(t) < 3; }, l1, l2, l3);
1007
1008 EXPECT_EQ(result.size(), N - 3); // Elements 3, 4
1009
1010 size_t i = 3;
1011 for (auto it = result.get_it(); it.has_curr(); it.next_ne(), ++i)
1012 {
1013 auto t = it.get_curr();
1014 EXPECT_EQ(get<0>(t), static_cast<int>(i));
1015 }
1016}
1017
1019{
1020 // Predicate immediately false - drop nothing
1021 auto result = zip_drop_while([](auto t) { return get<0>(t) < 0; }, l1, l2);
1022 EXPECT_EQ(result.size(), N);
1023}
1024
1026{
1027 // Predicate always true - drop all
1028 auto result = zip_drop_while([](auto t) { return get<0>(t) < 100; }, l1, l2);
1029 EXPECT_TRUE(result.is_empty());
1030}
1031
1033{
1035
1036 EXPECT_TRUE(zip_take(5, empty1, empty2).is_empty());
1037 EXPECT_TRUE(zip_drop(5, empty1, empty2).is_empty());
1038 EXPECT_TRUE(zip_take_while([](auto) { return true; }, empty1, empty2).is_empty());
1039 EXPECT_TRUE(zip_drop_while([](auto) { return true; }, empty1, empty2).is_empty());
1040}
1041
1042// ---------- Issue 20: Tuple helpers with index_sequence ----------
1043
1045{
1046 auto t = make_tuple(1, 2.5, string("hello"));
1047
1049 for_each_in_tuple([&collected](auto &elem) {
1050 ostringstream oss;
1051 oss << elem;
1052 collected.push_back(oss.str());
1053 }, t);
1054
1055 EXPECT_EQ(collected.size(), 3);
1056 EXPECT_EQ(collected[0], "1");
1057 EXPECT_EQ(collected[1], "2.5");
1058 EXPECT_EQ(collected[2], "hello");
1059}
1060
1062{
1063 auto t = make_tuple(1, 2, 3);
1064
1065 for_each_in_tuple([](auto &elem) { elem *= 2; }, t);
1066
1067 EXPECT_EQ(get<0>(t), 2);
1068 EXPECT_EQ(get<1>(t), 4);
1069 EXPECT_EQ(get<2>(t), 6);
1070}
1071
1073{
1074 auto t = make_tuple();
1075 size_t count = 0;
1076 for_each_in_tuple([&count](auto &) { ++count; }, t);
1077 EXPECT_EQ(count, 0);
1078}
1079
1081{
1082 auto t = make_tuple(1, 2, 3);
1083
1084 auto result = transform_tuple([](auto x) { return x * 10; }, t);
1085
1086 EXPECT_EQ(get<0>(result), 10);
1087 EXPECT_EQ(get<1>(result), 20);
1088 EXPECT_EQ(get<2>(result), 30);
1089}
1090
1092{
1093 auto t = make_tuple(1, 2, 3);
1094
1095 // Transform int -> string
1096 auto result = transform_tuple([](auto x) { return to_string(x); }, t);
1097
1098 static_assert(is_same_v<decay_t<decltype(get<0>(result))>, string>);
1099 EXPECT_EQ(get<0>(result), "1");
1100 EXPECT_EQ(get<1>(result), "2");
1101 EXPECT_EQ(get<2>(result), "3");
1102}
1103
1105{
1106 auto t = make_tuple(1, 2.5, string("hi"));
1107
1108 // Double each value (works differently for each type)
1109 auto result = transform_tuple([](auto x) {
1110 if constexpr (is_same_v<decay_t<decltype(x)>, string>)
1111 return x + x;
1112 else
1113 return x * 2;
1114 }, t);
1115
1116 EXPECT_EQ(get<0>(result), 2);
1117 EXPECT_DOUBLE_EQ(get<1>(result), 5.0);
1118 EXPECT_EQ(get<2>(result), "hihi");
1119}
1120
1122{
1123 auto t = make_tuple(2, 4, 6, 8);
1124
1125 bool result = all_of_tuple([](auto x) { return x % 2 == 0; }, t);
1126 EXPECT_TRUE(result);
1127}
1128
1130{
1131 auto t = make_tuple(2, 4, 5, 8); // 5 is odd
1132
1133 bool result = all_of_tuple([](auto x) { return x % 2 == 0; }, t);
1134 EXPECT_FALSE(result);
1135}
1136
1138{
1139 auto t = make_tuple();
1140 // Empty tuple should return true (vacuous truth)
1141 bool result = all_of_tuple([](auto) { return false; }, t);
1142 EXPECT_TRUE(result);
1143}
1144
1146{
1147 auto t = make_tuple(1, 3, 4, 7); // 4 is even
1148
1149 bool result = any_of_tuple([](auto x) { return x % 2 == 0; }, t);
1150 EXPECT_TRUE(result);
1151}
1152
1154{
1155 auto t = make_tuple(1, 3, 5, 7); // All odd
1156
1157 bool result = any_of_tuple([](auto x) { return x % 2 == 0; }, t);
1158 EXPECT_FALSE(result);
1159}
1160
1162{
1163 auto t = make_tuple();
1164 // Empty tuple should return false
1165 bool result = any_of_tuple([](auto) { return true; }, t);
1166 EXPECT_FALSE(result);
1167}
1168
1170{
1171 auto t = make_tuple(10, 20, 30, 40, 50);
1172
1173 // All > 0
1174 EXPECT_TRUE(all_of_tuple([](auto x) { return x > 0; }, t));
1175
1176 // Any > 45
1177 EXPECT_TRUE(any_of_tuple([](auto x) { return x > 45; }, t));
1178
1179 // None > 100
1180 EXPECT_FALSE(any_of_tuple([](auto x) { return x > 100; }, t));
1181
1182 // Not all > 25
1183 EXPECT_FALSE(all_of_tuple([](auto x) { return x > 25; }, t));
1184}
1185
1186// Stress test for new features
1188{
1189 const size_t SIZE = 1000;
1190 DynList<int> l1 = range<int>(0, SIZE - 1);
1191 DynList<int> l2 = range<int>(0, SIZE - 1);
1192
1193 // zip_transform
1194 auto transformed = zip_transform([](auto t) {
1195 return get<0>(t) + get<1>(t);
1196 }, l1, l2);
1198 for (size_t i = 0; i < SIZE; ++i)
1199 EXPECT_EQ(transformed[i], static_cast<int>(2 * i));
1200
1201 // zip_for_each_indexed
1202 size_t sum_indices = 0;
1203 zip_for_each_indexed([&sum_indices](size_t idx, auto) {
1204 sum_indices += idx;
1205 }, l1, l2);
1206 EXPECT_EQ(sum_indices, SIZE * (SIZE - 1) / 2);
1207
1208 // zip_take
1209 auto taken = zip_take(100, l1, l2);
1210 EXPECT_EQ(taken.size(), 100);
1211
1212 // zip_drop
1213 auto dropped = zip_drop(900, l1, l2);
1214 EXPECT_EQ(dropped.size(), 100);
1215
1216 // zip_take_while
1217 auto taken_while = zip_take_while([](auto t) { return get<0>(t) < 500; }, l1, l2);
1218 EXPECT_EQ(taken_while.size(), 500);
1219
1220 // zip_drop_while
1221 auto dropped_while = zip_drop_while([](auto t) { return get<0>(t) < 500; }, l1, l2);
1223}
1224
1225// ============================================================================
1226// Additional edge case tests
1227// ============================================================================
1228
1229// Test that original containers are not modified by zip operations
1231{
1232 DynList<int> original1 = { 1, 2, 3, 4, 5 };
1233 DynList<int> original2 = { 10, 20, 30, 40, 50 };
1234
1235 // Save copies
1238
1239 // Perform various zip operations
1241 auto mapped = zip_maps<int>([](auto t) { return get<0>(t) + get<1>(t); }, original1, original2);
1242 auto filtered = zip_filter([](auto t) { return get<0>(t) > 2; }, original1, original2);
1243 zip_for_each([](auto) {}, original1, original2);
1244 [[maybe_unused]] auto folded = zip_foldl(0, [](auto acc, auto t) { return acc + get<0>(t); }, original1, original2);
1245
1246 // Verify originals unchanged
1249}
1250
1251// Test zip_cmp with empty containers
1253{
1255
1256 // All comparisons on empty containers should return true (vacuous truth)
1257 EXPECT_TRUE(zip_cmp([](auto, auto) { return true; }, empty1, empty2));
1258 EXPECT_TRUE(zip_cmp([](auto, auto) { return false; }, empty1, empty2));
1259}
1260
1261// Test zip_cmp with single element
1263{
1264 DynList<int> l1 = { 5 };
1265 DynList<int> l2 = { 5 };
1266 DynList<int> l3 = { 10 };
1267
1268 EXPECT_TRUE(zip_cmp([](auto a, auto b) { return a == b; }, l1, l2));
1269 EXPECT_FALSE(zip_cmp([](auto a, auto b) { return a == b; }, l1, l3));
1270}
1271
1272// Test ZipIterator copy semantics
1274{
1275 DynList<int> l1 = { 1, 2, 3, 4, 5 };
1276 DynList<int> l2 = { 10, 20, 30, 40, 50 };
1277
1278 auto it1 = zip_it(l1, l2);
1279 it1.next_ne();
1280 it1.next_ne(); // Now at position 2
1281
1282 auto it2 = it1; // Copy
1283
1284 // Both should be at same position
1285 EXPECT_EQ(get<0>(it1.get_curr_ne()), get<0>(it2.get_curr_ne()));
1286 EXPECT_EQ(get<1>(it1.get_curr_ne()), get<1>(it2.get_curr_ne()));
1287
1288 // Advance original, copy should stay
1289 it1.next_ne();
1290 EXPECT_NE(get<0>(it1.get_curr_ne()), get<0>(it2.get_curr_ne()));
1291}
1292
1293// Test single container with all functional operations
1295{
1296 DynList<int> l = { 1, 2, 3, 4, 5 };
1297
1298 // zip_traverse
1299 EXPECT_TRUE(zip_traverse([](auto t) { return get<0>(t) <= 5; }, l));
1300 EXPECT_FALSE(zip_traverse([](auto t) { return get<0>(t) < 3; }, l));
1301
1302 // zip_all
1303 EXPECT_TRUE(zip_all([](auto t) { return get<0>(t) <= 5; }, l));
1304
1305 // zip_exists
1306 EXPECT_TRUE(zip_exists([](auto t) { return get<0>(t) == 3; }, l));
1307 EXPECT_FALSE(zip_exists([](auto t) { return get<0>(t) == 99; }, l));
1308
1309 // zip_find_index
1310 EXPECT_EQ(zip_find_index([](auto t) { return get<0>(t) == 3; }, l), 2);
1311 EXPECT_EQ(zip_find_index([](auto t) { return get<0>(t) == 99; }, l), 5);
1312
1313 // zip_foldl
1314 auto sum = zip_foldl(0, [](auto acc, auto t) { return acc + get<0>(t); }, l);
1315 EXPECT_EQ(sum, 15);
1316
1317 // zip_filter
1318 auto filtered = zip_filter([](auto t) { return get<0>(t) % 2 == 0; }, l);
1319 EXPECT_EQ(filtered.size(), 2); // 2 and 4
1320
1321 // zip_partition
1322 auto part = zip_partition([](auto t) { return get<0>(t) < 3; }, l);
1323 EXPECT_EQ(get<1>(part), 2); // 1, 2
1324 EXPECT_EQ(get<3>(part), 3); // 3, 4, 5
1325}
1326
1327// Test const correctness
1329{
1330 const DynList<int> cl1 = { 1, 2, 3 };
1331 const DynList<int> cl2 = { 10, 20, 30 };
1332
1333 // All operations should work with const containers
1334 auto zipped = t_zip(cl1, cl2);
1335 EXPECT_EQ(zipped.size(), 3);
1336
1338
1339 auto mapped = zip_maps<int>([](auto t) { return get<0>(t); }, cl1, cl2);
1340 EXPECT_EQ(mapped.size(), 3);
1341
1342 size_t count = 0;
1343 zip_for_each([&count](auto) { ++count; }, cl1, cl2);
1344 EXPECT_EQ(count, 3);
1345}
1346
1347// Test very large number of containers (up to 6)
1349{
1350 DynList<int> c1 = { 1, 2 };
1351 DynList<int> c2 = { 10, 20 };
1352 DynList<int> c3 = { 100, 200 };
1353 DynList<int> c4 = { 1000, 2000 };
1354 DynList<int> c5 = { 10000, 20000 };
1355 DynList<int> c6 = { 100000, 200000 };
1356
1357 size_t count = 0;
1358 for (auto it = zip_it(c1, c2, c3, c4, c5, c6); it.has_curr(); it.next_ne())
1359 {
1360 auto t = it.get_curr_ne();
1361 if (count == 0)
1362 {
1363 EXPECT_EQ(get<0>(t), 1);
1364 EXPECT_EQ(get<1>(t), 10);
1365 EXPECT_EQ(get<2>(t), 100);
1366 EXPECT_EQ(get<3>(t), 1000);
1367 EXPECT_EQ(get<4>(t), 10000);
1368 EXPECT_EQ(get<5>(t), 100000);
1369 }
1370 ++count;
1371 }
1372 EXPECT_EQ(count, 2);
1373}
1374
1375// Test zip operations with rvalue containers (temporary containers)
1377{
1378 // This tests that zip can work with inline-constructed containers
1379 // when the containers are captured by const ref
1380
1381 auto sum = zip_foldl(0, [](auto acc, auto t) { return acc + get<0>(t) + get<1>(t); },
1382 DynList<int>{1, 2, 3}, DynList<int>{10, 20, 30});
1383 EXPECT_EQ(sum, 66); // (1+10) + (2+20) + (3+30) = 66
1384}
1385
1386// Test t_zip with very short containers
1388{
1389 DynList<int> l1 = { 42 };
1390 DynList<string> l2 = { "hello" };
1391
1392 auto zipped = t_zip(l1, l2);
1393 EXPECT_EQ(zipped.size(), 1);
1394
1395 auto t = zipped.get_first();
1396 EXPECT_EQ(get<0>(t), 42);
1397 EXPECT_EQ(get<1>(t), "hello");
1398}
1399
1400// Test enum_zip with single container
1402{
1403 DynList<string> l = { "a", "b", "c" };
1404
1405 size_t count = 0;
1406 for (auto it = enum_zip_it(l); it.has_curr(); it.next_ne(), ++count)
1407 {
1408 auto t = it.get_curr_ne();
1409 EXPECT_EQ(get<1>(t), count); // Index is second element for single container
1410 EXPECT_EQ(get<0>(t), string(1, 'a' + count));
1411 }
1412 EXPECT_EQ(count, 3);
1413}
1414
1415// Test t_unzip with single-element tuples
1417{
1419
1420 auto result = t_unzip(l);
1421 EXPECT_EQ(get<0>(result), DynList<int>({1, 2, 3}));
1422}
1423
1424// Test t_unzip with empty list
1426{
1428
1429 auto result = t_unzip(l);
1430 EXPECT_TRUE(get<0>(result).is_empty());
1431 EXPECT_TRUE(get<1>(result).is_empty());
1432}
1433
1434// Test zip_cmp with 4 containers
1436{
1437 DynList<int> l1 = { 1, 2, 3 };
1438 DynList<int> l2 = { 1, 2, 3 };
1439 DynList<int> l3 = { 1, 2, 3 };
1440 DynList<int> l4 = { 1, 2, 3 };
1441
1442 EXPECT_TRUE(zip_cmp([](auto a, auto b) { return a == b; }, l1, l2, l3, l4));
1443
1444 DynList<int> l5 = { 1, 2, 4 }; // Different at position 2
1445 EXPECT_FALSE(zip_cmp([](auto a, auto b) { return a == b; }, l1, l2, l3, l5));
1446}
1447
1448// Test that next() throws on empty after exhaustion
1450{
1451 DynList<int> l1 = { 1 };
1452 DynList<int> l2 = { 10 };
1453
1454 auto it = zip_it(l1, l2);
1455 EXPECT_TRUE(it.has_curr());
1456 it.next();
1457 EXPECT_FALSE(it.has_curr());
1458 EXPECT_THROW(it.next(), std::overflow_error);
1459}
1460
1461// Test that get_curr() throws when not has_curr
1463{
1464 DynList<int> l1 = { 1 };
1465 DynList<int> l2 = { 10 };
1466
1467 auto it = zip_it(l1, l2);
1468 it.next();
1469 EXPECT_FALSE(it.has_curr());
1470 EXPECT_THROW(it.get_curr(), std::overflow_error);
1471}
1472
1473// ============================================================================
1474// Tests for new functions: zip_none, zip_count, zip_length, zip_find_first, etc.
1475// ============================================================================
1476
1477// ============================================================================
1478// Tests for zip_all_short, zip_forall, zip_forall_short, zip_any
1479// ============================================================================
1480
1482{
1483 EXPECT_TRUE(zip_all_short([](auto t) { return get<0>(t) >= 0; }, l1, l2));
1484}
1485
1487{
1488 EXPECT_FALSE(zip_all_short([](auto t) { return get<0>(t) < 3; }, l1, l2));
1489}
1490
1492{
1493 // zip_all_short should work on unequal lengths (uses minimum)
1494 // All elements in the intersection satisfy x >= 0
1495 EXPECT_TRUE(zip_all_short([](auto t) { return get<0>(t) >= 0; }, l1, l2));
1496}
1497
1499{
1500 // zip_all returns false on unequal lengths (even if predicate satisfied)
1501 EXPECT_FALSE(zip_all([](auto t) { return get<0>(t) >= 0; }, l1, l2));
1502
1503 // zip_all_short returns true (doesn't check lengths)
1504 EXPECT_TRUE(zip_all_short([](auto t) { return get<0>(t) >= 0; }, l1, l2));
1505}
1506
1508{
1510 // Vacuously true
1511 EXPECT_TRUE(zip_all_short([](auto) { return false; }, e1, e2));
1512}
1513
1515{
1516 // zip_forall is alias for zip_all
1517 EXPECT_EQ(
1518 zip_forall([](auto t) { return get<0>(t) >= 0; }, l1, l2),
1519 zip_all([](auto t) { return get<0>(t) >= 0; }, l1, l2)
1520 );
1521}
1522
1524{
1525 // zip_forall_short is alias for zip_all_short
1526 EXPECT_EQ(
1527 zip_forall_short([](auto t) { return get<0>(t) >= 0; }, l1, l2),
1528 zip_all_short([](auto t) { return get<0>(t) >= 0; }, l1, l2)
1529 );
1530}
1531
1533{
1534 // zip_any is alias for zip_exists
1535 EXPECT_EQ(
1536 zip_any([](auto t) { return get<0>(t) == 3; }, l1, l2),
1537 zip_exists([](auto t) { return get<0>(t) == 3; }, l1, l2)
1538 );
1539}
1540
1542{
1543 EXPECT_TRUE(zip_any([](auto t) { return get<0>(t) == 3; }, l1, l2));
1544}
1545
1547{
1548 EXPECT_FALSE(zip_any([](auto t) { return get<0>(t) == 99; }, l1, l2));
1549}
1550
1552{
1554 // No elements, so any is false
1555 EXPECT_FALSE(zip_any([](auto) { return true; }, e1, e2));
1556}
1557
1559{
1560 // No element > 100
1561 EXPECT_TRUE(zip_none([](auto t) { return get<0>(t) > 100; }, l1, l2));
1562}
1563
1565{
1566 // Some elements are >= 0
1567 EXPECT_FALSE(zip_none([](auto t) { return get<0>(t) >= 0; }, l1, l2));
1568}
1569
1571{
1573 // Empty = vacuously true
1574 EXPECT_TRUE(zip_none([](auto) { return true; }, e1, e2));
1575}
1576
1578{
1579 // Count all elements (all satisfy x >= 0)
1580 EXPECT_EQ(zip_count([](auto t) { return get<0>(t) >= 0; }, l1, l2), N);
1581}
1582
1584{
1585 // Count elements where first < 3
1586 EXPECT_EQ(zip_count([](auto t) { return get<0>(t) < 3; }, l1, l2), 3u);
1587}
1588
1590{
1591 // Count elements > 100 (none)
1592 EXPECT_EQ(zip_count([](auto t) { return get<0>(t) > 100; }, l1, l2), 0u);
1593}
1594
1596{
1598 EXPECT_EQ(zip_count([](auto) { return true; }, e1, e2), 0u);
1599}
1600
1602{
1603 EXPECT_EQ(zip_length(l1, l2, l3), N);
1604}
1605
1607{
1608 // l2 has only 4 elements, l1 and l3 have 5
1609 EXPECT_EQ(zip_length(l1, l2, l3), 4u);
1610}
1611
1617
1619{
1620 DynList<int> l = { 1, 2, 3, 4, 5 };
1621 EXPECT_EQ(zip_length(l), 5u);
1622}
1623
1625{
1626 auto [t, found] = zip_find_first([](auto t) { return get<0>(t) == 3; }, l1, l2, l3);
1627
1629 EXPECT_EQ(get<0>(t), 3);
1630 EXPECT_EQ(get<1>(t), 3);
1631 EXPECT_EQ(get<2>(t), "3");
1632}
1633
1635{
1636 auto [t, found] = zip_find_first([](auto t) { return get<0>(t) == 99; }, l1, l2);
1637
1639}
1640
1642{
1643 // Multiple elements satisfy x >= 2, should return the first (index 2)
1644 auto [t, found] = zip_find_first([](auto t) { return get<0>(t) >= 2; }, l1, l2);
1645
1647 EXPECT_EQ(get<0>(t), 2); // First match
1648}
1649
1651{
1653 auto [t, found] = zip_find_first([](auto) { return true; }, e1, e2);
1655}
1656
1658{
1659 // Find last element where x < 4
1660 auto [t, found] = zip_find_last([](auto t) { return get<0>(t) < 4; }, l1, l2, l3);
1661
1663 EXPECT_EQ(get<0>(t), 3); // Last element < 4 is 3
1664}
1665
1667{
1668 auto [t, found] = zip_find_last([](auto t) { return get<0>(t) > 100; }, l1, l2);
1669
1671}
1672
1674{
1675 // All elements satisfy x >= 0, should return the last (index N-1)
1676 auto [t, found] = zip_find_last([](auto t) { return get<0>(t) >= 0; }, l1, l2);
1677
1679 EXPECT_EQ(get<0>(t), static_cast<int>(N - 1));
1680}
1681
1683{
1685 auto [t, found] = zip_find_last([](auto) { return true; }, e1, e2);
1687}
1688
1690{
1691 auto [t, found] = zip_nth(2, l1, l2, l3);
1692
1694 EXPECT_EQ(get<0>(t), 2);
1695 EXPECT_EQ(get<1>(t), 2);
1696 EXPECT_EQ(get<2>(t), "2");
1697}
1698
1700{
1701 auto [t, found] = zip_nth(0, l1, l2);
1702
1704 EXPECT_EQ(get<0>(t), 0);
1705 EXPECT_EQ(get<1>(t), 0);
1706}
1707
1709{
1710 auto [t, found] = zip_nth(N - 1, l1, l2);
1711
1713 EXPECT_EQ(get<0>(t), static_cast<int>(N - 1));
1714}
1715
1717{
1718 auto [t, found] = zip_nth(N + 10, l1, l2);
1719
1721}
1722
1724{
1726 auto [t, found] = zip_nth(0, e1, e2);
1728}
1729
1731{
1732 auto [t, found] = zip_first(l1, l2, l3);
1733
1735 EXPECT_EQ(get<0>(t), 0);
1736 EXPECT_EQ(get<1>(t), 0);
1737 EXPECT_EQ(get<2>(t), "0");
1738}
1739
1741{
1743 auto [t, found] = zip_first(e1, e2);
1745}
1746
1747// Test Tuple_Type alias
1749{
1751 using ExpectedType = std::tuple<int, int, string>;
1752
1753 static_assert(std::is_same_v<ZipIt::Tuple_Type, ExpectedType>,
1754 "Tuple_Type should be tuple<int, int, string>");
1755
1756 // Verify we can use it to declare variables
1757 ZipIt::Tuple_Type t = std::make_tuple(1, 2, "test");
1758 EXPECT_EQ(get<0>(t), 1);
1759 EXPECT_EQ(get<1>(t), 2);
1760 EXPECT_EQ(get<2>(t), "test");
1761}
1762
1763// Test Item_Type alias
1765{
1767 static_assert(std::is_same_v<ZipIt::Item_Type, int>,
1768 "Item_Type should be int for single container");
1769}
1770
1771// ============================================================================
1772// Tests for zip_maps_eq, zip_maps_if_eq, zip_foldl_eq, zip_map, zip_map_eq
1773// ============================================================================
1774
1776{
1777 auto result = zip_maps_eq<string>([](auto t) {
1778 return to_string(get<0>(t)) + "-" + to_string(get<1>(t));
1779 }, l1, l2);
1780
1781 EXPECT_EQ(result.size(), N);
1782 EXPECT_EQ(result.get_first(), "0-0");
1783}
1784
1786{
1788 zip_maps_eq<int>([](auto t) { return get<0>(t); }, l1, l2),
1789 length_error
1790 );
1791}
1792
1794{
1795 // Map only elements where first > 1
1796 auto result = zip_maps_if_eq<int>(
1797 [](auto t) { return get<0>(t) > 1; },
1798 [](auto t) { return get<0>(t) * 10; },
1799 l1, l2
1800 );
1801
1802 EXPECT_EQ(result.size(), N - 2); // 2, 3, 4 -> 3 elements
1803 EXPECT_EQ(result.get_first(), 20);
1804}
1805
1807{
1810 [](auto) { return true; },
1811 [](auto t) { return get<0>(t); },
1812 l1, l2
1813 ),
1814 length_error
1815 );
1816}
1817
1819{
1820 auto sum = zip_foldl_eq(0, [](auto acc, auto t) {
1821 return acc + get<0>(t) + get<1>(t);
1822 }, l1, l2);
1823
1824 EXPECT_EQ(sum, static_cast<int>(N * (N - 1))); // 2 * sum(0..N-1)
1825}
1826
1828{
1830 (void) zip_foldl_eq(0, [](auto acc, auto t) { return acc + get<0>(t); }, l1, l2),
1831 length_error
1832 );
1833}
1834
1836{
1837 // Auto-deduce return type (string)
1838 auto result = zip_map([](auto t) {
1839 return to_string(get<0>(t)) + ":" + get<2>(t);
1840 }, l1, l2, l3);
1841
1842 EXPECT_EQ(result.size(), N);
1843 EXPECT_EQ(result.get_first(), "0:0");
1844
1845 // Verify the type is DynList<string>
1846 static_assert(std::is_same_v<decltype(result), DynList<string>>,
1847 "zip_map should return DynList<string>");
1848}
1849
1851{
1852 // Auto-deduce return type (int)
1853 auto result = zip_map([](auto t) {
1854 return get<0>(t) + get<1>(t);
1855 }, l1, l2);
1856
1857 EXPECT_EQ(result.size(), N);
1858
1859 size_t i = 0;
1860 for (auto it = result.get_it(); it.has_curr(); it.next_ne(), ++i)
1861 EXPECT_EQ(it.get_curr(), static_cast<int>(2 * i));
1862
1863 // Verify the type is DynList<int>
1864 static_assert(std::is_same_v<decltype(result), DynList<int>>,
1865 "zip_map should return DynList<int>");
1866}
1867
1869{
1870 auto result = zip_map_eq([](auto t) {
1871 return get<0>(t) * get<1>(t);
1872 }, l1, l2);
1873
1874 EXPECT_EQ(result.size(), N);
1875
1876 // 0*0, 1*1, 2*2, 3*3, 4*4
1877 size_t i = 0;
1878 for (auto it = result.get_it(); it.has_curr(); it.next_ne(), ++i)
1879 EXPECT_EQ(it.get_curr(), static_cast<int>(i * i));
1880}
1881
1883{
1885 zip_map_eq([](auto t) { return get<0>(t); }, l1, l2),
1886 length_error
1887 );
1888}
1889
1891{
1893
1894 auto result = zip_map([](auto t) { return get<0>(t); }, e1, e2);
1895 EXPECT_TRUE(result.is_empty());
1896
1897 // _eq version should not throw on empty (they're equal length)
1898 auto result_eq = zip_map_eq([](auto t) { return get<0>(t); }, e1, e2);
1900}
1901
1903{
1905
1906 auto sum = zip_foldl(100, [](auto acc, auto t) { return acc + get<0>(t); }, e1, e2);
1907 EXPECT_EQ(sum, 100); // Just returns init value
1908
1909 // _eq version should not throw on empty
1910 auto sum_eq = zip_foldl_eq(100, [](auto acc, auto t) { return acc + get<0>(t); }, e1, e2);
1911 EXPECT_EQ(sum_eq, 100);
1912}
1913
1914// ============================================================================
1915// Tests for zip_filter_eq and none_of_tuple
1916// ============================================================================
1917
1919{
1920 auto result = zip_filter_eq([](auto t) {
1921 return get<0>(t) > 2;
1922 }, l1, l2, l3);
1923
1924 // Should contain elements where first > 2: (3, 3, "3"), (4, 4, "4")
1925 EXPECT_EQ(result.size(), 2u);
1926}
1927
1929{
1931 zip_filter_eq([](auto) { return true; }, l1, l2),
1932 length_error
1933 );
1934}
1935
1937{
1939 auto result = zip_filter_eq([](auto) { return true; }, e1, e2);
1940 EXPECT_TRUE(result.is_empty());
1941}
1942
1944{
1945 auto result = zip_filter_eq([](auto t) {
1946 return get<0>(t) >= 0;
1947 }, l1, l2);
1948
1949 EXPECT_EQ(result.size(), N);
1950}
1951
1953{
1954 auto result = zip_filter_eq([](auto t) {
1955 return get<0>(t) > 100;
1956 }, l1, l2);
1957
1958 EXPECT_TRUE(result.is_empty());
1959}
1960
1962{
1963 auto t = make_tuple(2, 4, 6, 8);
1964 // All are even, so none are odd
1965 EXPECT_TRUE(none_of_tuple([](auto x) { return x % 2 != 0; }, t));
1966}
1967
1969{
1970 auto t = make_tuple(2, 3, 6, 8);
1971 // 3 is odd, so NOT none are odd
1972 EXPECT_FALSE(none_of_tuple([](auto x) { return x % 2 != 0; }, t));
1973}
1974
1976{
1977 auto t = make_tuple();
1978 // Vacuously true: no elements satisfy any predicate
1979 EXPECT_TRUE(none_of_tuple([](auto) { return true; }, t));
1980}
1981
1983{
1984 auto t = make_tuple(1, 2, 3, 4, 5);
1985
1986 auto pred = [](auto x) { return x > 10; };
1987
1988 // none_of should be complement of any_of
1990}
1991
1992// Stress test for new functions
1994{
1995 const size_t SIZE = 1000;
1996 DynList<int> l1 = range<int>(0, SIZE - 1);
1997 DynList<int> l2 = range<int>(0, SIZE - 1);
1998
1999 // zip_length
2000 EXPECT_EQ(zip_length(l1, l2), SIZE);
2001
2002 // zip_count - count even numbers
2003 EXPECT_EQ(zip_count([](auto t) { return get<0>(t) % 2 == 0; }, l1, l2), SIZE / 2);
2004
2005 // zip_none - no element > SIZE
2006 EXPECT_TRUE(zip_none([](auto t) { return get<0>(t) >= static_cast<int>(SIZE); }, l1, l2));
2007
2008 // zip_find_first
2009 auto [first, found1] = zip_find_first([](auto t) { return get<0>(t) == 500; }, l1, l2);
2011 EXPECT_EQ(get<0>(first), 500);
2012
2013 // zip_find_last
2014 auto [last, found2] = zip_find_last([](auto t) { return get<0>(t) < 100; }, l1, l2);
2016 EXPECT_EQ(get<0>(last), 99);
2017
2018 // zip_nth
2019 auto [nth, found3] = zip_nth(999, l1, l2);
2021 EXPECT_EQ(get<0>(nth), 999);
2022}
2023
2024// ============================================================================
2025// DynSkipList Specific Tests
2026// ============================================================================
2027
2029{
2030 DynSkipList<int> skip1{1, 2, 3, 4, 5};
2031 DynSkipList<string> skip2{"a", "b", "c", "d", "e"};
2032 DynList<double> list1{1.1, 2.2, 3.3, 4.4, 5.5};
2033
2034 // Test zip_it with DynSkipList
2035 size_t count = 0;
2036 for (auto it = zip_it(skip1, skip2); it.has_curr(); it.next_ne()) {
2037 auto [i, s] = it.get_curr_ne();
2038 EXPECT_EQ(i, count + 1);
2039 EXPECT_EQ(s, string(1, 'a' + count));
2040 ++count;
2041 }
2042 EXPECT_EQ(count, 5);
2043
2044 // Test zip_traverse with DynSkipList
2045 string result;
2046 zip_traverse([&result](auto t) {
2047 result += to_string(get<0>(t)) + get<1>(t);
2048 return true;
2049 }, skip1, skip2);
2050 EXPECT_EQ(result, "1a2b3c4d5e");
2051
2052 // Test zip_for_each with mixed containers
2054 zip_for_each([&mixed_results](auto t) {
2055 mixed_results.push_back(to_string(get<0>(t)) + ":" + get<1>(t) + ":" + to_string(get<2>(t)));
2056 }, skip1, skip2, list1);
2058 EXPECT_TRUE(mixed_results[0].find("1:a:1.1") != string::npos);
2059 EXPECT_TRUE(mixed_results[4].find("5:e:5.5") != string::npos);
2060
2061 // Test zip_all with DynSkipList
2062 bool all_positive = zip_all([](auto t) { return get<0>(t) > 0; }, skip1, skip2);
2064
2065 // Test zip_exists with DynSkipList
2066 bool has_three = zip_exists([](auto t) { return get<0>(t) == 3; }, skip1, skip2);
2068
2069 // Test zip_map with DynSkipList
2070 auto mapped = zip_map([](auto t) { return get<0>(t) * 10; }, skip1, skip2);
2071 EXPECT_EQ(mapped.size(), 5);
2072 EXPECT_EQ(mapped[0], 10);
2073 EXPECT_EQ(mapped[4], 50);
2074}
String manipulation utilities.
Zip iterators and functional operations for multiple containers.
TEST_F(EmptyGroup, empty)
Definition ah-zip.cc:77
Functional programming utilities for Aleph-w containers.
Simple dynamic array with automatic resizing and functional operations.
Definition tpl_array.H:138
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & get_first() const
Return the first item of the list.
Definition htlist.H:1675
Dynamic set backed by balanced binary search trees with automatic memory management.
bool contains(const Key &key) const
Dynamic ordered set implemented with a Skip List.
constexpr bool is_empty() const noexcept
Return true if list is empty.
Definition htlist.H:523
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
Aleph::DynList< __T > maps(Operation &op) const
Map the elements of the container.
Definition ah-dry.H:904
Type & nth(const size_t n)
Return the n-th item of container.
Definition ah-dry.H:267
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:190
Iterator that traverses multiple Aleph containers in lockstep.
#define TEST(name)
#define N
Definition fib.C:294
Freq_Node * pred
Predecessor node in level-order traversal.
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
void zip_for_each(Op &&op, const Cs &... cs)
Apply op to every zipped tuple.
Definition ah-zip.H:392
bool zip_none(Op &&op, const Cs &... cs)
Return true if op returns false for all tuples.
Definition ah-zip.H:524
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:429
bool zip_cmp(Cmp cmp, const Cs &... cs)
Return true if cmp(t) is true for each built tuple t.
Definition ah-zip.H:992
auto zip_find_first(Op &&op, const Cs &... cs)
Return the first tuple that satisfies predicate op.
Definition ah-zip.H:573
bool eq(const C1 &c1, const C2 &c2, Eq e=Eq())
Check equality of two containers using a predicate.
size_t zip_find_index(Op op, const Cs &... cs)
Find the first index where op returns true.
Definition ah-zip.H:1014
EnumZipIterator< Cs... > enum_zip_it(const Cs &... cs)
Alias for get_enum_zip_it.
Definition ah-zip.H:1323
size_t zip_count(Op &&op, const Cs &... cs)
Count tuples that satisfy predicate op.
Definition ah-zip.H:538
auto zip_transform_eq(Op &&op, const Cs &... cs)
Transform zipped tuples; throw if containers differ in length.
Definition ah-zip.H:1600
auto zip_drop_while(Pred &&pred, const Cs &... cs)
Skip tuples while predicate pred returns true, then return the rest.
Definition ah-zip.H:1728
auto zip_first(const Cs &... cs)
Return the first tuple from zipped containers.
Definition ah-zip.H:642
T zip_foldl(const T &init, Op op, const Cs &... cs)
Left fold (reduce) over zipped tuples.
Definition ah-zip.H:738
auto std_zip(const C1 &c1, const C2 &c2)
Build a vector of pairs from two STL containers.
Definition ah-zip.H:1498
auto tzip_std(const Cs &... cs)
Build a vector of tuples from 2 or more STL containers (variadic).
Definition ah-zip.H:1526
bool all_of_tuple(Pred &&pred, const Tuple &t)
Return true if all tuple elements satisfy pred.
Definition ah-zip.H:1896
auto transform_tuple(Op &&op, Tuple &&t)
Transform each element of a tuple, returning a new tuple.
Definition ah-zip.H:1866
auto zip_filter(Op op, const Cs &... cs)
Filter zipped tuples by predicate op.
Definition ah-zip.H:895
bool zip_any(Op &&op, const Cs &... cs)
Alias for zip_exists.
Definition ah-zip.H:508
auto zip_take_while(Pred &&pred, const Cs &... cs)
Take tuples while predicate pred returns true.
Definition ah-zip.H:1705
void for_each_in_tuple(Op &&op, Tuple &&t)
Apply op to each element of a tuple.
Definition ah-zip.H:1827
ZipIterator< Cs... > zip_it_pos(size_t pos, const Cs &... cs)
Alias for get_zip_it_pos.
Definition ah-zip.H:283
void zip_for_each_indexed(Op &&op, const Cs &... cs)
Apply op to each zipped tuple along with its index.
Definition ah-zip.H:1625
bool zip_traverse(Op &&op, const Cs &... cs)
Traverse zipped containers while op returns true.
Definition ah-zip.H:334
bool zip_forall(Op &&op, const Cs &... cs)
Alias for zip_all.
Definition ah-zip.H:466
bool equal_length(const Cs &... cs)
Return true if all containers have the same length.
Definition ah-zip.H:296
bool zip_traverse_eq(Op &&op, const Cs &... cs)
Traverse zipped containers while op returns true; verify equal lengths.
Definition ah-zip.H:352
auto zip_lists(const C &c, const Lists &... lists)
Take several container of same type and some length and builds a list of lists.
Definition ah-zip.H:1424
void zip_for_each_eq(Op &&op, const Cs &... cs)
Apply op to every zipped tuple; throw if containers differ in length.
Definition ah-zip.H:407
bool any_of_tuple(Pred &&pred, const Tuple &t)
Return true if any tuple element satisfies pred.
Definition ah-zip.H:1925
bool zip_forall_short(Op &&op, const Cs &... cs)
Alias for zip_all_short.
Definition ah-zip.H:477
auto zip_transform(Op &&op, const Cs &... cs)
Transform zipped tuples using op and return results in a vector.
Definition ah-zip.H:1578
auto zip_map_eq(Op &&op, const Cs &... cs)
Map op over zipped tuples with auto-deduced return type; throw if lengths differ.
Definition ah-zip.H:854
auto zip_take(size_t n, const Cs &... cs)
Take at most n tuples from the zipped containers.
Definition ah-zip.H:1661
Itor find(const Itor &beg, const Itor &end, const T &value)
Find the first element equal to a value.
Definition ahAlgo.H:230
bool none_of_tuple(Pred &&pred, const Tuple &t)
Return true if no tuple element satisfies pred.
Definition ah-zip.H:1954
auto t_zip(const Cs &... cs)
Materialize zipped tuples into a DynList.
Definition ah-zip.H:1112
auto zip_lists_eq(const C &c, const Lists &... lists)
Like zip_lists but throws if containers differ in length.
Definition ah-zip.H:1443
auto t_enum_zip_eq(const Cs &... cs)
Materialize enumerated zipped tuples; throw if containers differ in length.
Definition ah-zip.H:1366
auto t_unzip(const DynList< std::tuple< Ts... > > &tuples)
Unzip a list of tuples into a tuple of lists.
Definition ah-zip.H:1400
T zip_foldl_eq(const T &init, Op op, const Cs &... cs)
Left fold over zipped tuples; throw if containers differ in length.
Definition ah-zip.H:758
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
auto zip_partition(Op op, const Cs &... cs)
Partition zipped tuples by predicate op.
Definition ah-zip.H:1061
bool zip_all_short(Op &&op, const Cs &... cs)
Return true if op returns true for all tuples (without length check).
Definition ah-zip.H:451
size_t zip_length(const Cs &... cs)
Count all tuples (minimum length of containers).
Definition ah-zip.H:555
auto t_enum_zip(const Cs &... cs)
Materialize enumerated zipped tuples into a DynList.
Definition ah-zip.H:1346
auto zip_nth(size_t n, const Cs &... cs)
Return the n-th tuple from zipped containers.
Definition ah-zip.H:621
auto t_zip_eq(const Cs &... cs)
Materialize zipped tuples; throw if containers differ in length.
Definition ah-zip.H:1132
EnumZipIterator< Cs... > enum_zip_it_pos(size_t pos, const Cs &... cs)
Alias for get_enum_zip_it_pos.
Definition ah-zip.H:1331
auto std_zip_n(const Cs &... cs)
Build a vector of tuples from 2 or more STL containers (variadic).
Definition ah-zip.H:1560
auto zip_drop(size_t n, const Cs &... cs)
Skip n tuples and return the rest.
Definition ah-zip.H:1680
auto zip_filter_eq(Op op, const Cs &... cs)
Filter zipped tuples by predicate op; throw if containers differ in length.
Definition ah-zip.H:936
auto zip_map(Op &&op, const Cs &... cs)
Map op over zipped tuples with auto-deduced return type.
Definition ah-zip.H:833
bool zip_exists(Op &&op, const Cs &... cs)
Return true if op returns true for at least one tuple.
Definition ah-zip.H:493
ZipIterator< Cs... > zip_it(const Cs &... cs)
Alias for get_zip_it.
Definition ah-zip.H:275
auto zip_find_last(Op &&op, const Cs &... cs)
Return the last tuple that satisfies predicate op.
Definition ah-zip.H:594
void zip_for_each_indexed_eq(Op &&op, const Cs &... cs)
Apply op to each zipped tuple with index; throw if lengths differ.
Definition ah-zip.H:1641
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.
STL namespace.
DynSkipList< int > l4
Definition ah-zip.cc:66
DynList< int > l1
Definition ah-zip.cc:62
static constexpr size_t N
Definition ah-zip.cc:61
DynSetTree< int > l2
Definition ah-zip.cc:63
DynArray< string > l3
Definition ah-zip.cc:64
DynSkipList< int > l4
Definition ah-zip.cc:56
DynSetTree< int > l2
Definition ah-zip.cc:54
DynArray< string > l3
Definition ah-zip.cc:55
DynList< int > l1
Definition ah-zip.cc:53
Aleph::DynList< T > keys() const
Definition ah-dry.H:1516
DynSkipList< int > l4
Definition ah-zip.cc:74
DynArray< string > l3
Definition ah-zip.cc:73
DynSetTree< int > l2
Definition ah-zip.cc:72
DynList< int > l1
Definition ah-zip.cc:71
Dynamic array container with automatic resizing.
Lazy and scalable dynamic array implementation.
Dynamic set implementations based on hash tables.
Dynamic set implementations based on balanced binary search trees.
DynList< int > l