tinkering on #354

This commit is contained in:
Shane Grant 2017-02-19 16:25:32 -08:00
parent 8b8f5814e2
commit 546fd9b896
2 changed files with 264 additions and 24 deletions

View File

@ -116,9 +116,9 @@ namespace cereal
struct PolymorphicCasters
{
//! 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, std::unordered_map<std::type_index, std::vector<PolymorphicCaster const*>>> map;
std::multimap<std::type_index, std::type_index> reverseMap;
std::unordered_multimap<std::type_index, std::type_index> reverseMap;
//! Error message used for unregistered polymorphic casts
#define UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(LoadSave) \
@ -127,24 +127,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 +164,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();
@ -229,18 +231,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, {}} ).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} );
reverseMap.emplace( 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 +254,29 @@ 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(), {}};
};
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::unordered_set<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
// Begin processing the base key and mark derived as dirty
parentStack.push( baseKey );
dirtySet.insert( derivedKey );
dirtySet.emplace( 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();
@ -340,7 +341,7 @@ namespace cereal
{
auto & derivedMap = baseMap.find( it.first )->second;
derivedMap[it.second.first] = it.second.second;
reverseMap.insert( {it.second.first, it.first} );
reverseMap.emplace( it.second.first, it.first );
}
// Mark current parent as modified

View File

@ -356,4 +356,243 @@ void test_polymorphic_threading()
}
#endif // CEREAL_THREAD_SAFE
struct Object
{
Object() = default;
Object( int xx ) : x(xx) {}
virtual ~Object() {}
virtual void func() {}
int x;
template <class Archive>
void serialize( Archive & ar )
{
ar( x );
}
};
#define CEREAL_TEST_CREATE_DERIVED_CLASS(Base, Derived) \
struct Derived : public Base \
{ \
Derived() = default; \
Derived( int yy ) : Base( yy ), Derived##y( yy ) {} \
virtual ~Derived() {} \
\
virtual void func() override {} \
\
int Derived##y; \
template <class Archive> \
void serialize( Archive & ar ) \
{ \
ar( cereal::base_class<Base>( this ), Derived##y ); \
} \
}; \
CEREAL_REGISTER_TYPE(Derived)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived0)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived0,Derived1)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived1,Derived2)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived2,Derived3)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived3,Derived4)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived5)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived5,Derived6)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived6,Derived7)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived7,Derived8)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived8,Derived9)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived10)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived10,Derived11)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived11,Derived12)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived12,Derived13)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived13,Derived14)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived15)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived15,Derived16)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived16,Derived17)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived17,Derived18)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived18,Derived19)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived20)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived20,Derived21)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived21,Derived22)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived22,Derived23)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived23,Derived24)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived25)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived25,Derived26)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived26,Derived27)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived27,Derived28)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived28,Derived29)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived30)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived30,Derived31)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived31,Derived32)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived32,Derived33)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived33,Derived34)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived35)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived35,Derived36)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived36,Derived37)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived37,Derived38)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived38,Derived39)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived40)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived40,Derived41)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived41,Derived42)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived42,Derived43)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived43,Derived44)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived45)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived45,Derived46)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived46,Derived47)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived47,Derived48)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived48,Derived49)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived50)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived50,Derived51)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived51,Derived52)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived52,Derived53)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived53,Derived54)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived55)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived55,Derived56)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived56,Derived57)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived57,Derived58)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived58,Derived59)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived60)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived60,Derived61)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived61,Derived62)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived62,Derived63)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived63,Derived64)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived65)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived65,Derived66)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived66,Derived67)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived67,Derived68)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived68,Derived69)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived70)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived70,Derived71)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived71,Derived72)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived72,Derived73)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived73,Derived74)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived75)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived75,Derived76)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived76,Derived77)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived77,Derived78)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived78,Derived79)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived80)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived80,Derived81)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived81,Derived82)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived82,Derived83)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived83,Derived84)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived85)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived85,Derived86)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived86,Derived87)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived87,Derived88)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived88,Derived89)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived90)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived90,Derived91)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived91,Derived92)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived92,Derived93)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived93,Derived94)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived95)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived95,Derived96)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived96,Derived97)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived97,Derived98)
//CEREAL_TEST_CREATE_DERIVED_CLASS(Derived98,Derived99)
CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived0)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived0,Derived1)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived1,Derived2)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived2,Derived3)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived0,Derived4)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived4,Derived5)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived5,Derived6)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived0,Derived7)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived7,Derived8)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived8,Derived9)
CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived10)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived10,Derived11)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived11,Derived12)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived12,Derived13)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived10,Derived14)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived14,Derived15)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived15,Derived16)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived10,Derived17)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived17,Derived18)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived18,Derived19)
CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived20)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived20,Derived21)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived21,Derived22)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived22,Derived23)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived20,Derived24)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived24,Derived25)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived25,Derived26)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived20,Derived27)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived27,Derived28)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived28,Derived29)
CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived30)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived30,Derived31)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived31,Derived32)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived32,Derived33)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived30,Derived34)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived34,Derived35)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived35,Derived36)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived30,Derived37)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived37,Derived38)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived38,Derived39)
CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived40)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived40,Derived41)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived41,Derived42)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived42,Derived43)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived40,Derived44)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived44,Derived45)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived45,Derived46)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived40,Derived47)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived47,Derived48)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived48,Derived49)
CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived50)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived50,Derived51)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived51,Derived52)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived52,Derived53)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived50,Derived54)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived54,Derived55)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived55,Derived56)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived50,Derived57)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived57,Derived58)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived58,Derived59)
CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived60)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived60,Derived61)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived61,Derived62)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived62,Derived63)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived60,Derived64)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived64,Derived65)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived65,Derived66)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived60,Derived67)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived67,Derived68)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived68,Derived69)
CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived70)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived70,Derived71)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived71,Derived72)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived72,Derived73)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived70,Derived74)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived74,Derived75)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived75,Derived76)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived70,Derived77)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived77,Derived78)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived78,Derived79)
CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived80)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived80,Derived81)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived81,Derived82)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived82,Derived83)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived80,Derived84)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived84,Derived85)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived85,Derived86)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived80,Derived87)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived87,Derived88)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived88,Derived89)
CEREAL_TEST_CREATE_DERIVED_CLASS(Object,Derived90)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived90,Derived91)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived91,Derived92)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived92,Derived93)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived90,Derived94)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived94,Derived95)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived95,Derived96)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived90,Derived97)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived97,Derived98)
CEREAL_TEST_CREATE_DERIVED_CLASS(Derived98,Derived99)
#endif // CEREAL_TEST_POLYMORPHIC_H_