xform_signals.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 
31 
32 #include <atria/meta/pack.hpp>
36 #include <atria/xform/meta.hpp>
39 
40 #include <atria/estd/utility.hpp>
42 
43 namespace atria {
44 namespace funken {
45 
46 namespace detail {
47 
48 constexpr struct
49 {
50  template <typename DownSignalPtr, typename ...Inputs>
51  auto operator () (DownSignalPtr s, Inputs&& ...is) const
52  -> DownSignalPtr
53  {
54  s->push_down(tuplify(std::forward<Inputs>(is)...));
55  return s;
56  }
57 
58  template <typename DownSignalPtr, typename ...Inputs>
59  auto operator () (DownSignalPtr s) const
60  -> DownSignalPtr
61  {
62  return s;
63  }
64 } send_down_r {};
65 
66 
67 template <typename T, typename Err>
68 auto default_construct_or_throw()
69  -> estd::enable_if_t<std::is_default_constructible<T>::value, T>
70 {
71  return T();
72 }
73 
74 template <typename T, typename Err>
75 auto default_construct_or_throw()
76  -> estd::enable_if_t<!std::is_default_constructible<T>::value, T>
77 {
78  throw Err();
79 }
80 
84 template <typename XForm = identity_t,
85  typename ParentsPack = meta::pack<>,
86  template<class>class Base = down_signal>
87 class xform_down_signal;
88 
89 template <typename XForm,
90  typename ...Parents,
91  template<class>class Base>
92 class xform_down_signal<XForm, meta::pack<Parents...>, Base>
93  : public Base<xform::result_of_t<XForm, meta::value_t<Parents>...> >
94 {
95  using base_t = Base<xform::result_of_t<XForm, meta::value_t<Parents>...> >;
96  using down_rf_t = decltype(std::declval<XForm>()(send_down_r));
97 
98  std::tuple<std::shared_ptr<Parents>...> parents_;
99 
100 public:
101  using value_type = typename base_t::value_type;
102 
103  xform_down_signal(xform_down_signal&&) = default;
104  xform_down_signal(const xform_down_signal&) = delete;
105  xform_down_signal& operator=(xform_down_signal&&) = default;
106  xform_down_signal& operator=(const xform_down_signal&) = delete;
107 
108  template <typename XForm2>
109  xform_down_signal(XForm2&& xform, std::shared_ptr<Parents> ...parents)
110  : base_t([&]() -> value_type {
111  try {
112  return xform(xform::last_rf)(detail::no_value{}, parents->current()...);
113  }
114  catch (const no_value_error&) {
115  return default_construct_or_throw<value_type, no_value_error>();
116  }
117  }())
118  , parents_(std::move(parents)...)
119  , down_step_(xform(send_down_r))
120  {
121  }
122 
123  void recompute() final
124  { recompute(estd::make_index_sequence<sizeof...(Parents)>{}); }
125 
126  void recompute_deep() final
127  { recompute_deep(estd::make_index_sequence<sizeof...(Parents)>{}); }
128 
129  std::tuple<std::shared_ptr<Parents>...>& parents()
130  { return parents_; }
131  const std::tuple<std::shared_ptr<Parents>...>& parents() const
132  { return parents_; }
133 
134 private:
135  template <std::size_t ...Indices>
136  void recompute(estd::index_sequence<Indices...>)
137  {
138  down_step_(this, std::get<Indices>(parents_)->current()...);
139  }
140 
141  template <std::size_t ...Indices>
142  void recompute_deep(estd::index_sequence<Indices...>)
143  {
144  meta::noop(
145  (std::get<Indices>(parents_)->recompute_deep(),
146  meta::can_be_void)...);
147  recompute();
148  }
149 
150  down_rf_t down_step_;
151 };
152 
153 
158 constexpr struct
159 {
160  template <typename UpSignalPtr, typename ...Inputs>
161  auto operator () (UpSignalPtr s, Inputs&& ...is) const
162  -> UpSignalPtr
163  {
164  s->push_up(tuplify(std::forward<Inputs>(is)...));
165  return s;
166  }
167 } send_up_rf {};
168 
172 struct update_rf_gen
173 {
174  template <typename ReducingFnT, typename UpdateT>
175  struct apply
176  {
177  ReducingFnT step;
178  UpdateT updater;
179 
180  template <typename XformUpSignalPtr, typename ...Inputs>
181  auto operator () (XformUpSignalPtr s, Inputs&& ...is) const
182  -> XformUpSignalPtr
183  {
184  auto indices = estd::make_index_sequence<
185  std::tuple_size<estd::decay_t<decltype(s->parents())> >::value > {};
186  return step(s, updater(peek_parents(s, indices),
187  std::forward<Inputs>(is)...));
188  }
189 
190  template <typename XformUpSignalPtr, std::size_t ...Indices>
191  auto peek_parents(XformUpSignalPtr s, estd::index_sequence<Indices...>) const
193  s->recompute_deep(),
194  tuplify(std::get<Indices>(s->parents())->current()...)))
195  };
196 };
197 
209 template <typename UpdateT>
210 auto update(UpdateT&& updater)
211  -> xform::transducer_impl<update_rf_gen, estd::decay_t<UpdateT> >
212 {
213  return std::forward<UpdateT>(updater);
214 }
215 
219 template <typename XForm = identity_t,
220  typename SetXForm = identity_t,
221  typename ParentsPack = meta::pack<>,
222  template<class>class Base = up_down_signal>
223 class xform_up_down_signal;
224 
225 template <typename XForm,
226  typename SetXForm,
227  typename ...Parents,
228  template<class>class Base>
229 class xform_up_down_signal<XForm, SetXForm, meta::pack<Parents...>, Base>
230  : public xform_down_signal<XForm, meta::pack<Parents...>, Base>
231 {
232  using base_t = xform_down_signal<XForm, meta::pack<Parents...>, Base>;
233  using up_rf_t = decltype(std::declval<SetXForm>()(send_up_rf));
234 
235 public:
236  using value_type = typename base_t::value_type;
237 
238  xform_up_down_signal(xform_up_down_signal&&) = default;
239  xform_up_down_signal(const xform_up_down_signal&) = delete;
240  xform_up_down_signal& operator=(xform_up_down_signal&&) = default;
241  xform_up_down_signal& operator=(const xform_up_down_signal&) = delete;
242 
243  template <typename XForm2, typename SetXForm2>
244  xform_up_down_signal(XForm2&& xform,
245  SetXForm2&& set_xform,
246  std::shared_ptr<Parents> ...parents)
247  : base_t(std::forward<XForm2>(xform), std::move(parents)...)
248  , up_step_(set_xform(send_up_rf))
249  {}
250 
251  void send_up(const value_type& value) final
252  {
253  send_up(value,
254  estd::make_index_sequence<sizeof...(Parents)>{});
255  }
256 
257  void send_up(value_type&& value) final
258  {
259  send_up(std::move(value),
260  estd::make_index_sequence<sizeof...(Parents)>{});
261  }
262 
263  template <typename T>
264  void push_up(T&& value)
265  {
266  push_up(std::forward<T>(value),
267  estd::make_index_sequence<sizeof...(Parents)>{});
268  }
269 
270 private:
271  template <typename T, std::size_t... Indices>
272  void send_up(T&& x, estd::index_sequence<Indices...>)
273  {
274  up_step_(this, std::forward<T>(x));
275  }
276 
277  template <typename T, std::size_t ...Indices>
278  void push_up(T&& value, estd::index_sequence<Indices...>)
279  {
280  auto& parents = this->parents();
281  meta::noop(
282  (std::get<Indices>(parents)->send_up(
283  std::get<Indices>(std::forward<T>(value))),
284  meta::can_be_void)...);
285  }
286 
287  template <typename T>
288  void push_up(T&& value, estd::index_sequence<0>)
289  {
290  std::get<0>(this->parents())->send_up(std::forward<T>(value));
291  }
292 
293  up_rf_t up_step_;
294 };
295 
296 
300 template <typename SignalT>
301 auto link_to_parents(std::shared_ptr<SignalT> signal)
302  -> std::shared_ptr<SignalT>
303 {
304  return link_to_parents(
305  std::move(signal),
306  estd::make_index_sequence<std::tuple_size<
307  estd::decay_t<decltype(signal->parents())>
308  >::value>{});
309 }
310 
311 template <typename SignalT, std::size_t ...Indices>
312 auto link_to_parents(std::shared_ptr<SignalT> signal,
313  estd::index_sequence<Indices...>)
314  -> std::shared_ptr<SignalT>
315 {
316  auto& parents = signal->parents();
317  meta::noop(
318  (std::get<Indices>(parents)->link(signal),
319  meta::can_be_void)...);
320  return signal;
321 }
322 
323 
327 template <typename XForm, typename ...Parents>
328 auto make_xform_down_signal(XForm&& xform,
329  std::shared_ptr<Parents> ...parents)
330  -> std::shared_ptr<
331  xform_down_signal<estd::decay_t<XForm>,
332  meta::pack<Parents...> >
333  >
334 {
335  using signal_t = xform_down_signal<estd::decay_t<XForm>,
336  meta::pack<Parents...> >;
337  return link_to_parents(
338  std::make_shared<signal_t>(std::forward<XForm>(xform),
339  std::move(parents)...));
340 }
341 
345 template <typename XForm,
346  typename SetXForm,
347  typename ...Parents>
348 auto make_xform_up_down_signal(XForm&& xform,
349  SetXForm&& set_xform,
350  std::shared_ptr<Parents> ...parents)
351  -> std::shared_ptr<
352  xform_up_down_signal<estd::decay_t<XForm>,
353  estd::decay_t<SetXForm>,
354  meta::pack<Parents...> >
355  >
356 {
357  using signal_t = xform_up_down_signal<estd::decay_t<XForm>,
358  estd::decay_t<SetXForm>,
359  meta::pack<Parents...> >;
360  return link_to_parents(
361  std::make_shared<signal_t>(std::forward<XForm>(xform),
362  std::forward<SetXForm>(set_xform),
363  std::move(parents)...));
364 }
365 
366 } // namespace detail
367 
368 } // namespace funken
369 } // namespace atria
#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
constexpr int can_be_void
Use to allow a void expression by chaining it in a comma operator thing.
Definition: utils.hpp:103
STL namespace.
typename std::decay< T >::type decay_t
Similar to C++14 std::decay_t.
Definition: type_traits.hpp:54
This module implements the signal flow in funken.
C++ amazing templates and reusable implementations awesomeness.
Definition: _doc.hpp:35
Fork me on GitHub