Non default constructors now supported by pointers

This commit is contained in:
Shane Grant
2013-06-18 16:16:24 -07:00
parent 5c3c162fd1
commit 1b8dbfb96a
4 changed files with 200 additions and 37 deletions

View File

@@ -1,5 +1,5 @@
CPPFLAGS=-std=c++11 -I./include CPPFLAGS=-std=c++11 -I./include
CC=clang++ CC=g++
all: unittests sandbox performance all: unittests sandbox performance

View File

@@ -45,9 +45,10 @@ namespace cereal
} }
} }
//! Loading std::shared_ptr to binary //! Loading std::shared_ptr to binary, case when user load and allocate
template <class T> inline template <class T> inline
void load( BinaryInputArchive & ar, std::shared_ptr<T> & ptr ) typename std::enable_if<traits::has_load_and_allocate<T, BinaryInputArchive>(), void>::type
load( BinaryInputArchive & ar, std::shared_ptr<T> & ptr )
{ {
uint32_t id; uint32_t id;
@@ -55,7 +56,27 @@ namespace cereal
if( id & msb_32bit ) if( id & msb_32bit )
{ {
ptr.reset( new T ); ptr.reset( detail::Load<T, BinaryInputArchive>::load_andor_allocate( ar ) );
ar.registerSharedPointer(id, ptr);
}
else
{
ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
}
}
//! Loading std::shared_ptr to binary, case when no user load and allocate
template <class T> inline
typename std::enable_if<!traits::has_load_and_allocate<T, BinaryInputArchive>(), void>::type
load( BinaryInputArchive & ar, std::shared_ptr<T> & ptr )
{
uint32_t id;
ar & id;
if( id & msb_32bit )
{
ptr.reset( detail::Load<T, BinaryInputArchive>::load_andor_allocate( ar ) );
ar & *ptr; ar & *ptr;
ar.registerSharedPointer(id, ptr); ar.registerSharedPointer(id, ptr);
} }
@@ -89,11 +110,20 @@ namespace cereal
ar & *ptr; ar & *ptr;
} }
//! Loading std::unique_ptr from binary //! Loading std::unique_ptr from binary, case when user provides load_and_allocate
template <class T, class D> inline template <class T, class D> inline
void load( BinaryInputArchive & ar, std::unique_ptr<T, D> & ptr ) typename std::enable_if<traits::has_load_and_allocate<T, BinaryInputArchive>(), void>::type
load( BinaryInputArchive & ar, std::unique_ptr<T, D> & ptr )
{ {
ptr.reset(new T); ptr.reset( detail::Load<T, BinaryInputArchive>::load_andor_allocate( ar ) );
}
//! Loading std::unique_ptr from binary, case when no load_and_allocate
template <class T, class D> inline
typename std::enable_if<!traits::has_load_and_allocate<T, BinaryInputArchive>(), void>::type
load( BinaryInputArchive & ar, std::unique_ptr<T, D> & ptr )
{
ptr.reset( detail::Load<T, BinaryInputArchive>::load_andor_allocate( ar ) );
ar & *ptr; ar & *ptr;
} }

View File

@@ -29,28 +29,65 @@
#include <type_traits> #include <type_traits>
#include <memory> #include <memory>
#include <iostream>
namespace cereal namespace cereal
{ {
template <class T>
struct LoadAndAllocate
{
static void load_and_allocate(...)
{ }
};
struct access struct access
{ {
template<class Archive, class T> template<class Archive, class T> inline
static auto member_serialize(Archive & ar, T & t) -> decltype(t.serialize(ar)) static auto member_serialize(Archive & ar, T & t) -> decltype(t.serialize(ar))
{ t.serialize(ar); } { t.serialize(ar); }
template<class Archive, class T> template<class Archive, class T> inline
static auto member_save(Archive & ar, T const & t) -> decltype(t.save(ar)) static auto member_save(Archive & ar, T const & t) -> decltype(t.save(ar))
{ t.save(ar); } { t.save(ar); }
template<class Archive, class T> template<class Archive, class T> inline
static auto member_load(Archive & ar, T & t) -> decltype(t.load(ar)) static auto member_load(Archive & ar, T & t) -> decltype(t.load(ar))
{ t.load(ar); } { t.load(ar); }
template <class T>
static void load_and_allocate(...)
{ }
template<class T, class Archive> inline
static auto load_and_allocate(Archive & ar) -> decltype(T::load_and_allocate(ar))
{
std::cout << "yo2" << std::endl;
return T::load_and_allocate( ar );
}
}; };
namespace traits namespace traits
{ {
template<typename> struct Void { typedef void type; }; template<typename> struct Void { typedef void type; };
// ######################################################################
// Member load_and_allocate
template<typename T, typename A>
bool constexpr has_member_load_and_allocate()
{ return std::is_same<decltype( access::load_and_allocate<T>( std::declval<A&>() ) ), T*>::value; };
// ######################################################################
// Non Member load_and_allocate
template<typename T, typename A>
bool constexpr has_non_member_load_and_allocate()
{ return std::is_same<decltype( LoadAndAllocate<T>::load_and_allocate( std::declval<A&>() ) ), T*>::value; };
// ######################################################################
// Has either a member or non member allocate
template<typename T, typename A>
bool constexpr has_load_and_allocate()
{ return has_member_load_and_allocate<T, A>() || has_non_member_load_and_allocate<T, A>(); }
// ###################################################################### // ######################################################################
// Member Serialize // Member Serialize
template<typename T, class A, typename Sfinae = void> template<typename T, class A, typename Sfinae = void>
@@ -189,6 +226,53 @@ namespace cereal
#define CEREAL_ARCHIVE_RESTRICT_SERIALIZE(INTYPE, OUTTYPE) \ #define CEREAL_ARCHIVE_RESTRICT_SERIALIZE(INTYPE, OUTTYPE) \
typename std::enable_if<std::is_same<Archive, INTYPE>::value || std::is_same<Archive, OUTTYPE>::value, void>::type typename std::enable_if<std::is_same<Archive, INTYPE>::value || std::is_same<Archive, OUTTYPE>::value, void>::type
} // namespace traits } // namespace traits
namespace detail
{
template <class T, class A, bool Member = traits::has_member_load_and_allocate<T, A>(), bool NonMember = traits::has_non_member_load_and_allocate<T, A>()>
struct Load
{
static_assert( !sizeof(T), "Cereal detected both member and non member load_and_allocate functions!" );
static T * load_andor_allocate( A & ar )
{ return nullptr; }
};
template <class T, class A>
struct Load<T, A, false, false>
{
static_assert( std::is_default_constructible<T>::value,
"Trying to serialize a an object with no default constructor.\n\n"
"Types must either be default constructible or define either a member or non member Construct function.\n"
"Construct functions generally have the signature:\n\n"
"template <class Archive>\n"
"static T * load_and_allocate(Archive & ar)\n"
"{\n"
" var a;\n"
" ar & a\n"
" return new T(a);\n"
"}\n\n" );
static T * load_andor_allocate( A & ar )
{ return new T(); }
};
template <class T, class A>
struct Load<T, A, true, false>
{
static T * load_andor_allocate( A & ar )
{
return access::load_and_allocate<T>( ar );
}
};
template <class T, class A>
struct Load<T, A, false, true>
{
static T * load_andor_allocate( A & ar )
{
return LoadAndAllocate<T>::load_and_allocate( ar );
}
};
} // namespace detail
} // namespace cereal } // namespace cereal
#endif // CEREAL_DETAILS_TRAITS_HPP_ #endif // CEREAL_DETAILS_TRAITS_HPP_

View File

@@ -172,6 +172,39 @@ struct NonEmptyStruct
int x, y, z; int x, y, z;
}; };
struct NoDefaultCtor
{
NoDefaultCtor() = delete;
NoDefaultCtor(int x) : y(x)
{ }
int y;
template <class Archive>
void serialize( Archive & archive )
{
}
//template <class Archive>
//static NoDefaultCtor * load_and_allocate( Archive & ar )
//{
// return new NoDefaultCtor(5);
//}
};
namespace cereal
{
template <>
struct LoadAndAllocate<NoDefaultCtor>
{
template <class Archive>
static NoDefaultCtor * load_and_allocate( Archive & ar )
{
return new NoDefaultCtor(5);
}
};
}
// ###################################################################### // ######################################################################
int main() int main()
{ {
@@ -198,20 +231,20 @@ int main()
// archive & CEREAL_NVP(e_in); // archive & CEREAL_NVP(e_in);
//} //}
//assert(e_in == e_out); //assert(e_in == e_out);//
//
//{ //{ //
// std::ofstream os("ptr.txt"); // std::ofstream os("pt//r.txt");
// cereal::BinaryOutputArchive archive(os); // cereal::BinaryOutput//Archive archive(os);
// std::shared_ptr<std::shared_ptr<int>> xptr1 = std::make_shared<std::shared_ptr<int>>(std::make_shared<int>(5)); // std::shared_ptr<std://:shared_ptr<int>> xptr1 = std::make_shared<std::shared_ptr<int>>(std::make_shared<int>(5));
// std::shared_ptr<int> xptr2 = *xptr1; // std::shared_ptr<int>// xptr2 = *xptr1;
// std::weak_ptr<int> wptr2 = xptr2; // std::weak_ptr<int> w//ptr2 = xptr2;
// std::unique_ptr<Test1> uptr(new Test1); // std::unique_ptr<Test//1> uptr(new Test1);
// uptr->a = 99; // uptr->a = 99; //
// archive & xptr1; // archive & xptr1; //
// archive & xptr2; // archive & xptr2; //
// archive & wptr2; // archive & wptr2; //
// archive & uptr; // archive & uptr; //
//} //}
//{ //{
@@ -266,22 +299,38 @@ int main()
// std::cout << std::endl; // std::cout << std::endl;
//} //}
Private p;
NonEmptyStruct nes;
int q;
cereal::BinaryOutputArchive archive(std::cout);
archive & p;
std::ostringstream os;
cereal::BinaryOutputArchive out_archive(os);
//cereal::access::member_serialize(archive, p); //in_archive & nd;
//cereal::access::member_serialize(archive, q);
//archive & p;
//archive & q;
//decltype(cereal::access::member_serialize(archive, q)) sss;
std::cout << cereal::traits::has_member_serialize<Private, cereal::BinaryOutputArchive>() << std::endl; //std::cout << nd->y << std::endl;
std::cout << cereal::traits::is_output_serializable<Private, cereal::BinaryOutputArchive>() << std::endl;
std::cout << cereal::traits::has_member_serialize<int, cereal::BinaryOutputArchive>() << std::endl; //auto zxx = cereal::access::load_and_allocate<NonEmptyStruct>( out_archive );
//auto xxx = cereal::access::load_and_allocate<NoDefaultCtor>( out_archive );
//std::cout << cereal::traits::has_member_load_and_allocate<NoDefaultCtor, cereal::BinaryOutputArchive>() << std::endl;
//std::cout << cereal::traits::has_member_load_and_allocate<NonEmptyStruct, cereal::BinaryOutputArchive>() << std::endl;
//std::cout << cereal::traits::has_member_load_and_allocate<int, cereal::BinaryOutputArchive>() << std::endl;
//cereal::Construct<int>::Create( out_archive );
//cereal::Construct<NoDefaultCtor>::Create( out_archive );
//std::cout << cereal::traits::has_non_member_load_and_allocate<NoDefaultCtor, cereal::BinaryOutputArchive>() << std::endl;
//std::cout << cereal::traits::has_non_member_load_and_allocate<NonEmptyStruct, cereal::BinaryOutputArchive>() << std::endl;
//std::cout << cereal::traits::has_non_member_load_and_allocate<int, cereal::BinaryOutputArchive>() << std::endl;
auto p = std::make_shared<NoDefaultCtor>( 5 );
out_archive & p;
std::istringstream is(os.str());
cereal::BinaryInputArchive in_archive(is);
p->y = 3;
in_archive & p;
std::cout << p->y << std::endl;
return 0; return 0;
} }