upgrade cereal
This commit is contained in:
@@ -56,6 +56,14 @@
|
||||
#include <set>
|
||||
#include <stack>
|
||||
|
||||
//! Helper macro to omit unused warning
|
||||
#if defined(__GNUC__)
|
||||
// GCC / clang don't want the function
|
||||
#define CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION
|
||||
#else
|
||||
#define CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION static void unused() { (void)b; }
|
||||
#endif
|
||||
|
||||
//! Binds a polymorhic type to all registered archives
|
||||
/*! This binds a polymorphic type to all compatible registered archives that
|
||||
have been registered with CEREAL_REGISTER_ARCHIVE. This must be called
|
||||
@@ -67,7 +75,7 @@
|
||||
template<> \
|
||||
struct init_binding<__VA_ARGS__> { \
|
||||
static bind_to_archives<__VA_ARGS__> const & b; \
|
||||
static void unused() { (void)b; } \
|
||||
CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION \
|
||||
}; \
|
||||
bind_to_archives<__VA_ARGS__> const & init_binding<__VA_ARGS__>::b = \
|
||||
::cereal::detail::StaticObject< \
|
||||
@@ -115,8 +123,10 @@ namespace cereal
|
||||
all registered mappings between base and derived types. */
|
||||
struct PolymorphicCasters
|
||||
{
|
||||
//! Maps from a derived type index to a set of chainable casters
|
||||
using DerivedCasterMap = std::unordered_map<std::type_index, std::vector<PolymorphicCaster const *>>;
|
||||
//! Maps from base type index to a map from derived type index to caster
|
||||
std::map<std::type_index, std::map<std::type_index, std::vector<PolymorphicCaster const*>>> map;
|
||||
std::unordered_map<std::type_index, DerivedCasterMap> map;
|
||||
|
||||
std::multimap<std::type_index, std::type_index> reverseMap;
|
||||
|
||||
@@ -127,24 +137,26 @@ namespace cereal
|
||||
"Make sure you either serialize the base class at some point via cereal::base_class or cereal::virtual_base_class.\n" \
|
||||
"Alternatively, manually register the association with CEREAL_REGISTER_POLYMORPHIC_RELATION.");
|
||||
|
||||
//! Checks if the mapping object that can perform the upcast or downcast
|
||||
//! Checks if the mapping object that can perform the upcast or downcast exists, and returns it if so
|
||||
/*! Uses the type index from the base and derived class to find the matching
|
||||
registered caster. If no matching caster exists, returns false. */
|
||||
static bool exists( std::type_index const & baseIndex, std::type_index const & derivedIndex )
|
||||
registered caster. If no matching caster exists, the bool in the pair will be false and the vector
|
||||
reference should not be used. */
|
||||
static std::pair<bool, std::vector<PolymorphicCaster const *> const &>
|
||||
lookup_if_exists( std::type_index const & baseIndex, std::type_index const & derivedIndex )
|
||||
{
|
||||
// First phase of lookup - match base type index
|
||||
auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
|
||||
auto baseIter = baseMap.find( baseIndex );
|
||||
if (baseIter == baseMap.end())
|
||||
return false;
|
||||
return {false, {}};
|
||||
|
||||
// Second phase - find a match from base to derived
|
||||
auto & derivedMap = baseIter->second;
|
||||
auto const & derivedMap = baseIter->second;
|
||||
auto derivedIter = derivedMap.find( derivedIndex );
|
||||
if (derivedIter == derivedMap.end())
|
||||
return false;
|
||||
return {false, {}};
|
||||
|
||||
return true;
|
||||
return {true, derivedIter->second};
|
||||
}
|
||||
|
||||
//! Gets the mapping object that can perform the upcast or downcast
|
||||
@@ -162,7 +174,7 @@ namespace cereal
|
||||
exceptionFunc();
|
||||
|
||||
// Second phase - find a match from base to derived
|
||||
auto & derivedMap = baseIter->second;
|
||||
auto const & derivedMap = baseIter->second;
|
||||
auto derivedIter = derivedMap.find( derivedIndex );
|
||||
if( derivedIter == derivedMap.end() )
|
||||
exceptionFunc();
|
||||
@@ -176,8 +188,8 @@ namespace cereal
|
||||
{
|
||||
auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(save) } );
|
||||
|
||||
for( auto const * map : mapping )
|
||||
dptr = map->downcast( dptr );
|
||||
for( auto const * dmap : mapping )
|
||||
dptr = dmap->downcast( dptr );
|
||||
|
||||
return static_cast<Derived const *>( dptr );
|
||||
}
|
||||
@@ -213,6 +225,14 @@ namespace cereal
|
||||
#undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION
|
||||
};
|
||||
|
||||
#ifdef CEREAL_OLDER_GCC
|
||||
#define CEREAL_EMPLACE_MAP(map, key, value) \
|
||||
map.insert( std::make_pair(std::move(key), std::move(value)) );
|
||||
#else // NOT CEREAL_OLDER_GCC
|
||||
#define CEREAL_EMPLACE_MAP(map, key, value) \
|
||||
map.emplace( key, value );
|
||||
#endif // NOT_CEREAL_OLDER_GCC
|
||||
|
||||
//! Strongly typed derivation of PolymorphicCaster
|
||||
template <class Base, class Derived>
|
||||
struct PolymorphicVirtualCaster : PolymorphicCaster
|
||||
@@ -229,18 +249,16 @@ namespace cereal
|
||||
// First insert the relation Base->Derived
|
||||
const auto lock = StaticObject<PolymorphicCasters>::lock();
|
||||
auto & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
|
||||
auto lb = baseMap.lower_bound(baseKey);
|
||||
|
||||
{
|
||||
auto & derivedMap = baseMap.insert( lb, {baseKey, {}} )->second;
|
||||
auto lbd = derivedMap.lower_bound(derivedKey);
|
||||
auto & derivedVec = derivedMap.insert( lbd, { std::move(derivedKey), {}} )->second;
|
||||
auto & derivedMap = baseMap.insert( {baseKey, PolymorphicCasters::DerivedCasterMap{}} ).first->second;
|
||||
auto & derivedVec = derivedMap.insert( {derivedKey, {}} ).first->second;
|
||||
derivedVec.push_back( this );
|
||||
}
|
||||
|
||||
// Insert reverse relation Derived->Base
|
||||
auto & reverseMap = StaticObject<PolymorphicCasters>::getInstance().reverseMap;
|
||||
reverseMap.insert( {derivedKey, baseKey} );
|
||||
CEREAL_EMPLACE_MAP(reverseMap, derivedKey, baseKey);
|
||||
|
||||
// Find all chainable unregistered relations
|
||||
/* The strategy here is to process only the nodes in the class hierarchy graph that have been
|
||||
@@ -254,28 +272,40 @@ namespace cereal
|
||||
// Checks whether there is a path from parent->child and returns a <dist, path> pair
|
||||
// dist is set to MAX if the path does not exist
|
||||
auto checkRelation = [](std::type_index const & parentInfo, std::type_index const & childInfo) ->
|
||||
std::pair<size_t, std::vector<PolymorphicCaster const *>>
|
||||
std::pair<size_t, std::vector<PolymorphicCaster const *> const &>
|
||||
{
|
||||
if( PolymorphicCasters::exists( parentInfo, childInfo ) )
|
||||
auto result = PolymorphicCasters::lookup_if_exists( parentInfo, childInfo );
|
||||
if( result.first )
|
||||
{
|
||||
auto const & path = PolymorphicCasters::lookup( parentInfo, childInfo, [](){} );
|
||||
auto const & path = result.second;
|
||||
return {path.size(), path};
|
||||
}
|
||||
else
|
||||
return {std::numeric_limits<size_t>::max(), {}};
|
||||
return {(std::numeric_limits<size_t>::max)(), {}};
|
||||
};
|
||||
|
||||
std::stack<std::type_index> parentStack; // Holds the parent nodes to be processed
|
||||
std::set<std::type_index> dirtySet; // Marks child nodes that have been changed
|
||||
std::set<std::type_index> processedParents; // Marks parent nodes that have been processed
|
||||
std::stack<std::type_index> parentStack; // Holds the parent nodes to be processed
|
||||
std::vector<std::type_index> dirtySet; // Marks child nodes that have been changed
|
||||
std::unordered_set<std::type_index> processedParents; // Marks parent nodes that have been processed
|
||||
|
||||
// Checks if a child has been marked dirty
|
||||
auto isDirty = [&](std::type_index const & c)
|
||||
{
|
||||
auto const dirtySetSize = dirtySet.size();
|
||||
for( size_t i = 0; i < dirtySetSize; ++i )
|
||||
if( dirtySet[i] == c )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
// Begin processing the base key and mark derived as dirty
|
||||
parentStack.push( baseKey );
|
||||
dirtySet.insert( derivedKey );
|
||||
dirtySet.emplace_back( derivedKey );
|
||||
|
||||
while( !parentStack.empty() )
|
||||
{
|
||||
using Relations = std::multimap<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>>;
|
||||
using Relations = std::unordered_multimap<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>>;
|
||||
Relations unregisteredRelations; // Defer insertions until after main loop to prevent iterator invalidation
|
||||
|
||||
const auto parent = parentStack.top();
|
||||
@@ -285,7 +315,7 @@ namespace cereal
|
||||
for( auto const & childPair : baseMap[parent] )
|
||||
{
|
||||
const auto child = childPair.first;
|
||||
if( dirtySet.count( child ) && baseMap.count( child ) )
|
||||
if( isDirty( child ) && baseMap.count( child ) )
|
||||
{
|
||||
auto parentChildPath = checkRelation( parent, child );
|
||||
|
||||
@@ -340,11 +370,11 @@ namespace cereal
|
||||
{
|
||||
auto & derivedMap = baseMap.find( it.first )->second;
|
||||
derivedMap[it.second.first] = it.second.second;
|
||||
reverseMap.insert( {it.second.first, it.first} );
|
||||
CEREAL_EMPLACE_MAP(reverseMap, it.second.first, it.first );
|
||||
}
|
||||
|
||||
// Mark current parent as modified
|
||||
dirtySet.insert( parent );
|
||||
dirtySet.emplace_back( parent );
|
||||
|
||||
// Insert all parents of the current parent node that haven't yet been processed
|
||||
auto parentRange = reverseMap.equal_range( parent );
|
||||
@@ -361,6 +391,8 @@ namespace cereal
|
||||
} // end chainable relations
|
||||
} // end PolymorphicVirtualCaster()
|
||||
|
||||
#undef CEREAL_EMPLACE_MAP
|
||||
|
||||
//! Performs the proper downcast with the templated types
|
||||
void const * downcast( void const * const ptr ) const override
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user