write.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/prelude/comp.hpp>
34 #include <functional>
35 #include <ostream>
36 
37 namespace atria {
38 namespace xform {
39 
40 namespace detail {
41 
42 struct empty_output {};
43 
44 template <typename StreamT>
45 StreamT& operator<< (StreamT& stream, empty_output)
46 {
47  return stream;
48 }
49 
50 struct write_rf_gen
51 {
52  template <typename ReducingFnT,
53  typename OutputStreamRefT,
54  typename InSeparatorT,
55  typename ArgSeparatorT>
56  struct apply
57  {
58  ReducingFnT step;
59  OutputStreamRefT stream_ref;
60  InSeparatorT in_separator;
61  ArgSeparatorT arg_separator;
62 
63  template <typename OutputStreamT>
64  void impl(OutputStreamT&) {}
65 
66  template <typename OutputStreamT, typename InputT>
67  void impl(OutputStreamT& stream, InputT&& in)
68  {
69  stream << std::forward<InputT>(in);
70  }
71 
72  template <typename OutputStreamT, typename InputT, typename... InputTs>
73  void impl(OutputStreamT& stream, InputT&& in, InputTs... ins)
74  {
75  stream << std::forward<InputT>(in)
76  << arg_separator;
77  impl(stream, std::forward<InputTs>(ins)...);
78  }
79 
80  template <typename StateT, typename ...InputTs>
81  auto operator() (StateT&& s, InputTs&& ...is)
82  -> decltype(wrap_state(step(state_unwrap(s), is...)))
83  {
84  using std::begin;
85  using std::end;
86 
87  using result_t = decltype(wrap_state(step(state_unwrap(s), is...)));
88  using complete_t = decltype(state_complete(s));
89 
90  using wrapped_t = meta::copy_decay_t<StateT, estd::decay_t<result_t>>;
91  using unwrapped_t = meta::copy_decay_t<StateT, estd::decay_t<complete_t>>;
92 
93  auto& stream = stream_ref.get();
94  return with_state(
95  std::forward<StateT>(s),
96  [&] (unwrapped_t&& st) {
97  impl(stream, is...);
98  return wrap_state(
99  step(std::forward<unwrapped_t>(st),
100  std::forward<InputTs>(is)...));
101  },
102  [&] (wrapped_t&& st) {
103  stream << in_separator;
104  impl(stream, is...);
105  return wrap_state(
106  step(state_unwrap(std::forward<wrapped_t>(st)),
107  std::forward<InputTs>(is)...));
108  });
109  }
110  };
111 };
112 
113 } // namespace detail
114 
115 template <typename OutputStreamRefT, typename InSeparatorT, typename ArgSeparatorT>
116 using write_t = transducer_impl<detail::write_rf_gen,
117  OutputStreamRefT,
118  InSeparatorT,
119  ArgSeparatorT>;
120 
125 template <typename OutputStreamT, typename InSeparatorT = detail::empty_output>
126 auto write(OutputStreamT& stream, InSeparatorT in_sep = InSeparatorT{})
127  -> write_t<std::reference_wrapper<OutputStreamT>,
128  InSeparatorT,
129  InSeparatorT>
130 {
131  auto arg_sep = in_sep;
132  return { std::ref(stream), std::move(in_sep), std::move(arg_sep) };
133 }
134 
135 template <typename OutputStreamT, typename InSeparatorT, typename ArgSeparatorT>
136 auto write(OutputStreamT& stream, InSeparatorT in_sep, ArgSeparatorT arg_sep)
137  -> write_t<std::reference_wrapper<OutputStreamT>,
138  InSeparatorT,
139  ArgSeparatorT>
140 {
141  return { std::ref(stream), std::move(in_sep), std::move(arg_sep) };
142 }
143 
144 } // namespace xform
145 } // namespace atria
auto state_unwrap(T &&s) -> decltype(state_traits_t< T >::unwrap(std::forward< T >(s)))
Convenience function for calling state_traits::unwrap
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
auto in(InT &&object) -> estd::enable_if_t< (In_value< InT >()), detail::input_impl< detail::signal_type_t< InT > > >
Creates an in from another in value.
Definition: in.hpp:103
auto state_complete(T &&s) -> decltype(state_traits_t< T >::complete(std::forward< T >(s)))
Convenience function for calling state_traits::complete
C++ amazing templates and reusable implementations awesomeness.
Definition: _doc.hpp:35
auto write(OutputStreamT &stream, InSeparatorT in_sep=InSeparatorT{}) -> write_t< std::reference_wrapper< OutputStreamT >, InSeparatorT, InSeparatorT >
Transducer that writes the into a given stream using the operator <<.
Definition: write.hpp:126
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.
Fork me on GitHub