mirror of
https://github.com/NGSolve/netgen.git
synced 2024-12-25 13:30:34 +05:00
[ngcore] follow cpp guidelines, check them with clang-tidy
This commit is contained in:
parent
0dc04b661c
commit
17aba88117
@ -18,6 +18,7 @@ option( INSTALL_PROFILES "install environment variable settings to /etc/profile.
|
||||
option( USE_CCACHE "use ccache")
|
||||
option( USE_INTERNAL_TCL "Compile tcl files into the code and don't install them" ON)
|
||||
option( ENABLE_UNIT_TESTS "Enable Catch unit tests")
|
||||
option( ENABLE_CPP_CORE_GUIDELINES_CHECK "Enable cpp core guideline checks on ngcore" OFF)
|
||||
|
||||
option( USE_SUPERBUILD "use ccache" ON)
|
||||
|
||||
@ -349,6 +350,20 @@ endif(ENABLE_UNIT_TESTS)
|
||||
|
||||
#######################################################################
|
||||
|
||||
if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
||||
find_program(
|
||||
CLANG_TIDY_EXE
|
||||
NAMES "clang-tidy"
|
||||
DOC "Path to clang-tidy executable"
|
||||
)
|
||||
if(NOT CLANG_TIDY_EXE)
|
||||
message(WARNING "clang-tidy not found.")
|
||||
else()
|
||||
message(STATUS "clang-tidy found: ${CLANG_TIDY_EXE}")
|
||||
set(DO_CLANG_TIDY "${CLANG_TIDY_EXE}" "-checks=*,-clang-analyzer-alpha.*,-*braces-around-statements,-fuchsia-default-arguments")
|
||||
endif()
|
||||
endif(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
||||
|
||||
add_subdirectory(libsrc)
|
||||
add_subdirectory(ng)
|
||||
add_subdirectory(tutorials)
|
||||
|
@ -141,6 +141,7 @@ set_vars( NETGEN_CMAKE_ARGS
|
||||
CMAKE_PREFIX_PATH
|
||||
CMAKE_INSTALL_PREFIX
|
||||
ENABLE_UNIT_TESTS
|
||||
ENABLE_CPP_CORE_GUIDELINES_CHECK
|
||||
)
|
||||
|
||||
# propagate all variables set on the command line using cmake -DFOO=BAR
|
||||
|
@ -1,10 +1,14 @@
|
||||
add_library(ngcore basearchive.cpp)
|
||||
|
||||
add_library(ngcore archive.cpp version.cpp)
|
||||
|
||||
set_target_properties(ngcore PROPERTIES POSITION_INDEPENDENT_CODE ON )
|
||||
target_compile_definitions(ngcore PRIVATE -DNGCORE_EXPORTS)
|
||||
|
||||
install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen)
|
||||
|
||||
install(FILES ngcore.hpp archive.hpp basearchive.hpp version.hpp type_traits.hpp
|
||||
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel
|
||||
)
|
||||
install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp
|
||||
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel)
|
||||
|
||||
if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
||||
set_target_properties(ngcore PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
|
||||
endif(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
||||
|
57
libsrc/core/archive.cpp
Normal file
57
libsrc/core/archive.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
#include "archive.hpp"
|
||||
|
||||
#ifndef WIN32
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
void VersionInfo :: DoArchive(Archive& ar)
|
||||
{
|
||||
ar & mayor_ & minor_ & release & patch & git_hash;
|
||||
}
|
||||
|
||||
// clang-tidy should ignore this static object
|
||||
static std::map<std::string, VersionInfo> library_versions; // NOLINT
|
||||
std::map<std::string, VersionInfo>& Archive :: GetLibraryVersions()
|
||||
{
|
||||
return library_versions;
|
||||
}
|
||||
const VersionInfo& GetLibraryVersion(const std::string& library)
|
||||
{ return library_versions[library]; }
|
||||
|
||||
void SetLibraryVersion(const std::string& library, const VersionInfo& version)
|
||||
{ library_versions[library] = version; }
|
||||
|
||||
#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,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&status); }
|
||||
#endif
|
||||
|
||||
// clang-tidy should ignore this static object
|
||||
static std::unique_ptr<std::map<std::string, ClassArchiveInfo>> type_register; // NOLINT
|
||||
const ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname)
|
||||
{
|
||||
if(type_register == nullptr) type_register =
|
||||
std::make_unique<std::map<std::string, ClassArchiveInfo>>();
|
||||
return (*type_register)[classname];
|
||||
}
|
||||
void Archive :: SetArchiveRegister(const std::string& classname, const ClassArchiveInfo& info)
|
||||
{
|
||||
if(type_register == nullptr) type_register =
|
||||
std::make_unique<std::map<std::string, ClassArchiveInfo>>();
|
||||
(*type_register)[classname] = info;
|
||||
}
|
||||
bool Archive :: IsRegistered(const std::string& classname)
|
||||
{
|
||||
if(type_register == nullptr) type_register =
|
||||
std::make_unique<std::map<std::string, ClassArchiveInfo>>();
|
||||
return type_register->count(classname) != 0;
|
||||
}
|
||||
} // namespace ngcore
|
@ -1,8 +1,493 @@
|
||||
#ifndef NG_ARCHIVE_HPP
|
||||
#define NG_ARCHIVE_HPP
|
||||
#ifndef NETGEN_CORE_ARCHIVE_HPP
|
||||
#define NETGEN_CORE_ARCHIVE_HPP
|
||||
|
||||
#include <complex>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ngcore_api.hpp"
|
||||
#include "type_traits.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
// Libraries using this archive can store their version here to implement backwards compatibility
|
||||
const VersionInfo& GetLibraryVersion(const std::string& library);
|
||||
void SetLibraryVersion(const std::string& library, const VersionInfo& version);
|
||||
|
||||
class Archive;
|
||||
NGCORE_API std::string demangle(const char* typeinfo);
|
||||
|
||||
// create new pointer of type T if it is default constructible, else throw
|
||||
template<typename T>
|
||||
T* constructIfPossible_impl(...)
|
||||
{ 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>
|
||||
T* constructIfPossible_impl(int) { return new T; }
|
||||
|
||||
template<typename T>
|
||||
T* constructIfPossible() { return constructIfPossible_impl<T>(int{}); }
|
||||
|
||||
//Type trait to check if a class implements a 'void DoArchive(Archive&)' function
|
||||
template<typename T>
|
||||
struct has_DoArchive
|
||||
{
|
||||
private:
|
||||
template<typename T2>
|
||||
static constexpr auto check(T2*) ->
|
||||
typename std::is_same<decltype(std::declval<T2>().DoArchive(std::declval<Archive&>())),void>::type;
|
||||
template<typename>
|
||||
static constexpr std::false_type check(...);
|
||||
typedef decltype(check<T>(0)) type;
|
||||
public:
|
||||
NGCORE_API static constexpr bool value = type::value;
|
||||
};
|
||||
|
||||
// Check if class is archivable
|
||||
template<typename T>
|
||||
struct is_Archivable
|
||||
{
|
||||
private:
|
||||
template<typename T2>
|
||||
static constexpr auto check(T2*) ->
|
||||
typename std::is_same<decltype(std::declval<Archive>() & std::declval<T2&>()),Archive&>::type;
|
||||
template<typename>
|
||||
static constexpr std::false_type check(...);
|
||||
typedef decltype(check<T>(nullptr)) type;
|
||||
public:
|
||||
NGCORE_API 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
|
||||
// of the (base)class given by type_info
|
||||
std::function<void*(const std::type_info&)> creator;
|
||||
// This caster takes a void* pointer to the type stored in this info and casts it to a
|
||||
// void* pointer pointing to the (base)class type_info
|
||||
std::function<void*(const std::type_info&, void*)> upcaster;
|
||||
// This caster takes a void* pointer to the (base)class type_info and returns void* pointing
|
||||
// to the type stored in this info
|
||||
std::function<void*(const std::type_info&, void*)> downcaster;
|
||||
};
|
||||
|
||||
// Base Archive class
|
||||
class NGCORE_API Archive
|
||||
{
|
||||
bool is_output;
|
||||
// how many different shared_ptr/pointer have been (un)archived
|
||||
int shared_ptr_count, ptr_count;
|
||||
// maps for archived shared pointers and pointers
|
||||
std::map<void*, int> shared_ptr2nr, ptr2nr;
|
||||
// vectors for storing the unarchived (shared) pointers
|
||||
std::vector<std::shared_ptr<void>> nr2shared_ptr;
|
||||
std::vector<void*> nr2ptr;
|
||||
|
||||
// Helper class for up-/downcasting
|
||||
template<typename T, typename ... Bases>
|
||||
struct Caster
|
||||
{
|
||||
static void* tryUpcast(const std::type_info& ti, T* p);
|
||||
static void* tryDowncast(const std::type_info& ti, void* p);
|
||||
};
|
||||
template<typename T, typename ... Bases>
|
||||
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<type, bases...>
|
||||
static void SetArchiveRegister(const std::string& classname, const 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() { ; }
|
||||
|
||||
bool Output () { return is_output; }
|
||||
bool Input () { return !is_output; }
|
||||
virtual const VersionInfo& getVersion(const std::string& library) = 0;
|
||||
|
||||
// Pure virtual functions that have to be implemented by In-/OutArchive
|
||||
virtual Archive & operator & (double & d) = 0;
|
||||
virtual Archive & operator & (int & i) = 0;
|
||||
virtual Archive & operator & (long & i) = 0;
|
||||
virtual Archive & operator & (size_t & i) = 0;
|
||||
virtual Archive & operator & (short & i) = 0;
|
||||
virtual Archive & operator & (unsigned char & i) = 0;
|
||||
virtual Archive & operator & (bool & b) = 0;
|
||||
virtual Archive & operator & (std::string & str) = 0;
|
||||
virtual Archive & operator & (char *& str) = 0;
|
||||
|
||||
|
||||
// Archive std classes ================================================
|
||||
template<typename T>
|
||||
Archive& operator & (std::complex<T>& c)
|
||||
{
|
||||
if(is_output)
|
||||
(*this) << c.real() << c.imag();
|
||||
else
|
||||
{
|
||||
T tmp;
|
||||
(*this) & tmp;
|
||||
c.real(tmp);
|
||||
(*this) & tmp;
|
||||
c.imag(tmp);
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
template<typename T>
|
||||
Archive& operator & (std::vector<T>& v)
|
||||
{
|
||||
size_t size;
|
||||
if(is_output)
|
||||
size = v.size();
|
||||
(*this) & size;
|
||||
if(!is_output)
|
||||
v.resize(size);
|
||||
Do(&v[0], size);
|
||||
return (*this);
|
||||
}
|
||||
template<typename T1, typename T2>
|
||||
Archive& operator& (std::map<T1, T2>& map)
|
||||
{
|
||||
if(is_output)
|
||||
{
|
||||
(*this) << size_t(map.size());
|
||||
for(auto& pair : map)
|
||||
(*this) << pair.first << pair.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t size;
|
||||
(*this) & size;
|
||||
T1 key; T2 val;
|
||||
for(size_t i = 0; i < size; i++)
|
||||
{
|
||||
T1 key; T2 val;
|
||||
(*this) & key & val;
|
||||
map[key] = val;
|
||||
}
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
// Archive arrays =====================================================
|
||||
// this functions can be overloaded in Archive implementations for more efficiency
|
||||
template <typename T, typename = typename std::enable_if<is_Archivable<T>::value>::type>
|
||||
Archive & Do (T * data, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & data[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (double * d, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & d[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (int * i, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (long * i, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (size_t * i, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (short * i, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (unsigned char * i, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (bool * b, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & b[j]; }; return *this; };
|
||||
|
||||
// Archive a class implementing a (void DoArchive(Archive&)) method =======
|
||||
template<typename T, typename=std::enable_if_t<has_DoArchive<T>::value>>
|
||||
Archive& operator & (T& val)
|
||||
{
|
||||
val.DoArchive(*this); return *this;
|
||||
}
|
||||
|
||||
// Archive shared_ptrs =================================================
|
||||
template <typename T>
|
||||
Archive& operator & (std::shared_ptr<T>& ptr)
|
||||
{
|
||||
if(Output())
|
||||
{
|
||||
// save -2 for nullptr
|
||||
if(!ptr)
|
||||
return (*this) << -2;
|
||||
|
||||
void* reg_ptr = ptr.get();
|
||||
bool neededDowncast = false;
|
||||
// Downcasting is only possible for our registered classes
|
||||
if(typeid(T) != typeid(*ptr))
|
||||
{
|
||||
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());
|
||||
// if there was a true downcast we have to store more information
|
||||
if(reg_ptr != (void*) ptr.get())
|
||||
neededDowncast = true;
|
||||
}
|
||||
auto pos = shared_ptr2nr.find(reg_ptr);
|
||||
// if not found store -1 and the pointer
|
||||
if(pos == shared_ptr2nr.end())
|
||||
{
|
||||
auto p = ptr.get();
|
||||
(*this) << -1;
|
||||
(*this) & neededDowncast & p;
|
||||
// if we did downcast we store the true type as well
|
||||
if(neededDowncast)
|
||||
(*this) << demangle(typeid(*ptr).name());
|
||||
shared_ptr2nr[reg_ptr] = shared_ptr_count++;
|
||||
return *this;
|
||||
}
|
||||
// if found store the position and if it has to be downcasted and how
|
||||
(*this) << pos->second << neededDowncast;
|
||||
if(neededDowncast)
|
||||
(*this) << demangle(typeid(*ptr).name());
|
||||
return (*this);
|
||||
}
|
||||
else // Input
|
||||
{
|
||||
int nr;
|
||||
(*this) & nr;
|
||||
// -2 restores a nullptr
|
||||
if(nr == -2)
|
||||
{
|
||||
ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
// -1 restores a new shared ptr by restoring the inner pointer and creating a shared_ptr to it
|
||||
else if (nr == -1)
|
||||
{
|
||||
T* p;
|
||||
bool neededDowncast;
|
||||
(*this) & neededDowncast & p;
|
||||
ptr = std::shared_ptr<T>(p);
|
||||
// if we did downcast we need to store a shared_ptr<void> to the true object
|
||||
if(neededDowncast)
|
||||
{
|
||||
std::string name;
|
||||
(*this) & 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<void>(std::static_pointer_cast<void>(ptr),
|
||||
info.downcaster(typeid(T),
|
||||
ptr.get())));
|
||||
}
|
||||
else
|
||||
nr2shared_ptr.push_back(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto other = nr2shared_ptr[nr];
|
||||
bool neededDowncast;
|
||||
(*this) & neededDowncast;
|
||||
if(neededDowncast)
|
||||
{
|
||||
// if there was a downcast we can expect the class to be registered (since archiving
|
||||
// wouldn't have worked else)
|
||||
std::string name;
|
||||
(*this) & name;
|
||||
auto info = GetArchiveRegister(name);
|
||||
// same trick as above, create a shared ptr sharing lifetime with
|
||||
// the shared_ptr<void> in the register, but pointing to our object
|
||||
ptr = std::static_pointer_cast<T>(std::shared_ptr<void>(other,
|
||||
info.upcaster(typeid(T),
|
||||
other.get())));
|
||||
}
|
||||
else
|
||||
ptr = std::static_pointer_cast<T>(other);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Archive pointers =======================================================
|
||||
template <typename T>
|
||||
Archive & operator& (T *& p)
|
||||
{
|
||||
if (Output())
|
||||
{
|
||||
// if the pointer is null store -2
|
||||
if (!p)
|
||||
return (*this) << -2;
|
||||
void* reg_ptr = (void*)p;
|
||||
if(typeid(T) != typeid(*p))
|
||||
{
|
||||
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);
|
||||
}
|
||||
auto pos = ptr2nr.find(reg_ptr);
|
||||
// if the pointer is not found in the map create a new entry
|
||||
if (pos == ptr2nr.end())
|
||||
{
|
||||
ptr2nr[reg_ptr] = ptr_count++;
|
||||
if(typeid(*p) == typeid(T))
|
||||
if (std::is_constructible<T>::value)
|
||||
{
|
||||
return (*this) << -1 & (*p);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error(std::string("Archive error: Class ") +
|
||||
demangle(typeid(*p).name()) + " does not provide a default constructor!");
|
||||
else
|
||||
{
|
||||
// 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
|
||||
// implement a void DoArchive(Archive&) member function
|
||||
// To recreate the object we need to store the true type of it
|
||||
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
|
||||
return (*this) << -3 << demangle(typeid(*p).name()) & (*p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(*this) & pos->second;
|
||||
bool downcasted = !(reg_ptr == (void*) p);
|
||||
// store if the class has been downcasted and the name
|
||||
(*this) << downcasted << demangle(typeid(*p).name());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int nr;
|
||||
(*this) & nr;
|
||||
if (nr == -2) // restore a nullptr
|
||||
p = nullptr;
|
||||
else if (nr == -1) // create a new pointer of standard type (no virtual or multiple inheritance,...)
|
||||
{
|
||||
p = constructIfPossible<T>();
|
||||
nr2ptr.push_back(p);
|
||||
(*this) & *p;
|
||||
}
|
||||
else if(nr == -3) // restore one of our registered classes that can have multiple inheritance,...
|
||||
{
|
||||
// As stated above, we want this special behaviour only for our classes that implement DoArchive
|
||||
std::string name;
|
||||
(*this) & 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));
|
||||
// we store the downcasted pointer (to be able to find it again from
|
||||
// another class in a multiple inheritance tree)
|
||||
nr2ptr.push_back(info.downcaster(typeid(T),p));
|
||||
(*this) & *p;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool downcasted;
|
||||
std::string name;
|
||||
(*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]);
|
||||
}
|
||||
else
|
||||
p = (T*) nr2ptr[nr];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// const ptr
|
||||
template<typename T>
|
||||
Archive& operator &(const T*& t)
|
||||
{
|
||||
return (*this) & const_cast<T*&>(t);
|
||||
}
|
||||
|
||||
// Write a read only variable
|
||||
template <typename T>
|
||||
Archive & operator << (const T & t)
|
||||
{
|
||||
T ht(t);
|
||||
(*this) & ht;
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual void FlushBuffer() {}
|
||||
|
||||
protected:
|
||||
static std::map<std::string, VersionInfo>& GetLibraryVersions();
|
||||
private:
|
||||
template<typename T>
|
||||
struct Caster<T>
|
||||
{
|
||||
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<typename T, typename B1, typename ... Brest>
|
||||
struct Caster<T,B1,Brest...>
|
||||
{
|
||||
static void* tryUpcast(const std::type_info& ti, T* p)
|
||||
{
|
||||
try
|
||||
{ return GetArchiveRegister(demangle(typeid(B1).name())).upcaster(ti, (void*) (dynamic_cast<B1*>(p))); }
|
||||
catch(std::exception)
|
||||
{ return Caster<T, Brest...>::tryUpcast(ti, p); }
|
||||
}
|
||||
|
||||
static void* tryDowncast(const std::type_info& ti, void* p)
|
||||
{
|
||||
if(typeid(B1) == ti)
|
||||
return dynamic_cast<T*>((B1*) p);
|
||||
try
|
||||
{ return GetArchiveRegister(demangle(typeid(B1).name())).downcaster(ti, (void*) ((B1*)p)); }
|
||||
catch(std::exception)
|
||||
{ return Caster<T, Brest...>::tryDowncast(ti, p); }
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T, typename ... Bases>
|
||||
class NGCORE_API RegisterClassForArchive
|
||||
{
|
||||
public:
|
||||
RegisterClassForArchive()
|
||||
{
|
||||
static_assert(all_of_tmpl<std::is_base_of<Bases,T>::value...>,
|
||||
"Variadic template arguments must be base classes of T");
|
||||
ClassArchiveInfo info;
|
||||
info.creator = [this,&info](const std::type_info& ti) -> void*
|
||||
{ return typeid(T) == ti ? constructIfPossible<T>()
|
||||
: Archive::Caster<T, Bases...>::tryUpcast(ti, constructIfPossible<T>()); };
|
||||
info.upcaster = [this](const std::type_info& ti, void* p) -> void*
|
||||
{ return typeid(T) == ti ? p : Archive::Caster<T, Bases...>::tryUpcast(ti, (T*) p); };
|
||||
info.downcaster = [this](const std::type_info& ti, void* p) -> void*
|
||||
{ return typeid(T) == ti ? p : Archive::Caster<T, Bases...>::tryDowncast(ti, p); };
|
||||
Archive::SetArchiveRegister(std::string(demangle(typeid(T).name())),info);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
// BinaryOutArchive ======================================================================
|
||||
class NGCORE_API BinaryOutArchive : public Archive
|
||||
{
|
||||
@ -159,7 +644,7 @@ namespace ngcore
|
||||
(*this) & GetLibraryVersions();
|
||||
}
|
||||
TextOutArchive (std::string filename) :
|
||||
TextOutArchive(std::make_shared<std::ofstream>(filename.c_str())) { }
|
||||
TextOutArchive(std::make_shared<std::ofstream>(filename)) { }
|
||||
|
||||
const VersionInfo& getVersion(const std::string& library)
|
||||
{ return GetLibraryVersions()[library]; }
|
||||
@ -265,5 +750,6 @@ namespace ngcore
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif // NG_ARCHIVE_HPP
|
||||
} // namespace ngcore
|
||||
|
||||
#endif // NETGEN_CORE_ARCHIVE_HPP
|
||||
|
@ -1,44 +0,0 @@
|
||||
|
||||
#include "ngcore.hpp"
|
||||
|
||||
#ifndef WIN
|
||||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
static std::map<std::string, VersionInfo> library_versions;
|
||||
std::map<std::string, VersionInfo>& Archive :: GetLibraryVersions()
|
||||
{
|
||||
return library_versions;
|
||||
}
|
||||
VersionInfo GetLibraryVersion(const std::string& library)
|
||||
{ return library_versions[library]; }
|
||||
|
||||
void SetLibraryVersion(const std::string& library, VersionInfo version)
|
||||
{ library_versions[library] = version; }
|
||||
|
||||
#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
|
||||
|
||||
static std::map<std::string, ClassArchiveInfo>* type_register;
|
||||
const ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname)
|
||||
{
|
||||
if(!type_register) type_register = new std::map<std::string, ClassArchiveInfo>();
|
||||
return (*type_register)[classname];
|
||||
}
|
||||
void Archive :: SetArchiveRegister(const std::string& classname, ClassArchiveInfo info)
|
||||
{
|
||||
if(!type_register) type_register = new std::map<std::string, ClassArchiveInfo>();
|
||||
(*type_register)[classname] = info;
|
||||
}
|
||||
bool Archive :: IsRegistered(const std::string& classname)
|
||||
{
|
||||
if(!type_register) type_register = new std::map<std::string, ClassArchiveInfo>();
|
||||
return type_register->count(classname) != 0;
|
||||
}
|
||||
}
|
@ -1,480 +0,0 @@
|
||||
#ifndef NG_BASEARCHIVE_HPP
|
||||
#define NG_BASEARCHIVE_HPP
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
class VersionInfo;
|
||||
// Libraries using this archive can store their version here to implement backwards compatibility
|
||||
VersionInfo GetLibraryVersion(const std::string& library);
|
||||
void SetLibraryVersion(const std::string& library, VersionInfo version);
|
||||
|
||||
class Archive;
|
||||
NGCORE_API std::string demangle(const char* typeinfo);
|
||||
|
||||
// create new pointer of type T if it is default constructible, else throw
|
||||
template<typename T>
|
||||
T* constructIfPossible_impl(...)
|
||||
{ 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>
|
||||
T* constructIfPossible_impl(int) { return new T; }
|
||||
|
||||
template<typename T>
|
||||
T* constructIfPossible() { return constructIfPossible_impl<T>(int{}); }
|
||||
|
||||
//Type trait to check if a class implements a 'void DoArchive(Archive&)' function
|
||||
template<typename T>
|
||||
struct has_DoArchive
|
||||
{
|
||||
private:
|
||||
template<typename T2>
|
||||
static constexpr auto check(T2*) ->
|
||||
typename std::is_same<decltype(std::declval<T2>().DoArchive(std::declval<Archive&>())),void>::type;
|
||||
template<typename>
|
||||
static constexpr std::false_type check(...);
|
||||
typedef decltype(check<T>(0)) type;
|
||||
public:
|
||||
NGCORE_API static constexpr bool value = type::value;
|
||||
};
|
||||
|
||||
// Check if class is archivable
|
||||
template<typename T>
|
||||
struct is_Archivable
|
||||
{
|
||||
private:
|
||||
template<typename T2>
|
||||
static constexpr auto check(T2*) ->
|
||||
typename std::is_same<decltype(std::declval<Archive>() & std::declval<T2&>()),Archive&>::type;
|
||||
template<typename>
|
||||
static constexpr std::false_type check(...);
|
||||
typedef decltype(check<T>(nullptr)) type;
|
||||
public:
|
||||
NGCORE_API 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
|
||||
// of the (base)class given by type_info
|
||||
std::function<void*(const std::type_info&)> creator;
|
||||
// This caster takes a void* pointer to the type stored in this info and casts it to a
|
||||
// void* pointer pointing to the (base)class type_info
|
||||
std::function<void*(const std::type_info&, void*)> upcaster;
|
||||
// This caster takes a void* pointer to the (base)class type_info and returns void* pointing
|
||||
// to the type stored in this info
|
||||
std::function<void*(const std::type_info&, void*)> downcaster;
|
||||
};
|
||||
|
||||
// Base Archive class
|
||||
class NGCORE_API Archive
|
||||
{
|
||||
bool is_output;
|
||||
// how many different shared_ptr/pointer have been (un)archived
|
||||
int shared_ptr_count, ptr_count;
|
||||
// maps for archived shared pointers and pointers
|
||||
std::map<void*, int> shared_ptr2nr, ptr2nr;
|
||||
// vectors for storing the unarchived (shared) pointers
|
||||
std::vector<std::shared_ptr<void>> nr2shared_ptr;
|
||||
std::vector<void*> nr2ptr;
|
||||
|
||||
// Helper class for up-/downcasting
|
||||
template<typename T, typename ... Bases>
|
||||
struct Caster
|
||||
{
|
||||
static void* tryUpcast(const std::type_info& ti, T* p);
|
||||
static void* tryDowncast(const std::type_info& ti, void* p);
|
||||
};
|
||||
template<typename T, typename ... Bases>
|
||||
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<type, bases...>
|
||||
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() { ; }
|
||||
|
||||
bool Output () { return is_output; }
|
||||
bool Input () { return !is_output; }
|
||||
virtual const VersionInfo& getVersion(const std::string& library) = 0;
|
||||
|
||||
// Pure virtual functions that have to be implemented by In-/OutArchive
|
||||
virtual Archive & operator & (double & d) = 0;
|
||||
virtual Archive & operator & (int & i) = 0;
|
||||
virtual Archive & operator & (long & i) = 0;
|
||||
virtual Archive & operator & (size_t & i) = 0;
|
||||
virtual Archive & operator & (short & i) = 0;
|
||||
virtual Archive & operator & (unsigned char & i) = 0;
|
||||
virtual Archive & operator & (bool & b) = 0;
|
||||
virtual Archive & operator & (std::string & str) = 0;
|
||||
virtual Archive & operator & (char *& str) = 0;
|
||||
|
||||
|
||||
// Archive std classes ================================================
|
||||
template<typename T>
|
||||
Archive& operator & (std::complex<T>& c)
|
||||
{
|
||||
if(is_output)
|
||||
(*this) << c.real() << c.imag();
|
||||
else
|
||||
{
|
||||
T tmp;
|
||||
(*this) & tmp;
|
||||
c.real(tmp);
|
||||
(*this) & tmp;
|
||||
c.imag(tmp);
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
template<typename T>
|
||||
Archive& operator & (std::vector<T>& v)
|
||||
{
|
||||
size_t size;
|
||||
if(is_output)
|
||||
size = v.size();
|
||||
(*this) & size;
|
||||
if(!is_output)
|
||||
v.resize(size);
|
||||
Do(&v[0], size);
|
||||
return (*this);
|
||||
}
|
||||
template<typename T1, typename T2>
|
||||
Archive& operator& (std::map<T1, T2>& map)
|
||||
{
|
||||
if(is_output)
|
||||
{
|
||||
(*this) << size_t(map.size());
|
||||
for(auto& pair : map)
|
||||
(*this) << pair.first << pair.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t size;
|
||||
(*this) & size;
|
||||
T1 key; T2 val;
|
||||
for(size_t i = 0; i < size; i++)
|
||||
{
|
||||
T1 key; T2 val;
|
||||
(*this) & key & val;
|
||||
map[key] = val;
|
||||
}
|
||||
}
|
||||
return (*this);
|
||||
}
|
||||
// Archive arrays =====================================================
|
||||
// this functions can be overloaded in Archive implementations for more efficiency
|
||||
template <typename T, typename = typename std::enable_if<is_Archivable<T>::value>::type>
|
||||
Archive & Do (T * data, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & data[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (double * d, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & d[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (int * i, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (long * i, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (size_t * i, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (short * i, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (unsigned char * i, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; };
|
||||
|
||||
virtual Archive & Do (bool * b, size_t n)
|
||||
{ for (size_t j = 0; j < n; j++) { (*this) & b[j]; }; return *this; };
|
||||
|
||||
// Archive a class implementing a (void DoArchive(Archive&)) method =======
|
||||
template<typename T, typename=std::enable_if_t<has_DoArchive<T>::value>>
|
||||
Archive& operator & (T& val)
|
||||
{
|
||||
val.DoArchive(*this); return *this;
|
||||
}
|
||||
|
||||
// Archive shared_ptrs =================================================
|
||||
template <typename T>
|
||||
Archive& operator & (std::shared_ptr<T>& ptr)
|
||||
{
|
||||
if(Output())
|
||||
{
|
||||
// save -2 for nullptr
|
||||
if(!ptr)
|
||||
return (*this) << -2;
|
||||
|
||||
void* reg_ptr = ptr.get();
|
||||
bool neededDowncast = false;
|
||||
// Downcasting is only possible for our registered classes
|
||||
if(typeid(T) != typeid(*ptr))
|
||||
{
|
||||
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());
|
||||
// if there was a true downcast we have to store more information
|
||||
if(reg_ptr != (void*) ptr.get())
|
||||
neededDowncast = true;
|
||||
}
|
||||
auto pos = shared_ptr2nr.find(reg_ptr);
|
||||
// if not found store -1 and the pointer
|
||||
if(pos == shared_ptr2nr.end())
|
||||
{
|
||||
auto p = ptr.get();
|
||||
(*this) << -1;
|
||||
(*this) & neededDowncast & p;
|
||||
// if we did downcast we store the true type as well
|
||||
if(neededDowncast)
|
||||
(*this) << demangle(typeid(*ptr).name());
|
||||
shared_ptr2nr[reg_ptr] = shared_ptr_count++;
|
||||
return *this;
|
||||
}
|
||||
// if found store the position and if it has to be downcasted and how
|
||||
(*this) << pos->second << neededDowncast;
|
||||
if(neededDowncast)
|
||||
(*this) << demangle(typeid(*ptr).name());
|
||||
return (*this);
|
||||
}
|
||||
else // Input
|
||||
{
|
||||
int nr;
|
||||
(*this) & nr;
|
||||
// -2 restores a nullptr
|
||||
if(nr == -2)
|
||||
{
|
||||
ptr = nullptr;
|
||||
return *this;
|
||||
}
|
||||
// -1 restores a new shared ptr by restoring the inner pointer and creating a shared_ptr to it
|
||||
else if (nr == -1)
|
||||
{
|
||||
T* p;
|
||||
bool neededDowncast;
|
||||
(*this) & neededDowncast & p;
|
||||
ptr = std::shared_ptr<T>(p);
|
||||
// if we did downcast we need to store a shared_ptr<void> to the true object
|
||||
if(neededDowncast)
|
||||
{
|
||||
std::string name;
|
||||
(*this) & 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<void>(std::static_pointer_cast<void>(ptr),
|
||||
info.downcaster(typeid(T),
|
||||
ptr.get())));
|
||||
}
|
||||
else
|
||||
nr2shared_ptr.push_back(ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto other = nr2shared_ptr[nr];
|
||||
bool neededDowncast;
|
||||
(*this) & neededDowncast;
|
||||
if(neededDowncast)
|
||||
{
|
||||
// if there was a downcast we can expect the class to be registered (since archiving
|
||||
// wouldn't have worked else)
|
||||
std::string name;
|
||||
(*this) & name;
|
||||
auto info = GetArchiveRegister(name);
|
||||
// same trick as above, create a shared ptr sharing lifetime with
|
||||
// the shared_ptr<void> in the register, but pointing to our object
|
||||
ptr = std::static_pointer_cast<T>(std::shared_ptr<void>(other,
|
||||
info.upcaster(typeid(T),
|
||||
other.get())));
|
||||
}
|
||||
else
|
||||
ptr = std::static_pointer_cast<T>(other);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Archive pointers =======================================================
|
||||
template <typename T>
|
||||
Archive & operator& (T *& p)
|
||||
{
|
||||
if (Output())
|
||||
{
|
||||
// if the pointer is null store -2
|
||||
if (!p)
|
||||
return (*this) << -2;
|
||||
void* reg_ptr = (void*)p;
|
||||
if(typeid(T) != typeid(*p))
|
||||
{
|
||||
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);
|
||||
}
|
||||
auto pos = ptr2nr.find(reg_ptr);
|
||||
// if the pointer is not found in the map create a new entry
|
||||
if (pos == ptr2nr.end())
|
||||
{
|
||||
ptr2nr[reg_ptr] = ptr_count++;
|
||||
if(typeid(*p) == typeid(T))
|
||||
if (std::is_constructible<T>::value)
|
||||
{
|
||||
return (*this) << -1 & (*p);
|
||||
}
|
||||
else
|
||||
throw std::runtime_error(std::string("Archive error: Class ") +
|
||||
demangle(typeid(*p).name()) + " does not provide a default constructor!");
|
||||
else
|
||||
{
|
||||
// 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
|
||||
// implement a void DoArchive(Archive&) member function
|
||||
// To recreate the object we need to store the true type of it
|
||||
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
|
||||
return (*this) << -3 << demangle(typeid(*p).name()) & (*p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(*this) & pos->second;
|
||||
bool downcasted = !(reg_ptr == (void*) p);
|
||||
// store if the class has been downcasted and the name
|
||||
(*this) << downcasted << demangle(typeid(*p).name());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int nr;
|
||||
(*this) & nr;
|
||||
if (nr == -2) // restore a nullptr
|
||||
p = nullptr;
|
||||
else if (nr == -1) // create a new pointer of standard type (no virtual or multiple inheritance,...)
|
||||
{
|
||||
p = constructIfPossible<T>();
|
||||
nr2ptr.push_back(p);
|
||||
(*this) & *p;
|
||||
}
|
||||
else if(nr == -3) // restore one of our registered classes that can have multiple inheritance,...
|
||||
{
|
||||
// As stated above, we want this special behaviour only for our classes that implement DoArchive
|
||||
std::string name;
|
||||
(*this) & 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));
|
||||
// we store the downcasted pointer (to be able to find it again from
|
||||
// another class in a multiple inheritance tree)
|
||||
nr2ptr.push_back(info.downcaster(typeid(T),p));
|
||||
(*this) & *p;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool downcasted;
|
||||
std::string name;
|
||||
(*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]);
|
||||
}
|
||||
else
|
||||
p = (T*) nr2ptr[nr];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// const ptr
|
||||
template<typename T>
|
||||
Archive& operator &(const T*& t)
|
||||
{
|
||||
return (*this) & const_cast<T*&>(t);
|
||||
}
|
||||
|
||||
// Write a read only variable
|
||||
template <typename T>
|
||||
Archive & operator << (const T & t)
|
||||
{
|
||||
T ht(t);
|
||||
(*this) & ht;
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual void FlushBuffer() {}
|
||||
|
||||
protected:
|
||||
static std::map<std::string, VersionInfo>& GetLibraryVersions();
|
||||
private:
|
||||
template<typename T>
|
||||
struct Caster<T>
|
||||
{
|
||||
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<typename T, typename B1, typename ... Brest>
|
||||
struct Caster<T,B1,Brest...>
|
||||
{
|
||||
static void* tryUpcast(const std::type_info& ti, T* p)
|
||||
{
|
||||
try
|
||||
{ return GetArchiveRegister(demangle(typeid(B1).name())).upcaster(ti, (void*) (dynamic_cast<B1*>(p))); }
|
||||
catch(std::exception)
|
||||
{ return Caster<T, Brest...>::tryUpcast(ti, p); }
|
||||
}
|
||||
|
||||
static void* tryDowncast(const std::type_info& ti, void* p)
|
||||
{
|
||||
if(typeid(B1) == ti)
|
||||
return dynamic_cast<T*>((B1*) p);
|
||||
try
|
||||
{ return GetArchiveRegister(demangle(typeid(B1).name())).downcaster(ti, (void*) ((B1*)p)); }
|
||||
catch(std::exception)
|
||||
{ return Caster<T, Brest...>::tryDowncast(ti, p); }
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T, typename ... Bases>
|
||||
class NGCORE_API RegisterClassForArchive
|
||||
{
|
||||
public:
|
||||
RegisterClassForArchive()
|
||||
{
|
||||
static_assert(all_of_tmpl<std::is_base_of<Bases,T>::value...>,
|
||||
"Variadic template arguments must be base classes of T");
|
||||
ClassArchiveInfo info;
|
||||
info.creator = [this,&info](const std::type_info& ti) -> void*
|
||||
{ return typeid(T) == ti ? constructIfPossible<T>()
|
||||
: Archive::Caster<T, Bases...>::tryUpcast(ti, constructIfPossible<T>()); };
|
||||
info.upcaster = [this](const std::type_info& ti, void* p) -> void*
|
||||
{ return typeid(T) == ti ? p : Archive::Caster<T, Bases...>::tryUpcast(ti, (T*) p); };
|
||||
info.downcaster = [this](const std::type_info& ti, void* p) -> void*
|
||||
{ return typeid(T) == ti ? p : Archive::Caster<T, Bases...>::tryDowncast(ti, p); };
|
||||
Archive::SetArchiveRegister(std::string(demangle(typeid(T).name())),info);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // NG_BASEARCHIVE_HPP
|
@ -1,49 +1,7 @@
|
||||
#ifndef NG_CORE_HPP
|
||||
#define NG_CORE_HPP
|
||||
#ifndef NETGEN_CORE_NGCORE_HPP
|
||||
#define NETGEN_CORE_NGCORE_HPP
|
||||
|
||||
// std includes
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
#include <complex>
|
||||
|
||||
#ifdef WIN32
|
||||
#define NGCORE_API_EXPORT __declspec(dllexport)
|
||||
#define NGCORE_API_IMPORT __declspec(dllimport)
|
||||
#else
|
||||
#define NGCORE_API_EXPORT
|
||||
#define NGCORE_API_IMPORT
|
||||
#endif
|
||||
|
||||
#ifdef NGCORE_EXPORTS
|
||||
#define NGCORE_API NGCORE_API_EXPORT
|
||||
#else
|
||||
#define NGCORE_API NGCORE_API_IMPORT
|
||||
#endif
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
#if defined(__GNUC__)
|
||||
inline bool likely (bool x) { return __builtin_expect((x), true); }
|
||||
inline bool unlikely (bool x) { return __builtin_expect((x), false); }
|
||||
#else
|
||||
inline bool likely (bool x) { return x; }
|
||||
inline bool unlikely (bool x) { return x; }
|
||||
#endif
|
||||
}
|
||||
|
||||
// own includes
|
||||
#include "type_traits.hpp"
|
||||
#include "basearchive.hpp"
|
||||
#include "version.hpp"
|
||||
#include "archive.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
#endif // NG_CORE_HPP
|
||||
#endif // NETGEN_CORE_NGCORE_HPP
|
||||
|
29
libsrc/core/ngcore_api.hpp
Normal file
29
libsrc/core/ngcore_api.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef NETGEN_CORE_NGCORE_API_HPP
|
||||
#define NETGEN_CORE_NGCORE_API_HPP
|
||||
|
||||
#ifdef WIN32
|
||||
#define NGCORE_API_EXPORT __declspec(dllexport)
|
||||
#define NGCORE_API_IMPORT __declspec(dllimport)
|
||||
#else
|
||||
#define NGCORE_API_EXPORT
|
||||
#define NGCORE_API_IMPORT
|
||||
#endif
|
||||
|
||||
#ifdef NGCORE_EXPORTS
|
||||
#define NGCORE_API NGCORE_API_EXPORT
|
||||
#else
|
||||
#define NGCORE_API NGCORE_API_IMPORT
|
||||
#endif
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
#if defined(__GNUC__)
|
||||
inline bool likely (bool x) { return bool(__builtin_expect(long(x), 1L)); }
|
||||
inline bool unlikely (bool x) { return bool(__builtin_expect(long(x), 0L)); }
|
||||
#else
|
||||
inline bool likely (bool x) { return x; }
|
||||
inline bool unlikely (bool x) { return x; }
|
||||
#endif
|
||||
} // namespace ngcore
|
||||
|
||||
#endif // NETGEN_CORE_NGCORE_API_HPP
|
@ -1,11 +1,13 @@
|
||||
#ifndef NGS_TYPE_TRAITS_HPP
|
||||
#define NGS_TYPE_TRAITS_HPP
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
template<bool... b> struct _BoolArray{};
|
||||
template<bool ... vals>
|
||||
constexpr bool all_of_tmpl = std::is_same<_BoolArray<vals...>, _BoolArray<(vals || true)...>>::value;
|
||||
}
|
||||
} // namespace ngcore
|
||||
|
||||
#endif // NGS_TYPE_TRAITS_HPP
|
||||
|
11
libsrc/core/version.cpp
Normal file
11
libsrc/core/version.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
#include "archive.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
void VersionInfo :: DoArchive(Archive& ar)
|
||||
{
|
||||
ar & mayor_ & minor_ & release & patch & git_hash;
|
||||
}
|
||||
} // namespace ngcore
|
@ -1,8 +1,13 @@
|
||||
#ifndef NGS_VERSION_HPP
|
||||
#define NGS_VERSION_HPP
|
||||
#ifndef NETGEN_CORE_VERSION_HPP
|
||||
#define NETGEN_CORE_VERSION_HPP
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include "ngcore_api.hpp"
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
class Archive;
|
||||
class VersionInfo
|
||||
{
|
||||
private:
|
||||
@ -78,10 +83,8 @@ namespace ngcore
|
||||
bool operator <=(const VersionInfo& other) const { return !((*this) > other); }
|
||||
bool operator >=(const VersionInfo& other) const { return !((*this) < other); }
|
||||
|
||||
void DoArchive(Archive& ar)
|
||||
{
|
||||
ar & mayor_ & minor_ & release & patch & git_hash;
|
||||
}
|
||||
void DoArchive(Archive& ar);
|
||||
};
|
||||
}
|
||||
#endif // NGS_VERSION_HPP
|
||||
} // namespace ngcore
|
||||
|
||||
#endif // NETGEN_CORE_VERSION_HPP
|
||||
|
@ -28,4 +28,10 @@ endmacro()
|
||||
|
||||
add_unit_test(archive archive.cpp)
|
||||
add_unit_test(version version.cpp)
|
||||
|
||||
if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
||||
set_target_properties(test_archive PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
|
||||
set_target_properties(test_version PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
|
||||
endif(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
||||
|
||||
endif(ENABLE_UNIT_TESTS)
|
||||
|
Loading…
Reference in New Issue
Block a user