OpenShot Audio Library | OpenShotAudio 0.4.0
Loading...
Searching...
No Matches
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
23namespace juce
24{
25
65template <typename T> struct SerialisationTraits
66{
67 /* Intentionally left blank. */
68};
69
70#define JUCE_COMPARISON_OPS X(==) X(!=) X(<) X(<=) X(>) X(>=)
71
86template <typename T>
87struct 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;
95};
96
98template <typename T> constexpr auto named (std::string_view c, T& t) { return Named<T> { c, t }; }
99
101template <typename T> constexpr auto named (std::string_view c, const T& t) { return Named<const T> { c, t }; }
102
116template <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
127template <typename T> constexpr auto serialisationSize (T& t) -> std::enable_if_t<std::is_integral_v<T>, SerialisationSize<T>> { return { t }; }
128
130template <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
141template <typename... Ts>
142struct 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
167template <typename Element, typename Mutex, int minSize>
168struct 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
193template <>
194struct 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
205template <typename... Ts>
206struct 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
217template <typename T>
218struct 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
246template <>
247struct 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
266template <typename... Ts>
267struct 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
296template <typename... Ts>
297struct 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
326template <size_t N>
327struct 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
335template <typename Element, size_t N>
336struct 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
361template <typename Element, size_t N>
362struct 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*/
393namespace 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.