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
255 // STL iterator interface
256
261 [[nodiscard]] constexpr auto operator*() const
262 {
263 return get_curr();
264 }
265
271 {
272 next();
273 return *this;
274 }
275
280 constexpr StlZipIterator operator++(int) noexcept
281 {
282 auto tmp = *this;
283 next();
284 return tmp;
285 }
286
291 [[nodiscard]] constexpr bool operator==(const StlZipIterator & other) const noexcept
292 {
293 return not has_curr() and not other.has_curr();
294 }
295
297 [[nodiscard]] constexpr bool operator!=(const StlZipIterator & other) const noexcept
298 {
299 return not (*this == other);
300 }
301 };
302
322 template <typename... Containers>
324 {
325 std::tuple<const std::decay_t<Containers> &...> containers_;
326
327 public:
331
336 explicit constexpr StlZipView(const Containers &... cs)
337 : containers_(cs...) {}
338
343 [[nodiscard]] constexpr iterator begin() const
344 {
345 return std::apply([](const auto &... cs)
346 {
347 return iterator(cs...);
348 }, containers_);
349 }
350
355 [[nodiscard]] constexpr iterator end() const
356 {
357 return std::apply([](const auto &... cs)
358 {
359 return iterator(cs..., typename iterator::end_tag{});
360 }, containers_);
361 }
362
367 [[nodiscard]] constexpr bool empty() const
368 {
369 return not begin().has_curr();
370 }
371
377 [[nodiscard]] size_t size() const
378 {
379 size_t count = 0;
380 for (auto it = begin(); it.has_curr(); it.next())
381 ++count;
382 return count;
383 }
384 };
385
386 // ============================================================================
387 // Factory Functions
388 // ============================================================================
389
413 template <typename... Containers>
414 [[nodiscard]] constexpr auto stl_zip(const Containers &... cs)
415 {
416 static_assert(sizeof...(Containers) >= 2, "stl_zip requires at least 2 containers");
417 return StlZipView<Containers...>(cs...);
418 }
419
432 template <typename... Containers>
433 [[nodiscard]] constexpr auto stl_zip_it(const Containers &... cs)
434 {
436 }
437
438 // ============================================================================
439 // Functional Operations - Aleph Style
440 // ============================================================================
441
471 template <typename Pred, typename... Containers>
472 [[nodiscard]] bool stl_zip_all(Pred && pred, const Containers &... cs)
473 {
474 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
475 if (not std::forward<Pred>(pred)(it.get_curr()))
476 return false;
477 return true;
478 }
479
492 template <typename Pred, typename... Containers>
494 {
495 auto it = stl_zip_it(cs...);
496 for (; it.has_curr(); it.next())
497 if (not std::forward<Pred>(pred)(it.get_curr()))
498 return false;
499 return it.completed();
500 }
501
528 template <typename Pred, typename... Containers>
530 {
531 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
532 if (std::forward<Pred>(pred)(it.get_curr()))
533 return true;
534 return false;
535 }
536
538 template <typename Pred, typename... Containers>
539 [[nodiscard]] bool stl_zip_any(Pred && pred, const Containers &... cs)
540 {
541 return stl_zip_exists(std::forward<Pred>(pred), cs...);
542 }
543
557 template <typename Pred, typename... Containers>
558 [[nodiscard]] bool stl_zip_none(Pred && pred, const Containers &... cs)
559 {
560 return not stl_zip_exists(std::forward<Pred>(pred), cs...);
561 }
562
586 template <typename Op, typename... Containers>
587 void stl_zip_for_each(Op && op, const Containers &... cs)
588 {
589 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
590 std::forward<Op>(op)(it.get_curr());
591 }
592
602 template <typename Op, typename... Containers>
603 void stl_zip_for_each_indexed(Op && op, const Containers &... cs)
604 {
605 size_t idx = 0;
606 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next(), ++idx)
607 std::forward<Op>(op)(idx, it.get_curr());
608 }
609
640 template <typename T, typename Op, typename... Containers>
641 [[nodiscard]] T stl_zip_foldl(T init, Op && op, const Containers &... cs)
642 {
643 T acc = std::move(init);
644 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
645 acc = std::forward<Op>(op)(std::move(acc), it.get_curr());
646 return acc;
647 }
648
650 template <typename T, typename Op, typename... Containers>
651 [[nodiscard]] T stl_zip_reduce(T init, Op && op, const Containers &... cs)
652 {
653 return stl_zip_foldl(std::move(init), std::forward<Op>(op), cs...);
654 }
655
684 template <typename Op, typename... Containers>
685 [[nodiscard]] auto stl_zip_map(Op && op, const Containers &... cs)
686 {
687 using TupleType = decltype(stl_zip_it(cs...).get_curr());
688 using ResultType = std::decay_t<decltype(std::forward<Op>(op)(std::declval<TupleType>()))>;
689
690 std::vector<ResultType> result;
691 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
692 result.push_back(std::forward<Op>(op)(it.get_curr()));
693 return result;
694 }
695
708 template <typename Pred, typename... Containers>
710 {
711 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
712
713 std::vector<TupleType> result;
714 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
715 if (auto t = it.get_curr(); std::forward<Pred>(pred)(t))
716 result.push_back(t);
717 return result;
718 }
719
730 template <typename Pred, typename... Containers>
732 {
733 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
734
735 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
736 if (auto t = it.get_curr(); std::forward<Pred>(pred)(t))
737 return std::optional<TupleType>(t);
738 return std::optional<TupleType>{};
739 }
740
751 template <typename Pred, typename... Containers>
752 [[nodiscard]] size_t stl_zip_count(Pred && pred, const Containers &... cs)
753 {
754 size_t count = 0;
755 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
756 if (std::forward<Pred>(pred)(it.get_curr()))
757 ++count;
758 return count;
759 }
760
770 template <typename... Containers>
771 [[nodiscard]] size_t stl_zip_length(const Containers &... cs)
772 {
773 size_t count = 0;
774 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
775 ++count;
776 return count;
777 }
778
788 template <typename... Containers>
790 {
791 auto it = stl_zip_it(cs...);
792 while (it.has_curr())
793 it.next();
794 return it.completed();
795 }
796
807 template <typename... Containers>
808 [[nodiscard]] auto stl_zip_nth(const size_t n, const Containers &... cs)
809 {
810 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
811
812 size_t i = 0;
813 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next(), ++i)
814 if (i == n)
815 return std::optional<TupleType>(it.get_curr());
816 return std::optional<TupleType>{};
817 }
818
829 template <typename... Containers>
830 [[nodiscard]] auto stl_zip_take(const size_t n, const Containers &... cs)
831 {
832 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
833
834 std::vector<TupleType> result;
835 result.reserve(n);
836 size_t count = 0;
837 for (auto it = stl_zip_it(cs...); it.has_curr() and count < n; it.next(), ++count)
838 result.push_back(it.get_curr());
839 return result;
840 }
841
852 template <typename... Containers>
853 [[nodiscard]] auto stl_zip_drop(const size_t n, const Containers &... cs)
854 {
855 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
856
857 std::vector<TupleType> result;
858 auto it = stl_zip_it(cs...);
859
860 // Skip first n
861 for (size_t i = 0; i < n and it.has_curr(); ++i)
862 it.next();
863
864 // Collect rest
865 for (; it.has_curr(); it.next())
866 result.push_back(it.get_curr());
867 return result;
868 }
869
883 template <typename Pred, typename... Containers>
885 {
886 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
887
888 std::vector<TupleType> matching, non_matching;
889 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
890 if (auto t = it.get_curr(); std::forward<Pred>(pred)(t))
891 matching.push_back(t);
892 else
893 non_matching.push_back(t);
894 return std::make_pair(std::move(matching), std::move(non_matching));
895 }
896
911 template <typename... Containers>
913 {
914 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
915
916 std::vector<TupleType> result;
917 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
918 result.push_back(it.get_curr());
919 return result;
920 }
921
922 // ============================================================================
923 // Traverse operations (like zip_traverse in ah-zip.H)
924 // ============================================================================
925
939 template <typename Pred, typename... Containers>
941 {
942 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
943 if (not std::forward<Pred>(pred)(it.get_curr()))
944 return false;
945 return true;
946 }
947
958 template <typename Pred, typename... Containers>
960 {
961 auto it = stl_zip_it(cs...);
962 for (; it.has_curr(); it.next())
963 if (not std::forward<Pred>(pred)(it.get_curr()))
964 return false;
965 return it.completed();
966 }
967
968 // ============================================================================
969 // Comparison helpers
970 // ============================================================================
971
972 namespace stl_zip_detail
973 {
974 // Compare adjacent elements in a tuple
975 template <typename Cmp, typename Tuple, size_t... Is>
976 bool compare_adjacent_impl(Cmp & cmp, const Tuple & t, std::index_sequence<Is...>)
977 {
978 return (... and cmp(std::get<Is>(t), std::get<Is + 1>(t)));
979 }
980 }
981
1007 template <typename Cmp, typename... Containers>
1008 [[nodiscard]] bool stl_zip_cmp(Cmp && cmp, const Containers &... cs)
1009 {
1010 static_assert(sizeof...(Containers) >= 2, "stl_zip_cmp requires at least 2 containers");
1011
1012 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1013 {
1014 constexpr size_t N = sizeof...(Containers);
1015 if (auto t = it.get_curr(); not
1016 stl_zip_detail::compare_adjacent_impl(cmp, t, std::make_index_sequence<N - 1>{}))
1017 return false;
1018 }
1019 return true;
1020 }
1021
1022 // ============================================================================
1023 // Enumerate - like Python's enumerate()
1024 // ============================================================================
1025
1038 template <typename Container>
1040 {
1041 public:
1042 using iterator_category = std::input_iterator_tag;
1043 using difference_type = std::ptrdiff_t;
1044 using value_type = std::tuple<size_t, typename std::decay_t<Container>::value_type>;
1045
1046 private:
1047 typename std::decay_t<Container>::const_iterator curr_;
1048 typename std::decay_t<Container>::const_iterator end_;
1049 size_t index_ = 0;
1050
1051 public:
1052 explicit constexpr StlEnumerateIterator(const Container & c)
1053 : curr_(c.begin()), end_(c.end()), index_(0) {}
1054
1055 struct end_tag
1056 {};
1057
1059 : curr_(c.end()), end_(c.end()), index_(0) {}
1060
1061 [[nodiscard]] constexpr bool has_curr() const noexcept { return curr_ != end_; }
1062
1063 [[nodiscard]] constexpr auto get_curr() const { return std::make_tuple(index_, *curr_); }
1064
1065 constexpr void next() noexcept
1066 {
1067 ++curr_;
1068 ++index_;
1069 }
1070
1071 [[nodiscard]] constexpr auto operator*() const { return get_curr(); }
1072
1074 {
1075 next();
1076 return *this;
1077 }
1078
1079 [[nodiscard]] constexpr bool operator==(const StlEnumerateIterator & other) const noexcept
1080 {
1081 return not has_curr() and not other.has_curr();
1082 }
1083
1084 [[nodiscard]] constexpr bool operator!=(const StlEnumerateIterator & other) const noexcept
1085 {
1086 return not (*this == other);
1087 }
1088 };
1089
1098 template <typename Container>
1100 {
1101 const std::decay_t<Container> & container_;
1102
1103 public:
1105
1106 explicit constexpr StlEnumerateView(const Container & c) : container_(c) {}
1107
1108 [[nodiscard]] constexpr iterator begin() const { return iterator(container_); }
1109
1110 [[nodiscard]] constexpr iterator end() const
1111 {
1112 return iterator(container_, typename iterator::end_tag{});
1113 }
1114 };
1115
1139 template <typename Container>
1140 [[nodiscard]] constexpr auto stl_enumerate(const Container & c)
1141 {
1143 }
1144
1145 // ============================================================================
1146 // Take while / Drop while
1147 // ============================================================================
1148
1174 template <typename Pred, typename... Containers>
1176 {
1177 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1178
1179 std::vector<TupleType> result;
1180 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1181 {
1182 auto t = it.get_curr();
1183 if (not std::forward<Pred>(pred)(t))
1184 break;
1185 result.push_back(t);
1186 }
1187 return result;
1188 }
1189
1203 template <typename Pred, typename... Containers>
1205 {
1206 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1207
1208 std::vector<TupleType> result;
1209 auto it = stl_zip_it(cs...);
1210
1211 // Skip while pred is true
1212 for (; it.has_curr() and std::forward<Pred>(pred)(it.get_curr()); it.next())
1213 /* skip */;
1214
1215 // Collect the rest
1216 for (; it.has_curr(); it.next())
1217 result.push_back(it.get_curr());
1218 return result;
1219 }
1220
1221 // ============================================================================
1222 // First / Last convenience functions
1223 // ============================================================================
1224
1234 template <typename... Containers>
1236 {
1237 return stl_zip_nth(0, cs...);
1238 }
1239
1251 template <typename... Containers>
1253 {
1254 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1255
1256 std::optional<TupleType> result;
1257 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1258 result = it.get_curr();
1259 return result;
1260 }
1261
1272 template <typename Pred, typename... Containers>
1274 {
1275 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1276
1277 std::optional<TupleType> result;
1278 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1279 {
1280 auto t = it.get_curr();
1281 if (std::forward<Pred>(pred)(t))
1282 result = t;
1283 }
1284 return result;
1285 }
1286
1297 template <typename Pred, typename... Containers>
1299 {
1300 size_t idx = 0;
1301 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next(), ++idx)
1302 if (std::forward<Pred>(pred)(it.get_curr()))
1303 return idx;
1304 return idx;
1305 }
1306
1307 // ============================================================================
1308 // Unzip - inverse of zip
1309 // ============================================================================
1310
1329 template <typename T, typename U>
1330 [[nodiscard]] auto stl_unzip(const std::vector<std::pair<T, U>> & pairs)
1331 {
1332 std::vector<T> firsts;
1333 std::vector<U> seconds;
1334 firsts.reserve(pairs.size());
1335 seconds.reserve(pairs.size());
1336
1337 for (const auto & [f, s]: pairs)
1338 {
1339 firsts.push_back(f);
1340 seconds.push_back(s);
1341 }
1342 return std::make_pair(std::move(firsts), std::move(seconds));
1343 }
1344
1365 template <typename... Ts>
1366 [[nodiscard]] auto stl_unzip_tuple(const std::vector<std::tuple<Ts...>> & tuples)
1367 {
1368 std::tuple<std::vector<Ts>...> result;
1369
1370 // Reserve space in each vector
1371 std::apply([&tuples](auto &... vecs)
1372 {
1373 (vecs.reserve(tuples.size()), ...);
1374 }, result);
1375
1376 // Populate vectors
1377 for (const auto & t: tuples)
1378 {
1379 std::apply([&t](auto &... vecs)
1380 {
1381 std::apply([&vecs...](const auto &... elems)
1382 {
1383 (vecs.push_back(elems), ...);
1384 }, t);
1385 }, result);
1386 }
1387
1388 return result;
1389 }
1390
1391 // ============================================================================
1392 // Adjacent - zip consecutive elements of same container
1393 // ============================================================================
1394
1418 template <typename Container>
1420 {
1421 using T = typename std::decay_t<Container>::value_type;
1422 std::vector<std::pair<T, T>> result;
1423
1424 auto it = c.begin();
1425 if (it == c.end())
1426 return result;
1427
1428 auto prev = *it;
1429 ++it;
1430
1431 for (; it != c.end(); ++it)
1432 {
1433 result.emplace_back(prev, *it);
1434 prev = *it;
1435 }
1436 return result;
1437 }
1438
1456 template <typename Op, typename Container>
1457 [[nodiscard]] auto stl_adjacent_map(Op && op, const Container & c)
1458 {
1459 using T = typename std::decay_t<Container>::value_type;
1460 using R = std::decay_t<decltype(std::forward<Op>(op)(std::declval<T>(), std::declval<T>()))>;
1461
1462 std::vector<R> result;
1463
1464 auto it = c.begin();
1465 if (it == c.end())
1466 return result;
1467
1468 auto prev = *it;
1469 ++it;
1470
1471 for (; it != c.end(); ++it)
1472 {
1473 result.push_back(std::forward<Op>(op)(prev, *it));
1474 prev = *it;
1475 }
1476 return result;
1477 }
1478
1479 // ============================================================================
1480 // Pairwise operations on single container
1481 // ============================================================================
1482
1500 template <typename Pred, typename Container>
1502 {
1503 auto it = c.begin();
1504 if (it == c.end())
1505 return true;
1506
1507 auto prev = *it;
1508 ++it;
1509
1510 for (; it != c.end(); ++it)
1511 {
1512 if (not std::forward<Pred>(pred)(prev, *it))
1513 return false;
1514 prev = *it;
1515 }
1516 return true;
1517 }
1518
1529 template <typename Pred, typename Container>
1531 {
1532 auto it = c.begin();
1533 if (it == c.end())
1534 return false;
1535
1536 auto prev = *it;
1537 ++it;
1538
1539 for (; it != c.end(); ++it)
1540 {
1541 if (std::forward<Pred>(pred)(prev, *it))
1542 return true;
1543 prev = *it;
1544 }
1545 return false;
1546 }
1547
1548 // ============================================================================
1549 // ML-style Additional Operations
1550 // ============================================================================
1551
1571 template <typename Op, typename... Containers>
1572 [[nodiscard]] auto stl_zip_mapi(Op && op, const Containers &... cs)
1573 {
1574 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1575 using ResultType = std::decay_t<decltype(std::forward<Op>(op)(size_t{}, std::declval<TupleType>()))>;
1576
1577 std::vector<ResultType> result;
1578 size_t idx = 0;
1579 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next(), ++idx)
1580 result.push_back(std::forward<Op>(op)(idx, it.get_curr()));
1581 return result;
1582 }
1583
1596 template <typename Pred, typename... Containers>
1598 {
1599 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1600
1601 std::vector<TupleType> result;
1602 size_t idx = 0;
1603 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next(), ++idx)
1604 if (auto t = it.get_curr(); std::forward<Pred>(pred)(idx, t))
1605 result.push_back(t);
1606 return result;
1607 }
1608
1630 template <typename T, typename Op, typename... Containers>
1631 [[nodiscard]] auto stl_zip_scan_left(T init, Op && op, const Containers &... cs)
1632 {
1633 std::vector<T> result;
1634 result.push_back(init);
1635
1636 T acc = std::move(init);
1637 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1638 {
1639 acc = std::forward<Op>(op)(std::move(acc), it.get_curr());
1640 result.push_back(acc);
1641 }
1642 return result;
1643 }
1644
1657 template <typename Op, typename... Containers>
1658 [[nodiscard]] auto stl_zip_find_mapi(Op && op, const Containers &... cs)
1659 {
1660 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1661 using OptType = std::decay_t<decltype(std::forward<Op>(op)(size_t{}, std::declval<TupleType>()))>;
1662
1663 size_t idx = 0;
1664 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next(), ++idx)
1665 if (auto result = std::forward<Op>(op)(idx, it.get_curr()))
1666 return result;
1667 return OptType{};
1668 }
1669
1682 template <typename... Containers>
1684 {
1685 // For a single zip, check if all containers have equal length
1686 auto it = stl_zip_it(cs...);
1687 while (it.has_curr())
1688 it.next();
1689 return it.completed();
1690 }
1691
1702 template <typename Eq, typename... Containers>
1703 [[nodiscard]] bool stl_zip_equal_by(Eq && eq, const Containers &... cs)
1704 {
1705 auto it = stl_zip_it(cs...);
1706 for (; it.has_curr(); it.next())
1707 if (not std::forward<Eq>(eq)(it.get_curr()))
1708 return false;
1709 return it.completed();
1710 }
1711
1726 template <typename... Containers1, typename... Containers2>
1728 const std::tuple<const Containers1 &...> & cs1,
1729 const std::tuple<const Containers2 &...> & cs2)
1730 {
1731 auto it1 = std::apply([](const auto &... cs) { return stl_zip_it(cs...); }, cs1);
1732 auto it2 = std::apply([](const auto &... cs) { return stl_zip_it(cs...); }, cs2);
1733
1734 while (it1.has_curr() and it2.has_curr())
1735 {
1736 auto t1 = it1.get_curr();
1737 auto t2 = it2.get_curr();
1738 if (t1 < t2) return -1;
1739 if (t2 < t1) return 1;
1740 it1.next();
1741 it2.next();
1742 }
1743
1744 if (it1.has_curr()) return 1; // first is longer
1745 if (it2.has_curr()) return -1; // second is longer
1746 return 0; // equal
1747 }
1748
1759 template <typename Tuple, typename... Containers>
1760 [[nodiscard]] bool stl_zip_mem(const Tuple & target, const Containers &... cs)
1761 {
1762 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1763 if (it.get_curr() == target)
1764 return true;
1765 return false;
1766 }
1767
1780 template <typename Key, typename... Containers>
1781 [[nodiscard]] auto stl_zip_assoc(const Key & key, const Containers &... cs)
1782 {
1783 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1784
1785 for (auto it = stl_zip_it(cs...); it.has_curr(); it.next())
1786 if (auto t = it.get_curr(); std::get<0>(t) == key)
1787 return std::optional<TupleType>(t);
1788 return std::optional<TupleType>{};
1789 }
1790
1800 template <typename... Containers>
1801 [[nodiscard]] auto stl_zip_min(const Containers &... cs)
1802 {
1803 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1804
1805 auto it = stl_zip_it(cs...);
1806 if (not it.has_curr())
1807 return std::optional<TupleType>{};
1808
1809 TupleType min_val = it.get_curr();
1810 it.next();
1811
1812 for (; it.has_curr(); it.next())
1813 {
1814 auto t = it.get_curr();
1815 if (t < min_val)
1816 min_val = t;
1817 }
1818 return std::optional<TupleType>(min_val);
1819 }
1820
1830 template <typename... Containers>
1831 [[nodiscard]] auto stl_zip_max(const Containers &... cs)
1832 {
1833 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1834
1835 auto it = stl_zip_it(cs...);
1836 if (not it.has_curr())
1837 return std::optional<TupleType>{};
1838
1839 TupleType max_val = it.get_curr();
1840 it.next();
1841
1842 for (; it.has_curr(); it.next())
1843 {
1844 auto t = it.get_curr();
1845 if (t > max_val)
1846 max_val = t;
1847 }
1848 return std::optional<TupleType>(max_val);
1849 }
1850
1860 template <typename... Containers>
1862 {
1863 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1864 using ResultType = std::optional<std::pair<TupleType, TupleType>>;
1865
1866 auto it = stl_zip_it(cs...);
1867 if (not it.has_curr())
1868 return ResultType{};
1869
1870 TupleType min_val = it.get_curr();
1872 it.next();
1873
1874 for (; it.has_curr(); it.next())
1875 {
1876 auto t = it.get_curr();
1877 if (t < min_val) min_val = t;
1878 if (t > max_val) max_val = t;
1879 }
1880 return ResultType(std::make_pair(min_val, max_val));
1881 }
1882
1894 template <typename... Containers>
1895 [[nodiscard]] auto stl_zip_sum(const Containers &... cs)
1896 {
1897 using TupleType = typename StlZipIterator<std::decay_t<Containers>...>::value_type;
1898
1899 auto it = stl_zip_it(cs...);
1900 if (not it.has_curr())
1901 return std::optional<TupleType>{};
1902
1903 TupleType sum = it.get_curr();
1904 it.next();
1905
1906 for (; it.has_curr(); it.next())
1907 {
1908 auto t = it.get_curr();
1909 std::apply([&t](auto &... sum_elems)
1910 {
1911 size_t i = 0;
1912 ((sum_elems = sum_elems + std::get<decltype(i){}>(t), ++i), ...);
1913 }, sum);
1914 }
1915 return std::optional<TupleType>(sum);
1916 }
1917} // end namespace Aleph
1918
1919# endif // AH_STL_ZIP_H
size_t size() const noexcept
Count the number of elements of the list.
Definition htlist.H:1319
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
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 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:280
IteratorTuple iters_
Definition ah-stl-zip.H:163
constexpr bool operator!=(const StlZipIterator &other) const noexcept
Inequality comparison.
Definition ah-stl-zip.H:297
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:261
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:270
constexpr bool operator==(const StlZipIterator &other) const noexcept
Equality comparison.
Definition ah-stl-zip.H:291
Lazy view over multiple zipped STL containers.
Definition ah-stl-zip.H:324
std::tuple< const std::decay_t< Containers > &... > containers_
Definition ah-stl-zip.H:325
StlZipIterator< std::decay_t< Containers >... > iterator
Definition ah-stl-zip.H:328
size_t size() const
Get number of tuples (minimum size of all containers).
Definition ah-stl-zip.H:377
constexpr iterator begin() const
Get iterator to beginning.
Definition ah-stl-zip.H:343
typename iterator::value_type value_type
Definition ah-stl-zip.H:330
constexpr StlZipView(const Containers &... cs)
Construct view from containers.
Definition ah-stl-zip.H:336
constexpr bool empty() const
Check if view is empty.
Definition ah-stl-zip.H:367
constexpr iterator end() const
Get iterator to end.
Definition ah-stl-zip.H:355
#define N
Definition fib.C:294
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4118
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:976
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:433
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:529
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:940
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:493
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:752
bool stl_zip_equal_length(const Containers &... cs)
Check if all containers have equal length.
Definition ah-stl-zip.H:789
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:731
bool stl_zip_mem(const Tuple &target, const Containers &... cs)
Check if a tuple exists in the zipped sequence (mem in ML).
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:107
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:558
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:685
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:709
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:853
T stl_zip_foldl(T init, Op &&op, const Containers &... cs)
Left fold over zipped tuples.
Definition ah-stl-zip.H:641
static bool init
Definition hash-fct.C:47
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:651
auto stl_zip_nth(const size_t n, const Containers &... cs)
Get n-th tuple from zipped containers.
Definition ah-stl-zip.H:808
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:884
constexpr auto stl_zip(const Containers &... cs)
Create a lazy zip view over STL containers.
Definition ah-stl-zip.H:414
auto stl_zip_take(const size_t n, const Containers &... cs)
Take first n tuples from zipped containers.
Definition ah-stl-zip.H:830
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:771
bool stl_zip_traverse_eq(Pred &&pred, const Containers &... cs)
Traverse while predicate returns true, verify equal lengths.
Definition ah-stl-zip.H:959
void stl_zip_for_each(Op &&op, const Containers &... cs)
Apply operation to each zipped tuple (for side effects).
Definition ah-stl-zip.H:587
auto stl_zip_to_vector(const Containers &... cs)
Materialize zipped tuples into a vector.
Definition ah-stl-zip.H:912
void stl_zip_for_each_indexed(Op &&op, const Containers &... cs)
Apply operation to each tuple with its index.
Definition ah-stl-zip.H:603
bool stl_zip_all(Pred &&pred, const Containers &... cs)
Check if predicate holds for all zipped tuples.
Definition ah-stl-zip.H:472
DynList< T > maps(const C &c, Op op)
Classic map operation.
Itor::difference_type count(const Itor &beg, const Itor &end, const T &value)
Count elements equal to a value.
Definition ahAlgo.H:127
bool stl_zip_any(Pred &&pred, const Containers &... cs)
Alias for stl_zip_exists (Python/JS style name)
Definition ah-stl-zip.H:539
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