Nearly done with #23
Still some kinks to work out in regards to trait checks on a non-member load_minimal that accepts everything as template parameters and does enable_if style checks
This commit is contained in:
@@ -692,11 +692,14 @@ namespace cereal
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for all other types for JSON archives
|
||||
//! Prologue for all other types for JSON archives (except minimal types)
|
||||
/*! Starts a new node, named either automatically or by some NVP,
|
||||
that may be given data by the type about to be archived */
|
||||
that may be given data by the type about to be archived
|
||||
|
||||
Minimal types do not start or finish nodes */
|
||||
template <class T> inline
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value, void>::type
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value &&
|
||||
!traits::has_minimal_output_serialization<T, JSONOutputArchive>::value, void>::type
|
||||
prologue( JSONOutputArchive & ar, T const & )
|
||||
{
|
||||
ar.startNode();
|
||||
@@ -704,17 +707,21 @@ namespace cereal
|
||||
|
||||
//! Prologue for all other types for JSON archives
|
||||
template <class T> inline
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value, void>::type
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value &&
|
||||
!traits::has_minimal_input_serialization<T, JSONOutputArchive>::value, void>::type
|
||||
prologue( JSONInputArchive & ar, T const & )
|
||||
{
|
||||
ar.startNode();
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for all other types other for JSON archives
|
||||
/*! Finishes the node created in the prologue */
|
||||
//! Epilogue for all other types other for JSON archives (except minimal types
|
||||
/*! Finishes the node created in the prologue
|
||||
|
||||
Minimal types do not start or finish nodes */
|
||||
template <class T> inline
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value, void>::type
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value &&
|
||||
!traits::has_minimal_output_serialization<T, JSONOutputArchive>::value, void>::type
|
||||
epilogue( JSONOutputArchive & ar, T const & )
|
||||
{
|
||||
ar.finishNode();
|
||||
@@ -722,7 +729,8 @@ namespace cereal
|
||||
|
||||
//! Epilogue for all other types other for JSON archives
|
||||
template <class T> inline
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value, void>::type
|
||||
typename std::enable_if<!std::is_arithmetic<T>::value &&
|
||||
!traits::has_minimal_input_serialization<T, JSONOutputArchive>::value, void>::type
|
||||
epilogue( JSONInputArchive & ar, T const & )
|
||||
{
|
||||
ar.finishNode();
|
||||
|
||||
@@ -716,11 +716,14 @@ namespace cereal
|
||||
{ }
|
||||
|
||||
// ######################################################################
|
||||
//! Prologue for all other types for XML output archives
|
||||
//! Prologue for all other types for XML output archives (except minimal types)
|
||||
/*! Starts a new node, named either automatically or by some NVP,
|
||||
that may be given data by the type about to be archived */
|
||||
that may be given data by the type about to be archived
|
||||
|
||||
Minimal types do not start or end nodes */
|
||||
template <class T> inline
|
||||
void prologue( XMLOutputArchive & ar, T const & )
|
||||
typename std::enable_if<!traits::has_minimal_output_serialization<T, XMLOutputArchive>::value, void>::type
|
||||
prologue( XMLOutputArchive & ar, T const & )
|
||||
{
|
||||
ar.startNode();
|
||||
ar.insertType<T>();
|
||||
@@ -734,10 +737,13 @@ namespace cereal
|
||||
}
|
||||
|
||||
// ######################################################################
|
||||
//! Epilogue for all other types other for XML output archives
|
||||
/*! Finishes the node created in the prologue */
|
||||
//! Epilogue for all other types other for XML output archives (except minimal types)
|
||||
/*! Finishes the node created in the prologue
|
||||
|
||||
Minimal types do not start or end nodes */
|
||||
template <class T> inline
|
||||
void epilogue( XMLOutputArchive & ar, T const & )
|
||||
typename std::enable_if<!traits::has_minimal_output_serialization<T, XMLOutputArchive>::value, void>::type
|
||||
epilogue( XMLOutputArchive & ar, T const & )
|
||||
{
|
||||
ar.finishNode();
|
||||
}
|
||||
|
||||
@@ -408,8 +408,7 @@ namespace cereal
|
||||
ArchiveType &>::type
|
||||
processImpl(T const & t)
|
||||
{
|
||||
std::cerr << "I WOULD SAVE MINIMAL... IF I COULD!" << std::endl;
|
||||
//access::member_save(*self, t);
|
||||
self->process( access::member_save_minimal(*self, t) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
@@ -420,8 +419,7 @@ namespace cereal
|
||||
ArchiveType &>::type
|
||||
processImpl(T const & t)
|
||||
{
|
||||
std::cerr << "I WOULD SAVE MINIMAL (non member)... IF I COULD!" << std::endl;
|
||||
//save(*self, t);
|
||||
self->process( save_minimal(*self, t) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
@@ -531,9 +529,8 @@ namespace cereal
|
||||
ArchiveType &>::type
|
||||
processImpl(T const & t)
|
||||
{
|
||||
std::cerr << "I WOULD SAVE MINIMAL (versioned)... IF I COULD!" << std::endl;
|
||||
registerClassVersion<T>( detail::Version<T>::version );
|
||||
//access::member_save(*self, t, detail::Version<T>::version);
|
||||
self->process( access::member_save_minimal(*self, t, detail::Version<T>::version) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
@@ -545,9 +542,8 @@ namespace cereal
|
||||
ArchiveType &>::type
|
||||
processImpl(T const & t)
|
||||
{
|
||||
std::cerr << "I WOULD SAVE MINIMAL (versioned)... IF I COULD!" << std::endl;
|
||||
registerClassVersion<T>( detail::Version<T>::version );
|
||||
//save(*self, t, detail::Version<T>::version);
|
||||
self->process( save_minimal(*self, t, detail::Version<T>::version) );
|
||||
return *self;
|
||||
}
|
||||
|
||||
@@ -785,6 +781,32 @@ namespace cereal
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (load_minimal)
|
||||
template <class T> inline
|
||||
typename std::enable_if<traits::has_member_load_minimal<T, ArchiveType>::value &&
|
||||
(traits::is_specialized_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
|
||||
ArchiveType &>::type
|
||||
processImpl(T & t)
|
||||
{
|
||||
typename traits::has_member_save_minimal<T, ArchiveType>::type value;
|
||||
self->process( value );
|
||||
access::member_load_minimal(*self, t, value);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (load_minimal)
|
||||
template <class T> inline
|
||||
typename std::enable_if<traits::has_non_member_load_minimal<T, ArchiveType>::value &&
|
||||
(traits::is_specialized_non_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
|
||||
ArchiveType &>::type
|
||||
processImpl(T & t)
|
||||
{
|
||||
typename traits::has_non_member_save_minimal<T, ArchiveType>::type value;
|
||||
self->process( value );
|
||||
load_minimal(*self, t, value);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Empty class specialization
|
||||
template <class T> inline
|
||||
typename std::enable_if<(Flags & AllowEmptyClassElision) &&
|
||||
@@ -892,6 +914,36 @@ namespace cereal
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Member split (load_minimal)
|
||||
/*! Versioning implementation */
|
||||
template <class T> inline
|
||||
typename std::enable_if<traits::has_member_versioned_load_minimal<T, ArchiveType>::value &&
|
||||
(traits::is_specialized_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
|
||||
ArchiveType &>::type
|
||||
processImpl(T & t)
|
||||
{
|
||||
const auto version = loadClassVersion<T>();
|
||||
typename traits::has_member_versioned_save_minimal<T, ArchiveType>::type value;
|
||||
self->process(value);
|
||||
access::member_load_minimal(*self, t, value, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
//! Non member split (load_minimal)
|
||||
/*! Versioning implementation */
|
||||
template <class T> inline
|
||||
typename std::enable_if<traits::has_non_member_versioned_load_minimal<T, ArchiveType>::value &&
|
||||
(traits::is_specialized_non_member_load_minimal<T, ArchiveType>::value || traits::is_input_serializable<T, ArchiveType>::value),
|
||||
ArchiveType &>::type
|
||||
processImpl(T & t)
|
||||
{
|
||||
const auto version = loadClassVersion<T>();
|
||||
typename traits::has_non_member_versioned_save_minimal<T, ArchiveType>::type value;
|
||||
self->process(value);
|
||||
load_minimal(*self, t, value, version);
|
||||
return *self;
|
||||
}
|
||||
|
||||
private:
|
||||
ArchiveType * const self;
|
||||
|
||||
|
||||
@@ -596,22 +596,30 @@ namespace cereal
|
||||
// Member Load Minimal
|
||||
namespace detail
|
||||
{
|
||||
//! Used to help strip away conversion wrappers
|
||||
/*! If someone writes a non-member load/save minimal function that accepts its
|
||||
parameter as some generic template type and needs to perform trait checks
|
||||
on that type, our NoConvert wrappers will interfere with this. Using
|
||||
the struct strip_minmal, users can strip away our wrappers to get to
|
||||
the underlying type, allowing traits to work properly */
|
||||
struct NoConvertBase {};
|
||||
|
||||
//! A struct that prevents implicit conversion
|
||||
/*! Any type instantiated with this struct will be unable to implicitly convert
|
||||
to another type. Is designed to only allow conversion to Source const &.
|
||||
|
||||
@tparam Source the type of the original source */
|
||||
template <class Source>
|
||||
struct NoConvertConstRef
|
||||
struct NoConvertConstRef : NoConvertBase
|
||||
{
|
||||
//private:
|
||||
template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
|
||||
operator Dest () = delete;
|
||||
using type = Source; //!< Used to get underlying type easily
|
||||
|
||||
//public:
|
||||
// only allow conversion if the types are the same and we are converting into a const reference
|
||||
template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
|
||||
operator Dest const & () const;
|
||||
template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
|
||||
operator Dest () = delete;
|
||||
|
||||
//! only allow conversion if the types are the same and we are converting into a const reference
|
||||
template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
|
||||
operator Dest const & () const;
|
||||
};
|
||||
|
||||
//! A struct that prevents implicit conversion
|
||||
@@ -620,21 +628,21 @@ namespace cereal
|
||||
|
||||
@tparam Source the type of the original source */
|
||||
template <class Source>
|
||||
struct NoConvertRef
|
||||
struct NoConvertRef : NoConvertBase
|
||||
{
|
||||
//protected:
|
||||
template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
|
||||
operator Dest () = delete;
|
||||
using type = Source; //!< Used to get underlying type easily
|
||||
|
||||
#ifdef __clang__
|
||||
template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
|
||||
operator Dest const & () = delete;
|
||||
#endif // __clang__
|
||||
template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
|
||||
operator Dest () = delete;
|
||||
|
||||
//public:
|
||||
// only allow conversion if the types are the same and we are converting into a const reference
|
||||
template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
|
||||
operator Dest & ();
|
||||
#ifdef __clang__
|
||||
template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
|
||||
operator Dest const & () = delete;
|
||||
#endif // __clang__
|
||||
|
||||
//! only allow conversion if the types are the same and we are converting into a const reference
|
||||
template <class Dest, class = typename std::enable_if<std::is_same<Source, Dest>::value>::type>
|
||||
operator Dest & ();
|
||||
};
|
||||
|
||||
//! A type that can implicitly convert to anything else
|
||||
@@ -1083,6 +1091,30 @@ namespace cereal
|
||||
"cereal detected non-member save specialization but no non-member save function" );
|
||||
};
|
||||
|
||||
// ######################################################################
|
||||
// detects if a type has any active minimal output serialization
|
||||
template <class T, class OutputArchive>
|
||||
struct has_minimal_output_serialization : std::integral_constant<bool,
|
||||
is_specialized_member_save_minimal<T, OutputArchive>::value ||
|
||||
((has_member_save_minimal<T, OutputArchive>::value ||
|
||||
has_non_member_save_minimal<T, OutputArchive>::value ||
|
||||
has_member_versioned_save_minimal<T, OutputArchive>::value ||
|
||||
has_non_member_versioned_save_minimal<T, OutputArchive>::value) &&
|
||||
(!is_specialized_member_serialize<T, OutputArchive>::value ||
|
||||
!is_specialized_member_save<T, OutputArchive>::value))> {};
|
||||
|
||||
// ######################################################################
|
||||
// detects if a type has any active minimal input serialization
|
||||
template <class T, class InputArchive>
|
||||
struct has_minimal_input_serialization : std::integral_constant<bool,
|
||||
is_specialized_member_load_minimal<T, InputArchive>::value ||
|
||||
((has_member_load_minimal<T, InputArchive>::value ||
|
||||
has_non_member_load_minimal<T, InputArchive>::value ||
|
||||
has_member_versioned_load_minimal<T, InputArchive>::value ||
|
||||
has_non_member_versioned_load_minimal<T, InputArchive>::value) &&
|
||||
(!is_specialized_member_serialize<T, InputArchive>::value ||
|
||||
!is_specialized_member_load<T, InputArchive>::value))> {};
|
||||
|
||||
// ######################################################################
|
||||
namespace detail
|
||||
{
|
||||
@@ -1160,6 +1192,25 @@ namespace cereal
|
||||
using type = typename std::decay<typename PtrType::element_type>::type;
|
||||
};
|
||||
|
||||
//! Extracts the true type from something possibly wrapped in a cereal NoConvert
|
||||
/*! Internally cereal uses some wrapper classes to test the validity of non-member
|
||||
minimal load and save functions. This can interfere with user type traits on
|
||||
templated load and save minimal functions. To get to the correct underlying type,
|
||||
users should use strip_minimal when performing any enable_if type type trait checks.
|
||||
|
||||
See the enum serialization in types/common.hpp for an example of using this */
|
||||
template <class T, bool IsCerealMinimalTrait = std::is_base_of<detail::NoConvertBase, T>::value>
|
||||
struct strip_minimal
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
//! Specialization for types wrapped in a NoConvert
|
||||
template <class T>
|
||||
struct strip_minimal<T, true>
|
||||
{
|
||||
using type = typename T::type;
|
||||
};
|
||||
} // namespace traits
|
||||
|
||||
// ######################################################################
|
||||
|
||||
@@ -34,23 +34,6 @@
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
//! Serialization for enum types
|
||||
template<class Archive, class T> inline
|
||||
typename std::enable_if<std::is_enum<T>::value, void>::type
|
||||
serialize(Archive & ar, T & t)
|
||||
{
|
||||
ar( reinterpret_cast<typename std::underlying_type<T>::type &>(t) );
|
||||
}
|
||||
|
||||
//! Serialization for raw pointers
|
||||
/*! This exists only to throw a static_assert to let users know we don't support raw pointers. */
|
||||
template <class Archive, class T> inline
|
||||
void serialize( Archive &, T * & )
|
||||
{
|
||||
static_assert(cereal::traits::detail::delay_static_assert<T>::value,
|
||||
"Cereal does not support serializing raw pointers - please use a smart pointer");
|
||||
}
|
||||
|
||||
namespace common_detail
|
||||
{
|
||||
//! Serialization for arrays if BinaryData is supported and we are arithmetic
|
||||
@@ -69,6 +52,51 @@ namespace cereal
|
||||
for( auto & i : array )
|
||||
ar( i );
|
||||
}
|
||||
|
||||
/*! @internal */
|
||||
template <class T, bool IsEnum>
|
||||
struct enum_underlying_type_impl : std::false_type {};
|
||||
|
||||
/*! @internal */
|
||||
template <class T>
|
||||
struct enum_underlying_type_impl<T, true> { using type = typename std::underlying_type<T>::type; };
|
||||
|
||||
//! Helper for getting the type of an enum
|
||||
/* This will work even if T is not an enum - in that case the type will be something
|
||||
irrelevent
|
||||
@internal */
|
||||
template <class T>
|
||||
struct enum_underlying_type
|
||||
{
|
||||
using type = typename enum_underlying_type_impl<T, std::is_enum<T>::value>::type;
|
||||
};
|
||||
}
|
||||
|
||||
//! Saving for enum types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_enum<typename traits::strip_minimal<T>::type>::value,
|
||||
typename common_detail::enum_underlying_type<typename traits::strip_minimal<T>::type>::type>::type
|
||||
save_minimal( Archive const &, T const & t )
|
||||
{
|
||||
return static_cast<typename std::underlying_type<T>::type>(t);
|
||||
}
|
||||
|
||||
//! Loading for enum types
|
||||
template <class Archive, class T> inline
|
||||
typename std::enable_if<std::is_enum<typename traits::strip_minimal<T>::type>::value, void>::type
|
||||
load_minimal( Archive const &, T & t,
|
||||
typename common_detail::enum_underlying_type<typename traits::strip_minimal<T>::type>::type const & value )
|
||||
{
|
||||
t = static_cast<T>(value);
|
||||
}
|
||||
|
||||
//! Serialization for raw pointers
|
||||
/*! This exists only to throw a static_assert to let users know we don't support raw pointers. */
|
||||
template <class Archive, class T> inline
|
||||
void serialize( Archive &, T * & )
|
||||
{
|
||||
static_assert(cereal::traits::detail::delay_static_assert<T>::value,
|
||||
"Cereal does not support serializing raw pointers - please use a smart pointer");
|
||||
}
|
||||
|
||||
//! Serialization for C style arrays
|
||||
|
||||
Reference in New Issue
Block a user