Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-stl-zip.H
Go to the documentation of this file.
1/*
2 Aleph_w
3
4 Data structures & Algorithms
5 version 2.0.0b
6 https://github.com/lrleon/Aleph-w
7
8 This file is part of Aleph-w library
9
10 Copyright (c) 2002-2026 Leandro Rabindranath Leon
11
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files (the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions:
18
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29*/
30
31
32# ifndef AH_STL_ZIP_H
33# define AH_STL_ZIP_H
34
35# include <type_traits>
36# include <tuple>
37# include <iterator>
38# include <utility>
39# include <optional>
40# include <functional>
41
42
87namespace Aleph
88{
89 // ============================================================================
90 // StlZipIterator - Core iterator for zipping STL containers
91 // ============================================================================
92
93 namespace stl_zip_detail
94 {
95 // Check if all iterators are valid (not at end)
96 template <typename... IterPairs>
97 constexpr bool all_valid(const IterPairs &... its) noexcept
98 {
99 return (... and (std::get<0>(its) != std::get<1>(its)));
100 }
101
102 // Advance all iterators
103 template <typename... IterPairs>
104 constexpr void advance_all(IterPairs &... its) noexcept
105 {
106 (++std::get<0>(its), ...);
107 }
108
109 // Dereference all iterators and make a tuple
110 template <typename... IterPairs>
111 constexpr auto deref_all(const IterPairs &... its)
112 {
113 return std::tuple<decltype(*std::get<0>(its))...>(*std::get<0>(its)...);
114 }
115
116 // Get value types from iterator pairs
117 template <typename IterPair>
118 using iter_value_t = std::decay_t<decltype(*std::get<0>(std::declval<IterPair>()))>;
119 } // namespace stl_zip_detail
120
140 template <typename... Containers>
142 {
143 public:
144 // Iterator type aliases for STL compatibility
145 using iterator_category = std::input_iterator_tag;
146 using difference_type = std::ptrdiff_t;
147
148 // Each element is a pair of (current_iterator, end_iterator)
149 using IteratorTuple = std::tuple<
150 std::pair<typename std::decay_t<Containers>::const_iterator,
151 typename std::decay_t<Containers>::const_iterator>...>;
152
153 // Value type is a tuple of references to elements
154 using value_type = std::tuple<
155 typename std::decay_t<Containers>::value_type...>;
156
157 using reference = std::tuple<
158 const typename std::decay_t<Containers>::value_type &...>;
159
160 using pointer = void;
161
162 private:
164
165 // Helper to check if all iterators are valid
166 template <size_t... Is>
167 [[nodiscard]] constexpr bool has_curr_impl(std::index_sequence<Is...>) const noexcept
168 {
169 return stl_zip_detail::all_valid(std::get<Is>(iters_)...);
170 }
171
172 // Helper to dereference all iterators
173 template <size_t... Is>
174 [[nodiscard]] constexpr auto deref_impl(std::index_sequence<Is...>) const
175 {
176 return stl_zip_detail::deref_all(std::get<Is>(iters_)...);
177 }
178
179 // Helper to advance all iterators
180 template <size_t... Is>
181 constexpr void advance_impl(std::index_sequence<Is...>) noexcept
182 {
183 stl_zip_detail::advance_all(std::get<Is>(iters_)...);
184 }
185
186 // Helper to check if all iterators completed
187 template <size_t... Is>
188 [[nodiscard]] constexpr bool completed_impl(std::index_sequence<Is...>) const noexcept
189 {
190 return (... and (std::get<0>(std::get<Is>(iters_)) ==
191 std::get<1>(std::get<Is>(iters_))));
192 }
193
194 public:
196 static constexpr size_t num_containers = sizeof...(Containers);
197
202 explicit constexpr StlZipIterator(const Containers &... cs)
203 : iters_(std::make_pair(cs.begin(), cs.end())...) {}
204
210 struct end_tag
211 {};
212
213 constexpr StlZipIterator(const Containers &... cs, end_tag)
214 : iters_(std::make_pair(cs.end(), cs.end())...) {}
215
220 [[nodiscard]] constexpr bool has_curr() const noexcept
221 {
222 return has_curr_impl(std::make_index_sequence<num_containers>{});
223 }
224
231 [[nodiscard]] constexpr bool completed() const noexcept
232 {
233 return completed_impl(std::make_index_sequence<num_containers>{});
234 }
235
241 [[nodiscard]] constexpr auto get_curr() const
242 {
243 return deref_impl(std::make_index_sequence<num_containers>{});
244 }
245
250 constexpr void next() noexcept
251 {
252 advance_impl(std::make_index_sequence<num_containers>{});
253 }
254
260 constexpr void next_ne() noexcept { next(); }
261
262 // STL iterator interface
263
268 [[nodiscard]] constexpr auto operator*() const
269 {
270 return get_curr();
271 }
272
278 {
279 next();
280 return *this;
281 }
282
287 constexpr StlZipIterator operator++(int) noexcept
288 {
289 auto tmp = *this;
290 next();
291 return tmp;
292 }
293
298 [[nodiscard]] constexpr bool operator==(const StlZipIterator & other) const noexcept
299 {
300 return not has_curr() and not other.has_curr();
301 }
302
304 [[nodiscard]] constexpr bool operator!=(const StlZipIterator & other) const noexcept
305 {
306 return not (*this == other);
307 }
308 };
309
329 template <typename... Containers>
331 {
332 std::tuple<const std::decay_t<Containers> &...> containers_;
333
334 public:
338
343 explicit constexpr StlZipView(const Containers &... cs)
344 : containers_(cs...) {}
345
350 [[nodiscard]] constexpr iterator begin() const
351 {
352 return std::apply([](const auto &... cs)
353 {
354 return iterator(cs...);
355 }, containers_);
356 }
357
362 [[nodiscard]] constexpr iterator end() const
363 {
364 return std::apply([](const auto &... cs)
365 {
366 return iterator(cs..., typename iterator::end_tag{});
367 }, containers_);
368 }
369
374 [[nodiscard]] constexpr bool empty() const
375 {
376 return not begin().has_curr();
377 }
378
384 [[nodiscard]] size_t size() const
385 {
386 size_t count = 0;
387 for (auto it = begin(); it.has_curr(); it.next())
388 ++count;
389 return count;
390 }
391 };
392
393 // ============================================================================
394 // Factory Functions
395 // ============================================================================
396
420 template <typename... Containers>
421 [[nodiscard]] constexpr auto stl_zip(const Containers &... cs)
422 {
423 static_assert(sizeof...(Containers) >= 2, "stl_zip requires at least 2 containers");
424 return StlZipView<Containers...>(cs...);
425 }
426
439 template <typename... Containers>
440 [[nodiscard]] constexpr auto stl_zip_it(const Containers &... cs)
441 {
443 }
444
445 // ============================================================================
446 // Functional Operations - Aleph Style
447 // ============================================================================
448
478 template <typename Pred, typename... Containers>
479 [[nodiscard]] bool stl_zip_all(Pred && pred, const Containers &... cs)
480 {
481 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
482 if (not std::forward<Pred>(pred)(it.get_curr()))
483 return false;
484 return true;
485 }
486
499 template <typename Pred, typename... Containers>
501 {
502 auto it = stl_zip_it(cs...);
503 for (; it.has_curr(); it.next())
504 if (not std::forward<Pred>(pred)(it.get_curr()))
505 return false;
506 return it.completed();
507 }
508
535 template <typename Pred, typename... Containers>
537 {
538 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
539 if (std::forward<Pred>(pred)(it.get_curr()))
540 return true;
541 return false;
542 }
543
545 template <typename Pred, typename... Containers>
546 [[nodiscard]] bool stl_zip_any(Pred && pred, const Containers &... cs)
547 {
548 return stl_zip_exists(std::forward<Pred>(pred), cs...);
549 }
550
564 template <typename Pred, typename... Containers>
565 [[nodiscard]] bool stl_zip_none(Pred && pred, const Containers &... cs)
566 {
567 return not stl_zip_exists(std::forward<Pred>(pred), cs...);
568 }
569
593 template <typename Op, typename... Containers>
594 void stl_zip_for_each(Op && op, const Containers &... cs)
595 {
596 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
597 std::forward<Op>(op)(it.get_curr());
598 }
599
609 template <typename Op, typename... Containers>
610 void stl_zip_for_each_indexed(Op && op, const Containers &... cs)
611 {
612 size_t idx = 0;
613 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next(), ++idx)
614 std::forward<Op>(op)(idx, it.get_curr());
615 }
616
647 template <typename T, typename Op, typename... Containers>
648 [[nodiscard]] T stl_zip_foldl(T init, Op && op, const Containers &... cs)
649 {
650 T acc = std::move(init);
651 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
652 acc = std::forward<Op>(op)(std::move(acc), it.get_curr());
653 return acc;
654 }
655
657 template <typename T, typename Op, typename... Containers>
658 [[nodiscard]] T stl_zip_reduce(T init, Op && op, const Containers &... cs)
659 {
660 return stl_zip_foldl(std::move(init), std::forward<Op>(op), cs...);
661 }
662
691 template <typename Op, typename... Containers>
692 [[nodiscard]] auto stl_zip_map(Op && op, const Containers &... cs)
693 {
694 using TupleType = decltype(stl_zip_it(cs...).get_curr());
695 using ResultType = std::decay_t<decltype(std::forward<Op>(op)(std::declval<TupleType>()))>;
696
697 std::vector<ResultType> result;
698 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
699 result.push_back(std::forward<Op>(op)(it.get_curr()));
700 return result;
701 }
702
715 template <typename Pred, typename... Containers>
717 {
718 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
719
720 std::vector<TupleType> result;
721 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
722 if (auto t = it.get_curr(); std::forward<Pred>(pred)(t))
723 result.push_back(t);
724 return result;
725 }
726
737 template <typename Pred, typename... Containers>
739 {
740 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
741
742 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
743 if (auto t = it.get_curr(); std::forward<Pred>(pred)(t))
744 return std::optional<TupleType>(t);
745 return std::optional<TupleType>{};
746 }
747
758 template <typename Pred, typename... Containers>
759 [[nodiscard]] size_t stl_zip_count(Pred && pred, const Containers &... cs)
760 {
761 size_t count = 0;
762 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
763 if (std::forward<Pred>(pred)(it.get_curr()))
764 ++count;
765 return count;
766 }
767
777 template <typename... Containers>
778 [[nodiscard]] size_t stl_zip_length(const Containers &... cs)
779 {
780 size_t count = 0;
781 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
782 ++count;
783 return count;
784 }
785
795 template <typename... Containers>
797 {
798 auto it = stl_zip_it(cs...);
799 while (it.has_curr())
800 it.next();
801 return it.completed();
802 }
803
814 template <typename... Containers>
815 [[nodiscard]] auto stl_zip_nth(const size_t n, const Containers &... cs)
816 {
817 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
818
819 size_t i = 0;
820 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next(), ++i)
821 if (i == n)
822 return std::optional<TupleType>(it.get_curr());
823 return std::optional<TupleType>{};
824 }
825
836 template <typename... Containers>
837 [[nodiscard]] auto stl_zip_take(const size_t n, const Containers &... cs)
838 {
839 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
840
841 std::vector<TupleType> result;
842 result.reserve(n);
843 size_t count = 0;
844 for (auto it = stl_zip_it(cs...); it.has_curr() and count < n; it.next(), ++count)
845 result.push_back(it.get_curr());
846 return result;
847 }
848
859 template <typename... Containers>
860 [[nodiscard]] auto stl_zip_drop(const size_t n, const Containers &... cs)
861 {
862 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
863
864 std::vector<TupleType> result;
865 auto it = stl_zip_it(cs...);
866
867 // Skip first n
868 for (size_t i = 0; i < n and it.has_curr(); ++i)
869 it.next();
870
871 // Collect rest
872 for (; it.has_curr(); it.next())
873 result.push_back(it.get_curr());
874 return result;
875 }
876
890 template <typename Pred, typename... Containers>
892 {
893 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
894
895 std::vector<TupleType> matching, non_matching;
896 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
897 if (auto t = it.get_curr(); std::forward<Pred>(pred)(t))
898 matching.push_back(t);
899 else
900 non_matching.push_back(t);
901 return std::make_pair(std::move(matching), std::move(non_matching));
902 }
903
918 template <typename... Containers>
920 {
921 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
922
923 std::vector<TupleType> result;
924 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
925 result.push_back(it.get_curr());
926 return result;
927 }
928
929 // ============================================================================
930 // Traverse operations (like zip_traverse in ah-zip.H)
931 // ============================================================================
932
946 template <typename Pred, typename... Containers>
948 {
949 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
950 if (not std::forward<Pred>(pred)(it.get_curr()))
951 return false;
952 return true;
953 }
954
965 template <typename Pred, typename... Containers>
967 {
968 auto it = stl_zip_it(cs...);
969 for (; it.has_curr(); it.next())
970 if (not std::forward<Pred>(pred)(it.get_curr()))
971 return false;
972 return it.completed();
973 }
974
975 // ============================================================================
976 // Comparison helpers
977 // ============================================================================
978
979 namespace stl_zip_detail
980 {
981 // Compare adjacent elements in a tuple
982 template <typename Cmp, typename Tuple, size_t... Is>
983 bool compare_adjacent_impl(Cmp & cmp, const Tuple & t, std::index_sequence<Is...>)
984 {
985 return (... and cmp(std::get<Is>(t), std::get<Is + 1>(t)));
986 }
987 }
988
1014 template <typename Cmp, typename... Containers>
1015 [[nodiscard]] bool stl_zip_cmp(Cmp && cmp, const Containers &... cs)
1016 {
1017 static_assert(sizeof...(Containers) >= 2, "stl_zip_cmp requires at least 2 containers");
1018
1019 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1020 {
1021 constexpr size_t N = sizeof...(Containers);
1022 if (auto t = it.get_curr(); not
1023 stl_zip_detail::compare_adjacent_impl(cmp, t, std::make_index_sequence<N - 1>{}))
1024 return false;
1025 }
1026 return true;
1027 }
1028
1029 // ============================================================================
1030 // Enumerate - like Python's enumerate()
1031 // ============================================================================
1032
1045 template <typename Container>
1047 {
1048 public:
1049 using iterator_category = std::input_iterator_tag;
1050 using difference_type = std::ptrdiff_t;
1051 using value_type = std::tuple<size_t, typename std::decay_t<Container>::value_type>;
1052
1053 private:
1054 typename std::decay_t<Container>::const_iterator curr_;
1055 typename std::decay_t<Container>::const_iterator end_;
1056 size_t index_ = 0;
1057
1058 public:
1059 explicit constexpr StlEnumerateIterator(const Container & c)
1060 : curr_(c.begin()), end_(c.end()), index_(0) {}
1061
1062 struct end_tag
1063 {};
1064
1066 : curr_(c.end()), end_(c.end()), index_(0) {}
1067
1068 [[nodiscard]] constexpr bool has_curr() const noexcept { return curr_ != end_; }
1069
1070 [[nodiscard]] constexpr auto get_curr() const { return std::make_tuple(index_, *curr_); }
1071
1072 constexpr void next() noexcept
1073 {
1074 ++curr_;
1075 ++index_;
1076 }
1077
1083 constexpr void next_ne() noexcept { next(); }
1084
1085 [[nodiscard]] constexpr auto operator*() const { return get_curr(); }
1086
1088 {
1089 next();
1090 return *this;
1091 }
1092
1093 [[nodiscard]] constexpr bool operator==(const StlEnumerateIterator & other) const noexcept
1094 {
1095 return not has_curr() and not other.has_curr();
1096 }
1097
1098 [[nodiscard]] constexpr bool operator!=(const StlEnumerateIterator & other) const noexcept
1099 {
1100 return not (*this == other);
1101 }
1102 };
1103
1112 template <typename Container>
1114 {
1115 const std::decay_t<Container> & container_;
1116
1117 public:
1119
1120 explicit constexpr StlEnumerateView(const Container & c) : container_(c) {}
1121
1122 [[nodiscard]] constexpr iterator begin() const { return iterator(container_); }
1123
1124 [[nodiscard]] constexpr iterator end() const
1125 {
1126 return iterator(container_, typename iterator::end_tag{});
1127 }
1128 };
1129
1153 template <typename Container>
1154 [[nodiscard]] constexpr auto stl_enumerate(const Container & c)
1155 {
1157 }
1158
1159 // ============================================================================
1160 // Take while / Drop while
1161 // ============================================================================
1162
1188 template <typename Pred, typename... Containers>
1190 {
1191 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1192
1193 std::vector<TupleType> result;
1194 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1195 {
1196 auto t = it.get_curr();
1197 if (not std::forward<Pred>(pred)(t))
1198 break;
1199 result.push_back(t);
1200 }
1201 return result;
1202 }
1203
1217 template <typename Pred, typename... Containers>
1219 {
1220 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1221
1222 std::vector<TupleType> result;
1223 auto it = stl_zip_it(cs...);
1224
1225 // Skip while pred is true
1226 for (; it.has_curr() and std::forward<Pred>(pred)(it.get_curr()); it.next())
1227 /* skip */;
1228
1229 // Collect the rest
1230 for (; it.has_curr(); it.next())
1231 result.push_back(it.get_curr());
1232 return result;
1233 }
1234
1235 // ============================================================================
1236 // First / Last convenience functions
1237 // ============================================================================
1238
1248 template <typename... Containers>
1250 {
1251 return stl_zip_nth(0, cs...);
1252 }
1253
1265 template <typename... Containers>
1267 {
1268 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1269
1270 std::optional<TupleType> result;
1271 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1272 result = it.get_curr();
1273 return result;
1274 }
1275
1286 template <typename Pred, typename... Containers>
1288 {
1289 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1290
1291 std::optional<TupleType> result;
1292 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1293 {
1294 auto t = it.get_curr();
1295 if (std::forward<Pred>(pred)(t))
1296 result = t;
1297 }
1298 return result;
1299 }
1300
1311 template <typename Pred, typename... Containers>
1313 {
1314 size_t idx = 0;
1315 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next(), ++idx)
1316 if (std::forward<Pred>(pred)(it.get_curr()))
1317 return idx;
1318 return idx;
1319 }
1320
1321 // ============================================================================
1322 // Unzip - inverse of zip
1323 // ============================================================================
1324
1343 template <typename T, typename U>
1344 [[nodiscard]] auto stl_unzip(const std::vector<std::pair<T, U>> & pairs)
1345 {
1346 std::vector<T> firsts;
1347 std::vector<U> seconds;
1348 firsts.reserve(pairs.size());
1349 seconds.reserve(pairs.size());
1350
1351 for (const auto & [f, s]: pairs)
1352 {
1353 firsts.push_back(f);
1354 seconds.push_back(s);
1355 }
1356 return std::make_pair(std::move(firsts), std::move(seconds));
1357 }
1358
1379 template <typename... Ts>
1380 [[nodiscard]] auto stl_unzip_tuple(const std::vector<std::tuple<Ts...>> & tuples)
1381 {
1382 std::tuple<std::vector<Ts>...> result;
1383
1384 // Reserve space in each vector
1385 std::apply([&tuples](auto &... vecs)
1386 {
1387 (vecs.reserve(tuples.size()), ...);
1388 }, result);
1389
1390 // Populate vectors
1391 for (const auto & t: tuples)
1392 {
1393 std::apply([&t](auto &... vecs)
1394 {
1395 std::apply([&vecs...](const auto &... elems)
1396 {
1397 (vecs.push_back(elems), ...);
1398 }, t);
1399 }, result);
1400 }
1401
1402 return result;
1403 }
1404
1405 // ============================================================================
1406 // Adjacent - zip consecutive elements of same container
1407 // ============================================================================
1408
1432 template <typename Container>
1434 {
1435 using T = typename std::decay_t<Container>::value_type;
1436 std::vector<std::pair<T, T>> result;
1437
1438 auto it = c.begin();
1439 if (it == c.end())
1440 return result;
1441
1442 auto prev = *it;
1443 ++it;
1444
1445 for (; it != c.end(); ++it)
1446 {
1447 result.emplace_back(prev, *it);
1448 prev = *it;
1449 }
1450 return result;
1451 }
1452
1470 template <typename Op, typename Container>
1471 [[nodiscard]] auto stl_adjacent_map(Op && op, const Container & c)
1472 {
1473 using T = typename std::decay_t<Container>::value_type;
1474 using R = std::decay_t<decltype(std::forward<Op>(op)(std::declval<T>(), std::declval<T>()))>;
1475
1476 std::vector<R> result;
1477
1478 auto it = c.begin();
1479 if (it == c.end())
1480 return result;
1481
1482 auto prev = *it;
1483 ++it;
1484
1485 for (; it != c.end(); ++it)
1486 {
1487 result.push_back(std::forward<Op>(op)(prev, *it));
1488 prev = *it;
1489 }
1490 return result;
1491 }
1492
1493 // ============================================================================
1494 // Pairwise operations on single container
1495 // ============================================================================
1496
1514 template <typename Pred, typename Container>
1516 {
1517 auto it = c.begin();
1518 if (it == c.end())
1519 return true;
1520
1521 auto prev = *it;
1522 ++it;
1523
1524 for (; it != c.end(); ++it)
1525 {
1526 if (not std::forward<Pred>(pred)(prev, *it))
1527 return false;
1528 prev = *it;
1529 }
1530 return true;
1531 }
1532
1543 template <typename Pred, typename Container>
1545 {
1546 auto it = c.begin();
1547 if (it == c.end())
1548 return false;
1549
1550 auto prev = *it;
1551 ++it;
1552
1553 for (; it != c.end(); ++it)
1554 {
1555 if (std::forward<Pred>(pred)(prev, *it))
1556 return true;
1557 prev = *it;
1558 }
1559 return false;
1560 }
1561
1562 // ============================================================================
1563 // ML-style Additional Operations
1564 // ============================================================================
1565
1585 template <typename Op, typename... Containers>
1586 [[nodiscard]] auto stl_zip_mapi(Op && op, const Containers &... cs)
1587 {
1588 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1589 using ResultType = std::decay_t<decltype(std::forward<Op>(op)(size_t{}, std::declval<TupleType>()))>;
1590
1591 std::vector<ResultType> result;
1592 size_t idx = 0;
1593 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next(), ++idx)
1594 result.push_back(std::forward<Op>(op)(idx, it.get_curr()));
1595 return result;
1596 }
1597
1610 template <typename Pred, typename... Containers>
1612 {
1613 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1614
1615 std::vector<TupleType> result;
1616 size_t idx = 0;
1617 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next(), ++idx)
1618 if (auto t = it.get_curr(); std::forward<Pred>(pred)(idx, t))
1619 result.push_back(t);
1620 return result;
1621 }
1622
1644 template <typename T, typename Op, typename... Containers>
1645 [[nodiscard]] auto stl_zip_scan_left(T init, Op && op, const Containers &... cs)
1646 {
1647 std::vector<T> result;
1648 result.push_back(init);
1649
1650 T acc = std::move(init);
1651 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1652 {
1653 acc = std::forward<Op>(op)(std::move(acc), it.get_curr());
1654 result.push_back(acc);
1655 }
1656 return result;
1657 }
1658
1671 template <typename Op, typename... Containers>
1672 [[nodiscard]] auto stl_zip_find_mapi(Op && op, const Containers &... cs)
1673 {
1674 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1675 using OptType = std::decay_t<decltype(std::forward<Op>(op)(size_t{}, std::declval<TupleType>()))>;
1676
1677 size_t idx = 0;
1678 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next(), ++idx)
1679 if (auto result = std::forward<Op>(op)(idx, it.get_curr()))
1680 return result;
1681 return OptType{};
1682 }
1683
1696 template <typename... Containers>
1698 {
1699 // For a single zip, check if all containers have equal length
1700 auto it = stl_zip_it(cs...);
1701 while (it.has_curr())
1702 it.next();
1703 return it.completed();
1704 }
1705
1716 template <typename Eq, typename... Containers>
1717 [[nodiscard]] bool stl_zip_equal_by(Eq && eq, const Containers &... cs)
1718 {
1719 auto it = stl_zip_it(cs...);
1720 for (; it.has_curr(); it.next())
1721 if (not std::forward<Eq>(eq)(it.get_curr()))
1722 return false;
1723 return it.completed();
1724 }
1725
1740 template <typename... Containers1, typename... Containers2>
1742 const std::tuple<const Containers1 &...> & cs1,
1743 const std::tuple<const Containers2 &...> & cs2)
1744 {
1745 auto it1 = std::apply([](const auto &... cs) { return stl_zip_it(cs...); }, cs1);
1746 auto it2 = std::apply([](const auto &... cs) { return stl_zip_it(cs...); }, cs2);
1747
1748 while (it1.has_curr() and it2.has_curr())
1749 {
1750 auto t1 = it1.get_curr();
1751 auto t2 = it2.get_curr();
1752 if (t1 < t2) return -1;
1753 if (t2 < t1) return 1;
1754 it1.next();
1755 it2.next();
1756 }
1757
1758 if (it1.has_curr()) return 1; // first is longer
1759 if (it2.has_curr()) return -1; // second is longer
1760 return 0; // equal
1761 }
1762
1773 template <typename Tuple, typename... Containers>
1774 [[nodiscard]] bool stl_zip_mem(const Tuple & target, const Containers &... cs)
1775 {
1776 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1777 if (it.get_curr() == target)
1778 return true;
1779 return false;
1780 }
1781
1794 template <typename Key, typename... Containers>
1795 [[nodiscard]] auto stl_zip_assoc(const Key & key, const Containers &... cs)
1796 {
1797 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1798
1799 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1800 if (auto t = it.get_curr(); std::get<0>(t) == key)
1801 return std::optional<TupleType>(t);
1802 return std::optional<TupleType>{};
1803 }
1804
1814 template <typename... Containers>
1815 [[nodiscard]] auto stl_zip_min(const Containers &... cs)
1816 {
1817 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1818
1819 auto it = stl_zip_it(cs...);
1820 if (not it.has_curr())
1821 return std::optional<TupleType>{};
1822
1823 TupleType min_val = it.get_curr();
1824 it.next();
1825
1826 for (; it.has_curr(); it.next())
1827 {
1828 auto t = it.get_curr();
1829 if (t < min_val)
1830 min_val = t;
1831 }
1832 return std::optional<TupleType>(min_val);
1833 }
1834
1844 template <typename... Containers>
1845 [[nodiscard]] auto stl_zip_max(const Containers &... cs)
1846 {
1847 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1848
1849 auto it = stl_zip_it(cs...);
1850 if (not it.has_curr())
1851 return std::optional<TupleType>{};
1852
1853 TupleType max_val = it.get_curr();
1854 it.next();
1855
1856 for (; it.has_curr(); it.next())
1857 {
1858 auto t = it.get_curr();
1859 if (t > max_val)
1860 max_val = t;
1861 }
1862 return std::optional<TupleType>(max_val);
1863 }
1864
1874 template <typename... Containers>
1876 {
1877 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1878 using ResultType = std::optional<std::pair<TupleType, TupleType>>;
1879
1880 auto it = stl_zip_it(cs...);
1881 if (not it.has_curr())
1882 return ResultType{};
1883
1884 TupleType min_val = it.get_curr();
1885 TupleType max_val = min_val;
1886 it.next();
1887
1888 for (; it.has_curr(); it.next())
1889 {
1890 auto t = it.get_curr();
1891 if (t < min_val) min_val = t;
1892 if (t > max_val) max_val = t;
1893 }
1894 return ResultType(std::make_pair(min_val, max_val));
1895 }
1896
1908 template <typename... Containers>
1909 [[nodiscard]] auto stl_zip_sum(const Containers &... cs)
1910 {
1911 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1912
1913 auto it = stl_zip_it(cs...);
1914 if (not it.has_curr())
1915 return std::optional<TupleType>{};
1916
1917 TupleType sum = it.get_curr();
1918 it.next();
1919
1920 for (; it.has_curr(); it.next())
1921 {
1922 auto t = it.get_curr();
1923 std::apply([&t](auto &... sum_elems)
1924 {
1925 size_t i = 0;
1926 ((sum_elems = sum_elems + std::get<decltype(i){}>(t), ++i), ...);
1927 }, sum);
1928 }
1929 return std::optional<TupleType>(sum);
1930 }
1931} // end namespace Aleph
1932
1933# endif // AH_STL_ZIP_H
Iterator that pairs each element with its index.
constexpr bool has_curr() const noexcept
constexpr bool operator==(const StlEnumerateIterator &other) const noexcept
constexpr auto get_curr() const
constexpr void next_ne() noexcept
Advance without checking; same as next(), which does not check.
std::decay_t< Container >::const_iterator curr_
constexpr StlEnumerateIterator & operator++() noexcept
constexpr bool operator!=(const StlEnumerateIterator &other) const noexcept
std::input_iterator_tag iterator_category
constexpr auto operator*() const
std::tuple< size_t, typename std::decay_t< Container >::value_type > value_type
std::ptrdiff_t difference_type
std::decay_t< Container >::const_iterator end_
constexpr StlEnumerateIterator(const Container &c, end_tag)
constexpr StlEnumerateIterator(const Container &c)
constexpr void next() noexcept
Lazy view that pairs each element with its index.
const std::decay_t< Container > & container_
constexpr iterator begin() const
StlEnumerateIterator< std::decay_t< Container > > iterator
constexpr StlEnumerateView(const Container &c)
constexpr iterator end() const
Lazy iterator that traverses multiple STL containers in lockstep.
Definition ah-stl-zip.H:142
std::ptrdiff_t difference_type
Definition ah-stl-zip.H:146
static constexpr size_t num_containers
Number of containers being zipped.
Definition ah-stl-zip.H:196
std::input_iterator_tag iterator_category
Definition ah-stl-zip.H:145
constexpr void next() noexcept
Advance all iterators.
Definition ah-stl-zip.H:250
constexpr void next_ne() noexcept
Advance without checking; same as next(), which does not check.
Definition ah-stl-zip.H:260
constexpr bool has_curr() const noexcept
Check if iterator has current element.
Definition ah-stl-zip.H:220
std::tuple< const typename std::decay_t< Containers >::value_type &... > reference
Definition ah-stl-zip.H:158
constexpr bool completed() const noexcept
Check if all iterators have completed.
Definition ah-stl-zip.H:231
std::tuple< typename std::decay_t< Containers >::value_type... > value_type
Definition ah-stl-zip.H:155
constexpr StlZipIterator(const Containers &... cs, end_tag)
Definition ah-stl-zip.H:213
constexpr StlZipIterator operator++(int) noexcept
Post-increment operator.
Definition ah-stl-zip.H:287
IteratorTuple iters_
Definition ah-stl-zip.H:163
constexpr bool operator!=(const StlZipIterator &other) const noexcept
Inequality comparison.
Definition ah-stl-zip.H:304
constexpr StlZipIterator(const Containers &... cs)
Construct iterator from containers.
Definition ah-stl-zip.H:202
constexpr void advance_impl(std::index_sequence< Is... >) noexcept
Definition ah-stl-zip.H:181
constexpr bool completed_impl(std::index_sequence< Is... >) const noexcept
Definition ah-stl-zip.H:188
constexpr auto get_curr() const
Get current tuple of elements.
Definition ah-stl-zip.H:241
std::tuple< std::pair< typename std::decay_t< Containers >::const_iterator, typename std::decay_t< Containers >::const_iterator >... > IteratorTuple
Definition ah-stl-zip.H:151
constexpr auto operator*() const
Dereference operator for range-based for.
Definition ah-stl-zip.H:268
constexpr bool has_curr_impl(std::index_sequence< Is... >) const noexcept
Definition ah-stl-zip.H:167
constexpr auto deref_impl(std::index_sequence< Is... >) const
Definition ah-stl-zip.H:174
constexpr StlZipIterator & operator++() noexcept
Pre-increment operator.
Definition ah-stl-zip.H:277
constexpr bool operator==(const StlZipIterator &other) const noexcept
Equality comparison.
Definition ah-stl-zip.H:298
Lazy view over multiple zipped STL containers.
Definition ah-stl-zip.H:331
std::tuple< const std::decay_t< Containers > &... > containers_
Definition ah-stl-zip.H:332
StlZipIterator< std::decay_t< Containers >... > iterator
Definition ah-stl-zip.H:335
size_t size() const
Get number of tuples (minimum size of all containers).
Definition ah-stl-zip.H:384
constexpr iterator begin() const
Get iterator to beginning.
Definition ah-stl-zip.H:350
typename iterator::value_type value_type
Definition ah-stl-zip.H:337
constexpr StlZipView(const Containers &... cs)
Construct view from containers.
Definition ah-stl-zip.H:343
constexpr bool empty() const
Check if view is empty.
Definition ah-stl-zip.H:374
constexpr iterator end() const
Get iterator to end.
Definition ah-stl-zip.H:362
#define N
Definition fib.C:294
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4129
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
Definition Blossom.H:466
Freq_Node * pred
Predecessor node in level-order traversal.
constexpr bool all_valid(const IterPairs &... its) noexcept
Definition ah-stl-zip.H:97
std::decay_t< decltype(*std::get< 0 >(std::declval< IterPair >()))> iter_value_t
Definition ah-stl-zip.H:118
constexpr void advance_all(IterPairs &... its) noexcept
Definition ah-stl-zip.H:104
bool compare_adjacent_impl(Cmp &cmp, const Tuple &t, std::index_sequence< Is... >)
Definition ah-stl-zip.H:983
constexpr auto deref_all(const IterPairs &... its)
Definition ah-stl-zip.H:111
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
constexpr auto stl_zip_it(const Containers &... cs)
Get a zip iterator over STL containers.
Definition ah-stl-zip.H:440
auto stl_zip_filteri(Pred &&pred, const Containers &... cs)
Filter with index (filteri in ML).
auto stl_adjacent_map(Op &&op, const Container &c)
Apply function to adjacent pairs of elements.
bool stl_zip_exists(Pred &&pred, const Containers &... cs)
Check if predicate holds for any zipped tuple.
Definition ah-stl-zip.H:536
bool stl_zip_equal_by(Eq &&eq, const Containers &... cs)
Check equality with custom comparator.
bool stl_adjacent_exists(Pred &&pred, const Container &c)
Check if predicate holds for any adjacent pair.
auto stl_zip_find_last(Pred &&pred, const Containers &... cs)
Find last tuple satisfying predicate.
bool eq(const C1 &c1, const C2 &c2, Eq e=Eq())
Check equality of two containers using a predicate.
bool stl_zip_traverse(Pred &&pred, const Containers &... cs)
Traverse while predicate returns true.
Definition ah-stl-zip.H:947
bool stl_zip_all_eq(Pred &&pred, const Containers &... cs)
Check if predicate holds for all tuples AND containers have equal length.
Definition ah-stl-zip.H:500
auto stl_zip_min_max(const Containers &... cs)
Get both min and max in a single pass.
auto stl_zip_max(const Containers &... cs)
Get maximum tuple according to comparator.
bool stl_adjacent_all(Pred &&pred, const Container &c)
Check if predicate holds for all adjacent pairs.
auto stl_zip_take_while(Pred &&pred, const Containers &... cs)
Take tuples while predicate returns true.
size_t stl_zip_count(Pred &&pred, const Containers &... cs)
Count tuples satisfying predicate.
Definition ah-stl-zip.H:759
bool stl_zip_equal_length(const Containers &... cs)
Check if all containers have equal length.
Definition ah-stl-zip.H:796
auto stl_zip_drop_while(Pred &&pred, const Containers &... cs)
Skip tuples while predicate returns true, then return the rest.
bool stl_zip_cmp(Cmp &&cmp, const Containers &... cs)
Compare elements across containers using a comparator.
auto stl_zip_find_first(Pred &&pred, const Containers &... cs)
Find first tuple satisfying predicate.
Definition ah-stl-zip.H:738
bool stl_zip_mem(const Tuple &target, const Containers &... cs)
Check if a tuple exists in the zipped sequence (mem in ML).
and
Check uniqueness with explicit hash + equality functors.
auto stl_unzip_tuple(const std::vector< std::tuple< Ts... > > &tuples)
Unzip a vector of tuples into a tuple of vectors.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
auto stl_zip_first(const Containers &... cs)
Get first tuple from zipped containers.
auto stl_zip_mapi(Op &&op, const Containers &... cs)
Map with index (mapi in ML).
int stl_zip_compare(const std::tuple< const Containers1 &... > &cs1, const std::tuple< const Containers2 &... > &cs2)
Compare two zipped sequences lexicographically.
size_t stl_zip_find_index(Pred &&pred, const Containers &... cs)
Find index of first tuple satisfying predicate.
bool stl_zip_none(Pred &&pred, const Containers &... cs)
Check if no tuple satisfies the predicate.
Definition ah-stl-zip.H:565
auto stl_zip_scan_left(T init, Op &&op, const Containers &... cs)
Scan left (scan_left in ML) - fold with intermediate results.
constexpr auto stl_enumerate(const Container &c)
Create an enumerate view over a container.
auto stl_zip_map(Op &&op, const Containers &... cs)
Map operation over zipped tuples, returning a vector.
Definition ah-stl-zip.H:692
bool stl_zip_equal(const Containers &... cs)
Check equality of zipped sequences.
auto stl_zip_sum(const Containers &... cs)
Sum all tuples element-wise (requires + operator on tuple elements).
auto stl_zip_find_mapi(Op &&op, const Containers &... cs)
Find and map with index (find_mapi in ML).
auto stl_zip_assoc(const Key &key, const Containers &... cs)
Find value associated with key in zipped pairs (assoc in ML).
auto stl_zip_filter(Pred &&pred, const Containers &... cs)
Filter zipped tuples by predicate.
Definition ah-stl-zip.H:716
auto stl_unzip(const std::vector< std::pair< T, U > > &pairs)
Unzip a vector of pairs into two vectors.
auto stl_zip_drop(const size_t n, const Containers &... cs)
Skip first n tuples, return the rest.
Definition ah-stl-zip.H:860
T stl_zip_foldl(T init, Op &&op, const Containers &... cs)
Left fold over zipped tuples.
Definition ah-stl-zip.H:648
auto stl_zip_min(const Containers &... cs)
Get minimum tuple according to comparator.
T stl_zip_reduce(T init, Op &&op, const Containers &... cs)
Alias for stl_zip_foldl (alternative name)
Definition ah-stl-zip.H:658
auto stl_zip_nth(const size_t n, const Containers &... cs)
Get n-th tuple from zipped containers.
Definition ah-stl-zip.H:815
auto stl_adjacent(const Container &c)
Zip adjacent (consecutive) elements of a container.
auto stl_zip_partition(Pred &&pred, const Containers &... cs)
Partition tuples by predicate.
Definition ah-stl-zip.H:891
constexpr auto stl_zip(const Containers &... cs)
Create a lazy zip view over STL containers.
Definition ah-stl-zip.H:421
auto stl_zip_take(const size_t n, const Containers &... cs)
Take first n tuples from zipped containers.
Definition ah-stl-zip.H:837
auto stl_zip_last(const Containers &... cs)
Get last tuple from zipped containers.
size_t stl_zip_length(const Containers &... cs)
Count total tuples (minimum length of containers).
Definition ah-stl-zip.H:778
bool stl_zip_traverse_eq(Pred &&pred, const Containers &... cs)
Traverse while predicate returns true, verify equal lengths.
Definition ah-stl-zip.H:966
static std::atomic< bool > init
Definition hash-fct.C:54
void stl_zip_for_each(Op &&op, const Containers &... cs)
Apply operation to each zipped tuple (for side effects).
Definition ah-stl-zip.H:594
auto stl_zip_to_vector(const Containers &... cs)
Materialize zipped tuples into a vector.
Definition ah-stl-zip.H:919
void stl_zip_for_each_indexed(Op &&op, const Containers &... cs)
Apply operation to each tuple with its index.
Definition ah-stl-zip.H:610
bool stl_zip_all(Pred &&pred, const Containers &... cs)
Check if predicate holds for all zipped tuples.
Definition ah-stl-zip.H:479
@ Tuple
Tuple type such as (Int, Bool).
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
bool stl_zip_any(Pred &&pred, const Containers &... cs)
Alias for stl_zip_exists (Python/JS style name)
Definition ah-stl-zip.H:546
T sum(const Container &container, const T &init=T{})
Compute sum of all elements.
STL namespace.
Construct end iterator (all at end).
Definition ah-stl-zip.H:211