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
/*! @param self A pointer to the derived ArchiveType (pass this from the derived archive) */
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
template <class ... Types> inline
@@ -387,7 +384,8 @@ namespace cereal
template <class T> inline
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
process( make_nvp<ArchiveType>("cereal_class_version", version) );
}
@@ -696,6 +694,85 @@ namespace cereal
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:
ArchiveType * const self;
@@ -707,6 +784,9 @@ namespace cereal
//! Maps from name ids to names
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
} // namespace cereal

View File

@@ -305,6 +305,28 @@ namespace cereal
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
/*! 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,

View File

@@ -529,29 +529,6 @@ namespace cereal
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 cereal

View File

@@ -383,8 +383,12 @@ void test_unordered_loads()
class BoostTransitionMS
{
public:
BoostTransitionMS() {}
BoostTransitionMS( int xx ) : x(xx) {}
int getX(){ return x; }
void setX( int xx ){ x = xx; }
private:
friend class cereal::access;
int x;
@@ -397,8 +401,12 @@ class BoostTransitionMS
class BoostTransitionSplit
{
public:
BoostTransitionSplit() {}
BoostTransitionSplit( int xx ) : x(xx) {}
int getX(){ return x; }
void setX( int xx ){ x = xx; }
private:
friend class cereal::access;
int x;
@@ -415,6 +423,7 @@ class BoostTransitionSplit
class BoostTransitionNMS
{
public:
BoostTransitionNMS() {}
BoostTransitionNMS( int xx ) : x(xx) {}
int x;
@@ -422,11 +431,12 @@ class BoostTransitionNMS
template <class Archive>
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
{
public:
BoostTransitionNMSplit() {}
BoostTransitionNMSplit( int xx ) : x(xx) {}
int x;
@@ -434,11 +444,11 @@ struct BoostTransitionNMSplit
template <class Archive>
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>
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()
@@ -711,22 +721,10 @@ int main()
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
cereal::XMLOutputArchive ar(std::cout);
std::ofstream ss("cereal_version.out");
cereal::XMLOutputArchive ar(ss);
BoostTransitionMS b(3);
ar( b, b );
@@ -741,6 +739,40 @@ int main()
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;
}