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./..
unittests: unittests.cpp

View File

@@ -7,11 +7,11 @@
namespace cereal
{
// ######################################################################
class BinaryOutputArchive : public OutputArchive<BinaryOutputArchive>
class BinaryOutputArchive : public OutputArchive<BinaryOutputArchive, AllowEmptyClassElision>
{
public:
BinaryOutputArchive(std::ostream & stream) :
OutputArchive<BinaryOutputArchive>(this),
OutputArchive<BinaryOutputArchive, AllowEmptyClassElision>(this),
itsStream(stream)
{ }
@@ -62,11 +62,11 @@ namespace cereal
};
// ######################################################################
class BinaryInputArchive : public InputArchive<BinaryInputArchive>
class BinaryInputArchive : public InputArchive<BinaryInputArchive, AllowEmptyClassElision>
{
public:
BinaryInputArchive(std::istream & stream) :
InputArchive<BinaryInputArchive>(this),
InputArchive<BinaryInputArchive, AllowEmptyClassElision>(this),
itsStream(stream)
{ }
@@ -121,21 +121,23 @@ namespace cereal
typename std::enable_if<std::is_array<T>::value, void>::type
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>
typename std::enable_if<std::is_array<T>::value, void>::type
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>
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");
}
}
#endif // CEREAL_BINARY_ARCHIVE_BINARY_ARCHIVE_HPP_

View File

@@ -37,6 +37,21 @@ namespace cereal
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
@@ -59,6 +74,7 @@ namespace cereal
template <class T, class C, class Comp>
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 );
}
@@ -66,9 +82,13 @@ namespace cereal
template <class T, class C, class Comp>
void load( BinaryInputArchive & ar, std::priority_queue<T, C, Comp> & priority_queue )
{
Comp comparator;
ar & comparator;
C 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

View File

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

View File

@@ -24,7 +24,7 @@ namespace cereal
// ######################################################################
// Non Member Serialize
template<typename T, typename A> char & serialize(A&, T&);
char & serialize(...);
template<typename T, typename A>
bool constexpr has_non_member_serialize()
{ return std::is_void<decltype(serialize(std::declval<A&>(), std::declval<T&>()))>::value; };
@@ -43,7 +43,7 @@ namespace cereal
// ######################################################################
// Non Member Load
template<typename T, typename A> char & load(A&, T&);
char & load(...);
template<typename T, typename A>
bool constexpr has_non_member_load()
{ return std::is_void<decltype(load(std::declval<A&>(), std::declval<T&>()))>::value; };
@@ -62,7 +62,7 @@ namespace cereal
// ######################################################################
// Non Member Save
template<typename T, typename A> char & save(A&, T const &);
char & save(...);
template<typename T, typename A>
bool constexpr has_non_member_save()
{ return std::is_void<decltype(save(std::declval<A&>(), std::declval<T&>()))>::value; };
@@ -101,10 +101,30 @@ namespace cereal
// ######################################################################
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.

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()
{
@@ -184,6 +193,8 @@ int main()
int a2[][2] = {{4, 5}, {6, 7}};
archive & a1;
archive & a2;
EmptyStruct empty;
archive & empty;
}
{