fixing up polymorph prototype

This commit is contained in:
Shane Grant
2013-06-27 17:39:20 -07:00
parent 0414f5dcf6
commit 3efeab031d
3 changed files with 97 additions and 149 deletions

View File

@@ -1,5 +1,5 @@
CPPFLAGS=-std=c++11 -I./include -Wall -Werror CPPFLAGS=-std=c++11 -I./include -Wall -Werror
CC=g++ CC=clang++
all: unittests sandbox performance sandbox_rtti all: unittests sandbox performance sandbox_rtti
@@ -7,7 +7,7 @@ sandbox: sandbox.cpp
${CC} sandbox.cpp -o sandbox ${CPPFLAGS} ${CC} sandbox.cpp -o sandbox ${CPPFLAGS}
sandbox_rtti: sandbox_rtti.cpp sandbox_rtti: sandbox_rtti.cpp
${CC} sandbox_rtti.cpp -o sandbox_rtti ${CPPFLAGS} -lpthread ${CC} sandbox_rtti.cpp -o sandbox_rtti ${CPPFLAGS} -O3
unittests: unittests.cpp unittests: unittests.cpp
time ${CC} unittests.cpp -o unittests -lboost_unit_test_framework ${CPPFLAGS} time ${CC} unittests.cpp -o unittests -lboost_unit_test_framework ${CPPFLAGS}

View File

@@ -146,9 +146,15 @@ namespace cereal
enum Flags { AllowEmptyClassElision = 1 }; enum Flags { AllowEmptyClassElision = 1 };
// ###################################################################### // ######################################################################
namespace detail
{
struct OutputArchiveBase {};
struct InputArchiveBase {};
}
//! The base output archive class //! The base output archive class
template<class ArchiveType, uint32_t Flags = 0> template<class ArchiveType, uint32_t Flags = 0>
class OutputArchive class OutputArchive : public detail::OutputArchiveBase
{ {
public: public:
OutputArchive(ArchiveType * const self) : self(self), itsCurrentPointerId(1) OutputArchive(ArchiveType * const self) : self(self), itsCurrentPointerId(1)
@@ -297,7 +303,7 @@ namespace cereal
// ###################################################################### // ######################################################################
//! The base input archive class //! The base input archive class
template<class ArchiveType, uint32_t Flags = 0> template<class ArchiveType, uint32_t Flags = 0>
class InputArchive class InputArchive : public detail::InputArchiveBase
{ {
public: public:
InputArchive(ArchiveType * const self) : self(self) { } InputArchive(ArchiveType * const self) : self(self) { }

View File

@@ -26,174 +26,116 @@
*/ */
#include <type_traits> #include <type_traits>
#include <iostream>
#include <cereal/details/static_object.hpp> #include <cereal/details/static_object.hpp>
namespace boost { namespace archive { namespace detail { namespace cereal
// No instantiate_ptr_serialization overloads generated by
// BOOST_SERIALIZATION_REGISTER_ARCHIVE that lexically follow the call
// will be seen *unless* they are in an associated namespace of one of
// the arguments, so we pass one of these along to make sure this
// namespace is considered. See temp.dep.candidate (14.6.4.2) in the
// standard.
struct adl_tag {};
template <class Archive, class Serializable>
struct ptr_serialization_support;
// We could've just used ptr_serialization_support, above, but using
// it with only a forward declaration causes vc6/7 to complain about a
// missing instantiate member, even if it has one. This is just a
// friendly layer of indirection.
template <class Archive, class Serializable>
struct _ptr_serialization_support
: ptr_serialization_support<Archive,Serializable>
{ {
typedef int type; namespace detail
}; {
struct InputArchiveBase;
struct OutputArchiveBase;
// This function gets called, but its only purpose is to participate //TODO
// in overload resolution with the functions declared by template <class Archive, class T> struct InputBinding {};
// BOOST_SERIALIZATION_REGISTER_ARCHIVE, below. template <class Archive, class T> struct OutputBinding {};
template <class Serializable>
void instantiate_ptr_serialization(Serializable*, int, adl_tag ) {}
// The function declaration generated by this macro never actually struct adl_tag {};
// gets called, but its return type gets instantiated, and that's
// enough to cause registration of serialization functions between
// Archive and any exported Serializable type. See also:
// boost/serialization/export.hpp
# define BOOST_SERIALIZATION_REGISTER_ARCHIVE(Archive) \
namespace boost { namespace archive { namespace detail { \
\
template <class Serializable> \
typename _ptr_serialization_support<Archive, Serializable>::type \
instantiate_ptr_serialization( Serializable*, Archive*, adl_tag ); \
\
}}}
}}} // namespace boost::archive::detail
namespace boost { //! Causes the static object bindings between an archive type and a serializable type T
namespace archive { template <class Archive, class T>
namespace detail { struct create_bindings
{
static const InputBinding<Archive, T> &
load(std::true_type)
{
return cereal::detail::StaticObject<InputBinding<Archive, T>>::getInstance();
}
struct basic_pointer_iserializer{}; static const OutputBinding<Archive, T> &
struct basic_pointer_oserializer{}; save(std::true_type)
{
return cereal::detail::StaticObject<OutputBinding<Archive, T>>::getInstance();
}
template <class A, class S> inline static void load(std::false_type) {}
struct InputBinding{}; inline static void save(std::false_type) {}
template <class A, class S> };
struct OutputBinding{};
template <class Archive, class Serializable> //! When specialized, causes the compiler to instantiate its parameter
struct export_impl template <void(*)()>
{ struct instantiate_function {};
static const InputBinding<Archive, Serializable> &
enable_load(std::true_type){ template <class Archive, class T>
return cereal::detail::StaticObject<InputBinding<Archive, Serializable>>::getInstance(); struct polymorphic_serialization_support
{
static void instantiate();
typedef instantiate_function<instantiate> unused;
};
template <class Archive, class T>
void polymorphic_serialization_support<Archive,T>::instantiate()
{
create_bindings<Archive,T>::save( std::is_base_of<detail::OutputArchiveBase, Archive>() );
create_bindings<Archive,T>::load( std::is_base_of<detail::InputArchiveBase, Archive>() );
} }
static const OutputBinding<Archive, Serializable> & namespace detail2
enable_save(std::true_type){ {
return cereal::detail::StaticObject<OutputBinding<Archive, Serializable>>::getInstance(); template <class T>
} struct bind_to_archives
{
void bind(std::false_type) const
{
instantiate_polymorphic_binding( (T*)0, 0, adl_tag{} );
}
inline static void enable_load(std::false_type) {} void bind(std::true_type) const
inline static void enable_save(std::false_type) {} { }
};
// On many platforms, naming a specialization of this template is bind_to_archives const & bind() const
// enough to cause its argument to be instantiated. {
template <void(*)()> bind( std::is_abstract<T>() );
struct instantiate_function {}; return *this;
}
};
template <class Archive, class Serializable> template <class T>
struct ptr_serialization_support struct init_binding;
{ } // end namespace
static void instantiate() __attribute__((__used__));
typedef instantiate_function<
&ptr_serialization_support::instantiate
> x;
};
template <class Archive, class Serializable> template <class T>
void void instantiate_polymorphic_binding( T*, int, adl_tag ) {};
ptr_serialization_support<Archive,Serializable>::instantiate()
{
export_impl<Archive,Serializable>::enable_save(
typename
Archive::is_saving()
);
export_impl<Archive,Serializable>::enable_load( #define CEREAL_REGISTER_ARCHIVE(Archive) \
typename namespace cereal { namespace detail { \
Archive::is_loading() template <class T> \
); typename polymorphic_serialization_support<Archive, T>::type \
} instantiate_polymorphic_binding( T*, Archive*, adl_tag ); \
} } // end namespaces
// Note INTENTIONAL usage of anonymous namespace in header. #define CEREAL_BIND_TO_ARCHIVES(T) \
// This was made this way so that export.hpp could be included namespace cereal { \
// in other headers. This is still under study.
namespace extra_detail {
template<class T>
struct guid_initializer
{
void export_guid(std::false_type) const {
// generates the statically-initialized objects whose constructors
// register the information allowing serialization of T objects
// through pointers to their base classes.
instantiate_ptr_serialization((T*)0, 0, adl_tag());
}
void export_guid(std::true_type) const {
}
guid_initializer const & export_guid() const {
// note: exporting an abstract base class will have no effect
// and cannot be used to instantitiate serialization code
// (one might be using this in a DLL to instantiate code)
//BOOST_STATIC_WARNING(! boost::serialization::is_abstract< T >::value);
export_guid(std::is_abstract<T>());
return *this;
}
};
template<typename T>
struct init_guid;
} // anonymous
} // namespace detail
} // namespace archive
} // namespace boost
#define BOOST_CLASS_EXPORT_IMPLEMENT(T) \
namespace boost { \
namespace archive { \
namespace detail { \ namespace detail { \
namespace extra_detail { \ namespace detail2 { \
template<> \ template<> \
struct init_guid< T > { \ struct init_binding<T> { \
static guid_initializer< T > const & g; \ static bind_to_archives<T> const & b; \
}; \ }; \
guid_initializer< T > const & init_guid< T >::g = \ bind_to_archives<T> const & init_binding<T>::b = \
::cereal::detail::StaticObject< \ ::cereal::detail::StaticObject< \
guid_initializer< T > \ bind_to_archives<T > \
>::getInstance().export_guid(); \ >::getInstance().bind(); \
}}}} }}} // end namespaces
} // namespace detail
} // namespace cereal
#include <cereal/archives/binary.hpp>
struct Archive struct MyType {};
{
typedef std::true_type is_saving;
typedef std::false_type is_loading;
};
struct MyType CEREAL_REGISTER_ARCHIVE(BinaryInputArchive);
{}; CEREAL_BIND_TO_ARCHIVES(MyType);
BOOST_SERIALIZATION_REGISTER_ARCHIVE(Archive);
BOOST_CLASS_EXPORT_IMPLEMENT(MyType);
template <class T> template <class T>
void nop(T&&t) {} void nop(T&&t) {}