OSSIA
Open Scenario System for Interactive Application
value_algorithms.hpp
1 #pragma once
2 #include <ossia/network/value/value.hpp>
3 
4 namespace ossia
5 {
6 // SourcePrecedence causes the merging of values
7 // to occur only if the destination value is null
8 // (it won't replace an existing value).
9 
10 template <bool SourcePrecedence = true>
11 struct value_merger
12 {
13  template <typename Value_T>
14  static void merge_value(ossia::value& dest, Value_T&& src)
15  {
16  if(!dest.valid())
17  {
18  dest = src;
19  return;
20  }
21  else
22  {
23  if(dest.valid() && src.valid())
24  {
25  switch(src.get_type())
26  {
27  case ossia::val_type::LIST: {
28  auto& src_vec = src.template get<std::vector<ossia::value>>();
29  switch(dest.get_type())
30  {
32  merge_list(dest.get<std::vector<ossia::value>>(), src_vec);
33  break;
35  merge_list(dest.get<ossia::vec2f>(), src_vec);
36  break;
38  merge_list(dest.get<ossia::vec3f>(), src_vec);
39  break;
41  merge_list(dest.get<ossia::vec4f>(), src_vec);
42  break;
43  default:
44  break;
45  }
46  break;
47  }
49  auto& src_vec = src.template get<ossia::vec2f>();
50  switch(dest.get_type())
51  {
53  merge_list(dest.get<std::vector<ossia::value>>(), src_vec);
54  break;
56  merge_list(dest.get<ossia::vec2f>(), src_vec);
57  break;
59  merge_list(dest.get<ossia::vec3f>(), src_vec);
60  break;
62  merge_list(dest.get<ossia::vec4f>(), src_vec);
63  break;
64  default:
65  break;
66  }
67  break;
68  }
70  auto& src_vec = src.template get<ossia::vec3f>();
71  switch(dest.get_type())
72  {
74  merge_list(dest.get<std::vector<ossia::value>>(), src_vec);
75  break;
77  merge_list(dest.get<ossia::vec2f>(), src_vec);
78  break;
80  merge_list(dest.get<ossia::vec3f>(), src_vec);
81  break;
83  merge_list(dest.get<ossia::vec4f>(), src_vec);
84  break;
85  default:
86  break;
87  }
88  break;
89  }
91  auto& src_vec = src.template get<ossia::vec4f>();
92  switch(dest.get_type())
93  {
95  merge_list(dest.get<std::vector<ossia::value>>(), src_vec);
96  break;
98  merge_list(dest.get<ossia::vec2f>(), src_vec);
99  break;
101  merge_list(dest.get<ossia::vec3f>(), src_vec);
102  break;
104  merge_list(dest.get<ossia::vec4f>(), src_vec);
105  break;
106  default:
107  break;
108  }
109  break;
110  }
111  default: {
112  switch(dest.get_type())
113  {
115  set_first_value(
116  dest.get<std::vector<ossia::value>>(), std::forward<Value_T>(src));
117  break;
119  set_first_value(dest.get<ossia::vec2f>(), std::forward<Value_T>(src));
120  break;
122  set_first_value(dest.get<ossia::vec3f>(), std::forward<Value_T>(src));
123  break;
125  set_first_value(dest.get<ossia::vec4f>(), std::forward<Value_T>(src));
126  break;
127  default: {
128  // src overwrites dest
129  if(SourcePrecedence)
130  dest = std::forward<Value_T>(src);
131  return;
132  }
133  }
134  break;
135  }
136  }
137  return;
138  }
139  else
140  {
141  if(auto dest_list_ptr = dest.target<std::vector<ossia::value>>())
142  {
143  // Merge a single value in a list
144  set_first_value(*dest_list_ptr, std::forward<Value_T>(src));
145  return;
146  }
147  else if(auto src_list_ptr = src.template target<std::vector<ossia::value>>())
148  {
149  // If one of the two values is invalid, we always keep the other
150  if(src_list_ptr->empty())
151  {
152  std::vector<ossia::value> t{dest};
153  dest = std::move(t);
154  return;
155  }
156  else if(!(*src_list_ptr)[0].valid())
157  {
158  std::vector<ossia::value> t = *src_list_ptr;
159  t[0] = dest;
160  dest = std::move(t);
161  return;
162  }
163  else
164  {
165  // src overwrites dest
166  if(src.valid() && SourcePrecedence)
167  dest = std::forward<Value_T>(src);
168  return;
169  }
170  }
171  else
172  {
173  // src overwrites dest
174  if(src.valid() && SourcePrecedence)
175  dest = std::forward<Value_T>(src);
176  return;
177  }
178  }
179  }
180  }
181 
182  template <typename Value_T>
183  static void insert_in_list(
184  std::vector<ossia::value>& t, Value_T&& v, const ossia::destination_index& idx)
185  {
186  std::vector<ossia::value>* cur_ptr = &t;
187  for(auto it = idx.begin(); it != idx.end();)
188  {
189  auto& cur = *cur_ptr;
190  std::size_t pos = *it;
191  if(cur.size() < pos + 1)
192  {
193  cur.resize(pos + 1);
194  }
195 
196  if(++it == idx.end())
197  {
198  // We're at the deepest index position :
199  // we add the value at the current place.
200  merge_value(cur[pos], std::forward<Value_T>(v));
201  }
202  else
203  {
204  // We go through another depth layer.
205  if(auto sub_list = cur[pos].target<std::vector<ossia::value>>())
206  {
207  cur_ptr = sub_list;
208  }
209  else
210  {
211  // We put the current value at cur[pos] at index 0 of the
212  // newly-created sub-list.
213  std::vector<ossia::value> sub{std::move(cur[pos])};
214  cur[pos] = std::move(sub);
215 
216  // And use it for the next iteration
217  cur_ptr = cur[pos].target<std::vector<ossia::value>>();
218  }
219  }
220  }
221  }
222 
223  static void write_float(const ossia::value& val, float& f)
224  {
225  if(val.valid())
226  {
227  switch(val.get_type())
228  {
230  f = (float)val.template get<int32_t>();
231  break;
232  case ossia::val_type::FLOAT:
233  f = (float)val.template get<float>();
234  break;
236  f = (float)val.template get<bool>();
237  break;
238  default:
239  break;
240  }
241  }
242  }
243 
244  template <std::size_t N, typename Value_T>
245  static void set_first_value(std::array<float, N>& t, Value_T&& val)
246  {
247  write_float(val, t[0]);
248  }
249 
250  template <typename Value_T>
251  static void set_first_value(std::vector<ossia::value>& t, Value_T&& val)
252  {
253  if(t.empty())
254  {
255  t.push_back(std::forward<Value_T>(val));
256  }
257  else
258  {
259  merge_value(t[0], std::forward<Value_T>(val));
260  }
261  }
262 
263  static void
264  merge_list(std::vector<ossia::value>& lhs, const std::vector<ossia::value>& rhs)
265  {
266  std::size_t n = rhs.size();
267  if(lhs.size() < n)
268  {
269  lhs.resize(n);
270  }
271 
272  for(std::size_t i = 0u; i < n; i++)
273  {
274  merge_value(lhs[i], rhs[i]);
275  }
276  }
277  static void merge_list(std::vector<ossia::value>& lhs, std::vector<ossia::value>&& rhs)
278  {
279  std::size_t n = rhs.size();
280  if(lhs.size() < n)
281  {
282  lhs.resize(n);
283  }
284 
285  for(std::size_t i = 0u; i < n; i++)
286  {
287  merge_value(lhs[i], std::move(rhs)[i]);
288  }
289  }
290 
291  template <std::size_t N>
292  static void merge_list(std::vector<ossia::value>& lhs, const std::array<float, N>& rhs)
293  {
294  if(lhs.size() < N)
295  {
296  lhs.resize(N);
297  }
298 
299  for(std::size_t i = 0u; i < N; i++)
300  {
301  lhs[i] = rhs[i];
302  }
303  }
304 
305  template <std::size_t N>
306  static void merge_list(std::array<float, N>& lhs, const std::vector<ossia::value>& rhs)
307  {
308  const std::size_t n = std::min(N, rhs.size());
309  for(std::size_t i = 0u; i < n; i++)
310  {
311  write_float(rhs[i], lhs[i]);
312  }
313  }
314 
315  template <std::size_t N, std::size_t M>
316  static void merge_list(std::array<float, N>& lhs, const std::array<float, M>& rhs)
317  {
318  const std::size_t n = std::min(N, M);
319  for(std::size_t i = 0u; i < n; i++)
320  {
321  lhs[i] = rhs[i];
322  }
323  }
324 };
325 
326 namespace detail
327 {
336 {
337  const ossia::destination_index& index;
338  ossia::destination_index::const_iterator it;
339 
340  ossia::value operator()(const std::vector<ossia::value>& t)
341  {
342  if(it == index.end())
343  {
344  return ossia::value{t};
345  }
346  else if((int64_t)t.size() > *it)
347  {
348  auto& val = t[*it];
349  ++it;
350  return val.apply(*this);
351  }
352  else
353  {
354  return {};
355  }
356  }
357 
358  template <typename T>
359  ossia::value operator()(const T& t)
360  {
361  if(it == index.end())
362  {
363  return t;
364  }
365  else
366  {
367  return {};
368  }
369  }
370 
371  template <std::size_t N>
372  ossia::value operator()(const std::array<float, N>& t)
373  {
374  if(it == index.end())
375  {
376  return t;
377  }
378  else if((int64_t)t.size() > *it)
379  {
380  if(it + 1 == index.end())
381  return float{t[*it]};
382  }
383 
384  return {};
385  }
386 
387  ossia::value operator()() { return {}; }
388 };
389 }
390 }
The value class.
Definition: value.hpp:173
Definition: git_info.h:7
@ VEC3F
array<float, 2>
@ LIST
std::string
@ VEC4F
array<float, 3>
@ BOOL
ossia::impulse
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
ossia::small_vector< int32_t, 2 > destination_index
Definition: destination_index.hpp:40
The destination_index_retriever struct Get the value associated with an index in a list....
Definition: value_algorithms.hpp:336