mirror of
https://github.com/NGSolve/netgen.git
synced 2025-04-25 07:12:04 +05:00
fix for classes that have DoArchive but no inheritance. Some comments
This commit is contained in:
parent
8e29d38fc1
commit
b2a2c64845
@ -150,17 +150,21 @@ namespace ngcore
|
|||||||
|
|
||||||
void* reg_ptr = ptr.get();
|
void* reg_ptr = ptr.get();
|
||||||
bool neededDowncast = false;
|
bool neededDowncast = false;
|
||||||
if constexpr(has_DoArchive<T>::value)
|
// Downcasting is only possible for our registered classes
|
||||||
{
|
if(typeid(T) != typeid(*ptr))
|
||||||
if(GetArchiveRegister().count(std::string(typeid(*ptr).name())) == 0)
|
{
|
||||||
throw std::runtime_error(std::string("Archive error: Polymorphic type ")
|
if constexpr(has_DoArchive<T>::value)
|
||||||
+ typeid(*ptr).name()
|
{
|
||||||
+ " not registered for archive");
|
if(GetArchiveRegister().count(std::string(typeid(*ptr).name())) == 0)
|
||||||
else
|
throw std::runtime_error(std::string("Archive error: Polymorphic type ")
|
||||||
reg_ptr = GetArchiveRegister()[typeid(*ptr).name()].downcaster(typeid(T), ptr.get());
|
+ typeid(*ptr).name()
|
||||||
if(reg_ptr != (void*) ptr.get())
|
+ " not registered for archive");
|
||||||
neededDowncast = true;
|
reg_ptr = GetArchiveRegister()[typeid(*ptr).name()].downcaster(typeid(T), ptr.get());
|
||||||
}
|
// if there was a true downcast we have to store more information
|
||||||
|
if(reg_ptr != (void*) ptr.get())
|
||||||
|
neededDowncast = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
auto pos = shared_ptr2nr.find(reg_ptr);
|
auto pos = shared_ptr2nr.find(reg_ptr);
|
||||||
// if not found store -1 and the pointer
|
// if not found store -1 and the pointer
|
||||||
if(pos == shared_ptr2nr.end())
|
if(pos == shared_ptr2nr.end())
|
||||||
@ -168,6 +172,7 @@ namespace ngcore
|
|||||||
auto p = ptr.get();
|
auto p = ptr.get();
|
||||||
(*this) << -1;
|
(*this) << -1;
|
||||||
(*this) & neededDowncast & p;
|
(*this) & neededDowncast & p;
|
||||||
|
// if we did downcast we store the true type as well
|
||||||
if(neededDowncast)
|
if(neededDowncast)
|
||||||
(*this) << std::string(typeid(*ptr).name());
|
(*this) << std::string(typeid(*ptr).name());
|
||||||
shared_ptr2nr[reg_ptr] = shared_ptr_count++;
|
shared_ptr2nr[reg_ptr] = shared_ptr_count++;
|
||||||
@ -183,22 +188,27 @@ namespace ngcore
|
|||||||
{
|
{
|
||||||
int nr;
|
int nr;
|
||||||
(*this) & nr;
|
(*this) & nr;
|
||||||
|
// -2 restores a nullptr
|
||||||
if(nr == -2)
|
if(nr == -2)
|
||||||
{
|
{
|
||||||
ptr = nullptr;
|
ptr = nullptr;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
// -1 restores a new shared ptr by restoring the inner pointer and creating a shared_ptr to it
|
||||||
else if (nr == -1)
|
else if (nr == -1)
|
||||||
{
|
{
|
||||||
T* p;
|
T* p;
|
||||||
bool neededDowncast;
|
bool neededDowncast;
|
||||||
(*this) & neededDowncast & p;
|
(*this) & neededDowncast & p;
|
||||||
ptr = std::shared_ptr<T>(p);
|
ptr = std::shared_ptr<T>(p);
|
||||||
|
// if we did downcast we need to store a shared_ptr<void> to the true object
|
||||||
if(neededDowncast)
|
if(neededDowncast)
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
(*this) & name;
|
(*this) & name;
|
||||||
auto info = GetArchiveRegister()[name];
|
auto info = GetArchiveRegister()[name];
|
||||||
|
// for this we use an aliasing constructor to create a shared pointer sharing lifetime
|
||||||
|
// with our shared ptr, but pointing to the true object
|
||||||
nr2shared_ptr.push_back(std::shared_ptr<void>(std::static_pointer_cast<void>(ptr),
|
nr2shared_ptr.push_back(std::shared_ptr<void>(std::static_pointer_cast<void>(ptr),
|
||||||
info.downcaster(typeid(T),
|
info.downcaster(typeid(T),
|
||||||
ptr.get())));
|
ptr.get())));
|
||||||
@ -213,11 +223,15 @@ namespace ngcore
|
|||||||
(*this) & neededDowncast;
|
(*this) & neededDowncast;
|
||||||
if(neededDowncast)
|
if(neededDowncast)
|
||||||
{
|
{
|
||||||
|
// if there was a downcast we can expect the class to be registered (since archiving
|
||||||
|
// wouldn't have worked else)
|
||||||
if constexpr(has_DoArchive<T>::value)
|
if constexpr(has_DoArchive<T>::value)
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
(*this) & name;
|
(*this) & name;
|
||||||
auto info = GetArchiveRegister()[name];
|
auto info = GetArchiveRegister()[name];
|
||||||
|
// same trick as above, create a shared ptr sharing lifetime with
|
||||||
|
// the shared_ptr<void> in the register, but pointing to our object
|
||||||
ptr = std::static_pointer_cast<T>(std::shared_ptr<void>(other,
|
ptr = std::static_pointer_cast<T>(std::shared_ptr<void>(other,
|
||||||
info.upcaster(typeid(T),
|
info.upcaster(typeid(T),
|
||||||
other.get())));
|
other.get())));
|
||||||
@ -240,21 +254,20 @@ namespace ngcore
|
|||||||
{
|
{
|
||||||
// if the pointer is null store -2
|
// if the pointer is null store -2
|
||||||
if (!p)
|
if (!p)
|
||||||
{
|
return (*this) << -2;
|
||||||
int m2 = -2;
|
|
||||||
(*this) & m2;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
void* reg_ptr = (void*)p;
|
void* reg_ptr = (void*)p;
|
||||||
if constexpr(has_DoArchive<T>::value)
|
if(typeid(T) != typeid(*p))
|
||||||
{
|
{
|
||||||
if(GetArchiveRegister().count(std::string(typeid(*p).name())) == 0)
|
if constexpr(has_DoArchive<T>::value)
|
||||||
throw std::runtime_error(std::string("Archive error: Polimorphic type ")
|
{
|
||||||
+ typeid(*p).name()
|
if(GetArchiveRegister().count(std::string(typeid(*p).name())) == 0)
|
||||||
+ " not registered for archive");
|
throw std::runtime_error(std::string("Archive error: Polymorphic type ")
|
||||||
else
|
+ typeid(*p).name()
|
||||||
reg_ptr = GetArchiveRegister()[typeid(*p).name()].downcaster(typeid(T), p);
|
+ " not registered for archive");
|
||||||
}
|
else
|
||||||
|
reg_ptr = GetArchiveRegister()[typeid(*p).name()].downcaster(typeid(T), p);
|
||||||
|
}
|
||||||
|
}
|
||||||
auto pos = ptr2nr.find(reg_ptr);
|
auto pos = ptr2nr.find(reg_ptr);
|
||||||
// if the pointer is not found in the map create a new entry
|
// if the pointer is not found in the map create a new entry
|
||||||
if (pos == ptr2nr.end())
|
if (pos == ptr2nr.end())
|
||||||
@ -270,11 +283,14 @@ namespace ngcore
|
|||||||
typeid(*p).name() + " does not provide a default constructor!");
|
typeid(*p).name() + " does not provide a default constructor!");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// We want this special behaviour only for our classes that implement DoArchive
|
// 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 constexpr(has_DoArchive<T>::value)
|
if constexpr(has_DoArchive<T>::value)
|
||||||
{
|
{
|
||||||
if(GetArchiveRegister().count(std::string(typeid(*p).name())) == 0)
|
if(GetArchiveRegister().count(std::string(typeid(*p).name())) == 0)
|
||||||
throw std::runtime_error(std::string("Archive error: Polimorphic type ")
|
throw std::runtime_error(std::string("Archive error: Polymorphic type ")
|
||||||
+ typeid(*p).name()
|
+ typeid(*p).name()
|
||||||
+ " not registered for archive");
|
+ " not registered for archive");
|
||||||
else
|
else
|
||||||
@ -289,18 +305,18 @@ namespace ngcore
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
(*this) & pos->second;
|
(*this) & pos->second;
|
||||||
(*this) << std::string(typeid(*p).name());
|
bool downcasted = !(reg_ptr == (void*) p);
|
||||||
|
// store if the class has been downcasted and the name
|
||||||
|
(*this) << downcasted << std::string(typeid(*p).name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int nr;
|
int nr;
|
||||||
(*this) & nr;
|
(*this) & nr;
|
||||||
if (nr == -2)
|
if (nr == -2) // restore a nullptr
|
||||||
{
|
|
||||||
p = nullptr;
|
p = nullptr;
|
||||||
}
|
else if (nr == -1) // create a new pointer of standard type (no virtual or multiple inheritance,...)
|
||||||
else if (nr == -1)
|
|
||||||
{
|
{
|
||||||
if constexpr (std::is_constructible<T>::value)
|
if constexpr (std::is_constructible<T>::value)
|
||||||
{
|
{
|
||||||
@ -312,15 +328,19 @@ namespace ngcore
|
|||||||
throw std::runtime_error("Class isn't registered properly");
|
throw std::runtime_error("Class isn't registered properly");
|
||||||
|
|
||||||
}
|
}
|
||||||
else if(nr == -3)
|
else if(nr == -3) // restore one of our registered classes that can have multiple inheritance,...
|
||||||
{
|
{
|
||||||
// We want this special behaviour only for our classes that implement DoArchive
|
// As stated above, we want this special behaviour only for our classes that implement DoArchive
|
||||||
if constexpr(has_DoArchive<T>::value)
|
if constexpr(has_DoArchive<T>::value)
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
(*this) & name;
|
(*this) & name;
|
||||||
auto info = GetArchiveRegister()[name];
|
auto info = GetArchiveRegister()[name];
|
||||||
|
// the creator creates a new object of type name, and returns a void* pointing
|
||||||
|
// to T (which may have an offset)
|
||||||
p = (T*) info.creator(typeid(T));
|
p = (T*) info.creator(typeid(T));
|
||||||
|
// we store the downcasted pointer (to be able to find it again from
|
||||||
|
// another class in a multiple inheritance tree)
|
||||||
nr2ptr.push_back(info.downcaster(typeid(T),p));
|
nr2ptr.push_back(info.downcaster(typeid(T),p));
|
||||||
(*this) & *p;
|
(*this) & *p;
|
||||||
}
|
}
|
||||||
@ -329,13 +349,18 @@ namespace ngcore
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
bool downcasted;
|
||||||
std::string name;
|
std::string name;
|
||||||
(*this) & name;
|
(*this) & downcasted & name;
|
||||||
if constexpr(has_DoArchive<T>::value)
|
if(downcasted)
|
||||||
{
|
{
|
||||||
auto info = GetArchiveRegister()[name];
|
// if the class has been downcasted we can assume it is in the register
|
||||||
p = (T*) info.upcaster(typeid(T), nr2ptr[nr]);
|
if constexpr(has_DoArchive<T>::value)
|
||||||
}
|
{
|
||||||
|
auto info = GetArchiveRegister()[name];
|
||||||
|
p = (T*) info.upcaster(typeid(T), nr2ptr[nr]);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
p = (T*) nr2ptr[nr];
|
p = (T*) nr2ptr[nr];
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,11 @@ using namespace std;
|
|||||||
|
|
||||||
class CommonBase
|
class CommonBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
int a;
|
||||||
virtual ~CommonBase() {}
|
virtual ~CommonBase() {}
|
||||||
|
|
||||||
virtual void DoArchive(Archive& archive) { }
|
virtual void DoArchive(Archive& archive) { archive & a; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class SharedPtrHolder : virtual public CommonBase
|
class SharedPtrHolder : virtual public CommonBase
|
||||||
@ -19,7 +20,11 @@ public:
|
|||||||
virtual ~SharedPtrHolder()
|
virtual ~SharedPtrHolder()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual void DoArchive(Archive& archive) { archive & names; }
|
virtual void DoArchive(Archive& archive)
|
||||||
|
{
|
||||||
|
CommonBase::DoArchive(archive);
|
||||||
|
archive & names;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PtrHolder : virtual public CommonBase
|
class PtrHolder : virtual public CommonBase
|
||||||
@ -28,7 +33,11 @@ public:
|
|||||||
vector<int*> numbers;
|
vector<int*> numbers;
|
||||||
virtual ~PtrHolder() {}
|
virtual ~PtrHolder() {}
|
||||||
|
|
||||||
virtual void DoArchive(Archive& archive) { archive & numbers; }
|
virtual void DoArchive(Archive& archive)
|
||||||
|
{
|
||||||
|
CommonBase::DoArchive(archive);
|
||||||
|
archive & numbers;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SharedPtrAndPtrHolder : public SharedPtrHolder, public PtrHolder
|
class SharedPtrAndPtrHolder : public SharedPtrHolder, public PtrHolder
|
||||||
@ -42,6 +51,18 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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 NotRegisteredForArchive : public SharedPtrAndPtrHolder {};
|
||||||
|
|
||||||
class OneMoreDerivedClass : public SharedPtrAndPtrHolder {};
|
class OneMoreDerivedClass : public SharedPtrAndPtrHolder {};
|
||||||
@ -52,6 +73,19 @@ static RegisterClassForArchive<PtrHolder, CommonBase> regp;
|
|||||||
static RegisterClassForArchive<SharedPtrAndPtrHolder, SharedPtrHolder, PtrHolder> regspp;
|
static RegisterClassForArchive<SharedPtrAndPtrHolder, SharedPtrHolder, PtrHolder> regspp;
|
||||||
static RegisterClassForArchive<OneMoreDerivedClass, SharedPtrAndPtrHolder> regom;
|
static RegisterClassForArchive<OneMoreDerivedClass, SharedPtrAndPtrHolder> regom;
|
||||||
|
|
||||||
|
void testNullPtr(Archive& in, Archive& out)
|
||||||
|
{
|
||||||
|
SharedPtrHolder* p = nullptr;
|
||||||
|
shared_ptr<string> sp = nullptr;
|
||||||
|
out & p & sp;
|
||||||
|
out.FlushBuffer();
|
||||||
|
SharedPtrHolder* pin;
|
||||||
|
shared_ptr<string> spin;
|
||||||
|
in & pin & spin;
|
||||||
|
CHECK(pin == nullptr);
|
||||||
|
CHECK(spin == nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
void testSharedPointer(Archive& in, Archive& out)
|
void testSharedPointer(Archive& in, Archive& out)
|
||||||
{
|
{
|
||||||
SECTION("Same shared ptr")
|
SECTION("Same shared ptr")
|
||||||
@ -92,6 +126,7 @@ void testMultipleInheritance(Archive& in, Archive& out)
|
|||||||
{
|
{
|
||||||
PtrHolder* p = new OneMoreDerivedClass;
|
PtrHolder* p = new OneMoreDerivedClass;
|
||||||
p->numbers.push_back(new int(2));
|
p->numbers.push_back(new int(2));
|
||||||
|
p->a = 5;
|
||||||
auto p2 = dynamic_cast<SharedPtrHolder*>(p);
|
auto p2 = dynamic_cast<SharedPtrHolder*>(p);
|
||||||
p2->names.push_back(make_shared<string>("test"));
|
p2->names.push_back(make_shared<string>("test"));
|
||||||
auto sp1 = shared_ptr<PtrHolder>(p);
|
auto sp1 = shared_ptr<PtrHolder>(p);
|
||||||
@ -103,6 +138,8 @@ void testMultipleInheritance(Archive& in, Archive& out)
|
|||||||
CHECK(*pin2->names[0] == "test");
|
CHECK(*pin2->names[0] == "test");
|
||||||
CHECK(*pin->numbers[0] == 2);
|
CHECK(*pin->numbers[0] == 2);
|
||||||
CHECK(dynamic_cast<SharedPtrAndPtrHolder*>(pin) == dynamic_cast<SharedPtrAndPtrHolder*>(pin2));
|
CHECK(dynamic_cast<SharedPtrAndPtrHolder*>(pin) == dynamic_cast<SharedPtrAndPtrHolder*>(pin2));
|
||||||
|
CHECK(pin->a == pin2->a);
|
||||||
|
CHECK(pin->a == 5);
|
||||||
REQUIRE(dynamic_cast<SharedPtrAndPtrHolder*>(pin2) != nullptr);
|
REQUIRE(dynamic_cast<SharedPtrAndPtrHolder*>(pin2) != nullptr);
|
||||||
CHECK(*dynamic_cast<SharedPtrAndPtrHolder*>(pin2)->numbers[0] == 2);
|
CHECK(*dynamic_cast<SharedPtrAndPtrHolder*>(pin2)->numbers[0] == 2);
|
||||||
CHECK(*pin->numbers[0] == *dynamic_cast<SharedPtrAndPtrHolder*>(pin2)->numbers[0]);
|
CHECK(*pin->numbers[0] == *dynamic_cast<SharedPtrAndPtrHolder*>(pin2)->numbers[0]);
|
||||||
@ -136,6 +173,31 @@ void testMultipleInheritance(Archive& in, Archive& out)
|
|||||||
in & bin & pin;
|
in & bin & pin;
|
||||||
checkPtr(pin, dynamic_cast<SharedPtrHolder*>(bin));
|
checkPtr(pin, dynamic_cast<SharedPtrHolder*>(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<SimpleClass>(a);
|
||||||
|
out & spa;
|
||||||
|
out.FlushBuffer();
|
||||||
|
shared_ptr<SimpleClass> spain;
|
||||||
|
in & spain;
|
||||||
|
CHECK(spain->a == 5);
|
||||||
|
CHECK(spain->d == 2.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void testArchive(Archive& in, Archive& out)
|
void testArchive(Archive& in, Archive& out)
|
||||||
@ -157,6 +219,10 @@ void testArchive(Archive& in, Archive& out)
|
|||||||
SharedPtrAndPtrHolder* p = new NotRegisteredForArchive;
|
SharedPtrAndPtrHolder* p = new NotRegisteredForArchive;
|
||||||
REQUIRE_THROWS(out & p, Catch::Contains("not registered for archive"));
|
REQUIRE_THROWS(out & p, Catch::Contains("not registered for archive"));
|
||||||
}
|
}
|
||||||
|
SECTION("nullptr")
|
||||||
|
{
|
||||||
|
testNullPtr(in, out);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("BinaryArchive")
|
TEST_CASE("BinaryArchive")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user