Versioning working

see #8
This commit is contained in:
Shane Grant
2013-12-11 12:02:12 -08:00
parent 6dcef8370b
commit d6bfabe7cc
4 changed files with 156 additions and 45 deletions

View File

@@ -173,10 +173,7 @@ namespace cereal
//! Construct the output archive //! Construct the output archive
/*! @param self A pointer to the derived ArchiveType (pass this from the derived archive) */ /*! @param self A pointer to the derived ArchiveType (pass this from the derived archive) */
OutputArchive(ArchiveType * const self) : self(self), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1) OutputArchive(ArchiveType * const self) : self(self), itsCurrentPointerId(1), itsCurrentPolymorphicTypeId(1)
{ { }
// Immediately dump all version information
self->process( make_nvp<ArchiveType>( "cereal_version_information", detail::Versions ) );
}
//! Serializes all passed in data //! Serializes all passed in data
template <class ... Types> inline template <class ... Types> inline
@@ -387,7 +384,8 @@ namespace cereal
template <class T> inline template <class T> inline
void registerClassVersion( const std::uint32_t version ) void registerClassVersion( const std::uint32_t version )
{ {
const auto insertResult = itsVersionedTypes.insert( std::type_index(typeid(T)).hash_code() ); static const auto hash = std::type_index(typeid(T)).hash_code();
const auto insertResult = itsVersionedTypes.insert( hash );
if( insertResult.second ) // insertion took place, serialize the version number if( insertResult.second ) // insertion took place, serialize the version number
process( make_nvp<ArchiveType>("cereal_class_version", version) ); process( make_nvp<ArchiveType>("cereal_class_version", version) );
} }
@@ -696,6 +694,85 @@ namespace cereal
return *self; return *self;
} }
/*! @name Boost Transition Layer (private)
Specific private functionality and overrides for enabling the Boost Transition Layer */
//! @{
//! Registers a class version with the archive and serializes it if necessary
/*! If this is the first time this class has been serialized, we will record its
version number and serialize that.
@tparam T The type of the class being serialized
@param version The version number associated with it */
template <class T> inline
std::uint32_t loadClassVersion()
{
static const auto hash = std::type_index(typeid(T)).hash_code();
auto lookupResult = itsVersionedTypes.find( hash );
if( lookupResult != itsVersionedTypes.end() ) // already exists
return lookupResult->second;
else // need to load
{
std::uint32_t version;
process( make_nvp<ArchiveType>("cereal_class_version", version) );
itsVersionedTypes.emplace_hint( lookupResult, hash, version );
return version;
}
}
//! Member serialization
/*! Boost Transition Layer version */
template <class T> inline
typename std::enable_if<traits::is_input_serializable<T, ArchiveType>::value && traits::has_member_versioned_serialize<T, ArchiveType>::value,
ArchiveType &>::type
processImpl(T & t)
{
static const auto version = loadClassVersion<T>();
access::member_serialize(*self, t, version);
return *self;
}
//! Non member serialization
/*! Boost Transition Layer version */
template <class T> inline
typename std::enable_if<traits::is_input_serializable<T, ArchiveType>::value && traits::has_non_member_versioned_serialize<T, ArchiveType>::value,
ArchiveType &>::type
processImpl(T & t)
{
static const auto version = loadClassVersion<T>();
serialize(*self, t, version);
return *self;
}
//! Member split (load)
/*! Boost Transition Layer version */
template <class T> inline
typename std::enable_if<traits::is_input_serializable<T, ArchiveType>::value && traits::has_member_versioned_load<T, ArchiveType>::value,
ArchiveType &>::type
processImpl(T & t)
{
static const auto version = loadClassVersion<T>();
access::member_load(*self, t, version);
return *self;
}
//! Non member split (load)
/*! Boost Transition Layer version */
template <class T> inline
typename std::enable_if<traits::is_input_serializable<T, ArchiveType>::value && traits::has_non_member_versioned_load<T, ArchiveType>::value,
ArchiveType &>::type
processImpl(T & t)
{
static const auto version = loadClassVersion<T>();
load(*self, t, version);
return *self;
}
//! @}
private: private:
ArchiveType * const self; ArchiveType * const self;
@@ -707,6 +784,9 @@ namespace cereal
//! Maps from name ids to names //! Maps from name ids to names
std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap; std::unordered_map<std::uint32_t, std::string> itsPolymorphicTypeMap;
//! Maps from type hash codes to version numbers
std::unordered_map<std::size_t, std::uint32_t> itsVersionedTypes;
}; // class InputArchive }; // class InputArchive
} // namespace cereal } // namespace cereal

View File

@@ -305,6 +305,28 @@ namespace cereal
return {std::forward<KeyType>(key), std::forward<ValueType>(value)}; return {std::forward<KeyType>(key), std::forward<ValueType>(value)};
} }
namespace detail
{
//! Holds all registered version information
struct Versions
{
static std::unordered_map<std::size_t, std::uint32_t> mapping;
}; // struct Versions
//! Initialize the mapping
std::unordered_map<std::size_t, std::uint32_t> Versions::mapping = {};
//! Version information class - used in Boost Transition Layer
/*! This is the base case for classes that have not been explicitly
registered */
template <class T> struct Version
{
static const std::uint32_t version = 0;
// we don't need to explicitly register these types since they
// always get a version number of 0
};
} // namespace detail
//! Defines a class version for some type //! Defines a class version for some type
/*! This is part of the Boost Transition Layer and is not the recommended way /*! This is part of the Boost Transition Layer and is not the recommended way
of using cereal. This works identically to how it does in Boost serialization, of using cereal. This works identically to how it does in Boost serialization,

View File

@@ -529,29 +529,6 @@ namespace cereal
return LoadAndAllocate<T>::load_and_allocate( ar ); return LoadAndAllocate<T>::load_and_allocate( ar );
} }
}; };
namespace
{
}
//! Holds all registered version information
struct Versions
{
std::unordered_map<std::size_t, std::uint32_t> mapping;
};
//! Initialize the mapping
std::unordered_map<std::size_t, std::uint32_t> Versions::mapping = {};
//! Version information class - used in Boost Transition Layer
/*! This is the base case for classes that have not been explicitly
registered */
template <class T> struct Version
{
static const std::uint32_t version = 0;
// we don't need to explicitly register these types since they
// always get a version number of 0
};
} // namespace detail } // namespace detail
} // namespace cereal } // namespace cereal

View File

@@ -383,8 +383,12 @@ void test_unordered_loads()
class BoostTransitionMS class BoostTransitionMS
{ {
public: public:
BoostTransitionMS() {}
BoostTransitionMS( int xx ) : x(xx) {} BoostTransitionMS( int xx ) : x(xx) {}
int getX(){ return x; }
void setX( int xx ){ x = xx; }
private: private:
friend class cereal::access; friend class cereal::access;
int x; int x;
@@ -397,8 +401,12 @@ class BoostTransitionMS
class BoostTransitionSplit class BoostTransitionSplit
{ {
public: public:
BoostTransitionSplit() {}
BoostTransitionSplit( int xx ) : x(xx) {} BoostTransitionSplit( int xx ) : x(xx) {}
int getX(){ return x; }
void setX( int xx ){ x = xx; }
private: private:
friend class cereal::access; friend class cereal::access;
int x; int x;
@@ -415,6 +423,7 @@ class BoostTransitionSplit
class BoostTransitionNMS class BoostTransitionNMS
{ {
public: public:
BoostTransitionNMS() {}
BoostTransitionNMS( int xx ) : x(xx) {} BoostTransitionNMS( int xx ) : x(xx) {}
int x; int x;
@@ -422,11 +431,12 @@ class BoostTransitionNMS
template <class Archive> template <class Archive>
void serialize( Archive & ar, BoostTransitionNMS & bnms, const std::uint32_t version ) void serialize( Archive & ar, BoostTransitionNMS & bnms, const std::uint32_t version )
{ ar( bnms.x ); } { ar( bnms.x ); std::cout << "NMS version: " << version << std::endl; }
struct BoostTransitionNMSplit struct BoostTransitionNMSplit
{ {
public: public:
BoostTransitionNMSplit() {}
BoostTransitionNMSplit( int xx ) : x(xx) {} BoostTransitionNMSplit( int xx ) : x(xx) {}
int x; int x;
@@ -434,11 +444,11 @@ struct BoostTransitionNMSplit
template <class Archive> template <class Archive>
void save( Archive & ar, BoostTransitionNMSplit const & bnsplit, const std::uint32_t version ) void save( Archive & ar, BoostTransitionNMSplit const & bnsplit, const std::uint32_t version )
{ ar( bnsplit.x ); } { ar( bnsplit.x ); std::cout << "NMsave version: " << version << std::endl; }
template <class Archive> template <class Archive>
void load( Archive & ar, BoostTransitionNMSplit & bnsplit, const std::uint32_t version ) void load( Archive & ar, BoostTransitionNMSplit & bnsplit, const std::uint32_t version )
{ ar( bnsplit.x ); } { ar( bnsplit.x ); std::cout << "NMload version: " << version << std::endl; }
// ###################################################################### // ######################################################################
int main() int main()
@@ -711,22 +721,10 @@ int main()
std::cout << std::endl; std::cout << std::endl;
} }
std::cerr << "-------------------------" << std::endl;
std::cout << cereal::traits::has_member_serialize<BoostTransitionMS, cereal::BinaryOutputArchive>() << std::endl;
std::cout << cereal::traits::has_member_versioned_serialize<BoostTransitionMS, cereal::BinaryOutputArchive>() << std::endl;
std::cout << cereal::traits::is_output_serializable<BoostTransitionMS, cereal::BinaryOutputArchive>() << std::endl;
std::cout << cereal::traits::is_output_versioned<BoostTransitionMS, cereal::BinaryOutputArchive>() << std::endl;
std::cout << (cereal::traits::is_output_serializable<BoostTransitionMS, cereal::BinaryOutputArchive>::value &&
cereal::traits::has_member_serialize<BoostTransitionMS, cereal::BinaryOutputArchive>::value &&
cereal::traits::is_output_versioned<BoostTransitionMS, cereal::BinaryOutputArchive>::value )<< std::endl;
std::cout << "---------snarf" << std::endl;
std::cout << cereal::traits::has_non_member_serialize<BoostTransitionNMS, cereal::BinaryOutputArchive>() << std::endl;
{ {
// Boost transition layer stuff // Boost transition layer stuff
cereal::XMLOutputArchive ar(std::cout); std::ofstream ss("cereal_version.out");
cereal::XMLOutputArchive ar(ss);
BoostTransitionMS b(3); BoostTransitionMS b(3);
ar( b, b ); ar( b, b );
@@ -741,6 +739,40 @@ int main()
ar( e, e ); ar( e, e );
} }
{
// Boost transition layer stuff
std::ifstream ss("cereal_version.out");
cereal::XMLInputArchive ar(ss);
BoostTransitionMS b;
ar( b );
assert( b.getX() == 3 );
b.setX( 0 );
ar( b );
assert( b.getX() == 3 );
BoostTransitionSplit c;
ar( c );
assert( c.getX() == 4 );
c.setX( 0 );
ar( c );
assert( c.getX() == 4 );
BoostTransitionNMS d;
ar( d );
assert( d.x == 5 );
d.x = 0;
ar( d );
assert( d.x == 5 );
BoostTransitionNMSplit e;
ar( e );
assert( e.x == 32 );
e.x = 0;
ar( e );
assert( e.x == 32 );
}
return 0; return 0;
} }