From a1785f3e159fd89c31e2e787fd8b6debe2e393fb Mon Sep 17 00:00:00 2001 From: Mindaugas Vinkelis Date: Tue, 2 Jul 2019 16:20:28 +0300 Subject: [PATCH] all bitsery types that allocates memory can be configured to accept memory resource for allocation --- CHANGELOG.md | 6 +- include/bitsery/deserializer.h | 3 +- include/bitsery/ext/pointer.h | 20 +- include/bitsery/ext/std_smart_ptr.h | 98 +++++----- include/bitsery/ext/utils/memory_allocator.h | 4 +- include/bitsery/ext/utils/pointer_utils.h | 180 +++++++++++------- .../bitsery/ext/utils/polymorphism_utils.h | 48 ++++- include/bitsery/serializer.h | 3 +- ...rialization_ext_pointer_with_allocator.cpp | 14 +- 9 files changed, 221 insertions(+), 155 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 529342b..069dfe0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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{});` * 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) diff --git a/include/bitsery/deserializer.h b/include/bitsery/deserializer.h index bea1d12..cd480da 100644 --- a/include/bitsery/deserializer.h +++ b/include/bitsery/deserializer.h @@ -209,8 +209,9 @@ namespace bitsery { * value */ - template::value>::type * = nullptr> + template void value(T &v) { + static_assert(details::IsFundamentalType::value, "Value must be integral, float or enum type."); using TValue = typename details::IntegralFromFundamental::TValue; this->_adapter.template readBytes(reinterpret_cast(v)); } diff --git a/include/bitsery/ext/pointer.h b/include/bitsery/ext/pointer.h index a5dde19..da5939a 100644 --- a/include/bitsery/ext/pointer.h +++ b/include/bitsery/ext/pointer.h @@ -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(typeId); } - static void createPolymorphic(T& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, + static void createPolymorphic(T& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc, const std::shared_ptr& handler) { obj = static_cast(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& 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 diff --git a/include/bitsery/ext/std_smart_ptr.h b/include/bitsery/ext/std_smart_ptr.h index c61ceca..6c209fc 100644 --- a/include/bitsery/ext/std_smart_ptr.h +++ b/include/bitsery/ext/std_smart_ptr.h @@ -70,108 +70,100 @@ namespace bitsery { } template - static void create(std::unique_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, + static void create(std::unique_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc, size_t typeId) { obj.reset(alloc.newObject(typeId)); } template - static void createPolymorphic(std::unique_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, + static void createPolymorphic(std::unique_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc, const std::shared_ptr& handler) { obj.reset(static_cast(handler->create(alloc))); } template - static void destroy(std::unique_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, size_t typeId) { + static void destroy(std::unique_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc, size_t typeId) { uniquePtrDestroy(obj, alloc, typeId, std::is_same, T>{}); } template - static void destroyPolymorphic(std::unique_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, + static void destroyPolymorphic(std::unique_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId alloc, const std::shared_ptr& handler) { uniquePtrDestroyPolymorphic(obj, alloc, handler, std::is_same, T>{}); } - static void destroy(std::shared_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId&, size_t) { + static void destroy(std::shared_ptr& obj, MemResourceBase*, size_t) { obj.reset(); } - static void destroyPolymorphic(std::shared_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId&, + static void destroyPolymorphic(std::shared_ptr& obj, MemResourceBase*, const std::shared_ptr&) { obj.reset(); } - static void destroy(std::weak_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId&, size_t) { + static void destroy(std::weak_ptr& obj, MemResourceBase*, size_t) { obj.reset(); } - static void destroyPolymorphic(std::weak_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId&, + static void destroyPolymorphic(std::weak_ptr& obj, MemResourceBase*, const std::shared_ptr&) { obj.reset(); } - static std::unique_ptr createShared( - std::shared_ptr& 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& obj, MemResourceBase* memResource, size_t typeId) { // capture deleter parameters by value - obj = std::shared_ptr(alloc.newObject(typeId), - [alloc, typeId](TElement* data) { - alloc.deleteObject(data, typeId); - }); - auto state = new SharedPtrSharedState{}; - state->obj = obj; - return std::unique_ptr{state}; + pointer_utils::PolymorphicAllocatorWithTypeId alloc{memResource}; + obj.reset(alloc.newObject(typeId), [alloc, typeId](TElement* data) { + alloc.deleteObject(data, typeId); + }, pointer_utils::PolymorphicAllocatorWrapper(memResource)); + state.obj = obj; } - static std::unique_ptr createSharedPolymorphic( - std::shared_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, + static void createSharedPolymorphic(TSharedState& state, + std::shared_ptr& obj, MemResourceBase* memResource, const std::shared_ptr& handler) { // capture deleter parameters by value - obj = std::shared_ptr(static_cast(handler->create(alloc)), - [alloc, handler](TElement* data) { - handler->destroy(alloc, data); - }); - auto state = new SharedPtrSharedState{}; - state->obj = obj; - return std::unique_ptr{state}; + pointer_utils::PolymorphicAllocatorWithTypeId alloc{memResource}; + obj.reset(static_cast(handler->create(alloc)), [alloc, handler](TElement* data) { + handler->destroy(alloc, data); + }, pointer_utils::PolymorphicAllocatorWrapper(memResource)); + state.obj = obj; } - static std::unique_ptr createShared( - std::weak_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, size_t typeId) { - auto res = std::shared_ptr(alloc.newObject(typeId), - [alloc, typeId](TElement* data) { - alloc.deleteObject(data, typeId); - }); + static void createShared(TSharedState& state, + std::weak_ptr& obj, MemResourceBase* memResource, size_t typeId) { + pointer_utils::PolymorphicAllocatorWithTypeId alloc{memResource}; + std::shared_ptr res(alloc.newObject(typeId),[alloc, typeId](TElement* data) { + alloc.deleteObject(data, typeId); + }, pointer_utils::PolymorphicAllocatorWrapper(memResource)); obj = res; - auto state = new SharedPtrSharedState{}; - state->obj = res; - return std::unique_ptr{state}; + state.obj = res; } - static std::unique_ptr createSharedPolymorphic( - std::weak_ptr& obj, pointer_utils::PolymorphicAllocatorWithTypeId& alloc, + static void createSharedPolymorphic(TSharedState& state, + std::weak_ptr& obj, MemResourceBase* memResource, const std::shared_ptr& handler) { - auto res = std::shared_ptr(static_cast(handler->create(alloc)), - [alloc, handler](TElement* data) { - handler->destroy(alloc, data); - }); + pointer_utils::PolymorphicAllocatorWithTypeId alloc{memResource}; + std::shared_ptr res(static_cast(handler->create(alloc)), + [alloc, handler](TElement* data) { + handler->destroy(alloc, data); + }, pointer_utils::PolymorphicAllocatorWrapper(memResource)); obj = res; - auto state = new SharedPtrSharedState{}; - state->obj = res; - return std::unique_ptr{state}; + state.obj = res; } - static std::unique_ptr 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(obj); - return std::unique_ptr{state}; + static void saveToSharedState(TSharedState& state, T& obj) { + state.obj = std::shared_ptr(obj); } - static void loadFromSharedState(pointer_utils::PointerSharedStateBase* ctx, T& obj) { - auto state = dynamic_cast(ctx); + static void loadFromSharedState(TSharedState& state, T& obj) { //reinterpret_pointer_cast is only since c++17 - auto p = reinterpret_cast(state->obj.get()); - obj = std::shared_ptr(state->obj, p); + auto p = reinterpret_cast(state.obj.get()); + obj = std::shared_ptr(state.obj, p); } private: diff --git a/include/bitsery/ext/utils/memory_allocator.h b/include/bitsery/ext/utils/memory_allocator.h index 727ad9d..2f1450b 100644 --- a/include/bitsery/ext/utils/memory_allocator.h +++ b/include/bitsery/ext/utils/memory_allocator.h @@ -64,7 +64,7 @@ namespace bitsery { class PolymorphicAllocatorWithTypeId final { public: - explicit constexpr PolymorphicAllocatorWithTypeId(MemResourceBase* memResource = nullptr) + constexpr PolymorphicAllocatorWithTypeId(MemResourceBase* memResource = nullptr) :_resource{memResource} {} template @@ -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 - struct PolymorphicAllocatorWrapper final { + struct PolymorphicAllocatorWrapper { using value_type = T; explicit constexpr PolymorphicAllocatorWrapper(MemResourceBase* memResource) diff --git a/include/bitsery/ext/utils/pointer_utils.h b/include/bitsery/ext/utils/pointer_utils.h index 256471e..7421e00 100644 --- a/include/bitsery/ext/utils/pointer_utils.h +++ b/include/bitsery/ext/utils/pointer_utils.h @@ -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 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>{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> observersList{}; - std::unique_ptr sharedState{}; + MemResourceBase* memResource; + std::vector, + PolymorphicAllocatorWrapper>> observersList; + std::unique_ptr sharedState{}; }; class PointerLinkingContextSerialization { public: - explicit PointerLinkingContextSerialization() + explicit PointerLinkingContextSerialization(MemResourceBase* memResource = nullptr) : _currId{0}, - _ptrMap{} {} + _ptrMap{PolymorphicAllocatorWrapper>{memResource}} {} PointerLinkingContextSerialization(const PointerLinkingContextSerialization&) = delete; @@ -172,14 +188,17 @@ namespace bitsery { private: size_t _currId; - std::unordered_map _ptrMap; - + std::unordered_map, std::equal_to, + PolymorphicAllocatorWrapper> + > _ptrMap; }; class PointerLinkingContextDeserialization { public: - explicit PointerLinkingContextDeserialization() - : _idMap{} {} + explicit PointerLinkingContextDeserialization(MemResourceBase* memResource = nullptr) + : _memResource{memResource}, + _idMap{PolymorphicAllocatorWrapper>{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 _idMap; + MemResourceBase* _memResource; + std::unordered_map, std::equal_to, + PolymorphicAllocatorWrapper>> _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::getPtr(const_cast(obj)); if (ptr) { - auto& ctx = ser.template context(); + auto& ctx = ser.template context(); auto& ptrInfo = ctx.getInfoByPtr(getBasePtr(ptr), TPtrManager::getOwnership()); details::writeSize(w, ptrInfo.id); if (TPtrManager::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(); - auto& alloc = ctx.getAllocator(); + auto& ctx = des.template context(); + 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::getOwnership()); - deserializeImpl(alloc, ptrInfo, des, obj, std::forward(fnc), r, IsPolymorphic{}, + deserializeImpl(memResource, ptrInfo, des, obj, std::forward(fnc), r, IsPolymorphic{}, OwnershipType::getOwnership()>{}); } else { if (_ptrType == PointerType::Nullable) { if (auto ptr = TPtrManager::getPtr(obj)) { - auto prevMemResource = alloc.getMemResource(); - if (_resource) alloc.setMemResource(_resource); - destroyPtr(alloc, des, obj, IsPolymorphic{}); - alloc.setMemResource(prevMemResource); + destroyPtr(memResource, des, obj, IsPolymorphic{}); }; } else r.error(ReaderError::InvalidPointer); } + if (_resource && _resourcePropagate) { + ctx.setMemResource(prevResource); + } } private: template - 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>(); auto ptr = TPtrManager::getPtr(obj); - TPtrManager::destroyPolymorphic(obj, alloc, ctx.getPolymorphicHandler(*ptr)); + TPtrManager::destroyPolymorphic(obj, memResource, ctx.getPolymorphicHandler(*ptr)); } template - void destroyPtr(PolymorphicAllocatorWithTypeId& alloc, Des&, TObj& obj, + void destroyPtr(MemResourceBase* memResource, Des&, TObj& obj, std::false_type /*polymorphic*/) const { - TPtrManager::destroy(obj, alloc, RTTI::template get::TElement>()); + TPtrManager::destroy(obj, memResource, RTTI::template get::TElement>()); } @@ -339,113 +372,112 @@ namespace bitsery { } template - 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) const { const auto& ctx = des.template context>(); - auto prevMemResource = alloc.getMemResource(); ctx.deserialize(des, r, TPtrManager::getPtr(obj), - [&obj, &alloc, this, prevMemResource]( + [&obj, this, memResource]( const std::shared_ptr& handler) { - if (_resource) alloc.setMemResource(_resource); - TPtrManager::createPolymorphic(obj, alloc, handler); - if (!_resourcePropagate) alloc.setMemResource(prevMemResource); + TPtrManager::createPolymorphic(obj, memResource, handler); return TPtrManager::getPtr(obj); }, - [&obj, &alloc, this](const std::shared_ptr& handler) { - if (_resource) alloc.setMemResource(_resource); - TPtrManager::destroyPolymorphic(obj, alloc, handler); + [&obj, memResource, this](const std::shared_ptr& handler) { + TPtrManager::destroyPolymorphic(obj, memResource, handler); }); - alloc.setMemResource(prevMemResource); ptrInfo.processOwner(TPtrManager::getPtr(obj)); } template - 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) const { auto ptr = TPtrManager::getPtr(obj); if (ptr) { fnc(des, *ptr); } else { - auto prevMemResource = alloc.getMemResource(); - if (_resource) alloc.setMemResource(_resource); - TPtrManager::create(obj, alloc, RTTI::template get::TElement>()); - if (!_resourcePropagate) alloc.setMemResource(prevMemResource); + TPtrManager::create(obj, memResource, RTTI::template get::TElement>()); ptr = TPtrManager::getPtr(obj); fnc(des, *ptr); - alloc.setMemResource(prevMemResource); } ptrInfo.processOwner(ptr); } template - 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) const { - auto& sharedState = ptrInfo.sharedState; - if (!sharedState) { + if (!ptrInfo.sharedState) { const auto& ctx = des.template context>(); - auto prevMemResource = alloc.getMemResource(); ctx.deserialize(des, r, TPtrManager::getPtr(obj), - [&obj, &alloc, &sharedState, this, prevMemResource]( + [&obj, &ptrInfo, memResource, this]( const std::shared_ptr& handler) { - if (_resource) alloc.setMemResource(_resource); - sharedState = TPtrManager::createSharedPolymorphic(obj, alloc, handler); - if (!_resourcePropagate) alloc.setMemResource(prevMemResource); + TPtrManager::createSharedPolymorphic( + createAndGetSharedStateObj(ptrInfo), + obj, memResource, handler); return TPtrManager::getPtr(obj); }, - [&obj, &alloc, this](const std::shared_ptr& handler) { - if (_resource) alloc.setMemResource(_resource); - TPtrManager::destroyPolymorphic(obj, alloc, handler); + [&obj, memResource, this](const std::shared_ptr& handler) { + TPtrManager::destroyPolymorphic(obj, memResource, handler); }); - alloc.setMemResource(prevMemResource); - if (!sharedState) - sharedState = TPtrManager::getSharedState(obj); + if (!ptrInfo.sharedState) + TPtrManager::saveToSharedState(createAndGetSharedStateObj(ptrInfo), obj); } - TPtrManager::loadFromSharedState(sharedState.get(), obj); + TPtrManager::loadFromSharedState(getSharedStateObj(ptrInfo), obj); ptrInfo.processOwner(TPtrManager::getPtr(obj)); } template - 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) const { - auto& sharedState = ptrInfo.sharedState; - if (!sharedState) { + if (!ptrInfo.sharedState) { auto ptr = TPtrManager::getPtr(obj); - auto prevMemResource = alloc.getMemResource(); if (ptr) { - sharedState = TPtrManager::getSharedState(obj); + TPtrManager::saveToSharedState(createAndGetSharedStateObj(ptrInfo), obj); } else { - if (_resource) alloc.setMemResource(_resource); - sharedState = TPtrManager::createShared(obj, alloc, - RTTI::template get::TElement>()); - if (!_resourcePropagate) alloc.setMemResource(prevMemResource); + TPtrManager::createShared( + createAndGetSharedStateObj(ptrInfo), + obj, memResource, RTTI::template get::TElement>()); ptr = TPtrManager::getPtr(obj); } fnc(des, *ptr); - alloc.setMemResource(prevMemResource); } - TPtrManager::loadFromSharedState(sharedState.get(), obj); + TPtrManager::loadFromSharedState(getSharedStateObj(ptrInfo), obj); ptrInfo.processOwner(TPtrManager::getPtr(obj)); } template - 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) const { - deserializeImpl(alloc, ptrInfo, des, obj, fnc, r, polymorph, + deserializeImpl(memResource, ptrInfo, des, obj, fnc, r, polymorph, OwnershipType{}); } template - void deserializeImpl(PolymorphicAllocatorWithTypeId&, PLCInfoDeserializer& ptrInfo, Des&, T& obj, Fnc&&, + void deserializeImpl(MemResourceBase* , PLCInfoDeserializer& ptrInfo, Des&, T& obj, Fnc&&, Reader&, isPolymorphic, OwnershipType) const { ptrInfo.processObserver(reinterpret_cast(TPtrManager::getPtrRef(obj))); } + template + typename TPtrManager::TSharedState& createAndGetSharedStateObj(PLCInfoDeserializer& info) const { + using TSharedState = typename TPtrManager::TSharedState; + PolymorphicAllocatorWrapper alloc {info.memResource}; + auto* ptr = alloc.allocate(1); + auto* obj = new (ptr)TSharedState{}; + info.sharedState = std::unique_ptr( + obj, PointerSharedStateDeleter{info.memResource}); + return *obj; + } + + template + typename TPtrManager::TSharedState& getSharedStateObj(PLCInfoDeserializer& info) const { + return static_cast::TSharedState&>(*info.sharedState); + } + PointerType _ptrType; bool _resourcePropagate; - bitsery::ext::MemResourceBase* _resource; + MemResourceBase* _resource; }; } diff --git a/include/bitsery/ext/utils/polymorphism_utils.h b/include/bitsery/ext/utils/polymorphism_utils.h index c26af29..4d0f398 100644 --- a/include/bitsery/ext/utils/polymorphism_utils.h +++ b/include/bitsery/ext/utils/polymorphism_utils.h @@ -140,11 +140,27 @@ namespace bitsery { template void addToMap(std::false_type) { + using THandler = PolymorphicHandler; BaseToDerivedKey key{RTTI::template get(), RTTI::template get()}; + pointer_utils::PolymorphicAllocatorWrapper alloc{_memResource}; + auto ptr = alloc.allocate(1); + std::shared_ptr handler(new (ptr)THandler{}, [this](THandler* data) { + data->~THandler(); + pointer_utils::PolymorphicAllocatorWrapper alloc{_memResource}; + alloc.deallocate(data, 1); + }, pointer_utils::PolymorphicAllocatorWrapper(_memResource)); if (_baseToDerivedMap - .emplace(key, std::make_shared>()) - .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{_memResource})).first; + } + it->second.push_back(key.derivedHash); + } } template @@ -152,14 +168,36 @@ namespace bitsery { //cannot add abstract class } - std::unordered_map, BaseToDerivedKeyHashier> _baseToDerivedMap{}; + MemResourceBase* _memResource; + // store shared ptr to polymorphic handler, because it might be copied to "smart pointer" deleter + std::unordered_map, + BaseToDerivedKeyHashier, std::equal_to, + pointer_utils::PolymorphicAllocatorWrapper>> + > _baseToDerivedMap; // this will allow convert from platform specific type information, to platform independent base->derived index // this only works if all polymorphic relationships (PolymorphicBaseClass -> PolymorphicDerivedClasses) // is equal between platforms. - std::unordered_map> _baseToDerivedArray{}; + std::unordered_map>, + std::hash, std::equal_to, + pointer_utils::PolymorphicAllocatorWrapper>>> + > _baseToDerivedArray; public: + explicit PolymorphicContext(MemResourceBase* memResource = nullptr) + :_memResource{memResource}, + _baseToDerivedMap{pointer_utils::PolymorphicAllocatorWrapper>>{memResource}}, + _baseToDerivedArray{pointer_utils::PolymorphicAllocatorWrapper>>>{memResource}} + {} + + PolymorphicContext(const PolymorphicContext& ) = delete; + PolymorphicContext& operator = (const PolymorphicContext&) = delete; + PolymorphicContext(PolymorphicContext&& ) = default; + PolymorphicContext& operator = (PolymorphicContext&&) = default; + + void clear() { _baseToDerivedMap.clear(); _baseToDerivedArray.clear(); diff --git a/include/bitsery/serializer.h b/include/bitsery/serializer.h index 7c2c328..ad7bcf9 100644 --- a/include/bitsery/serializer.h +++ b/include/bitsery/serializer.h @@ -204,8 +204,9 @@ namespace bitsery { * value overloads */ - template::value>::type * = nullptr> + template void value(const T &v) { + static_assert(details::IsFundamentalType::value, "Value must be integral, float or enum type."); using TValue = typename details::IntegralFromFundamental::TValue; this->_adapter.template writeBytes(reinterpret_cast(v)); } diff --git a/tests/serialization_ext_pointer_with_allocator.cpp b/tests/serialization_ext_pointer_with_allocator.cpp index 358168f..e835a6e 100644 --- a/tests/serialization_ext_pointer_with_allocator.cpp +++ b/tests/serialization_ext_pointer_with_allocator.cpp @@ -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 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 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(new PolyPtrWithPolyPtrBase{}); data->ptr = std::unique_ptr(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(new PolyPtrWithPolyPtrBase{}); data->ptr = std::unique_ptr(new Derived1{5, 6});