Empty class elision, and priority_queue unit tests

This commit is contained in:
Randolph Voorhies
2013-06-14 18:05:08 -07:00
parent 2ba3fe9165
commit 4aecb595d5
6 changed files with 96 additions and 21 deletions

View File

@@ -1,4 +1,4 @@
all: test.cpp unittests all: test.cpp
g++ -std=c++0x test.cpp -o test -ljsoncpp -I./.. g++ -std=c++0x test.cpp -o test -ljsoncpp -I./..
unittests: unittests.cpp unittests: unittests.cpp

View File

@@ -7,11 +7,11 @@
namespace cereal namespace cereal
{ {
// ###################################################################### // ######################################################################
class BinaryOutputArchive : public OutputArchive<BinaryOutputArchive> class BinaryOutputArchive : public OutputArchive<BinaryOutputArchive, AllowEmptyClassElision>
{ {
public: public:
BinaryOutputArchive(std::ostream & stream) : BinaryOutputArchive(std::ostream & stream) :
OutputArchive<BinaryOutputArchive>(this), OutputArchive<BinaryOutputArchive, AllowEmptyClassElision>(this),
itsStream(stream) itsStream(stream)
{ } { }
@@ -62,11 +62,11 @@ namespace cereal
}; };
// ###################################################################### // ######################################################################
class BinaryInputArchive : public InputArchive<BinaryInputArchive> class BinaryInputArchive : public InputArchive<BinaryInputArchive, AllowEmptyClassElision>
{ {
public: public:
BinaryInputArchive(std::istream & stream) : BinaryInputArchive(std::istream & stream) :
InputArchive<BinaryInputArchive>(this), InputArchive<BinaryInputArchive, AllowEmptyClassElision>(this),
itsStream(stream) itsStream(stream)
{ } { }
@@ -121,21 +121,23 @@ namespace cereal
typename std::enable_if<std::is_array<T>::value, void>::type typename std::enable_if<std::is_array<T>::value, void>::type
save(BinaryOutputArchive & ar, T const & array) save(BinaryOutputArchive & ar, T const & array)
{ {
ar.save_binary(array, traits::sizeofArray<T>() * sizeof(typename std::remove_all_extents<T>::type)); ar.save_binary(array, traits::sizeof_array<T>() * sizeof(typename std::remove_all_extents<T>::type));
} }
template <class T> template <class T>
typename std::enable_if<std::is_array<T>::value, void>::type typename std::enable_if<std::is_array<T>::value, void>::type
load(BinaryInputArchive & ar, T & array) load(BinaryInputArchive & ar, T & array)
{ {
ar.load_binary(array, traits::sizeofArray<T>() * sizeof(typename std::remove_all_extents<T>::type)); ar.load_binary(array, traits::sizeof_array<T>() * sizeof(typename std::remove_all_extents<T>::type));
} }
template <class Archive, class T> template <class Archive, class T>
void serialize( Archive & ar, T * & t ) CEREAL_ARCHIVE_RESTRICT_SERIALIZE(BinaryInputArchive, BinaryOutputArchive)
serialize( Archive & ar, T * & t )
{ {
static_assert(!sizeof(T), "Cereal does not support serializing raw pointers - please use a smart pointer"); static_assert(!sizeof(T), "Cereal does not support serializing raw pointers - please use a smart pointer");
} }
} }
#endif // CEREAL_BINARY_ARCHIVE_BINARY_ARCHIVE_HPP_ #endif // CEREAL_BINARY_ARCHIVE_BINARY_ARCHIVE_HPP_

View File

@@ -37,6 +37,21 @@ namespace cereal
return H::get( priority_queue ); return H::get( priority_queue );
} }
//! Allows access to the protected comparator in priority queue
template <class T, class C, class Comp>
Comp const & comparator( std::priority_queue<T, C, Comp> const & priority_queue )
{
struct H : public std::priority_queue<T, C, Comp>
{
static Comp const & get( std::priority_queue<T, C, Comp> const & pq )
{
return pq.*(&H::comp);
}
};
return H::get( priority_queue );
}
} }
//! Saving for std::queue to binary //! Saving for std::queue to binary
@@ -59,6 +74,7 @@ namespace cereal
template <class T, class C, class Comp> template <class T, class C, class Comp>
void save( BinaryOutputArchive & ar, std::priority_queue<T, C, Comp> const & priority_queue ) void save( BinaryOutputArchive & ar, std::priority_queue<T, C, Comp> const & priority_queue )
{ {
ar & queue_detail::comparator( priority_queue );
ar & queue_detail::container( priority_queue ); ar & queue_detail::container( priority_queue );
} }
@@ -66,9 +82,13 @@ namespace cereal
template <class T, class C, class Comp> template <class T, class C, class Comp>
void load( BinaryInputArchive & ar, std::priority_queue<T, C, Comp> & priority_queue ) void load( BinaryInputArchive & ar, std::priority_queue<T, C, Comp> & priority_queue )
{ {
Comp comparator;
ar & comparator;
C container; C container;
ar & container; ar & container;
priority_queue = std::priority_queue<T, C, Comp>( container.begin(), container.end() );
priority_queue = std::priority_queue<T, C, Comp>( comparator, std::move( container ) );
} }
} // namespace cereal } // namespace cereal

View File

@@ -32,9 +32,11 @@ namespace cereal
//! Creates a name value pair for the variable T, using the same name //! Creates a name value pair for the variable T, using the same name
#define CEREAL_NVP(T) ::cereal::make_nvp(#T, T); #define CEREAL_NVP(T) ::cereal::make_nvp(#T, T);
enum Flags { AllowEmptyClassElision = 1 };
// ###################################################################### // ######################################################################
//! The base output archive class //! The base output archive class
template<class ArchiveType> template<class ArchiveType, uint32_t Flags = 0>
class OutputArchive class OutputArchive
{ {
public: public:
@@ -101,9 +103,19 @@ namespace cereal
return *self; return *self;
} }
template <class T>
typename std::enable_if<(Flags & AllowEmptyClassElision) &&
!traits::is_output_serializable<T, ArchiveType>() && traits::is_empty_class<T>(), ArchiveType &>::type
operator & (T const & t)
{
return *self;
}
//! No matching serialization //! No matching serialization
template <class T> template <class T>
typename std::enable_if<!traits::is_output_serializable<T, ArchiveType>(), ArchiveType &>::type typename std::enable_if<!traits::is_output_serializable<T, ArchiveType>() &&
(!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !traits::is_empty_class<T>())),
ArchiveType &>::type
operator & (T const & t) operator & (T const & t)
{ {
static_assert(traits::is_output_serializable<T, ArchiveType>(), "Trying to serialize an unserializable type with an output archive.\n\n" static_assert(traits::is_output_serializable<T, ArchiveType>(), "Trying to serialize an unserializable type with an output archive.\n\n"
@@ -140,7 +152,7 @@ namespace cereal
// ###################################################################### // ######################################################################
//! The base input archive class //! The base input archive class
template<class ArchiveType> template<class ArchiveType, uint32_t Flags = 0>
class InputArchive class InputArchive
{ {
public: public:
@@ -186,13 +198,23 @@ namespace cereal
return *self; return *self;
} }
template <class T>
typename std::enable_if<(Flags & AllowEmptyClassElision) &&
!traits::is_input_serializable<T, ArchiveType>() && traits::is_empty_class<T>(), ArchiveType &>::type
operator & (T const & t)
{
return *self;
}
//! No matching serialization //! No matching serialization
template <class T> template <class T>
typename std::enable_if<!traits::is_input_serializable<T, ArchiveType>(), ArchiveType &>::type typename std::enable_if<!traits::is_input_serializable<T, ArchiveType>() &&
operator & (T & t) (!(Flags & AllowEmptyClassElision) || ((Flags & AllowEmptyClassElision) && !traits::is_empty_class<T>())),
ArchiveType &>::type
operator & (T const & t)
{ {
static_assert(traits::is_input_serializable<T, ArchiveType>(), "Trying to serialize an unserializable type with an input archive.\n\n" static_assert(traits::is_output_serializable<T, ArchiveType>(), "Trying to serialize an unserializable type with an output archive.\n\n"
"Types must either have a serialize function, or separate load/load functions (but not both).\n" "Types must either have a serialize function, or separate save/load functions (but not both).\n"
"Serialize functions generally have the following signature:\n\n" "Serialize functions generally have the following signature:\n\n"
"template<class Archive>\n" "template<class Archive>\n"
" void serialize(int & ar)\n" " void serialize(int & ar)\n"

View File

@@ -24,7 +24,7 @@ namespace cereal
// ###################################################################### // ######################################################################
// Non Member Serialize // Non Member Serialize
template<typename T, typename A> char & serialize(A&, T&); char & serialize(...);
template<typename T, typename A> template<typename T, typename A>
bool constexpr has_non_member_serialize() bool constexpr has_non_member_serialize()
{ return std::is_void<decltype(serialize(std::declval<A&>(), std::declval<T&>()))>::value; }; { return std::is_void<decltype(serialize(std::declval<A&>(), std::declval<T&>()))>::value; };
@@ -43,7 +43,7 @@ namespace cereal
// ###################################################################### // ######################################################################
// Non Member Load // Non Member Load
template<typename T, typename A> char & load(A&, T&); char & load(...);
template<typename T, typename A> template<typename T, typename A>
bool constexpr has_non_member_load() bool constexpr has_non_member_load()
{ return std::is_void<decltype(load(std::declval<A&>(), std::declval<T&>()))>::value; }; { return std::is_void<decltype(load(std::declval<A&>(), std::declval<T&>()))>::value; };
@@ -62,7 +62,7 @@ namespace cereal
// ###################################################################### // ######################################################################
// Non Member Save // Non Member Save
template<typename T, typename A> char & save(A&, T const &); char & save(...);
template<typename T, typename A> template<typename T, typename A>
bool constexpr has_non_member_save() bool constexpr has_non_member_save()
{ return std::is_void<decltype(save(std::declval<A&>(), std::declval<T&>()))>::value; }; { return std::is_void<decltype(save(std::declval<A&>(), std::declval<T&>()))>::value; };
@@ -101,10 +101,30 @@ namespace cereal
// ###################################################################### // ######################################################################
template <class T> template <class T>
constexpr size_t sizeofArray( size_t rank = std::rank<T>::value ) constexpr size_t sizeof_array( size_t rank = std::rank<T>::value )
{ {
return rank == 0 ? 1 : std::extent<T>::value * sizeofArray<typename std::remove_extent<T>::type>( rank - 1 ); return rank == 0 ? 1 : std::extent<T>::value * sizeof_array<typename std::remove_extent<T>::type>( rank - 1 );
} }
// ######################################################################
namespace detail
{
template <class T, typename Enable = void>
struct is_empty_class_impl
{ static constexpr bool value = false; };
template <class T>
struct is_empty_class_impl<T, typename std::enable_if<std::is_class<T>::value>::type>
{
struct S : T
{ uint8_t t; };
static constexpr bool value = sizeof(S) == sizeof(uint8_t);
};
}
template<class T>
using is_empty_class = std::integral_constant<bool, detail::is_empty_class_impl<T>::value>;
// ###################################################################### // ######################################################################
//! A macro to use to restrict which types of archives your serialize function will work for. //! A macro to use to restrict which types of archives your serialize function will work for.

View File

@@ -109,6 +109,15 @@ struct Everything
} }
}; };
struct EmptyStruct
{
template<class Archive>
void serialize(Archive & ar)
{
std::cout << "Side effects up the wazoo" << std::endl;
};
};
// ###################################################################### // ######################################################################
int main() int main()
{ {
@@ -184,6 +193,8 @@ int main()
int a2[][2] = {{4, 5}, {6, 7}}; int a2[][2] = {{4, 5}, {6, 7}};
archive & a1; archive & a1;
archive & a2; archive & a2;
EmptyStruct empty;
archive & empty;
} }
{ {