mirror of
https://github.com/fraillt/bitsery.git
synced 2026-06-08 00:03:54 +00:00
cast from polymorphic owner pointer-like type to observer during assignment
This commit is contained in:
@@ -147,6 +147,7 @@ struct SmartPtrOwnerManager
|
|||||||
[alloc, typeId](TElement* data) { alloc.deleteObject(data, typeId); },
|
[alloc, typeId](TElement* data) { alloc.deleteObject(data, typeId); },
|
||||||
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
||||||
state.obj = obj;
|
state.obj = obj;
|
||||||
|
state.typeId = typeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void createSharedPolymorphic(
|
static void createSharedPolymorphic(
|
||||||
@@ -162,6 +163,7 @@ struct SmartPtrOwnerManager
|
|||||||
[alloc, handler](TElement* data) { handler->destroy(alloc, data); },
|
[alloc, handler](TElement* data) { handler->destroy(alloc, data); },
|
||||||
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
||||||
state.obj = obj;
|
state.obj = obj;
|
||||||
|
state.typeId = handler->getDerivedTypeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void createShared(TSharedState& state,
|
static void createShared(TSharedState& state,
|
||||||
@@ -176,6 +178,7 @@ struct SmartPtrOwnerManager
|
|||||||
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
||||||
obj = res;
|
obj = res;
|
||||||
state.obj = res;
|
state.obj = res;
|
||||||
|
state.typeId = typeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void createSharedPolymorphic(
|
static void createSharedPolymorphic(
|
||||||
@@ -191,6 +194,7 @@ struct SmartPtrOwnerManager
|
|||||||
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
||||||
obj = res;
|
obj = res;
|
||||||
state.obj = res;
|
state.obj = res;
|
||||||
|
state.typeId = handler->getDerivedTypeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void saveToSharedState(TSharedState& state, T& obj)
|
static void saveToSharedState(TSharedState& state, T& obj)
|
||||||
@@ -205,20 +209,17 @@ struct SmartPtrOwnerManager
|
|||||||
|
|
||||||
static void loadFromSharedState(TSharedState& state, T& obj)
|
static void loadFromSharedState(TSharedState& state, T& obj)
|
||||||
{
|
{
|
||||||
// reinterpret_pointer_cast is only since c++17
|
|
||||||
auto v = state.obj.get();
|
auto v = state.obj.get();
|
||||||
auto p = reinterpret_cast<TElement*>(v);
|
auto p = static_cast<TElement*>(v);
|
||||||
obj = std::shared_ptr<TElement>(state.obj, p);
|
obj = std::shared_ptr<TElement>(state.obj, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loadFromSharedStatePolymorphic(TSharedState& state, T& obj)
|
static void loadFromSharedStatePolymorphic(TSharedState& state,
|
||||||
|
T& obj,
|
||||||
|
const PolymorphicHandlerBase&)
|
||||||
{
|
{
|
||||||
// TODO Fix pointer addresses in case objects are deserialized using
|
|
||||||
// different bases
|
|
||||||
|
|
||||||
// reinterpret_pointer_cast is only since c++17
|
|
||||||
auto v = state.obj.get();
|
auto v = state.obj.get();
|
||||||
auto p = reinterpret_cast<TElement*>(v);
|
auto p = static_cast<TElement*>(v);
|
||||||
obj = std::shared_ptr<TElement>(state.obj, p);
|
obj = std::shared_ptr<TElement>(state.obj, p);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ namespace pointer_utils {
|
|||||||
// this class is used to store context for shared ptr owners
|
// this class is used to store context for shared ptr owners
|
||||||
struct PointerSharedStateBase
|
struct PointerSharedStateBase
|
||||||
{
|
{
|
||||||
|
size_t typeId{};
|
||||||
virtual ~PointerSharedStateBase() = default;
|
virtual ~PointerSharedStateBase() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -541,10 +542,10 @@ private:
|
|||||||
} else {
|
} else {
|
||||||
deserializedTypeId = ptrInfo.ownerTypeId;
|
deserializedTypeId = ptrInfo.ownerTypeId;
|
||||||
}
|
}
|
||||||
|
if (auto hndl =
|
||||||
if (canAssignToBase(baseTypeId, deserializedTypeId, ctx)) {
|
ctx.getPolymorphicHandler(baseTypeId, ptrInfo.sharedState->typeId)) {
|
||||||
TPtrManager<T>::loadFromSharedStatePolymorphic(
|
TPtrManager<T>::loadFromSharedStatePolymorphic(
|
||||||
getSharedStateObj<T>(ptrInfo), obj);
|
getSharedStateObj<T>(ptrInfo), obj, **hndl);
|
||||||
processObserverListPolymorphic(des, ptrInfo, ctx);
|
processObserverListPolymorphic(des, ptrInfo, ctx);
|
||||||
} else {
|
} else {
|
||||||
des.adapter().error(ReaderError::InvalidPointer);
|
des.adapter().error(ReaderError::InvalidPointer);
|
||||||
@@ -643,9 +644,9 @@ private:
|
|||||||
RTTI::template get<typename TPtrManager<T>::TElement>();
|
RTTI::template get<typename TPtrManager<T>::TElement>();
|
||||||
void*(&ptr) = reinterpret_cast<void*&>(TPtrManager<T>::getPtrRef(obj));
|
void*(&ptr) = reinterpret_cast<void*&>(TPtrManager<T>::getPtrRef(obj));
|
||||||
if (ptrInfo.ownerPtr) {
|
if (ptrInfo.ownerPtr) {
|
||||||
if (canAssignToBase(baseTypeId, ptrInfo.ownerTypeId, ctx)) {
|
if (auto hndl =
|
||||||
// TODO cast from one ptr to another
|
ctx.getPolymorphicHandler(baseTypeId, ptrInfo.ownerTypeId)) {
|
||||||
ptr = ptrInfo.ownerPtr;
|
ptr = hndl->get()->fromDerivedToBasePtr(ptrInfo.ownerPtr);
|
||||||
} else {
|
} else {
|
||||||
des.adapter().error(ReaderError::InvalidPointer);
|
des.adapter().error(ReaderError::InvalidPointer);
|
||||||
}
|
}
|
||||||
@@ -654,25 +655,6 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if actual deserialized type can be assigned to the base type
|
|
||||||
// (statically typed)
|
|
||||||
bool canAssignToBase(size_t baseTypeId,
|
|
||||||
size_t deserializedTypeId,
|
|
||||||
const TPolymorphicContext<RTTI>& ctx) const
|
|
||||||
{
|
|
||||||
if (baseTypeId == deserializedTypeId)
|
|
||||||
return true;
|
|
||||||
auto bases = ctx.getDirectBases(deserializedTypeId);
|
|
||||||
if (bases) {
|
|
||||||
for (auto typeId : *bases) {
|
|
||||||
if (canAssignToBase(baseTypeId, typeId, ctx)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Des>
|
template<typename Des>
|
||||||
void processObserverList(Des& des, PLCInfoDeserializer& ptrInfo) const
|
void processObserverList(Des& des, PLCInfoDeserializer& ptrInfo) const
|
||||||
{
|
{
|
||||||
@@ -696,9 +678,9 @@ private:
|
|||||||
{
|
{
|
||||||
assert(ptrInfo.ownershipType != PointerOwnershipType::Observer);
|
assert(ptrInfo.ownershipType != PointerOwnershipType::Observer);
|
||||||
for (auto& o : ptrInfo.observersList) {
|
for (auto& o : ptrInfo.observersList) {
|
||||||
if (canAssignToBase(o.baseTypeId, ptrInfo.ownerTypeId, ctx)) {
|
if (auto hndl =
|
||||||
// TODO cast from one ptr to another
|
ctx.getPolymorphicHandler(o.baseTypeId, ptrInfo.ownerTypeId)) {
|
||||||
o.obj.get() = ptrInfo.ownerPtr;
|
o.obj.get() = hndl->get()->fromDerivedToBasePtr(ptrInfo.ownerPtr);
|
||||||
} else {
|
} else {
|
||||||
des.adapter().error(ReaderError::InvalidPointer);
|
des.adapter().error(ReaderError::InvalidPointer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,8 @@ public:
|
|||||||
|
|
||||||
virtual void* getRootPtr(const void* obj) const = 0;
|
virtual void* getRootPtr(const void* obj) const = 0;
|
||||||
|
|
||||||
|
virtual void* fromDerivedToBasePtr(void* obj) const = 0;
|
||||||
|
|
||||||
virtual size_t getDerivedTypeId() const = 0;
|
virtual size_t getDerivedTypeId() const = 0;
|
||||||
|
|
||||||
virtual ~PolymorphicHandlerBase() = default;
|
virtual ~PolymorphicHandlerBase() = default;
|
||||||
@@ -111,6 +113,8 @@ public:
|
|||||||
static_cast<TBase*>(const_cast<void*>(obj)));
|
static_cast<TBase*>(const_cast<void*>(obj)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* fromDerivedToBasePtr(void* obj) const final { return toBase(obj); }
|
||||||
|
|
||||||
size_t getDerivedTypeId() const final
|
size_t getDerivedTypeId() const final
|
||||||
{
|
{
|
||||||
return RTTI::template get<TDerived>();
|
return RTTI::template get<TDerived>();
|
||||||
@@ -154,6 +158,12 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* fromDerivedToBasePtr(void*) const final
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
size_t getDerivedTypeId() const { return RTTI::template get<TDerived>(); };
|
size_t getDerivedTypeId() const { return RTTI::template get<TDerived>(); };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -188,12 +198,11 @@ private:
|
|||||||
typename TRoot,
|
typename TRoot,
|
||||||
typename TBase,
|
typename TBase,
|
||||||
typename TDerived>
|
typename TDerived>
|
||||||
void add(size_t depth)
|
void add()
|
||||||
{
|
{
|
||||||
addToMap<TSerializer, TRoot, TBase, TDerived>(depth == 1,
|
addToMap<TSerializer, TRoot, TBase, TDerived>(std::is_abstract<TDerived>{});
|
||||||
std::is_abstract<TDerived>{});
|
|
||||||
addChilds<TSerializer, THierarchy, TRoot, TBase, TDerived>(
|
addChilds<TSerializer, THierarchy, TRoot, TBase, TDerived>(
|
||||||
depth + 1, typename THierarchy<TDerived>::Childs{});
|
typename THierarchy<TDerived>::Childs{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TSerializer,
|
template<typename TSerializer,
|
||||||
@@ -204,15 +213,15 @@ private:
|
|||||||
typename TDerived,
|
typename TDerived,
|
||||||
typename T1,
|
typename T1,
|
||||||
typename... Tn>
|
typename... Tn>
|
||||||
void addChilds(size_t depth, PolymorphicClassesList<T1, Tn...>)
|
void addChilds(PolymorphicClassesList<T1, Tn...>)
|
||||||
{
|
{
|
||||||
static_assert(std::is_base_of<TDerived, T1>::value,
|
static_assert(std::is_base_of<TDerived, T1>::value,
|
||||||
"PolymorphicBaseClass<TBase> must derive a list of derived "
|
"PolymorphicBaseClass<TBase> must derive a list of derived "
|
||||||
"classes from TBase.");
|
"classes from TBase.");
|
||||||
add<TSerializer, THierarchy, TRoot, TBase, T1>(depth);
|
add<TSerializer, THierarchy, TRoot, TBase, T1>();
|
||||||
addChilds<TSerializer, THierarchy, TRoot, TBase, TDerived>(
|
addChilds<TSerializer, THierarchy, TRoot, TBase, TDerived>(
|
||||||
depth, PolymorphicClassesList<Tn...>{});
|
PolymorphicClassesList<Tn...>{});
|
||||||
add<TSerializer, THierarchy, TRoot, T1, T1>(0);
|
add<TSerializer, THierarchy, TRoot, T1, T1>();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TSerializer,
|
template<typename TSerializer,
|
||||||
@@ -221,7 +230,7 @@ private:
|
|||||||
typename TRoot,
|
typename TRoot,
|
||||||
typename TBase,
|
typename TBase,
|
||||||
typename TDerived>
|
typename TDerived>
|
||||||
void addChilds(size_t, PolymorphicClassesList<>)
|
void addChilds(PolymorphicClassesList<>)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +238,7 @@ private:
|
|||||||
typename TRoot,
|
typename TRoot,
|
||||||
typename TBase,
|
typename TBase,
|
||||||
typename TDerived>
|
typename TDerived>
|
||||||
void addToMap(bool directBase, std::false_type)
|
void addToMap(std::false_type)
|
||||||
{
|
{
|
||||||
using THandler =
|
using THandler =
|
||||||
PolymorphicHandler<RTTI, TSerializer, TRoot, TBase, TDerived>;
|
PolymorphicHandler<RTTI, TSerializer, TRoot, TBase, TDerived>;
|
||||||
@@ -256,25 +265,13 @@ private:
|
|||||||
}
|
}
|
||||||
it->second.push_back(key.derivedHash);
|
it->second.push_back(key.derivedHash);
|
||||||
}
|
}
|
||||||
if (directBase) {
|
|
||||||
auto it = _derivedToBaseArray.find(key.derivedHash);
|
|
||||||
if (it == _derivedToBaseArray.end()) {
|
|
||||||
it = _derivedToBaseArray
|
|
||||||
.emplace(std::piecewise_construct,
|
|
||||||
std::forward_as_tuple(key.derivedHash),
|
|
||||||
std::forward_as_tuple(
|
|
||||||
pointer_utils::StdPolyAlloc<size_t>{ _memResource }))
|
|
||||||
.first;
|
|
||||||
}
|
|
||||||
it->second.push_back(key.baseHash);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TSerializer,
|
template<typename TSerializer,
|
||||||
typename TRoot,
|
typename TRoot,
|
||||||
typename TBase,
|
typename TBase,
|
||||||
typename TDerived>
|
typename TDerived>
|
||||||
void addToMap(bool directBase, std::true_type)
|
void addToMap(std::true_type)
|
||||||
{
|
{
|
||||||
using THandler = AbstractPolymorphicHandler<RTTI, TRoot, TBase, TDerived>;
|
using THandler = AbstractPolymorphicHandler<RTTI, TRoot, TBase, TDerived>;
|
||||||
BaseToDerivedKey key{ RTTI::template get<TBase>(),
|
BaseToDerivedKey key{ RTTI::template get<TBase>(),
|
||||||
@@ -288,19 +285,7 @@ private:
|
|||||||
alloc.deallocate(data, 1);
|
alloc.deallocate(data, 1);
|
||||||
},
|
},
|
||||||
alloc);
|
alloc);
|
||||||
_baseToDerivedMap.emplace(key, std::move(handler)).second;
|
_baseToDerivedMap.emplace(key, std::move(handler));
|
||||||
if (directBase) {
|
|
||||||
auto it = _derivedToBaseArray.find(key.derivedHash);
|
|
||||||
if (it == _derivedToBaseArray.end()) {
|
|
||||||
it = _derivedToBaseArray
|
|
||||||
.emplace(std::piecewise_construct,
|
|
||||||
std::forward_as_tuple(key.derivedHash),
|
|
||||||
std::forward_as_tuple(
|
|
||||||
pointer_utils::StdPolyAlloc<size_t>{ _memResource }))
|
|
||||||
.first;
|
|
||||||
}
|
|
||||||
it->second.push_back(key.baseHash);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MemResourceBase* _memResource;
|
MemResourceBase* _memResource;
|
||||||
@@ -328,17 +313,6 @@ private:
|
|||||||
std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>>
|
std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>>
|
||||||
_baseToDerivedArray;
|
_baseToDerivedArray;
|
||||||
|
|
||||||
// Used to iterate through hierarchy chain from most derived to the base(s)
|
|
||||||
std::unordered_map<
|
|
||||||
size_t,
|
|
||||||
std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>,
|
|
||||||
std::hash<size_t>,
|
|
||||||
std::equal_to<size_t>,
|
|
||||||
pointer_utils::StdPolyAlloc<
|
|
||||||
std::pair<const size_t,
|
|
||||||
std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>>
|
|
||||||
_derivedToBaseArray;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PolymorphicContext(MemResourceBase* memResource = nullptr)
|
explicit PolymorphicContext(MemResourceBase* memResource = nullptr)
|
||||||
: _memResource{ memResource }
|
: _memResource{ memResource }
|
||||||
@@ -349,11 +323,6 @@ public:
|
|||||||
std::pair<const size_t,
|
std::pair<const size_t,
|
||||||
std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>{
|
std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>{
|
||||||
memResource } }
|
memResource } }
|
||||||
, _derivedToBaseArray{ pointer_utils::StdPolyAlloc<
|
|
||||||
std::pair<const size_t,
|
|
||||||
std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>{
|
|
||||||
memResource } }
|
|
||||||
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,7 +348,7 @@ public:
|
|||||||
typename... Tn>
|
typename... Tn>
|
||||||
void registerBasesList(PolymorphicClassesList<T1, Tn...>)
|
void registerBasesList(PolymorphicClassesList<T1, Tn...>)
|
||||||
{
|
{
|
||||||
add<TSerializer, THierarchy, T1, T1, T1>(0);
|
add<TSerializer, THierarchy, T1, T1, T1>();
|
||||||
registerBasesList<TSerializer, THierarchy>(PolymorphicClassesList<Tn...>{});
|
registerBasesList<TSerializer, THierarchy>(PolymorphicClassesList<Tn...>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,15 +433,16 @@ public:
|
|||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>*
|
const std::shared_ptr<PolymorphicHandlerBase>* getPolymorphicHandler(
|
||||||
getDirectBases(size_t derivedTypeId) const
|
size_t baseTypeId,
|
||||||
|
size_t derivedTypeId) const
|
||||||
{
|
{
|
||||||
auto it = _derivedToBaseArray.find(derivedTypeId);
|
auto it =
|
||||||
if (it != _derivedToBaseArray.end()) {
|
_baseToDerivedMap.find(BaseToDerivedKey{ baseTypeId, derivedTypeId });
|
||||||
return &it->second;
|
if (it == _baseToDerivedMap.end()) {
|
||||||
} else {
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
return &it->second;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -149,12 +149,10 @@ struct PolymorphicBaseClass<Base>
|
|||||||
: PolymorphicDerivedClasses<Derived1, Derived2>
|
: PolymorphicDerivedClasses<Derived1, Derived2>
|
||||||
{};
|
{};
|
||||||
|
|
||||||
// this is commented on purpose, to test scenario when base class is registered
|
template<>
|
||||||
// (Base) but using instance of Derived1 which is not registered as base
|
struct PolymorphicBaseClass<Derived1>
|
||||||
// template<>
|
: PolymorphicDerivedClasses<MultipleVirtualInheritance>
|
||||||
// struct PolymorphicBaseClass<Derived1> :
|
{};
|
||||||
// PolymorphicDerivedClasses<MultipleVirtualInheritance> {
|
|
||||||
// };
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct PolymorphicBaseClass<Derived2>
|
struct PolymorphicBaseClass<Derived2>
|
||||||
@@ -410,8 +408,7 @@ TEST_F(SerializeExtensionPointerPolymorphicTypes,
|
|||||||
Eq(bitsery::ReaderError::InvalidPointer));
|
Eq(bitsery::ReaderError::InvalidPointer));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(SerializeExtensionPointerPolymorphicTypes,
|
TEST_F(SerializeExtensionPointerPolymorphicTypes, OwnerIsCastObserverType)
|
||||||
OwnerIsStaticallyCastToObserverType)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
MultipleVirtualInheritance md{ 1, 2, 3, 4 };
|
MultipleVirtualInheritance md{ 1, 2, 3, 4 };
|
||||||
|
|||||||
Reference in New Issue
Block a user