Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-zip.H
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# ifndef AH_ZIP_H
34# define AH_ZIP_H 1
35
36# include <type_traits>
37# include <tuple>
38# include <vector>
39
40# include <htlist.H>
41# include <ahFunctional.H>
42# include <tpl_dynSkipList.H>
43
67namespace Aleph
68{
69
101template <class HeadC, class ... TailC>
102class ZipIterator : public ZipIterator<TailC...>
104{
105 typename HeadC::Iterator it;
106
107 using T = std::decay_t<typename HeadC::Item_Type>;
108
109 public:
110
112 using Tuple_Type = decltype(std::tuple_cat(
113 std::declval<std::tuple<T>>(),
114 std::declval<typename ZipIterator<TailC...>::Tuple_Type>()));
115
117 using Item_Type = T;
118
126 ZipIterator(const HeadC &head, const TailC &...tail)
127 : ZipIterator<TailC...>(tail...), it(head) {}
128
131 {
132 return it.has_curr() and ZipIterator<TailC...>::has_curr();
133 }
134
141 {
142 return not it.has_curr() and ZipIterator<TailC...>::completed();
143 }
144
149 auto get_curr() const
150 {
151 std::tuple<T> curr(it.get_curr());
152 return std::tuple_cat(curr, ZipIterator<TailC...>::get_curr());
153 }
154
160 {
161 std::tuple<T> curr(it.get_curr_ne());
162 return std::tuple_cat(curr, ZipIterator<TailC...>::get_curr_ne());
163 }
164
167 {
169 l.append(it.get_curr());
171 return l;
172 }
173
175 void next()
176 {
177 it.next();
179 }
180
186 {
187 it.next_ne();
189 }
190};
191
192template <class C>
193class ZipIterator<C> : public C::Iterator
194{
195 public:
196
197 using T = std::decay_t<typename C::Item_Type>;
198
200 using Tuple_Type = std::tuple<T>;
201
203 using Item_Type = T;
204
211 ZipIterator(const C &c) : C::Iterator(c) {}
212
217 std::tuple<T> get_curr() const
218 {
219 return std::tuple<T>(C::Iterator::get_curr());
220 }
221
226 std::tuple<T> get_curr_ne() const noexcept
227 {
228 return std::tuple<T>(C::Iterator::get_curr_ne());
229 }
230
232 {
234 l.append(C::Iterator::get_curr());
235 return l;
236 }
237
239 [[nodiscard]] bool completed() const noexcept { return not this->has_curr(); }
240};
241
248template <class ... Cs>
249[[nodiscard]] inline
251{
252 return ZipIterator<Cs...>(cs...);
253}
254
262template <class ... Cs>
263[[nodiscard]] inline
264ZipIterator<Cs...> get_zip_it_pos(size_t pos, const Cs &... cs)
265{
266 ZipIterator<Cs...> ret(cs...);
267 for (size_t i = 0; i < pos; ++i)
268 ret.next();
269 return ret;
270}
271
273template <class ... Cs>
274[[nodiscard]] inline
275ZipIterator<Cs...> zip_it(const Cs &... cs)
276{
277 return get_zip_it(cs...);
278}
279
281template <class ... Cs>
282[[nodiscard]] inline
283ZipIterator<Cs...> zip_it_pos(size_t pos, const Cs &... cs)
284{
285 return get_zip_it_pos(pos, cs...);
286}
287
294template <class ... Cs>
295[[nodiscard]] inline
296bool equal_length(const Cs &... cs)
297{
298 auto it = get_zip_it(cs...);
299 for (/* already initialized */; it.has_curr(); it.next_ne())
300 /* empty */;
301
302 return it.completed();
303}
304
332template <class Op, class ... Cs>
333[[nodiscard]] inline
334bool zip_traverse(Op &&op, const Cs &... cs)
335{
336 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
337 if (not std::forward<Op>(op)(it.get_curr()))
338 return false;
339 return true;
340}
341
350template <class Op, class ... Cs>
351[[nodiscard]] inline
352bool zip_traverse_eq(Op &&op, const Cs &... cs)
353{
354 auto it = zip_it(cs...);
355 for (; it.has_curr(); it.next_ne())
356 if (not std::forward<Op>(op)(it.get_curr()))
357 return false;
358 return it.completed();
359}
360
390template <class Op, class ... Cs>
391inline
392void zip_for_each(Op &&op, const Cs &... cs)
393{
394 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
395 std::forward<Op>(op)(it.get_curr());
396}
397
405template <class Op, class ... Cs>
406inline
407void zip_for_each_eq(Op &&op, const Cs &... cs)
408{
409 auto it = get_zip_it(cs...);
410 for (; it.has_curr(); it.next_ne())
411 std::forward<Op>(op)(it.get_curr());
412
413 ah_length_error_if(not it.completed())
414 << "zip_for_each_eq() containers sizes mismatch";
415}
416
427template <class Op, class ... Cs>
428[[nodiscard]] inline
429bool zip_all(Op &&op, const Cs &... cs)
430{
431 auto it = zip_it(cs...);
432 for (; it.has_curr(); it.next_ne())
433 if (not std::forward<Op>(op)(it.get_curr()))
434 return false;
435
436 return it.completed();
437}
438
449template <class Op, class ... Cs>
450[[nodiscard]] inline
451bool zip_all_short(Op &&op, const Cs &... cs)
452{
453 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
454 if (not std::forward<Op>(op)(it.get_curr()))
455 return false;
456
457 return true;
458}
459
464template <class Op, class ... Cs>
465[[nodiscard]] inline
466bool zip_forall(Op &&op, const Cs &... cs)
467{
468 return zip_all(std::forward<Op>(op), cs...);
469}
470
475template <class Op, class ... Cs>
476[[nodiscard]] inline
477bool zip_forall_short(Op &&op, const Cs &... cs)
478{
479 return zip_all_short(std::forward<Op>(op), cs...);
480}
481
491template <class Op, class ... Cs>
492[[nodiscard]] inline
493bool zip_exists(Op &&op, const Cs &... cs)
494{
495 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
496 if (std::forward<Op>(op)(it.get_curr()))
497 return true;
498
499 return false;
500}
501
506template <class Op, class ... Cs>
507[[nodiscard]] inline
508bool zip_any(Op &&op, const Cs &... cs)
509{
510 return zip_exists(std::forward<Op>(op), cs...);
511}
512
522template <class Op, class ... Cs>
523[[nodiscard]] inline
524bool zip_none(Op &&op, const Cs &... cs)
525{
526 return not zip_exists(std::forward<Op>(op), cs...);
527}
528
536template <class Op, class ... Cs>
537[[nodiscard]] inline
538size_t zip_count(Op &&op, const Cs &... cs)
539{
540 size_t count = 0;
541 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
542 if (std::forward<Op>(op)(it.get_curr()))
543 ++count;
544 return count;
545}
546
553template <class ... Cs>
554[[nodiscard]] inline
555size_t zip_length(const Cs &... cs)
556{
557 size_t count = 0;
558 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
559 ++count;
560 return count;
561}
562
571template <class Op, class ... Cs>
572[[nodiscard]]
573auto zip_find_first(Op &&op, const Cs &... cs)
574{
575 using ZipType = typename ZipIterator<Cs...>::Tuple_Type;
576
577 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
578 if (auto t = it.get_curr(); std::forward<Op>(op)(t))
579 return std::make_pair(t, true);
580
581 return std::make_pair(ZipType{}, false);
582}
583
592template <class Op, class ... Cs>
593[[nodiscard]]
594auto zip_find_last(Op &&op, const Cs &... cs)
595{
596 using ZipType = typename ZipIterator<Cs...>::Tuple_Type;
597
598 ZipType result{};
599 bool found = false;
600
601 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
602 if (auto t = it.get_curr(); std::forward<Op>(op)(t))
603 {
604 result = t;
605 found = true;
606 }
607
608 return std::make_pair(result, found);
609}
610
619template <class ... Cs>
620[[nodiscard]]
621auto zip_nth(size_t n, const Cs &... cs)
622{
623 using ZipType = typename ZipIterator<Cs...>::Tuple_Type;
624
625 size_t i = 0;
626 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne(), ++i)
627 if (i == n)
628 return std::make_pair(it.get_curr(), true);
629
630 return std::make_pair(ZipType{}, false);
631}
632
640template <class ... Cs>
641[[nodiscard]]
642auto zip_first(const Cs &... cs)
643{
644 return zip_nth(0, cs...);
645}
646
677template <typename T, class Op, class ... Cs>
678[[nodiscard]]
679DynList<T> zip_maps(Op op, const Cs &... cs)
680{
682 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
683 ret.append(op(it.get_curr()));
684 return ret;
685}
686
696template <typename T, class Prop, class Op, class ... Cs>
697[[nodiscard]]
699{
701 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
702 if (auto t = it.get_curr(); prop(t))
703 ret.append(op(t));
704
705 return ret;
706}
707
736template <typename T, class Op, class ... Cs>
737[[nodiscard]]
738T zip_foldl(const T &init, Op op, const Cs &... cs)
739{
740 T acu = init;
741 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
742 acu = op(acu, it.get_curr());
743 return acu;
744}
745
756template <typename T, class Op, class ... Cs>
757[[nodiscard]]
758T zip_foldl_eq(const T &init, Op op, const Cs &... cs)
759{
760 T acu = init;
761 auto it = zip_it(cs...);
762 for (; it.has_curr(); it.next_ne())
763 acu = op(acu, it.get_curr());
764
765 ah_length_error_if(not it.completed())
766 << "zip_foldl_eq() containers sizes mismatch";
767
768 return acu;
769}
770
780template <typename T, class Op, class ... Cs>
781[[nodiscard]]
783{
785 auto it = zip_it(cs...);
786 for (; it.has_curr(); it.next_ne())
787 ret.append(op(it.get_curr()));
788
789 ah_length_error_if(not it.completed())
790 << "zip_maps_eq() containers sizes mismatch";
791
792 return ret;
793}
794
805template <typename T, class Prop, class Op, class ... Cs>
806[[nodiscard]]
808{
810 auto it = zip_it(cs...);
811 for (; it.has_curr(); it.next_ne())
812 if (auto t = it.get_curr(); prop(t))
813 ret.append(op(t));
814
815 ah_length_error_if(not it.completed())
816 << "zip_maps_if_eq() containers sizes mismatch";
817
818 return ret;
819}
820
831template <class Op, class ... Cs>
832[[nodiscard]]
833auto zip_map(Op &&op, const Cs &... cs)
834{
835 using ZipType = typename ZipIterator<Cs...>::Tuple_Type;
836 using ResultType = std::decay_t<decltype(std::forward<Op>(op)(std::declval<ZipType>()))>;
837
839 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
840 ret.append(std::forward<Op>(op)(it.get_curr()));
841 return ret;
842}
843
852template <class Op, class ... Cs>
853[[nodiscard]]
854auto zip_map_eq(Op &&op, const Cs &... cs)
855{
856 using ZipType = typename ZipIterator<Cs...>::Tuple_Type;
857 using ResultType = std::decay_t<decltype(std::forward<Op>(op)(std::declval<ZipType>()))>;
858
860 auto it = zip_it(cs...);
861 for (; it.has_curr(); it.next_ne())
862 ret.append(std::forward<Op>(op)(it.get_curr()));
863
864 ah_length_error_if(not it.completed())
865 << "zip_map_eq() containers sizes mismatch";
866
867 return ret;
868}
869
893template <class Op, class ... Cs>
894[[nodiscard]]
895auto zip_filter(Op op, const Cs &... cs)
896{
897 using ZipType = decltype(zip_it(cs...).get_curr());
898
900 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
901 if (auto t = it.get_curr(); op(t))
902 ret.append(t);
903
904 return ret;
905}
906
934template <class Op, class ... Cs>
935[[nodiscard]]
936auto zip_filter_eq(Op op, const Cs &... cs)
937{
938 using ZipType = decltype(zip_it(cs...).get_curr());
939
941 auto it = zip_it(cs...);
942 for (; it.has_curr(); it.next_ne())
943 if (auto t = it.get_curr(); op(t))
944 ret.append(t);
945
946 ah_length_error_if(not it.completed())
947 << "zip_filter_eq() containers sizes mismatch";
948
949 return ret;
950}
951
955namespace zip_detail
956{
962 template <class Cmp, class Tuple, size_t... Is>
963 bool compare_adjacent(Cmp &cmp, const Tuple &t, std::index_sequence<Is...>)
964 {
965 // Compare t[0] with t[1], t[1] with t[2], etc.
966 return (... and cmp(std::get<Is>(t), std::get<Is + 1>(t)));
967 }
968}
969
990template <class Cmp, class ... Cs>
991[[nodiscard]]
992bool zip_cmp(Cmp cmp, const Cs &... cs)
993{
994 constexpr size_t N = sizeof...(Cs);
995 static_assert(N >= 2, "zip_cmp requires at least 2 containers");
996
997 for (auto it = get_zip_it(cs...); it.has_curr(); it.next_ne())
998 if (auto t = it.get_curr(); not zip_detail::compare_adjacent(cmp, t, std::make_index_sequence<N - 1>{}))
999 return false;
1000
1001 return true;
1002}
1003
1012template <class Op, class ... Cs>
1013[[nodiscard]]
1014size_t zip_find_index(Op op, const Cs &... cs)
1015{
1016 size_t i = 0;
1017 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne(), ++i)
1018 if (auto t = it.get_curr(); op(t))
1019 break;
1020
1021 return i;
1022}
1023
1059template <class Op, class ... Cs>
1060[[nodiscard]]
1061auto zip_partition(Op op, const Cs &... cs)
1062{
1063 using ZipType = decltype(zip_it(cs...).get_curr());
1064
1066 size_t n1 = 0, n2 = 0;
1067 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
1068 if (auto t = it.get_curr(); op(t))
1069 {
1070 ret1.append(t);
1071 ++n1;
1072 }
1073 else
1074 {
1075 ret2.append(t);
1076 ++n2;
1077 }
1078
1079 return std::make_tuple(ret1, n1, ret2, n2);
1080}
1081
1110template <class ... Cs>
1111[[nodiscard]] inline
1112auto t_zip(const Cs &... cs)
1113{
1114 auto it = zip_it(cs...);
1115 using T = decltype(it.get_curr());
1117 for (; it.has_curr(); it.next_ne())
1118 ret.append(it.get_curr());
1119
1120 return ret;
1121}
1122
1130template <class ... Cs>
1131[[nodiscard]] inline
1132auto t_zip_eq(const Cs &... cs)
1133{
1134 auto it = zip_it(cs...);
1135 using T = decltype(it.get_curr());
1137 for (; it.has_curr(); it.next_ne())
1138 ret.append(it.get_curr());
1139
1140 ah_length_error_if(not it.completed())
1141 << "Container sizes mismatch";
1142
1143 return ret;
1144}
1145
1173template <class HeadC, class ... TailC>
1174class EnumZipIterator : public EnumZipIterator<TailC...>
1176{
1177 typename HeadC::Iterator it;
1178
1179 using T = std::decay_t<typename HeadC::Item_Type>;
1180
1181 public:
1182
1187 EnumZipIterator(const HeadC &head, const TailC &...tail)
1188 : EnumZipIterator<TailC...>(tail...), it(head) {}
1189
1191 [[nodiscard]] bool has_curr() const noexcept
1192 {
1193 return it.has_curr() and EnumZipIterator<TailC...>::has_curr();
1194 }
1195
1198 {
1199 return not it.has_curr() and EnumZipIterator<TailC...>::completed();
1200 }
1201
1206 auto get_curr() const
1207 {
1208 std::tuple<T> curr(it.get_curr());
1209 return std::tuple_cat(curr, EnumZipIterator<TailC...>::get_curr());
1210 }
1211
1213 void next()
1214 {
1215 it.next();
1217 }
1218
1220 {
1221 std::tuple<T> curr(it.get_curr_ne());
1222 return std::tuple_cat(curr, EnumZipIterator<TailC...>::get_curr_ne());
1223 }
1224
1229 void next_ne() noexcept
1230 {
1231 it.next_ne();
1233 }
1234};
1235
1236template <class C>
1237class EnumZipIterator<C> : public C::Iterator
1238{
1239 size_t i = 0;
1240
1241 public:
1242
1244 void next()
1245 {
1246 C::Iterator::next();
1247 ++i;
1248 }
1249
1255 {
1256 C::Iterator::next_ne();
1257 ++i;
1258 }
1259
1260 using T = std::decay_t<typename C::Item_Type>;
1261
1266 EnumZipIterator(const C &c) : C::Iterator(c) {}
1267
1269 std::tuple<T, size_t> get_curr() const
1270 {
1271 return std::tuple<T, size_t>(C::Iterator::get_curr(), i);
1272 }
1273
1278 std::tuple<T, size_t> get_curr_ne() const noexcept
1279 {
1280 return std::tuple<T, size_t>(C::Iterator::get_curr_ne(), i);
1281 }
1282
1284 [[nodiscard]] bool completed() const noexcept { return not this->has_curr(); }
1285};
1286
1293template <class ... Cs>
1294[[nodiscard]] inline
1296{
1297 return EnumZipIterator<Cs...>(cs...);
1298}
1299
1308template <class C, class ... Cs>
1309[[nodiscard]] inline
1310EnumZipIterator<C, Cs...>
1311get_enum_zip_it_pos(size_t pos, const C &c, const Cs &... cs)
1312{
1313 EnumZipIterator<C, Cs...> ret(c, cs...);
1314 for (size_t i = 0; i < pos; ++i)
1315 ret.next();
1316
1317 return ret;
1318}
1319
1321template <class ... Cs>
1322[[nodiscard]] inline
1324{
1325 return EnumZipIterator<Cs...>(cs...);
1326}
1327
1329template <class ... Cs>
1330[[nodiscard]] inline
1331EnumZipIterator<Cs...> enum_zip_it_pos(size_t pos, const Cs &... cs)
1332{
1333 return get_enum_zip_it_pos(pos, cs...);
1334}
1335
1344template <class ... Cs>
1345[[nodiscard]] inline
1346auto t_enum_zip(const Cs &... cs)
1347{
1348 auto it = get_enum_zip_it(cs...);
1349 using T = decltype(it.get_curr());
1351 for (; it.has_curr(); it.next_ne())
1352 ret.append(it.get_curr());
1353
1354 return ret;
1355}
1356
1364template <class ... Cs>
1365[[nodiscard]] inline
1366auto t_enum_zip_eq(const Cs &... cs)
1367{
1368 auto it = get_enum_zip_it(cs...);
1369 using T = decltype(it.get_curr());
1371 for (; it.has_curr(); it.next_ne())
1372 ret.append(it.get_curr());
1373
1374 ah_length_error_if(not it.completed())
1375 << "Container sizes mismatch";
1376
1377 return ret;
1378}
1379
1380template <typename... Ts, size_t... is>
1381static inline
1382auto t_unzip_impl(const DynList<std::tuple<Ts...>> &l,
1383 std::index_sequence<is...>)
1384{
1385 std::tuple<DynList<Ts>...> ret;
1386 for (auto it = l.get_it(); it.has_curr(); it.next_ne())
1387 std::initializer_list<int>{(std::get<is>(ret).append(std::get<is>(it.get_curr())), 0)...};
1388
1389 return ret;
1390}
1391
1398template <class... Ts>
1399[[nodiscard]] inline
1400auto t_unzip(const DynList<std::tuple<Ts...>> &tuples)
1401{
1402 return t_unzip_impl(tuples, std::index_sequence_for<Ts...>{});
1403}
1404
1422template <class C, typename ... Lists>
1423[[nodiscard]]
1424auto zip_lists(const C &c, const Lists &... lists)
1425{
1426 using T = typename C::Item_Type;
1428 for (auto it = get_zip_it(c, lists...); it.has_curr(); it.next_ne())
1429 ret.append(it.get_curr_list());
1430 return ret;
1431}
1432
1441template <class C, typename ... Lists>
1442[[nodiscard]]
1443auto zip_lists_eq(const C &c, const Lists &... lists)
1444{
1445 using T = typename C::Item_Type;
1447 auto it = get_zip_it(c, lists...);
1448 for (; it.has_curr(); it.next_ne())
1449 ret.append(it.get_curr_list());
1450
1451 ah_length_error_if(not it.completed())
1452 << "zip_list_eq: container sizes mismatch";
1453
1454 return ret;
1455}
1456
1460namespace std_zip_detail
1461{
1466 template <typename... Its>
1467 bool all_valid(const Its&... its)
1468 {
1469 return (... and (its.first != its.second));
1470 }
1471
1475 template <typename... Its>
1477 {
1478 (++its.first, ...);
1479 }
1480
1485 template <typename... Its>
1486 auto deref_all(const Its&... its)
1487 {
1488 return std::make_tuple(*its.first...);
1489 }
1490}
1491
1496template <typename C1, typename C2>
1497[[nodiscard]]
1498auto std_zip(const C1 &c1, const C2 &c2)
1499{
1500 using T = typename C1::value_type;
1501 using U = typename C2::value_type;
1502 std::vector<std::pair<T, U>> result;
1503 auto it1 = c1.begin();
1504 auto it2 = c2.begin();
1505 for (; it1 != c1.end() and it2 != c2.end(); ++it1, ++it2)
1506 result.emplace_back(*it1, *it2);
1507 return result;
1508}
1509
1524template <typename... Cs>
1525[[nodiscard]]
1526auto tzip_std(const Cs&... cs)
1527{
1528 static_assert(sizeof...(Cs) >= 2, "tzip_std requires at least 2 containers");
1529
1530 using TupleType = std::tuple<typename Cs::value_type...>;
1531 std::vector<TupleType> ret;
1532
1533 // Create iterator pairs (begin, end) for each container
1534 auto iters = std::make_tuple(std::make_pair(cs.begin(), cs.end())...);
1535
1536 // Helper to check all iterators and build tuples
1537 auto check_and_push = [&ret](auto&... its) {
1538 while (std_zip_detail::all_valid(its...))
1539 {
1540 ret.push_back(std_zip_detail::deref_all(its...));
1542 }
1543 };
1544
1545 std::apply(check_and_push, iters);
1546 return ret;
1547}
1548
1558template <typename... Cs>
1559[[nodiscard]]
1560auto std_zip_n(const Cs &... cs)
1561{
1562 return tzip_std(cs...);
1563}
1564
1565
1576template <class Op, class ... Cs>
1577[[nodiscard]]
1578auto zip_transform(Op &&op, const Cs &... cs)
1579{
1580 using ZipType = decltype(zip_it(cs...).get_curr());
1581 using ResultType = std::decay_t<decltype(std::forward<Op>(op)(std::declval<ZipType>()))>;
1582
1583 std::vector<ResultType> ret;
1584 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
1585 ret.push_back(std::forward<Op>(op)(it.get_curr()));
1586 return ret;
1587}
1588
1598template <class Op, class ... Cs>
1599[[nodiscard]]
1600auto zip_transform_eq(Op &&op, const Cs &... cs)
1601{
1602 using ZipType = decltype(zip_it(cs...).get_curr());
1603 using ResultType = std::decay_t<decltype(std::forward<Op>(op)(std::declval<ZipType>()))>;
1604
1605 std::vector<ResultType> ret;
1606 auto it = zip_it(cs...);
1607 for (; it.has_curr(); it.next_ne())
1608 ret.push_back(std::forward<Op>(op)(it.get_curr()));
1609
1610 ah_length_error_if(not it.completed())
1611 << "zip_transform_eq() containers sizes mismatch";
1612 return ret;
1613}
1614
1623template <class Op, class ... Cs>
1624inline
1625void zip_for_each_indexed(Op &&op, const Cs &... cs)
1626{
1627 size_t idx = 0;
1628 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne(), ++idx)
1629 std::forward<Op>(op)(idx, it.get_curr());
1630}
1631
1639template <class Op, class ... Cs>
1640inline
1641void zip_for_each_indexed_eq(Op &&op, const Cs &... cs)
1642{
1643 size_t idx = 0;
1644 auto it = zip_it(cs...);
1645 for (; it.has_curr(); it.next_ne(), ++idx)
1646 std::forward<Op>(op)(idx, it.get_curr());
1647
1648 ah_length_error_if(not it.completed())
1649 << "zip_for_each_indexed_eq() containers sizes mismatch";
1650}
1651
1659template <class ... Cs>
1660[[nodiscard]]
1661auto zip_take(size_t n, const Cs &... cs)
1662{
1663 using ZipType = decltype(zip_it(cs...).get_curr());
1665 size_t count = 0;
1666 for (auto it = zip_it(cs...); it.has_curr() and count < n; it.next_ne(), ++count)
1667 ret.append(it.get_curr());
1668 return ret;
1669}
1670
1678template <class ... Cs>
1679[[nodiscard]]
1680auto zip_drop(size_t n, const Cs &... cs)
1681{
1682 using ZipType = decltype(zip_it(cs...).get_curr());
1684 auto it = zip_it(cs...);
1685
1686 // Skip first n elements
1687 for (size_t i = 0; i < n and it.has_curr(); ++i)
1688 it.next_ne();
1689
1690 // Collect the rest
1691 for (; it.has_curr(); it.next_ne())
1692 ret.append(it.get_curr());
1693 return ret;
1694}
1695
1703template <class Pred, class ... Cs>
1704[[nodiscard]]
1705auto zip_take_while(Pred &&pred, const Cs &... cs)
1706{
1707 using ZipType = decltype(zip_it(cs...).get_curr());
1709 for (auto it = zip_it(cs...); it.has_curr(); it.next_ne())
1710 {
1711 auto t = it.get_curr();
1712 if (not std::forward<Pred>(pred)(t))
1713 break;
1714 ret.append(t);
1715 }
1716 return ret;
1717}
1718
1726template <class Pred, class ... Cs>
1727[[nodiscard]]
1728auto zip_drop_while(Pred &&pred, const Cs &... cs)
1729{
1730 using ZipType = decltype(zip_it(cs...).get_curr());
1732 auto it = zip_it(cs...);
1733
1734 // Skip while pred is true
1735 for (; it.has_curr() and std::forward<Pred>(pred)(it.get_curr()); it.next_ne())
1736 /* skip */;
1737
1738 // Collect the rest
1739 for (; it.has_curr(); it.next_ne())
1740 ret.append(it.get_curr());
1741 return ret;
1742}
1743
1744// ============================================================================
1745// Index sequence helpers
1746// ============================================================================
1747
1751namespace zip_index_detail
1752{
1757 template <class Op, class Tuple, size_t... Is>
1758 void for_each_in_tuple_impl(Op &&op, Tuple &&t, std::index_sequence<Is...>)
1759 {
1760 (std::forward<Op>(op)(std::get<Is>(std::forward<Tuple>(t))), ...);
1761 }
1762
1768 template <class Op, class Tuple, size_t... Is>
1769 auto transform_tuple_impl(Op &&op, Tuple &&t, std::index_sequence<Is...>)
1770 {
1771 return std::make_tuple(std::forward<Op>(op)(std::get<Is>(std::forward<Tuple>(t)))...);
1772 }
1773
1779 template <class Pred, class Tuple, size_t... Is>
1780 bool all_of_tuple_impl(Pred &&pred, const Tuple &t, std::index_sequence<Is...>)
1781 {
1782 return (... and std::forward<Pred>(pred)(std::get<Is>(t)));
1783 }
1784
1790 template <class Pred, class Tuple, size_t... Is>
1791 bool any_of_tuple_impl(Pred &&pred, const Tuple &t, std::index_sequence<Is...>)
1792 {
1793 return (... or std::forward<Pred>(pred)(std::get<Is>(t)));
1794 }
1795}
1796
1826template <class Op, class Tuple>
1828{
1829 constexpr auto N = std::tuple_size_v<std::decay_t<Tuple>>;
1831 std::forward<Op>(op), std::forward<Tuple>(t), std::make_index_sequence<N>{});
1832}
1833
1864template <class Op, class Tuple>
1865[[nodiscard]]
1866auto transform_tuple(Op &&op, Tuple &&t)
1867{
1868 constexpr auto N = std::tuple_size_v<std::decay_t<Tuple>>;
1870 std::forward<Op>(op), std::forward<Tuple>(t), std::make_index_sequence<N>{});
1871}
1872
1894template <class Pred, class Tuple>
1895[[nodiscard]]
1896bool all_of_tuple(Pred &&pred, const Tuple &t)
1897{
1898 constexpr auto N = std::tuple_size_v<std::decay_t<Tuple>>;
1900 std::forward<Pred>(pred), t, std::make_index_sequence<N>{});
1901}
1902
1923template <class Pred, class Tuple>
1924[[nodiscard]]
1925bool any_of_tuple(Pred &&pred, const Tuple &t)
1926{
1927 constexpr auto N = std::tuple_size_v<std::decay_t<Tuple>>;
1929 std::forward<Pred>(pred), t, std::make_index_sequence<N>{});
1930}
1931
1952template <class Pred, class Tuple>
1953[[nodiscard]]
1954bool none_of_tuple(Pred &&pred, const Tuple &t)
1955{
1956 return not any_of_tuple(std::forward<Pred>(pred), t);
1957}
1958
1959} // end namespace Aleph
1960
1961# endif // AH_ZIP_H
1962
#define ah_length_error_if(C)
Throws std::length_error if condition holds.
Definition ah-errors.H:698
Functional programming utilities for Aleph-w containers.
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
bool completed() const noexcept
Return true if the underlying iterator has reached the end.
Definition ah-zip.H:1284
std::tuple< T, size_t > get_curr_ne() const noexcept
Return the current tuple (value, index) (no-throw variant).
Definition ah-zip.H:1278
std::tuple< T, size_t > get_curr() const
Return the current tuple (value, index) (bounds-checked).
Definition ah-zip.H:1269
EnumZipIterator(const C &c)
Construct an enumerating iterator over a single container.
Definition ah-zip.H:1266
void next()
Advance the iterator and increment the associated index (bounds-checked).
Definition ah-zip.H:1244
void next_ne() noexcept
Advance the iterator and increment the associated index (no-throw variant).
Definition ah-zip.H:1254
std::decay_t< typename C::Item_Type > T
Definition ah-zip.H:1260
std::tuple< T > get_curr_ne() const noexcept
Return the current tuple (no-throw variant).
Definition ah-zip.H:226
std::tuple< T > Tuple_Type
The tuple type returned by get_curr() and get_curr_ne()
Definition ah-zip.H:200
std::decay_t< typename C::Item_Type > T
Definition ah-zip.H:197
bool completed() const noexcept
Return true if the underlying iterator has reached the end.
Definition ah-zip.H:239
DynList< T > get_curr_list() const
Definition ah-zip.H:231
std::tuple< T > get_curr() const
Return the current tuple (bounds-checked).
Definition ah-zip.H:217
ZipIterator(const C &c)
Construct a zip iterator over a single container.
Definition ah-zip.H:211
T Item_Type
Type of elements from the container.
Definition ah-zip.H:203
Iterator that traverses multiple containers with enumeration index.
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.
Iterator that traverses multiple Aleph containers in lockstep.
#define N
Definition fib.C:294
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4118
Singly linked list implementations with head-tail access.
Freq_Node * pred
Predecessor node in level-order traversal.
bool all_valid(const Its &... its)
Check if all iterators are valid (not at end).
Definition ah-zip.H:1467
auto deref_all(const Its &... its)
Dereference all iterators and make a tuple.
Definition ah-zip.H:1486
void advance_all(Its &... its)
Advance all iterators.
Definition ah-zip.H:1476
bool compare_adjacent(Cmp &cmp, const Tuple &t, std::index_sequence< Is... >)
Compare all adjacent pairs in a tuple using the given comparator.
Definition ah-zip.H:963
bool any_of_tuple_impl(Pred &&pred, const Tuple &t, std::index_sequence< Is... >)
Check if any element satisfies a predicate.
Definition ah-zip.H:1791
auto transform_tuple_impl(Op &&op, Tuple &&t, std::index_sequence< Is... >)
Transform each element in a tuple.
Definition ah-zip.H:1769
void for_each_in_tuple_impl(Op &&op, Tuple &&t, std::index_sequence< Is... >)
Apply a function to each element in a tuple.
Definition ah-zip.H:1758
bool all_of_tuple_impl(Pred &&pred, const Tuple &t, std::index_sequence< Is... >)
Check if all elements satisfy a predicate.
Definition ah-zip.H:1780
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
DynList< T > zip_maps_eq(Op op, const Cs &... cs)
Map op over zipped tuples; throw if containers differ in length.
Definition ah-zip.H:782
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
T Item_Type
Type of elements from the first container.
Definition ah-zip.H:117
bool completed() const noexcept
Return true if all underlying iterators are finished.
Definition ah-zip.H:140
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
static auto t_unzip_impl(const DynList< std::tuple< Ts... > > &l, std::index_sequence< is... >)
Definition ah-zip.H:1382
auto zip_filter(Op op, const Cs &... cs)
Filter zipped tuples by predicate op.
Definition ah-zip.H:895
EnumZipIterator< Cs... > get_enum_zip_it(const Cs &... cs)
Create an EnumZipIterator over the given containers.
Definition ah-zip.H:1295
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
void next_ne() noexcept
Advance all underlying iterators (no-throw variant).
Definition ah-zip.H:185
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
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:107
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
decltype(std::tuple_cat(std::declval< std::tuple< T > >(), std::declval< typename ZipIterator< TailC... >::Tuple_Type >())) Tuple_Type
The tuple type returned by get_curr() and get_curr_ne()
Definition ah-zip.H:114
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
auto get_curr() const
Return the current tuple (bounds-checked).
Definition ah-zip.H:149
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
bool has_curr() const noexcept
Return true if all underlying iterators are positioned on a valid item.
Definition ah-zip.H:130
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
DynList< T > zip_maps_if_eq(Prop prop, Op op, const Cs &... cs)
Map op over zipped tuples that satisfy prop; throw if lengths differ.
Definition ah-zip.H:807
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
static bool init
Definition hash-fct.C:47
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
DynList< T > zip_maps_if(Prop prop, Op op, const Cs &... cs)
Map op over zipped tuples that satisfy prop.
Definition ah-zip.H:698
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
DynList< T > get_curr_list() const
Returns current elements as a DynList (requires homogeneous Item_Type)
Definition ah-zip.H:166
auto get_curr_ne() const noexcept
Return the current tuple (no-throw variant).
Definition ah-zip.H:159
EnumZipIterator< Cs... > enum_zip_it_pos(size_t pos, const Cs &... cs)
Alias for get_enum_zip_it_pos.
Definition ah-zip.H:1331
void next()
Advance all underlying iterators (bounds-checked).
Definition ah-zip.H:175
auto std_zip_n(const Cs &... cs)
Build a vector of tuples from 2 or more STL containers (variadic).
Definition ah-zip.H:1560
EnumZipIterator< C, Cs... > get_enum_zip_it_pos(size_t pos, const C &c, const Cs &... cs)
Create an EnumZipIterator positioned at index pos.
Definition ah-zip.H:1311
auto zip_drop(size_t n, const Cs &... cs)
Skip n tuples and return the rest.
Definition ah-zip.H:1680
ZipIterator< Cs... > get_zip_it_pos(size_t pos, const Cs &... cs)
Create a ZipIterator positioned at index pos.
Definition ah-zip.H:264
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... > get_zip_it(const Cs &... cs)
Create a ZipIterator over the given containers.
Definition ah-zip.H:250
DynList< T > zip_maps(Op op, const Cs &... cs)
Map op over zipped tuples, returning a list of results.
Definition ah-zip.H:679
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
Dynamic ordered set implemented with a Skip List.
DynList< int > l