store demangled type names for cross platform archive

This commit is contained in:
Christopher Lackner 2018-12-04 11:13:12 +01:00
parent e845a203e9
commit a1847ec05f
2 changed files with 29 additions and 17 deletions

View File

@ -1,8 +1,19 @@
#include "ngcore.hpp" #include "ngcore.hpp"
#ifndef WIN
#include <cxxabi.h>
#endif
namespace ngcore namespace ngcore
{ {
#ifdef WIN
// windows does demangling in typeid(T).name()
std::string demangle(const char* typeinfo) { return typeinfo; }
#else
std::string demangle(const char* typeinfo) { int status; return abi::__cxa_demangle(typeinfo, 0, 0, &status); }
#endif
std::map<std::string, ClassArchiveInfo>& GetArchiveRegister() std::map<std::string, ClassArchiveInfo>& GetArchiveRegister()
{ {
static std::map<std::string, ClassArchiveInfo> type_register; static std::map<std::string, ClassArchiveInfo> type_register;

View File

@ -4,11 +4,12 @@
namespace ngcore namespace ngcore
{ {
class Archive; class Archive;
std::string demangle(const char* typeinfo);
// create new pointer of type T if it is default constructible, else throw // create new pointer of type T if it is default constructible, else throw
template<typename T> template<typename T>
T* constructIfPossible_impl(...) T* constructIfPossible_impl(...)
{ throw std::runtime_error(std::string(typeid(T).name()) + " is not default constructible!"); } { throw std::runtime_error(std::string(demangle(typeid(T).name())) + " is not default constructible!"); }
template<typename T, typename= typename std::enable_if<std::is_constructible<T>::value>::type> template<typename T, typename= typename std::enable_if<std::is_constructible<T>::value>::type>
T* constructIfPossible_impl(int) { return new T; } T* constructIfPossible_impl(int) { return new T; }
@ -164,11 +165,11 @@ namespace ngcore
// Downcasting is only possible for our registered classes // Downcasting is only possible for our registered classes
if(typeid(T) != typeid(*ptr)) if(typeid(T) != typeid(*ptr))
{ {
if(GetArchiveRegister().count(std::string(typeid(*ptr).name())) == 0) if(GetArchiveRegister().count(demangle(typeid(*ptr).name())) == 0)
throw std::runtime_error(std::string("Archive error: Polymorphic type ") throw std::runtime_error(std::string("Archive error: Polymorphic type ")
+ typeid(*ptr).name() + demangle(typeid(*ptr).name())
+ " not registered for archive"); + " not registered for archive");
reg_ptr = GetArchiveRegister()[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 there was a true downcast we have to store more information
if(reg_ptr != (void*) ptr.get()) if(reg_ptr != (void*) ptr.get())
neededDowncast = true; neededDowncast = true;
@ -182,14 +183,14 @@ namespace ngcore
(*this) & neededDowncast & p; (*this) & neededDowncast & p;
// if we did downcast we store the true type as well // if we did downcast we store the true type as well
if(neededDowncast) if(neededDowncast)
(*this) << std::string(typeid(*ptr).name()); (*this) << demangle(typeid(*ptr).name());
shared_ptr2nr[reg_ptr] = shared_ptr_count++; shared_ptr2nr[reg_ptr] = shared_ptr_count++;
return *this; return *this;
} }
// if found store the position and if it has to be downcasted and how // if found store the position and if it has to be downcasted and how
(*this) << pos->second << neededDowncast; (*this) << pos->second << neededDowncast;
if(neededDowncast) if(neededDowncast)
(*this) << std::string(typeid(*ptr).name()); (*this) << demangle(typeid(*ptr).name());
return (*this); return (*this);
} }
else // Input else // Input
@ -261,12 +262,12 @@ namespace ngcore
void* reg_ptr = (void*)p; void* reg_ptr = (void*)p;
if(typeid(T) != typeid(*p)) if(typeid(T) != typeid(*p))
{ {
if(GetArchiveRegister().count(std::string(typeid(*p).name())) == 0) if(GetArchiveRegister().count(demangle(typeid(*p).name())) == 0)
throw std::runtime_error(std::string("Archive error: Polymorphic type ") throw std::runtime_error(std::string("Archive error: Polymorphic type ")
+ typeid(*p).name() + demangle(typeid(*p).name())
+ " not registered for archive"); + " not registered for archive");
else else
reg_ptr = GetArchiveRegister()[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); auto pos = ptr2nr.find(reg_ptr);
// if the pointer is not found in the map create a new entry // if the pointer is not found in the map create a new entry
@ -280,19 +281,19 @@ namespace ngcore
} }
else else
throw std::runtime_error(std::string("Archive error: Class ") + throw std::runtime_error(std::string("Archive error: Class ") +
typeid(*p).name() + " does not provide a default constructor!"); demangle(typeid(*p).name()) + " does not provide a default constructor!");
else else
{ {
// if a pointer to a base class is archived, the class hierarchy must be registered // if a pointer to a base class is archived, the class hierarchy must be registered
// to avoid compile time issues we allow this behaviour only for "our" classes that // to avoid compile time issues we allow this behaviour only for "our" classes that
// implement a void DoArchive(Archive&) member function // implement a void DoArchive(Archive&) member function
// To recreate the object we need to store the true type of it // To recreate the object we need to store the true type of it
if(GetArchiveRegister().count(std::string(typeid(*p).name())) == 0) if(GetArchiveRegister().count(demangle(typeid(*p).name())) == 0)
throw std::runtime_error(std::string("Archive error: Polymorphic type ") throw std::runtime_error(std::string("Archive error: Polymorphic type ")
+ typeid(*p).name() + demangle(typeid(*p).name())
+ " not registered for archive"); + " not registered for archive");
else else
return (*this) << -3 << std::string(typeid(*p).name()) & (*p); return (*this) << -3 << demangle(typeid(*p).name()) & (*p);
} }
} }
else else
@ -300,7 +301,7 @@ namespace ngcore
(*this) & pos->second; (*this) & pos->second;
bool downcasted = !(reg_ptr == (void*) p); bool downcasted = !(reg_ptr == (void*) p);
// store if the class has been downcasted and the name // store if the class has been downcasted and the name
(*this) << downcasted << std::string(typeid(*p).name()); (*this) << downcasted << demangle(typeid(*p).name());
} }
} }
else else
@ -373,7 +374,7 @@ namespace ngcore
{ return typeid(T) == ti ? p : Caster<T, Bases...>::tryUpcast(ti, (T*) p); }; { return typeid(T) == ti ? p : Caster<T, Bases...>::tryUpcast(ti, (T*) p); };
info.downcaster = [this](const std::type_info& ti, void* p) -> void* info.downcaster = [this](const std::type_info& ti, void* p) -> void*
{ return typeid(T) == ti ? p : Caster<T, Bases...>::tryDowncast(ti, p); }; { return typeid(T) == ti ? p : Caster<T, Bases...>::tryDowncast(ti, p); };
GetArchiveRegister()[std::string(typeid(T).name())] = info; GetArchiveRegister()[std::string(demangle(typeid(T).name()))] = info;
} }
}; };
@ -396,7 +397,7 @@ namespace ngcore
static void* tryUpcast(const std::type_info& ti, T* p) static void* tryUpcast(const std::type_info& ti, T* p)
{ {
try try
{ return GetArchiveRegister()[typeid(B1).name()].upcaster(ti, (void*) (dynamic_cast<B1*>(p))); } { return GetArchiveRegister()[demangle(typeid(B1).name())].upcaster(ti, (void*) (dynamic_cast<B1*>(p))); }
catch(std::exception) catch(std::exception)
{ return Caster<T, Brest...>::tryUpcast(ti, p); } { return Caster<T, Brest...>::tryUpcast(ti, p); }
} }
@ -406,7 +407,7 @@ namespace ngcore
if(typeid(B1) == ti) if(typeid(B1) == ti)
return dynamic_cast<T*>((B1*) p); return dynamic_cast<T*>((B1*) p);
try try
{ return GetArchiveRegister()[typeid(B1).name()].downcaster(ti, (void*) ((B1*)p)); } { return GetArchiveRegister()[demangle(typeid(B1).name())].downcaster(ti, (void*) ((B1*)p)); }
catch(std::exception) catch(std::exception)
{ return Caster<T, Brest...>::tryDowncast(ti, p); } { return Caster<T, Brest...>::tryDowncast(ti, p); }
} }