cxtream  0.5.1
C++17 data pipeline with Python bindings.
filter.hpp
1 /****************************************************************************
2  * cxtream library
3  * Copyright (c) 2017, Cognexa Solutions s.r.o.
4  * Author(s) Filip Matzner
5  *
6  * This file is distributed under the MIT License.
7  * See the accompanying file LICENSE.txt for the complete license agreement.
8  ****************************************************************************/
9 
10 #ifndef CXTREAM_CORE_STREAM_FILTER_HPP
11 #define CXTREAM_CORE_STREAM_FILTER_HPP
12 
13 #include <cxtream/core/stream/template_arguments.hpp>
14 #include <cxtream/core/stream/transform.hpp>
15 #include <cxtream/core/utility/tuple.hpp>
16 
17 #include <range/v3/view/filter.hpp>
18 #include <range/v3/view/move.hpp>
19 #include <range/v3/view/zip.hpp>
20 
21 #include <functional>
22 #include <utility>
23 
24 namespace cxtream::stream {
25 
26 namespace detail {
27 
28  // Filter the stream using the given function.
29  // This function wrapper is to be applied in one lower
30  // dimension than the wrapped function itself.
31  // This function wrapper is to be called in dimensions higher than 0.
32  template<typename Fun, typename From, typename ByIdxs>
33  struct wrap_filter_fun_for_transform;
34  template<typename Fun, typename... FromTypes, std::size_t... ByIdxs>
35  struct wrap_filter_fun_for_transform<Fun, from_t<FromTypes...>, std::index_sequence<ByIdxs...>>
36  {
37  Fun fun;
38 
39  // Properly zips/unzips the data and applies the filter function.
40  constexpr utility::maybe_tuple<FromTypes...> operator()(FromTypes&... cols)
41  {
42  auto range_of_tuples =
43  ranges::view::zip(cols...)
44  | ranges::view::filter([this](const auto& tuple) -> bool {
45  auto slice_view = utility::tuple_index_view<ByIdxs...>(tuple);
46  return boost::hana::unpack(std::move(slice_view), this->fun);
47  })
48  | ranges::view::move;
49  return utility::maybe_untuple(utility::unzip(std::move(range_of_tuples)));
50  }
51  };
52 
53  // Helper function wrapper for dimension 0.
54  // This wrapper takes a single tuple of columns as argument and
55  // applies the stored function to a subset of columns selected by types.
56  // The columns are projected to their value().
57  template<typename Fun, typename... ByColumns>
58  struct apply_filter_fun_to_columns
59  {
60  Fun fun;
61 
62  template<typename... SourceColumns>
63  constexpr bool operator()(const std::tuple<SourceColumns...>& tuple)
64  {
65  auto proj = [](auto& column) { return std::ref(column.value()); };
66  auto slice_view = utility::tuple_type_view<ByColumns...>(tuple);
67  auto values = utility::tuple_transform(std::move(slice_view), std::move(proj));
68  return boost::hana::unpack(std::move(values), fun);
69  }
70  };
71 
72  // Entry point for stream::filter.
73  // For dimensions higher than 0, use stream::transform to Dim-1 and
74  // wrap_filter_fun_for_transform wrapper.
75  template<int Dim>
76  struct filter_impl
77  {
78  template<typename... FromColumns, typename... ByColumns, typename Fun>
79  static constexpr auto impl(from_t<FromColumns...> f, by_t<ByColumns...> b, Fun fun)
80  {
81  static_assert(sizeof...(ByColumns) <= sizeof...(FromColumns),
82  "Cannot have more ByColumns than FromColumns.");
83 
84  detail::wrap_filter_fun_for_transform<
85  Fun, from_t<utility::ndim_type_t<typename FromColumns::batch_type, Dim-1>...>,
86  std::index_sequence<utility::variadic_find<ByColumns, FromColumns...>::value...>>
87  fun_wrapper{std::move(fun)};
88 
89  return stream::transform(f, to<FromColumns...>, std::move(fun_wrapper), dim<Dim-1>);
90  }
91  };
92 
93  // Special case for batch filtering (Dim == 0).
94  template<>
95  struct filter_impl<0>
96  {
97  template<typename From, typename... ByColumns, typename Fun>
98  static constexpr auto impl(From, by_t<ByColumns...>, Fun fun)
99  {
100  apply_filter_fun_to_columns<Fun, ByColumns...> fun_wrapper{std::move(fun)};
101  return ranges::view::filter(std::move(fun_wrapper));
102  }
103  };
104 
105 } // namespace detail
106 
126 template<typename... FromColumns, typename... ByColumns, typename Fun, int Dim = 1>
127 constexpr auto filter(from_t<FromColumns...> f,
128  by_t<ByColumns...> b,
129  Fun fun,
130  dim_t<Dim> d = dim_t<1>{})
131 {
132  return detail::filter_impl<Dim>::impl(f, b, std::move(fun));
133 }
134 
135 } // namespace cxtream::stream
136 #endif
auto unzip(Rng range_of_tuples)
Unzips a range of tuples to a tuple of ranges.
Definition: tuple.hpp:408
constexpr auto transform(from_t< FromColumns... > f, to_t< ToColumns... > t, Fun fun, dim_t< Dim > d=dim_t< 1 >{})
Transform a subset of cxtream columns to a different subset of cxtream columns.
Definition: transform.hpp:177
STL namespace.
decltype(auto) maybe_untuple(Tuple &&tuple)
Extract a value from a tuple if the tuple contains only a single value.
Definition: tuple.hpp:522
constexpr auto tuple_type_view(Tuple &tuple)
Makes a sub-tuple made of references to the original tuple (selected by type).
Definition: tuple.hpp:186
constexpr auto filter(from_t< FromColumns... > f, by_t< ByColumns... > b, Fun fun, dim_t< Dim > d=dim_t< 1 >{})
Filter stream data.
Definition: filter.hpp:127
constexpr auto unpack(Rng &&rng, from_t< FromColumns... > f, dim_t< Dim > d=dim_t< 1 >{})
Unpack a stream into a tuple of ranges.
Definition: unpack.hpp:100
constexpr auto tuple_index_view(Tuple &tuple, std::index_sequence< Idxs... >={})
Makes a sub-tuple made of references to the original tuple (selected by index).
Definition: tuple.hpp:205
constexpr auto tuple_transform(Tuple &&tuple, Fun &&fun)
Transform each element of a tuple.
Definition: tuple.hpp:155