OSSIA
Open Scenario System for Interactive Application
Loading...
Searching...
No Matches
value_conversion_impl.hpp
1#pragma once
2#include <ossia/detail/config.hpp>
3
4#include <ossia/detail/fmt.hpp>
5#include <ossia/detail/parse_relax.hpp>
6#include <ossia/network/value/value.hpp>
9
10#include <boost/type_traits/function_traits.hpp>
11namespace ossia
12{
13
14namespace detail
15{
16template <typename T>
17struct array_size;
18template <typename T, std::size_t N>
19struct array_size<std::array<T, N>> : public std::integral_constant<std::size_t, N>
20{
21};
22
23template <typename Target, typename = void>
24struct value_converter
25{
26};
27
28template <>
29struct value_converter<ossia::impulse>
30{
31 ossia::impulse cur;
32 template <typename U>
33 ossia::impulse operator()(const U&)
34 {
35 return {};
36 }
37
38 ossia::impulse operator()() { return {}; }
39};
40
41template <typename T>
42struct numeric_value_converter
43{
44 T cur{};
45
46 T operator()(impulse) const { return T{}; }
47 T operator()(int32_t v) { return v; }
48 T operator()(float v) { return v; }
49 T operator()(bool v) { return v; }
50 T operator()(char v) { return v; }
51 T operator()() const { return T{}; }
52
53 T operator()(const std::string& v) const = delete;
54 T operator()(const vec2f& v) const { return v[0]; }
55 T operator()(const vec3f& v) const { return v[0]; }
56 T operator()(const vec4f& v) const { return v[0]; }
57
58 T operator()(const std::vector<ossia::value>& v) const
59 {
60 return !v.empty() ? convert<T>(v[0]) : T{};
61 }
62 T operator()(const value_map_type& v) const
63 {
64 return !v.empty() ? convert<T>(v.begin()->second) : T{};
65 }
66};
67
68template <>
69struct value_converter<int32_t> : public numeric_value_converter<int32_t>
70{
71 using numeric_value_converter<int32_t>::operator();
72 int32_t operator()(const std::string& v) const
73 {
74 if(auto n = parse_relax<int>(v))
75 return *n;
76 return {};
77 }
78};
79template <>
80struct value_converter<float> : public numeric_value_converter<float>
81{
82 using numeric_value_converter<float>::operator();
83 float operator()(const std::string& v) const
84 {
85 if(auto n = parse_relax<float>(v))
86 return *n;
87 return {};
88 }
89};
90template <>
91struct value_converter<double> : public numeric_value_converter<double>
92{
93 using numeric_value_converter<double>::operator();
94 double operator()(const std::string& v) const
95 {
96 if(auto n = parse_relax<double>(v))
97 return *n;
98 return {};
99 }
100};
101template <>
102struct value_converter<bool> : public numeric_value_converter<bool>
103{
104 using numeric_value_converter<bool>::operator();
105 bool operator()(const std::string& v) const
106 {
107 return v.starts_with('T') || v.starts_with('t') || v.starts_with('Y')
108 || v.starts_with('y') || v == "1";
109 }
110};
111template <>
112struct value_converter<char> : public numeric_value_converter<char>
113{
114};
115
116#if defined(OSSIA_HAS_FMT)
117struct fmt_writer
118{
119 fmt::memory_buffer& wr;
120
121 void operator()(impulse) const { fmt::format_to(fmt::appender(wr), "impulse"); }
122 void operator()(int32_t v) const { fmt::format_to(fmt::appender(wr), "{}", v); }
123 void operator()(float v) const { fmt::format_to(fmt::appender(wr), "{}", v); }
124 void operator()(bool v) const
125 {
126 if(v)
127 fmt::format_to(fmt::appender(wr), "true");
128 else
129 fmt::format_to(fmt::appender(wr), "false");
130 }
131 void operator()(char v) const { fmt::format_to(fmt::appender(wr), "{}", v); }
132 void operator()(const std::string& v) const
133 {
134 fmt::format_to(fmt::appender(wr), "{}", v);
135 }
136 void operator()() const { }
137 template <std::size_t N>
138 void operator()(std::array<float, N> v) const
139 {
140 fmt::format_to(fmt::appender(wr), "[{}", v[0]);
141 for(std::size_t i = 1; i < N; i++)
142 fmt::format_to(fmt::appender(wr), ", {}", v[i]);
143 fmt::format_to(fmt::appender(wr), "]");
144 }
145 void operator()(const std::vector<ossia::value>& v) const
146 {
147 using namespace std::literals;
148 fmt::format_to(fmt::appender(wr), "[");
149 const auto n = v.size();
150 if(n > 0)
151 {
152 v[0].apply(*this);
153
154 for(std::size_t i = 1; i < n; i++)
155 {
156 fmt::format_to(fmt::appender(wr), ", ");
157 v[i].apply(*this);
158 }
159 }
160 fmt::format_to(fmt::appender(wr), "]");
161 }
162 void operator()(const value_map_type& v) const
163 {
164 using namespace std::literals;
165 fmt::format_to(fmt::appender(wr), "{{");
166 const auto n = v.size();
167 if(n > 0)
168 {
169 auto it = v.begin();
170 fmt::format_to(fmt::appender(wr), "\"{}\": ", it->first);
171 it->second.apply(*this);
172
173 for(++it; it != v.end(); ++it)
174 {
175 fmt::format_to(fmt::appender(wr), ", \"{}\": ", it->first);
176 it->second.apply(*this);
177 }
178 }
179 fmt::format_to(fmt::appender(wr), "}}");
180 }
181};
182
183template <>
184struct value_converter<std::string>
185{
186 const std::string& cur;
187 using T = std::string;
188 T operator()(impulse) const { return "impulse"; }
189 T operator()(int32_t v) const { return fmt::format("{}", v); }
190 T operator()(float v) const { return fmt::format("{}", v); }
191 T operator()(bool v) const
192 {
193 using namespace std::literals;
194 return v ? "true"s : "false"s;
195 }
196 T operator()(char v) const { return std::string(1, v); }
197 T operator()(const std::string& v) const { return v; }
198
199 T operator()() const { return {}; }
200
201 template <std::size_t N>
202 T operator()(std::array<float, N> v) const
203 {
204 std::string wr;
205 wr.reserve(N * 10);
206 fmt::format_to(std::back_inserter(wr), "[{}", v[0]);
207 for(std::size_t i = 1; i < N; i++)
208 fmt::format_to(std::back_inserter(wr), ", {}", v[i]);
209 fmt::format_to(std::back_inserter(wr), "]");
210 return wr;
211 }
212
213 T operator()(const std::vector<ossia::value>& v) const
214 {
215 using namespace std::literals;
216 fmt::memory_buffer wr;
217 fmt_writer{wr}(v);
218 return {wr.data(), wr.size()};
219 }
220
221 T operator()(const value_map_type& v) const
222 {
223 using namespace std::literals;
224 fmt::memory_buffer wr;
225 fmt_writer{wr}(v);
226 return {wr.data(), wr.size()};
227 }
228};
229#else
230
231template <>
232struct value_converter<std::string>
233{
234 const std::string& cur;
235 using T = std::string;
236 T operator()(impulse) const { return "impulse"; }
237 T operator()(int32_t v) const { return std::to_string(v); }
238 T operator()(float v) const { return std::to_string(v); }
239 T operator()(bool v) const
240 {
241 using namespace std::literals;
242 return v ? "true"s : "false"s;
243 }
244 T operator()(char v) const { return std::string(1, v); }
245 T operator()(const std::string& v) const { return v; }
246
247 T operator()() const { return {}; }
248
249 template <std::size_t N>
250 T operator()(std::array<float, N> v) const
251 {
252 std::string wr;
253 wr.reserve(N * 10);
254 wr += "[";
255 wr += std::to_string(v[0]);
256
257 for(std::size_t i = 1; i < N; i++)
258 {
259 wr += ", ";
260 wr += std::to_string(v[i]);
261 }
262 wr += "]";
263 return wr;
264 }
265
266 T operator()(const std::vector<ossia::value>& v) const { return "(TODO)"; }
267
268 T operator()(const value_map_type& v) const { return "(TODO)"; }
269};
270#endif
271
272template <>
273struct value_converter<std::vector<ossia::value>>
274{
275 const std::vector<ossia::value>& cur;
276 template <typename U>
277 std::vector<ossia::value> operator()(const U& u)
278 {
279 return {u};
280 }
281
282 template <std::size_t N>
283 std::vector<ossia::value> operator()(const std::array<float, N>& u)
284 {
285 std::vector<ossia::value> v;
286 for(std::size_t i = 0; i < N; i++)
287 {
288 v.emplace_back(float{u[i]});
289 }
290 return v;
291 }
292
293 std::vector<ossia::value> operator()(const std::vector<ossia::value>& t) { return t; }
294 std::vector<ossia::value> operator()(std::vector<ossia::value>&& t)
295 {
296 return std::move(t);
297 }
298
299 std::vector<ossia::value> operator()() { return {}; }
300};
301
302template <>
303struct value_converter<value_map_type>
304{
305 const value_map_type& cur;
306 template <typename U>
307 value_map_type operator()(const U& u)
308 {
309 return value_map_type{{"0", u}};
310 }
311
312 template <std::size_t N>
313 value_map_type operator()(const std::array<float, N>& u)
314 {
315 value_map_type v;
316 for(std::size_t i = 0; i < N; i++)
317 {
318 v[std::to_string(i)] = float{u[i]};
319 }
320 return v;
321 }
322
323 value_map_type operator()(const std::vector<ossia::value>& t)
324 {
325 value_map_type v;
326 for(std::size_t i = 0; i < t.size(); i++)
327 {
328 v[std::to_string(i)] = t[i];
329 }
330 return v;
331 }
332 value_map_type operator()(std::vector<ossia::value>&& t)
333 {
334 value_map_type v;
335 for(std::size_t i = 0; i < t.size(); i++)
336 {
337 v[std::to_string(i)] = std::move(t[i]);
338 }
339 return v;
340 }
341
342 value_map_type operator()(const value_map_type& t) { return t; }
343 value_map_type operator()(value_map_type&& t) { return std::move(t); }
344
345 value_map_type operator()() { return {}; }
346};
347
348template <std::size_t N>
349struct value_converter<std::array<float, N>>
350{
351 const std::array<float, N>& cur;
352 template <typename U>
353 std::array<float, N> operator()(const U&)
354 {
355 return {};
356 }
357
358 std::array<float, N> operator()(std::array<float, N> v) { return v; }
359
360 template <std::size_t M>
361 std::array<float, N> operator()(std::array<float, M> v)
362 {
363 std::array<float, N> a = cur;
364 for(std::size_t i = 0; i < std::min(N, M); i++)
365 {
366 a[i] = v[i];
367 }
368 return a;
369 }
370
371 std::array<float, N> operator()(float f)
372 {
373 std::array<float, N> a;
374 a.fill(f);
375 return a;
376 }
377
378 std::array<float, N> operator()(int32_t f)
379 {
380 std::array<float, N> a;
381 a.fill(f);
382 return a;
383 }
384
385 std::array<float, N> operator()(char f)
386 {
387 std::array<float, N> a;
388 a.fill(f);
389 return a;
390 }
391
392 std::array<float, N> operator()(bool f)
393 {
394 std::array<float, N> a;
395 a.fill(f ? 1. : 0.);
396 return a;
397 }
398
399 std::array<float, N> operator()(const std::vector<ossia::value>& t)
400 {
401 return convert<std::array<float, N>>(t);
402 }
403
404 std::array<float, N> operator()(const value_map_type& t) { return {}; }
405
406 std::array<float, N> operator()() { return {}; }
407};
408}
409
410template <typename T>
411T convert(const ossia::value& val)
412{
413 return val.apply(detail::value_converter<T>{{T{}}});
414}
415
416template <typename T>
417void convert_inplace(ossia::value& val)
418{
419 val = val.apply(detail::value_converter<T>{{T{}}});
420}
421
422template <typename T>
423T convert(const T& cur, const ossia::value& val)
424{
425 return val.apply(detail::value_converter<T>{{cur}});
426}
427
428// Used to convert List in Vec2f, Vec3f, Vec4f...
429template <typename T>
430T convert(const std::vector<ossia::value>& val)
431{
432 // TODO should we have an error if the List does not
433 // have the correct number of arguments ? Or just silently fill
434 // with zeros ?
435
436 T res{};
437 const auto N = std::min(val.size(), detail::array_size<T>::value);
438 for(std::size_t i = 0; i < N; i++)
439 {
440 res[i] = val[i].apply(detail::value_converter<typename T::value_type>{});
441 }
442 return res;
443}
444
445// MOVEME
446template <typename Fun, typename... Args>
447auto lift(ossia::val_type type, Fun f, Args&&... args)
448{
449 switch(type)
450 {
452 return f(ossia::value_trait<impulse>{}, std::forward<Args>(args)...);
453 case val_type::BOOL:
454 return f(ossia::value_trait<bool>{}, std::forward<Args>(args)...);
455 case val_type::INT:
456 return f(ossia::value_trait<int32_t>{}, std::forward<Args>(args)...);
457 case val_type::FLOAT:
458 return f(ossia::value_trait<float>{}, std::forward<Args>(args)...);
459 case val_type::MAP:
460 return f(ossia::value_trait<value_map_type>{}, std::forward<Args>(args)...);
461 case val_type::STRING:
462 return f(ossia::value_trait<std::string>{}, std::forward<Args>(args)...);
463 case val_type::LIST:
464 return f(
465 ossia::value_trait<std::vector<ossia::value>>{}, std::forward<Args>(args)...);
466 case val_type::VEC2F:
467 return f(ossia::value_trait<vec2f>{}, std::forward<Args>(args)...);
468 case val_type::VEC3F:
469 return f(ossia::value_trait<vec3f>{}, std::forward<Args>(args)...);
470 case val_type::VEC4F:
471 return f(ossia::value_trait<vec4f>{}, std::forward<Args>(args)...);
472 case val_type::NONE:
473 break;
474 }
475
476 ossia_do_throw(invalid_value_type_error, "lift: Invalid type");
477 return decltype(f(ossia::value_trait<impulse>{}, std::forward<Args>(args)...)){};
478}
479template <typename Fun, typename... Args>
480auto lift_inplace(ossia::val_type type, Fun f, Args&&... args)
481{
482 switch(type)
483 {
485 f(ossia::value_trait<impulse>{}, std::forward<Args>(args)...);
486 break;
487 case val_type::BOOL:
488 f(ossia::value_trait<bool>{}, std::forward<Args>(args)...);
489 break;
490 case val_type::INT:
491 f(ossia::value_trait<int32_t>{}, std::forward<Args>(args)...);
492 break;
493 case val_type::FLOAT:
494 f(ossia::value_trait<float>{}, std::forward<Args>(args)...);
495 break;
496 case val_type::MAP:
497 f(ossia::value_trait<value_map_type>{}, std::forward<Args>(args)...);
498 break;
499 case val_type::STRING:
500 f(ossia::value_trait<std::string>{}, std::forward<Args>(args)...);
501 break;
502 case val_type::LIST:
503 f(ossia::value_trait<std::vector<ossia::value>>{}, std::forward<Args>(args)...);
504 break;
505 case val_type::VEC2F:
506 f(ossia::value_trait<vec2f>{}, std::forward<Args>(args)...);
507 break;
508 case val_type::VEC3F:
509 f(ossia::value_trait<vec3f>{}, std::forward<Args>(args)...);
510 break;
511 case val_type::VEC4F:
512 f(ossia::value_trait<vec4f>{}, std::forward<Args>(args)...);
513 break;
514 case val_type::NONE:
515 break;
516 }
517}
518}
519
520extern template double ossia::convert<double>(const ossia::value&);
521extern template float ossia::convert<float>(const ossia::value&);
522extern template int32_t ossia::convert<int32_t>(const ossia::value&);
523// extern template char ossia::convert<char>(const ossia::value&);
524extern template bool ossia::convert<bool>(const ossia::value&);
525extern template std::string ossia::convert<std::string>(const ossia::value&);
526extern template std::vector<ossia::value>
527ossia::convert<std::vector<ossia::value>>(const ossia::value&);
528extern template ossia::vec2f ossia::convert<ossia::vec2f>(const ossia::value&);
529extern template ossia::vec3f ossia::convert<ossia::vec3f>(const ossia::value&);
530extern template ossia::vec4f ossia::convert<ossia::vec4f>(const ossia::value&);
The value class.
Definition value.hpp:173
Definition git_info.h:7
val_type
Enum to represent the types that a value can take.
Definition parameter_properties.hpp:16
@ IMPULSE
array<float, 4>
@ VEC3F
array<float, 2>
@ LIST
std::string
@ VEC4F
array<float, 3>
@ MAP
std::vector<value>
@ BOOL
ossia::impulse
@ NONE
map<string, value>