skip.hpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2014, 2015 Ableton AG, Berlin. All rights reserved.
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining a
5 // copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the
9 // Software is furnished to do so, subject to the following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 // DEALINGS IN THE SOFTWARE.
21 //
22 
27 #pragma once
28 
32 #include <atria/estd/utility.hpp>
33 #include <functional>
34 
35 namespace atria {
36 namespace xform {
37 
44 template <typename SkippedT, typename CalledT>
45 struct skip_state : eggs::variant<SkippedT, CalledT>
46 {
47  using skipped_t = SkippedT;
48  using called_t = CalledT;
49 
51 
52  using base_t = eggs::variant<SkippedT, CalledT>;
53  using base_t::base_t;
54 };
55 
56 } // namespace xform
57 } // namespace atria
58 
59 namespace atria {
60 namespace xform {
61 
62 template <typename T>
64  : std::false_type {};
65 
66 template <typename SkippedT, typename CalledT>
67 struct is_skip_state<skip_state<SkippedT, CalledT> >
68  : std::true_type {};
69 
70 namespace detail {
71 
72 struct state_is_reduced_t
73 {
74  template <typename T>
75  auto operator() (T&& s)
77  state_is_reduced(std::forward<T>(s)))
78 };
79 
80 struct state_complete_t
81 {
82  template <typename T>
83  auto operator() (T&& s)
85  state_complete(std::forward<T>(s)))
86 };
87 
88 struct state_unwrap_all_t
89 {
90  template <typename T>
91  auto operator() (T&& s)
93  state_unwrap_all(std::forward<T>(s)))
94 };
95 
96 template <typename U>
97 struct state_rewrap_t
98 {
99  U&& x;
100 
101  template <typename T>
102  auto operator() (T&& s)
104  state_rewrap(std::forward<T>(s), std::forward<U>(x)))
105 };
106 
107 } // namespace detail
108 
109 template <typename SkippedT, typename CalledT>
110 struct state_traits<skip_state<SkippedT, CalledT> >
111 {
112  template <typename T>
113  static auto is_reduced(T&& s)
116  std::forward<T>(s),
117  detail::state_is_reduced_t{}))
118 
119  template <typename T>
120  static auto complete(T&& s)
123  std::forward<T>(s),
124  variant::otherwise<SkippedT>(detail::state_complete_t{})))
125 
126  template <typename T>
127  static auto unwrap_all(T&& s)
130  std::forward<T>(s),
131  variant::otherwise<SkippedT>(detail::state_unwrap_all_t{})))
132 
133  template <typename T, typename U>
134  static auto rewrap(T&& s, U&& x)
137  std::forward<T>(s),
138  variant::otherwise<estd::decay_t<T> >(
139  detail::state_rewrap_t<U>{ std::forward<U>(x) })))
140 
141  // Marks methods that don't make sense for a `skip_state` Note that
142  // these methods still need to be implemented for type erasure to
143  // work (via `any_state`).
144  struct can_not_do_that {};
145 
146  template <typename T, typename D>
147  static can_not_do_that data(T&&, D&&) { return {}; }
148  template <typename T>
149  static can_not_do_that unwrap(T&&) { return {}; }
150 };
151 
152 namespace detail
153 {
154 
155 template <typename ReducingFnT, typename StateT, typename... InputTs>
156 struct skip_result_impl
157 {
158  using skipped_t = StateT;
159  using called_t = estd::result_of_t<ReducingFnT(StateT, InputTs...)>;
160 
161  using common_type_t = meta::common_type_t<skipped_t, called_t>;
162  using error_t = meta::could_not_find_common_type<skipped_t, called_t>;
163 
164  using type = estd::conditional_t<
165  !std::is_same<common_type_t, error_t>{},
167  skip_state<estd::decay_t<skipped_t>,
168  estd::decay_t<called_t> > >;
169 };
170 
171 } // namespace detail
172 
192 template <typename ReducingFnT, typename StateT, typename... InputTs>
194  : boost::mpl::eval_if<
195  is_skip_state<estd::decay_t<StateT> >,
196  meta::identity<estd::decay_t<StateT> >,
197  detail::skip_result_impl<ReducingFnT, StateT, InputTs...> >
198 {};
199 
200 template <typename ReducingFnT, typename StateT, typename... InputTs>
201 using skip_result_t = typename skip_result<
202  ReducingFnT, StateT, InputTs...>::type;
203 
227 template <typename ReducingFnT, typename StateT, typename... InputTs>
228 auto skip(ReducingFnT&&, StateT&& state, InputTs&& ...)
229  -> skip_result_t<ReducingFnT, StateT, InputTs...>
230 {
231  return std::forward<StateT>(state);
232 }
233 
234 template <typename StateT>
235 auto skip(StateT&& state)
236  -> StateT&&
237 {
238  return std::forward<StateT>(state);
239 }
240 
241 namespace detail {
242 
243 template <typename ReducingFnT, typename... InputTs>
244 struct bind_forward_reducing_function
245 {
246  ReducingFnT&& fn;
247  std::tuple<InputTs&&...> ins;
248 
249  template <std::size_t... Indices, typename StateT>
250  auto impl(estd::index_sequence<Indices...>, StateT&& st)
252  std::forward<ReducingFnT>(fn)(
253  std::forward<StateT>(st),
254  std::forward<typename std::tuple_element<Indices, decltype(ins)>::type>(
255  std::get<Indices>(ins))...))
256 
257  template <typename StateT>
258  auto operator() (StateT&& st)
260  impl(estd::make_index_sequence<sizeof...(InputTs)>{},
261  std::forward<StateT>(st)))
262 };
263 
264 } // namespace detail
265 
275 template <typename ReducingFnT, typename StateT, typename... InputTs>
276 auto call(ReducingFnT&& step, StateT&& state, InputTs&& ...ins)
280 {
281  return variant::match(
282  std::forward<StateT>(state),
283  detail::bind_forward_reducing_function<ReducingFnT, InputTs...> {
284  std::forward<ReducingFnT>(step),
285  std::forward_as_tuple<InputTs...>(
286  std::forward<InputTs>(ins)...)
287  });
288 }
289 
290 template <typename ReducingFnT, typename StateT, typename... InputTs>
291 auto call(ReducingFnT&& step, StateT&& state, InputTs&& ...ins)
293  !is_skip_state<estd::decay_t<StateT> >{},
294  skip_result_t<ReducingFnT, StateT, InputTs...> >
295 {
296  return std::forward<ReducingFnT>(step)(
297  std::forward<StateT>(state),
298  std::forward<InputTs>(ins)...);
299 }
300 
301 } // namespace xform
302 } // namespace atria
static auto complete(T &&state) -> decltype(std::forward< T >(state))
Unwraps all the layers of state wrappers returning the deepmost.
static auto is_reduced(T &&) -> bool
Returns whether the value is idempotent, and thus, the reduction can finish.
auto call(ReducingFnT &&step, StateT &&state, InputTs &&...ins) -> estd::enable_if_t< is_skip_state< estd::decay_t< StateT > >
Call the next reducing function in a transducer that could otherwise skip calling the next reducing f...
Definition: skip.hpp:276
#define ABL_DECLTYPE_RETURN(body_expr)
Utility for defining generic functions with a deduced return type, that are composed of a single expr...
Definition: utils.hpp:109
typename std::enable_if< X, T >::type enable_if_t
Similar to C++14 std::enable_if_t.
Definition: type_traits.hpp:84
typename std::decay< T >::type decay_t
Similar to C++14 std::decay_t.
Definition: type_traits.hpp:54
typename common_type< Ts... >::type common_type_t
C++14 style alias for common_type
typename std::conditional< X, T, F >::type conditional_t
Similar to C++14 std::conditional_t.
Definition: type_traits.hpp:66
Interface for a type specializing the State concept.
MPL-compatible sequence that just holds a vector of types as a paremeter pack.
Definition: pack.hpp:57
static auto unwrap(T &&state) -> decltype(std::forward< T >(state))
Unwraps this layers of state wrappers, returning the nested state for the next reducing function...
auto state_rewrap(T &&s, U &&x) -> decltype(state_traits_t< T >::rewrap(std::forward< T >(s), std::forward< U >(x)))
Convenience function for calling state_traits::unwrap_all
auto state_complete(T &&s) -> decltype(state_traits_t< T >::complete(std::forward< T >(s)))
Convenience function for calling state_traits::complete
Type-safe union type that can hold values of both SkippedT and CalledT types.
Definition: skip.hpp:45
static auto data(T &&, D &&d) -> decltype(std::forward< D >(d)())
Returns the associated from the current state.
auto match(VariantT &variant, FnTs &&...fns) -> estd::enable_if_t< detail::is_boost_variant< estd::decay_t< VariantT > >
Destructure a boost::variant with a given set of functions.
Definition: match_boost.hpp:69
static auto unwrap_all(T &&state) -> decltype(std::forward< T >(state))
Unwraps all layers of state wrappers, returning the most nested state for the innermost reducing func...
static auto rewrap(T &&, U &&x) -> decltype(std::forward< U >(x))
Copies all layers of state wrappers but replaces the innermost state with substate.
C++ amazing templates and reusable implementations awesomeness.
Definition: _doc.hpp:35
auto state_is_reduced(T &&s) -> bool
Convenience function for calling state_traits::is_reduced
auto state_unwrap_all(T &&s) -> decltype(state_traits_t< T >::unwrap_all(std::forward< T >(s)))
Convenience function for calling state_traits::unwrap_all
auto skip(ReducingFnT &&, StateT &&state, InputTs &&...) -> skip_result_t< ReducingFnT, StateT, InputTs... >
Skip calling the next reducing function in a transducer.
Definition: skip.hpp:228
Metafunction that returns a type that can hold both values of type skipped_t = StateT and wrapped_t =...
Definition: skip.hpp:193
typename std::result_of< T >::type result_of_t
Similar to C++14 std::result_of_t.
Definition: type_traits.hpp:60
Fork me on GitHub