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
CC=g++
CC=clang++
all: unittests sandbox performance sandbox_rtti
@ -7,7 +7,7 @@ sandbox: sandbox.cpp
${CC} sandbox.cpp -o sandbox ${CPPFLAGS}
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
time ${CC} unittests.cpp -o unittests -lboost_unit_test_framework ${CPPFLAGS}

View File

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

View File

@ -26,174 +26,116 @@
*/
#include <type_traits>
#include <iostream>
#include <cereal/details/static_object.hpp>
namespace boost { namespace archive { namespace detail {
// 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>
namespace cereal
{
typedef int type;
};
namespace detail
{
struct InputArchiveBase;
struct OutputArchiveBase;
// This function gets called, but its only purpose is to participate
// in overload resolution with the functions declared by
// BOOST_SERIALIZATION_REGISTER_ARCHIVE, below.
template <class Serializable>
void instantiate_ptr_serialization(Serializable*, int, adl_tag ) {}
//TODO
template <class Archive, class T> struct InputBinding {};
template <class Archive, class T> struct OutputBinding {};
// The function declaration generated by this macro never actually
// 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
struct adl_tag {};
namespace boost {
namespace archive {
namespace detail {
//! Causes the static object bindings between an archive type and a serializable type T
template <class Archive, class T>
struct create_bindings
{
static const InputBinding<Archive, T> &
load(std::true_type)
{
return cereal::detail::StaticObject<InputBinding<Archive, T>>::getInstance();
}
struct basic_pointer_iserializer{};
struct basic_pointer_oserializer{};
static const OutputBinding<Archive, T> &
save(std::true_type)
{
return cereal::detail::StaticObject<OutputBinding<Archive, T>>::getInstance();
}
template <class A, class S>
struct InputBinding{};
template <class A, class S>
struct OutputBinding{};
inline static void load(std::false_type) {}
inline static void save(std::false_type) {}
};
template <class Archive, class Serializable>
struct export_impl
{
static const InputBinding<Archive, Serializable> &
enable_load(std::true_type){
return cereal::detail::StaticObject<InputBinding<Archive, Serializable>>::getInstance();
//! When specialized, causes the compiler to instantiate its parameter
template <void(*)()>
struct instantiate_function {};
template <class Archive, class T>
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> &
enable_save(std::true_type){
return cereal::detail::StaticObject<OutputBinding<Archive, Serializable>>::getInstance();
}
namespace detail2
{
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) {}
inline static void enable_save(std::false_type) {}
};
void bind(std::true_type) const
{ }
// On many platforms, naming a specialization of this template is
// enough to cause its argument to be instantiated.
template <void(*)()>
struct instantiate_function {};
bind_to_archives const & bind() const
{
bind( std::is_abstract<T>() );
return *this;
}
};
template <class Archive, class Serializable>
struct ptr_serialization_support
{
static void instantiate() __attribute__((__used__));
typedef instantiate_function<
&ptr_serialization_support::instantiate
> x;
};
template <class T>
struct init_binding;
} // end namespace
template <class Archive, class Serializable>
void
ptr_serialization_support<Archive,Serializable>::instantiate()
{
export_impl<Archive,Serializable>::enable_save(
typename
Archive::is_saving()
);
template <class T>
void instantiate_polymorphic_binding( T*, int, adl_tag ) {};
export_impl<Archive,Serializable>::enable_load(
typename
Archive::is_loading()
);
}
#define CEREAL_REGISTER_ARCHIVE(Archive) \
namespace cereal { namespace detail { \
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.
// This was made this way so that export.hpp could be included
// 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 { \
#define CEREAL_BIND_TO_ARCHIVES(T) \
namespace cereal { \
namespace detail { \
namespace extra_detail { \
namespace detail2 { \
template<> \
struct init_guid< T > { \
static guid_initializer< T > const & g; \
struct init_binding<T> { \
static bind_to_archives<T> const & b; \
}; \
guid_initializer< T > const & init_guid< T >::g = \
::cereal::detail::StaticObject< \
guid_initializer< T > \
>::getInstance().export_guid(); \
}}}}
bind_to_archives<T> const & init_binding<T>::b = \
::cereal::detail::StaticObject< \
bind_to_archives<T > \
>::getInstance().bind(); \
}}} // end namespaces
} // namespace detail
} // namespace cereal
#include <cereal/archives/binary.hpp>
struct Archive
{
typedef std::true_type is_saving;
typedef std::false_type is_loading;
};
struct MyType {};
struct MyType
{};
BOOST_SERIALIZATION_REGISTER_ARCHIVE(Archive);
BOOST_CLASS_EXPORT_IMPLEMENT(MyType);
CEREAL_REGISTER_ARCHIVE(BinaryInputArchive);
CEREAL_BIND_TO_ARCHIVES(MyType);
template <class T>
void nop(T&&t) {}