1#ifndef SERIALIZE_CORE_HH
2#define SERIALIZE_CORE_HH
11#include <initializer_list>
20template<
typename T>
struct Serializer : std::false_type {
42template<>
struct is_primitive<unsigned long long> : std::true_type {};
50template<
typename Archive,
typename T>
55 t.serialize(ar, version);
58template<
typename Archive,
typename T1,
typename T2>
59void serialize(Archive& ar, std::pair<T1, T2>& p,
unsigned )
61 ar.serialize(
"first", p.first,
66 static constexpr unsigned value = 0;
113[[noreturn]]
void enumError(std::string_view str);
118 for (
auto& [str,
t] : list) {
119 if (
t == t_)
return str;
122 return "internal-error-unknown-enum-value";
128 for (
auto& [str,
t] : list) {
129 if (str == str_)
return t;
135#define SERIALIZE_ENUM(TYPE,INFO) \
136template<> struct serialize_as_enum< TYPE > : std::true_type { \
137 serialize_as_enum() : info(INFO) {} \
138 std::initializer_list<enum_string< TYPE >> info; \
141template<
typename Archive,
typename T,
typename SaveAction>
144 if constexpr (Archive::TRANSLATE_ENUM_TO_STRING) {
151template<
typename Archive,
typename T,
typename LoadAction>
154 if constexpr (Archive::TRANSLATE_ENUM_TO_STRING) {
167template<
size_t I,
typename Variant>
170 if constexpr (I == std::variant_size_v<Variant>) {
172 }
else if (index == I) {
173 return std::variant_alternative_t<I, Variant>{};
179template<
typename Variant>
191 template<
typename Archive>
192 void operator()(Archive& ar,
const V& v,
bool saveId)
const {
194 [&](
const auto&
t) { ar.attribute(
"type", t); });
195 std::visit([&]<
typename T>(T& e) {
196 using TNC = std::remove_cvref_t<T>;
197 auto& e2 =
const_cast<TNC&
>(e);
199 saver(ar, e2, saveId);
204 template<
typename Archive,
typename TUPLE>
205 void operator()(Archive& ar, V& v, TUPLE args,
int id)
const {
208 [&](
auto& l) { ar.attribute(
"type", l); });
209 v = defaultConstructVariant<V>(idx);
210 std::visit([&]<
typename T>(T& e) {
212 loader(ar, e, args,
id);
252 "can't serialize ptr to primitive type");
259 template<
typename Archive>
267 static inline T*
getPointer(
const std::unique_ptr<T>&
t) {
return t.get(); }
268 template<
typename Archive>
269 static inline void setPointer(std::unique_ptr<T>&
t, T* p, Archive& ) {
277 template<
typename Archive>
278 static void setPointer(std::shared_ptr<T>&
t, T* p, Archive& ar) {
279 ar.resetSharedPtr(
t, p);
329 static constexpr int size = N;
333 static auto begin(
const std::array<T, N>& a) {
return a.begin(); }
334 static auto end (
const std::array<T, N>& a) {
return a.end(); }
336 static constexpr bool loadInPlace =
true;
337 static void prepare(std::array<T, N>& ,
int ) { }
338 static T*
output(std::array<T, N>& a) {
return a.data(); }
384 template<
typename Archive>
void operator()(Archive& ar,
const T&
t,
393 template<
typename Archive>
void operator()(Archive& ar,
const T&
t,
397 saveEnum<Archive>(sae.info,
t,
398 [&](
const auto& s) { ar.save(s); });
404 Archive& ar,
const T&
t,
bool saveId,
405 const char* type =
nullptr,
bool saveConstrArgs =
false)
const
420 unsigned id = ar.generateId(&
t);
421 ar.attribute(
"id",
id);
425 ar.attribute(
"type", type);
429 if ((version != 0) && ar.NEED_VERSION) {
430 if (!ar.CAN_HAVE_OPTIONAL_ATTRIBUTES ||
432 ar.attribute(
"version", version);
436 if (saveConstrArgs) {
439 constrArgs.
save(ar,
t);
442 using TNC = std::remove_const_t<T>;
443 auto& t2 =
const_cast<TNC&
>(
t);
450 template<
typename Archive>
void operator()(Archive& ar,
const TP& tp2,
454 "must be serialized as pointer");
459 ar.attribute(
"id_ref",
id);
462 if (
unsigned id = ar.getId(tp)) {
463 ar.attribute(
"id_ref",
id);
465 if constexpr (std::is_polymorphic_v<T>) {
471 saver(ar, *tp,
true,
nullptr,
true);
478 template<
typename Archive>
void operator()(Archive& ar,
const TP& tp2)
const
481 "must be serialized as pointer");
490 ar.attribute(
"id_ref",
id);
495 template<
typename Archive>
void operator()(Archive& ar,
const TC& tc,
499 static_assert(sac::value,
"must be serialized as collection");
500 auto begin = sac::begin(tc);
501 auto end = sac::end (tc);
502 if ((sac::size < 0) && (!ar.CAN_COUNT_CHILDREN)) {
507 int n = int(std::distance(
begin,
end));
508 ar.serialize(
"size", n);
512 ar.serializeWithID(
"item", *
begin);
514 ar.serialize(
"item", *
begin);
523 : std::conditional_t<is_primitive<T>::value, PrimitiveSaver<T>,
524 std::conditional_t<Serializer<T>::value, typename Serializer<T>::Saver,
525 std::conditional_t<serialize_as_enum<T>::value, EnumSaver<T>,
526 std::conditional_t<serialize_as_pointer<T>::value, PointerSaver<T>,
527 std::conditional_t<serialize_as_collection<T>::value, CollectionSaver<T>,
528 ClassSaver<T>>>>>> {};
550 template<
typename Archive,
typename TUPLE>
553 static_assert(std::tuple_size_v<TUPLE> == 0,
554 "can't have constructor arguments");
560 template<
typename Archive,
typename TUPLE>
563 static_assert(std::tuple_size_v<TUPLE> == 0,
564 "can't have constructor arguments");
566 loadEnum<Archive>(sae.info,
t, [&](
auto& l) { ar.load(l); });
571 unsigned latestVersion);
573 unsigned latestVersion);
574template<
typename T,
typename Archive>
unsigned loadVersion(Archive& ar)
577 if ((latestVersion != 0) && ar.NEED_VERSION) {
580 return latestVersion;
585 template<
typename Archive,
typename TUPLE>
587 int version = -1)
const
589 static_assert(std::tuple_size_v<TUPLE> == 0,
590 "can't have constructor arguments");
597 ar.attribute(
"id",
id);
599 ar.addPointer(
id, &
t);
605 version = loadVersion<T>(ar);
608 using TNC = std::remove_const_t<T>;
609 auto& t2 =
const_cast<TNC&
>(
t);
615 template<
typename Archive,
typename GlobalTuple>
616 T*
operator()(Archive& ar,
unsigned id, GlobalTuple globalArgs)
618 int version = loadVersion<T>(ar);
621 using TNC = std::remove_const_t<T>;
623 ConstrArgs constrArgs;
624 auto localArgs = constrArgs.
load(ar, version);
627 auto args = std::tuple_cat(globalArgs, localArgs);
631 auto tp = creator(args);
633 loader(ar, *tp, std::tuple<>(),
id, version);
639 template<
typename Archive,
typename TUPLE>
643 static_assert(std::is_same_v<TUPLE, ArgsType>,
644 "constructor arguments types must match");
645 return static_cast<T*
>(
653 : std::conditional_t<std::is_polymorphic_v<T>,
654 PolymorphicPointerLoader<T>,
655 NonPolymorphicPointerLoader<T>> {};
659 template<
typename Archive,
typename GlobalTuple>
660 void operator()(Archive& ar, TP& tp2, GlobalTuple globalArgs,
int )
const
663 "must be serialized as a pointer");
667 if constexpr (Archive::CAN_HAVE_OPTIONAL_ATTRIBUTES) {
668 if (
auto i = ar.template findAttributeAs<unsigned>(
"id_ref")) {
673 ar.attribute(
"id", i);
678 T* tp = [&]() -> T* {
682 if (
void* p = ar.getPointer(
id)) {
683 return static_cast<T*
>(p);
686 return loader(ar,
id, globalArgs);
696 template<
typename Archive>
700 "must be serialized as a pointer");
702 ar.attribute(
"id_ref",
id);
709 void* p = ar.getPointer(
id);
713 tp =
static_cast<T*
>(p);
723 template<
typename Archive,
typename TUPLE,
typename OUT_ITER>
724 void operator()(Archive& ar, TUPLE args, OUT_ITER it,
int id)
const
726 ar.doSerialize(
"item", *it, args,
id);
735 template<
typename Archive,
typename TUPLE,
typename OUT_ITER>
736 void operator()(Archive& ar, TUPLE args, OUT_ITER it,
int id)
const
738 typename sac::value_type elem;
739 ar.doSerialize(
"item", elem, args,
id);
740 *it = std::move(elem);
745 template<
typename Archive,
typename TUPLE>
746 void operator()(Archive& ar, TC& tc, TUPLE args,
int id = 0)
const
748 assert(
id ==
one_of(0, -1));
750 static_assert(sac::value,
"must be serialized as a collection");
754 if constexpr (Archive::CAN_COUNT_CHILDREN) {
755 n = ar.countChildren();
757 ar.serialize(
"size", n);
761 auto it = sac::output(tc);
764 loadOneElement(ar, args, it,
id);
770 : std::conditional_t<is_primitive<T>::value, PrimitiveLoader<T>,
771 std::conditional_t<Serializer<T>::value, typename Serializer<T>::Loader,
772 std::conditional_t<serialize_as_enum<T>::value, EnumLoader<T>,
773 std::conditional_t<serialize_as_pointer<T>::value, PointerLoader<T>,
774 std::conditional_t<serialize_as_collection<T>::value, CollectionLoader<T>,
775 ClassLoader<T>>>>>> {};
static void * load(Archive &ar, unsigned id, const void *args)
static void save(Archive &ar, T *t)
This file implemented 3 utility functions:
void enumError(std::string_view str)
void saveEnum(std::initializer_list< enum_string< T > > list, T t, SaveAction save)
Variant defaultConstructVariant(size_t index)
unsigned loadVersion(Archive &ar)
T fromString(std::initializer_list< enum_string< T > > list, std::string_view str_)
void serialize(Archive &ar, T &t, unsigned version)
std::string toString(const BooleanInput &input)
void pointerError(unsigned id)
unsigned loadVersionHelper(MemInputArchive &, const char *, unsigned)
void loadEnum(std::initializer_list< enum_string< T > > list, T &t, LoadAction load)
void operator()(Archive &ar, T &t, TUPLE, int id=0, int version=-1) const
void operator()(Archive &ar, const T &t, bool saveId, const char *type=nullptr, bool saveConstrArgs=false) const
void operator()(Archive &ar, TUPLE args, OUT_ITER it, int id) const
void operator()(Archive &ar, TUPLE args, OUT_ITER it, int id) const
void operator()(Archive &ar, TC &tc, TUPLE args, int id=0) const
void operator()(Archive &ar, const TC &tc, bool saveId) const
Utility to do T* t = new T(...)
Variant operator()(size_t index) const
void operator()(Archive &ar, T &t, TUPLE, int) const
void operator()(Archive &ar, const T &t, bool) const
void operator()(Archive &ar, TP &tp2) const
void operator()(Archive &ar, const TP &tp2) const
T * operator()(Archive &ar, unsigned id, GlobalTuple globalArgs)
void operator()(Archive &ar, TP &tp2, GlobalTuple globalArgs, int) const
void operator()(Archive &ar, const TP &tp2, bool) const
Store association between polymorphic class (base- or subclass) and the list of constructor arguments...
T * operator()(Archive &ar, unsigned id, TUPLE args)
void operator()(Archive &ar, T &t, TUPLE, int) const
void operator()(Archive &ar, const T &t, bool) const
Store serialization-version number of a class.
static constexpr unsigned value
Serialize (local) constructor arguments.
type load(Archive &, unsigned) const
void save(Archive &, const T &) const
void operator()(Archive &ar, V &v, TUPLE args, int id) const
void operator()(Archive &ar, const V &v, bool saveId) const
static constexpr size_t index
static auto end(const std::array< T, N > &a)
static void prepare(std::array< T, N > &, int)
static auto begin(const std::array< T, N > &a)
static T * output(std::array< T, N > &a)
typename std::array< T, N >::const_iterator const_iterator
static void setPointer(T *&t, T *p, Archive &)
static T * getPointer(T *t)
static T * getPointer(const std::shared_ptr< T > &t)
static void setPointer(std::shared_ptr< T > &t, T *p, Archive &ar)
static T * getPointer(const std::unique_ptr< T > &t)
static void setPointer(std::unique_ptr< T > &t, T *p, Archive &)
constexpr void repeat(T n, Op op)
Repeat the given operation 'op' 'n' times.
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)