mirror of
https://github.com/NGSolve/netgen.git
synced 2025-01-27 13:20:34 +05:00
archive works for pointers and shared_ptrs (even with
mult. inheritance and virtual base classes)
This commit is contained in:
parent
7bfc48e8f3
commit
8e29d38fc1
@ -17,6 +17,7 @@ option( INTEL_MIC "cross compile for intel xeon phi")
|
|||||||
option( INSTALL_PROFILES "install environment variable settings to /etc/profile.d" OFF )
|
option( INSTALL_PROFILES "install environment variable settings to /etc/profile.d" OFF )
|
||||||
option( USE_CCACHE "use ccache")
|
option( USE_CCACHE "use ccache")
|
||||||
option( USE_INTERNAL_TCL "Compile tcl files into the code and don't install them" ON)
|
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( USE_SUPERBUILD "use ccache" ON)
|
option( USE_SUPERBUILD "use ccache" ON)
|
||||||
|
|
||||||
@ -341,6 +342,11 @@ execute_process(COMMAND hdiutil create -volname Netgen -srcfolder ${CMAKE_INSTAL
|
|||||||
enable_testing()
|
enable_testing()
|
||||||
include(CTest)
|
include(CTest)
|
||||||
|
|
||||||
|
if(ENABLE_UNIT_TESTS)
|
||||||
|
include(${CMAKE_CURRENT_LIST_DIR}/cmake/external_projects/catch.cmake)
|
||||||
|
endif(ENABLE_UNIT_TESTS)
|
||||||
|
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
|
|
||||||
add_subdirectory(libsrc)
|
add_subdirectory(libsrc)
|
||||||
|
@ -140,6 +140,7 @@ set_vars( NETGEN_CMAKE_ARGS
|
|||||||
INTEL_MIC
|
INTEL_MIC
|
||||||
CMAKE_PREFIX_PATH
|
CMAKE_PREFIX_PATH
|
||||||
CMAKE_INSTALL_PREFIX
|
CMAKE_INSTALL_PREFIX
|
||||||
|
ENABLE_UNIT_TESTS
|
||||||
)
|
)
|
||||||
|
|
||||||
# propagate all variables set on the command line using cmake -DFOO=BAR
|
# propagate all variables set on the command line using cmake -DFOO=BAR
|
||||||
|
18
cmake/external_projects/catch.cmake
Normal file
18
cmake/external_projects/catch.cmake
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
include (ExternalProject)
|
||||||
|
find_program(GIT_EXECUTABLE git)
|
||||||
|
ExternalProject_Add(
|
||||||
|
project_catch
|
||||||
|
PREFIX ${CMAKE_BINARY_DIR}/catch
|
||||||
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
||||||
|
GIT_TAG v2.0.1
|
||||||
|
TIMEOUT 10
|
||||||
|
UPDATE_COMMAND "" # ${GIT_EXECUTABLE} pull
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
LOG_DOWNLOAD ON
|
||||||
|
)
|
||||||
|
|
||||||
|
# Expose required variable (CATCH_INCLUDE_DIR) to parent scope
|
||||||
|
ExternalProject_Get_Property(project_catch source_dir)
|
||||||
|
set(CATCH_INCLUDE_DIR ${source_dir}/single_include CACHE INTERNAL "Path to include folder for Catch")
|
@ -1,8 +1,10 @@
|
|||||||
add_definitions(-DNGINTERFACE_EXPORTS)
|
add_definitions(-DNGINTERFACE_EXPORTS)
|
||||||
add_library(ngcore OBJECT basearchive.cpp)
|
add_library(ngcore basearchive.cpp)
|
||||||
|
|
||||||
set_target_properties(ngcore PROPERTIES POSITION_INDEPENDENT_CODE ON )
|
set_target_properties(ngcore PROPERTIES POSITION_INDEPENDENT_CODE ON )
|
||||||
|
|
||||||
|
install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen)
|
||||||
|
|
||||||
install(FILES ngcore.hpp archive.hpp basearchive.hpp
|
install(FILES ngcore.hpp archive.hpp basearchive.hpp
|
||||||
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel
|
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel
|
||||||
)
|
)
|
||||||
|
@ -16,6 +16,7 @@ namespace ngcore
|
|||||||
: BinaryOutArchive(std::make_shared<std::ofstream>(filename)) {}
|
: BinaryOutArchive(std::make_shared<std::ofstream>(filename)) {}
|
||||||
virtual ~BinaryOutArchive () { FlushBuffer(); }
|
virtual ~BinaryOutArchive () { FlushBuffer(); }
|
||||||
|
|
||||||
|
using Archive::operator&;
|
||||||
virtual Archive & operator & (double & d)
|
virtual Archive & operator & (double & d)
|
||||||
{ return Write(d); }
|
{ return Write(d); }
|
||||||
virtual Archive & operator & (int & i)
|
virtual Archive & operator & (int & i)
|
||||||
@ -81,6 +82,7 @@ namespace ngcore
|
|||||||
BinaryInArchive (std::string filename)
|
BinaryInArchive (std::string filename)
|
||||||
: BinaryInArchive(std::make_shared<std::ifstream>(filename)) {}
|
: BinaryInArchive(std::make_shared<std::ifstream>(filename)) {}
|
||||||
|
|
||||||
|
using Archive::operator&;
|
||||||
virtual Archive & operator & (double & d)
|
virtual Archive & operator & (double & d)
|
||||||
{ Read(d); return *this; }
|
{ Read(d); return *this; }
|
||||||
virtual Archive & operator & (int & i)
|
virtual Archive & operator & (int & i)
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
namespace ngcore
|
namespace ngcore
|
||||||
{
|
{
|
||||||
std::map<std::string, std::function<void*()>>& GetArchiveRegister()
|
std::map<std::string, ClassArchiveInfo>& GetArchiveRegister()
|
||||||
{
|
{
|
||||||
static std::map<std::string, std::function<void*()>> type_register = {};
|
static std::map<std::string, ClassArchiveInfo> type_register;
|
||||||
return type_register;
|
return type_register;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,31 @@ namespace ngcore
|
|||||||
static constexpr bool value = type::value;
|
static constexpr bool value = type::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::map<std::string, std::function<void*()>>& GetArchiveRegister();
|
// Info stored by registering a class using the RegisterClassForArchive struct in the map
|
||||||
|
// stored in GetArchiveRegister
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns a map of from the mangled typeids to the ClassArchiveInfo
|
||||||
|
std::map<std::string, ClassArchiveInfo>& GetArchiveRegister();
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
};
|
||||||
|
|
||||||
// Base Archive class
|
// Base Archive class
|
||||||
class Archive
|
class Archive
|
||||||
@ -76,11 +100,12 @@ namespace ngcore
|
|||||||
size = v.size();
|
size = v.size();
|
||||||
(*this) & size;
|
(*this) & size;
|
||||||
if(!is_output)
|
if(!is_output)
|
||||||
v.reserve(size);
|
v.resize(size);
|
||||||
Do(&v[0], size);
|
Do(&v[0], size);
|
||||||
return (*this);
|
return (*this);
|
||||||
}
|
}
|
||||||
// Archive arrays =====================================================
|
// Archive arrays =====================================================
|
||||||
|
// this functions can be overloaded in Archive implementations for more efficiency
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Archive & Do (T * data, size_t n)
|
Archive & Do (T * data, size_t n)
|
||||||
{ for (size_t j = 0; j < n; j++) { (*this) & data[j]; }; return *this; };
|
{ for (size_t j = 0; j < n; j++) { (*this) & data[j]; }; return *this; };
|
||||||
@ -122,32 +147,87 @@ namespace ngcore
|
|||||||
// save -2 for nullptr
|
// save -2 for nullptr
|
||||||
if(!ptr)
|
if(!ptr)
|
||||||
return (*this) << -2;
|
return (*this) << -2;
|
||||||
auto pos = shared_ptr2nr.find((void*) ptr.get());
|
|
||||||
|
void* reg_ptr = ptr.get();
|
||||||
|
bool neededDowncast = false;
|
||||||
|
if constexpr(has_DoArchive<T>::value)
|
||||||
|
{
|
||||||
|
if(GetArchiveRegister().count(std::string(typeid(*ptr).name())) == 0)
|
||||||
|
throw std::runtime_error(std::string("Archive error: Polymorphic type ")
|
||||||
|
+ typeid(*ptr).name()
|
||||||
|
+ " not registered for archive");
|
||||||
|
else
|
||||||
|
reg_ptr = GetArchiveRegister()[typeid(*ptr).name()].downcaster(typeid(T), ptr.get());
|
||||||
|
if(reg_ptr != (void*) ptr.get())
|
||||||
|
neededDowncast = true;
|
||||||
|
}
|
||||||
|
auto pos = shared_ptr2nr.find(reg_ptr);
|
||||||
// if not found store -1 and the pointer
|
// if not found store -1 and the pointer
|
||||||
if(pos == shared_ptr2nr.end())
|
if(pos == shared_ptr2nr.end())
|
||||||
{
|
{
|
||||||
shared_ptr2nr[(void*) ptr.get()] = shared_ptr_count++;
|
|
||||||
auto p = ptr.get();
|
auto p = ptr.get();
|
||||||
return (*this) << -1 & p;
|
(*this) << -1;
|
||||||
|
(*this) & neededDowncast & p;
|
||||||
|
if(neededDowncast)
|
||||||
|
(*this) << std::string(typeid(*ptr).name());
|
||||||
|
shared_ptr2nr[reg_ptr] = shared_ptr_count++;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
// if found store the position
|
// if found store the position and if it has to be downcasted and how
|
||||||
return (*this) << pos->second;
|
(*this) << pos->second << neededDowncast;
|
||||||
|
if(neededDowncast)
|
||||||
|
(*this) << std::string(typeid(*ptr).name());
|
||||||
|
return (*this);
|
||||||
}
|
}
|
||||||
else // Input
|
else // Input
|
||||||
{
|
{
|
||||||
int nr;
|
int nr;
|
||||||
(*this) & nr;
|
(*this) & nr;
|
||||||
if(nr == -2)
|
if(nr == -2)
|
||||||
ptr = nullptr;
|
{
|
||||||
|
ptr = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
else if (nr == -1)
|
else if (nr == -1)
|
||||||
{
|
{
|
||||||
T* p;
|
T* p;
|
||||||
(*this) & p;
|
bool neededDowncast;
|
||||||
|
(*this) & neededDowncast & p;
|
||||||
ptr = std::shared_ptr<T>(p);
|
ptr = std::shared_ptr<T>(p);
|
||||||
nr2shared_ptr.push_back(ptr);
|
if(neededDowncast)
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
(*this) & name;
|
||||||
|
auto info = GetArchiveRegister()[name];
|
||||||
|
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
|
else
|
||||||
ptr = std::reinterpret_pointer_cast<T>(nr2shared_ptr[nr]);
|
{
|
||||||
|
auto other = nr2shared_ptr[nr];
|
||||||
|
bool neededDowncast;
|
||||||
|
(*this) & neededDowncast;
|
||||||
|
if(neededDowncast)
|
||||||
|
{
|
||||||
|
if constexpr(has_DoArchive<T>::value)
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
(*this) & name;
|
||||||
|
auto info = GetArchiveRegister()[name];
|
||||||
|
ptr = std::static_pointer_cast<T>(std::shared_ptr<void>(other,
|
||||||
|
info.upcaster(typeid(T),
|
||||||
|
other.get())));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Shouldn't get here...");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ptr = std::static_pointer_cast<T>(other);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -165,11 +245,21 @@ namespace ngcore
|
|||||||
(*this) & m2;
|
(*this) & m2;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
auto pos = ptr2nr.find( (void*) p);
|
void* reg_ptr = (void*)p;
|
||||||
|
if constexpr(has_DoArchive<T>::value)
|
||||||
|
{
|
||||||
|
if(GetArchiveRegister().count(std::string(typeid(*p).name())) == 0)
|
||||||
|
throw std::runtime_error(std::string("Archive error: Polimorphic type ")
|
||||||
|
+ typeid(*p).name()
|
||||||
|
+ " not registered for archive");
|
||||||
|
else
|
||||||
|
reg_ptr = GetArchiveRegister()[typeid(*p).name()].downcaster(typeid(T), p);
|
||||||
|
}
|
||||||
|
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
|
||||||
if (pos == ptr2nr.end())
|
if (pos == ptr2nr.end())
|
||||||
{
|
{
|
||||||
ptr2nr[(void*) p] = ptr_count++;
|
ptr2nr[reg_ptr] = ptr_count++;
|
||||||
if(typeid(*p) == typeid(T))
|
if(typeid(*p) == typeid(T))
|
||||||
if constexpr (std::is_constructible<T>::value)
|
if constexpr (std::is_constructible<T>::value)
|
||||||
{
|
{
|
||||||
@ -183,7 +273,7 @@ namespace ngcore
|
|||||||
// We want this special behaviour only for our classes that implement DoArchive
|
// We want this special behaviour only for our classes that implement DoArchive
|
||||||
if constexpr(has_DoArchive<T>::value)
|
if constexpr(has_DoArchive<T>::value)
|
||||||
{
|
{
|
||||||
if(GetArchiveRegister().count(typeid(*p).name()) == 0)
|
if(GetArchiveRegister().count(std::string(typeid(*p).name())) == 0)
|
||||||
throw std::runtime_error(std::string("Archive error: Polimorphic type ")
|
throw std::runtime_error(std::string("Archive error: Polimorphic type ")
|
||||||
+ typeid(*p).name()
|
+ typeid(*p).name()
|
||||||
+ " not registered for archive");
|
+ " not registered for archive");
|
||||||
@ -199,13 +289,13 @@ namespace ngcore
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
(*this) & pos->second;
|
(*this) & pos->second;
|
||||||
|
(*this) << std::string(typeid(*p).name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int nr;
|
int nr;
|
||||||
(*this) & nr;
|
(*this) & nr;
|
||||||
// cout << "in, got nr " << nr << endl;
|
|
||||||
if (nr == -2)
|
if (nr == -2)
|
||||||
{
|
{
|
||||||
p = nullptr;
|
p = nullptr;
|
||||||
@ -215,9 +305,8 @@ namespace ngcore
|
|||||||
if constexpr (std::is_constructible<T>::value)
|
if constexpr (std::is_constructible<T>::value)
|
||||||
{
|
{
|
||||||
p = new T;
|
p = new T;
|
||||||
// cout << "create new ptr, p = " << p << endl;
|
|
||||||
(*this) & *p;
|
|
||||||
nr2ptr.push_back(p);
|
nr2ptr.push_back(p);
|
||||||
|
(*this) & *p;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw std::runtime_error("Class isn't registered properly");
|
throw std::runtime_error("Class isn't registered properly");
|
||||||
@ -230,16 +319,25 @@ namespace ngcore
|
|||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
(*this) & name;
|
(*this) & name;
|
||||||
p = reinterpret_cast<T*>(GetArchiveRegister()[name]());
|
auto info = GetArchiveRegister()[name];
|
||||||
nr2ptr.push_back(p);
|
p = (T*) info.creator(typeid(T));
|
||||||
|
nr2ptr.push_back(info.downcaster(typeid(T),p));
|
||||||
|
(*this) & *p;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw std::runtime_error("Class isn't registered properly");
|
throw std::runtime_error("Class isn't registered properly");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
p = (T*)nr2ptr[nr];
|
std::string name;
|
||||||
// cout << "reuse ptr " << nr << ": " << p << endl;
|
(*this) & name;
|
||||||
|
if constexpr(has_DoArchive<T>::value)
|
||||||
|
{
|
||||||
|
auto info = GetArchiveRegister()[name];
|
||||||
|
p = (T*) info.upcaster(typeid(T), nr2ptr[nr]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p = (T*) nr2ptr[nr];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
@ -253,14 +351,62 @@ namespace ngcore
|
|||||||
(*this) & ht;
|
(*this) & ht;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void FlushBuffer() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename ... Bases>
|
||||||
|
class RegisterClassForArchive
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RegisterClassForArchive()
|
||||||
|
{
|
||||||
|
static_assert(std::is_constructible_v<T>, "Class registered for archive must be default constructible");
|
||||||
|
ClassArchiveInfo info;
|
||||||
|
info.creator = [this,&info](const std::type_info& ti) -> void*
|
||||||
|
{ return typeid(T) == ti ? new T : Caster<T, Bases...>::tryUpcast(ti, new T); };
|
||||||
|
info.upcaster = [this](const std::type_info& ti, void* p) -> void*
|
||||||
|
{ return typeid(T) == ti ? p : Caster<T, Bases...>::tryUpcast(ti, (T*) p); };
|
||||||
|
info.downcaster = [this](const std::type_info& ti, void* p) -> void*
|
||||||
|
{ return typeid(T) == ti ? p : Caster<T, Bases...>::tryDowncast(ti, p); };
|
||||||
|
GetArchiveRegister()[std::string(typeid(T).name())] = info;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void RegisterClassForArchive()
|
struct Caster<T>
|
||||||
{
|
{
|
||||||
static_assert(std::is_constructible_v<T>, "Class registered for archive must be default constructible");
|
static void* tryUpcast (const std::type_info& ti, T* p)
|
||||||
GetArchiveRegister()[std::string(typeid(T).name())] = []() -> void* { return new T; };
|
{
|
||||||
}
|
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()[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()[typeid(B1).name()].downcaster(ti, (void*) ((B1*)p)); }
|
||||||
|
catch(std::exception)
|
||||||
|
{ return Caster<T, Brest...>::tryDowncast(ti, p); }
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // NG_BASEARCHIVE_HPP
|
#endif // NG_BASEARCHIVE_HPP
|
||||||
|
@ -4,7 +4,6 @@ if(NOT WIN32)
|
|||||||
$<TARGET_OBJECTS:la>
|
$<TARGET_OBJECTS:la>
|
||||||
$<TARGET_OBJECTS:gprim>
|
$<TARGET_OBJECTS:gprim>
|
||||||
$<TARGET_OBJECTS:gen>
|
$<TARGET_OBJECTS:gen>
|
||||||
$<TARGET_OBJECTS:ngcore>
|
|
||||||
)
|
)
|
||||||
endif(NOT WIN32)
|
endif(NOT WIN32)
|
||||||
|
|
||||||
@ -31,7 +30,7 @@ if(APPLE)
|
|||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
target_link_libraries( mesh ${ZLIB_LIBRARIES} ${MPI_CXX_LIBRARIES} ${PYTHON_LIBRARIES} ${METIS_LIBRARY})
|
target_link_libraries( mesh ngcore ${ZLIB_LIBRARIES} ${MPI_CXX_LIBRARIES} ${PYTHON_LIBRARIES} ${METIS_LIBRARY})
|
||||||
install( TARGETS mesh ${NG_INSTALL_DIR})
|
install( TARGETS mesh ${NG_INSTALL_DIR})
|
||||||
endif(NOT WIN32)
|
endif(NOT WIN32)
|
||||||
|
|
||||||
|
@ -1 +1,2 @@
|
|||||||
|
add_subdirectory(catch)
|
||||||
add_subdirectory(pytest)
|
add_subdirectory(pytest)
|
||||||
|
30
tests/catch/CMakeLists.txt
Normal file
30
tests/catch/CMakeLists.txt
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
if(ENABLE_UNIT_TESTS)
|
||||||
|
add_custom_target(unit_tests)
|
||||||
|
|
||||||
|
# Build catch_main test object
|
||||||
|
message("netgen include dir = ${NETGEN_INCLUDE_DIR_ABSOLUTE} --------------------------------------")
|
||||||
|
include_directories(${CATCH_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../../libsrc/include})
|
||||||
|
add_library(catch_main STATIC main.cpp)
|
||||||
|
set_target_properties(catch_main PROPERTIES CXX_STANDARD 17)
|
||||||
|
add_dependencies(unit_tests catch_main)
|
||||||
|
add_dependencies(catch_main project_catch)
|
||||||
|
|
||||||
|
# ensure the test targets are built before testing
|
||||||
|
add_test(NAME unit_tests_built COMMAND ${CMAKE_COMMAND} --build . --target unit_tests --config ${CMAKE_BUILD_TYPE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../.. )
|
||||||
|
|
||||||
|
macro(add_unit_test name sources)
|
||||||
|
add_executable(test_${name} ${sources} )
|
||||||
|
if (WIN32)
|
||||||
|
target_link_libraries(test_${name} ngcore catch_main)
|
||||||
|
else(WIN32)
|
||||||
|
target_link_libraries(test_${name} ngcore catch_main)
|
||||||
|
endif(WIN32)
|
||||||
|
|
||||||
|
add_dependencies(unit_tests test_${name})
|
||||||
|
add_test(NAME unit_${name} COMMAND test_${name})
|
||||||
|
set_tests_properties(unit_${name} PROPERTIES DEPENDS unit_tests_built)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
add_unit_test(archive archive.cpp)
|
||||||
|
endif(ENABLE_UNIT_TESTS)
|
176
tests/catch/archive.cpp
Normal file
176
tests/catch/archive.cpp
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
|
||||||
|
#include "catch.hpp"
|
||||||
|
#include <../core/ngcore.hpp>
|
||||||
|
using namespace ngcore;
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class CommonBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~CommonBase() {}
|
||||||
|
|
||||||
|
virtual void DoArchive(Archive& archive) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SharedPtrHolder : virtual public CommonBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
vector<shared_ptr<string>> names;
|
||||||
|
virtual ~SharedPtrHolder()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
virtual void DoArchive(Archive& archive) { archive & names; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class PtrHolder : virtual public CommonBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
vector<int*> numbers;
|
||||||
|
virtual ~PtrHolder() {}
|
||||||
|
|
||||||
|
virtual void DoArchive(Archive& archive) { archive & numbers; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SharedPtrAndPtrHolder : public SharedPtrHolder, public PtrHolder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~SharedPtrAndPtrHolder() {}
|
||||||
|
virtual void DoArchive(Archive& archive)
|
||||||
|
{
|
||||||
|
SharedPtrHolder::DoArchive(archive);
|
||||||
|
PtrHolder::DoArchive(archive);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class NotRegisteredForArchive : public SharedPtrAndPtrHolder {};
|
||||||
|
|
||||||
|
class OneMoreDerivedClass : public SharedPtrAndPtrHolder {};
|
||||||
|
|
||||||
|
static RegisterClassForArchive<CommonBase> regb;
|
||||||
|
static RegisterClassForArchive<SharedPtrHolder, CommonBase> regsp;
|
||||||
|
static RegisterClassForArchive<PtrHolder, CommonBase> regp;
|
||||||
|
static RegisterClassForArchive<SharedPtrAndPtrHolder, SharedPtrHolder, PtrHolder> regspp;
|
||||||
|
static RegisterClassForArchive<OneMoreDerivedClass, SharedPtrAndPtrHolder> regom;
|
||||||
|
|
||||||
|
void testSharedPointer(Archive& in, Archive& out)
|
||||||
|
{
|
||||||
|
SECTION("Same shared ptr")
|
||||||
|
{
|
||||||
|
static_assert(has_DoArchive<SharedPtrHolder>::value, "");
|
||||||
|
SharedPtrHolder holder, holder2;
|
||||||
|
holder.names.push_back(make_shared<string>("name"));
|
||||||
|
holder2.names = holder.names; // same shared ptr
|
||||||
|
out & holder & holder2;
|
||||||
|
out.FlushBuffer();
|
||||||
|
SharedPtrHolder inholder, inholder2;
|
||||||
|
in & inholder & inholder2;
|
||||||
|
CHECK(inholder.names.size() == 1);
|
||||||
|
CHECK(inholder.names[0] == inholder2.names[0]);
|
||||||
|
CHECK(inholder.names[0].use_count() == 3); // one shared ptr is still kept in the archive
|
||||||
|
CHECK(*inholder.names[0] == "name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testPointer(Archive& in, Archive& out)
|
||||||
|
{
|
||||||
|
SECTION("Same pointer")
|
||||||
|
{
|
||||||
|
PtrHolder holder, holder2;
|
||||||
|
holder.numbers.push_back(new int(3));
|
||||||
|
holder2.numbers = holder.numbers; // same shared ptr
|
||||||
|
out & holder & holder2;
|
||||||
|
out.FlushBuffer();
|
||||||
|
PtrHolder inholder, inholder2;
|
||||||
|
in & inholder & inholder2;
|
||||||
|
CHECK(inholder.numbers.size() == 1);
|
||||||
|
CHECK(inholder.numbers[0] == inholder2.numbers[0]);
|
||||||
|
CHECK(*inholder.numbers[0] == 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testMultipleInheritance(Archive& in, Archive& out)
|
||||||
|
{
|
||||||
|
PtrHolder* p = new OneMoreDerivedClass;
|
||||||
|
p->numbers.push_back(new int(2));
|
||||||
|
auto p2 = dynamic_cast<SharedPtrHolder*>(p);
|
||||||
|
p2->names.push_back(make_shared<string>("test"));
|
||||||
|
auto sp1 = shared_ptr<PtrHolder>(p);
|
||||||
|
auto sp2 = dynamic_pointer_cast<SharedPtrHolder>(sp1);
|
||||||
|
auto checkPtr = [] (auto pin, auto pin2)
|
||||||
|
{
|
||||||
|
CHECK(typeid(*pin) == typeid(*pin2));
|
||||||
|
CHECK(typeid(*pin) == typeid(OneMoreDerivedClass));
|
||||||
|
CHECK(*pin2->names[0] == "test");
|
||||||
|
CHECK(*pin->numbers[0] == 2);
|
||||||
|
CHECK(dynamic_cast<SharedPtrAndPtrHolder*>(pin) == dynamic_cast<SharedPtrAndPtrHolder*>(pin2));
|
||||||
|
REQUIRE(dynamic_cast<SharedPtrAndPtrHolder*>(pin2) != nullptr);
|
||||||
|
CHECK(*dynamic_cast<SharedPtrAndPtrHolder*>(pin2)->numbers[0] == 2);
|
||||||
|
CHECK(*pin->numbers[0] == *dynamic_cast<SharedPtrAndPtrHolder*>(pin2)->numbers[0]);
|
||||||
|
REQUIRE(dynamic_cast<SharedPtrAndPtrHolder*>(pin) != nullptr);
|
||||||
|
CHECK(dynamic_cast<SharedPtrAndPtrHolder*>(pin)->names[0] == pin2->names[0]);
|
||||||
|
};
|
||||||
|
SECTION("Archive ptrs to leaves of mult. inh.")
|
||||||
|
{
|
||||||
|
out & p & p2;
|
||||||
|
out.FlushBuffer();
|
||||||
|
PtrHolder* pin;
|
||||||
|
SharedPtrHolder* pin2;
|
||||||
|
in & pin & pin2;
|
||||||
|
checkPtr(pin, pin2);
|
||||||
|
}
|
||||||
|
SECTION("Archive shared ptrs to leaves of mult. inh.")
|
||||||
|
{
|
||||||
|
out & sp1 & sp2;
|
||||||
|
out.FlushBuffer();
|
||||||
|
shared_ptr<PtrHolder> pin;
|
||||||
|
shared_ptr<SharedPtrHolder> pin2;
|
||||||
|
in & pin & pin2;
|
||||||
|
checkPtr(pin.get(), pin2.get());
|
||||||
|
}
|
||||||
|
SECTION("Virtual base class")
|
||||||
|
{
|
||||||
|
CommonBase* b = dynamic_cast<CommonBase*>(p);
|
||||||
|
out & b & p;
|
||||||
|
PtrHolder* pin;
|
||||||
|
CommonBase* bin;
|
||||||
|
in & bin & pin;
|
||||||
|
checkPtr(pin, dynamic_cast<SharedPtrHolder*>(bin));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testArchive(Archive& in, Archive& out)
|
||||||
|
{
|
||||||
|
SECTION("SharedPtr")
|
||||||
|
{
|
||||||
|
testSharedPointer(in, out);
|
||||||
|
}
|
||||||
|
SECTION("Pointer")
|
||||||
|
{
|
||||||
|
testPointer(in, out);
|
||||||
|
}
|
||||||
|
SECTION("Multiple inheritance")
|
||||||
|
{
|
||||||
|
testMultipleInheritance(in, out);
|
||||||
|
}
|
||||||
|
SECTION("Not registered")
|
||||||
|
{
|
||||||
|
SharedPtrAndPtrHolder* p = new NotRegisteredForArchive;
|
||||||
|
REQUIRE_THROWS(out & p, Catch::Contains("not registered for archive"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("BinaryArchive")
|
||||||
|
{
|
||||||
|
auto stream = make_shared<stringstream>();
|
||||||
|
BinaryOutArchive out(stream);
|
||||||
|
BinaryInArchive in(stream);
|
||||||
|
testArchive(in, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("TextArchive")
|
||||||
|
{
|
||||||
|
auto stream = make_shared<stringstream>();
|
||||||
|
TextOutArchive out(stream);
|
||||||
|
TextInArchive in(stream);
|
||||||
|
testArchive(in, out);
|
||||||
|
}
|
3
tests/catch/main.cpp
Normal file
3
tests/catch/main.cpp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
#define CATCH_CONFIG_MAIN
|
||||||
|
#include <catch.hpp>
|
Loading…
Reference in New Issue
Block a user