mirror of
https://github.com/fraillt/bitsery.git
synced 2026-08-09 06:49:32 +00:00
all bitsery types that allocates memory can be configured to accept
memory resource for allocation
This commit is contained in:
committed by
Mindaugas Vinkelis
parent
105aa5f9e5
commit
a1785f3e15
@@ -37,14 +37,16 @@
|
||||
* helper classes (FtorExtValue, FtorExtObject) to reduce boilerplate and improve readability in places where you need to provide (des)serialize function/lambda that uses extension.
|
||||
e.g. instead of writing `s.container(obj, [](S& s, MyData& data) {s.ext(data, MyExtension{});});` you can write `s.container(obj, FtorExtObject<MyExtension>{});`
|
||||
* added config options to enable/disable checking input adapter and data errors (`CheckAdapterErrors` and `CheckDataErrors`) (default is enabled)
|
||||
* all allocation in the library can be customized using memory resource (similar to c++ 17 memory resource)
|
||||
* shared state in PolymorphicLinkingContext is allocated using memory resource
|
||||
* in `SharedPtr` extension, shared_ptr managed object and control block is allocated using memory resource
|
||||
* classes that accept memory resource: PolymorphicLinkingContext, PolymorphicContext, InheritanceContext.
|
||||
|
||||
## bugfix
|
||||
* fixed enabledBitPacking where writer and internal context states was not restored properly after exiting from this function
|
||||
|
||||
## todo
|
||||
* add allocator support for polymorphic and pointer linking contexts
|
||||
* flexible syntax, enable option (using config) to use compactvalue for fundamental types by default (it should be off to preserve ABI breaking change).
|
||||
* improve SmartPtr by allocating shared_ptr control block using provided allocator
|
||||
* rename "flexible" to "brief_syntax"
|
||||
|
||||
# [4.6.1](https://github.com/fraillt/bitsery/compare/v4.6.0...v4.6.1) (2019-06-27)
|
||||
|
||||
@@ -209,8 +209,9 @@ namespace bitsery {
|
||||
* value
|
||||
*/
|
||||
|
||||
template<size_t VSIZE, typename T, typename std::enable_if<details::IsFundamentalType<T>::value>::type * = nullptr>
|
||||
template<size_t VSIZE, typename T>
|
||||
void value(T &v) {
|
||||
static_assert(details::IsFundamentalType<T>::value, "Value must be integral, float or enum type.");
|
||||
using TValue = typename details::IntegralFromFundamental<T>::TValue;
|
||||
this->_adapter.template readBytes<VSIZE>(reinterpret_cast<TValue &>(v));
|
||||
}
|
||||
|
||||
@@ -49,21 +49,21 @@ namespace bitsery {
|
||||
return PointerOwnershipType::Owner;
|
||||
}
|
||||
|
||||
static void create(T& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, size_t typeId) {
|
||||
static void create(T& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc, size_t typeId) {
|
||||
obj = alloc.newObject<TElement>(typeId);
|
||||
}
|
||||
|
||||
static void createPolymorphic(T& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc,
|
||||
static void createPolymorphic(T& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc,
|
||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
obj = static_cast<TElement*>(handler->create(alloc));
|
||||
}
|
||||
|
||||
static void destroy(T& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, size_t typeId) {
|
||||
static void destroy(T& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc, size_t typeId) {
|
||||
alloc.deleteObject(obj, typeId);
|
||||
obj = nullptr;
|
||||
}
|
||||
|
||||
static void destroyPolymorphic(T& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc,
|
||||
static void destroyPolymorphic(T& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc,
|
||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
handler->destroy(alloc, obj);
|
||||
obj = nullptr;
|
||||
@@ -91,11 +91,11 @@ namespace bitsery {
|
||||
return obj;
|
||||
}
|
||||
|
||||
static void destroy(T& obj, pointer_utils::PolymorphicAllocatorWithTypeId& , size_t ) {
|
||||
static void destroy(T& obj, MemResourceBase* , size_t ) {
|
||||
obj = nullptr;
|
||||
}
|
||||
|
||||
static void destroyPolymorphic(T& obj, pointer_utils::PolymorphicAllocatorWithTypeId& , PolymorphicHandlerBase& ) {
|
||||
static void destroyPolymorphic(T& obj, MemResourceBase* , PolymorphicHandlerBase& ) {
|
||||
obj = nullptr;
|
||||
}
|
||||
|
||||
@@ -119,19 +119,19 @@ namespace bitsery {
|
||||
// this code is unreachable for reference type, but is necessary to compile
|
||||
// LCOV_EXCL_START
|
||||
|
||||
static void create(T& , pointer_utils::PolymorphicAllocatorWithTypeId& , size_t ) {
|
||||
static void create(T& , MemResourceBase* , size_t ) {
|
||||
|
||||
}
|
||||
|
||||
static void createPolymorphic(T& , pointer_utils::PolymorphicAllocatorWithTypeId& , PolymorphicHandlerBase& ) {
|
||||
static void createPolymorphic(T& , MemResourceBase* , PolymorphicHandlerBase& ) {
|
||||
|
||||
}
|
||||
|
||||
static void destroy(T& , pointer_utils::PolymorphicAllocatorWithTypeId& , size_t ) {
|
||||
static void destroy(T& , MemResourceBase* , size_t ) {
|
||||
|
||||
}
|
||||
|
||||
static void destroyPolymorphic(T& , pointer_utils::PolymorphicAllocatorWithTypeId& , PolymorphicHandlerBase& ) {
|
||||
static void destroyPolymorphic(T& , MemResourceBase* , PolymorphicHandlerBase& ) {
|
||||
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
@@ -70,108 +70,100 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename TDeleter>
|
||||
static void create(std::unique_ptr<TElement, TDeleter>& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc,
|
||||
static void create(std::unique_ptr<TElement, TDeleter>& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc,
|
||||
size_t typeId) {
|
||||
obj.reset(alloc.newObject<TElement>(typeId));
|
||||
}
|
||||
|
||||
template<typename TDeleter>
|
||||
static void createPolymorphic(std::unique_ptr<TElement, TDeleter>& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc,
|
||||
static void createPolymorphic(std::unique_ptr<TElement, TDeleter>& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc,
|
||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
obj.reset(static_cast<TElement*>(handler->create(alloc)));
|
||||
}
|
||||
|
||||
template<typename TDel>
|
||||
static void destroy(std::unique_ptr<TElement, TDel>& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, size_t typeId) {
|
||||
static void destroy(std::unique_ptr<TElement, TDel>& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc, size_t typeId) {
|
||||
uniquePtrDestroy(obj, alloc, typeId, std::is_same<std::unique_ptr<TElement>, T>{});
|
||||
}
|
||||
|
||||
template<typename TDel>
|
||||
static void destroyPolymorphic(std::unique_ptr<TElement, TDel>& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc,
|
||||
static void destroyPolymorphic(std::unique_ptr<TElement, TDel>& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc,
|
||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
uniquePtrDestroyPolymorphic(obj, alloc, handler, std::is_same<std::unique_ptr<TElement>, T>{});
|
||||
}
|
||||
|
||||
static void destroy(std::shared_ptr<TElement>& obj, pointer_utils::PolymorphicAllocatorWithTypeId&, size_t) {
|
||||
static void destroy(std::shared_ptr<TElement>& obj, MemResourceBase*, size_t) {
|
||||
obj.reset();
|
||||
}
|
||||
|
||||
static void destroyPolymorphic(std::shared_ptr<TElement>& obj, pointer_utils::PolymorphicAllocatorWithTypeId&,
|
||||
static void destroyPolymorphic(std::shared_ptr<TElement>& obj, MemResourceBase*,
|
||||
const std::shared_ptr<PolymorphicHandlerBase>&) {
|
||||
obj.reset();
|
||||
}
|
||||
|
||||
static void destroy(std::weak_ptr<TElement>& obj, pointer_utils::PolymorphicAllocatorWithTypeId&, size_t) {
|
||||
static void destroy(std::weak_ptr<TElement>& obj, MemResourceBase*, size_t) {
|
||||
obj.reset();
|
||||
}
|
||||
|
||||
static void destroyPolymorphic(std::weak_ptr<TElement>& obj, pointer_utils::PolymorphicAllocatorWithTypeId&,
|
||||
static void destroyPolymorphic(std::weak_ptr<TElement>& obj, MemResourceBase*,
|
||||
const std::shared_ptr<PolymorphicHandlerBase>&) {
|
||||
obj.reset();
|
||||
}
|
||||
|
||||
static std::unique_ptr<pointer_utils::PointerSharedStateBase> createShared(
|
||||
std::shared_ptr<TElement>& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, size_t typeId) {
|
||||
// define a type that will store shared state for shared and weak ptrs
|
||||
using TSharedState = SharedPtrSharedState;
|
||||
|
||||
static void createShared(TSharedState& state,
|
||||
std::shared_ptr<TElement>& obj, MemResourceBase* memResource, size_t typeId) {
|
||||
// capture deleter parameters by value
|
||||
obj = std::shared_ptr<TElement>(alloc.newObject<TElement>(typeId),
|
||||
[alloc, typeId](TElement* data) {
|
||||
alloc.deleteObject(data, typeId);
|
||||
});
|
||||
auto state = new SharedPtrSharedState{};
|
||||
state->obj = obj;
|
||||
return std::unique_ptr<pointer_utils::PointerSharedStateBase>{state};
|
||||
pointer_utils::PolymorphicAllocatorWithTypeId alloc{memResource};
|
||||
obj.reset(alloc.newObject<TElement>(typeId), [alloc, typeId](TElement* data) {
|
||||
alloc.deleteObject(data, typeId);
|
||||
}, pointer_utils::PolymorphicAllocatorWrapper<TElement>(memResource));
|
||||
state.obj = obj;
|
||||
}
|
||||
|
||||
static std::unique_ptr<pointer_utils::PointerSharedStateBase> createSharedPolymorphic(
|
||||
std::shared_ptr<TElement>& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc,
|
||||
static void createSharedPolymorphic(TSharedState& state,
|
||||
std::shared_ptr<TElement>& obj, MemResourceBase* memResource,
|
||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
// capture deleter parameters by value
|
||||
obj = std::shared_ptr<TElement>(static_cast<TElement*>(handler->create(alloc)),
|
||||
[alloc, handler](TElement* data) {
|
||||
handler->destroy(alloc, data);
|
||||
});
|
||||
auto state = new SharedPtrSharedState{};
|
||||
state->obj = obj;
|
||||
return std::unique_ptr<pointer_utils::PointerSharedStateBase>{state};
|
||||
pointer_utils::PolymorphicAllocatorWithTypeId alloc{memResource};
|
||||
obj.reset(static_cast<TElement*>(handler->create(alloc)), [alloc, handler](TElement* data) {
|
||||
handler->destroy(alloc, data);
|
||||
}, pointer_utils::PolymorphicAllocatorWrapper<TElement>(memResource));
|
||||
state.obj = obj;
|
||||
}
|
||||
|
||||
static std::unique_ptr<pointer_utils::PointerSharedStateBase> createShared(
|
||||
std::weak_ptr<TElement>& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, size_t typeId) {
|
||||
auto res = std::shared_ptr<TElement>(alloc.newObject<TElement>(typeId),
|
||||
[alloc, typeId](TElement* data) {
|
||||
alloc.deleteObject(data, typeId);
|
||||
});
|
||||
static void createShared(TSharedState& state,
|
||||
std::weak_ptr<TElement>& obj, MemResourceBase* memResource, size_t typeId) {
|
||||
pointer_utils::PolymorphicAllocatorWithTypeId alloc{memResource};
|
||||
std::shared_ptr<TElement> res(alloc.newObject<TElement>(typeId),[alloc, typeId](TElement* data) {
|
||||
alloc.deleteObject(data, typeId);
|
||||
}, pointer_utils::PolymorphicAllocatorWrapper<TElement>(memResource));
|
||||
obj = res;
|
||||
auto state = new SharedPtrSharedState{};
|
||||
state->obj = res;
|
||||
return std::unique_ptr<pointer_utils::PointerSharedStateBase>{state};
|
||||
state.obj = res;
|
||||
}
|
||||
|
||||
static std::unique_ptr<pointer_utils::PointerSharedStateBase> createSharedPolymorphic(
|
||||
std::weak_ptr<TElement>& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc,
|
||||
static void createSharedPolymorphic(TSharedState& state,
|
||||
std::weak_ptr<TElement>& obj, MemResourceBase* memResource,
|
||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
auto res = std::shared_ptr<TElement>(static_cast<TElement*>(handler->create(alloc)),
|
||||
[alloc, handler](TElement* data) {
|
||||
handler->destroy(alloc, data);
|
||||
});
|
||||
pointer_utils::PolymorphicAllocatorWithTypeId alloc{memResource};
|
||||
std::shared_ptr<TElement> res(static_cast<TElement*>(handler->create(alloc)),
|
||||
[alloc, handler](TElement* data) {
|
||||
handler->destroy(alloc, data);
|
||||
}, pointer_utils::PolymorphicAllocatorWrapper<TElement>(memResource));
|
||||
obj = res;
|
||||
auto state = new SharedPtrSharedState{};
|
||||
state->obj = res;
|
||||
return std::unique_ptr<pointer_utils::PointerSharedStateBase>{state};
|
||||
state.obj = res;
|
||||
}
|
||||
|
||||
static std::unique_ptr<pointer_utils::PointerSharedStateBase> getSharedState(T& obj) {
|
||||
auto state = new SharedPtrSharedState{};
|
||||
//to work with weak_ptr and shared_ptr create new std::shared_ptr
|
||||
state->obj = std::shared_ptr<TElement>(obj);
|
||||
return std::unique_ptr<pointer_utils::PointerSharedStateBase>{state};
|
||||
static void saveToSharedState(TSharedState& state, T& obj) {
|
||||
state.obj = std::shared_ptr<TElement>(obj);
|
||||
}
|
||||
|
||||
static void loadFromSharedState(pointer_utils::PointerSharedStateBase* ctx, T& obj) {
|
||||
auto state = dynamic_cast<SharedPtrSharedState*>(ctx);
|
||||
static void loadFromSharedState(TSharedState& state, T& obj) {
|
||||
//reinterpret_pointer_cast is only since c++17
|
||||
auto p = reinterpret_cast<TElement*>(state->obj.get());
|
||||
obj = std::shared_ptr<TElement>(state->obj, p);
|
||||
auto p = reinterpret_cast<TElement*>(state.obj.get());
|
||||
obj = std::shared_ptr<TElement>(state.obj, p);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -64,7 +64,7 @@ namespace bitsery {
|
||||
class PolymorphicAllocatorWithTypeId final {
|
||||
public:
|
||||
|
||||
explicit constexpr PolymorphicAllocatorWithTypeId(MemResourceBase* memResource = nullptr)
|
||||
constexpr PolymorphicAllocatorWithTypeId(MemResourceBase* memResource = nullptr)
|
||||
:_resource{memResource} {}
|
||||
|
||||
template<typename T>
|
||||
@@ -122,7 +122,7 @@ namespace bitsery {
|
||||
// it just wraps our PolymorphicAllocatorWithTypeId and pass 0 as typeId
|
||||
// and defines core functions for c++ Allocator concept,
|
||||
template<class T>
|
||||
struct PolymorphicAllocatorWrapper final {
|
||||
struct PolymorphicAllocatorWrapper {
|
||||
using value_type = T;
|
||||
|
||||
explicit constexpr PolymorphicAllocatorWrapper(MemResourceBase* memResource)
|
||||
|
||||
@@ -62,6 +62,18 @@ namespace bitsery {
|
||||
virtual ~PointerSharedStateBase() = default;
|
||||
};
|
||||
|
||||
struct PointerSharedStateDeleter {
|
||||
PointerSharedStateDeleter() = default;
|
||||
explicit PointerSharedStateDeleter(MemResourceBase* memResource)
|
||||
:_memResource{memResource} {}
|
||||
void operator()(PointerSharedStateBase* data) const {
|
||||
data->~PointerSharedStateBase();
|
||||
PolymorphicAllocatorWrapper<PointerSharedStateBase> alloc{_memResource};
|
||||
alloc.deallocate(data, 1);
|
||||
}
|
||||
MemResourceBase* _memResource;
|
||||
};
|
||||
|
||||
//PLC info is internal classes for serializer, and deserializer
|
||||
struct PLCInfo {
|
||||
explicit PLCInfo(PointerOwnershipType ownershipType_)
|
||||
@@ -98,9 +110,11 @@ namespace bitsery {
|
||||
};
|
||||
|
||||
struct PLCInfoDeserializer : PLCInfo {
|
||||
PLCInfoDeserializer(void* ptr, PointerOwnershipType ownershipType_)
|
||||
PLCInfoDeserializer(void* ptr, PointerOwnershipType ownershipType_, MemResourceBase* memResource_)
|
||||
: PLCInfo(ownershipType_),
|
||||
ownerPtr{ptr} {};
|
||||
ownerPtr{ptr},
|
||||
memResource{memResource_},
|
||||
observersList{PolymorphicAllocatorWrapper<std::reference_wrapper<void*>>{memResource_}} {};
|
||||
|
||||
//need to override these explicitly because we have pointer member
|
||||
PLCInfoDeserializer(const PLCInfoDeserializer&) = delete;
|
||||
@@ -129,15 +143,17 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
void* ownerPtr;
|
||||
std::vector<std::reference_wrapper<void*>> observersList{};
|
||||
std::unique_ptr<PointerSharedStateBase> sharedState{};
|
||||
MemResourceBase* memResource;
|
||||
std::vector<std::reference_wrapper<void*>,
|
||||
PolymorphicAllocatorWrapper<std::reference_wrapper<void*>>> observersList;
|
||||
std::unique_ptr<PointerSharedStateBase, PointerSharedStateDeleter> sharedState{};
|
||||
};
|
||||
|
||||
class PointerLinkingContextSerialization {
|
||||
public:
|
||||
explicit PointerLinkingContextSerialization()
|
||||
explicit PointerLinkingContextSerialization(MemResourceBase* memResource = nullptr)
|
||||
: _currId{0},
|
||||
_ptrMap{} {}
|
||||
_ptrMap{PolymorphicAllocatorWrapper<std::pair<const void*, PLCInfoSerializer>>{memResource}} {}
|
||||
|
||||
PointerLinkingContextSerialization(const PointerLinkingContextSerialization&) = delete;
|
||||
|
||||
@@ -172,14 +188,17 @@ namespace bitsery {
|
||||
|
||||
private:
|
||||
size_t _currId;
|
||||
std::unordered_map<const void*, PLCInfoSerializer> _ptrMap;
|
||||
|
||||
std::unordered_map<const void*, PLCInfoSerializer,
|
||||
std::hash<const void*>, std::equal_to<const void*>,
|
||||
PolymorphicAllocatorWrapper<std::pair<const void*, PLCInfoSerializer>>
|
||||
> _ptrMap;
|
||||
};
|
||||
|
||||
class PointerLinkingContextDeserialization {
|
||||
public:
|
||||
explicit PointerLinkingContextDeserialization()
|
||||
: _idMap{} {}
|
||||
explicit PointerLinkingContextDeserialization(MemResourceBase* memResource = nullptr)
|
||||
: _memResource{memResource},
|
||||
_idMap{PolymorphicAllocatorWrapper<std::pair<size_t, PLCInfoDeserializer>>{memResource}} {}
|
||||
|
||||
PointerLinkingContextDeserialization(const PointerLinkingContextDeserialization&) = delete;
|
||||
|
||||
@@ -192,7 +211,7 @@ namespace bitsery {
|
||||
~PointerLinkingContextDeserialization() = default;
|
||||
|
||||
PLCInfoDeserializer& getInfoById(size_t id, PointerOwnershipType ptrType) {
|
||||
auto res = _idMap.emplace(id, PLCInfoDeserializer{nullptr, ptrType});
|
||||
auto res = _idMap.emplace(id, PLCInfoDeserializer{nullptr, ptrType, _memResource});
|
||||
auto& ptrInfo = res.first->second;
|
||||
if (!res.second)
|
||||
ptrInfo.update(ptrType);
|
||||
@@ -213,13 +232,19 @@ namespace bitsery {
|
||||
});
|
||||
}
|
||||
|
||||
PolymorphicAllocatorWithTypeId& getAllocator() {
|
||||
return _polyAlloc;
|
||||
MemResourceBase* getMemResource() noexcept {
|
||||
return _memResource;
|
||||
}
|
||||
|
||||
void setMemResource(MemResourceBase* resource) noexcept {
|
||||
_memResource = resource;
|
||||
}
|
||||
|
||||
private:
|
||||
PolymorphicAllocatorWithTypeId _polyAlloc{};
|
||||
std::unordered_map<size_t, PLCInfoDeserializer> _idMap;
|
||||
MemResourceBase* _memResource;
|
||||
std::unordered_map<size_t, PLCInfoDeserializer,
|
||||
std::hash<size_t>, std::equal_to<size_t>,
|
||||
PolymorphicAllocatorWrapper<std::pair<size_t, PLCInfoDeserializer>>> _idMap;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -228,7 +253,9 @@ namespace bitsery {
|
||||
public pointer_utils::PointerLinkingContextSerialization,
|
||||
public pointer_utils::PointerLinkingContextDeserialization {
|
||||
public:
|
||||
explicit PointerLinkingContext() = default;
|
||||
explicit PointerLinkingContext(MemResourceBase* memResource = nullptr)
|
||||
:pointer_utils::PointerLinkingContextSerialization(memResource),
|
||||
pointer_utils::PointerLinkingContextDeserialization(memResource) {};
|
||||
|
||||
bool isValid() {
|
||||
return isPointerSerializationValid() && isPointerDeserializationValid();
|
||||
@@ -265,7 +292,7 @@ namespace bitsery {
|
||||
|
||||
auto ptr = TPtrManager<T>::getPtr(const_cast<T&>(obj));
|
||||
if (ptr) {
|
||||
auto& ctx = ser.template context<PointerLinkingContext>();
|
||||
auto& ctx = ser.template context<pointer_utils::PointerLinkingContextSerialization>();
|
||||
auto& ptrInfo = ctx.getInfoByPtr(getBasePtr(ptr), TPtrManager<T>::getOwnership());
|
||||
details::writeSize(w, ptrInfo.id);
|
||||
if (TPtrManager<T>::getOwnership() != PointerOwnershipType::Observer) {
|
||||
@@ -283,39 +310,45 @@ namespace bitsery {
|
||||
void deserialize(Des& des, Reader& r, T& obj, Fnc&& fnc) const {
|
||||
size_t id{};
|
||||
details::readSize(r, id, 0, std::false_type{});
|
||||
auto& ctx = des.template context<PointerLinkingContext>();
|
||||
auto& alloc = ctx.getAllocator();
|
||||
auto& ctx = des.template context<pointer_utils::PointerLinkingContextDeserialization>();
|
||||
auto prevResource = ctx.getMemResource();
|
||||
auto memResource = _resource ? _resource : prevResource;
|
||||
// if we have resource and propagate is true, then change current resource
|
||||
// so that deserializing nested pointers it will be used
|
||||
if (_resource && _resourcePropagate) {
|
||||
ctx.setMemResource(memResource);
|
||||
}
|
||||
if (id) {
|
||||
auto& ptrInfo = ctx.getInfoById(id, TPtrManager<T>::getOwnership());
|
||||
deserializeImpl(alloc, ptrInfo, des, obj, std::forward<Fnc>(fnc), r, IsPolymorphic<T>{},
|
||||
deserializeImpl(memResource, ptrInfo, des, obj, std::forward<Fnc>(fnc), r, IsPolymorphic<T>{},
|
||||
OwnershipType<TPtrManager<T>::getOwnership()>{});
|
||||
} else {
|
||||
if (_ptrType == PointerType::Nullable) {
|
||||
if (auto ptr = TPtrManager<T>::getPtr(obj)) {
|
||||
auto prevMemResource = alloc.getMemResource();
|
||||
if (_resource) alloc.setMemResource(_resource);
|
||||
destroyPtr(alloc, des, obj, IsPolymorphic<T>{});
|
||||
alloc.setMemResource(prevMemResource);
|
||||
destroyPtr(memResource, des, obj, IsPolymorphic<T>{});
|
||||
};
|
||||
} else
|
||||
r.error(ReaderError::InvalidPointer);
|
||||
}
|
||||
if (_resource && _resourcePropagate) {
|
||||
ctx.setMemResource(prevResource);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template<typename Des, typename TObj>
|
||||
void destroyPtr(PolymorphicAllocatorWithTypeId& alloc, Des& des, TObj& obj,
|
||||
void destroyPtr(MemResourceBase* memResource, Des& des, TObj& obj,
|
||||
std::true_type /*polymorphic*/) const {
|
||||
const auto& ctx = des.template context<TPolymorphicContext<RTTI>>();
|
||||
auto ptr = TPtrManager<TObj>::getPtr(obj);
|
||||
TPtrManager<TObj>::destroyPolymorphic(obj, alloc, ctx.getPolymorphicHandler(*ptr));
|
||||
TPtrManager<TObj>::destroyPolymorphic(obj, memResource, ctx.getPolymorphicHandler(*ptr));
|
||||
}
|
||||
|
||||
template<typename Des, typename TObj>
|
||||
void destroyPtr(PolymorphicAllocatorWithTypeId& alloc, Des&, TObj& obj,
|
||||
void destroyPtr(MemResourceBase* memResource, Des&, TObj& obj,
|
||||
std::false_type /*polymorphic*/) const {
|
||||
TPtrManager<TObj>::destroy(obj, alloc, RTTI::template get<typename TPtrManager<TObj>::TElement>());
|
||||
TPtrManager<TObj>::destroy(obj, memResource, RTTI::template get<typename TPtrManager<TObj>::TElement>());
|
||||
}
|
||||
|
||||
|
||||
@@ -339,113 +372,112 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc, typename Reader>
|
||||
void deserializeImpl(PolymorphicAllocatorWithTypeId& alloc, PLCInfoDeserializer& ptrInfo, Des& des, T& obj, Fnc&&,
|
||||
void deserializeImpl(MemResourceBase* memResource, PLCInfoDeserializer& ptrInfo, Des& des, T& obj, Fnc&&,
|
||||
Reader& r, std::true_type, OwnershipType<PointerOwnershipType::Owner>) const {
|
||||
const auto& ctx = des.template context<TPolymorphicContext<RTTI>>();
|
||||
auto prevMemResource = alloc.getMemResource();
|
||||
ctx.deserialize(des, r, TPtrManager<T>::getPtr(obj),
|
||||
[&obj, &alloc, this, prevMemResource](
|
||||
[&obj, this, memResource](
|
||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
if (_resource) alloc.setMemResource(_resource);
|
||||
TPtrManager<T>::createPolymorphic(obj, alloc, handler);
|
||||
if (!_resourcePropagate) alloc.setMemResource(prevMemResource);
|
||||
TPtrManager<T>::createPolymorphic(obj, memResource, handler);
|
||||
return TPtrManager<T>::getPtr(obj);
|
||||
},
|
||||
[&obj, &alloc, this](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
if (_resource) alloc.setMemResource(_resource);
|
||||
TPtrManager<T>::destroyPolymorphic(obj, alloc, handler);
|
||||
[&obj, memResource, this](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
TPtrManager<T>::destroyPolymorphic(obj, memResource, handler);
|
||||
});
|
||||
alloc.setMemResource(prevMemResource);
|
||||
ptrInfo.processOwner(TPtrManager<T>::getPtr(obj));
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc, typename Reader>
|
||||
void deserializeImpl(PolymorphicAllocatorWithTypeId& alloc, PLCInfoDeserializer& ptrInfo, Des& des, T& obj, Fnc&& fnc,
|
||||
void deserializeImpl(MemResourceBase* memResource, PLCInfoDeserializer& ptrInfo, Des& des, T& obj, Fnc&& fnc,
|
||||
Reader&, std::false_type, OwnershipType<PointerOwnershipType::Owner>) const {
|
||||
auto ptr = TPtrManager<T>::getPtr(obj);
|
||||
if (ptr) {
|
||||
fnc(des, *ptr);
|
||||
} else {
|
||||
auto prevMemResource = alloc.getMemResource();
|
||||
if (_resource) alloc.setMemResource(_resource);
|
||||
TPtrManager<T>::create(obj, alloc, RTTI::template get<typename TPtrManager<T>::TElement>());
|
||||
if (!_resourcePropagate) alloc.setMemResource(prevMemResource);
|
||||
TPtrManager<T>::create(obj, memResource, RTTI::template get<typename TPtrManager<T>::TElement>());
|
||||
ptr = TPtrManager<T>::getPtr(obj);
|
||||
fnc(des, *ptr);
|
||||
alloc.setMemResource(prevMemResource);
|
||||
}
|
||||
ptrInfo.processOwner(ptr);
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc, typename Reader>
|
||||
void deserializeImpl(PolymorphicAllocatorWithTypeId& alloc, PLCInfoDeserializer& ptrInfo, Des& des, T& obj, Fnc&&,
|
||||
void deserializeImpl(MemResourceBase* memResource, PLCInfoDeserializer& ptrInfo, Des& des, T& obj, Fnc&&,
|
||||
Reader& r, std::true_type,
|
||||
OwnershipType<PointerOwnershipType::SharedOwner>) const {
|
||||
auto& sharedState = ptrInfo.sharedState;
|
||||
if (!sharedState) {
|
||||
if (!ptrInfo.sharedState) {
|
||||
const auto& ctx = des.template context<TPolymorphicContext<RTTI>>();
|
||||
auto prevMemResource = alloc.getMemResource();
|
||||
ctx.deserialize(des, r, TPtrManager<T>::getPtr(obj),
|
||||
[&obj, &alloc, &sharedState, this, prevMemResource](
|
||||
[&obj, &ptrInfo, memResource, this](
|
||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
if (_resource) alloc.setMemResource(_resource);
|
||||
sharedState = TPtrManager<T>::createSharedPolymorphic(obj, alloc, handler);
|
||||
if (!_resourcePropagate) alloc.setMemResource(prevMemResource);
|
||||
TPtrManager<T>::createSharedPolymorphic(
|
||||
createAndGetSharedStateObj<T>(ptrInfo),
|
||||
obj, memResource, handler);
|
||||
return TPtrManager<T>::getPtr(obj);
|
||||
},
|
||||
[&obj, &alloc, this](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
if (_resource) alloc.setMemResource(_resource);
|
||||
TPtrManager<T>::destroyPolymorphic(obj, alloc, handler);
|
||||
[&obj, memResource, this](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
TPtrManager<T>::destroyPolymorphic(obj, memResource, handler);
|
||||
});
|
||||
alloc.setMemResource(prevMemResource);
|
||||
if (!sharedState)
|
||||
sharedState = TPtrManager<T>::getSharedState(obj);
|
||||
if (!ptrInfo.sharedState)
|
||||
TPtrManager<T>::saveToSharedState(createAndGetSharedStateObj<T>(ptrInfo), obj);
|
||||
}
|
||||
TPtrManager<T>::loadFromSharedState(sharedState.get(), obj);
|
||||
TPtrManager<T>::loadFromSharedState(getSharedStateObj<T>(ptrInfo), obj);
|
||||
ptrInfo.processOwner(TPtrManager<T>::getPtr(obj));
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc, typename Reader>
|
||||
void deserializeImpl(PolymorphicAllocatorWithTypeId& alloc, PLCInfoDeserializer& ptrInfo, Des& des, T& obj, Fnc&& fnc,
|
||||
void deserializeImpl(MemResourceBase* memResource, PLCInfoDeserializer& ptrInfo, Des& des, T& obj, Fnc&& fnc,
|
||||
Reader&, std::false_type, OwnershipType<PointerOwnershipType::SharedOwner>) const {
|
||||
auto& sharedState = ptrInfo.sharedState;
|
||||
if (!sharedState) {
|
||||
if (!ptrInfo.sharedState) {
|
||||
auto ptr = TPtrManager<T>::getPtr(obj);
|
||||
auto prevMemResource = alloc.getMemResource();
|
||||
if (ptr) {
|
||||
sharedState = TPtrManager<T>::getSharedState(obj);
|
||||
TPtrManager<T>::saveToSharedState(createAndGetSharedStateObj<T>(ptrInfo), obj);
|
||||
} else {
|
||||
if (_resource) alloc.setMemResource(_resource);
|
||||
sharedState = TPtrManager<T>::createShared(obj, alloc,
|
||||
RTTI::template get<typename TPtrManager<T>::TElement>());
|
||||
if (!_resourcePropagate) alloc.setMemResource(prevMemResource);
|
||||
TPtrManager<T>::createShared(
|
||||
createAndGetSharedStateObj<T>(ptrInfo),
|
||||
obj, memResource, RTTI::template get<typename TPtrManager<T>::TElement>());
|
||||
ptr = TPtrManager<T>::getPtr(obj);
|
||||
}
|
||||
fnc(des, *ptr);
|
||||
alloc.setMemResource(prevMemResource);
|
||||
}
|
||||
TPtrManager<T>::loadFromSharedState(sharedState.get(), obj);
|
||||
TPtrManager<T>::loadFromSharedState(getSharedStateObj<T>(ptrInfo), obj);
|
||||
ptrInfo.processOwner(TPtrManager<T>::getPtr(obj));
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc, typename Reader, typename isPolymorph>
|
||||
void deserializeImpl(PolymorphicAllocatorWithTypeId& alloc, PLCInfoDeserializer& ptrInfo, Des& des, T& obj,
|
||||
void deserializeImpl(MemResourceBase* memResource, PLCInfoDeserializer& ptrInfo, Des& des, T& obj,
|
||||
Fnc&& fnc, Reader& r, isPolymorph polymorph,
|
||||
OwnershipType<PointerOwnershipType::SharedObserver>) const {
|
||||
deserializeImpl(alloc, ptrInfo, des, obj, fnc, r, polymorph,
|
||||
deserializeImpl(memResource, ptrInfo, des, obj, fnc, r, polymorph,
|
||||
OwnershipType<PointerOwnershipType::SharedOwner>{});
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc, typename Reader, typename isPolymorphic>
|
||||
void deserializeImpl(PolymorphicAllocatorWithTypeId&, PLCInfoDeserializer& ptrInfo, Des&, T& obj, Fnc&&,
|
||||
void deserializeImpl(MemResourceBase* , PLCInfoDeserializer& ptrInfo, Des&, T& obj, Fnc&&,
|
||||
Reader&, isPolymorphic, OwnershipType<PointerOwnershipType::Observer>) const {
|
||||
ptrInfo.processObserver(reinterpret_cast<void*&>(TPtrManager<T>::getPtrRef(obj)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename TPtrManager<T>::TSharedState& createAndGetSharedStateObj(PLCInfoDeserializer& info) const {
|
||||
using TSharedState = typename TPtrManager<T>::TSharedState;
|
||||
PolymorphicAllocatorWrapper<TSharedState> alloc {info.memResource};
|
||||
auto* ptr = alloc.allocate(1);
|
||||
auto* obj = new (ptr)TSharedState{};
|
||||
info.sharedState = std::unique_ptr<PointerSharedStateBase, PointerSharedStateDeleter>(
|
||||
obj, PointerSharedStateDeleter{info.memResource});
|
||||
return *obj;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
typename TPtrManager<T>::TSharedState& getSharedStateObj(PLCInfoDeserializer& info) const {
|
||||
return static_cast<typename TPtrManager<T>::TSharedState&>(*info.sharedState);
|
||||
}
|
||||
|
||||
|
||||
PointerType _ptrType;
|
||||
bool _resourcePropagate;
|
||||
bitsery::ext::MemResourceBase* _resource;
|
||||
MemResourceBase* _resource;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -140,11 +140,27 @@ namespace bitsery {
|
||||
|
||||
template<typename TSerializer, typename TBase, typename TDerived>
|
||||
void addToMap(std::false_type) {
|
||||
using THandler = PolymorphicHandler<RTTI, TSerializer, TBase, TDerived>;
|
||||
BaseToDerivedKey key{RTTI::template get<TBase>(), RTTI::template get<TDerived>()};
|
||||
pointer_utils::PolymorphicAllocatorWrapper<THandler> alloc{_memResource};
|
||||
auto ptr = alloc.allocate(1);
|
||||
std::shared_ptr<THandler> handler(new (ptr)THandler{}, [this](THandler* data) {
|
||||
data->~THandler();
|
||||
pointer_utils::PolymorphicAllocatorWrapper<THandler> alloc{_memResource};
|
||||
alloc.deallocate(data, 1);
|
||||
}, pointer_utils::PolymorphicAllocatorWrapper<THandler>(_memResource));
|
||||
if (_baseToDerivedMap
|
||||
.emplace(key, std::make_shared<PolymorphicHandler<RTTI, TSerializer, TBase, TDerived>>())
|
||||
.second)
|
||||
_baseToDerivedArray[key.baseHash].push_back(key.derivedHash);
|
||||
.emplace(key, std::move(handler))
|
||||
.second) {
|
||||
auto it = _baseToDerivedArray.find(key.baseHash);
|
||||
if (it == _baseToDerivedArray.end()) {
|
||||
it = _baseToDerivedArray.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(key.baseHash),
|
||||
std::forward_as_tuple(pointer_utils::PolymorphicAllocatorWrapper<size_t>{_memResource})).first;
|
||||
}
|
||||
it->second.push_back(key.derivedHash);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TSerializer, typename TBase, typename TDerived>
|
||||
@@ -152,14 +168,36 @@ namespace bitsery {
|
||||
//cannot add abstract class
|
||||
}
|
||||
|
||||
std::unordered_map<BaseToDerivedKey, std::shared_ptr<PolymorphicHandlerBase>, BaseToDerivedKeyHashier> _baseToDerivedMap{};
|
||||
MemResourceBase* _memResource;
|
||||
// store shared ptr to polymorphic handler, because it might be copied to "smart pointer" deleter
|
||||
std::unordered_map<BaseToDerivedKey, std::shared_ptr<PolymorphicHandlerBase>,
|
||||
BaseToDerivedKeyHashier, std::equal_to<BaseToDerivedKey>,
|
||||
pointer_utils::PolymorphicAllocatorWrapper<std::pair<const BaseToDerivedKey, std::shared_ptr<PolymorphicHandlerBase>>>
|
||||
> _baseToDerivedMap;
|
||||
// this will allow convert from platform specific type information, to platform independent base->derived index
|
||||
// this only works if all polymorphic relationships (PolymorphicBaseClass<TBase> -> PolymorphicDerivedClasses<TDerived...>)
|
||||
// is equal between platforms.
|
||||
std::unordered_map<size_t, std::vector<size_t>> _baseToDerivedArray{};
|
||||
std::unordered_map<size_t, std::vector<size_t, pointer_utils::PolymorphicAllocatorWrapper<size_t>>,
|
||||
std::hash<size_t>, std::equal_to<size_t>,
|
||||
pointer_utils::PolymorphicAllocatorWrapper<std::pair<const size_t, std::vector<size_t, pointer_utils::PolymorphicAllocatorWrapper<size_t>>>>
|
||||
> _baseToDerivedArray;
|
||||
|
||||
public:
|
||||
|
||||
explicit PolymorphicContext(MemResourceBase* memResource = nullptr)
|
||||
:_memResource{memResource},
|
||||
_baseToDerivedMap{pointer_utils::PolymorphicAllocatorWrapper<std::pair<const BaseToDerivedKey,
|
||||
std::shared_ptr<PolymorphicHandlerBase>>>{memResource}},
|
||||
_baseToDerivedArray{pointer_utils::PolymorphicAllocatorWrapper<std::pair<const size_t,
|
||||
std::vector<size_t, pointer_utils::PolymorphicAllocatorWrapper<size_t>>>>{memResource}}
|
||||
{}
|
||||
|
||||
PolymorphicContext(const PolymorphicContext& ) = delete;
|
||||
PolymorphicContext& operator = (const PolymorphicContext&) = delete;
|
||||
PolymorphicContext(PolymorphicContext&& ) = default;
|
||||
PolymorphicContext& operator = (PolymorphicContext&&) = default;
|
||||
|
||||
|
||||
void clear() {
|
||||
_baseToDerivedMap.clear();
|
||||
_baseToDerivedArray.clear();
|
||||
|
||||
@@ -204,8 +204,9 @@ namespace bitsery {
|
||||
* value overloads
|
||||
*/
|
||||
|
||||
template<size_t VSIZE, typename T, typename std::enable_if<details::IsFundamentalType<T>::value>::type * = nullptr>
|
||||
template<size_t VSIZE, typename T>
|
||||
void value(const T &v) {
|
||||
static_assert(details::IsFundamentalType<T>::value, "Value must be integral, float or enum type.");
|
||||
using TValue = typename details::IntegralFromFundamental<T>::TValue;
|
||||
this->_adapter.template writeBytes<VSIZE>(reinterpret_cast<const TValue &>(v));
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ public:
|
||||
TEST_F(SerializeExtensionPointerWithAllocator, CanSetDefaultMemoryResourceInPointerLinkingContext) {
|
||||
|
||||
MemResourceForTest memRes{};
|
||||
std::get<0>(plctx).getAllocator().setMemResource(&memRes);
|
||||
std::get<0>(plctx).setMemResource(&memRes);
|
||||
|
||||
Base* baseData = new Derived1{2, 1};
|
||||
createSerializer().ext(baseData, PointerOwner{});
|
||||
@@ -225,7 +225,7 @@ TEST_F(SerializeExtensionPointerWithAllocator, CanSetDefaultMemoryResourceInPoin
|
||||
|
||||
TEST_F(SerializeExtensionPointerWithAllocator, CorrectlyDeallocatesPreviousInstance) {
|
||||
MemResourceForTest memRes{};
|
||||
std::get<0>(plctx).getAllocator().setMemResource(&memRes);
|
||||
std::get<0>(plctx).setMemResource(&memRes);
|
||||
|
||||
Base* baseData = new Derived1{2, 1};
|
||||
createSerializer().ext(baseData, PointerOwner{});
|
||||
@@ -252,7 +252,7 @@ TEST_F(SerializeExtensionPointerWithAllocator, CorrectlyDeallocatesPreviousInsta
|
||||
|
||||
TEST_F(SerializeExtensionPointerWithAllocator, DefaultDeleterIsNotUsedForStdUniquePtr) {
|
||||
MemResourceForTest memRes{};
|
||||
std::get<0>(plctx).getAllocator().setMemResource(&memRes);
|
||||
std::get<0>(plctx).setMemResource(&memRes);
|
||||
|
||||
std::unique_ptr<Base> baseData{};
|
||||
createSerializer().ext(baseData, StdSmartPtr{});
|
||||
@@ -274,7 +274,7 @@ struct CustomBaseDeleter {
|
||||
|
||||
TEST_F(SerializeExtensionPointerWithAllocator, CustomDeleterIsUsedForStdUniquePtr) {
|
||||
MemResourceForTest memRes{};
|
||||
std::get<0>(plctx).getAllocator().setMemResource(&memRes);
|
||||
std::get<0>(plctx).setMemResource(&memRes);
|
||||
|
||||
std::unique_ptr<Base, CustomBaseDeleter> baseData{};
|
||||
createSerializer().ext(baseData, StdSmartPtr{});
|
||||
@@ -289,7 +289,7 @@ TEST_F(SerializeExtensionPointerWithAllocator, CustomDeleterIsUsedForStdUniquePt
|
||||
TEST_F(SerializeExtensionPointerWithAllocator, CanSetMemResourcePerPointer) {
|
||||
MemResourceForTest memRes1{};
|
||||
MemResourceForTest memRes2{};
|
||||
std::get<0>(plctx).getAllocator().setMemResource(&memRes1);
|
||||
std::get<0>(plctx).setMemResource(&memRes1);
|
||||
|
||||
Base* baseData = new Derived1{2, 1};
|
||||
createSerializer().ext(baseData, PointerOwner{bitsery::ext::PointerType::Nullable, &memRes2});
|
||||
@@ -320,7 +320,7 @@ TEST_F(SerializeExtensionPointerWithAllocator, CanSetMemResourcePerPointer) {
|
||||
TEST_F(SerializeExtensionPointerWithAllocator, MemResourceSetPerPointerByDefaultDoNotPropagate) {
|
||||
MemResourceForTest memRes1{};
|
||||
MemResourceForTest memRes2{};
|
||||
std::get<0>(plctx).getAllocator().setMemResource(&memRes1);
|
||||
std::get<0>(plctx).setMemResource(&memRes1);
|
||||
|
||||
auto data = std::unique_ptr<PolyPtrWithPolyPtrBase>(new PolyPtrWithPolyPtrBase{});
|
||||
data->ptr = std::unique_ptr<Base>(new Derived1{5, 6});
|
||||
@@ -343,7 +343,7 @@ TEST_F(SerializeExtensionPointerWithAllocator, MemResourceSetPerPointerByDefault
|
||||
TEST_F(SerializeExtensionPointerWithAllocator, MemResourceSetPerPointerCanPropagate) {
|
||||
MemResourceForTest memRes1{};
|
||||
MemResourceForTest memRes2{};
|
||||
std::get<0>(plctx).getAllocator().setMemResource(&memRes1);
|
||||
std::get<0>(plctx).setMemResource(&memRes1);
|
||||
|
||||
auto data = std::unique_ptr<PolyPtrWithPolyPtrBase>(new PolyPtrWithPolyPtrBase{});
|
||||
data->ptr = std::unique_ptr<Base>(new Derived1{5, 6});
|
||||
|
||||
Reference in New Issue
Block a user