OSSIA
Open Scenario System for Interactive Application
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>
11 namespace ossia
12 {
13 
14 namespace detail
15 {
16 template <typename T>
17 struct array_size;
18 template <typename T, std::size_t N>
19 struct array_size<std::array<T, N>> : public std::integral_constant<std::size_t, N>
20 {
21 };
22 
23 template <typename Target, typename = void>
24 struct value_converter
25 {
26 };
27 
28 template <>
29 struct 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 
41 template <typename T>
42 struct 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 
68 template <>
69 struct 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 };
79 template <>
80 struct 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 };
90 template <>
91 struct 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 };
101 template <>
102 struct 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 };
111 template <>
112 struct value_converter<char> : public numeric_value_converter<char>
113 {
114 };
115 
116 #if defined(OSSIA_HAS_FMT)
117 struct 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 
183 template <>
184 struct 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 
231 template <>
232 struct 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 
272 template <>
273 struct 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 
302 template <>
303 struct 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 
348 template <std::size_t N>
349 struct 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 
410 template <typename T>
411 T convert(const ossia::value& val)
412 {
413  return val.apply(detail::value_converter<T>{{T{}}});
414 }
415 
416 template <typename T>
417 void convert_inplace(ossia::value& val)
418 {
419  val = val.apply(detail::value_converter<T>{{T{}}});
420 }
421 
422 template <typename T>
423 T 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...
429 template <typename T>
430 T 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
446 template <typename Fun, typename... Args>
447 auto lift(ossia::val_type type, Fun f, Args&&... args)
448 {
449  switch(type)
450  {
451  case val_type::IMPULSE:
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 }
479 template <typename Fun, typename... Args>
480 auto lift_inplace(ossia::val_type type, Fun f, Args&&... args)
481 {
482  switch(type)
483  {
484  case val_type::IMPULSE:
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 
520 extern template double ossia::convert<double>(const ossia::value&);
521 extern template float ossia::convert<float>(const ossia::value&);
522 extern template int32_t ossia::convert<int32_t>(const ossia::value&);
523 // extern template char ossia::convert<char>(const ossia::value&);
524 extern template bool ossia::convert<bool>(const ossia::value&);
525 extern template std::string ossia::convert<std::string>(const ossia::value&);
526 extern template std::vector<ossia::value>
527 ossia::convert<std::vector<ossia::value>>(const ossia::value&);
528 extern template ossia::vec2f ossia::convert<ossia::vec2f>(const ossia::value&);
529 extern template ossia::vec3f ossia::convert<ossia::vec3f>(const ossia::value&);
530 extern 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>
constexpr OSSIA_INLINE auto min(const T a, const U b) noexcept -> typename std::conditional<(sizeof(T) > sizeof(U)), T, U >::type
min function tailored for values
Definition: math.hpp:125