mirror of
https://github.com/NGSolve/netgen.git
synced 2024-12-24 21:10:33 +05:00
Archive with nondefault constructor
This commit is contained in:
parent
22b45dde67
commit
90729810d4
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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 {};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user