OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
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
15namespace ossia::net
16{
17template <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
21struct 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
132 bool ok = false;
133 if(auto ep = ossia::net::get_extended_type(parameter))
134 ok = process_extended_array(*ep, p, v);
135 if(!ok)
136 dynamic_policy{{p, parameter.get_unit()}}(v);
137 p << oscpack::EndMessage();
138
139 writer(p.Data(), p.Size());
140 break;
141 }
142 catch(...)
143 {
144 auto n = buf.size();
145 buf.clear();
146 buf.resize(n * 2 + 1);
147 }
148 }
149
150 pool.release(std::move(buf));
151 }
152 catch(const std::exception& e)
153 {
154 ossia::logger().error("osc_value_send_visitor: {}", e.what());
155 }
156 catch(...)
157 {
158 ossia::logger().error("osc_value_send_visitor: unknown error");
159 }
160
161 void operator()(const value_map_type& v) const noexcept { }
162 void operator()() { }
163
164 bool process_extended_array(
165 const ossia::extended_type& e, oscpack::OutboundPacketStream& out,
166 const std::vector<ossia::value>& v) const
167 {
168 if(e == u8_blob_type())
169 {
170 std::string data;
171 for(auto& val : v)
172 {
173 data += static_cast<unsigned char>(ossia::convert<int>(val));
174 }
175
176 oscpack::Blob b(data.data(), data.size());
177 out << b;
178 return true;
179 }
180 return false;
181 }
182};
183
184template <typename Parameter, typename OscPolicy>
185struct osc_value_write_visitor
186{
187 const Parameter& parameter;
188 std::string_view address_pattern;
189 ossia::buffer_pool::buffer& result;
190
191 using static_policy = typename OscPolicy::static_policy;
192 using dynamic_policy = typename OscPolicy::dynamic_policy;
193
194 template <typename T>
195 void operator()(T v) const noexcept
196 {
197 const std::size_t sz
198 = pattern_size(address_pattern.size()) + 8 + oscpack::RoundUp4(sizeof(v));
199 result.resize(sz);
200 std::size_t i = write_string(address_pattern, result.data());
201
202 i += static_policy{parameter.get_unit()}(result.data() + i, v);
203
204 result.resize(i);
205 }
206
207 void operator()(const std::string& v) const noexcept
208 {
209 const std::size_t sz
210 = pattern_size(address_pattern.size()) + 4 + pattern_size(v.size());
211 result.resize(sz);
212 std::size_t i = write_string(address_pattern, result.data());
213
214 if(is_blob(parameter))
215 i += static_policy{parameter.get_unit()}(
216 result.data() + i, oscpack::Blob(v.data(), v.size()));
217 else
218 i += static_policy{parameter.get_unit()}(result.data() + i, v);
219
220 result.resize(i);
221 }
222
223 void operator()(const std::vector<ossia::value>& v) const noexcept
224 {
225 // OPTIMIZEME
226 while(result.size() < max_osc_message_size)
227 {
228 try
229 {
230 oscpack::OutboundPacketStream p{result.data(), result.size()};
231
232 p << oscpack::BeginMessageN(address_pattern);
233 dynamic_policy{{p, parameter.get_unit()}}(v);
234 p << oscpack::EndMessage();
235
236 result.resize(p.Size());
237 break;
238 }
239 catch(...)
240 {
241 auto n = result.size();
242 result.clear();
243 result.resize(n * 2 + 1);
244 }
245 }
246 }
247
248 void operator()(const value_map_type& v) const noexcept { }
249
250 void operator()() { }
251};
252}
spdlog::logger & logger() noexcept
Where the errors will be logged. Default is stderr.
Definition context.cpp:118
std::string extended_type
How a low-level type should be interpreted.
Definition complex_type.hpp:9
extended_type u8_blob_type()
Definition extended_types.cpp:43