mirror of
https://github.com/fraillt/bitsery.git
synced 2026-06-18 13:19:11 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d22b7c1527 | ||
|
|
8d6ffc9873 | ||
|
|
0e76e0608c | ||
|
|
501d60f67d | ||
|
|
04afd16fbd | ||
|
|
9621db1cd7 | ||
|
|
c555088aa3 | ||
|
|
c9619e3e3d | ||
|
|
01d56e00b8 | ||
|
|
04526ff0f4 | ||
|
|
b7d159bbfc |
19
CHANGELOG.md
19
CHANGELOG.md
@@ -1,3 +1,22 @@
|
||||
# [5.0.2](https://github.com/fraillt/bitsery/compare/v5.0.1...v5.0.2) (2020-01-17)
|
||||
|
||||
### Bug fixes
|
||||
* fixed a bug when deserializing non-default constructible containers (thanks to [nicktrandafil](https://github.com/nicktrandafil)).
|
||||
* fixed issue with a brace initialization in extension StdMap and StdSet. It was working on major compilers, but it wasn't C++11 compatible.
|
||||
More info about it in [stackoverflow](https://stackoverflow.com/questions/25612262/why-does-auto-x3-deduce-an-initializer-list) (thanks to [BotellaA](https://github.com/BotellaA)).
|
||||
|
||||
### Other notes
|
||||
* added [patches/centos7_gcc4.8.2.diff](patches/centos7_gcc4.8.2.diff) that allows to use bitsery with gcc4.8.2 on Centos7 (thanks to [BotellaA](https://github.com/BotellaA)).
|
||||
More information on patches is [here](patches/README.md).
|
||||
* added documentation on how [extensions](doc/design/extensions.md) work.
|
||||
|
||||
# [5.0.1](https://github.com/fraillt/bitsery/compare/v5.0.0...v5.0.1) (2019-08-21)
|
||||
|
||||
### Bug fixes
|
||||
* fixed polymorphic handler deleter in `PolymorphicContext`, now it is captured by value and doesn't depend on lifetime of `PolymorphicContext` instance.
|
||||
* fixed compilation errors in `ext/utils/pointer_utils.h` on macOS.
|
||||
* reduced warnings on Visual Studio (thanks to [BotellaA](https://github.com/BotellaA))
|
||||
|
||||
# [5.0.0](https://github.com/fraillt/bitsery/compare/v4.6.1...v5.0.0) (2019-07-09)
|
||||
|
||||
This version reduces library complexity by removing redundant features and changing existing ones.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(bitsery
|
||||
LANGUAGES CXX
|
||||
VERSION 5.0.0)
|
||||
VERSION 5.0.1)
|
||||
|
||||
#======== build options ===================================
|
||||
option(BITSERY_BUILD_EXAMPLES "Build examples" OFF)
|
||||
|
||||
@@ -6,7 +6,7 @@ Library design:
|
||||
* `valueNb instead of value`
|
||||
* `brief syntax`
|
||||
* `serializer/deserializer functions overloads`
|
||||
* `extending library functionality`
|
||||
* [extending library functionality](design/extensions.md)
|
||||
* `errors handling`
|
||||
* `forward/backward compatibility via Growable extension`
|
||||
* [pointers](design/pointers.md)
|
||||
@@ -64,8 +64,10 @@ Output adapters (buffer and stream) functions:
|
||||
* `writeBytes`
|
||||
* `writeBuffer`
|
||||
* `flush`
|
||||
* `currentyWritePos (get/set)` (buffer adapter only)
|
||||
* `writtenBytesCount` (buffer adapter only)
|
||||
* `currentyWritePos (get/set)` (buffer adapter only) gets/sets write position in buffer, it can jump past the buffer end, in this case buffer will be resized.
|
||||
This function doesn't write any bytes.
|
||||
* `writtenBytesCount` (buffer adapter only) this doesn't necessary mean how many bytes are written, but rather how many bytes in the buffer was "affected" during serialization.
|
||||
E.g. if `currentyWritePos` (set) jumps from 0 to 100, and then 4 bytes are written, `writtenBytesCount` return 104, it also returns 104 if you jump in somewhere in the middle.
|
||||
|
||||
|
||||
Tips and tricks:
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
Extensions are at the heart of bitsery. They allow implementing all sorts of things, that requires customizing serialization and deserialization flows separately.
|
||||
Bitsery already provides a lot of useful extensions, which can be found [here](../../include/bitsery/ext).
|
||||
|
||||
Let's see what are the core components of an extension:
|
||||
|
||||
1. Extension class itself, which implements templated `serialize` and `deserialize` methods. These functions provide similar capabilities to `save` and `load` functions in other frameworks e.g. [cereal](https://uscilab.github.io/cereal/) or [boost](https://www.boost.org/doc/libs/1_71_0/libs/serialization/doc/index.html), but are more powerful because extension itself can store extension related data as well, that can be used for additional functionality.
|
||||
```cpp
|
||||
class MyExtension {
|
||||
public:
|
||||
template<typename Ser, typename T, typename Fnc>
|
||||
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const {
|
||||
...
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserialize(Des& des, T& obj, Fnc&& fnc) const {
|
||||
...
|
||||
}
|
||||
};
|
||||
```
|
||||
2. `ExtensionTraits` specialization for an extension, which specifies how it should be used:
|
||||
```cpp
|
||||
namespace bitsery {
|
||||
namespace traits {
|
||||
template<typename T>
|
||||
struct ExtensionTraits<ext::MyExtension, T> {
|
||||
using TValue = ...;
|
||||
static constexpr bool SupportValueOverload = ...;
|
||||
static constexpr bool SupportObjectOverload = ...;
|
||||
static constexpr bool SupportLambdaOverload = ...;
|
||||
};
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, that we know the core components of an extension, let's see how everything fits together.
|
||||
|
||||
An Extension can be called in 3 different ways, and `Support...Overload` methods basically define, what call syntax can be used with a particular extension.
|
||||
* `SupportValueOverload` - allows to call extension by providing the size of the value type, the same as `valueNb` function. e.g. `s.ext4b(value, MyExtension{})`.
|
||||
* `SupportObjectOverload` - allows to call extension the same as simple `object` function. e.g. `s.ext(value, MyExtension{})`.
|
||||
* `SupportLambdaOverload` - allows to call extension by providing a custom lambda. e.g. `s.ext(value, MyExtension{}, [](...) { ... })`.
|
||||
|
||||
You might wonder, how there are 3 ways to call an extension, but only one signature for `serialize` and `deserialize` functions?
|
||||
|
||||
This is where a `TValue` from `ExtensionTraits` and the third parameter `Fnc` in `serialize` and `deserialize` comes in.
|
||||
|
||||
In case of lambda overload is called, the lambda is passed straight to the serialize/deserialize function as the third parameter. In theory `SupportLambdaOverload` can be any object, not necessary a callable object.
|
||||
When value overload is used, then lambda is constructed by bitsery like this `[](Serializer& s, VType &v) { s.value<VSIZE>(v); }`, where `VType` is equal to `TValue` from `ExtensionTraits`.
|
||||
Similarly, when object overload is used `[](Serializer& s, VType &v) { s.object(v); }` lambda is constructed.
|
||||
|
||||
When there is no direct mapping from object type to its underlying value type, you can disable lambda generation for value and object overload, by setting `TValue=void`, in this case, a "dummy" lambda will be provided.
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#define BITSERY_MAJOR_VERSION 5
|
||||
#define BITSERY_MINOR_VERSION 0
|
||||
#define BITSERY_PATCH_VERSION 0
|
||||
#define BITSERY_PATCH_VERSION 1
|
||||
|
||||
#define BITSERY_QUOTE_MACRO(name) #name
|
||||
#define BITSERY_BUILD_VERSION_STR(major,minor, patch) \
|
||||
|
||||
@@ -62,8 +62,8 @@ namespace bitsery {
|
||||
|
||||
auto hint = obj.begin();
|
||||
for (auto i = 0u; i < size; ++i) {
|
||||
auto key{bitsery::Access::create<TKey>()};
|
||||
auto value{bitsery::Access::create<TValue>()};
|
||||
auto key = bitsery::Access::create<TKey>();
|
||||
auto value = bitsery::Access::create<TValue>();
|
||||
fnc(des, key, value);
|
||||
hint = obj.emplace_hint(hint, std::move(key), std::move(value));
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace bitsery {
|
||||
reserve(obj, size);
|
||||
auto hint = obj.begin();
|
||||
for (auto i = 0u; i < size; ++i) {
|
||||
auto key{bitsery::Access::create<TKey>()};
|
||||
auto key = bitsery::Access::create<TKey>();
|
||||
fnc(des, key);
|
||||
hint = obj.emplace_hint(hint, std::move(key));
|
||||
}
|
||||
|
||||
@@ -124,7 +124,8 @@ namespace bitsery {
|
||||
// it just wraps our PolyAllocWithTypeId and pass 0 as typeId
|
||||
// and defines core functions for c++ Allocator concept,
|
||||
template<class T>
|
||||
struct StdPolyAlloc {
|
||||
class StdPolyAlloc {
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
explicit constexpr StdPolyAlloc(MemResourceBase* memResource)
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace bitsery {
|
||||
public:
|
||||
explicit PointerLinkingContextSerialization(MemResourceBase* memResource = nullptr)
|
||||
: _currId{0},
|
||||
_ptrMap{StdPolyAlloc<std::pair<const void*, PLCInfoSerializer>>{memResource}} {}
|
||||
_ptrMap{StdPolyAlloc<std::pair<const void* const, PLCInfoSerializer>>{memResource}} {}
|
||||
|
||||
PointerLinkingContextSerialization(const PointerLinkingContextSerialization&) = delete;
|
||||
|
||||
@@ -190,7 +190,7 @@ namespace bitsery {
|
||||
size_t _currId;
|
||||
std::unordered_map<const void*, PLCInfoSerializer,
|
||||
std::hash<const void*>, std::equal_to<const void*>,
|
||||
StdPolyAlloc<std::pair<const void*, PLCInfoSerializer>>
|
||||
StdPolyAlloc<std::pair<const void* const, PLCInfoSerializer>>
|
||||
> _ptrMap;
|
||||
};
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace bitsery {
|
||||
public:
|
||||
explicit PointerLinkingContextDeserialization(MemResourceBase* memResource = nullptr)
|
||||
: _memResource{memResource},
|
||||
_idMap{StdPolyAlloc<std::pair<size_t, PLCInfoDeserializer>>{memResource}} {}
|
||||
_idMap{StdPolyAlloc<std::pair<const size_t, PLCInfoDeserializer>>{memResource}} {}
|
||||
|
||||
PointerLinkingContextDeserialization(const PointerLinkingContextDeserialization&) = delete;
|
||||
|
||||
@@ -244,7 +244,7 @@ namespace bitsery {
|
||||
MemResourceBase* _memResource;
|
||||
std::unordered_map<size_t, PLCInfoDeserializer,
|
||||
std::hash<size_t>, std::equal_to<size_t>,
|
||||
StdPolyAlloc<std::pair<size_t, PLCInfoDeserializer>>> _idMap;
|
||||
StdPolyAlloc<std::pair<const size_t, PLCInfoDeserializer>>> _idMap;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -257,7 +257,7 @@ namespace bitsery {
|
||||
:pointer_utils::PointerLinkingContextSerialization(memResource),
|
||||
pointer_utils::PointerLinkingContextDeserialization(memResource) {};
|
||||
|
||||
bool isValid() {
|
||||
bool isValid() const {
|
||||
return isPointerSerializationValid() && isPointerDeserializationValid();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -144,11 +144,10 @@ namespace bitsery {
|
||||
BaseToDerivedKey key{RTTI::template get<TBase>(), RTTI::template get<TDerived>()};
|
||||
pointer_utils::StdPolyAlloc<THandler> alloc{_memResource};
|
||||
auto ptr = alloc.allocate(1);
|
||||
std::shared_ptr<THandler> handler(new (ptr)THandler{}, [this](THandler* data) {
|
||||
std::shared_ptr<THandler> handler(new (ptr)THandler{}, [alloc](THandler* data) mutable {
|
||||
data->~THandler();
|
||||
pointer_utils::StdPolyAlloc<THandler> alloc{_memResource};
|
||||
alloc.deallocate(data, 1);
|
||||
}, pointer_utils::StdPolyAlloc<THandler>(_memResource));
|
||||
}, alloc);
|
||||
if (_baseToDerivedMap
|
||||
.emplace(key, std::move(handler))
|
||||
.second) {
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace bitsery {
|
||||
container.push_back(::bitsery::Access::create<TValue>());
|
||||
}
|
||||
if (oldSize > newSize) {
|
||||
container.erase(std::next(std::begin(container), newSize));
|
||||
container.erase(std::next(std::begin(container), newSize), std::end(container));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
11
patches/README.md
Normal file
11
patches/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Compiler specific patches
|
||||
|
||||
This folder will provide patches for various C++ compilers that are not C++11 compatible yet. This allows providing any fix for any compiler, without polluting core library with compiler-specific fixes.
|
||||
|
||||
A patch can be applied either with `git apply` or `patch` command, like this:
|
||||
```bash
|
||||
git apply patches/<patch_name>
|
||||
patch -p1 < patches/<patch_name>
|
||||
```
|
||||
|
||||
* [centos7_gcc4.8.2.diff](centos7_gcc4.8.2.diff) in this version, unordered_map is not fully C++11 compatible yet. It is lacking some constructors that accept allocator, and isn't using `std::allocator_traits`.
|
||||
119
patches/centos7_gcc4.8.2.diff
Normal file
119
patches/centos7_gcc4.8.2.diff
Normal file
@@ -0,0 +1,119 @@
|
||||
diff --git a/include/bitsery/details/serialization_common.h b/include/bitsery/details/serialization_common.h
|
||||
index 6d5a441..462cee2 100644
|
||||
--- a/include/bitsery/details/serialization_common.h
|
||||
+++ b/include/bitsery/details/serialization_common.h
|
||||
@@ -380,7 +380,7 @@ namespace bitsery {
|
||||
template <typename ... TArgs>
|
||||
explicit AdapterAndContextRef(Context& ctx, TArgs&& ... args)
|
||||
: _adapter{std::forward<TArgs>(args)...},
|
||||
- _context{ctx}
|
||||
+ _context(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
diff --git a/include/bitsery/ext/inheritance.h b/include/bitsery/ext/inheritance.h
|
||||
index f4c6655..5cd44ab 100644
|
||||
--- a/include/bitsery/ext/inheritance.h
|
||||
+++ b/include/bitsery/ext/inheritance.h
|
||||
@@ -36,7 +36,7 @@ namespace bitsery {
|
||||
class InheritanceContext {
|
||||
public:
|
||||
explicit InheritanceContext(MemResourceBase* memResource = nullptr)
|
||||
- :_virtualBases{pointer_utils::StdPolyAlloc<const void*>{memResource}}
|
||||
+ :_virtualBases{0, std::hash<const void*>{}, std::equal_to<const void*>{}, pointer_utils::StdPolyAlloc<const void*>{memResource}}
|
||||
{}
|
||||
InheritanceContext(const InheritanceContext&) = delete;
|
||||
InheritanceContext&operator = (const InheritanceContext&) = delete;
|
||||
diff --git a/include/bitsery/ext/utils/memory_resource.h b/include/bitsery/ext/utils/memory_resource.h
|
||||
index 472965a..18b3f31 100644
|
||||
--- a/include/bitsery/ext/utils/memory_resource.h
|
||||
+++ b/include/bitsery/ext/utils/memory_resource.h
|
||||
@@ -24,6 +24,7 @@
|
||||
#define BITSERY_EXT_MEMORY_RESOURCE_H
|
||||
|
||||
#include "../../details/serialization_common.h"
|
||||
+#include <cstddef>
|
||||
#include <new>
|
||||
|
||||
namespace bitsery {
|
||||
@@ -128,6 +129,40 @@ namespace bitsery {
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
+ using pointer = T*;
|
||||
+ using const_pointer = const T*;
|
||||
+ using reference = T&;
|
||||
+ using const_reference = const T&;
|
||||
+ using size_type = size_t;
|
||||
+ using difference_type = ptrdiff_t;
|
||||
+
|
||||
+ size_t max_size() const noexcept {
|
||||
+ return std::numeric_limits<size_t>::max() / sizeof(value_type);
|
||||
+ }
|
||||
+
|
||||
+ void construct(T *p, const T &val) {
|
||||
+ new((void *) p) T(val);
|
||||
+ }
|
||||
+
|
||||
+ template<class U, class... Args>
|
||||
+ void construct(U *p, Args &&... args) {
|
||||
+ new((void *) p) U(std::forward<Args>(args)...);
|
||||
+ }
|
||||
+
|
||||
+ void destroy(T *p) {
|
||||
+ p->~T();
|
||||
+ }
|
||||
+
|
||||
+ template<class U>
|
||||
+ void destroy(U *p) {
|
||||
+ p->~U();
|
||||
+ }
|
||||
+
|
||||
+ template<typename U>
|
||||
+ struct rebind {
|
||||
+ using other = StdPolyAlloc<U>;
|
||||
+ };
|
||||
+
|
||||
explicit constexpr StdPolyAlloc(MemResourceBase* memResource)
|
||||
:_alloc{memResource} {}
|
||||
explicit constexpr StdPolyAlloc(PolyAllocWithTypeId alloc) : _alloc{alloc} {}
|
||||
diff --git a/include/bitsery/ext/utils/pointer_utils.h b/include/bitsery/ext/utils/pointer_utils.h
|
||||
index f6f90da..6b65600 100644
|
||||
--- a/include/bitsery/ext/utils/pointer_utils.h
|
||||
+++ b/include/bitsery/ext/utils/pointer_utils.h
|
||||
@@ -153,7 +153,7 @@ namespace bitsery {
|
||||
public:
|
||||
explicit PointerLinkingContextSerialization(MemResourceBase* memResource = nullptr)
|
||||
: _currId{0},
|
||||
- _ptrMap{StdPolyAlloc<std::pair<const void* const, PLCInfoSerializer>>{memResource}} {}
|
||||
+ _ptrMap{0, std::hash<const void*>{}, std::equal_to<const void*>{}, StdPolyAlloc<std::pair<const void* const, PLCInfoSerializer>>{memResource}} {}
|
||||
|
||||
PointerLinkingContextSerialization(const PointerLinkingContextSerialization&) = delete;
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace bitsery {
|
||||
public:
|
||||
explicit PointerLinkingContextDeserialization(MemResourceBase* memResource = nullptr)
|
||||
: _memResource{memResource},
|
||||
- _idMap{StdPolyAlloc<std::pair<const size_t, PLCInfoDeserializer>>{memResource}} {}
|
||||
+ _idMap{0, std::hash<size_t>{}, std::equal_to<size_t>{}, StdPolyAlloc<std::pair<const size_t, PLCInfoDeserializer>>{memResource}} {}
|
||||
|
||||
PointerLinkingContextDeserialization(const PointerLinkingContextDeserialization&) = delete;
|
||||
|
||||
diff --git a/include/bitsery/ext/utils/polymorphism_utils.h b/include/bitsery/ext/utils/polymorphism_utils.h
|
||||
index 6678230..a2cef4d 100644
|
||||
--- a/include/bitsery/ext/utils/polymorphism_utils.h
|
||||
+++ b/include/bitsery/ext/utils/polymorphism_utils.h
|
||||
@@ -185,11 +185,8 @@ namespace bitsery {
|
||||
|
||||
explicit PolymorphicContext(MemResourceBase* memResource = nullptr)
|
||||
:_memResource{memResource},
|
||||
- _baseToDerivedMap{pointer_utils::StdPolyAlloc<std::pair<const BaseToDerivedKey,
|
||||
- std::shared_ptr<PolymorphicHandlerBase>>>{memResource}},
|
||||
- _baseToDerivedArray{pointer_utils::StdPolyAlloc<std::pair<const size_t,
|
||||
- std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>{memResource}}
|
||||
- {}
|
||||
+ _baseToDerivedMap{0, BaseToDerivedKeyHashier{}, std::equal_to<BaseToDerivedKey>{}, pointer_utils::StdPolyAlloc<std::pair<const BaseToDerivedKey, std::shared_ptr<PolymorphicHandlerBase>>>{memResource}},
|
||||
+ _baseToDerivedArray{0, std::hash<size_t>{}, std::equal_to<size_t>{}, pointer_utils::StdPolyAlloc<std::pair<const size_t, std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>{memResource}} {}
|
||||
|
||||
PolymorphicContext(const PolymorphicContext& ) = delete;
|
||||
PolymorphicContext& operator = (const PolymorphicContext&) = delete;
|
||||
@@ -96,6 +96,7 @@ TEST(DeserializeNonDefaultConstructible, ResultContainerShouldShrink) {
|
||||
std::vector<NonDefaultConstructible> res{};
|
||||
res.emplace_back(2);
|
||||
res.emplace_back(3);
|
||||
res.emplace_back(4);
|
||||
|
||||
ctx.createSerializer().container(data, 10);
|
||||
ctx.createDeserializer().container(res, 10);
|
||||
|
||||
Reference in New Issue
Block a user