diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9f86836a..85d70d56 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,16 +45,8 @@ stages: - pwd - ls - docker info - -.template_ubuntu_1510: &ubuntu_1510 - <<: *ubuntu variables: - UBUNTU_VERSION: "15.10" - -.template_ubuntu_1604: &ubuntu_1604 - <<: *ubuntu - variables: - UBUNTU_VERSION: "16.04" + UBUNTU_VERSION: "18.04" ############################################ # Build stage @@ -98,18 +90,14 @@ build_netgen_win64: .template_build_linux: &build_linux stage: build script: - - docker build -t netgen_${CI_BUILD_REF_NAME}:${UBUNTU_VERSION} -f tests/docker_${UBUNTU_VERSION} . + - docker build -t netgen_${CI_BUILD_REF_NAME}:${UBUNTU_VERSION} -f tests/dockerfile . - rm -f netgen_${CI_BUILD_REF_NAME}_$UBUNTU_VERSION.id - docker run --cidfile netgen_${CI_BUILD_REF_NAME}_${UBUNTU_VERSION}.id -e CCACHE_DIR=/ccache -v /mnt/ccache:/ccache netgen_${CI_BUILD_REF_NAME}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build.sh - docker commit `cat netgen_${CI_BUILD_REF_NAME}_${UBUNTU_VERSION}.id` netgen_${CI_BUILD_REF_NAME}_installed:${UBUNTU_VERSION} - rm netgen_${CI_BUILD_REF_NAME}_${UBUNTU_VERSION}.id -.build_ubuntu_1510: - <<: *ubuntu_1510 - <<: *build_linux - -build_ubuntu_1604: - <<: *ubuntu_1604 +build_ubuntu: + <<: *ubuntu <<: *build_linux @@ -145,13 +133,17 @@ test_win64: netgen_${CI_BUILD_REF_NAME}_installed:${UBUNTU_VERSION} bash -c 'cd /root/build/netgen && make test_netgen ARGS="-V"' -.test_ubuntu_1510: - <<: *ubuntu_1510 - <<: *test_linux -test_ubuntu_1604: - <<: *ubuntu_1604 +test_ubuntu: + <<: *ubuntu <<: *test_linux +# cpp guideline checks +test_guidelines: + <<: *ubuntu + stage: test + script: + - docker run -e CCACHE_DIR=/ccache -v /mnt/ccache:/ccache netgen_${CI_BUILD_REF_NAME}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build_guidelines.sh + when: always ############################################ # Deploy stage ############################################ diff --git a/CMakeLists.txt b/CMakeLists.txt index ef0ee424..14931c4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,8 @@ option( INTEL_MIC "cross compile for intel xeon phi") option( INSTALL_PROFILES "install environment variable settings to /etc/profile.d" OFF ) 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) @@ -341,8 +343,27 @@ execute_process(COMMAND hdiutil create -volname Netgen -srcfolder ${CMAKE_INSTAL enable_testing() include(CTest) +if(ENABLE_UNIT_TESTS) + include(${CMAKE_CURRENT_LIST_DIR}/cmake/external_projects/catch.cmake) +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}" "-header-filter=libsrc/core/") + endif() +endif(ENABLE_CPP_CORE_GUIDELINES_CHECK) + add_subdirectory(libsrc) add_subdirectory(ng) add_subdirectory(tutorials) diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index 78be04ec..36ea3fcb 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -140,6 +140,8 @@ set_vars( NETGEN_CMAKE_ARGS INTEL_MIC 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 diff --git a/cmake/external_projects/catch.cmake b/cmake/external_projects/catch.cmake new file mode 100644 index 00000000..0f79e6c7 --- /dev/null +++ b/cmake/external_projects/catch.cmake @@ -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") diff --git a/cmake/external_projects/tcltk.cmake b/cmake/external_projects/tcltk.cmake index 06852df1..7b174a7c 100644 --- a/cmake/external_projects/tcltk.cmake +++ b/cmake/external_projects/tcltk.cmake @@ -27,85 +27,35 @@ if(APPLE) set(TCL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_tcl) set(TK_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_tk) - set(TCL_INCLUDE_PATH ${TCL_DIR}/generic;${TCL_DIR}/macosx) - set(TK_INCLUDE_PATH ${TK_DIR}/generic;${TK_DIR}/macosx;${TK_DIR}/xlib) - find_package(TCL 8.6 REQUIRED) - list(APPEND NETGEN_DEPENDENCIES project_tcl project_tk) + set(TCL_INCLUDE_PATH "${TCL_DIR}/generic;${TCL_DIR}/macosx") + set(TK_INCLUDE_PATH "${TK_DIR}/generic;${TK_DIR}/macosx;${TK_DIR}/xlib") + string(REPLACE ";" "$" TCL_INC "${TCL_INCLUDE_PATH}") + string(REPLACE ";" "$" TK_INC "${TK_INCLUDE_PATH}") + ExternalProject_Add(project_tkdnd + URL "http://sourceforge.net/projects/tkdnd/files/TkDND/TkDND%202.8/tkdnd2.8-src.tar.gz" + URL_MD5 a6d47a996ea957416469b12965d4db91 + DEPENDS project_tcl project_tk + DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies + PATCH_COMMAND patch -p1 < ${CMAKE_CURRENT_LIST_DIR}/tkdnd_macosx.patch + UPDATE_COMMAND "" # Disable update + BUILD_IN_SOURCE 1 + CMAKE_ARGS + -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/Contents/MacOS + -DTCL_INCLUDE_PATH=${TCL_INC} + -DTK_INCLUDE_PATH=${TK_INC} + -DTK_LIBRARY=${TK_LIBRARY} + -DTCL_LIBRARY=${TCL_LIBRARY} + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 + LOG_INSTALL 1 + ) + +list(APPEND NETGEN_DEPENDENCIES project_tkdnd) else() find_package(TCL 8.5 REQUIRED) endif() -# set(HOME $ENV{HOME}) -# set(tcl_prefix ${CMAKE_INSTALL_PREFIX}/../../) -# ExternalProject_Add(project_tcl -# URL "http://sourceforge.net/projects/tcl/files/Tcl/8.6.4/tcl8.6.4-src.tar.gz" -# URL_MD5 d7cbb91f1ded1919370a30edd1534304 -# DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies -# UPDATE_COMMAND "" # Disable update -# CONFIGURE_COMMAND ../project_tcl/macosx/configure --enable-threads --enable-framework --prefix=${tcl_prefix} --libdir=${tcl_prefix}/Contents/Frameworks --bindir=${tcl_prefix}/Contents/Frameworks/Tcl.framework/bin -# BUILD_COMMAND make -j4 binaries libraries -# INSTALL_COMMAND make install-binaries install-headers install-libraries install-private-headers -# LOG_DOWNLOAD 1 -# LOG_BUILD 1 -# LOG_CONFIGURE 1 -# LOG_INSTALL 1 -# ) -# -# ExternalProject_Add(project_tk -# DEPENDS project_tcl -# URL "http://sourceforge.net/projects/tcl/files/Tcl/8.6.4/tk8.6.4-src.tar.gz" -# URL_MD5 261754d7dc2a582f00e35547777e1fea -# DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies -# UPDATE_COMMAND "" # Disable update -# CONFIGURE_COMMAND ../project_tk/macosx/configure --enable-aqua=yes --enable-threads --enable-framework --prefix=${tcl_prefix} --libdir=${tcl_prefix}/Contents/Frameworks --bindir=${tcl_prefix}/Contents/Frameworks/Tcl.framework/bin --with-tcl=${tcl_prefix}/Contents/Frameworks/Tcl.framework -# BUILD_COMMAND make -j4 binaries libraries -# INSTALL_COMMAND make install-binaries install-headers install-libraries install-private-headers -# LOG_DOWNLOAD 1 -# LOG_BUILD 1 -# LOG_CONFIGURE 1 -# LOG_INSTALL 1 -# ) -# -# ExternalProject_Add(project_tkdnd -# URL "https://sourceforge.net/projects/tkdnd/files/OS%20X%20Binaries/TkDND%202.8/tkdnd2.8-OSX-MountainLion.tar.gz" -# URL_MD5 2dbb471b1d66c5f391f3c3c5b71548fb -# DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies -# BUILD_IN_SOURCE 1 -# CONFIGURE_COMMAND "" -# BUILD_COMMAND "" -# INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${CMAKE_INSTALL_PREFIX}/../MacOS -# LOG_DOWNLOAD 1 -# LOG_CONFIGURE 1 -# LOG_BUILD 1 -# LOG_INSTALL 1 -# ) -# -# list(APPEND NETGEN_DEPENDENCIES project_tcl project_tk project_tkdnd) -# list(APPEND CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}../Frameworks) -# set(TCL_INCLUDE_PATH ${CMAKE_INSTALL_PREFIX}/../Frameworks/Tcl.framework/Headers) -# set(TCL_LIBRARY ${CMAKE_INSTALL_PREFIX}/../Frameworks/Tcl.framework) -# set(TK_LIBRARY ${CMAKE_INSTALL_PREFIX}/../Frameworks/Tk.framework) -# set(TK_INCLUDE_PATH ${CMAKE_INSTALL_PREFIX}/../Frameworks/Tk.framework/Headers) -# - - - -ExternalProject_Add(project_tkdnd - URL "http://sourceforge.net/projects/tkdnd/files/TkDND/TkDND%202.8/tkdnd2.8-src.tar.gz" - URL_MD5 a6d47a996ea957416469b12965d4db91 - DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies - PATCH_COMMAND patch -p1 < ${CMAKE_CURRENT_LIST_DIR}/tkdnd_macosx.patch - UPDATE_COMMAND "" # Disable update - BUILD_IN_SOURCE 1 - CONFIGURE_COMMAND ./configure --prefix=${CMAKE_INSTALL_PREFIX}/Contents/MacOS --libdir=${CMAKE_INSTALL_PREFIX}/Contents/MacOS - BUILD_COMMAND make - INSTALL_COMMAND make install - LOG_DOWNLOAD 1 - LOG_CONFIGURE 1 - LOG_BUILD 1 - LOG_INSTALL 1 -) -list(APPEND NETGEN_DEPENDENCIES project_tkdnd) elseif(WIN32) diff --git a/cmake/external_projects/tkdnd_macosx.patch b/cmake/external_projects/tkdnd_macosx.patch index a2ed4217..e6af1974 100644 --- a/cmake/external_projects/tkdnd_macosx.patch +++ b/cmake/external_projects/tkdnd_macosx.patch @@ -1,35 +1,36 @@ -diff -Naur orig/tkdnd2.8/configure changed/tkdnd2.8/configure ---- tkdnd2.8/configure 2015-05-13 19:24:32.000000000 +0200 -+++ tkdnd2.8/configure 2016-02-22 15:26:37.000000000 +0100 -@@ -6145,7 +6145,7 @@ - - - -- PKG_CFLAGS="$PKG_CFLAGS -DMAC_TK_COCOA -std=gnu99 -x objective-c -fobjc-gc" -+ PKG_CFLAGS="$PKG_CFLAGS -DMAC_TK_COCOA -std=gnu99 -x objective-c" - - - -diff -Naur orig/tkdnd2.8/configure.in changed/tkdnd2.8/configure.in ---- tkdnd2.8/configure.in 2015-05-13 19:24:32.000000000 +0200 -+++ tkdnd2.8/configure.in 2016-02-22 15:26:44.000000000 +0100 -@@ -126,7 +126,7 @@ - - if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then - TEA_ADD_SOURCES([macosx/macdnd.m]) -- TEA_ADD_CFLAGS([-DMAC_TK_COCOA -std=gnu99 -x objective-c -fobjc-gc]) -+ TEA_ADD_CFLAGS([-DMAC_TK_COCOA -std=gnu99 -x objective-c]) - TEA_ADD_LIBS([-framework Cocoa -framework Carbon]) - fi - -diff -Naur orig/tkdnd2.8/macosx/macdnd.m changed/tkdnd2.8/macosx/macdnd.m ---- tkdnd2.8/macosx/macdnd.m 2015-07-06 21:49:14.000000000 +0200 -+++ tkdnd2.8/macosx/macdnd.m 2016-02-22 15:27:04.000000000 +0100 -@@ -16,6 +16,7 @@ - #import - #import - #import -+#undef panic - #import - #import +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 4eb497c..c6424fc 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -43,17 +43,17 @@ IF ( WIN32 ) + ELSE ( WIN32 ) + ## Unix and OS X... + IF ( APPLE ) +- SET ( CMAKE_OSX_ARCHITECTURES "x86_64;i386" ) ++ SET ( CMAKE_OSX_ARCHITECTURES "x86_64") + FIND_LIBRARY ( COCOA_LIBRARY Cocoa ) + INCLUDE_DIRECTORIES ( macosx ) +- INCLUDE_DIRECTORIES ( /Library/Frameworks/Tk.framework/Versions/8.6/PrivateHeaders ) +- INCLUDE_DIRECTORIES ( /System/Library/Frameworks/Tk.framework/Versions/8.5/Headers/tk-private ) +- INCLUDE_DIRECTORIES ( /System/Library/Frameworks/Tk.framework/Versions/8.5/Headers/tk-private ) ++# INCLUDE_DIRECTORIES ( /Library/Frameworks/Tk.framework/Versions/8.6/PrivateHeaders ) ++# INCLUDE_DIRECTORIES ( /System/Library/Frameworks/Tk.framework/Versions/8.5/Headers/tk-private ) ++# INCLUDE_DIRECTORIES ( /System/Library/Frameworks/Tk.framework/Versions/8.5/Headers/tk-private ) + ADD_DEFINITIONS ( -DMAC_TK_COCOA -DMAC_OSX_TK) + ADD_DEFINITIONS ( -DMAC_OSX_TK ) + ADD_DEFINITIONS ( -std=gnu99 ) + ADD_DEFINITIONS ( -x objective-c ) +- ADD_DEFINITIONS ( -fobjc-gc ) ++# ADD_DEFINITIONS ( -fobjc-gc ) + ADD_DEFINITIONS ( -fno-objc-arc ) + # ADD_DEFINITIONS ( -fobjc-arc ) + LINK_LIBRARIES ( ${COCOA_LIBRARY} ) +@@ -125,7 +125,7 @@ SET ( CP ${CMAKE_COMMAND} -E copy ) + ## Locate Tcl/Tk + ## =========================================================================== + MESSAGE ( STATUS "Searching for Tcl/Tk..." ) +-FIND_PACKAGE ( TCL REQUIRED ) ++#FIND_PACKAGE ( TCL REQUIRED ) + FIND_PACKAGE ( TclStub REQUIRED ) + ## Tcl/Tk info (useful for debug purposes)... diff --git a/external_dependencies/pybind11 b/external_dependencies/pybind11 index 2a150736..e2b884c3 160000 --- a/external_dependencies/pybind11 +++ b/external_dependencies/pybind11 @@ -1 +1 @@ -Subproject commit 2a150736601bb3113877bb673fb934bb60d46ec5 +Subproject commit e2b884c33bcde70b2ea562ffa52dd7ebee276d50 diff --git a/libsrc/CMakeLists.txt b/libsrc/CMakeLists.txt index 89dc88a5..eb67d688 100644 --- a/libsrc/CMakeLists.txt +++ b/libsrc/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(core) add_subdirectory(general) add_subdirectory(gprim) add_subdirectory(linalg) diff --git a/libsrc/core/.clang-tidy b/libsrc/core/.clang-tidy new file mode 100644 index 00000000..290188fb --- /dev/null +++ b/libsrc/core/.clang-tidy @@ -0,0 +1,5 @@ +Checks: '*,-clang-analyzer-alpha.*,-*braces-around-statements,-fuchsia-*,-google-runtime-references,-readability-implicit-bool-conversion,-google-explicit-constructor,-hicpp-explicit-conversions,-google-runtime-int,-llvm-header-guard' +CheckOptions: + - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor + value: 1 +WarningsAsErrors: '*' \ No newline at end of file diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt new file mode 100644 index 00000000..e7fe7240 --- /dev/null +++ b/libsrc/core/CMakeLists.txt @@ -0,0 +1,12 @@ +add_library(ngcore SHARED archive.cpp) + +target_compile_definitions(ngcore PRIVATE -DNGCORE_EXPORTS) + +install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen) + +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) diff --git a/libsrc/core/archive.cpp b/libsrc/core/archive.cpp new file mode 100644 index 00000000..64789904 --- /dev/null +++ b/libsrc/core/archive.cpp @@ -0,0 +1,52 @@ + +#include "archive.hpp" + +#ifndef WIN32 +#include +#endif + +namespace ngcore +{ + // clang-tidy should ignore this static object + static std::map library_versions; // NOLINT + std::map& 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 WIN32 + // 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> type_register; // NOLINT + const detail::ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname) + { + if(type_register == nullptr) type_register = + std::make_unique>(); + return (*type_register)[classname]; + } + void Archive :: SetArchiveRegister(const std::string& classname, const detail::ClassArchiveInfo& info) + { + if(type_register == nullptr) type_register = + std::make_unique>(); + (*type_register)[classname] = info; + } + bool Archive :: IsRegistered(const std::string& classname) + { + if(type_register == nullptr) type_register = + std::make_unique>(); + return type_register->count(classname) != 0; + } +} // namespace ngcore diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp new file mode 100644 index 00000000..c69fa293 --- /dev/null +++ b/libsrc/core/archive.hpp @@ -0,0 +1,796 @@ +#ifndef NETGEN_CORE_ARCHIVE_HPP +#define NETGEN_CORE_ARCHIVE_HPP + +#include // for complex +#include // for size_t, strlen +#include // for operator<<, ifstream, ofstream, basic... +#include // for function +#include // for map, _Rb_tree_iterator +#include // for __shared_ptr_access, __shared_ptr_acc... +#include // for runtime_error +#include // for string, operator+ +#include // for declval, enable_if, false_type, is_co... +#include // for type_info +#include // for move, swap, pair +#include // for vector + +#include "ngcore_api.hpp" // for NGCORE_API, unlikely +#include "type_traits.hpp" // for all_of_tmpl +#include "version.hpp" // for VersionInfo + +namespace ngcore +{ + // Libraries using this archive can store their version here to implement backwards compatibility + NGCORE_API const VersionInfo& GetLibraryVersion(const std::string& library); + NGCORE_API void SetLibraryVersion(const std::string& library, const VersionInfo& version); + NGCORE_API std::string Demangle(const char* typeinfo); + + class NGCORE_API Archive; + + namespace detail + { + // create new pointer of type T if it is default constructible, else throw + template + T* constructIfPossible_impl(Rest... /*unused*/) + { throw std::runtime_error(std::string(Demangle(typeid(T).name())) + " is not default constructible!"); } + + template::value>::type> + T* constructIfPossible_impl(int /*unused*/) { return new T; } // NOLINT + + template + T* constructIfPossible() { return constructIfPossible_impl(int{}); } + + //Type trait to check if a class implements a 'void DoArchive(Archive&)' function + template + struct has_DoArchive + { + private: + template + static constexpr auto check(T2*) -> + typename std::is_same().DoArchive(std::declval())),void>::type; + template + static constexpr std::false_type check(...); + using type = decltype(check(nullptr)); // NOLINT + public: + NGCORE_API static constexpr bool value = type::value; + }; + + // Check if class is archivable + template + struct is_Archivable_struct + { + private: + template + static constexpr auto check(T2*) -> + typename std::is_same() & std::declval()),Archive&>::type; + template + static constexpr std::false_type check(...); + using type = decltype(check(nullptr)); // NOLINT + 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 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 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 downcaster; + }; + } // namespace detail + + template + constexpr bool is_archivable = detail::is_Archivable_struct::value; + + // Base Archive class + class NGCORE_API Archive + { + const 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 shared_ptr2nr, ptr2nr; + // vectors for storing the unarchived (shared) pointers + std::vector> nr2shared_ptr; + std::vector nr2ptr; + + public: + Archive() = delete; + Archive(const Archive&) = delete; + Archive(Archive&&) = delete; + Archive (bool ais_output) : + is_output(ais_output), shared_ptr_count(0), ptr_count(0) { ; } + + virtual ~Archive() { ; } + + Archive& operator=(const Archive&) = delete; + Archive& operator=(Archive&&) = delete; + + bool Output () const { return is_output; } + bool Input () const { 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; + + virtual Archive & operator & (VersionInfo & version) + { + if(Output()) + (*this) << version.to_string(); + else + { + std::string s; + (*this) & s; + version = VersionInfo(s); + } + return *this; + } + + // Archive std classes ================================================ + template + Archive& operator & (std::complex& c) + { + if(Output()) + (*this) << c.real() << c.imag(); + else + { + T tmp; + (*this) & tmp; + c.real(tmp); + (*this) & tmp; + c.imag(tmp); + } + return (*this); + } + template + Archive& operator & (std::vector& v) + { + size_t size; + if(Output()) + size = v.size(); + (*this) & size; + if(Input()) + v.resize(size); + Do(&v[0], size); + return (*this); + } + template + Archive& operator& (std::map& map) + { + if(Output()) + { + (*this) << size_t(map.size()); + for(auto& pair : map) + (*this) << pair.first << pair.second; + } + else + { + size_t size = 0; + (*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 >::type> + Archive & Do (T * data, size_t n) + { for (size_t j = 0; j < n; j++) { (*this) & data[j]; }; return *this; }; // NOLINT + + virtual Archive & Do (double * d, size_t n) + { for (size_t j = 0; j < n; j++) { (*this) & d[j]; }; return *this; }; // NOLINT + + virtual Archive & Do (int * i, size_t n) + { for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; }; // NOLINT + + virtual Archive & Do (long * i, size_t n) + { for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; }; // NOLINT + + virtual Archive & Do (size_t * i, size_t n) + { for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; }; // NOLINT + + virtual Archive & Do (short * i, size_t n) + { for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; }; // NOLINT + + virtual Archive & Do (unsigned char * i, size_t n) + { for (size_t j = 0; j < n; j++) { (*this) & i[j]; }; return *this; }; // NOLINT + + virtual Archive & Do (bool * b, size_t n) + { for (size_t j = 0; j < n; j++) { (*this) & b[j]; }; return *this; }; // NOLINT + + // Archive a class implementing a (void DoArchive(Archive&)) method ======= + template::value>> + Archive& operator & (T& val) + { + val.DoArchive(*this); return *this; + } + + // Archive shared_ptrs ================================================= + template + Archive& operator & (std::shared_ptr& 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 != static_cast(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()); + } + 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 + if (nr == -1) + { + T* p = nullptr; + bool neededDowncast; + (*this) & neededDowncast & p; + ptr = std::shared_ptr(p); + // if we did downcast we need to store a shared_ptr 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(std::static_pointer_cast(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 in the register, but pointing to our object + ptr = std::static_pointer_cast(std::shared_ptr(other, + info.upcaster(typeid(T), + other.get()))); + } + else + ptr = std::static_pointer_cast(other); + } + } + return *this; + } + + // Archive pointers ======================================================= + template + Archive & operator& (T *& p) + { + if (Output()) + { + // if the pointer is null store -2 + if (!p) + return (*this) << -2; + auto reg_ptr = static_cast(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"); + reg_ptr = GetArchiveRegister(Demangle(typeid(*p).name())).downcaster(typeid(T), static_cast(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::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"); + return (*this) << -3 << Demangle(typeid(*p).name()) & (*p); + } + } + else + { + (*this) & pos->second; + bool downcasted = !(reg_ptr == static_cast(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 = detail::constructIfPossible(); + 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 = static_cast(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 = static_cast(info.upcaster(typeid(T), nr2ptr[nr])); + } + else + p = static_cast(nr2ptr[nr]); + } + } + return *this; + } + + // const ptr + template + Archive& operator &(const T*& t) + { + return (*this) & const_cast(t); // NOLINT + } + + // Write a read only variable + template + Archive & operator << (const T & t) + { + T ht(t); + (*this) & ht; + return *this; + } + + virtual void FlushBuffer() {} + + protected: + static std::map& GetLibraryVersions(); + + private: + template + friend class RegisterClassForArchive; + + // Returns ClassArchiveInfo of Demangled typeid + static const detail::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, const detail::ClassArchiveInfo& info); + static bool IsRegistered(const std::string& classname); + + // Helper class for up-/downcasting + template + struct Caster{}; + + template + struct Caster + { + static void* tryUpcast (const std::type_info& /*unused*/, T* /*unused*/) + { + throw std::runtime_error("Upcast not successful, some classes are not registered properly for archiving!"); + } + static void* tryDowncast (const std::type_info& /*unused*/, void* /*unused*/) + { + 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, static_cast(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(static_cast(p)); + try + { + return dynamic_cast(static_cast(GetArchiveRegister(Demangle(typeid(B1).name())). + downcaster(ti, p))); + } + catch(std::exception&) + { + return Caster::tryDowncast(ti, p); + } + } + }; + }; + + template + class RegisterClassForArchive + { + public: + RegisterClassForArchive() + { + static_assert(detail::all_of_tmpl::value...>, + "Variadic template arguments must be base classes of T"); + detail::ClassArchiveInfo info; + info.creator = [this,&info](const std::type_info& ti) -> void* + { return typeid(T) == ti ? detail::constructIfPossible() + : Archive::Caster::tryUpcast(ti, detail::constructIfPossible()); }; + info.upcaster = [this](const std::type_info& ti, void* p) -> void* + { return typeid(T) == ti ? p : Archive::Caster::tryUpcast(ti, static_cast(p)); }; + info.downcaster = [this](const std::type_info& ti, void* p) -> void* + { return typeid(T) == ti ? p : Archive::Caster::tryDowncast(ti, p); }; + Archive::SetArchiveRegister(std::string(Demangle(typeid(T).name())),info); + } + + + }; + + // BinaryOutArchive ====================================================================== + class NGCORE_API BinaryOutArchive : public Archive + { + size_t ptr = 0; + static constexpr size_t BUFFERSIZE = 1024; + alignas(64) char buffer[BUFFERSIZE] = {}; + std::shared_ptr fout; + public: + BinaryOutArchive() = delete; + BinaryOutArchive(const BinaryOutArchive&) = delete; + BinaryOutArchive(BinaryOutArchive&&) = delete; + BinaryOutArchive(std::shared_ptr&& afout) + : Archive(true), fout(std::move(afout)) + { + (*this) & GetLibraryVersions(); + } + BinaryOutArchive(const std::string& filename) + : BinaryOutArchive(std::make_shared(filename)) {} + ~BinaryOutArchive () override { FlushBuffer(); } + + BinaryOutArchive& operator=(const BinaryOutArchive&) = delete; + BinaryOutArchive& operator=(BinaryOutArchive&&) = delete; + + const VersionInfo& GetVersion(const std::string& library) override + { return GetLibraryVersions()[library]; } + + using Archive::operator&; + Archive & operator & (double & d) override + { return Write(d); } + Archive & operator & (int & i) override + { return Write(i); } + Archive & operator & (short & i) override + { return Write(i); } + Archive & operator & (long & i) override + { return Write(i); } + Archive & operator & (size_t & i) override + { return Write(i); } + Archive & operator & (unsigned char & i) override + { return Write(i); } + Archive & operator & (bool & b) override + { return Write(b); } + Archive & operator & (std::string & str) override + { + int len = str.length(); + (*this) & len; + FlushBuffer(); + if(len) + fout->write (&str[0], len); + return *this; + } + Archive & operator & (char *& str) override + { + long len = str ? strlen (str) : -1; + (*this) & len; + FlushBuffer(); + if(len > 0) + fout->write (&str[0], len); // NOLINT + return *this; + } + void FlushBuffer() override + { + if (ptr > 0) + { + fout->write(&buffer[0], ptr); + ptr = 0; + } + } + + private: + template + Archive & Write (T x) + { + if (unlikely(ptr > BUFFERSIZE-sizeof(T))) + { + fout->write(&buffer[0], ptr); + *reinterpret_cast(&buffer[0]) = x; // NOLINT + ptr = sizeof(T); + return *this; + } + *reinterpret_cast(&buffer[ptr]) = x; // NOLINT + ptr += sizeof(T); + return *this; + } + }; + + // BinaryInArchive ====================================================================== + class NGCORE_API BinaryInArchive : public Archive + { + std::map vinfo{}; + std::shared_ptr fin; + public: + BinaryInArchive (std::shared_ptr&& afin) + : Archive(false), fin(std::move(afin)) + { + (*this) & vinfo; + } + BinaryInArchive (const std::string& filename) + : BinaryInArchive(std::make_shared(filename)) { ; } + + const VersionInfo& GetVersion(const std::string& library) override + { return vinfo[library]; } + + using Archive::operator&; + Archive & operator & (double & d) override + { Read(d); return *this; } + Archive & operator & (int & i) override + { Read(i); return *this; } + Archive & operator & (short & i) override + { Read(i); return *this; } + Archive & operator & (long & i) override + { Read(i); return *this; } + Archive & operator & (size_t & i) override + { Read(i); return *this; } + Archive & operator & (unsigned char & i) override + { Read(i); return *this; } + Archive & operator & (bool & b) override + { Read(b); return *this; } + Archive & operator & (std::string & str) override + { + int len; + (*this) & len; + str.resize(len); + if(len) + fin->read(&str[0], len); // NOLINT + return *this; + } + Archive & operator & (char *& str) override + { + long len; + (*this) & len; + if(len == -1) + str = nullptr; + else + { + str = new char[len+1]; // NOLINT + fin->read(&str[0], len); // NOLINT + str[len] = '\0'; // NOLINT + } + return *this; + } + + Archive & Do (double * d, size_t n) override + { fin->read(reinterpret_cast(d), n*sizeof(double)); return *this; } // NOLINT + Archive & Do (int * i, size_t n) override + { fin->read(reinterpret_cast(i), n*sizeof(int)); return *this; } // NOLINT + Archive & Do (size_t * i, size_t n) override + { fin->read(reinterpret_cast(i), n*sizeof(size_t)); return *this; } // NOLINT + + private: + template + inline void Read(T& val) + { fin->read(reinterpret_cast(&val), sizeof(T)); } // NOLINT + }; + + // TextOutArchive ====================================================================== + class NGCORE_API TextOutArchive : public Archive + { + std::shared_ptr fout; + public: + TextOutArchive (std::shared_ptr&& afout) + : Archive(true), fout(std::move(afout)) + { + (*this) & GetLibraryVersions(); + } + TextOutArchive (const std::string& filename) : + TextOutArchive(std::make_shared(filename)) { } + + const VersionInfo& GetVersion(const std::string& library) override + { return GetLibraryVersions()[library]; } + + using Archive::operator&; + Archive & operator & (double & d) override + { *fout << d << '\n'; return *this; } + Archive & operator & (int & i) override + { *fout << i << '\n'; return *this; } + Archive & operator & (short & i) override + { *fout << i << '\n'; return *this; } + Archive & operator & (long & i) override + { *fout << i << '\n'; return *this; } + Archive & operator & (size_t & i) override + { *fout << i << '\n'; return *this; } + Archive & operator & (unsigned char & i) override + { *fout << int(i) << '\n'; return *this; } + Archive & operator & (bool & b) override + { *fout << (b ? 't' : 'f') << '\n'; return *this; } + Archive & operator & (std::string & str) override + { + int len = str.length(); + *fout << len << '\n'; + if(len) + { + fout->write(&str[0], len); // NOLINT + *fout << '\n'; + } + return *this; + } + Archive & operator & (char *& str) override + { + long len = str ? strlen (str) : -1; + *this & len; + if(len > 0) + { + fout->write (&str[0], len); // NOLINT + *fout << '\n'; + } + return *this; + } + }; + + // TextInArchive ====================================================================== + class NGCORE_API TextInArchive : public Archive + { + std::map vinfo{}; + std::shared_ptr fin; + public: + TextInArchive (std::shared_ptr&& afin) : + Archive(false), fin(std::move(afin)) + { + (*this) & vinfo; + } + TextInArchive (const std::string& filename) + : TextInArchive(std::make_shared(filename)) {} + + const VersionInfo& GetVersion(const std::string& library) override + { return vinfo[library]; } + + using Archive::operator&; + Archive & operator & (double & d) override + { *fin >> d; return *this; } + Archive & operator & (int & i) override + { *fin >> i; return *this; } + Archive & operator & (short & i) override + { *fin >> i; return *this; } + Archive & operator & (long & i) override + { *fin >> i; return *this; } + Archive & operator & (size_t & i) override + { *fin >> i; return *this; } + Archive & operator & (unsigned char & i) override + { int _i; *fin >> _i; i = _i; return *this; } + Archive & operator & (bool & b) override + { char c; *fin >> c; b = (c=='t'); return *this; } + Archive & operator & (std::string & str) override + { + int len; + *fin >> len; + char ch; + fin->get(ch); // '\n' + str.resize(len); + if(len) + fin->get(&str[0], len+1, '\0'); + return *this; + } + Archive & operator & (char *& str) override + { + long len; + (*this) & len; + char ch; + if(len == -1) + { + str = nullptr; + return (*this); + } + str = new char[len+1]; // NOLINT + if(len) + { + fin->get(ch); // \n + fin->get(&str[0], len+1, '\0'); // NOLINT + } + str[len] = '\0'; // NOLINT + return *this; + } + }; +} // namespace ngcore + +#endif // NETGEN_CORE_ARCHIVE_HPP diff --git a/libsrc/core/ngcore.hpp b/libsrc/core/ngcore.hpp new file mode 100644 index 00000000..1c8fa591 --- /dev/null +++ b/libsrc/core/ngcore.hpp @@ -0,0 +1,7 @@ +#ifndef NETGEN_CORE_NGCORE_HPP +#define NETGEN_CORE_NGCORE_HPP + +#include "archive.hpp" +#include "version.hpp" + +#endif // NETGEN_CORE_NGCORE_HPP diff --git a/libsrc/core/ngcore_api.hpp b/libsrc/core/ngcore_api.hpp new file mode 100644 index 00000000..c08d0ac9 --- /dev/null +++ b/libsrc/core/ngcore_api.hpp @@ -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 diff --git a/libsrc/core/type_traits.hpp b/libsrc/core/type_traits.hpp new file mode 100644 index 00000000..3e7cd4b4 --- /dev/null +++ b/libsrc/core/type_traits.hpp @@ -0,0 +1,17 @@ +#ifndef NETGEN_CORE_TYPE_TRAITS_HPP +#define NETGEN_CORE_TYPE_TRAITS_HPP + +#include + +namespace ngcore +{ + namespace detail + { + template struct _BoolArray{}; + + template + constexpr bool all_of_tmpl = std::is_same<_BoolArray, _BoolArray<(vals || true)...>>::value; // NOLINT + } // namespace detail +} // namespace ngcore + +#endif // NETGEN_CORE_TYPE_TRAITS_HPP diff --git a/libsrc/core/version.hpp b/libsrc/core/version.hpp new file mode 100644 index 00000000..69598716 --- /dev/null +++ b/libsrc/core/version.hpp @@ -0,0 +1,88 @@ +#ifndef NETGEN_CORE_VERSION_HPP +#define NETGEN_CORE_VERSION_HPP + +#include +#include + +#include "ngcore_api.hpp" + +namespace ngcore +{ + class VersionInfo + { + private: + size_t mayor_{}, minor_{}, release{}, patch{}; + std::string git_hash{}; + public: + VersionInfo() = default; + VersionInfo(std::string vstring) + { + minor_ = release = patch = 0; + git_hash = ""; + if(vstring.substr(0,1) == "v") + vstring = vstring.substr(1,vstring.size()-1); + auto dot = vstring.find('.'); + mayor_ = std::stoi(vstring.substr(0,dot)); + if(dot == size_t(-1)) vstring = ""; + else vstring = vstring.substr(dot+1, vstring.size()-dot-1); + if(!vstring.empty()) + { + dot = vstring.find('.'); + minor_ = std::stoi(vstring.substr(0,dot)); + if (dot == size_t(-1)) vstring = ""; + else vstring = vstring.substr(dot+1, vstring.size()-dot-1); + if(!vstring.empty()) + { + dot = vstring.find('-'); + release = std::stoi(vstring.substr(0,dot)); + if(dot == size_t(-1)) vstring = ""; + else vstring = vstring.substr(dot+1,vstring.size()-dot-1); + if(!vstring.empty()) + { + dot = vstring.find('-'); + patch = std::stoi(vstring.substr(0,dot)); + if(dot == size_t(-1)) vstring = ""; + else vstring = vstring.substr(dot+1, vstring.size()-dot-1); + if(!vstring.empty()) + git_hash = vstring; + } + } + } + } + VersionInfo(const char* cstr) : VersionInfo(std::string(cstr)) { } + + std::string to_string() const + { std::string vstring = "v" + std::to_string(mayor_); + if(minor_ || release || patch || !git_hash.empty()) + { + vstring += "." + std::to_string(minor_); + if(release || patch || !git_hash.empty()) + { + vstring += "." + std::to_string(release); + if(patch || !git_hash.empty()) + { + vstring += "-" + std::to_string(patch); + if(!git_hash.empty()) + vstring += "-" + git_hash; + } + } + } + return vstring; + } + bool operator <(const VersionInfo& other) const + { + return std::tie(mayor_, minor_, release, patch) < + std::tie(other.mayor_, other.minor_, other.release, other.patch); + } + bool operator ==(const VersionInfo& other) const + { + return mayor_ == other.mayor_ && minor_ == other.minor_ && release == other.release + && patch == other.patch; + } + bool operator >(const VersionInfo& other) const { return other < (*this); } + bool operator <=(const VersionInfo& other) const { return !((*this) > other); } + bool operator >=(const VersionInfo& other) const { return !((*this) < other); } + }; +} // namespace ngcore + +#endif // NETGEN_CORE_VERSION_HPP diff --git a/libsrc/csg/algprim.cpp b/libsrc/csg/algprim.cpp index aa08c245..0f870d98 100644 --- a/libsrc/csg/algprim.cpp +++ b/libsrc/csg/algprim.cpp @@ -1949,6 +1949,13 @@ void EllipticCone :: GetTriangleApproximation << R << " " << r << endl; } - - +RegisterClassForArchive regqs; +RegisterClassForArchive regpl; +RegisterClassForArchive regsph; +RegisterClassForArchive regcyl; +RegisterClassForArchive regelcyl; +RegisterClassForArchive regell; +RegisterClassForArchive regcone; +RegisterClassForArchive regellcone; +RegisterClassForArchive regtorus; } diff --git a/libsrc/csg/algprim.hpp b/libsrc/csg/algprim.hpp index 30b46a0b..6daf643b 100644 --- a/libsrc/csg/algprim.hpp +++ b/libsrc/csg/algprim.hpp @@ -47,6 +47,11 @@ namespace netgen virtual void Print (ostream & str) const; virtual void Read (istream & ist); void PrintCoeff (ostream & ost) const; + virtual void DoArchive(Archive& ar) + { + OneSurfacePrimitive::DoArchive(ar); + ar & cxx & cyy & czz & cxy & cxz & cyz & cx & cy & cz & c1; + } }; @@ -64,6 +69,14 @@ namespace netgen public: /// Plane (const Point<3> & ap, Vec<3> an); + // default constructor for archive + Plane() {} + + virtual void DoArchive(Archive& ar) + { + QuadraticSurface::DoArchive(ar); + ar & p & n & eps_base; + } Point<3> P() const { return p; } Vec<3> N() const { return n; } virtual void GetPrimitiveData (const char *& classname, @@ -130,6 +143,14 @@ namespace netgen public: /// Sphere (const Point<3> & ac, double ar); + // default constructor for archive + Sphere() {} + + virtual void DoArchive(Archive& ar) + { + QuadraticSurface::DoArchive(ar); + ar & c & r & invr; + } virtual void GetPrimitiveData (const char *& classname, Array & coeffs) const; @@ -188,6 +209,14 @@ namespace netgen public: Cylinder (const Point<3> & aa, const Point<3> & ab, double ar); Cylinder (Array & coeffs); + // default constructor for archive + Cylinder() {} + + virtual void DoArchive(Archive& ar) + { + QuadraticSurface::DoArchive(ar); + ar & a & b & r & vab; + } Point<3> A() const { return a; } Point<3> B() const { return b; } double R() const { return r; } @@ -250,7 +279,14 @@ namespace netgen EllipticCylinder (const Point<3> & aa, const Vec<3> & avl, const Vec<3> & avs); EllipticCylinder (Array & coeffs); + // default constructor for archive + EllipticCylinder() {} + virtual void DoArchive(Archive& ar) + { + QuadraticSurface::DoArchive(ar); + ar & a & vl & vs & vab & t0vec & t1vec & vabl & t0 & t1; + } // static Primitive * CreateDefault (); virtual void GetPrimitiveData (const char *& classname, Array & coeffs) const; @@ -300,6 +336,14 @@ namespace netgen const Vec<3> & av1, const Vec<3> & av2, const Vec<3> & av3); + // default constructor for archive + Ellipsoid() {} + + virtual void DoArchive(Archive& ar) + { + QuadraticSurface::DoArchive(ar); + ar & a & v1 & v2 & v3 & rmin; + } /// virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; /// @@ -340,6 +384,14 @@ namespace netgen /// Cone (const Point<3> & aa, const Point<3> & ab, double ara, double arb); /// + // default constructor for archive + Cone() {} + + virtual void DoArchive(Archive& ar) + { + QuadraticSurface::DoArchive(ar); + ar & a & b & ra & rb & minr & vab & t0vec & t1vec & vabl & t0 & t1 & cosphi; + } static Primitive * CreateDefault (); virtual void GetPrimitiveData (const char *& classname, Array & coeffs) const; virtual void SetPrimitiveData (Array & coeffs); @@ -384,7 +436,14 @@ namespace netgen /// EllipticCone (const Point<3> & aa, const Vec<3> & avl, const Vec<3> & avs, double ah, double avlr); + // default constructor for archive + EllipticCone() {} + virtual void DoArchive(Archive& ar) + { + QuadraticSurface::DoArchive(ar); + ar & a & vl & vs & h & vlr; + } static Primitive * CreateDefault (); virtual void GetPrimitiveData (const char *& classname, Array & coeffs) const; virtual void SetPrimitiveData (Array & coeffs); @@ -426,6 +485,14 @@ namespace netgen public: /// OK Torus (const Point<3> & ac, const Vec<3> & an, double aR, double ar); + // default constructor for archive + Torus() {} + + virtual void DoArchive(Archive& ar) + { + OneSurfacePrimitive::DoArchive(ar); + ar & c & n & R & r; + } /// OK const Point<3> & Center () const { return c; } /// OK diff --git a/libsrc/csg/brick.cpp b/libsrc/csg/brick.cpp index 54c23b17..b9508fba 100644 --- a/libsrc/csg/brick.cpp +++ b/libsrc/csg/brick.cpp @@ -523,4 +523,8 @@ void OrthoBrick :: Reduce (const BoxSphere<3> & box) surfaceactive.Elem(6) = (box.PMin()(0) < pmax(0)) && (pmax(0) < box.PMax()(0)); } + +RegisterClassForArchive regpar; +RegisterClassForArchive regbrick; +RegisterClassForArchive regob; } diff --git a/libsrc/csg/brick.hpp b/libsrc/csg/brick.hpp index 25b003e0..7db7b02d 100644 --- a/libsrc/csg/brick.hpp +++ b/libsrc/csg/brick.hpp @@ -28,8 +28,16 @@ namespace netgen public: Parallelogram3d (Point<3> ap1, Point<3> ap2, Point<3> ap3); + // default constructor for archive + Parallelogram3d() {} virtual ~Parallelogram3d (); + virtual void DoArchive(Archive& ar) + { + Surface::DoArchive(ar); + ar & p1 & p2 & p3 & p4 & v12 & v13 & n; + } + void SetPoints (Point<3> ap1, Point<3> ap2, Point<3> ap3); virtual int IsIdentic (const Surface & s2, int & inv, double eps) const; @@ -60,7 +68,15 @@ namespace netgen public: Brick (Point<3> ap1, Point<3> ap2, Point<3> ap3, Point<3> ap4); + // default constructor for archive + Brick() {} virtual ~Brick (); + + virtual void DoArchive(Archive& ar) + { + Primitive::DoArchive(ar); + ar & p1 & p2 & p3 & p4 & v12 & v13 & v14 & faces; + } static Primitive * CreateDefault (); virtual Primitive * Copy () const; @@ -116,7 +132,15 @@ namespace netgen Point<3> pmin, pmax; public: OrthoBrick (const Point<3> & ap1, const Point<3> & ap2); - + // default constructor for archive + OrthoBrick() {} + + virtual void DoArchive(Archive& ar) + { + Brick::DoArchive(ar); + ar & pmin & pmax; + } + virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; virtual void Reduce (const BoxSphere<3> & box); }; diff --git a/libsrc/csg/csgeom.cpp b/libsrc/csg/csgeom.cpp index 40dda44e..b861d451 100644 --- a/libsrc/csg/csgeom.cpp +++ b/libsrc/csg/csgeom.cpp @@ -324,6 +324,14 @@ namespace netgen } + void CSGeometry :: DoArchive(Archive& archive) + { + archive & surfaces & solids & toplevelobjects & userpoints & userpoints_ref_factor + & identpoints & boundingbox & isidenticto & ideps + & filename & spline_surfaces & splinecurves2d & splinecurves3d & surf2prim; + if(archive.Input()) + FindIdenticSurfaces(1e-6); + } void CSGeometry :: SaveSurfaces (ostream & out) const { diff --git a/libsrc/csg/csgeom.hpp b/libsrc/csg/csgeom.hpp index f9266de4..f1a8d8b6 100644 --- a/libsrc/csg/csgeom.hpp +++ b/libsrc/csg/csgeom.hpp @@ -39,7 +39,14 @@ namespace netgen public: TopLevelObject (Solid * asolid, Surface * asurface = NULL); + // default constructor for archive + TopLevelObject() {} + void DoArchive(Archive& archive) + { + archive & solid & surface & red & blue & green & visible & transp & maxh + & material & layer & bc & bcname; + } const Solid * GetSolid() const { return solid; } Solid * GetSolid() { return solid; } @@ -124,6 +131,11 @@ namespace netgen UserPoint() = default; UserPoint (Point<3> p, int _index) : Point<3>(p), index(_index) { ; } int GetIndex() const { return index; } + void DoArchive(Archive& archive) + { + archive & index; + Point<3>::DoArchive(archive); + } }; private: @@ -198,6 +210,8 @@ namespace netgen void SetSplineCurve (const char * name, SplineGeometry<3> * spl); const SplineGeometry<2> * GetSplineCurve2d (const string & name) const; const SplineGeometry<3> * GetSplineCurve3d (const string & name) const; + + void DoArchive(Archive& archive); void SetFlags (const char * solidname, const Flags & flags); diff --git a/libsrc/csg/extrusion.cpp b/libsrc/csg/extrusion.cpp index 8b257c20..61446b0c 100644 --- a/libsrc/csg/extrusion.cpp +++ b/libsrc/csg/extrusion.cpp @@ -653,15 +653,15 @@ namespace netgen Extrusion :: Extrusion(const SplineGeometry<3> & path_in, const SplineGeometry<2> & profile_in, const Vec<3> & z_dir) : - path(path_in), profile(profile_in), z_direction(z_dir) + path(&path_in), profile(&profile_in), z_direction(z_dir) { surfaceactive.SetSize(0); surfaceids.SetSize(0); - for(int j=0; jGetNSplines(); j++) { - ExtrusionFace * face = new ExtrusionFace(&(profile.GetSpline(j)), - &path, + ExtrusionFace * face = new ExtrusionFace(&((*profile).GetSpline(j)), + path, z_direction); faces.Append(face); surfaceactive.Append(true); @@ -872,5 +872,6 @@ namespace netgen surfaceactive[i] = true; } - + RegisterClassForArchive regexf; + RegisterClassForArchive regextr; } diff --git a/libsrc/csg/extrusion.hpp b/libsrc/csg/extrusion.hpp index e80ac244..2d6b3bbe 100644 --- a/libsrc/csg/extrusion.hpp +++ b/libsrc/csg/extrusion.hpp @@ -49,9 +49,18 @@ namespace netgen const Vec<3> & z_direction); ExtrusionFace(const Array & raw_data); - + // default constructor for archive + ExtrusionFace() {} ~ExtrusionFace(); + + virtual void DoArchive(Archive& ar) + { + Surface::DoArchive(ar); + ar & profile & path & glob_z_direction & deletable & spline3_path & line_path & + x_dir & y_dir & z_dir & loc_z_dir & p0 & profile_tangent & profile_par & + profile_spline_coeff & latest_seg & latest_t & latest_point2d & latest_point3d; + } virtual int IsIdentic (const Surface & s2, int & inv, double eps) const; @@ -109,10 +118,10 @@ namespace netgen class Extrusion : public Primitive { private: - const SplineGeometry<3> & path; - const SplineGeometry<2> & profile; // closed, clockwise oriented curve + const SplineGeometry<3>* path; + const SplineGeometry<2>* profile; // closed, clockwise oriented curve - const Vec<3> & z_direction; + Vec<3> z_direction; Array faces; @@ -122,7 +131,15 @@ namespace netgen Extrusion(const SplineGeometry<3> & path_in, const SplineGeometry<2> & profile_in, const Vec<3> & z_dir); + // default constructor for archive + Extrusion() {} ~Extrusion(); + + virtual void DoArchive(Archive& ar) + { + Primitive::DoArchive(ar); + ar & path & profile & z_direction & faces & latestfacenum; + } virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const; virtual INSOLID_TYPE PointInSolid (const Point<3> & p, double eps) const; diff --git a/libsrc/csg/python_csg.cpp b/libsrc/csg/python_csg.cpp index f63cc192..6ed85a22 100644 --- a/libsrc/csg/python_csg.cpp +++ b/libsrc/csg/python_csg.cpp @@ -364,37 +364,31 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails! py::class_> (m, "CSGeometry") .def(py::init<>()) - .def("__init__", - [](CSGeometry *instance, const string & filename) - { - cout << "load geometry"; - ifstream ist(filename); - ParseCSG(ist, instance); - instance -> FindIdenticSurfaces(1e-8 * instance->MaxSize()); - }) - .def("__init__", - [](CSGeometry *instance, const py::list & solidlist) - { - cout << "csg from list"; - new (instance) CSGeometry(); - for (int i = 0; i < len(solidlist); i++) - { - py::object obj = solidlist[i]; - cout << "obj " << i << endl; - - py::extract> solid(solidlist[i]); - if(solid.check()) - { - cout << "its a solid" << endl; - solid()->AddSurfaces (*instance); - solid()->GiveUpOwner(); - int tlonr = instance->SetTopLevelObject (solid()->GetSolid()); - instance->GetTopLevelObject(tlonr) -> SetMaterial(solid()->GetMaterial()); - } - } - instance -> FindIdenticSurfaces(1e-8 * instance->MaxSize()); - }) - + .def(py::init([](const string& filename) + { + ifstream ist (filename); + auto geo = make_shared(); + ParseCSG(ist, geo.get()); + geo->FindIdenticSurfaces(1e-8 * geo->MaxSize()); + return geo; + }), py::arg("filename")) + .def(py::pickle( + [](CSGeometry& self) + { + auto ss = make_shared(); + BinaryOutArchive archive(ss); + archive & self; + archive.FlushBuffer(); + return py::make_tuple(py::bytes(ss->str())); + }, + [](py::tuple state) + { + auto geo = make_shared(); + auto ss = make_shared (py::cast(state[0])); + BinaryInArchive archive(ss); + archive & (*geo); + return geo; + })) .def("Save", FunctionPointer([] (CSGeometry & self, string filename) { cout << "save geometry to file " << filename << endl; diff --git a/libsrc/csg/revolution.cpp b/libsrc/csg/revolution.cpp index 4c13c109..dac2e277 100644 --- a/libsrc/csg/revolution.cpp +++ b/libsrc/csg/revolution.cpp @@ -640,9 +640,9 @@ namespace netgen Revolution :: Revolution(const Point<3> & p0_in, const Point<3> & p1_in, const SplineGeometry<2> & spline_in) : - p0(p0_in), p1(p1_in), splinecurve(spline_in), - nsplines(spline_in.GetNSplines()) + p0(p0_in), p1(p1_in) { + auto nsplines = spline_in.GetNSplines(); surfaceactive.SetSize(0); surfaceids.SetSize(0); @@ -650,21 +650,21 @@ namespace netgen v_axis.Normalize(); - if(splinecurve.GetSpline(0).StartPI()(1) <= 0. && - splinecurve.GetSpline(nsplines-1).EndPI()(1) <= 0.) + if(spline_in.GetSpline(0).StartPI()(1) <= 0. && + spline_in.GetSpline(nsplines-1).EndPI()(1) <= 0.) type = 2; - else if (Dist(splinecurve.GetSpline(0).StartPI(), - splinecurve.GetSpline(nsplines-1).EndPI()) < 1e-7) + else if (Dist(spline_in.GetSpline(0).StartPI(), + spline_in.GetSpline(nsplines-1).EndPI()) < 1e-7) type = 1; else cerr << "Surface of revolution cannot be constructed" << endl; - for(int i=0; i regrevf; + RegisterClassForArchive regrev; } diff --git a/libsrc/csg/revolution.hpp b/libsrc/csg/revolution.hpp index c9b4cb92..879829fd 100644 --- a/libsrc/csg/revolution.hpp +++ b/libsrc/csg/revolution.hpp @@ -45,9 +45,18 @@ namespace netgen const int id_in = 0); RevolutionFace(const Array & raw_data); + // default constructor for archive + RevolutionFace() {} ~RevolutionFace(); + virtual void DoArchive(Archive& ar) + { + Surface::DoArchive(ar); + ar & isfirst & islast & spline & deletable & p0 & v_axis & id & spline_coefficient + & spline_coefficient_shifted & checklines_vec & checklines_start & checklines_normal; + } + virtual int IsIdentic (const Surface & s2, int & inv, double eps) const; virtual double CalcFunctionValue (const Point<3> & point) const; @@ -96,8 +105,6 @@ namespace netgen private: Point<3> p0,p1; Vec<3> v_axis; - const SplineGeometry<2> & splinecurve; - const int nsplines; // 1 ... torus-like // 2 ... sphere-like @@ -112,9 +119,16 @@ namespace netgen Revolution(const Point<3> & p0_in, const Point<3> & p1_in, const SplineGeometry<2> & spline_in); + // default constructor for archive + Revolution() {} ~Revolution(); - + + virtual void DoArchive(Archive& ar) + { + Primitive::DoArchive(ar); + ar & p0 & p1 & v_axis & type & faces & intersecting_face; + } /* Check, whether box intersects solid defined by surface. diff --git a/libsrc/csg/solid.hpp b/libsrc/csg/solid.hpp index 724030bd..4d620c04 100644 --- a/libsrc/csg/solid.hpp +++ b/libsrc/csg/solid.hpp @@ -55,8 +55,22 @@ namespace netgen public: Solid (Primitive * aprim); Solid (optyp aop, Solid * as1, Solid * as2 = NULL); + // default constructor for archive + Solid () {} ~Solid (); + void DoArchive(Archive& archive) + { + archive & name & prim & s1 & s2 & visited & maxh & num_surfs; + if(archive.Output()) + archive << int(op); + else + { + int iop; + archive & iop; + op = optyp(iop); + } + } const char * Name () const { return name; } void SetName (const char * aname); diff --git a/libsrc/csg/surface.cpp b/libsrc/csg/surface.cpp index db315e99..f829840b 100644 --- a/libsrc/csg/surface.cpp +++ b/libsrc/csg/surface.cpp @@ -566,4 +566,8 @@ void ProjectToEdge (const Surface * f1, const Surface * f2, Point<3> & hp) if (Abs2 (rs) < 1e-24 && i > 1) i = 1; } } + +RegisterClassForArchive regsurf; +RegisterClassForArchive regprim; +RegisterClassForArchive regosf; } diff --git a/libsrc/csg/surface.hpp b/libsrc/csg/surface.hpp index 5e9afbdf..39a6ceee 100644 --- a/libsrc/csg/surface.hpp +++ b/libsrc/csg/surface.hpp @@ -63,6 +63,12 @@ namespace netgen //@} public: + virtual void DoArchive(Archive& archive) + { + archive & inverse & maxh & name & bcprop & bcname + & p1 & p2 & ex & ey & ez; + } + void SetName (const char * aname); const char * Name () const { return name; } @@ -234,6 +240,9 @@ namespace netgen class Primitive { + protected: + Array surfaceids; + Array surfaceactive; public: @@ -241,6 +250,10 @@ namespace netgen virtual ~Primitive(); + virtual void DoArchive(Archive& archive) + { + archive & surfaceids & surfaceactive; + } /* Check, whether box intersects solid defined by surface. @@ -299,9 +312,6 @@ namespace netgen virtual Surface & GetSurface (int i = 0) = 0; virtual const Surface & GetSurface (int i = 0) const = 0; - Array surfaceids; - Array surfaceactive; - int GetSurfaceId (int i = 0) const; void SetSurfaceId (int i, int id); int SurfaceActive (int i) const { return surfaceactive[i]; } @@ -329,6 +339,12 @@ namespace netgen OneSurfacePrimitive(); ~OneSurfacePrimitive(); + virtual void DoArchive(Archive& archive) + { + Surface::DoArchive(archive); + Primitive::DoArchive(archive); + } + virtual INSOLID_TYPE PointInSolid (const Point<3> & p, double eps) const; virtual INSOLID_TYPE VecInSolid (const Point<3> & p, diff --git a/libsrc/general/CMakeLists.txt b/libsrc/general/CMakeLists.txt index 5faf7c6c..00c59ea2 100644 --- a/libsrc/general/CMakeLists.txt +++ b/libsrc/general/CMakeLists.txt @@ -11,7 +11,7 @@ set_target_properties( gen PROPERTIES POSITION_INDEPENDENT_CODE ON ) install( FILES ngexception.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE} COMPONENT netgen_devel ) install(FILES - archive_base.hpp array.hpp autodiff.hpp autoptr.hpp bitarray.hpp + array.hpp autodiff.hpp autoptr.hpp bitarray.hpp dynamicmem.hpp flags.hpp hashtabl.hpp mpi_interface.hpp myadt.hpp ngsimd.hpp mystring.hpp netgenout.hpp ngexception.hpp ngpython.hpp optmem.hpp parthreads.hpp profiler.hpp seti.hpp sort.hpp diff --git a/libsrc/general/archive_base.hpp b/libsrc/general/archive_base.hpp deleted file mode 100644 index 9e74b0e5..00000000 --- a/libsrc/general/archive_base.hpp +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef NGS_ARCHIVE_BASE -#define NGS_ARCHIVE_BASE - -// copied from netgen - -#include -#include - -namespace ngstd -{ - - class Archive - { - bool is_output; - public: - Archive (bool ais_output) : is_output(ais_output) { ; } - virtual ~Archive() { ; } - - bool Output () { return is_output; } - bool Input () { return !is_output; } - - 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 & (string & str) = 0; - virtual Archive & operator & (char *& str) = 0; - - template - 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; }; - - - // nvirtual Archive & Do (string * str, size_t n) - // { for (size_t j = 0; j < n; j++) { (*this) & str[j]; }; return *this; }; - // virtual Archive & operator & (char *& str) = 0; - - - // archive a pointer ... - - int cnt = 0; - std::map ptr2nr; - std::vector nr2ptr; - - /* - // necessary for msvc ??? - Archive & operator& (string* & ps) - { - return operator& (ps); - } - */ - - template - Archive & operator& (T *& p) - { - if (Output()) - { - if (!p) - { - int m2 = -2; - (*this) & m2; - return *this; - } - auto pos = ptr2nr.find( (void*) p); - if (pos == ptr2nr.end()) - { - ptr2nr[p] = cnt; - int m1 = -1; - (*this) & m1; - cnt++; - (*this) & (*p); - } - else - { - (*this) & pos->second; - } - } - else - { - int nr; - (*this) & nr; - // cout << "in, got nr " << nr << endl; - if (nr == -2) - { - p = nullptr; - } - else if (nr == -1) - { - p = new T; - // cout << "create new ptr, p = " << p << endl; - (*this) & *p; - nr2ptr.push_back(p); - } - else - { - p = (T*)nr2ptr[nr]; - // cout << "reuse ptr " << nr << ": " << p << endl; - } - } - return *this; - } - - - - - template - Archive & operator << (const T & t) - { - T ht(t); - (*this) & ht; - return *this; - } - }; - - -} - - -#endif diff --git a/libsrc/general/array.hpp b/libsrc/general/array.hpp index ead43dac..16bb6e78 100644 --- a/libsrc/general/array.hpp +++ b/libsrc/general/array.hpp @@ -400,6 +400,21 @@ namespace netgen ownmem = false; return data; } + + // Only provide this function if T is archivable + template + auto DoArchive(Archive& archive) -> typename std::enable_if, void>::type + { + if(archive.Output()) + archive << size; + else + { + size_t s; + archive & s; + SetSize(s); + } + archive.Do(data, size); + } private: @@ -778,30 +793,6 @@ namespace netgen if(in2.Contains(in1[i]) && in3.Contains(in1[i])) out.Append(in1[i]); } - - - - - template - ngstd::Archive & operator & (ngstd::Archive & archive, Array & a) - { - if (archive.Output()) - archive << a.Size(); - else - { - size_t size; - archive & size; - a.SetSize (size); - } - - /* - for (auto & ai : a) - archive & ai; - */ - archive.Do (&a[BASE], a.Size()); - return archive; - } - } #endif diff --git a/libsrc/general/hashtabl.hpp b/libsrc/general/hashtabl.hpp index 0898e58f..4d8fadc8 100644 --- a/libsrc/general/hashtabl.hpp +++ b/libsrc/general/hashtabl.hpp @@ -259,20 +259,13 @@ public: const T & GetData (const Iterator & it) const { return cont[it.BagNr()][it.Pos()]; } - ngstd::Archive & DoArchive (ngstd::Archive & ar) + void DoArchive (Archive & ar) { ar & hash & cont; - return ar; } }; - template - inline ngstd::Archive & operator & (ngstd::Archive & archive, INDEX_2_HASHTABLE & mp) - { return mp.DoArchive(archive); } - - - template inline ostream & operator<< (ostream & ost, const INDEX_2_HASHTABLE & ht) { @@ -436,24 +429,15 @@ public: { return cont[it.BagNr()][it.Pos()]; } - ngstd::Archive & DoArchive (ngstd::Archive & ar) + void DoArchive (Archive & ar) { ar & hash & cont; - return ar; } }; - - template - inline ngstd::Archive & operator & (ngstd::Archive & archive, INDEX_3_HASHTABLE & mp) - { return mp.DoArchive(archive); } - - - - template inline ostream & operator<< (ostream & ost, const INDEX_3_HASHTABLE & ht) { diff --git a/libsrc/general/myadt.hpp b/libsrc/general/myadt.hpp index 7c4374d8..601a3da0 100644 --- a/libsrc/general/myadt.hpp +++ b/libsrc/general/myadt.hpp @@ -17,11 +17,15 @@ #include "../include/mydefs.hpp" +#include "../core/ngcore.hpp" +namespace netgen +{ + using namespace ngcore; +} #include "ngexception.hpp" #include "parthreads.hpp" // #include "moveablemem.hpp" #include "dynamicmem.hpp" -#include "archive_base.hpp" #include "template.hpp" #include "array.hpp" diff --git a/libsrc/general/ngpython.hpp b/libsrc/general/ngpython.hpp index dacbb822..fa9862b1 100644 --- a/libsrc/general/ngpython.hpp +++ b/libsrc/general/ngpython.hpp @@ -1,28 +1,5 @@ #ifdef NG_PYTHON -// BEGIN EVIL HACK: Patch PyThread_get_key_value/PyThread_tss_get inside pybind11 to avoid deadlocks -// see https://github.com/pybind/pybind11/pull/1211 (please merge!) -#if defined(__GNUG__) && !defined(__clang__) -# pragma GCC diagnostic ignored "-Wattributes" -#endif -#include -#include -#include -#undef PYBIND11_TLS_GET_VALUE -#if PY_VERSION_HEX >= 0x03070000 - inline void * PYBIND11_TLS_GET_VALUE(Py_tss_t *state) { - PyThreadState *tstate = (PyThreadState *) PyThread_tss_get(state); - if (!tstate) tstate = PyGILState_GetThisThreadState(); - return tstate; - } -#else - inline void * PYBIND11_TLS_GET_VALUE(int state) { - PyThreadState *tstate = (PyThreadState *) PyThread_get_key_value(state); - if (!tstate) tstate = PyGILState_GetThisThreadState(); - return tstate; - } -#endif -// END EVIL HACK #include #include #include diff --git a/libsrc/general/symbolta.hpp b/libsrc/general/symbolta.hpp index c246347f..b599ea42 100644 --- a/libsrc/general/symbolta.hpp +++ b/libsrc/general/symbolta.hpp @@ -69,6 +69,8 @@ public: /// Deletes symboltable inline void DeleteAll (); + void DoArchive(Archive& archive) { archive & names & data;} + inline T & operator[] (int i) { return data[i]; } inline const T & operator[] (int i) const diff --git a/libsrc/general/table.cpp b/libsrc/general/table.cpp index 6769e03c..c964c470 100644 --- a/libsrc/general/table.cpp +++ b/libsrc/general/table.cpp @@ -213,7 +213,7 @@ namespace netgen - ngstd::Archive & BASE_TABLE :: DoArchive (ngstd::Archive & ar, int elemsize) + void BASE_TABLE :: DoArchive (Archive & ar, int elemsize) { if (ar.Output()) { @@ -248,7 +248,6 @@ namespace netgen cnt += data[i].size*elemsize; } } - return ar; } diff --git a/libsrc/general/table.hpp b/libsrc/general/table.hpp index e112e135..6a08b3dc 100644 --- a/libsrc/general/table.hpp +++ b/libsrc/general/table.hpp @@ -89,7 +89,7 @@ public: void SetElementSizesToMaxSizes (); - ngstd::Archive & DoArchive (ngstd::Archive & ar, int elemsize); + void DoArchive (Archive & ar, int elemsize); }; @@ -238,21 +238,13 @@ public: return FlatArray (data[i-BASE].size, (T*)data[i-BASE].col); } - ngstd::Archive & DoArchive (ngstd::Archive & ar) + void DoArchive (Archive & ar) { - return BASE_TABLE::DoArchive(ar, sizeof(T)); + BASE_TABLE::DoArchive(ar, sizeof(T)); } }; - -template - inline ngstd::Archive & operator & (ngstd::Archive & archive, TABLE & mp) - { return mp.DoArchive(archive); } - - - - template inline ostream & operator<< (ostream & ost, const TABLE & table) { diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index 208d0c2b..43193e3a 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -207,6 +207,9 @@ namespace netgen // mesh size restrictions ... + + for (auto & point : geompoints) + mesh2d.RestrictLocalH (Point<3> (point(0), point(1), 0), point.hmax); for (int i = 0; i < splines.Size(); i++) { @@ -240,7 +243,21 @@ namespace netgen for (auto mspnt : mp.meshsize_points) mesh2d.RestrictLocalH (mspnt.pnt, mspnt.h); - + + // add point elements + for (auto & point : geompoints) + if (point.name.length()) + { + Point<3> newp(point(0), point(1), 0); + PointIndex npi = mesh2d.AddPoint (newp, 1, FIXEDPOINT); + mesh2d.AddLockedPoint(npi); + Element0d el(npi, npi); + el.name = point.name; + mesh2d.SetCD2Name(npi, point.name); + mesh2d.pointelements.Append (el); + searchtree.Insert (newp, npi); + } + // first add all vertices (for compatible orientation on periodic bnds) { double diam2 = Dist2(pmin, pmax); @@ -584,8 +601,10 @@ namespace netgen // not complete, use at own risk ... // meshing.Delaunay(*mesh, domnr, mp); mp.checkoverlap = 0; - meshing.GenerateMesh (*mesh, mp, h, domnr); - + auto res = meshing.GenerateMesh (*mesh, mp, h, domnr); + if (res != 0) + throw NgException("meshing failed"); + for (SurfaceElementIndex sei = oldnf; sei < mesh->GetNSE(); sei++) (*mesh)[sei].SetIndex (domnr); diff --git a/libsrc/geom2d/geom2dmesh.cpp b/libsrc/geom2d/geom2dmesh.cpp index 3de7f97f..be1fc6c9 100644 --- a/libsrc/geom2d/geom2dmesh.cpp +++ b/libsrc/geom2d/geom2dmesh.cpp @@ -47,8 +47,8 @@ namespace netgen auto ext = dynamic_cast(spline); if(ext) { - ss3 = dynamic_cast *>(&ext->seg); - ls = dynamic_cast *>(&ext->seg); + ss3 = dynamic_cast *>(ext->seg); + ls = dynamic_cast *>(ext->seg); } else { diff --git a/libsrc/geom2d/geometry2d.hpp b/libsrc/geom2d/geometry2d.hpp index ad02f754..d9704577 100644 --- a/libsrc/geom2d/geometry2d.hpp +++ b/libsrc/geom2d/geometry2d.hpp @@ -21,7 +21,7 @@ namespace netgen class SplineSegExt : public SplineSeg<2> { public: - const SplineSeg<2> & seg; + SplineSeg<2>* seg; /// left domain int leftdom; @@ -42,35 +42,43 @@ namespace netgen /// int layer; - SplineSegExt (const SplineSeg<2> & hseg) - : seg(hseg) + SplineSegExt (SplineSeg<2> & hseg) + : seg(&hseg) { layer = 1; } + // default constructor for archive + SplineSegExt() {} ~SplineSegExt () { - delete &seg; + delete seg; + } + + virtual void DoArchive(Archive& ar) + { + ar & seg & leftdom & rightdom & reffak & hmax & bc & copyfrom + & hpref_left & hpref_right & layer; } virtual const GeomPoint<2> & StartPI () const { - return seg.StartPI(); + return seg->StartPI(); } virtual const GeomPoint<2> & EndPI () const { - return seg.EndPI(); + return seg->EndPI(); } virtual Point<2> GetPoint (double t) const { - return seg.GetPoint(t); + return seg->GetPoint(t); } virtual Vec<2> GetTangent (const double t) const { - return seg.GetTangent(t); + return seg->GetTangent(t); } virtual void GetDerivatives (const double t, @@ -78,27 +86,27 @@ namespace netgen Vec<2> & first, Vec<2> & second) const { - seg.GetDerivatives (t, point, first, second); + seg->GetDerivatives (t, point, first, second); } virtual void GetCoeff (Vector & coeffs) const { - seg.GetCoeff (coeffs); + seg->GetCoeff (coeffs); } virtual void GetPoints (int n, Array > & points) const { - seg.GetPoints (n, points); + seg->GetPoints (n, points); } virtual double MaxCurvature () const { - return seg.MaxCurvature(); + return seg->MaxCurvature(); } virtual string GetType () const { - return seg.GetType(); + return seg->GetType(); } virtual double CalcCurvature (double t) const @@ -112,7 +120,7 @@ namespace netgen virtual bool InConvexHull (Point<2> p, double eps) const { - return seg.InConvexHull (p, eps); + return seg->InConvexHull (p, eps); } }; diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index f44b525e..d6abe3b8 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -31,7 +31,7 @@ DLL_HEADER void ExportGeom2d(py::module &m) .def("Load",&SplineGeometry2d::Load) .def("AppendPoint", FunctionPointer - ([](SplineGeometry2d &self, double px, double py, double maxh, double hpref) + ([](SplineGeometry2d &self, double px, double py, double maxh, double hpref, string name) { Point<2> p; p(0) = px; @@ -39,10 +39,11 @@ DLL_HEADER void ExportGeom2d(py::module &m) GeomPoint<2> gp(p); gp.hmax = maxh; gp.hpref = hpref; + gp.name = name; self.geompoints.Append(gp); return self.geompoints.Size()-1; }), - py::arg("x"), py::arg("y"), py::arg("maxh") = 1e99, py::arg("hpref")=0) + py::arg("x"), py::arg("y"), py::arg("maxh") = 1e99, py::arg("hpref")=0, py::arg("name")="") .def("Append", FunctionPointer([](SplineGeometry2d &self, py::list segment, int leftdomain, int rightdomain, py::object bc, py::object copy, double maxh, double hpref) { diff --git a/libsrc/gprim/geomobjects.hpp b/libsrc/gprim/geomobjects.hpp index 388e9a54..ad215278 100644 --- a/libsrc/gprim/geomobjects.hpp +++ b/libsrc/gprim/geomobjects.hpp @@ -64,6 +64,12 @@ namespace netgen const T & operator() (int i) const { return x[i]; } operator const T* () const { return x; } + + void DoArchive(Archive& archive) + { + for(int i=0; i @@ -117,6 +123,12 @@ namespace netgen operator const T* () const { return x; } + void DoArchive(Archive& archive) + { + for(int i=0; i - inline Point SplineSeg3 :: GetPoint (double t) const + Point SplineSeg3 :: GetPoint (double t) const { double b1, b2, b3; @@ -551,11 +551,10 @@ namespace netgen template class SplineSeg3<2>; template class SplineSeg3<3>; - - - - - - - + RegisterClassForArchive> regss2; + RegisterClassForArchive> regss3; + RegisterClassForArchive, SplineSeg<2>> regls2; + RegisterClassForArchive, SplineSeg<3>> regls3; + RegisterClassForArchive, SplineSeg<2>> regsss2; + RegisterClassForArchive, SplineSeg<3>> regsss3; } diff --git a/libsrc/gprim/spline.hpp b/libsrc/gprim/spline.hpp index a628d07d..71700189 100644 --- a/libsrc/gprim/spline.hpp +++ b/libsrc/gprim/spline.hpp @@ -28,13 +28,19 @@ namespace netgen double hmax; /// hp-refinement double hpref; - + /// + string name; /// GeomPoint () { ; } /// GeomPoint (const Point & ap, double aref = 1, double ahpref=0) : Point(ap), refatpoint(aref), hmax(1e99), hpref(ahpref) { ; } + void DoArchive(Archive& ar) + { + Point::DoArchive(ar); + ar & refatpoint & hmax & hpref; + } }; @@ -72,6 +78,7 @@ namespace netgen second = 1.0/sqr(eps) * ( (pr-point)+(pl-point)); } + virtual void DoArchive(Archive& ar) = 0; /// returns initial point on curve virtual const GeomPoint & StartPI () const = 0; @@ -122,6 +129,12 @@ namespace netgen /// LineSeg (const GeomPoint & ap1, const GeomPoint & ap2); /// + // default constructor for archive + LineSeg() {} + virtual void DoArchive(Archive& ar) + { + ar & p1 & p2; + } virtual double Length () const; /// inline virtual Point GetPoint (double t) const; @@ -172,8 +185,14 @@ namespace netgen SplineSeg3 (const GeomPoint & ap1, const GeomPoint & ap2, const GeomPoint & ap3); + // default constructor for archive + SplineSeg3() {} /// - inline virtual Point GetPoint (double t) const; + virtual void DoArchive(Archive& ar) + { + ar & p1 & p2 & p3 & weight & proj_latest_t; + } + virtual Point GetPoint (double t) const; /// virtual Vec GetTangent (const double t) const; @@ -226,6 +245,12 @@ namespace netgen CircleSeg (const GeomPoint & ap1, const GeomPoint & ap2, const GeomPoint & ap3); + // default constructor for archive + CircleSeg() {} + virtual void DoArchive(Archive& ar) + { + ar & p1 & p2 & p3 & pm & radius & w1 & w3; + } /// virtual Point GetPoint (double t) const; /// @@ -270,6 +295,12 @@ namespace netgen public: /// DiscretePointsSeg (const Array > & apts); + // default constructor for archive + DiscretePointsSeg() {} + virtual void DoArchive(Archive& ar) + { + ar & pts & p1n & p2n; + } /// virtual ~DiscretePointsSeg (); /// @@ -624,8 +655,14 @@ namespace netgen /// BSplineSeg (const Array > & apts); /// + //default constructor for archive + BSplineSeg() {} virtual ~BSplineSeg(); /// + virtual void DoArchive(Archive& ar) + { + ar & pts & p1n & p2n & ti; + } virtual Point GetPoint (double t) const; /// virtual const GeomPoint & StartPI () const { return p1n; }; diff --git a/libsrc/gprim/splinegeometry.hpp b/libsrc/gprim/splinegeometry.hpp index 16574516..8e01cc62 100644 --- a/libsrc/gprim/splinegeometry.hpp +++ b/libsrc/gprim/splinegeometry.hpp @@ -55,6 +55,10 @@ namespace netgen // void SetGrading (const double grading); DLL_HEADER void AppendPoint (const Point & p, const double reffac = 1., const bool hpref = false); + void DoArchive(Archive& ar) + { + ar & geompoints & splines; + } void AppendSegment(SplineSeg * spline) { diff --git a/libsrc/include/nginterface_v2.hpp b/libsrc/include/nginterface_v2.hpp index 580a340a..33a596db 100644 --- a/libsrc/include/nginterface_v2.hpp +++ b/libsrc/include/nginterface_v2.hpp @@ -230,7 +230,7 @@ namespace netgen void LoadMesh (istream & str); void SaveMesh (ostream & str) const; void UpdateTopology (); - void DoArchive (ngstd::Archive & archive); + void DoArchive (Archive & archive); virtual ~Ngx_Mesh(); diff --git a/libsrc/include/nginterface_v2_impl.hpp b/libsrc/include/nginterface_v2_impl.hpp index aa538761..62e8068d 100644 --- a/libsrc/include/nginterface_v2_impl.hpp +++ b/libsrc/include/nginterface_v2_impl.hpp @@ -47,6 +47,7 @@ NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<0> (size_t nr) const Ng_Element ret; ret.type = NG_PNT; ret.index = el.index; + ret.mat = &el.name; ret.points.num = 1; ret.points.ptr = (int*)&el.pnum; diff --git a/libsrc/interface/CMakeLists.txt b/libsrc/interface/CMakeLists.txt index ef52c30b..cb460fae 100644 --- a/libsrc/interface/CMakeLists.txt +++ b/libsrc/interface/CMakeLists.txt @@ -9,9 +9,7 @@ add_library(interface ${NG_LIB_TYPE} if(NOT WIN32) target_link_libraries(interface mesh csg geom2d) - if(USE_GUI) - target_link_libraries(interface visual) - endif(USE_GUI) + target_link_libraries(interface visual) install( TARGETS interface ${NG_INSTALL_DIR}) endif(NOT WIN32) diff --git a/libsrc/interface/nginterface_v2.cpp b/libsrc/interface/nginterface_v2.cpp index 5e2bbd34..fee63976 100644 --- a/libsrc/interface/nginterface_v2.cpp +++ b/libsrc/interface/nginterface_v2.cpp @@ -69,7 +69,7 @@ namespace netgen mesh -> Save (ost); } - void Ngx_Mesh :: DoArchive (ngstd::Archive & archive) + void Ngx_Mesh :: DoArchive (Archive & archive) { if (archive.Input()) mesh = make_shared(); mesh->DoArchive(archive); diff --git a/libsrc/linalg/vector.hpp b/libsrc/linalg/vector.hpp index dec8b57d..97ad05ed 100644 --- a/libsrc/linalg/vector.hpp +++ b/libsrc/linalg/vector.hpp @@ -139,6 +139,14 @@ public: ~Vector () { if (ownmem) delete [] data; } + virtual void DoArchive(Archive& ar) + { + auto size = s; + ar & ownmem & size; + if(!ar.Output()) + SetSize(size); + ar.Do(data, size); + } Vector & operator= (const FlatVector & v) { memcpy (data, &v(0), s*sizeof(double)); return *this; } diff --git a/libsrc/meshing/CMakeLists.txt b/libsrc/meshing/CMakeLists.txt index e9e6e211..bc9f7f18 100644 --- a/libsrc/meshing/CMakeLists.txt +++ b/libsrc/meshing/CMakeLists.txt @@ -30,7 +30,7 @@ if(APPLE) endif(APPLE) 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}) endif(NOT WIN32) diff --git a/libsrc/meshing/adfront2.cpp b/libsrc/meshing/adfront2.cpp index 7eb426ad..11dd7421 100644 --- a/libsrc/meshing/adfront2.cpp +++ b/libsrc/meshing/adfront2.cpp @@ -22,7 +22,7 @@ namespace netgen mgi = new MultiPointGeomInfo (*amgi); for (int i = 1; i <= mgi->GetNPGI(); i++) if (mgi->GetPGI(i).trignum <= 0) - cout << "Add FrontPoint2, illegal geominfo = " << mgi->GetPGI(i).trignum << endl; + cout << "WARNING: Add FrontPoint2, illegal geominfo = " << mgi->GetPGI(i).trignum << endl; } else mgi = NULL; @@ -136,7 +136,7 @@ namespace netgen if (!gi1.trignum || !gi2.trignum) { - cout << "ERROR: in AdFront::AddLine, illegal geominfo" << endl; + cout << "WARNING: in AdFront::AddLine, illegal geominfo" << endl; } lines[li].SetGeomInfo (gi1, gi2); diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index 78a8be18..9ec9aed3 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -1304,7 +1304,7 @@ namespace netgen } - void Mesh :: DoArchive (ngstd::Archive & archive) + void Mesh :: DoArchive (Archive & archive) { archive & dimension; archive & points; diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index 2de6d3ee..fe72de2a 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -517,7 +517,7 @@ namespace netgen DLL_HEADER void Merge (const string & filename, const int surfindex_offset = 0); - DLL_HEADER void DoArchive (ngstd::Archive & archive); + DLL_HEADER void DoArchive (Archive & archive); /// DLL_HEADER void ImproveMesh (const MeshingParameters & mp, OPTIMIZEGOAL goal = OPT_QUALITY); diff --git a/libsrc/meshing/meshtype.cpp b/libsrc/meshing/meshtype.cpp index cdfa7c7c..baed182e 100644 --- a/libsrc/meshing/meshtype.cpp +++ b/libsrc/meshing/meshtype.cpp @@ -148,9 +148,9 @@ namespace netgen return *this; } - ngstd::Archive & Segment :: DoArchive (ngstd::Archive & ar) + void Segment :: DoArchive (Archive & ar) { - return ar & pnums[0] & pnums[1] & pnums[2] + ar & pnums[0] & pnums[1] & pnums[2] & edgenr & singedge_left & singedge_right & si & cd2i & domin & domout & tlosurf & surfnr1 & surfnr2 @@ -2427,9 +2427,9 @@ namespace netgen bcn = &default_bcname; } - ngstd::Archive & FaceDescriptor :: DoArchive (ngstd::Archive & ar) + void FaceDescriptor :: DoArchive (Archive & ar) { - return ar & surfnr & domin & domout & tlosurf & bcprop + ar & surfnr & domin & domout & tlosurf & bcprop & surfcolour.X() & surfcolour.Y() & surfcolour.Z() & bcname & domin_singular & domout_singular ; @@ -2482,7 +2482,7 @@ namespace netgen maxidentnr = 0; } - ngstd::Archive & Identifications :: DoArchive (ngstd::Archive & ar) + void Identifications :: DoArchive (Archive & ar) { ar & maxidentnr; ar & identifiedpoints & identifiedpoints_nr; @@ -2503,7 +2503,6 @@ namespace netgen for (auto & t : type) ar & (unsigned char&)(t); } - return ar; } diff --git a/libsrc/meshing/meshtype.hpp b/libsrc/meshing/meshtype.hpp index 5fe1d8a6..5ded7330 100644 --- a/libsrc/meshing/meshtype.hpp +++ b/libsrc/meshing/meshtype.hpp @@ -171,13 +171,9 @@ namespace netgen enum { BASE = 1 }; #endif - ngstd::Archive & DoArchive (ngstd::Archive & ar) { return ar & i; } + void DoArchive (Archive & ar) { ar & i; } }; - inline ngstd::Archive & operator & (ngstd::Archive & archive, PointIndex & mp) - { return mp.DoArchive(archive); } - - inline istream & operator>> (istream & ist, PointIndex & pi) { int i; ist >> i; pi = PointIndex(i); return ist; @@ -247,14 +243,9 @@ namespace netgen SurfaceElementIndex & operator-- () { --i; return *this; } SurfaceElementIndex & operator+= (int inc) { i+=inc; return *this; } - ngstd::Archive & DoArchive (ngstd::Archive & ar) { return ar & i; } + void DoArchive (Archive & ar) { ar & i; } }; - inline ngstd::Archive & operator & (ngstd::Archive & archive, SurfaceElementIndex & mp) - { return mp.DoArchive(archive); } - - - inline istream & operator>> (istream & ist, SurfaceElementIndex & pi) { int i; ist >> i; pi = i; return ist; @@ -337,19 +328,13 @@ namespace netgen static MPI_Datatype MyGetMPIType ( ); #endif - ngstd::Archive & DoArchive (ngstd::Archive & ar) + void DoArchive (Archive & ar) { ar & x[0] & x[1] & x[2] & layer & singular; ar & (unsigned char&)(type); - return ar; } }; - inline ngstd::Archive & operator & (ngstd::Archive & archive, MeshPoint & mp) - { return mp.DoArchive(archive); } - - - inline ostream & operator<<(ostream & s, const MeshPoint & pt) { return (s << Point<3> (pt)); @@ -497,7 +482,7 @@ namespace netgen /// const PointGeomInfo & GeomInfoPiMod (int i) const { return geominfo[(i-1) % np]; } - ngstd::Archive & DoArchive (ngstd::Archive & ar) + void DoArchive (Archive & ar) { short _np, _typ; bool _curved, _vis, _deleted; @@ -511,7 +496,6 @@ namespace netgen visible = _vis; deleted = _deleted; } for (size_t i = 0; i < np; i++) ar & pnum[i]; - return ar; } void SetIndex (int si) { index = si; } @@ -630,9 +614,6 @@ namespace netgen #endif }; - inline ngstd::Archive & operator & (ngstd::Archive & archive, Element2d & mp) - { return mp.DoArchive(archive); } - ostream & operator<<(ostream & s, const Element2d & el); @@ -774,7 +755,7 @@ namespace netgen /// const PointIndex & PNumMod (int i) const { return pnum[(i-1) % np]; } - ngstd::Archive & DoArchive (ngstd::Archive & ar) + void DoArchive (Archive & ar) { short _np, _typ; if (ar.Output()) @@ -784,7 +765,6 @@ namespace netgen { np = _np; typ = ELEMENT_TYPE(_typ); } for (size_t i = 0; i < np; i++) ar & pnum[i]; - return ar; } /// @@ -928,9 +908,6 @@ namespace netgen int hp_elnr; }; - inline ngstd::Archive & operator & (ngstd::Archive & archive, Element & mp) - { return mp.DoArchive(archive); } - ostream & operator<<(ostream & s, const Element & el); @@ -1049,12 +1026,9 @@ namespace netgen #else int GetPartition () const { return 0; } #endif - ngstd::Archive & DoArchive (ngstd::Archive & ar); + void DoArchive (Archive & ar); }; - inline ngstd::Archive & operator & (ngstd::Archive & archive, Segment & mp) - { return mp.DoArchive(archive); } - ostream & operator<<(ostream & s, const Segment & seg); @@ -1062,6 +1036,7 @@ namespace netgen { public: PointIndex pnum; + string name; int index; Element0d () = default; Element0d (PointIndex _pnum, int _index) @@ -1142,13 +1117,9 @@ namespace netgen // friend ostream & operator<<(ostream & s, const FaceDescriptor & fd); friend class Mesh; - ngstd::Archive & DoArchive (ngstd::Archive & ar); + void DoArchive (Archive & ar); }; - inline ngstd::Archive & operator & (ngstd::Archive & archive, FaceDescriptor & mp) - { return mp.DoArchive(archive); } - - ostream & operator<< (ostream & s, const FaceDescriptor & fd); @@ -1516,12 +1487,8 @@ namespace netgen DLL_HEADER void Print (ostream & ost) const; - ngstd::Archive & DoArchive (ngstd::Archive & ar); + void DoArchive (Archive & ar); }; - - inline ngstd::Archive & operator & (ngstd::Archive & archive, Identifications & mp) - { return mp.DoArchive(archive); } - } diff --git a/libsrc/occ/CMakeLists.txt b/libsrc/occ/CMakeLists.txt index 2f10e54e..831a3875 100644 --- a/libsrc/occ/CMakeLists.txt +++ b/libsrc/occ/CMakeLists.txt @@ -4,13 +4,17 @@ add_library(occ ${NG_LIB_TYPE} Partition_Loop.cxx Partition_Loop2d.cxx Partition_Loop3d.cxx Partition_Spliter.cxx occconstruction.cpp occgenmesh.cpp occgeom.cpp occmeshsurf.cpp python_occ.cpp ) - -add_library(occvis ${NG_LIB_TYPE} vsocc.cpp) +if(USE_GUI) + add_library(occvis ${NG_LIB_TYPE} vsocc.cpp) +endif(USE_GUI) if(NOT WIN32) target_link_libraries( occ ${OCC_LIBRARIES} ${PYTHON_LIBRARIES}) - target_link_libraries( occvis occ ) - install( TARGETS occ occvis ${NG_INSTALL_DIR}) + install( TARGETS occ ${NG_INSTALL_DIR}) + if (USE_GUI) + target_link_libraries( occvis occ ) + install( TARGETS occvis ${NG_INSTALL_DIR}) + endif(USE_GUI) endif(NOT WIN32) install(FILES diff --git a/nglib/CMakeLists.txt b/nglib/CMakeLists.txt index 5429ffe6..ff8bd1d5 100644 --- a/nglib/CMakeLists.txt +++ b/nglib/CMakeLists.txt @@ -32,6 +32,8 @@ if(NOT WIN32) endif(USE_GUI) endif(NOT WIN32) +target_link_libraries(nglib PUBLIC ngcore) + target_link_libraries( nglib PRIVATE ${OCC_LIBRARIES} ${MPI_CXX_LIBRARIES} ${OPENGL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${X11_Xmu_LIB} ${JPEG_LIBRARIES} ${MKL_LIBRARIES} ${ZLIB_LIBRARIES} ${OCC_LIBRARIES} ) if(USE_OCC AND NOT WIN32) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f898217f..a0783363 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1 +1,2 @@ +add_subdirectory(catch) add_subdirectory(pytest) diff --git a/tests/build_guidelines.sh b/tests/build_guidelines.sh new file mode 100644 index 00000000..111b1cd0 --- /dev/null +++ b/tests/build_guidelines.sh @@ -0,0 +1,8 @@ +cd +mkdir -p build/netgen +cd build/netgen +cmake ../../src/netgen -DUSE_CCACHE=ON -DENABLE_CPP_CORE_GUIDELINES_CHECK=ON -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_C_COMPILER=clang +make -j12 +make install + diff --git a/tests/catch/CMakeLists.txt b/tests/catch/CMakeLists.txt new file mode 100644 index 00000000..fc0ebe41 --- /dev/null +++ b/tests/catch/CMakeLists.txt @@ -0,0 +1,37 @@ + +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) +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) diff --git a/tests/catch/archive.cpp b/tests/catch/archive.cpp new file mode 100644 index 00000000..ea5ac1dc --- /dev/null +++ b/tests/catch/archive.cpp @@ -0,0 +1,317 @@ + +#include "catch.hpp" +#include <../core/ngcore.hpp> +using namespace ngcore; +using namespace std; + +class CommonBase +{ +public: + int a; + virtual ~CommonBase() {} + + virtual void DoArchive(Archive& archive) { archive & a; } +}; + +// pure abstract base class +class SharedPtrHolder : virtual public CommonBase +{ +public: + vector> names; + virtual ~SharedPtrHolder() + { } + + virtual void abstract() = 0; + virtual void DoArchive(Archive& archive) + { + CommonBase::DoArchive(archive); + archive & names; + } +}; + +class PtrHolder : virtual public CommonBase +{ +public: + vector numbers; + virtual ~PtrHolder() {} + + virtual void DoArchive(Archive& archive) + { + CommonBase::DoArchive(archive); + archive & numbers; + } +}; + +class SharedPtrAndPtrHolder : public SharedPtrHolder, public PtrHolder +{ +public: + virtual ~SharedPtrAndPtrHolder() {} + virtual void DoArchive(Archive& archive) + { + SharedPtrHolder::DoArchive(archive); + PtrHolder::DoArchive(archive); + } + virtual void abstract() {} +}; + +// Classes without virt. or multiple inheritance do not need to be registered +class SimpleClass : public CommonBase +{ +public: + double d; + virtual void DoArchive(Archive& ar) + { + CommonBase::DoArchive(ar); + ar & d; + } +}; + +class NotRegisteredForArchive : public SharedPtrAndPtrHolder {}; + +class ClassWithConstPtr +{ +private: + const int* ptr; +public: + ClassWithConstPtr(const int* aptr) : ptr(aptr) { } + // constructor only for archive + ClassWithConstPtr() {} + void DoArchive(Archive& ar) + { + ar & ptr; + } + const int* getPtr() { return ptr; } +}; + +class OneMoreDerivedClass : public SharedPtrAndPtrHolder {}; + +static RegisterClassForArchive regb; +static RegisterClassForArchive regsp; +static RegisterClassForArchive regp; +static RegisterClassForArchive regspp; +static RegisterClassForArchive regom; + +void testNullPtr(Archive& in, Archive& out) +{ + SharedPtrHolder* p = nullptr; + shared_ptr sp = nullptr; + out & p & sp; + out.FlushBuffer(); + SharedPtrHolder* pin = nullptr; + shared_ptr spin = nullptr; + in & pin & spin; + CHECK(pin == nullptr); + CHECK(spin == nullptr); +} + +void testSharedPointer(Archive& in, Archive& out) +{ + SECTION("Same shared ptr") + { + static_assert(detail::has_DoArchive::value, ""); + SharedPtrAndPtrHolder holder, holder2; + holder.names.push_back(make_shared("name")); + holder2.names = holder.names; // same shared ptr + out & holder & holder2; + out.FlushBuffer(); + SharedPtrAndPtrHolder 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) +{ + 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 testConstPointer(Archive& in, Archive& out) +{ + SECTION("Const pointer") + { + int* iptr = new int(4); + double d = 0.1; + ClassWithConstPtr cls(iptr); + out & cls & iptr & d; + out.FlushBuffer(); + ClassWithConstPtr incls; + int* iniptr; + double ind; + in & incls & iniptr & ind; + CHECK(*incls.getPtr() == 4); + CHECK(incls.getPtr() == iniptr); + CHECK(ind == 0.1); + delete iptr; + delete iniptr; + } +} + +void testMultipleInheritance(Archive& in, Archive& out) +{ + PtrHolder* p = new OneMoreDerivedClass; + p->numbers.push_back(new int(2)); + p->a = 5; + auto p2 = dynamic_cast(p); + p2->names.push_back(make_shared("test")); + auto sp1 = shared_ptr(p); + auto sp2 = dynamic_pointer_cast(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(pin) == dynamic_cast(pin2)); + CHECK(pin->a == pin2->a); + CHECK(pin->a == 5); + REQUIRE(dynamic_cast(pin2) != nullptr); + CHECK(*dynamic_cast(pin2)->numbers[0] == 2); + CHECK(*pin->numbers[0] == *dynamic_cast(pin2)->numbers[0]); + REQUIRE(dynamic_cast(pin) != nullptr); + CHECK(dynamic_cast(pin)->names[0] == pin2->names[0]); + }; + SECTION("Archive ptrs to leaves of mult. inh.") + { + out & p & p2; + out.FlushBuffer(); + PtrHolder* pin = nullptr; + SharedPtrHolder* pin2 = nullptr; + in & pin & pin2; + checkPtr(pin, pin2); + } + SECTION("Archive shared ptrs to leaves of mult. inh.") + { + out & sp1 & sp2; + out.FlushBuffer(); + shared_ptr pin; + shared_ptr pin2; + in & pin & pin2; + checkPtr(pin.get(), pin2.get()); + } + SECTION("Virtual base class") + { + CommonBase* b = dynamic_cast(p); + out & b & p; + PtrHolder* pin; + CommonBase* bin; + in & bin & pin; + checkPtr(pin, dynamic_cast(bin)); + } + SECTION("Simple class without register") + { + auto a = new SimpleClass; + a->a = 5; + a->d = 2.3; + SECTION("check pointer") + { + out & a; + out.FlushBuffer(); + SimpleClass* ain; + in & ain; + CHECK(ain->a == 5); + CHECK(ain->d == 2.3); + } + SECTION("check shared pointer") + { + auto spa = shared_ptr(a); + out & spa; + out.FlushBuffer(); + shared_ptr spain; + in & spain; + CHECK(spain->a == 5); + CHECK(spain->d == 2.3); + } + } +} + +void testLibraryVersion(Archive& in, Archive& out) +{ + SetLibraryVersion("netgen","v6.2.1812"); + CHECK(in.GetVersion("netgen") == "v6.2.1811"); + CHECK(out.GetVersion("netgen") == "v6.2.1812"); +} + +void testArchive(Archive& in, Archive& out) +{ + SECTION("Empty String") + { + char* cstr = nullptr; + char* empty = new char[1]; + char* simple = new char[7] {'s','i','m','p','l','e','\0'}; + empty[0] = '\0'; + out << string("") << cstr << empty << simple << string("simple") << long(1); + out.FlushBuffer(); + string str; long i; char* readempty; char* readsimple; + string simplestr; + in & str & cstr & readempty & readsimple & simplestr & i; + CHECK(str == ""); + CHECK(cstr == nullptr); + CHECK(strcmp(readempty,"") == 0); + CHECK(strcmp(readsimple,"simple") == 0); + CHECK(i == 1); + CHECK(simplestr == "simple"); + delete[] readempty; + delete[] empty; + delete[] simple; + delete[] readsimple; + } + SECTION("SharedPtr") + { + testSharedPointer(in, out); + } + SECTION("Pointer") + { + testPointer(in, out); + } + SECTION("Const Pointer") + { + testConstPointer(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")); + } + SECTION("nullptr") + { + testNullPtr(in, out); + } + SECTION("Library Version") + { + testLibraryVersion(in,out); + } +} + +TEST_CASE("BinaryArchive") +{ + SetLibraryVersion("netgen","v6.2.1811"); + auto stream = make_shared(); + BinaryOutArchive out(stream); + BinaryInArchive in(stream); + testArchive(in, out); +} + +TEST_CASE("TextArchive") +{ + SetLibraryVersion("netgen","v6.2.1811"); + auto stream = make_shared(); + TextOutArchive out(stream); + TextInArchive in(stream); + testArchive(in, out); +} diff --git a/tests/catch/main.cpp b/tests/catch/main.cpp new file mode 100644 index 00000000..de419564 --- /dev/null +++ b/tests/catch/main.cpp @@ -0,0 +1,3 @@ + +#define CATCH_CONFIG_MAIN +#include diff --git a/tests/catch/version.cpp b/tests/catch/version.cpp new file mode 100644 index 00000000..5655ab23 --- /dev/null +++ b/tests/catch/version.cpp @@ -0,0 +1,19 @@ + +#include "catch.hpp" +#include <../core/ngcore.hpp> +using namespace ngcore; +using namespace std; + + +TEST_CASE("Version") +{ + VersionInfo v("v6.2.1811-3-asdf"); + CHECK(v.to_string() == "v6.2.1811-3-asdf"); + VersionInfo v2("6.2"); + CHECK(v2.to_string() == "v6.2"); + CHECK(v < "v7"); + CHECK(v >= "6.2"); + CHECK(v > "6.2.1811"); + CHECK(v < "6.2.1811-5"); + CHECK(v == "v6.2.1811-3"); +} diff --git a/tests/docker_16.04 b/tests/docker_16.04 deleted file mode 100644 index 2195714b..00000000 --- a/tests/docker_16.04 +++ /dev/null @@ -1,4 +0,0 @@ -FROM ubuntu:16.04 -MAINTAINER Matthias Hochsteger -RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk -ADD . /root/src/netgen diff --git a/tests/docker_15.10 b/tests/dockerfile similarity index 62% rename from tests/docker_15.10 rename to tests/dockerfile index b386f250..ebed3dea 100644 --- a/tests/docker_15.10 +++ b/tests/dockerfile @@ -1,4 +1,5 @@ -FROM ubuntu:15.10 +FROM ubuntu:18.04 +ENV DEBIAN_FRONTEND=noninteractive MAINTAINER Matthias Hochsteger -RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk +RUN apt-get update && apt-get -y install python3 libpython3-dev libxmu-dev tk-dev tcl-dev cmake git g++ libglu1-mesa-dev ccache python3-pytest python3-numpy python3-tk clang-tidy python3-distutils clang ADD . /root/src/netgen diff --git a/tests/pytest/test_pickling.py b/tests/pytest/test_pickling.py new file mode 100644 index 00000000..09e571a7 --- /dev/null +++ b/tests/pytest/test_pickling.py @@ -0,0 +1,39 @@ + +import netgen.csg as csg +import pickle, numpy + +def test_pickle_csg(): + geo = csg.CSGeometry() + geo.Add(csg.Sphere(csg.Pnt(0,0,0), 2).bc("sphere")) + brick = csg.OrthoBrick(csg.Pnt(-3,-3,-3), csg.Pnt(3,3,3)) + geo.Add(csg.Cylinder(csg.Pnt(0,0,0), csg.Pnt(1,0,0), 0.5) * brick) + geo.Add(csg.Ellipsoid(csg.Pnt(0,0,0), csg.Vec(1,0,0), csg.Vec(0,1,0), csg.Vec(0,0,0.5))) + geo.Add(csg.Cone(csg.Pnt(0,0,0), csg.Pnt(3,0,0), 1, 0.5) * brick) + geo.Add(csg.EllipticCone(csg.Pnt(0,0,0), csg.Vec(2,0,0), csg.Vec(0,1,0), 3, 0.5) * brick) + geo.Add(csg.Torus(csg.Pnt(0,0,0), csg.Vec(0,1,0), 0.3, 0.05)) + pts2d = [[1,1], [1,-1], [-1,-1], [-1,1]] + segs = [[0,1], [1,2], [2,3], [3,0]] + curve = csg.SplineCurve2d() + pnrs = [curve.AddPoint(*p) for p in pts2d] + for s in segs: + curve.AddSegment(pnrs[s[0]], pnrs[s[1]]) + geo.Add(csg.Revolution(csg.Pnt(0,0,0), csg.Pnt(1,0,0), curve)) + path = csg.SplineCurve3d() + pnts = [(0,0,0), (2,0,0), (2,2,0)] + segs = [(0,1,2)] + for pnt in pnts: + path.AddPoint (*pnt) + + for seg in segs: + path.AddSegment (*seg) + geo.Add(csg.Extrusion(path, curve, csg.Vec(0,0,1))) + + geo_dump = pickle.dumps(geo) + geo2 = pickle.loads(geo_dump) + vd1 = geo._visualizationData() + vd2 = geo2._visualizationData() + for val1, val2 in zip(vd1.values(), vd2.values()): + assert numpy.array_equal(val1, val2) + +if __name__ == "__main__": + test_pickle_csg()