all bitsery types that allocates memory can be configured to accept

memory resource for allocation
This commit is contained in:
Mindaugas Vinkelis
2019-07-02 16:20:28 +03:00
committed by Mindaugas Vinkelis
parent 105aa5f9e5
commit a1785f3e15
9 changed files with 221 additions and 155 deletions

View File

@@ -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)

View File

@@ -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));
}

View File

@@ -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

View File

@@ -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:

View File

@@ -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)

View File

@@ -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;
};
}

View File

@@ -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();

View File

@@ -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));
}

View File

@@ -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});