33# ifndef AH_ZIP_UTILS_H
34# define AH_ZIP_UTILS_H
36# include <type_traits>
89namespace uni_zip_detail
93template <
typename T,
typename =
void>
98 decltype(std::declval<const T&>().begin()),
99 decltype(std::declval<const T&>().end()),
100 typename T::value_type
101>> : std::true_type {};
105template <
typename T,
typename =
void>
110 typename T::Iterator,
111 typename T::Item_Type,
112 decltype(std::declval<typename T::Iterator>().has_curr()),
113 decltype(std::declval<typename T::Iterator>().get_curr()),
114 decltype(std::declval<typename T::Iterator>().next_ne())
115>> : std::true_type {};
118template <
typename T,
typename =
void>
124 using type =
typename T::value_type;
129 has_aleph_iterator<T>::value && !has_stl_iterator<T>::value>>
131 using type = std::decay_t<typename T::Item_Type>;
144template <
typename Container>
147 typename std::decay_t<Container>::const_iterator
curr_;
148 typename std::decay_t<Container>::const_iterator
end_;
151 using value_type =
typename std::decay_t<Container>::value_type;
165template <
typename Container>
168 typename std::decay_t<Container>::Iterator
it_;
171 using value_type = std::decay_t<typename std::decay_t<Container>::Item_Type>;
185template <
typename Container,
typename =
void>
189template <
typename Container>
191 std::
enable_if_t<has_stl_iterator<std::decay_t<Container>>::value>>
197template <
typename Container>
200 has_aleph_iterator<std::decay_t<Container>>::value &&
201 !has_stl_iterator<std::decay_t<Container>>::value>>
206template <
typename Container>
249 static_assert((uni_zip_detail::is_supported_container_v<Containers> && ...),
250 "All containers must have either STL (begin/end) or Aleph (Iterator) interface");
253 using value_type = std::tuple<uni_zip_detail::container_value_t<Containers>...>;
256 std::tuple<uni_zip_detail::iterator_wrapper_t<Containers>...>
iters_;
258 template <
size_t...
Is>
264 template <
size_t...
Is>
270 template <
size_t...
Is>
276 template <
size_t...
Is>
282 template <
size_t...
Is>
285 (std::get<Is>(
iters_).next(), ...);
297 return has_curr_impl(std::make_index_sequence<num_containers>{});
320 return get_curr_impl(std::make_index_sequence<num_containers>{});
325 next_impl(std::make_index_sequence<num_containers>{});
345 return !(*
this == s);
357 return !(*
this ==
other);
384 return std::apply([](
const auto&...
cs) {
404 for (
auto it =
begin(); it !=
end(); ++it)
436 static_assert(
sizeof...(Containers) >= 2,
437 "uni_zip requires at least 2 containers");
474 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
491 for (; it.has_curr(); it.next())
494 return it.all_completed();
511 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
549 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
567 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next(), ++idx)
568 op_ref(idx, it.get_curr());
587 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
613 using ResultType = std::decay_t<decltype(op(std::declval<TupleType>()))>;
616 std::vector<ResultType> result;
617 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
618 result.push_back(
op_ref(it.get_curr()));
638 std::vector<TupleType> result;
639 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
641 auto t = it.get_curr();
664 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
666 auto t = it.get_curr();
668 return std::optional<TupleType>(t);
670 return std::optional<TupleType>{};
684 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
700 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
715 while (it.has_curr())
717 return it.all_completed();
732 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next(), ++i)
734 return std::optional<TupleType>(it.get_curr());
735 return std::optional<TupleType>{};
749 std::vector<TupleType> result;
753 result.push_back(it.get_curr());
768 std::vector<TupleType> result;
771 for (
size_t i = 0; i < n && it.has_curr(); ++i)
774 for (; it.has_curr(); it.next())
775 result.push_back(it.get_curr());
791 std::vector<TupleType> result;
792 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
794 auto t = it.get_curr();
814 std::vector<TupleType> result;
817 for (; it.has_curr() &&
pred_ref(it.get_curr()); it.next())
820 for (; it.has_curr(); it.next())
821 result.push_back(it.get_curr());
848 std::optional<TupleType> result;
849 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
867 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
869 auto t = it.get_curr();
889 std::vector<TupleType> result;
890 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
891 result.push_back(it.get_curr());
905 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
929 using ResultType = std::decay_t<
decltype(op(
size_t{}, std::declval<TupleType>()))>;
932 std::vector<ResultType> result;
934 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next(), ++idx)
935 result.push_back(
op_ref(idx, it.get_curr()));
955 std::vector<TupleType> result;
957 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next(), ++idx)
959 auto t = it.get_curr();
981 std::vector<T> result;
982 result.push_back(
init);
985 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
988 result.push_back(
acc);
1007 using OptType = std::decay_t<
decltype(op(
size_t{}, std::declval<TupleType>()))>;
1011 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next(), ++idx)
1013 auto result =
op_ref(idx, it.get_curr());
1030template <
typename Eq,
typename...
Containers>
1035 for (; it.has_curr(); it.next())
1036 if (!
eq_ref(it.get_curr()))
1038 return it.all_completed();
1054 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
1055 if (it.get_curr() ==
target)
1070template <
typename Key,
typename...
Containers>
1075 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
1078 if (std::get<0>(t) == key)
1079 return std::optional<TupleType>(t);
1081 return std::optional<TupleType>{};
1100 return std::optional<TupleType>{};
1105 for (; it.has_curr(); it.next())
1107 auto t = it.get_curr();
1111 return std::optional<TupleType>(
min_val);
1130 return std::optional<TupleType>{};
1135 for (; it.has_curr(); it.next())
1137 auto t = it.get_curr();
1141 return std::optional<TupleType>(
max_val);
1157 using ResultType = std::optional<std::pair<TupleType, TupleType>>;
1167 for (; it.has_curr(); it.next())
1169 auto t = it.get_curr();
1207template <
typename Container>
1211 using T1 = std::decay_t<decltype(std::declval<PairType>().first)>;
1212 using T2 = std::decay_t<decltype(std::declval<PairType>().second)>;
1219 for (
const auto& p : c)
1227 for (
auto it = c.get_it(); it.has_curr(); it.next_ne())
1229 const auto& p = it.get_curr();
1235 return std::make_pair(std::move(
firsts), std::move(
seconds));
1238namespace uni_unzip_detail
1241template <
typename Tuple,
size_t...
Is>
1244 return std::make_tuple(
DynList<std::tuple_element_t<Is, Tuple>>()...);
1250 ((std::get<Is>(result).append(std::get<Is>(t))), ...);
1276template <
typename Container>
1280 constexpr size_t N = std::tuple_size_v<TupleType>;
1282 auto result = uni_unzip_detail::make_dynlist_tuple<TupleType>(
1283 std::make_index_sequence<N>{});
1287 for (
const auto& t : c)
1289 std::make_index_sequence<N>{});
1293 for (
auto it = c.get_it(); it.has_curr(); it.next_ne())
1295 std::make_index_sequence<N>{});
1318 for (
auto it =
uni_zip_it(
cs...); it.has_curr(); it.next())
1319 result.
append(it.get_curr());
Dynamic singly linked list with functional programming support.
T & append(const T &item)
Append a new item by copy.
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
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
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_
std::decay_t< Container >::const_iterator end_
bool has_curr() const noexcept
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.
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.
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.
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