OpenShot Audio Library | OpenShotAudio  0.6.0
juce_Serialisation.h
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2022 - Raw Material Software Limited
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  The code included in this file is provided under the terms of the ISC license
11  http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12  To use, copy, modify, and/or distribute this software for any purpose with or
13  without fee is hereby granted provided that the above copyright notice and
14  this permission notice appear in all copies.
15 
16  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18  DISCLAIMED.
19 
20  ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
65 template <typename T> struct SerialisationTraits
66 {
67  /* Intentionally left blank. */
68 };
69 
70 #define JUCE_COMPARISON_OPS X(==) X(!=) X(<) X(<=) X(>) X(>=)
71 
86 template <typename T>
87 struct Named
88 {
89  #define X(op) auto operator op (const Named& other) const { return value op other.value; }
90  JUCE_COMPARISON_OPS
91  #undef X
92 
93  std::string_view name;
94  T& value;
95 };
96 
98 template <typename T> constexpr auto named (std::string_view c, T& t) { return Named<T> { c, t }; }
99 
101 template <typename T> constexpr auto named (std::string_view c, const T& t) { return Named<const T> { c, t }; }
102 
116 template <typename T>
118 {
119  #define X(op) auto operator op (const SerialisationSize& other) const { return size op other.size; }
120  JUCE_COMPARISON_OPS
121  #undef X
122 
123  T& size;
124 };
125 
127 template <typename T> constexpr auto serialisationSize (T& t) -> std::enable_if_t<std::is_integral_v<T>, SerialisationSize<T>> { return { t }; }
128 
130 template <typename T> constexpr auto serialisationSize (const T& t) -> std::enable_if_t<std::is_integral_v<T>, SerialisationSize<const T>> { return { t }; }
131 
132 #undef JUCE_COMPARISON_OPS
133 
134 //==============================================================================
135 /*
136  The following are specialisations of SerialisationTraits for commonly-used types.
137 */
138 
139 #ifndef DOXYGEN
140 
141 template <typename... Ts>
142 struct SerialisationTraits<std::vector<Ts...>>
143 {
144  static constexpr auto marshallingVersion = std::nullopt;
145 
146  template <typename Archive, typename T>
147  static void load (Archive& archive, T& t)
148  {
149  auto size = t.size();
150  archive (serialisationSize (size));
151  t.resize (size);
152 
153  for (auto& element : t)
154  archive (element);
155  }
156 
157  template <typename Archive, typename T>
158  static void save (Archive& archive, const T& t)
159  {
160  archive (serialisationSize (t.size()));
161 
162  for (auto& element : t)
163  archive (element);
164  }
165 };
166 
167 template <typename Element, typename Mutex, int minSize>
168 struct SerialisationTraits<Array<Element, Mutex, minSize>>
169 {
170  static constexpr auto marshallingVersion = std::nullopt;
171 
172  template <typename Archive, typename T>
173  static void load (Archive& archive, T& t)
174  {
175  auto size = t.size();
176  archive (serialisationSize (size));
177  t.resize (size);
178 
179  for (auto& element : t)
180  archive (element);
181  }
182 
183  template <typename Archive, typename T>
184  static void save (Archive& archive, const T& t)
185  {
186  archive (serialisationSize (t.size()));
187 
188  for (auto& element : t)
189  archive (element);
190  }
191 };
192 
193 template <>
194 struct SerialisationTraits<StringArray>
195 {
196  static constexpr auto marshallingVersion = std::nullopt;
197 
198  template <typename Archive, typename T>
199  static void serialise (Archive& archive, T& t)
200  {
201  archive (t.strings);
202  }
203 };
204 
205 template <typename... Ts>
206 struct SerialisationTraits<std::pair<Ts...>>
207 {
208  static constexpr auto marshallingVersion = std::nullopt;
209 
210  template <typename Archive, typename T>
211  static void serialise (Archive& archive, T& t)
212  {
213  archive (named ("first", t.first), named ("second", t.second));
214  }
215 };
216 
217 template <typename T>
218 struct SerialisationTraits<std::optional<T>>
219 {
220  static constexpr auto marshallingVersion = std::nullopt;
221 
222  template <typename Archive>
223  static void load (Archive& archive, std::optional<T>& t)
224  {
225  bool engaged = false;
226 
227  archive (named ("engaged", engaged));
228 
229  if (! engaged)
230  return;
231 
232  t.emplace();
233  archive (named ("value", *t));
234  }
235 
236  template <typename Archive>
237  static void save (Archive& archive, const std::optional<T>& t)
238  {
239  archive (named ("engaged", t.has_value()));
240 
241  if (t.has_value())
242  archive (named ("value", *t));
243  }
244 };
245 
246 template <>
247 struct SerialisationTraits<std::string>
248 {
249  static constexpr auto marshallingVersion = std::nullopt;
250 
251  template <typename Archive>
252  static void load (Archive& archive, std::string& t)
253  {
254  String temporary;
255  archive (temporary);
256  t = temporary.toStdString();
257  }
258 
259  template <typename Archive>
260  static void save (Archive& archive, const std::string& t)
261  {
262  archive (String (t));
263  }
264 };
265 
266 template <typename... Ts>
267 struct SerialisationTraits<std::map<Ts...>>
268 {
269  static constexpr auto marshallingVersion = std::nullopt;
270 
271  template <typename Archive, typename T>
272  static void load (Archive& archive, T& t)
273  {
274  auto size = t.size();
275  archive (serialisationSize (size));
276 
277  for (auto i = (decltype (size)) 0; i < size; ++i)
278  {
279  std::pair<typename T::key_type, typename T::mapped_type> element;
280  archive (element);
281  t.insert (element);
282  }
283  }
284 
285  template <typename Archive, typename T>
286  static void save (Archive& archive, const T& t)
287  {
288  auto size = t.size();
289  archive (serialisationSize (size));
290 
291  for (const auto& element : t)
292  archive (element);
293  }
294 };
295 
296 template <typename... Ts>
297 struct SerialisationTraits<std::set<Ts...>>
298 {
299  static constexpr auto marshallingVersion = std::nullopt;
300 
301  template <typename Archive, typename T>
302  static void load (Archive& archive, T& t)
303  {
304  auto size = t.size();
305  archive (serialisationSize (size));
306 
307  for (auto i = (decltype (size)) 0; i < size; ++i)
308  {
309  typename T::value_type element;
310  archive (element);
311  t.insert (element);
312  }
313  }
314 
315  template <typename Archive, typename T>
316  static void save (Archive& archive, const T& t)
317  {
318  auto size = t.size();
319  archive (serialisationSize (size));
320 
321  for (const auto& element : t)
322  archive (element);
323  }
324 };
325 
326 template <size_t N>
327 struct SerialisationTraits<char[N]>
328 {
329  static constexpr auto marshallingVersion = std::nullopt;
330 
331  template <typename Archive, typename T>
332  static void serialise (Archive& archive, T& t) { archive (String (t, N)); }
333 };
334 
335 template <typename Element, size_t N>
336 struct SerialisationTraits<Element[N]>
337 {
338  static constexpr auto marshallingVersion = std::nullopt;
339 
340  template <typename Archive, typename T>
341  static void load (Archive& archive, T& t)
342  {
343  auto size = N;
344  archive (serialisationSize (size));
345 
346  for (auto& element : t)
347  archive (element);
348  }
349 
350  template <typename Archive, typename T>
351  static void save (Archive& archive, const T& t)
352  {
353  const auto size = N;
354  archive (serialisationSize (size));
355 
356  for (auto& element : t)
357  archive (element);
358  }
359 };
360 
361 template <typename Element, size_t N>
362 struct SerialisationTraits<std::array<Element, N>>
363 {
364  static constexpr auto marshallingVersion = std::nullopt;
365 
366  template <typename Archive, typename T>
367  static void load (Archive& archive, T& t)
368  {
369  auto size = N;
370  archive (serialisationSize (size));
371 
372  for (auto& element : t)
373  archive (element);
374  }
375 
376  template <typename Archive, typename T>
377  static void save (Archive& archive, const T& t)
378  {
379  const auto size = N;
380  archive (serialisationSize (size));
381 
382  for (auto& element : t)
383  archive (element);
384  }
385 };
386 
387 /*
388  This namespace holds utilities for detecting and using serialisation functions.
389 
390  The contents of this namespace are private, and liable to change, so you shouldn't use any of
391  the contents directly.
392 */
393 namespace detail
394 {
395  struct DummyArchive
396  {
397  template <typename... Ts>
398  bool operator() (Ts&&...);
399 
400  std::optional<int> getVersion() const { return {}; }
401  };
402 
403  template <typename T, typename = void>
404  constexpr auto hasInternalVersion = false;
405 
406  template <typename T>
407  constexpr auto hasInternalVersion<T, std::void_t<decltype (T::marshallingVersion)>> = true;
408 
409  template <typename Traits, typename T, typename = void>
410  constexpr auto hasInternalSerialise = false;
411 
412  template <typename Traits, typename T>
413  constexpr auto hasInternalSerialise<Traits, T, std::void_t<decltype (Traits::serialise (std::declval<DummyArchive&>(), std::declval<T&>()))>> = true;
414 
415  template <typename Traits, typename T, typename = void>
416  constexpr auto hasInternalLoad = false;
417 
418  template <typename Traits, typename T>
419  constexpr auto hasInternalLoad<Traits, T, std::void_t<decltype (Traits::load (std::declval<DummyArchive&>(), std::declval<T&>()))>> = true;
420 
421  template <typename Traits, typename T, typename = void>
422  constexpr auto hasInternalSave = false;
423 
424  template <typename Traits, typename T>
425  constexpr auto hasInternalSave<Traits, T, std::void_t<decltype (Traits::save (std::declval<DummyArchive&>(), std::declval<const T&>()))>> = true;
426 
427  template <typename T>
428  struct SerialisedTypeTrait { using type = T; };
429 
430  template <typename T>
431  struct SerialisedTypeTrait<SerialisationTraits<T>> { using type = T; };
432 
433  template <typename T>
434  using SerialisedType = typename SerialisedTypeTrait<T>::type;
435 
436  template <typename T>
437  constexpr auto hasSerialisation = hasInternalVersion<SerialisedType<T>>
438  || hasInternalSerialise<T, SerialisedType<T>>
439  || hasInternalLoad<T, SerialisedType<T>>
440  || hasInternalSave<T, SerialisedType<T>>;
441 
442  /* Different kinds of serialisation function. */
443  enum class SerialisationKind
444  {
445  none, // The type doesn't have any serialisation
446  primitive, // The type has serialisation handling defined directly on the archiver. enums will be converted to equivalent integral values
447  internal, // The type has internally-defined serialisation utilities
448  external, // The type has an external specialisation of SerialisationTraits
449  };
450 
451  /* The SerialisationKind to use for the type T.
452 
453  Primitive serialisation is used for arithmetic types, enums, Strings, and vars.
454  Internal serialisation is used for types that declare an internal marshallingVersion,
455  serialise(), load(), or save().
456  External serialisation is used in all other cases.
457  */
458  template <typename T>
459  constexpr auto serialisationKind = []
460  {
461  if constexpr (std::is_arithmetic_v<T> || std::is_enum_v<T> || std::is_same_v<T, String> || std::is_same_v<T, var>)
462  return SerialisationKind::primitive;
463  else if constexpr (hasSerialisation<T>)
464  return SerialisationKind::internal;
465  else if constexpr (hasSerialisation<SerialisationTraits<T>>)
466  return SerialisationKind::external;
467  else
468  return SerialisationKind::none;
469  }();
470 
471  /* This trait defines the serialisation utilities that are used for primitive types. */
472  template <typename T, SerialisationKind kind = serialisationKind<T>>
473  struct ForwardingSerialisationTraits
474  {
475  static constexpr auto marshallingVersion = std::nullopt;
476 
477  template <typename Archive, typename Primitive>
478  static auto load (Archive& archive, Primitive& t)
479  {
480  if constexpr (std::is_enum_v<Primitive>)
481  return archive (*reinterpret_cast<std::underlying_type_t<Primitive>*> (&t));
482  else
483  return archive (t);
484  }
485 
486  template <typename Archive, typename Primitive>
487  static auto save (Archive& archive, const Primitive& t)
488  {
489  if constexpr (std::is_enum_v<Primitive>)
490  return archive (*reinterpret_cast<const std::underlying_type_t<Primitive>*> (&t));
491  else
492  return archive (t);
493  }
494  };
495 
496  /* This specialisation will be used for types with internal serialisation.
497 
498  All members of ForwardingSerialisationTraits forward to the corresponding member of T.
499  */
500  template <typename T>
501  struct ForwardingSerialisationTraits<T, SerialisationKind::internal>
502  {
503  static constexpr std::optional<int> marshallingVersion { T::marshallingVersion };
504 
505  template <typename Archive, typename Item>
506  static auto serialise (Archive& archive, Item& t) -> decltype (Item::serialise (archive, t)) { return Item::serialise (archive, t); }
507 
508  template <typename Archive, typename Item>
509  static auto load (Archive& archive, Item& t) -> decltype (Item::load (archive, t)) { return Item::load (archive, t); }
510 
511  template <typename Archive, typename Item>
512  static auto save (Archive& archive, const Item& t) -> decltype (Item::save (archive, t)) { return Item::save (archive, t); }
513  };
514 
515  /* This specialisation will be used for types with external serialisation.
516 
517  @see SerialisationTraits
518  */
519  template <typename T>
520  struct ForwardingSerialisationTraits<T, SerialisationKind::external> : SerialisationTraits<T> {};
521 
522  template <typename T, typename = void>
523  constexpr auto hasSerialise = false;
524 
525  template <typename T>
526  constexpr auto hasSerialise<T, std::void_t<decltype (ForwardingSerialisationTraits<T>::serialise (std::declval<DummyArchive&>(), std::declval<T&>()))>> = true;
527 
528  template <typename T, typename = void>
529  constexpr auto hasLoad = false;
530 
531  template <typename T>
532  constexpr auto hasLoad<T, std::void_t<decltype (ForwardingSerialisationTraits<T>::load (std::declval<DummyArchive&>(), std::declval<T&>()))>> = true;
533 
534  template <typename T, typename = void>
535  constexpr auto hasSave = false;
536 
537  template <typename T>
538  constexpr auto hasSave<T, std::void_t<decltype (ForwardingSerialisationTraits<T>::save (std::declval<DummyArchive&>(), std::declval<const T&>()))>> = true;
539 
540  template <typename T>
541  constexpr auto delayStaticAssert = false;
542 
543  /* Calls the correct function (serialise or save) to save the argument t to the archive.
544  */
545  template <typename Archive, typename T>
546  auto doSave (Archive& archive, const T& t)
547  {
548  if constexpr (serialisationKind<T> == SerialisationKind::none)
549  static_assert (delayStaticAssert<T>, "No serialisation function found or marshallingVersion unset");
550  else if constexpr (hasSerialise<T> && ! hasSave<T>)
551  return ForwardingSerialisationTraits<T>::serialise (archive, t);
552  else if constexpr (! hasSerialise<T> && hasSave<T>)
553  return ForwardingSerialisationTraits<T>::save (archive, t);
554  else
555  static_assert (delayStaticAssert<T>, "Multiple serialisation functions found");
556  }
557 
558  /* Calls the correct function (serialise or load) to load the argument t from the archive.
559  */
560  template <typename Archive, typename T>
561  auto doLoad (Archive& archive, T& t)
562  {
563  if constexpr (serialisationKind<T> == SerialisationKind::none)
564  static_assert (delayStaticAssert<T>, "No serialisation function found or marshallingVersion unset");
565  else if constexpr (hasSerialise<T> && ! hasLoad<T>)
566  return ForwardingSerialisationTraits<T>::serialise (archive, t);
567  else if constexpr (! hasSerialise<T> && hasLoad<T>)
568  return ForwardingSerialisationTraits<T>::load (archive, t);
569  else
570  static_assert (delayStaticAssert<T>, "Multiple serialisation functions found");
571  }
572 } // namespace detail
573 
574 #endif
575 
576 } // namespace juce
T & value
A reference to a value to wrap.
JUCE_COMPARISON_OPS std::string_view name
A name that corresponds to the value.