Archive with nondefault constructor

This commit is contained in:
Hochsteger, Matthias 2023-08-28 10:02:22 +02:00
parent 22b45dde67
commit 90729810d4
13 changed files with 211 additions and 73 deletions

View File

@ -255,7 +255,6 @@ target_include_directories(nglib PRIVATE ${ZLIB_INCLUDE_DIRS})
if(USE_GUI)
target_include_directories(nggui PRIVATE ${ZLIB_INCLUDE_DIRS})
endif(USE_GUI)
target_link_libraries(nglib PRIVATE ${ZLIB_LIBRARIES})
#######################################################################
if(WIN32)

View File

@ -18,7 +18,8 @@ string(REPLACE "|" ";" ng_compile_flags_replace_sep "${NG_COMPILE_FLAGS}")
target_compile_options(ngcore PUBLIC ${ng_compile_flags_replace_sep})
if(EMSCRIPTEN)
target_link_options(nglib PUBLIC -sALLOW_MEMORY_GROWTH -sENVIRONMENT=web)
target_link_options(ngcore PUBLIC -sALLOW_MEMORY_GROWTH -sENVIRONMENT=web)
target_compile_options(ngcore PUBLIC -sNO_DISABLE_EXCEPTION_CATCHING)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9)

View File

@ -41,16 +41,35 @@ namespace ngcore
class NGCORE_API Archive;
namespace detail
{
template <class T, class Tuple, size_t... Is>
T* construct_from_tuple(Tuple&& tuple, std::index_sequence<Is...> ) {
return new T{std::get<Is>(std::forward<Tuple>(tuple))...};
}
template <class T, class Tuple>
T* construct_from_tuple(Tuple&& tuple) {
return construct_from_tuple<T>(std::forward<Tuple>(tuple),
std::make_index_sequence<std::tuple_size<std::decay_t<Tuple>>::value>{}
);
}
// create new pointer of type T if it is default constructible, else throw
template<typename T, typename ...Rest>
T* constructIfPossible_impl(Rest... /*unused*/)
{ throw Exception(std::string(Demangle(typeid(T).name())) + " is not default constructible!"); }
template<typename T, typename... TArgs>
T* constructIfPossible(std::tuple<TArgs...> args)
{
if constexpr(std::is_constructible_v<T, TArgs...>)
return construct_from_tuple<T>(args);
throw Exception(std::string(Demangle(typeid(T).name())) +
" is not constructible!");
}
template<typename T, typename= std::enable_if_t<std::is_constructible<T>::value>>
T* constructIfPossible_impl(int /*unused*/) { return new T; } // NOLINT
template<typename T>
T* constructIfPossible() { return constructIfPossible_impl<T>(int{}); }
template <typename T> T *constructIfPossible()
{
if constexpr(std::is_constructible_v<T>)
return new T();
throw Exception(std::string(Demangle(typeid(T).name())) +
" is not default constructible!");
}
//Type trait to check if a class implements a 'void DoArchive(Archive&)' function
template<typename T>
@ -87,7 +106,7 @@ namespace ngcore
// create new object of this type and return a void* pointer that is points to the location
// of the (base)class given by type_info
// std::function<void*(const std::type_info&)> creator;
void* (*creator)(const std::type_info&);
void* (*creator)(const std::type_info&, Archive&);
// This caster takes a void* pointer to the type stored in this info and casts it to a
// void* pointer pointing to the (base)class type_info
// std::function<void*(const std::type_info&, void*)> upcaster;
@ -97,6 +116,9 @@ namespace ngcore
// std::function<void*(const std::type_info&, void*)> downcaster;
void* (*downcaster)(const std::type_info&, void*);
// Archive constructor arguments
std::function<void(Archive&, void*)> cargs_archiver;
#ifdef NETGEN_PYTHON
// std::function<pybind11::object(const std::any&)> anyToPyCaster;
pybind11::object (*anyToPyCaster)(const std::any&);
@ -528,8 +550,18 @@ namespace ngcore
if (std::is_constructible<T>::value)
return (*this) << -1 & (*p);
else
throw Exception(std::string("Archive error: Class ") +
Demangle(typeid(*p).name()) + " does not provide a default constructor!");
{
if (IsRegistered(Demangle(typeid(*p).name())))
{
(*this) << -3 << Demangle(typeid(*p).name());
GetArchiveRegister(Demangle(typeid(*p).name())).
cargs_archiver(*this, p);
return (*this) & (*p);
}
else
throw Exception(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
@ -540,7 +572,10 @@ namespace ngcore
throw Exception(std::string("Archive error: Polymorphic type ")
+ Demangle(typeid(*p).name())
+ " not registered for archive");
return (*this) << -3 << Demangle(typeid(*p).name()) & (*p);
(*this) << -3 << Demangle(typeid(*p).name());
GetArchiveRegister(Demangle(typeid(*p).name())).
cargs_archiver(*this, p);
return (*this) & (*p);
}
}
else
@ -571,7 +606,7 @@ namespace ngcore
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<T*>(info.creator(typeid(T)));
p = static_cast<T*>(info.creator(typeid(T), *this));
// 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));
@ -595,6 +630,16 @@ namespace ngcore
return *this;
}
Archive& operator&(std::tuple<>&) { return *this; }
template <typename... T>
Archive& operator&(std::tuple<T...> &t)
{
// call operator& for each element of the tuple
std::apply([this](auto&... arg) { std::make_tuple(((*this) & arg).IsParallel()...);}, t);
return *this;
}
// const ptr
template<typename T>
Archive& operator &(const T*& t)
@ -618,7 +663,7 @@ namespace ngcore
void SetParallel (bool _parallel) { parallel = _parallel; }
private:
template<typename T, typename ... Bases>
template<typename T, typename Bases, typename CArgs>
friend class RegisterClassForArchive;
#ifdef NETGEN_PYTHON
@ -637,7 +682,7 @@ namespace ngcore
struct Caster{};
template<typename T>
struct Caster<T>
struct Caster<T, std::tuple<>>
{
static void* tryUpcast (const std::type_info& /*unused*/, T* /*unused*/)
{
@ -649,8 +694,37 @@ namespace ngcore
}
};
template<typename T, typename B1>
struct Caster<T,B1>
{
static void* tryUpcast(const std::type_info& ti, T* p)
{
try {
return GetArchiveRegister(Demangle(typeid(B1).name()))
.upcaster(ti, static_cast<void *>(dynamic_cast<B1 *>(p)));
} catch (const Exception &) {
throw Exception("Upcast not successful, some classes are not "
"registered properly for archiving!");
}
}
static void* tryDowncast(const std::type_info& ti, void* p)
{
if(typeid(B1) == ti)
return dynamic_cast<T*>(static_cast<B1*>(p));
try
{
return dynamic_cast<T*>(static_cast<B1*>(GetArchiveRegister(Demangle(typeid(B1).name())).
downcaster(ti, p)));
} catch (const Exception &) {
throw Exception("Downcast not successful, some classes are not "
"registered properly for archiving!");
}
}
};
template<typename T, typename B1, typename ... Brest>
struct Caster<T,B1,Brest...>
struct Caster<T,std::tuple<B1, Brest...>>
{
static void* tryUpcast(const std::type_info& ti, T* p)
{
@ -658,7 +732,7 @@ namespace ngcore
{ return GetArchiveRegister(Demangle(typeid(B1).name())).
upcaster(ti, static_cast<void*>(dynamic_cast<B1*>(p))); }
catch(const Exception&)
{ return Caster<T, Brest...>::tryUpcast(ti, p); }
{ return Caster<T, std::tuple<Brest...>>::tryUpcast(ti, p); }
}
static void* tryDowncast(const std::type_info& ti, void* p)
@ -672,7 +746,7 @@ namespace ngcore
}
catch(const Exception&)
{
return Caster<T, Brest...>::tryDowncast(ti, p);
return Caster<T, std::tuple<Brest...>>::tryDowncast(ti, p);
}
}
};

View File

@ -156,30 +156,6 @@ namespace ngcore
{ return std::string("sp_")+GetPyName<T>(); }
};
// *************** Archiving functionality **************
template<typename T>
Archive& Archive :: Shallow(T& val)
{
static_assert(detail::is_any_pointer<T>, "ShallowArchive must be given pointer type!");
#ifdef NETGEN_PYTHON
if(shallow_to_python)
{
if(is_output)
ShallowOutPython(pybind11::cast(val));
else
{
pybind11::object obj;
ShallowInPython(obj);
val = pybind11::cast<T>(obj);
}
}
else
#endif // NETGEN_PYTHON
*this & val;
return *this;
}
template<typename ARCHIVE>
class NGCORE_API_EXPORT PyArchive : public ARCHIVE
{

View File

@ -5,35 +5,72 @@
#include <pybind11/pybind11.h>
#include <pybind11/cast.h>
#endif // NETGEN_PYTHON
#include <tuple>
#include "archive.hpp"
namespace ngcore {
// *************** Archiving functionality **************
template<typename T, typename ... Bases>
#ifdef NETGEN_PYTHON
template<typename T>
Archive& Archive :: Shallow(T& val)
{
static_assert(detail::is_any_pointer<T>, "ShallowArchive must be given pointer type!");
if(shallow_to_python)
{
if(is_output)
ShallowOutPython(pybind11::cast(val));
else
{
pybind11::object obj;
ShallowInPython(obj);
val = pybind11::cast<T>(obj);
}
}
else
*this & val;
return *this;
}
#endif // NETGEN_PYTHON
template<typename T, typename Bases=std::tuple<>, typename CArgs=std::tuple<>>
class RegisterClassForArchive
{
public:
RegisterClassForArchive()
std::function<CArgs(T&)> get_cargs;
RegisterClassForArchive(std::function<CArgs(T&)> _get_cargs =
[](T&) -> std::tuple<> { return std::tuple<>{}; }) :
get_cargs(_get_cargs)
{
static_assert(detail::all_of_tmpl<std::is_base_of<Bases,T>::value...>,
"Variadic template arguments must be base classes of T");
static_assert(std::is_base_of<Bases, T>::value ||
detail::is_base_of_tuple<T, Bases>,
"Second argument must be base class or tuple of base classes of T");
detail::ClassArchiveInfo info {};
info.creator = [](const std::type_info& ti) -> void*
{ return typeid(T) == ti ? detail::constructIfPossible<T>()
: Archive::Caster<T, Bases...>::tryUpcast(ti, detail::constructIfPossible<T>()); };
info.upcaster = [/*this*/](const std::type_info& ti, void* p) -> void*
{ return typeid(T) == ti ? p : Archive::Caster<T, Bases...>::tryUpcast(ti, static_cast<T*>(p)); };
info.downcaster = [/*this*/](const std::type_info& ti, void* p) -> void*
{ return typeid(T) == ti ? p : Archive::Caster<T, Bases...>::tryDowncast(ti, p); };
#ifdef NETGEN_PYTHON
info.anyToPyCaster = [](const std::any& a)
info.creator = [](const std::type_info& ti, Archive& ar) -> void*
{
const T* val = std::any_cast<T>(&a);
return pybind11::cast(val); };
CArgs args;
ar &args;
auto nT = detail::constructIfPossible<T>(args);
return typeid(T) == ti ? nT
: Archive::Caster<T, Bases>::tryUpcast(ti, nT);
};
info.upcaster = [/*this*/](const std::type_info& ti, void* p) -> void*
{ return typeid(T) == ti ? p : Archive::Caster<T, Bases>::tryUpcast(ti, static_cast<T*>(p)); };
info.downcaster = [/*this*/](const std::type_info& ti, void* p) -> void*
{ return typeid(T) == ti ? p : Archive::Caster<T, Bases>::tryDowncast(ti, p); };
info.cargs_archiver = [this](Archive &ar, void* p) {
ar << get_cargs(*static_cast<T*>(p));
};
#ifdef NETGEN_PYTHON
info.anyToPyCaster = [](const std::any &a) {
const T* val = std::any_cast<T>(&a);
return pybind11::cast(val);
};
#endif // NETGEN_PYTHON
Archive::SetArchiveRegister(std::string(Demangle(typeid(T).name())),info);
}
};
Archive::SetArchiveRegister(std::string(Demangle(typeid(T).name())),info);
}
};
} // namespace ngcore
#endif // NETGEN_REGISTER_ARCHIVE_HPP

View File

@ -16,6 +16,15 @@ namespace ngcore
template<typename T>
struct is_any_pointer_impl : std::false_type {};
// check if second template argument is tuple of base classes to first
// template argument, return constexpr bool
template<typename T, typename Tuple>
constexpr bool is_base_of_tuple = false;
template<typename T, typename... Ts>
constexpr bool is_base_of_tuple<T, std::tuple<Ts...>> =
all_of_tmpl<std::is_base_of<Ts, T>::value...>;
template<typename T>
struct is_any_pointer_impl<T*> : std::true_type {};

View File

@ -43,6 +43,14 @@ namespace ngcore
{
for(const auto & [r, sub] : demangle_regexes)
s = std::regex_replace (s,r,sub);
#ifdef EMSCRIPTEN
// for some reason regex_replace is not working at all
std::string temp = s;
s = "";
for(auto c : temp)
if(c!=' ')
s+=c;
#endif // EMSCRIPTEN
return s;
}

View File

@ -580,5 +580,5 @@ void ProjectToEdge (const Surface * f1, const Surface * f2, Point<3> & hp)
RegisterClassForArchive<Surface> regsurf;
RegisterClassForArchive<Primitive> regprim;
RegisterClassForArchive<OneSurfacePrimitive, Surface, Primitive> regosf;
RegisterClassForArchive<OneSurfacePrimitive, tuple<Surface, Primitive>> regosf;
}

View File

@ -1105,6 +1105,6 @@ namespace netgen
};
SplineGeoInit sginit;
static RegisterClassForArchive<SplineGeometry2d, SplineGeometry<2>, NetgenGeometry> regspg2;
static RegisterClassForArchive<SplineGeometry2d, tuple<SplineGeometry<2>, NetgenGeometry>> regspg2;
static RegisterClassForArchive<SplineSegExt, SplineSeg<2>> regssext;
}

View File

@ -15,7 +15,7 @@ target_sources(nglib PRIVATE
boundarylayer2d.cpp
)
target_link_libraries( nglib PRIVATE netgen_metis "$<BUILD_INTERFACE:netgen_python>" ${ZLIB_LIBRARIES} )
target_link_libraries( nglib PRIVATE netgen_metis "$<BUILD_INTERFACE:netgen_python>" )
install(FILES
adfront2.hpp adfront3.hpp basegeom.hpp bcfunctions.hpp bisect.hpp

View File

@ -4,10 +4,7 @@
#include "meshing.hpp"
#include "../general/gzstream.h"
#ifdef NG_PYTHON
// must be included to instantiate Archive::Shallow(NetgenGeometry&)
#include <core/python_ngcore.hpp>
#endif
#include <core/register_archive.hpp>
namespace netgen
{
@ -4493,7 +4490,11 @@ namespace netgen
double local_sum = 0.0;
double teterrpow = mp.opterrpow;
std::array<int,n_classes> classes_local{};
// std::array<int,n_classes> classes_local{};
size_t n_classes = tets_in_qualclass.Size();
Array<int> classes_local(n_classes);
for (int i = 0; i < n_classes; i++)
classes_local[i] = 0;
for (auto i : myrange)
{

View File

@ -3756,5 +3756,5 @@ void STLGeometry :: WriteChartToFile( ChartId chartnumber, filesystem::path file
STLInit stlinit;
static RegisterClassForArchive<STLGeometry, NetgenGeometry, STLTopology> stlgeo;
static RegisterClassForArchive<STLGeometry, std::tuple<NetgenGeometry, STLTopology>> stlgeo;
}

View File

@ -86,12 +86,32 @@ public:
const int* getPtr() { return ptr; }
};
class OneMoreDerivedClass : public SharedPtrAndPtrHolder {};
class ClassWithoutDefaultConstructor
{
public:
int a;
double b;
double c;
ClassWithoutDefaultConstructor(int aa, double c) : a(aa), c(c) {}
void DoArchive(Archive& ar)
{
ar & b;
}
};
static RegisterClassForArchive<ClassWithoutDefaultConstructor,
tuple<>, tuple<int, double>>
regwdc([](ClassWithoutDefaultConstructor& self)
{ return make_tuple(self.a, self.c); });
class OneMoreDerivedClass : public SharedPtrAndPtrHolder {
};
static RegisterClassForArchive<CommonBase> regb;
static RegisterClassForArchive<SharedPtrHolder, CommonBase> regsp;
static RegisterClassForArchive<PtrHolder, CommonBase> regp;
static RegisterClassForArchive<SharedPtrAndPtrHolder, SharedPtrHolder, PtrHolder> regspp;
static RegisterClassForArchive<SharedPtrAndPtrHolder, tuple<SharedPtrHolder, PtrHolder>> regspp;
static RegisterClassForArchive<OneMoreDerivedClass, SharedPtrAndPtrHolder> regom;
void testNullPtr(Archive& in, Archive& out)
@ -334,6 +354,19 @@ void testArchive(Archive& in, Archive& out)
SharedPtrAndPtrHolder* p = new NotRegisteredForArchive;
REQUIRE_THROWS(out & p, Catch::Contains("not registered for archive"));
}
SECTION("Non-default constructor")
{
ClassWithoutDefaultConstructor c(5, 2.2);
c.b = 3.2;
auto p = &c;
out & p;
out.FlushBuffer();
ClassWithoutDefaultConstructor* cin;
in & cin;
CHECK(cin->a == 5);
CHECK(cin->b == 3.2);
CHECK(cin->c == 2.2);
}
SECTION("nullptr")
{
testNullPtr(in, out);