Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
ah-zip-utils.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_UTILS_H
34# define AH_ZIP_UTILS_H
35
36# include <type_traits>
37# include <tuple>
38# include <iterator>
39# include <utility>
40# include <optional>
41# include <functional>
42# include <ah-concepts.H>
43
83namespace Aleph
84{
85
86// ============================================================================
87// Type Traits for Container Detection
88// ============================================================================
89
90namespace uni_zip_detail
91{
92
93// Detect if type has STL-style begin()/end()
94template <typename T>
95struct has_stl_iterator : std::bool_constant<StlIterableContainer<T>> {};
96
97// Detect if type has Aleph-style Iterator with has_curr()/get_curr()/next_ne()
98// Note: We check for next_ne() which is the non-exception-throwing variant used in Aleph
99template <typename T>
100struct has_aleph_iterator : std::bool_constant<AlephIterable<T>> {};
101
102// Get value type from container
103template <typename T, typename = void>
105
106template <typename T>
107struct container_value_type<T, std::enable_if_t<has_stl_iterator<T>::value>>
108{
109 using type = typename T::value_type;
110};
111
112template <typename T>
114 has_aleph_iterator<T>::value && !has_stl_iterator<T>::value>>
115{
116 using type = std::decay_t<typename T::Item_Type>;
117};
118
119template <typename T>
121
122// ============================================================================
123// Unified Iterator Wrapper
124// ============================================================================
125
129template <typename Container>
131{
132 typename std::decay_t<Container>::const_iterator curr_;
133 typename std::decay_t<Container>::const_iterator end_;
134
135public:
136 using value_type = typename std::decay_t<Container>::value_type;
137
138 explicit StlIteratorWrapper(const Container& c)
139 : curr_(c.begin()), end_(c.end()) {}
140
141 [[nodiscard]] bool has_curr() const noexcept { return curr_ != end_; }
142 [[nodiscard]] bool completed() const noexcept { return curr_ == end_; }
143 [[nodiscard]] auto get_curr() const { return *curr_; }
144 void next() noexcept { ++curr_; }
145
151 void next_ne() noexcept { next(); }
152};
153
157template <typename Container>
159{
160 // mutable: the wrapper's const accessors forward to the Aleph iterator,
161 // whose get_curr() may be non-const (e.g. the chained hash tables).
162 mutable typename std::decay_t<Container>::Iterator it_;
163
164public:
165 using value_type = std::decay_t<typename std::decay_t<Container>::Item_Type>;
166
168 : it_(c) {}
169
170 [[nodiscard]] bool has_curr() const noexcept { return it_.has_curr(); }
171 [[nodiscard]] bool completed() const noexcept { return !it_.has_curr(); }
172 [[nodiscard]] auto get_curr() const { return it_.get_curr(); }
173 void next() { it_.next_ne(); }
174
180 void next_ne() { next(); }
181};
182
186template <typename Container, typename = void>
188
189// STL containers (prefer STL if both interfaces exist)
190template <typename Container>
192 std::enable_if_t<has_stl_iterator<std::decay_t<Container>>::value>>
193{
195};
196
197// Aleph-only containers (no STL interface)
198template <typename Container>
201 has_aleph_iterator<std::decay_t<Container>>::value &&
202 !has_stl_iterator<std::decay_t<Container>>::value>>
203{
205};
206
207template <typename Container>
209
210// Static assertion helper for unsupported container types
211template <typename T>
212inline constexpr bool is_supported_container_v =
215
216} // namespace uni_zip_detail
217
218// ============================================================================
219// Sentinel type for O(1) end()
220// ============================================================================
221
229
230// ============================================================================
231// Unified Zip Iterator
232// ============================================================================
233
247template <typename... Containers>
249{
250 static_assert((uni_zip_detail::is_supported_container_v<Containers> && ...),
251 "All containers must have either STL (begin/end) or Aleph (Iterator) interface");
252
253public:
254 using value_type = std::tuple<uni_zip_detail::container_value_t<Containers>...>;
255
256private:
257 std::tuple<uni_zip_detail::iterator_wrapper_t<Containers>...> iters_;
258
259 template <size_t... Is>
260 [[nodiscard]] bool has_curr_impl(std::index_sequence<Is...>) const noexcept
261 {
262 return (... && std::get<Is>(iters_).has_curr());
263 }
264
265 template <size_t... Is>
266 [[nodiscard]] bool any_has_curr_impl(std::index_sequence<Is...>) const noexcept
267 {
268 return (... || std::get<Is>(iters_).has_curr());
269 }
270
271 template <size_t... Is>
272 [[nodiscard]] bool all_completed_impl(std::index_sequence<Is...>) const noexcept
273 {
274 return (... && std::get<Is>(iters_).completed());
275 }
276
277 template <size_t... Is>
278 [[nodiscard]] auto get_curr_impl(std::index_sequence<Is...>) const
279 {
280 return std::make_tuple(std::get<Is>(iters_).get_curr()...);
281 }
282
283 template <size_t... Is>
284 void next_impl(std::index_sequence<Is...>)
285 {
286 (std::get<Is>(iters_).next(), ...);
287 }
288
289public:
290 static constexpr size_t num_containers = sizeof...(Containers);
291
292 explicit UniZipIterator(const Containers&... cs)
293 : iters_(uni_zip_detail::iterator_wrapper_t<Containers>(cs)...) {}
294
297 {
298 return has_curr_impl(std::make_index_sequence<num_containers>{});
299 }
300
303 {
304 return any_has_curr_impl(std::make_index_sequence<num_containers>{});
305 }
306
309 {
310 return all_completed_impl(std::make_index_sequence<num_containers>{});
311 }
312
315 {
316 return all_completed();
317 }
318
319 [[nodiscard]] auto get_curr() const
320 {
321 return get_curr_impl(std::make_index_sequence<num_containers>{});
322 }
323
324 void next()
325 {
326 next_impl(std::make_index_sequence<num_containers>{});
327 }
328
334 void next_ne() { next(); }
335
336 // STL iterator interface for range-based for
337 [[nodiscard]] auto operator*() const { return get_curr(); }
338
340 {
341 next();
342 return *this;
343 }
344
346 [[nodiscard]] bool operator==(UniZipSentinel) const noexcept
347 {
348 return !has_curr();
349 }
350
351 [[nodiscard]] bool operator!=(UniZipSentinel s) const noexcept
352 {
353 return !(*this == s);
354 }
355
357 [[nodiscard]] bool operator==(const UniZipIterator& other) const noexcept
358 {
359 // Both at end (any container exhausted)
360 return !has_curr() && !other.has_curr();
361 }
362
363 [[nodiscard]] bool operator!=(const UniZipIterator& other) const noexcept
364 {
365 return !(*this == other);
366 }
367};
368
377template <typename... Containers>
379{
380 std::tuple<const std::decay_t<Containers>&...> containers_;
381
382public:
386
387 explicit UniZipView(const Containers&... cs)
388 : containers_(cs...) {}
389
391 {
392 return std::apply([](const auto&... cs) {
393 return iterator(cs...);
394 }, containers_);
395 }
396
399 {
400 return sentinel{};
401 }
402
403 [[nodiscard]] bool empty() const
404 {
405 return !begin().has_curr();
406 }
407
409 [[nodiscard]] size_t size() const
410 {
411 size_t count = 0;
412 for (auto it = begin(); it != end(); ++it)
413 ++count;
414 return count;
415 }
416};
417
418// ============================================================================
419// Factory Functions
420// ============================================================================
421
441template <typename... Containers>
442[[nodiscard]] auto uni_zip(const Containers&... cs)
443{
444 static_assert(sizeof...(Containers) >= 2,
445 "uni_zip requires at least 2 containers");
446 return UniZipView<Containers...>(cs...);
447}
448
458template <typename... Containers>
460{
462}
463
464// ============================================================================
465// Functional Operations
466// ============================================================================
467
478template <typename Pred, typename... Containers>
480{
481 auto& pred_ref = pred; // Preserve as lvalue to avoid invalidating in loop
482 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
483 if (!pred_ref(it.get_curr()))
484 return false;
485 return true;
486}
487
494template <typename Pred, typename... Containers>
496{
497 auto& pred_ref = pred;
498 auto it = uni_zip_it(cs...);
499 for (; it.has_curr(); it.next())
500 if (!pred_ref(it.get_curr()))
501 return false;
502 return it.all_completed(); // All containers exhausted = equal length
503}
504
515template <typename Pred, typename... Containers>
517{
518 auto& pred_ref = pred;
519 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
520 if (pred_ref(it.get_curr()))
521 return true;
522 return false;
523}
524
526template <typename Pred, typename... Containers>
528{
529 return uni_zip_exists(std::forward<Pred>(pred), cs...);
530}
531
538template <typename Pred, typename... Containers>
540{
541 return !uni_zip_exists(std::forward<Pred>(pred), cs...);
542}
543
553template <typename Op, typename... Containers>
554void uni_zip_for_each(Op&& op, const Containers&... cs)
555{
556 auto& op_ref = op;
557 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
558 op_ref(it.get_curr());
559}
560
570template <typename Op, typename... Containers>
571void uni_zip_for_each_indexed(Op&& op, const Containers&... cs)
572{
573 auto& op_ref = op;
574 size_t idx = 0;
575 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next(), ++idx)
576 op_ref(idx, it.get_curr());
577}
578
590template <typename T, typename Op, typename... Containers>
591[[nodiscard]] T uni_zip_foldl(T init, Op&& op, const Containers&... cs)
592{
593 auto& op_ref = op;
594 T acc = std::move(init);
595 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
596 acc = op_ref(std::move(acc), it.get_curr());
597 return acc;
598}
599
601template <typename T, typename Op, typename... Containers>
602[[nodiscard]] T uni_zip_reduce(T init, Op&& op, const Containers&... cs)
603{
604 return uni_zip_foldl(std::move(init), std::forward<Op>(op), cs...);
605}
606
617template <typename Op, typename... Containers>
618[[nodiscard]] auto uni_zip_map(Op&& op, const Containers&... cs)
619{
620 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
621 using ResultType = std::decay_t<decltype(op(std::declval<TupleType>()))>;
622
623 auto& op_ref = op;
624 std::vector<ResultType> result;
625 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
626 result.push_back(op_ref(it.get_curr()));
627 return result;
628}
629
640template <typename Pred, typename... Containers>
642{
643 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
644
645 auto& pred_ref = pred;
646 std::vector<TupleType> result;
647 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
648 {
649 auto t = it.get_curr();
650 if (pred_ref(t))
651 result.push_back(t);
652 }
653 return result;
654}
655
666template <typename Pred, typename... Containers>
668{
669 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
670
671 auto& pred_ref = pred;
672 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
673 {
674 auto t = it.get_curr();
675 if (pred_ref(t))
676 return std::optional<TupleType>(t);
677 }
678 return std::optional<TupleType>{};
679}
680
687template <typename Pred, typename... Containers>
689{
690 auto& pred_ref = pred;
691 size_t count = 0;
692 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
693 if (pred_ref(it.get_curr()))
694 ++count;
695 return count;
696}
697
704template <typename... Containers>
706{
707 size_t count = 0;
708 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
709 ++count;
710 return count;
711}
712
719template <typename... Containers>
721{
722 auto it = uni_zip_it(cs...);
723 while (it.has_curr())
724 it.next();
725 return it.all_completed(); // All exhausted = equal length
726}
727
734template <typename... Containers>
735[[nodiscard]] auto uni_zip_nth(size_t n, const Containers&... cs)
736{
737 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
738
739 size_t i = 0;
740 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next(), ++i)
741 if (i == n)
742 return std::optional<TupleType>(it.get_curr());
743 return std::optional<TupleType>{};
744}
745
752template <typename... Containers>
753[[nodiscard]] auto uni_zip_take(size_t n, const Containers&... cs)
754{
755 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
756
757 std::vector<TupleType> result;
758 result.reserve(n);
759 size_t count = 0;
760 for (auto it = uni_zip_it(cs...); it.has_curr() && count < n; it.next(), ++count)
761 result.push_back(it.get_curr());
762 return result;
763}
764
771template <typename... Containers>
772[[nodiscard]] auto uni_zip_drop(size_t n, const Containers&... cs)
773{
774 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
775
776 std::vector<TupleType> result;
777 auto it = uni_zip_it(cs...);
778
779 for (size_t i = 0; i < n && it.has_curr(); ++i)
780 it.next();
781
782 for (; it.has_curr(); it.next())
783 result.push_back(it.get_curr());
784 return result;
785}
786
793template <typename Pred, typename... Containers>
795{
796 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
797
798 auto& pred_ref = pred;
799 std::vector<TupleType> result;
800 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
801 {
802 auto t = it.get_curr();
803 if (!pred_ref(t))
804 break;
805 result.push_back(t);
806 }
807 return result;
808}
809
816template <typename Pred, typename... Containers>
818{
819 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
820
821 auto& pred_ref = pred;
822 std::vector<TupleType> result;
823 auto it = uni_zip_it(cs...);
824
825 for (; it.has_curr() && pred_ref(it.get_curr()); it.next())
826 /* skip */;
827
828 for (; it.has_curr(); it.next())
829 result.push_back(it.get_curr());
830 return result;
831}
832
839template <typename... Containers>
841{
842 return uni_zip_nth(0, cs...);
843}
844
851template <typename... Containers>
853{
854 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
855
856 std::optional<TupleType> result;
857 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
858 result = it.get_curr();
859 return result;
860}
861
868template <typename Pred, typename... Containers>
870{
871 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
872
873 auto& pred_ref = pred;
874 std::vector<TupleType> matching, non_matching;
875 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
876 {
877 auto t = it.get_curr();
878 if (pred_ref(t))
879 matching.push_back(t);
880 else
881 non_matching.push_back(t);
882 }
883 return std::make_pair(std::move(matching), std::move(non_matching));
884}
885
892template <typename... Containers>
894{
895 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
896
897 std::vector<TupleType> result;
898 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
899 result.push_back(it.get_curr());
900 return result;
901}
902
909template <typename Pred, typename... Containers>
911{
912 auto& pred_ref = pred;
913 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
914 if (!pred_ref(it.get_curr()))
915 return false;
916 return true;
917}
918
919// ============================================================================
920// ML-style Additional Operations
921// ============================================================================
922
933template <typename Op, typename... Containers>
934[[nodiscard]] auto uni_zip_mapi(Op&& op, const Containers&... cs)
935{
936 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
937 using ResultType = std::decay_t<decltype(op(size_t{}, std::declval<TupleType>()))>;
938
939 auto& op_ref = op;
940 std::vector<ResultType> result;
941 size_t idx = 0;
942 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next(), ++idx)
943 result.push_back(op_ref(idx, it.get_curr()));
944 return result;
945}
946
957template <typename Pred, typename... Containers>
959{
960 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
961
962 auto& pred_ref = pred;
963 std::vector<TupleType> result;
964 size_t idx = 0;
965 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next(), ++idx)
966 {
967 auto t = it.get_curr();
968 if (pred_ref(idx, t))
969 result.push_back(t);
970 }
971 return result;
972}
973
985template <typename T, typename Op, typename... Containers>
986[[nodiscard]] auto uni_zip_scan_left(T init, Op&& op, const Containers&... cs)
987{
988 auto& op_ref = op;
989 std::vector<T> result;
990 result.push_back(init);
991
992 T acc = std::move(init);
993 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
994 {
995 acc = op_ref(std::move(acc), it.get_curr());
996 result.push_back(acc);
997 }
998 return result;
999}
1000
1011template <typename Op, typename... Containers>
1012[[nodiscard]] auto uni_zip_find_mapi(Op&& op, const Containers&... cs)
1013{
1014 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
1015 using OptType = std::decay_t<decltype(op(size_t{}, std::declval<TupleType>()))>;
1016
1017 auto& op_ref = op;
1018 size_t idx = 0;
1019 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next(), ++idx)
1020 {
1021 auto result = op_ref(idx, it.get_curr());
1022 if (result)
1023 return result;
1024 }
1025 return OptType{};
1026}
1027
1038template <typename Eq, typename... Containers>
1039[[nodiscard]] bool uni_zip_equal_by(Eq&& eq, const Containers&... cs)
1040{
1041 auto& eq_ref = eq;
1042 auto it = uni_zip_it(cs...);
1043 for (; it.has_curr(); it.next())
1044 if (!eq_ref(it.get_curr()))
1045 return false;
1046 return it.all_completed(); // All exhausted = equal length
1047}
1048
1059template <typename Tuple, typename... Containers>
1060[[nodiscard]] bool uni_zip_mem(const Tuple& target, const Containers&... cs)
1061{
1062 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
1063 if (it.get_curr() == target)
1064 return true;
1065 return false;
1066}
1067
1078template <typename Key, typename... Containers>
1079[[nodiscard]] auto uni_zip_assoc(const Key& key, const Containers&... cs)
1080{
1081 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
1082
1083 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
1084 {
1085 auto t = it.get_curr();
1086 if (std::get<0>(t) == key)
1087 return std::optional<TupleType>(t);
1088 }
1089 return std::optional<TupleType>{};
1090}
1091
1101template <typename... Containers>
1103{
1104 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
1105
1106 auto it = uni_zip_it(cs...);
1107 if (!it.has_curr())
1108 return std::optional<TupleType>{};
1109
1110 TupleType min_val = it.get_curr();
1111 it.next();
1112
1113 for (; it.has_curr(); it.next())
1114 {
1115 auto t = it.get_curr();
1116 if (t < min_val)
1117 min_val = t;
1118 }
1119 return std::optional<TupleType>(min_val);
1120}
1121
1131template <typename... Containers>
1133{
1134 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
1135
1136 auto it = uni_zip_it(cs...);
1137 if (!it.has_curr())
1138 return std::optional<TupleType>{};
1139
1140 TupleType max_val = it.get_curr();
1141 it.next();
1142
1143 for (; it.has_curr(); it.next())
1144 {
1145 auto t = it.get_curr();
1146 if (t > max_val)
1147 max_val = t;
1148 }
1149 return std::optional<TupleType>(max_val);
1150}
1151
1161template <typename... Containers>
1163{
1164 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
1165 using ResultType = std::optional<std::pair<TupleType, TupleType>>;
1166
1167 auto it = uni_zip_it(cs...);
1168 if (!it.has_curr())
1169 return ResultType{};
1170
1171 TupleType min_val = it.get_curr();
1172 TupleType max_val = min_val;
1173 it.next();
1174
1175 for (; it.has_curr(); it.next())
1176 {
1177 auto t = it.get_curr();
1178 if (t < min_val) min_val = t;
1179 if (t > max_val) max_val = t;
1180 }
1181 return ResultType(std::make_pair(min_val, max_val));
1182}
1183
1184// ============================================================================
1185// Unzip Operations (returns DynList for mixed containers)
1186// ============================================================================
1187
1188} // end namespace Aleph
1189
1190// Need DynList for unzip operations
1191# include <htlist.H>
1192
1193namespace Aleph
1194{
1195
1215template <typename Container>
1217{
1219 using T1 = std::decay_t<decltype(std::declval<PairType>().first)>;
1220 using T2 = std::decay_t<decltype(std::declval<PairType>().second)>;
1221
1224
1226 {
1227 for (const auto& p : c)
1228 {
1229 firsts.append(p.first);
1230 seconds.append(p.second);
1231 }
1232 }
1233 else
1234 {
1235 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
1236 {
1237 const auto& p = it.get_curr();
1238 firsts.append(p.first);
1239 seconds.append(p.second);
1240 }
1241 }
1242
1243 return std::make_pair(std::move(firsts), std::move(seconds));
1244}
1245
1246namespace uni_unzip_detail
1247{
1248
1249template <typename Tuple, size_t... Is>
1250auto make_dynlist_tuple(std::index_sequence<Is...>)
1251{
1252 return std::make_tuple(DynList<std::tuple_element_t<Is, Tuple>>()...);
1253}
1254
1255template <typename Tuple, typename ResultTuple, size_t... Is>
1256void append_tuple_elements(const Tuple& t, ResultTuple& result, std::index_sequence<Is...>)
1257{
1258 ((std::get<Is>(result).append(std::get<Is>(t))), ...);
1259}
1260
1261} // namespace uni_unzip_detail
1262
1284template <typename Container>
1286{
1288 constexpr size_t N = std::tuple_size_v<TupleType>;
1289
1290 auto result = uni_unzip_detail::make_dynlist_tuple<TupleType>(
1291 std::make_index_sequence<N>{});
1292
1294 {
1295 for (const auto& t : c)
1297 std::make_index_sequence<N>{});
1298 }
1299 else
1300 {
1301 for (auto it = c.get_it(); it.has_curr(); it.next_ne())
1302 uni_unzip_detail::append_tuple_elements(it.get_curr(), result,
1303 std::make_index_sequence<N>{});
1304 }
1305
1306 return result;
1307}
1308
1320template <typename... Containers>
1322{
1323 using TupleType = typename UniZipIterator<std::decay_t<Containers>...>::value_type;
1324
1325 DynList<TupleType> result;
1326 for (auto it = uni_zip_it(cs...); it.has_curr(); it.next())
1327 result.append(it.get_curr());
1328 return result;
1329}
1330
1331} // end namespace Aleph
1332
1333# endif // AH_ZIP_UTILS_H
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
size_t size_t int32_t value
Definition ca-c-api.h:116
Doubly-linked list (defined in tpl_dynList.H).
Definition htlist.H:1155
T & append(const T &item)
Definition htlist.H:1271
Iterator that traverses multiple containers (STL or Aleph) in lockstep.
std::tuple< uni_zip_detail::container_value_t< Containers >... > value_type
std::tuple< uni_zip_detail::iterator_wrapper_t< Containers >... > iters_
UniZipIterator(const Containers &... cs)
bool all_completed() const noexcept
Returns true if ALL containers are exhausted (equal length check)
bool any_has_curr() const noexcept
Returns true if ANY container still has elements (for length checking)
static constexpr size_t num_containers
auto get_curr_impl(std::index_sequence< Is... >) const
bool any_has_curr_impl(std::index_sequence< Is... >) const noexcept
bool has_curr_impl(std::index_sequence< Is... >) const noexcept
bool operator!=(const UniZipIterator &other) const noexcept
void next_ne()
Advance without checking; same as next(), which does not check.
bool operator==(const UniZipIterator &other) const noexcept
Comparison with another iterator (for algorithms that need it)
bool has_curr() const noexcept
Returns true if ALL containers have current element (zip continues)
void next_impl(std::index_sequence< Is... >)
bool operator==(UniZipSentinel) const noexcept
Comparison with sentinel - iterator is "at end" when any container exhausted.
bool completed() const noexcept
bool operator!=(UniZipSentinel s) const noexcept
bool all_completed_impl(std::index_sequence< Is... >) const noexcept
UniZipIterator & operator++()
Lazy view over multiple zipped containers (STL or Aleph).
size_t size() const
Note: O(n) - iterates through all elements to count.
iterator begin() const
bool empty() const
UniZipView(const Containers &... cs)
std::tuple< const std::decay_t< Containers > &... > containers_
UniZipIterator< std::decay_t< Containers >... > iterator
typename iterator::value_type value_type
sentinel end() const noexcept
O(1) end() using sentinel.
Wrapper that provides uniform interface for Aleph iterators.
std::decay_t< Container >::Iterator it_
void next_ne()
Advance without checking; same as next(), which does not check.
std::decay_t< typename std::decay_t< Container >::Item_Type > value_type
Wrapper that provides uniform interface for STL iterators.
typename std::decay_t< Container >::value_type value_type
std::decay_t< Container >::const_iterator curr_
void next_ne() noexcept
Advance without checking; same as next(), which does not check.
std::decay_t< Container >::const_iterator end_
#define N
Definition fib.C:294
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
Singly linked list implementations with head-tail access.
Freq_Node * pred
Predecessor node in level-order traversal.
void append_tuple_elements(const Tuple &t, ResultTuple &result, std::index_sequence< Is... >)
auto make_dynlist_tuple(std::index_sequence< Is... >)
typename IteratorWrapperSelector< Container >::type iterator_wrapper_t
typename container_value_type< std::decay_t< T > >::type container_value_t
constexpr bool is_supported_container_v
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
bool eq(const C1 &c1, const C2 &c2, Eq e=Eq())
Check equality of two containers using a predicate.
bool uni_zip_traverse(Pred &&pred, const Containers &... cs)
Traverse while predicate returns true.
auto uni_zip_scan_left(T init, Op &&op, const Containers &... cs)
Scan left - fold with intermediate results.
auto uni_zip(const Containers &... cs)
Create a lazy zip view over any combination of STL/Aleph containers.
auto uni_zip_take(size_t n, const Containers &... cs)
Take first n tuples.
bool uni_zip_equal_length(const Containers &... cs)
Check if all containers have equal length.
bool uni_zip_exists(Pred &&pred, const Containers &... cs)
Check if predicate holds for any zipped tuple.
auto uni_zip_to_vector(const Containers &... cs)
Materialize zipped tuples into a vector.
auto uni_zip_min_max(const Containers &... cs)
Get both min and max in a single pass.
bool uni_zip_none(Pred &&pred, const Containers &... cs)
Check if no tuple satisfies the predicate.
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:105
auto uni_zip_filteri(Pred &&pred, const Containers &... cs)
Filter with index (filteri in ML).
T uni_zip_foldl(T init, Op &&op, const Containers &... cs)
Left fold over zipped tuples.
size_t uni_zip_length(const Containers &... cs)
Get zip length (minimum of all container sizes).
auto uni_unzip_tuple(const Container &c)
Unzip a container of tuples into a tuple of DynLists.
auto uni_zip_mapi(Op &&op, const Containers &... cs)
Map with index (mapi in ML).
bool uni_zip_equal_by(Eq &&eq, const Containers &... cs)
Check equality with custom comparator.
auto uni_zip_last(const Containers &... cs)
Get last tuple.
auto uni_zip_partition(Pred &&pred, const Containers &... cs)
Partition tuples by predicate.
auto uni_zip_nth(size_t n, const Containers &... cs)
Get n-th tuple from zipped containers.
auto uni_zip_min(const Containers &... cs)
Get minimum tuple.
auto uni_unzip(const Container &c)
Unzip a container of pairs into two DynLists.
bool uni_zip_any(Pred &&pred, const Containers &... cs)
Alias for uni_zip_exists.
auto uni_zip_to_dynlist(const Containers &... cs)
Materialize a zipped view into a DynList of tuples.
void uni_zip_for_each(Op &&op, const Containers &... cs)
Apply operation to each zipped tuple.
auto uni_zip_max(const Containers &... cs)
Get maximum tuple.
auto uni_zip_assoc(const Key &key, const Containers &... cs)
Find value associated with key in zipped pairs (assoc in ML).
auto uni_zip_it(const Containers &... cs)
Get a unified zip iterator.
bool uni_zip_all(Pred &&pred, const Containers &... cs)
Check if predicate holds for all zipped tuples.
size_t uni_zip_count(Pred &&pred, const Containers &... cs)
Count tuples satisfying predicate.
auto uni_zip_first(const Containers &... cs)
Get first tuple.
auto uni_zip_drop_while(Pred &&pred, const Containers &... cs)
Skip tuples while predicate is true, return the rest.
auto uni_zip_find_mapi(Op &&op, const Containers &... cs)
Find and map with index (find_mapi in ML).
auto uni_zip_filter(Pred &&pred, const Containers &... cs)
Filter zipped tuples by predicate.
auto uni_zip_map(Op &&op, const Containers &... cs)
Map operation over zipped tuples.
T uni_zip_reduce(T init, Op &&op, const Containers &... cs)
Alias for uni_zip_foldl.
auto uni_zip_take_while(Pred &&pred, const Containers &... cs)
Take tuples while predicate is true.
auto uni_zip_drop(size_t n, const Containers &... cs)
Skip first n tuples, return the rest.
static std::atomic< bool > init
Definition hash-fct.C:54
bool uni_zip_all_eq(Pred &&pred, const Containers &... cs)
Check if all tuples satisfy predicate AND containers have equal length.
void uni_zip_for_each_indexed(Op &&op, const Containers &... cs)
Apply operation to each tuple with index.
auto uni_zip_find_first(Pred &&pred, const Containers &... cs)
Find first tuple satisfying predicate.
@ 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 uni_zip_mem(const Tuple &target, const Containers &... cs)
Check if a tuple exists in the zipped sequence (mem in ML).
STL namespace.
Sentinel type for UniZipIterator end comparison.
Select appropriate wrapper based on container type.