33# ifndef AH_ZIP_UTILS_H
34# define AH_ZIP_UTILS_H
36# include <type_traits>
90namespace uni_zip_detail
103template <
typename T,
typename =
void>
109 using type =
typename T::value_type;
114 has_aleph_iterator<T>::value && !has_stl_iterator<T>::value>>
116 using type = std::decay_t<typename T::Item_Type>;
129template <
typename Container>
132 typename std::decay_t<Container>::const_iterator
curr_;
133 typename std::decay_t<Container>::const_iterator
end_;
136 using value_type =
typename std::decay_t<Container>::value_type;
157template <
typename Container>
162 mutable typename std::decay_t<Container>::Iterator
it_;
165 using value_type = std::decay_t<typename std::decay_t<Container>::Item_Type>;
186template <
typename Container,
typename =
void>
190template <
typename Container>
192 std::
enable_if_t<has_stl_iterator<std::decay_t<Container>>::value>>
198template <
typename Container>
201 has_aleph_iterator<std::decay_t<Container>>::value &&
202 !has_stl_iterator<std::decay_t<Container>>::value>>
207template <
typename Container>
250 static_assert((uni_zip_detail::is_supported_container_v<Containers> && ...),
251 "All containers must have either STL (begin/end) or Aleph (Iterator) interface");
254 using value_type = std::tuple<uni_zip_detail::container_value_t<Containers>...>;
257 std::tuple<uni_zip_detail::iterator_wrapper_t<Containers>...>
iters_;
259 template <
size_t...
Is>
265 template <
size_t...
Is>
271 template <
size_t...
Is>
277 template <
size_t...
Is>
283 template <
size_t...
Is>
286 (std::get<Is>(
iters_).next(), ...);
298 return has_curr_impl(std::make_index_sequence<num_containers>{});
321 return get_curr_impl(std::make_index_sequence<num_containers>{});
326 next_impl(std::make_index_sequence<num_containers>{});
353 return !(*
this == s);
365 return !(*
this ==
other);
392 return std::apply([](
const auto&...
cs) {
412 for (
auto it =
begin(); it !=
end(); ++it)
444 static_assert(
sizeof...(Containers) >= 2,
445 "uni_zip requires at least 2 containers");
482 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
499 for (; it.has_curr(); it.next())
502 return it.all_completed();
519 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
557 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
575 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next(), ++idx)
576 op_ref(idx, it.get_curr());
590template <
typename T,
typename Op,
typename...
Containers>
595 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
601template <
typename T,
typename Op,
typename...
Containers>
621 using ResultType = std::decay_t<decltype(op(std::declval<TupleType>()))>;
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()));
646 std::vector<TupleType> result;
647 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
649 auto t = it.get_curr();
672 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
674 auto t = it.get_curr();
676 return std::optional<TupleType>(t);
678 return std::optional<TupleType>{};
692 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
708 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
723 while (it.has_curr())
725 return it.all_completed();
740 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next(), ++i)
742 return std::optional<TupleType>(it.get_curr());
743 return std::optional<TupleType>{};
757 std::vector<TupleType> result;
761 result.push_back(it.get_curr());
776 std::vector<TupleType> result;
779 for (
size_t i = 0; i < n && it.has_curr(); ++i)
782 for (; it.has_curr(); it.next())
783 result.push_back(it.get_curr());
799 std::vector<TupleType> result;
800 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
802 auto t = it.get_curr();
822 std::vector<TupleType> result;
825 for (; it.has_curr() &&
pred_ref(it.get_curr()); it.next())
828 for (; it.has_curr(); it.next())
829 result.push_back(it.get_curr());
856 std::optional<TupleType> result;
857 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
875 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
877 auto t = it.get_curr();
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());
913 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
937 using ResultType = std::decay_t<
decltype(op(
size_t{}, std::declval<TupleType>()))>;
940 std::vector<ResultType> result;
942 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next(), ++idx)
943 result.push_back(
op_ref(idx, it.get_curr()));
963 std::vector<TupleType> result;
965 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next(), ++idx)
967 auto t = it.get_curr();
985template <
typename T,
typename Op,
typename...
Containers>
989 std::vector<T> result;
990 result.push_back(
init);
993 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
996 result.push_back(
acc);
1011template <
typename Op,
typename...
Containers>
1015 using OptType = std::decay_t<
decltype(op(
size_t{}, std::declval<TupleType>()))>;
1019 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next(), ++idx)
1021 auto result =
op_ref(idx, it.get_curr());
1038template <
typename Eq,
typename...
Containers>
1043 for (; it.has_curr(); it.next())
1044 if (!
eq_ref(it.get_curr()))
1046 return it.all_completed();
1062 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
1063 if (it.get_curr() == target)
1078template <
typename Key,
typename...
Containers>
1083 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
1086 if (std::get<0>(t) == key)
1087 return std::optional<TupleType>(t);
1089 return std::optional<TupleType>{};
1108 return std::optional<TupleType>{};
1113 for (; it.has_curr(); it.next())
1115 auto t = it.get_curr();
1119 return std::optional<TupleType>(min_val);
1138 return std::optional<TupleType>{};
1143 for (; it.has_curr(); it.next())
1145 auto t = it.get_curr();
1149 return std::optional<TupleType>(max_val);
1165 using ResultType = std::optional<std::pair<TupleType, TupleType>>;
1175 for (; it.has_curr(); it.next())
1177 auto t = it.get_curr();
1178 if (t < min_val) min_val = t;
1179 if (t > max_val) max_val = t;
1181 return ResultType(std::make_pair(min_val, max_val));
1215template <
typename Container>
1219 using T1 = std::decay_t<decltype(std::declval<PairType>().first)>;
1220 using T2 = std::decay_t<decltype(std::declval<PairType>().second)>;
1227 for (
const auto& p : c)
1235 for (
auto it = c.get_it(); it.has_curr(); it.next_ne())
1237 const auto& p = it.get_curr();
1243 return std::make_pair(std::move(
firsts), std::move(
seconds));
1246namespace uni_unzip_detail
1249template <
typename Tuple,
size_t...
Is>
1252 return std::make_tuple(
DynList<std::tuple_element_t<Is, Tuple>>()...);
1258 ((std::get<Is>(result).append(std::get<Is>(t))), ...);
1284template <
typename Container>
1288 constexpr size_t N = std::tuple_size_v<TupleType>;
1290 auto result = uni_unzip_detail::make_dynlist_tuple<TupleType>(
1291 std::make_index_sequence<N>{});
1295 for (
const auto& t : c)
1297 std::make_index_sequence<N>{});
1301 for (
auto it = c.get_it(); it.has_curr(); it.next_ne())
1303 std::make_index_sequence<N>{});
1326 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
1327 result.
append(it.get_curr());
C++20 concepts hub: comparison, BST policy, and Aleph container concepts.
size_t size_t int32_t value
Doubly-linked list (defined in tpl_dynList.H).
T & append(const T &item)
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.
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_
bool completed() const noexcept
void next_ne()
Advance without checking; same as next(), which does not check.
AlephIteratorWrapper(const Container &c)
bool has_curr() const noexcept
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
StlIteratorWrapper(const Container &c)
bool completed() const noexcept
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_
bool has_curr() const noexcept
size_t blossom_maximum_cardinality_matching(const GT &g, DynDlist< typename GT::Arc * > &matching, SA sa=SA())
Alias of compute_maximum_cardinality_general_matching().
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.
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
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
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.
bool uni_zip_mem(const Tuple &target, const Containers &... cs)
Check if a tuple exists in the zipped sequence (mem in ML).
Sentinel type for UniZipIterator end comparison.
Select appropriate wrapper based on container type.
typename T::value_type type
std::decay_t< typename T::Item_Type > type