chain.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 
34 #include <atria/prelude/comp.hpp>
37 
38 namespace atria {
39 namespace xform {
40 
41 namespace detail {
42 
43 struct chainr_rf_gen
44 {
45  struct tag {};
46 
47  template <typename ReducingFnT,
48  typename InputRangeT>
49  struct apply
50  {
51  ReducingFnT step;
52  InputRangeT range;
53 
54  template <typename StateT, typename ...InputTs>
55  auto operator() (StateT&& s, InputTs&& ...is)
56  -> decltype(wrap_state<tag>(step(state_unwrap(s), is...), *this))
57  {
58  auto data = state_data(std::forward<StateT>(s), constantly(*this));
59  return wrap_state<tag>(
60  data.step(state_unwrap(std::forward<StateT>(s)),
61  std::forward<InputTs>(is)...),
62  std::move(data));
63  }
64  };
65 
66  template <typename T>
67  friend auto state_wrapper_complete(tag, T&& wrapper)
69  identity_(
72  state_wrapper_data(std::forward<T>(wrapper)).step,
73  state_unwrap(std::forward<T>(wrapper)),
74  state_wrapper_data(std::forward<T>(wrapper)).range))))
75 };
76 
77 } // namespace detail
78 
79 template <typename T>
80 using chainr_t = transducer_impl<detail::chainr_rf_gen, T>;
81 
86 template <typename InputRangeT>
87 constexpr auto chainr(InputRangeT&& r)
89 {
91  std::forward<InputRangeT>(r) };
92 }
93 
94 template <typename InputRangeT, typename ...InputRangeTs>
95 constexpr auto chainr(InputRangeT&& r, InputRangeTs&& ...rs)
97  comp(chainr(std::forward<InputRangeT>(r)),
98  chainr(std::forward<InputRangeTs>(rs))...))
99 
100 
104 template <typename ...InputRangeTs>
105 constexpr auto chain(InputRangeTs&& ...rs)
107  chainr(std::forward<InputRangeTs>(rs)...))
108 
109 namespace detail {
110 
111 struct chainl_rf_gen
112 {
113  template <typename ReducingFnT,
114  typename InputRangeT>
115  struct apply
116  {
117  ReducingFnT step;
118  InputRangeT range;
119 
120  template <typename StateT, typename ...InputTs>
121  auto operator() (StateT&& s, InputTs&& ...is)
122  -> decltype(wrap_state(step(state_unwrap(s), is...)))
123  {
124  using std::begin;
125  using std::end;
126 
127  using result_t = decltype(wrap_state(step(state_unwrap(s), is...)));
128  using complete_t = decltype(state_complete(s));
129 
130  using wrapped_t = meta::copy_decay_t<StateT, estd::decay_t<result_t>>;
131  using unwrapped_t = meta::copy_decay_t<StateT, estd::decay_t<complete_t>>;
132 
133  return with_state(
134  std::forward<StateT>(s),
135  [&] (unwrapped_t&& st) {
136  return wrap_state(
137  begin(range) != end(range)
138  ? step(reduce_nested_non_empty(
139  step, std::forward<unwrapped_t>(st), range),
140  std::forward<InputTs>(is)...)
141  : step(std::forward<unwrapped_t>(st),
142  std::forward<InputTs>(is)...));
143  },
144  [&] (wrapped_t&& st) {
145  return wrap_state(
146  step(state_unwrap(std::forward<wrapped_t>(st)),
147  std::forward<InputTs>(is)...));
148  });
149  }
150  };
151 };
152 
153 } // namespace detail
154 
155 template <typename T>
156 using chainl_t = transducer_impl<detail::chainl_rf_gen, T>;
157 
162 template <typename InputRangeT>
163 constexpr auto chainl(InputRangeT&& r)
165 {
167  std::forward<InputRangeT>(r) };
168 }
169 
170 template <typename InputRangeT, typename ...InputRangeTs>
171 constexpr auto chainl(InputRangeT&& r, InputRangeTs&& ...rs)
173  comp(chainl(std::forward<InputRangeT>(r)),
174  chainl(std::forward<InputRangeTs>(rs))...))
175 
176 } // namespace xform
177 } // namespace atria
auto state_wrapper_data(TagT tag, T &&s, D &&) -> decltype(state_wrapper_data(tag, std::forward< T >(s)))
Utility function for easy overloading of state_traits::data for state wrappers with a specific tag...
constexpr auto chain(InputRangeTs &&...rs) -> decltype(chainr(std::forward< InputRangeTs >(rs)...))
Alias for chainr
Definition: chain.hpp:105
#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
auto state_unwrap(T &&s) -> decltype(state_traits_t< T >::unwrap(std::forward< T >(s)))
Convenience function for calling state_traits::unwrap
auto constantly(T &&value) -> constantly_t< estd::decay_t< T > >
Similar to clojure.core/constantly.
Definition: constantly.hpp:56
auto with_state(StateT &&st, UnwrappedFn &&, WrappedFn &&fn) -> meta::lazy_enable_if_t< !std::is_same< estd::decay_t< StateT >, estd::decay_t< decltype(state_complete(st))> >::value, std::result_of< WrappedFn(StateT)> >
Given a value st that represents the state of a reduction, this function generically dispatches to th...
Definition: with_state.hpp:58
constexpr auto chainl(InputRangeT &&r) -> chainl_t< estd::decay_t< InputRangeT > >
Transducer produces the sequence passed as parameter before processing the first input.
Definition: chain.hpp:163
auto state_data(T &&s, D &&d) -> decltype(state_traits_t< T >::data(std::forward< T >(s), std::forward< D >(d)))
Convenience function for calling state_traits::data
constexpr auto range(StopT &&stop) -> decltype(comp( count(), take(std::forward< StopT >(stop))))
Generator transducer version of Python range
Definition: range.hpp:42
Utility to write simple transducers easily.
auto state_complete(T &&s) -> decltype(state_traits_t< T >::complete(std::forward< T >(s)))
Convenience function for calling state_traits::complete
auto reduce_nested(ReducingFnT &&step, StateT &&state, InputRangeTs &&...ranges) -> decltype(detail::is_non_empty(ranges...) ?call(detail::reduce_nested_non_empty_flipped, std::forward< StateT >(state), std::forward< ReducingFnT >(step), std::forward< InputRangeTs >(ranges)...) :skip(std::forward< StateT >(state)))
Similar to reduce, but does not unwrap reduced values.
auto comp(F &&f) -> F &&
Right-to left function composition.
Definition: comp.hpp:80
C++ amazing templates and reusable implementations awesomeness.
Definition: _doc.hpp:35
auto wrap_state(StateT &&next, DataT &&data=DataT{}) -> state_wrapper< TagT, estd::decay_t< StateT >, estd::decay_t< DataT > >
Given a tag TagT and a state next and associated data, returns a state_wrapper instance.
constexpr auto chainr(InputRangeT &&r) -> chainr_t< estd::decay_t< InputRangeT > >
Transducer produces the sequence passed as parameter after all other input has finished.
Definition: chain.hpp:87
auto state_wrapper_complete(TagT, T &&s) -> decltype(state_complete(state_unwrap(std::forward< T >(s))))
Utility function for easy overloading of state_traits::complete for state wrappers with a specific ta...
Fork me on GitHub