OSSIA
Open Scenario System for Interactive Application
osc_value_write_visitor.hpp
1 #pragma once
2 #include <ossia/detail/buffer_pool.hpp>
4 #include <ossia/network/osc/detail/message_generator.hpp>
5 #include <ossia/network/osc/detail/osc_messages.hpp>
6 #include <ossia/network/osc/detail/osc_packet_processor.hpp>
7 #include <ossia/network/osc/detail/osc_utils.hpp>
8 #include <ossia/network/value/value.hpp>
9 
10 #include <boost/endian/conversion.hpp>
11 
12 #include <oscpack/osc/OscOutboundPacketStream.h>
13 #include <oscpack/osc/OscReceivedElements.h>
14 
15 namespace ossia::net
16 {
17 template <typename Parameter, typename OscPolicy, typename Writer>
18 #if __cpp_lib_concepts >= 201907L
19  requires std::is_invocable_v<Writer, const char*, std::size_t>
20 #endif
21 struct osc_value_send_visitor
22 {
23  const Parameter& parameter;
24  std::string_view address_pattern;
25  Writer writer;
26 
27  using static_policy = typename OscPolicy::static_policy;
28  using dynamic_policy = typename OscPolicy::dynamic_policy;
29 
30  template <typename T>
31  void operator()(T v) const noexcept
32  try
33  {
34  const std::size_t sz
35  = pattern_size(address_pattern.size()) + 8 + oscpack::RoundUp4(sizeof(v));
36  char* buffer = (char*)alloca(sz);
37  std::size_t i = write_string(address_pattern, buffer);
38 
39  i += static_policy{parameter.get_unit()}(buffer + i, v);
40 
41  writer(buffer, i);
42  }
43  catch(const std::exception& e)
44  {
45  ossia::logger().error("osc_value_send_visitor: {}", e.what());
46  }
47  catch(...)
48  {
49  ossia::logger().error("osc_value_send_visitor: unknown error");
50  }
51 
52  void operator()(ossia::impulse v) const noexcept
53  try
54  {
55  const std::size_t sz
56  = pattern_size(address_pattern.size()) + 8 + oscpack::RoundUp4(sizeof(v));
57  char* buffer = (char*)alloca(sz);
58  std::size_t i = write_string(address_pattern, buffer);
59 
60  if(auto ep = ossia::net::get_extended_type(parameter))
61  i += static_policy{parameter.get_unit()}(buffer + i, v, *ep);
62  else
63  i += static_policy{parameter.get_unit()}(buffer + i, v);
64 
65  writer(buffer, i);
66  }
67  catch(const std::exception& e)
68  {
69  ossia::logger().error("osc_value_send_visitor: {}", e.what());
70  }
71  catch(...)
72  {
73  ossia::logger().error("osc_value_send_visitor: unknown error");
74  }
75 
76  void operator()(const std::string& v) const noexcept
77  try
78  {
79  const std::size_t sz
80  = pattern_size(address_pattern.size()) + 4 + pattern_size(v.size());
81  if(sz < 16384)
82  {
83  char* buffer = (char*)alloca(sz);
84  std::size_t i = write_string(address_pattern, buffer);
85 
86  if(is_blob(parameter))
87  i += static_policy{parameter.get_unit()}(
88  buffer + i, oscpack::Blob(v.data(), v.size()));
89  else
90  i += static_policy{parameter.get_unit()}(buffer + i, v);
91 
92  writer(buffer, i);
93  }
94  else
95  {
96  auto& pool = buffer_pool::instance();
97  auto buffer = pool.acquire();
98  buffer.resize(sz);
99  std::size_t i = write_string(address_pattern, buffer.data());
100 
101  if(is_blob(parameter))
102  i += static_policy{parameter.get_unit()}(
103  buffer.data() + i, oscpack::Blob(v.data(), v.size()));
104  else
105  i += static_policy{parameter.get_unit()}(buffer.data() + i, v);
106 
107  writer(buffer.data(), i);
108  }
109  }
110  catch(const std::exception& e)
111  {
112  ossia::logger().error("osc_value_send_visitor: {}", e.what());
113  }
114  catch(...)
115  {
116  ossia::logger().error("osc_value_send_visitor: unknown error");
117  }
118 
119  void operator()(const std::vector<ossia::value>& v) const noexcept
120  try
121  {
122  auto& pool = buffer_pool::instance();
123  auto buf = pool.acquire();
124  while(buf.size() < max_osc_message_size)
125  {
126  try
127  {
128  oscpack::OutboundPacketStream p{buf.data(), buf.size()};
129 
130  p << oscpack::BeginMessageN(address_pattern);
131  dynamic_policy{{p, parameter.get_unit()}}(v);
132  p << oscpack::EndMessage();
133 
134  writer(p.Data(), p.Size());
135  break;
136  }
137  catch(...)
138  {
139  auto n = buf.size();
140  buf.clear();
141  buf.resize(n * 2 + 1);
142  }
143  }
144 
145  pool.release(std::move(buf));
146  }
147  catch(const std::exception& e)
148  {
149  ossia::logger().error("osc_value_send_visitor: {}", e.what());
150  }
151  catch(...)
152  {
153  ossia::logger().error("osc_value_send_visitor: unknown error");
154  }
155 
156  void operator()(const value_map_type& v) const noexcept { }
157 
158  void operator()() { }
159 };
160 
161 template <typename Parameter, typename OscPolicy>
162 struct osc_value_write_visitor
163 {
164  const Parameter& parameter;
165  std::string_view address_pattern;
166  ossia::buffer_pool::buffer& result;
167 
168  using static_policy = typename OscPolicy::static_policy;
169  using dynamic_policy = typename OscPolicy::dynamic_policy;
170 
171  template <typename T>
172  void operator()(T v) const noexcept
173  {
174  const std::size_t sz
175  = pattern_size(address_pattern.size()) + 8 + oscpack::RoundUp4(sizeof(v));
176  result.resize(sz);
177  std::size_t i = write_string(address_pattern, result.data());
178 
179  i += static_policy{parameter.get_unit()}(result.data() + i, v);
180 
181  result.resize(i);
182  }
183 
184  void operator()(const std::string& v) const noexcept
185  {
186  const std::size_t sz
187  = pattern_size(address_pattern.size()) + 4 + pattern_size(v.size());
188  result.resize(sz);
189  std::size_t i = write_string(address_pattern, result.data());
190 
191  if(is_blob(parameter))
192  i += static_policy{parameter.get_unit()}(
193  result.data() + i, oscpack::Blob(v.data(), v.size()));
194  else
195  i += static_policy{parameter.get_unit()}(result.data() + i, v);
196 
197  result.resize(i);
198  }
199 
200  void operator()(const std::vector<ossia::value>& v) const noexcept
201  {
202  // OPTIMIZEME
203  while(result.size() < max_osc_message_size)
204  {
205  try
206  {
207  oscpack::OutboundPacketStream p{result.data(), result.size()};
208 
209  p << oscpack::BeginMessageN(address_pattern);
210  dynamic_policy{{p, parameter.get_unit()}}(v);
211  p << oscpack::EndMessage();
212 
213  result.resize(p.Size());
214  break;
215  }
216  catch(...)
217  {
218  auto n = result.size();
219  result.clear();
220  result.resize(n * 2 + 1);
221  }
222  }
223  }
224 
225  void operator()(const value_map_type& v) const noexcept { }
226 
227  void operator()() { }
228 };
229 }
spdlog::logger & logger() noexcept
Where the errors will be logged. Default is stderr.
Definition: context.cpp:104