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:
Shane Grant
2014-03-19 22:41:34 -07:00
parent 0423779b94
commit 8abfa583b0
5 changed files with 204 additions and 59 deletions
+16 -8
View File
@@ -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();
+12 -6
View File
@@ -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();
}
+60 -8
View File
@@ -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;
+71 -20
View File
@@ -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
// ######################################################################
+45 -17
View File
@@ -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