12 #ifndef HIPIPE_CORE_TUPLE_UTILS_HPP
13 #define HIPIPE_CORE_TUPLE_UTILS_HPP
15 #include <range/v3/core.hpp>
16 #include <range/v3/range/conversion.hpp>
17 #include <range/v3/range/primitives.hpp>
19 #include <experimental/tuple>
21 #include <type_traits>
24 namespace hipipe::utility {
38 template<
typename T1,
typename T2,
typename... Ts>
39 struct variadic_find : std::integral_constant<std::size_t, variadic_find<T1, Ts...>{}+1> {
42 template<
typename T,
typename... Ts>
43 struct variadic_find<T, T, Ts...> : std::integral_constant<std::size_t, 0> {
55 template<std::size_t N,
typename... Ts>
57 using type = std::tuple<Ts...>;
65 template<
typename... Ts>
66 using maybe_tuple =
typename maybe_tuple_impl<
sizeof...(Ts), Ts...>::type;
76 template<std::size_t Value, std::size_t... Is>
77 constexpr std::index_sequence<(Value + Is)...>
plus(std::index_sequence<Is...>)
90 template <std::
size_t Offset, std::
size_t N>
97 template<
typename Fun,
typename Tuple, std::size_t... Is>
98 constexpr Fun tuple_for_each_impl(Tuple&& tuple, Fun&& fun, std::index_sequence<Is...>)
100 (..., (std::invoke(fun, std::get<Is>(std::forward<Tuple>(tuple)))));
118 template<
typename Tuple,
typename Fun>
121 constexpr std::size_t tuple_size = std::tuple_size<std::decay_t<Tuple>>::value;
122 return detail::tuple_for_each_impl(std::forward<Tuple>(tuple),
123 std::forward<Fun>(fun),
124 std::make_index_sequence<tuple_size>{});
131 template<
typename Tuple,
typename Fun, std::size_t... Is>
132 constexpr
auto tuple_transform_impl(Tuple&& tuple, Fun&& fun, std::index_sequence<Is...>)
134 return std::make_tuple(std::invoke(fun, std::get<Is>(std::forward<Tuple>(tuple)))...);
153 template<
typename Tuple,
typename Fun>
156 constexpr std::size_t tuple_size = std::tuple_size<std::decay_t<Tuple>>::value;
157 return detail::tuple_transform_impl(std::forward<Tuple>(tuple),
158 std::forward<Fun>(fun),
159 std::make_index_sequence<tuple_size>{});
164 template<
typename T,
typename Tuple =
void>
167 template<
typename T,
typename... Types>
169 : std::disjunction<std::is_same<std::decay_t<T>, std::decay_t<Types>>...> {
174 template<
typename Tuple,
size_t... Is>
175 std::ostream&
tuple_print(std::ostream& out,
const Tuple& tuple, std::index_sequence<Is...>)
178 (..., (out << (Is == 0 ?
"" :
", ") << std::get<Is>(tuple)));
185 template<
typename... Ts>
186 std::ostream&
operator<<(std::ostream& out,
const std::tuple<Ts...>& tuple)
196 template<
typename Tuple, std::size_t... Is>
197 auto vectorize_tuple(std::index_sequence<Is...>)
199 return std::make_tuple(std::vector<std::tuple_element_t<Is, std::decay_t<Tuple>>>()...);
203 template<
typename ToR,
typename Tuple, std::size_t... Is>
204 void push_unzipped(ToR& tuple_of_ranges, Tuple&& tuple, std::index_sequence<Is...>)
206 (..., (std::get<Is>(tuple_of_ranges).push_back(std::get<Is>(std::forward<Tuple>(tuple)))));
210 CPP_template(
class Rng)(requires ranges::sized_range<Rng>)
211 std::size_t safe_reserve_size(Rng&& rng)
213 return ranges::size(rng);
215 CPP_template(
class Rng)(requires !ranges::sized_range<Rng>)
216 std::size_t safe_reserve_size(Rng&& rng)
221 template<
typename Rng>
222 auto unzip_impl(Rng& range_of_tuples)
224 using tuple_type = ranges::range_value_t<Rng>;
225 constexpr
auto tuple_size = std::tuple_size<tuple_type>{};
226 constexpr
auto indices = std::make_index_sequence<tuple_size>{};
227 std::size_t reserve_size = detail::safe_reserve_size(range_of_tuples);
229 auto tuple_of_ranges = detail::vectorize_tuple<tuple_type>(indices);
231 tuple_of_ranges, [reserve_size](
auto& rng) { rng.reserve(reserve_size); });
233 for (
auto& v : range_of_tuples) {
234 detail::push_unzipped(tuple_of_ranges, std::move(v), indices);
237 return tuple_of_ranges;
256 CPP_template(
class Rng)(requires ranges::range<Rng> && !ranges::view_<Rng>)
257 auto unzip(Rng range_of_tuples)
260 return detail::unzip_impl(range_of_tuples);
265 auto unzip(Rng view_of_tuples)
267 return utility::unzip(ranges::to_vector(view_of_tuples));
274 template<
bool Enable>
277 template<
typename Rng>
278 static decltype(
auto) impl(Rng&& rng)
280 return utility::unzip(std::forward<Rng>(rng));
285 struct unzip_if_impl<false>
287 template<
typename Rng>
288 static Rng&& impl(Rng&& rng)
290 return std::forward<Rng>(rng);
316 template<
bool Enable,
typename RangeT>
317 decltype(
auto)
unzip_if(RangeT&& range)
319 return detail::unzip_if_impl<Enable>::impl(std::forward<RangeT>(range));
326 template<std::
size_t Size>
327 struct maybe_untuple_impl
329 template<
typename Tuple>
330 static Tuple&& impl(Tuple&& tuple)
332 return std::forward<Tuple>(tuple);
337 struct maybe_untuple_impl<1>
339 template<
typename Tuple>
340 static decltype(
auto) impl(Tuple&& tuple)
342 return std::get<0>(std::forward<Tuple>(tuple));
370 template<
typename Tuple>
373 constexpr std::size_t tuple_size = std::tuple_size<std::decay_t<Tuple>>::value;
374 return detail::maybe_untuple_impl<tuple_size>::impl(std::forward<Tuple>(tuple));
381 template<
typename Fun, std::size_t... Is>
382 constexpr Fun times_with_index_impl(Fun&& fun, std::index_sequence<Is...>)
384 (..., (std::invoke(fun, std::integral_constant<std::size_t, Is>{})));
402 template<std::
size_t N,
typename Fun>
405 return detail::times_with_index_impl(std::forward<Fun>(fun), std::make_index_sequence<N>{});
421 template <
typename Tuple,
typename Fun>
424 return utility::times_with_index<std::tuple_size<std::decay_t<Tuple>>{}>(
425 [&fun, &tuple](
auto index) {
426 std::invoke(fun, std::get<index>(tuple), index);
434 template <
typename Fun,
typename Tuple, std::size_t... Is>
435 constexpr
auto tuple_transform_with_index_impl(Tuple&& tuple, Fun&& fun,
436 std::index_sequence<Is...>)
438 return std::make_tuple(std::invoke(fun, std::get<Is>(std::forward<Tuple>(tuple)),
439 std::integral_constant<std::size_t, Is>{})...);
457 template <
typename Tuple,
typename Fun>
460 return detail::tuple_transform_with_index_impl(
461 std::forward<Tuple>(tuple), std::forward<Fun>(fun),
462 std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>{}>{});