Itoyori  v0.0.1
reducer.hpp
Go to the documentation of this file.
1 #pragma once
2 
3 #include "ityr/common/util.hpp"
4 
5 namespace ityr::reducer {
6 
7 template <typename T>
9  using value_type = T;
10  operator value_type() { return T{}; }
11  value_type operator()() const { return T{}; }
12 };
13 
14 template <typename T, typename BinaryOp, typename IdentityProvider = default_identity_provider<T>>
15 struct monoid {
16  static_assert(std::is_same_v<T, typename IdentityProvider::value_type>);
17 
18  using value_type = T;
19  using accumulator_type = T;
20 
21  void operator()(T& l, const T& r) const {
22  l = bop_(l, r);
23  }
24 
25  void operator()(const T& l, T& r) const {
26  r = bop_(l, r);
27  }
28 
29  T operator()() const {
30  return IdentityProvider();
31  }
32 
33 private:
34  static constexpr auto bop_ = BinaryOp();
35 };
36 
37 template <typename T>
38 struct one {
39  static_assert(std::is_arithmetic_v<T>);
40  using value_type = T;
41  static constexpr T value = T{1};
42  constexpr operator value_type() noexcept { return value; }
43  constexpr value_type operator()() const noexcept { return value; }
44 };
45 
46 template <typename T>
47 struct lowest {
48  static_assert(std::is_arithmetic_v<T>);
49  using value_type = T;
50  static constexpr T value = std::numeric_limits<T>::lowest();
51  constexpr operator value_type() noexcept { return value; }
52  constexpr value_type operator()() const noexcept { return value; }
53 };
54 
55 template <typename T>
56 struct highest {
57  static_assert(std::is_arithmetic_v<T>);
58  using value_type = T;
59  static constexpr T value = std::numeric_limits<T>::max();
60  constexpr operator value_type() noexcept { return value; }
61  constexpr value_type operator()() const noexcept { return value; }
62 };
63 
64 template <typename T = void>
65 struct min_functor {
66  constexpr T operator()(const T& x, const T& y) const {
67  return std::min(x, y);
68  }
69 };
70 
71 template <>
72 struct min_functor<void> {
73  template <typename T, typename U>
74  constexpr auto operator()(T&& v, U&& u) const {
75  return std::min(std::forward<T>(v), std::forward<U>(u));
76  }
77 };
78 
79 template <typename T = void>
80 struct max_functor {
81  constexpr T operator()(const T& x, const T& y) const {
82  return std::max(x, y);
83  }
84 };
85 
86 template <>
87 struct max_functor<void> {
88  template <typename T, typename U>
89  constexpr auto operator()(T&& t, U&& u) const {
90  return std::max(std::forward<T>(t), std::forward<U>(u));
91  }
92 };
93 
94 template <typename T>
96 
97 template <typename T>
99 
100 template <typename T>
102 
103 template <typename T>
105 
106 template <typename T>
107 struct minmax {
108  using value_type = T;
109  using accumulator_type = std::pair<T, T>;
110 
111  void operator()(accumulator_type& acc, const value_type& x) const {
112  acc.first = std::min(acc.first, x);
113  acc.second = std::max(acc.second, x);
114  }
115 
116  void operator()(accumulator_type& acc_l, const accumulator_type& acc_r) const {
117  acc_l.first = std::min(acc_l.first, acc_r.first);
118  acc_l.second = std::max(acc_l.second, acc_r.second);
119  }
120 
121  void operator()(const accumulator_type& acc_l, accumulator_type& acc_r) const {
122  (*this)(acc_r, acc_l); // commutative
123  }
124 
126  return std::make_pair(std::numeric_limits<T>::max(), std::numeric_limits<T>::lowest());
127  }
128 };
129 
131 using logical_or = monoid<bool, std::logical_or<> , std::false_type>;
132 
133 template <typename Acc, typename... Fns>
134 struct reducer_generic : Fns... {
135  using accumulator_type = Acc;
136  reducer_generic(Fns&&... fns)
137  : Fns(std::forward<Fns>(fns))... {}
138  using Fns::operator()...;
139 };
140 
141 namespace internal {
142 
143 template <typename T, typename = void>
144 struct type_or_void {
145  using type = void;
146 };
147 
148 template <typename T>
149 struct type_or_void<T, std::void_t<typename T::type>> {
150  using type = typename T::type;
151 };
152 
153 // If T::type is defined, return T::type. Otherwise, return void.
154 template <typename T>
155 using type_or_void_t = typename type_or_void<T>::type;
156 
157 template <typename...>
158 struct identity_retval {
159  using type = void;
160 };
161 
162 template <typename Fn, typename... Rest>
163 struct identity_retval<Fn, Rest...> {
164  // `type_or_void` indirection is needed because std::invoke_result<Fn> cannot be evaluated
165  // if is_invocable_v<Fn> == false
166  using type = std::conditional_t<std::is_invocable_v<Fn>,
167  type_or_void_t<std::invoke_result<Fn>>,
168  typename identity_retval<Rest...>::type>;
169 };
170 
171 template <typename... Fns>
172 using identity_retval_t = typename identity_retval<std::remove_reference_t<Fns>...>::type;
173 
174 }
175 
176 template <typename... Fns>
177 inline decltype(auto) make_reducer(Fns&&... fns) {
178  using acc_t = internal::identity_retval_t<Fns...>;
179  static_assert(!std::is_void_v<acc_t>,
180  "Please define an identity function that returns a nonvoid value.");
181  return reducer_generic<acc_t, Fns...>(std::forward<Fns>(fns)...);
182 }
183 
184 }
Definition: reducer.hpp:5
monoid< T, min_functor<>, highest< T > > min
Definition: reducer.hpp:101
monoid< T, max_functor<>, lowest< T > > max
Definition: reducer.hpp:104
decltype(auto) make_reducer(Fns &&... fns)
Definition: reducer.hpp:177
value_type operator()() const
Definition: reducer.hpp:11
T value_type
Definition: reducer.hpp:9
Definition: reducer.hpp:56
T value_type
Definition: reducer.hpp:58
constexpr value_type operator()() const noexcept
Definition: reducer.hpp:61
static constexpr T value
Definition: reducer.hpp:59
Definition: reducer.hpp:47
static constexpr T value
Definition: reducer.hpp:50
T value_type
Definition: reducer.hpp:49
constexpr value_type operator()() const noexcept
Definition: reducer.hpp:52
constexpr auto operator()(T &&t, U &&u) const
Definition: reducer.hpp:89
Definition: reducer.hpp:80
constexpr T operator()(const T &x, const T &y) const
Definition: reducer.hpp:81
constexpr auto operator()(T &&v, U &&u) const
Definition: reducer.hpp:74
Definition: reducer.hpp:65
constexpr T operator()(const T &x, const T &y) const
Definition: reducer.hpp:66
Definition: reducer.hpp:107
void operator()(accumulator_type &acc, const value_type &x) const
Definition: reducer.hpp:111
accumulator_type operator()() const
Definition: reducer.hpp:125
void operator()(const accumulator_type &acc_l, accumulator_type &acc_r) const
Definition: reducer.hpp:121
void operator()(accumulator_type &acc_l, const accumulator_type &acc_r) const
Definition: reducer.hpp:116
T value_type
Definition: reducer.hpp:108
std::pair< T, T > accumulator_type
Definition: reducer.hpp:109
Definition: reducer.hpp:15
T value_type
Definition: reducer.hpp:18
void operator()(const T &l, T &r) const
Definition: reducer.hpp:25
void operator()(T &l, const T &r) const
Definition: reducer.hpp:21
T accumulator_type
Definition: reducer.hpp:19
T operator()() const
Definition: reducer.hpp:29
Definition: reducer.hpp:38
constexpr value_type operator()() const noexcept
Definition: reducer.hpp:43
static constexpr T value
Definition: reducer.hpp:41
T value_type
Definition: reducer.hpp:40
Definition: reducer.hpp:134
reducer_generic(Fns &&... fns)
Definition: reducer.hpp:136
Acc accumulator_type
Definition: reducer.hpp:135