13 #include <hipipe/build_config.hpp>
14 #include <hipipe/core/stream/stream_t.hpp>
15 #include <hipipe/core/stream/template_arguments.hpp>
16 #include <hipipe/core/utility/ndim.hpp>
17 #include <hipipe/core/utility/random.hpp>
18 #include <hipipe/core/utility/tuple.hpp>
20 #include <range/v3/range/conversion.hpp>
21 #include <range/v3/view/any_view.hpp>
22 #include <range/v3/view/transform.hpp>
23 #include <range/v3/view/zip.hpp>
28 namespace hipipe::stream {
30 namespace rgv = ranges::views;
37 template<
typename Fun,
typename From,
typename To>
38 struct partial_transform_impl;
40 template<
typename Fun,
typename... FromTypes,
typename... ToTypes>
41 struct partial_transform_impl<Fun, from_t<FromTypes...>, to_t<ToTypes...>> {
44 batch_t operator()(batch_t source)
47 std::tuple<
typename FromTypes::data_type&...> slice_view{
51 static_assert(std::is_invocable_v<Fun&, decltype(slice_view)&&>,
52 "hipipe::stream::partial_transform: "
53 "Cannot apply the given function to the given `from<>` columns.");
54 static_assert(std::is_invocable_r_v<
55 std::tuple<typename ToTypes::data_type...>, Fun&, decltype(slice_view)&&>,
56 "hipipe::stream::partial_transform: "
57 "The function return type does not correspond to the tuple of the "
58 "selected `to<>` columns.");
59 std::tuple<
typename ToTypes::data_type...> result =
60 std::invoke(fun, std::move(slice_view));
63 using Column = std::tuple_element_t<i, std::tuple<ToTypes...>>;
64 source.insert_or_assign<Column>(std::move(std::get<i>(result)));
70 class partial_transform_fn {
72 friend rgv::view_access;
74 template <
typename From,
typename To,
typename Fun>
75 static auto bind(partial_transform_fn transformer, From f, To t, Fun fun)
77 return ranges::make_pipeable(
78 std::bind(transformer, std::placeholders::_1, f, t, std::move(fun)));
82 template <
typename... FromTypes,
typename... ToTypes,
typename Fun>
86 static_assert(
sizeof...(ToTypes) > 0,
87 "For non-transforming operations, please use stream::for_each.");
89 detail::partial_transform_impl<Fun, from_t<FromTypes...>, to_t<ToTypes...>>
90 trans_fun{std::move(fun)};
107 inline rgv::view<detail::partial_transform_fn> partial_transform{};
116 template <
typename DestTuple,
typename SourceTuple>
117 DestTuple convert_tuple_of_ranges(SourceTuple rngs)
119 static_assert(std::tuple_size_v<SourceTuple> == std::tuple_size_v<DestTuple>);
121 using DestType = std::tuple_element_t<index, DestTuple>;
122 return ranges::to<DestType>(rgv::move(rng));
127 template<
typename Fun, std::
size_t Dim,
typename From,
typename To>
128 struct wrap_fun_for_dim;
130 template<
typename Fun, std::size_t Dim,
typename... FromTypes,
typename... ToTypes>
131 struct wrap_fun_for_dim<Fun, Dim, from_t<FromTypes...>, to_t<ToTypes...>> {
133 using FunRef = decltype(std::ref(fun));
135 utility::maybe_tuple<ToTypes...>
136 operator()(std::tuple<FromTypes&...> tuple_of_ranges)
140 wrap_fun_for_dim<FunRef, Dim-1,
141 from_t<ranges::range_value_t<FromTypes>...>,
142 to_t<ranges::range_value_t<ToTypes>...>>
143 fun_wrapper{std::ref(fun)};
145 auto trans_view_of_tuples =
147 std::apply(rgv::zip, std::move(tuple_of_ranges)),
148 std::move(fun_wrapper));
150 if constexpr (
sizeof...(ToTypes) > 1) {
151 auto trans_tuple_of_vectors =
152 utility::unzip(std::move(trans_view_of_tuples));
153 return convert_tuple_of_ranges<std::tuple<ToTypes...>>(
154 std::move(trans_tuple_of_vectors));
157 return ranges::to<ToTypes...>(std::move(trans_view_of_tuples));
162 template<
typename Fun,
typename... FromTypes,
typename... ToTypes>
163 struct wrap_fun_for_dim<Fun, 0, from_t<FromTypes...>, to_t<ToTypes...>> {
166 utility::maybe_tuple<ToTypes...>
167 operator()(std::tuple<FromTypes&...> tuple)
169 static_assert(std::is_invocable_v<Fun&, FromTypes&...>,
170 "hipipe::stream::transform: "
171 "Cannot call the given function on the selected from<> columns.");
172 if constexpr(
sizeof...(ToTypes) == 1) {
173 static_assert(std::is_invocable_r_v<
174 ToTypes..., Fun&, FromTypes&...>,
175 "hipipe::stream::transform: "
176 "The function does not return the selected to<> column.");
178 static_assert(std::is_invocable_r_v<
179 std::tuple<ToTypes...>, Fun&, FromTypes&...>,
180 "hipipe::stream::transform: "
181 "The function does not return the tuple of the selected to<> columns.");
183 return std::apply(fun, std::move(tuple));
211 template<
typename... FromColumns,
typename... ToColumns,
typename Fun,
int Dim = 1>
213 from_t<FromColumns...> f,
214 to_t<ToColumns...> t,
216 dim_t<Dim> d = dim_t<1>{})
221 "hipipe::stream::transform: The dimension in which to apply the operation needs"
222 " to be at most the lowest dimension of all the from<> and to<> columns.");
225 using FunT = std::function<
226 utility::maybe_tuple<utility::ndim_type_t<typename ToColumns::data_type, Dim>...>
227 (utility::ndim_type_t<typename FromColumns::data_type, Dim>&...)>;
229 detail::wrap_fun_for_dim<
231 from_t<
typename FromColumns::data_type...>,
232 to_t<
typename ToColumns::data_type...>>
233 fun_wrapper{std::move(fun)};
235 return stream::partial_transform(f, t, std::move(fun_wrapper));
243 template<
typename Fun,
typename FromIdxs,
typename ToIdxs,
typename From,
typename To>
244 struct wrap_fun_with_cond;
246 template<
typename Fun, std::size_t... FromIdxs, std::size_t... ToIdxs,
247 typename CondCol,
typename... Cols,
typename... ToTypes>
248 struct wrap_fun_with_cond<Fun,
249 std::index_sequence<FromIdxs...>,
250 std::index_sequence<ToIdxs...>,
251 from_t<CondCol, Cols...>, to_t<ToTypes...>> {
254 utility::maybe_tuple<ToTypes...> operator()(CondCol& cond, Cols&... cols)
257 std::tuple<Cols&...> args_view{cols...};
262 static_assert(std::is_invocable_v<Fun&,
263 std::tuple_element_t<FromIdxs, decltype(args_view)>...>,
264 "hipipe::stream::conditional_transform: "
265 "Cannot apply the given function to the given `from<>` columns.");
266 static_assert(std::is_invocable_r_v<
267 std::tuple<ToTypes...>, Fun&,
268 std::tuple_element_t<FromIdxs, decltype(args_view)>...>,
269 "hipipe::stream::conditional_transform: "
270 "The function return type does not correspond to the selected `to<>` columns.");
271 return std::invoke(fun, std::get<FromIdxs>(args_view)...);
277 return {std::move(std::get<ToIdxs>(args_view))...};
334 typename... FromColumns,
335 typename... ToColumns,
340 from_t<FromColumns...> f,
341 to_t<ToColumns...> t,
342 cond_t<CondColumn> c,
344 dim_t<Dim> d = dim_t<1>{})
348 constexpr std::size_t n_from =
sizeof...(FromColumns);
349 constexpr std::size_t n_to =
sizeof...(ToColumns);
350 using FromIdxs = std::make_index_sequence<n_from>;
357 "hipipe::stream::conditional_transform: The dimension in which to apply the operation needs"
358 " to be at most the lowest dimension of all the from<>, to<> and cond<> columns.");
361 using FunT = std::function<
362 utility::maybe_tuple<utility::ndim_type_t<typename ToColumns::data_type, Dim>...>
363 (utility::ndim_type_t<typename FromColumns::data_type, Dim>&...)>;
365 detail::wrap_fun_with_cond<
366 FunT, FromIdxs, ToIdxs,
367 from_t<utility::ndim_type_t<typename CondColumn::data_type, Dim>,
368 utility::ndim_type_t<typename FromColumns::data_type, Dim>...,
369 utility::ndim_type_t<typename ToColumns::data_type, Dim>...>,
370 to_t<utility::ndim_type_t<typename ToColumns::data_type, Dim>...>>
371 cond_fun{std::move(fun)};
376 t, std::move(cond_fun), d);
384 template<
typename Fun,
typename Prng,
385 typename FromIdxs,
typename ToIdxs,
386 typename From,
typename To>
387 struct wrap_fun_with_prob;
389 template<
typename Fun,
typename Prng,
390 std::size_t... FromIdxs, std::size_t... ToIdxs,
391 typename... FromTypes,
typename... ToTypes>
392 struct wrap_fun_with_prob<Fun, Prng,
393 std::index_sequence<FromIdxs...>,
394 std::index_sequence<ToIdxs...>,
395 from_t<FromTypes...>, to_t<ToTypes...>> {
397 std::reference_wrapper<Prng> prng;
400 utility::maybe_tuple<ToTypes...> operator()(FromTypes&... cols)
402 assert(prob >= 0. && prob <= 1.);
403 std::uniform_real_distribution<> dis{0, 1};
405 std::tuple<FromTypes&...> args_view{cols...};
407 if (prob == 1. || (prob > 0. && dis(prng.get()) < prob)) {
410 static_assert(std::is_invocable_v<Fun&,
411 std::tuple_element_t<FromIdxs, decltype(args_view)>...>,
412 "hipipe::stream::probabilistic_transform: "
413 "Cannot apply the given function to the given `from<>` columns.");
414 static_assert(std::is_invocable_r_v<
415 std::tuple<ToTypes...>, Fun&,
416 std::tuple_element_t<FromIdxs, decltype(args_view)>...>,
417 "hipipe::stream::probabilistic_transform: "
418 "The function return type does not correspond to the selected `to<>` columns.");
419 return std::invoke(fun, std::get<FromIdxs>(args_view)...);
425 return {std::move(std::get<ToIdxs>(args_view))...};
463 typename... FromColumns,
464 typename... ToColumns,
466 typename Prng = std::mt19937,
469 from_t<FromColumns...> f,
470 to_t<ToColumns...> t,
474 dim_t<Dim> d = dim_t<1>{})
478 constexpr std::size_t n_from =
sizeof...(FromColumns);
479 constexpr std::size_t n_to =
sizeof...(ToColumns);
480 using FromIdxs = std::make_index_sequence<n_from>;
486 "hipipe::stream::probabilistic_transform: The dimension in which to apply the operation "
487 " needs to be at most the lowest dimension of all the from<> and to<> columns.");
490 using FunT = std::function<
491 utility::maybe_tuple<utility::ndim_type_t<typename ToColumns::data_type, Dim>...>
492 (utility::ndim_type_t<typename FromColumns::data_type, Dim>&...)>;
494 detail::wrap_fun_with_prob<
495 FunT, Prng, FromIdxs, ToIdxs,
496 from_t<utility::ndim_type_t<typename FromColumns::data_type, Dim>...,
497 utility::ndim_type_t<typename ToColumns::data_type, Dim>...>,
498 to_t<utility::ndim_type_t<typename ToColumns::data_type, Dim>...>>
499 prob_fun{std::move(fun), prng, prob};
503 return stream::transform(from_t<FromColumns..., ToColumns...>{}, t, std::move(prob_fun), d);