From 3bb82dd2dfc7895f5447c8d46232a6d13c6ecb17 Mon Sep 17 00:00:00 2001 From: Christopher Lackner Date: Fri, 7 Dec 2018 11:20:47 +0100 Subject: [PATCH] DoArchive for array only if T is archivable, little cleanup --- libsrc/core/basearchive.cpp | 17 +++- libsrc/core/basearchive.hpp | 150 +++++++++++++++++++++--------------- libsrc/core/ngcore.hpp | 1 - libsrc/core/type_traits.hpp | 4 +- libsrc/general/array.hpp | 4 +- libsrc/gprim/spline.cpp | 2 +- libsrc/gprim/spline.hpp | 2 +- 7 files changed, 107 insertions(+), 73 deletions(-) diff --git a/libsrc/core/basearchive.cpp b/libsrc/core/basearchive.cpp index 30f493bb..ad0d1866 100644 --- a/libsrc/core/basearchive.cpp +++ b/libsrc/core/basearchive.cpp @@ -25,9 +25,20 @@ namespace ngcore std::string demangle(const char* typeinfo) { int status; return abi::__cxa_demangle(typeinfo, 0, 0, &status); } #endif - std::map& GetArchiveRegister() + static std::map* type_register; + const ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname) { - static std::map type_register; - return type_register; + if(!type_register) type_register = new std::map(); + return (*type_register)[classname]; + } + void Archive :: SetArchiveRegister(const std::string& classname, ClassArchiveInfo info) + { + if(!type_register) type_register = new std::map(); + (*type_register)[classname] = info; + } + bool Archive :: IsRegistered(const std::string& classname) + { + if(!type_register) type_register = new std::map(); + return type_register->count(classname) != 0; } } diff --git a/libsrc/core/basearchive.hpp b/libsrc/core/basearchive.hpp index 249c6e22..29cafd7b 100644 --- a/libsrc/core/basearchive.hpp +++ b/libsrc/core/basearchive.hpp @@ -22,7 +22,7 @@ namespace ngcore template T* constructIfPossible() { return constructIfPossible_impl(int{}); } - // Type trait to check if a class implements a 'void DoArchive(Archive&)' function + //Type trait to check if a class implements a 'void DoArchive(Archive&)' function template struct has_DoArchive { @@ -37,8 +37,21 @@ namespace ngcore static constexpr bool value = type::value; }; - // Info stored by registering a class using the RegisterClassForArchive struct in the map - // stored in GetArchiveRegister + // Check if class is archivable + template + struct is_Archivable + { + private: + template + static constexpr auto check(T2*) -> + typename std::is_same() & std::declval()),Archive&>::type; + template + static constexpr std::false_type check(...); + typedef decltype(check(nullptr)) type; + public: + static constexpr bool value = type::value; + }; + struct ClassArchiveInfo { // create new object of this type and return a void* pointer that is points to the location @@ -52,17 +65,6 @@ namespace ngcore std::function downcaster; }; - // Returns a map of from the mangled typeids to the ClassArchiveInfo - std::map& GetArchiveRegister(); - - // Helper class for up-/downcasting - template - struct Caster - { - static void* tryUpcast(const std::type_info& ti, T* p); - static void* tryDowncast(const std::type_info& ti, void* p); - }; - // Base Archive class class Archive { @@ -74,6 +76,23 @@ namespace ngcore // vectors for storing the unarchived (shared) pointers std::vector> nr2shared_ptr; std::vector nr2ptr; + + // Helper class for up-/downcasting + template + struct Caster + { + static void* tryUpcast(const std::type_info& ti, T* p); + static void* tryDowncast(const std::type_info& ti, void* p); + }; + template + friend class RegisterClassForArchive; + + // Returns ClassArchiveInfo of demangled typeid + static const ClassArchiveInfo& GetArchiveRegister(const std::string& classname); + // Set ClassArchiveInfo for demangled typeid, this is done by creating an instance of + // RegisterClassForArchive + static void SetArchiveRegister(const std::string& classname, ClassArchiveInfo info); + static bool IsRegistered(const std::string& classname); public: Archive (bool ais_output) : is_output(ais_output), shared_ptr_count(0), ptr_count(0) { ; } virtual ~Archive() { ; } @@ -147,7 +166,7 @@ namespace ngcore } // Archive arrays ===================================================== // this functions can be overloaded in Archive implementations for more efficiency - template + template ::value>::type> Archive & Do (T * data, size_t n) { for (size_t j = 0; j < n; j++) { (*this) & data[j]; }; return *this; }; @@ -194,11 +213,11 @@ namespace ngcore // Downcasting is only possible for our registered classes if(typeid(T) != typeid(*ptr)) { - if(GetArchiveRegister().count(demangle(typeid(*ptr).name())) == 0) + if(!IsRegistered(demangle(typeid(*ptr).name()))) throw std::runtime_error(std::string("Archive error: Polymorphic type ") + demangle(typeid(*ptr).name()) + " not registered for archive"); - reg_ptr = GetArchiveRegister()[demangle(typeid(*ptr).name())].downcaster(typeid(T), ptr.get()); + reg_ptr = GetArchiveRegister(demangle(typeid(*ptr).name())).downcaster(typeid(T), ptr.get()); // if there was a true downcast we have to store more information if(reg_ptr != (void*) ptr.get()) neededDowncast = true; @@ -244,7 +263,7 @@ namespace ngcore { std::string name; (*this) & name; - auto info = GetArchiveRegister()[name]; + auto info = GetArchiveRegister(name); // for this we use an aliasing constructor to create a shared pointer sharing lifetime // with our shared ptr, but pointing to the true object nr2shared_ptr.push_back(std::shared_ptr(std::static_pointer_cast(ptr), @@ -265,7 +284,7 @@ namespace ngcore // wouldn't have worked else) std::string name; (*this) & name; - auto info = GetArchiveRegister()[name]; + auto info = GetArchiveRegister(name); // same trick as above, create a shared ptr sharing lifetime with // the shared_ptr in the register, but pointing to our object ptr = std::static_pointer_cast(std::shared_ptr(other, @@ -291,12 +310,12 @@ namespace ngcore void* reg_ptr = (void*)p; if(typeid(T) != typeid(*p)) { - if(GetArchiveRegister().count(demangle(typeid(*p).name())) == 0) + if(!IsRegistered(demangle(typeid(*p).name()))) throw std::runtime_error(std::string("Archive error: Polymorphic type ") + demangle(typeid(*p).name()) + " not registered for archive"); else - reg_ptr = GetArchiveRegister()[demangle(typeid(*p).name())].downcaster(typeid(T), (void*) p); + reg_ptr = GetArchiveRegister(demangle(typeid(*p).name())).downcaster(typeid(T), (void*) p); } auto pos = ptr2nr.find(reg_ptr); // if the pointer is not found in the map create a new entry @@ -317,7 +336,7 @@ namespace ngcore // to avoid compile time issues we allow this behaviour only for "our" classes that // implement a void DoArchive(Archive&) member function // To recreate the object we need to store the true type of it - if(GetArchiveRegister().count(demangle(typeid(*p).name())) == 0) + if(!IsRegistered(demangle(typeid(*p).name()))) throw std::runtime_error(std::string("Archive error: Polymorphic type ") + demangle(typeid(*p).name()) + " not registered for archive"); @@ -350,7 +369,7 @@ namespace ngcore // As stated above, we want this special behaviour only for our classes that implement DoArchive std::string name; (*this) & name; - auto info = GetArchiveRegister()[name]; + auto info = GetArchiveRegister(name); // the creator creates a new object of type name, and returns a void* pointing // to T (which may have an offset) p = (T*) info.creator(typeid(T)); @@ -366,9 +385,9 @@ namespace ngcore (*this) & downcasted & name; if(downcasted) { - // if the class has been downcasted we can assume it is in the register - auto info = GetArchiveRegister()[name]; - p = (T*) info.upcaster(typeid(T), nr2ptr[nr]); + // if the class has been downcasted we can assume it is in the register + auto info = GetArchiveRegister(name); + p = (T*) info.upcaster(typeid(T), nr2ptr[nr]); } else p = (T*) nr2ptr[nr]; @@ -397,6 +416,41 @@ namespace ngcore protected: static std::map& GetLibraryVersions(); + private: + template + struct Caster + { + static void* tryUpcast (const std::type_info& ti, T* p) + { + throw std::runtime_error("Upcast not successful, some classes are not registered properly for archiving!"); + } + static void* tryDowncast (const std::type_info& ti, void* p) + { + throw std::runtime_error("Downcast not successful, some classes are not registered properly for archiving!"); + } + }; + + template + struct Caster + { + static void* tryUpcast(const std::type_info& ti, T* p) + { + try + { return GetArchiveRegister(demangle(typeid(B1).name())).upcaster(ti, (void*) (dynamic_cast(p))); } + catch(std::exception) + { return Caster::tryUpcast(ti, p); } + } + + static void* tryDowncast(const std::type_info& ti, void* p) + { + if(typeid(B1) == ti) + return dynamic_cast((B1*) p); + try + { return GetArchiveRegister(demangle(typeid(B1).name())).downcaster(ti, (void*) ((B1*)p)); } + catch(std::exception) + { return Caster::tryDowncast(ti, p); } + } + }; }; template @@ -410,49 +464,17 @@ namespace ngcore ClassArchiveInfo info; info.creator = [this,&info](const std::type_info& ti) -> void* { return typeid(T) == ti ? constructIfPossible() - : Caster::tryUpcast(ti, constructIfPossible()); }; + : Archive::Caster::tryUpcast(ti, constructIfPossible()); }; info.upcaster = [this](const std::type_info& ti, void* p) -> void* - { return typeid(T) == ti ? p : Caster::tryUpcast(ti, (T*) p); }; + { return typeid(T) == ti ? p : Archive::Caster::tryUpcast(ti, (T*) p); }; info.downcaster = [this](const std::type_info& ti, void* p) -> void* - { return typeid(T) == ti ? p : Caster::tryDowncast(ti, p); }; - GetArchiveRegister()[std::string(demangle(typeid(T).name()))] = info; - } - }; - - template - struct Caster - { - static void* tryUpcast (const std::type_info& ti, T* p) - { - throw std::runtime_error("Upcast not successful, some classes are not registered properly for archiving!"); - } - static void* tryDowncast (const std::type_info& ti, void* p) - { - throw std::runtime_error("Downcast not successful, some classes are not registered properly for archiving!"); - } - }; - - template - struct Caster - { - static void* tryUpcast(const std::type_info& ti, T* p) - { - try - { return GetArchiveRegister()[demangle(typeid(B1).name())].upcaster(ti, (void*) (dynamic_cast(p))); } - catch(std::exception) - { return Caster::tryUpcast(ti, p); } + { return typeid(T) == ti ? p : Archive::Caster::tryDowncast(ti, p); }; + Archive::SetArchiveRegister(std::string(demangle(typeid(T).name())),info); } - static void* tryDowncast(const std::type_info& ti, void* p) - { - if(typeid(B1) == ti) - return dynamic_cast((B1*) p); - try - { return GetArchiveRegister()[demangle(typeid(B1).name())].downcaster(ti, (void*) ((B1*)p)); } - catch(std::exception) - { return Caster::tryDowncast(ti, p); } - } + }; + } #endif // NG_BASEARCHIVE_HPP diff --git a/libsrc/core/ngcore.hpp b/libsrc/core/ngcore.hpp index 9d600991..5c3b5338 100644 --- a/libsrc/core/ngcore.hpp +++ b/libsrc/core/ngcore.hpp @@ -15,7 +15,6 @@ #include #include - namespace ngcore { #if defined(__GNUC__) diff --git a/libsrc/core/type_traits.hpp b/libsrc/core/type_traits.hpp index 3d515c08..b77a612e 100644 --- a/libsrc/core/type_traits.hpp +++ b/libsrc/core/type_traits.hpp @@ -3,6 +3,6 @@ namespace ngcore { template struct _BoolArray{}; - template - constexpr bool all_of_tmpl = std::is_same<_BoolArray, _BoolArray<(T || true)...>>::value; + template + constexpr bool all_of_tmpl = std::is_same<_BoolArray, _BoolArray<(vals || true)...>>::value; } diff --git a/libsrc/general/array.hpp b/libsrc/general/array.hpp index 8f8263e8..bd2b569a 100644 --- a/libsrc/general/array.hpp +++ b/libsrc/general/array.hpp @@ -401,7 +401,9 @@ namespace netgen return data; } - void DoArchive(Archive& archive) + // Only provide this function if T is archivable + template + auto DoArchive(Archive& archive) -> typename std::enable_if::value, void>::type { if(archive.Output()) archive << size; diff --git a/libsrc/gprim/spline.cpp b/libsrc/gprim/spline.cpp index 2d888f9e..3f8ccf98 100644 --- a/libsrc/gprim/spline.cpp +++ b/libsrc/gprim/spline.cpp @@ -99,7 +99,7 @@ namespace netgen } template - inline Point SplineSeg3 :: GetPoint (double t) const + Point SplineSeg3 :: GetPoint (double t) const { double b1, b2, b3; diff --git a/libsrc/gprim/spline.hpp b/libsrc/gprim/spline.hpp index 1454d685..90935d42 100644 --- a/libsrc/gprim/spline.hpp +++ b/libsrc/gprim/spline.hpp @@ -191,7 +191,7 @@ namespace netgen { ar & p1 & p2 & p3 & weight & proj_latest_t; } - inline virtual Point GetPoint (double t) const; + virtual Point GetPoint (double t) const; /// virtual Vec GetTangent (const double t) const;