From ddd7ff82a39d52320a1f0619bee4daf38b30700b Mon Sep 17 00:00:00 2001 From: Shane Grant Date: Sun, 19 Feb 2017 16:25:32 -0800 Subject: [PATCH] tinkering on #354 --- include/cereal/details/polymorphic_impl.hpp | 49 ++-- unittests/polymorphic.hpp | 239 ++++++++++++++++++++ 2 files changed, 264 insertions(+), 24 deletions(-) diff --git a/include/cereal/details/polymorphic_impl.hpp b/include/cereal/details/polymorphic_impl.hpp index 81128c8b1..fc669b69e 100644 --- a/include/cereal/details/polymorphic_impl.hpp +++ b/include/cereal/details/polymorphic_impl.hpp @@ -116,9 +116,9 @@ namespace cereal struct PolymorphicCasters { //! Maps from base type index to a map from derived type index to caster - std::map>> map; + std::unordered_map>> map; - std::multimap reverseMap; + std::unordered_multimap 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 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::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::lock(); auto & baseMap = StaticObject::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::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 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> + std::pair 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::max(), {}}; }; - std::stack parentStack; // Holds the parent nodes to be processed - std::set dirtySet; // Marks child nodes that have been changed - std::set processedParents; // Marks parent nodes that have been processed + std::stack parentStack; // Holds the parent nodes to be processed + std::unordered_set dirtySet; // Marks child nodes that have been changed + std::unordered_set 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>>; + using Relations = std::unordered_multimap>>; 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 diff --git a/unittests/polymorphic.hpp b/unittests/polymorphic.hpp index 9309ac4f5..7e69be9b0 100644 --- a/unittests/polymorphic.hpp +++ b/unittests/polymorphic.hpp @@ -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 + 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 \ + void serialize( Archive & ar ) \ + { \ + ar( cereal::base_class( 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_