mirror of
https://github.com/fraillt/bitsery.git
synced 2026-06-18 13:19:11 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bebfd4911 | ||
|
|
5e7ecede9b | ||
|
|
ff841d63f6 | ||
|
|
66d16516e2 | ||
|
|
7ea1da0d48 | ||
|
|
8bda82576e | ||
|
|
ee992d8b57 | ||
|
|
4dcdd594da | ||
|
|
b714459a2b | ||
|
|
be2f295310 | ||
|
|
cd73aca2f5 | ||
|
|
94f7adaf6c | ||
|
|
ceeb189c8b | ||
|
|
90243480ec |
8
.github/FUNDING.yml
vendored
Normal file
8
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
github: fraillt
|
||||||
|
buy_me_a_coffee: fraillt
|
||||||
|
custom:
|
||||||
|
- "https://www.paypal.com/paypalme/fraillt"
|
||||||
|
- "https://explorer.solana.com/address/5uHU32nBuniRxg6RZu4tsLWrXGFFz4pwMGHGuCLmkGJQ"
|
||||||
|
- "https://etherscan.io/address/0xe51cb417d1BFcd3EE4cfad9fa11b05631823AADb"
|
||||||
|
- "https://polygonscan.com/address/0xe51cb417d1BFcd3EE4cfad9fa11b05631823AADb"
|
||||||
28
.github/workflows/on_linux.yml
vendored
28
.github/workflows/on_linux.yml
vendored
@@ -9,53 +9,37 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: ${{ matrix.config.name }}
|
name: ${{ matrix.config.name }}
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-24.04
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
config:
|
config:
|
||||||
- name: "Ubuntu 18.04 with Clang 3.9"
|
- name: "Ubuntu Latest with GCC 14"
|
||||||
cxx_ver: 11
|
|
||||||
compiler: clang
|
|
||||||
compiler_ver: 3.9
|
|
||||||
- name: "Ubuntu 18.04 with GCC 5.0"
|
|
||||||
cxx_ver: 11
|
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
compiler_ver: 5
|
compiler_ver: 14
|
||||||
- name: "Ubuntu 18.04 with GCC 11.0"
|
- name: "Ubuntu Latests with Clang 18"
|
||||||
cxx_ver: 17
|
|
||||||
compiler: gcc
|
|
||||||
compiler_ver: 11
|
|
||||||
- name: "Ubuntu 18.04 with Clang 13"
|
|
||||||
cxx_ver: 17
|
|
||||||
compiler: clang
|
compiler: clang
|
||||||
compiler_ver: 13
|
compiler_ver: 18
|
||||||
steps:
|
steps:
|
||||||
- name: Prepare specific Clang version
|
- name: Prepare specific Clang version
|
||||||
if: ${{ matrix.config.compiler == 'clang' }}
|
if: ${{ matrix.config.compiler == 'clang' }}
|
||||||
run: |
|
run: |
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
|
||||||
sudo apt-add-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-13 main"
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install clang-${{ matrix.config.compiler_ver}}
|
sudo apt install clang-${{ matrix.config.compiler_ver}}
|
||||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${{ matrix.config.compiler_ver}} 100
|
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${{ matrix.config.compiler_ver}} 100
|
||||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${{ matrix.config.compiler_ver}} 100
|
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${{ matrix.config.compiler_ver}} 100
|
||||||
- name: Prepare specific GCC version
|
- name: Prepare specific GCC version
|
||||||
if: ${{ matrix.config.compiler == 'gcc' }}
|
if: ${{ matrix.config.compiler == 'gcc' }}
|
||||||
run: |
|
run: |
|
||||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install g++-${{ matrix.config.compiler_ver}}
|
sudo apt install g++-${{ matrix.config.compiler_ver}}
|
||||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-${{ matrix.config.compiler_ver}} 100
|
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-${{ matrix.config.compiler_ver}} 100
|
||||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-${{ matrix.config.compiler_ver}} 100
|
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-${{ matrix.config.compiler_ver}} 100
|
||||||
- name: Installing GTest
|
- name: Installing GTest
|
||||||
run: |
|
run: |
|
||||||
sudo add-apt-repository ppa:team-xbmc/ppa
|
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install libgmock-dev
|
sudo apt-get install libgmock-dev
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=${{ matrix.config.cxx_ver }}
|
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build
|
run: cmake --build build
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
|
|||||||
4
.github/workflows/on_mac.yml
vendored
4
.github/workflows/on_mac.yml
vendored
@@ -14,9 +14,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
git clone https://github.com/google/googletest.git
|
git clone https://github.com/google/googletest.git
|
||||||
cd googletest
|
cd googletest
|
||||||
git checkout release-1.11.0
|
git checkout v1.14.0
|
||||||
cmake -S . -B build
|
cmake -S . -B build
|
||||||
cmake --build build --target install
|
sudo cmake --build build --target install
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17
|
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17
|
||||||
|
|||||||
2
.github/workflows/on_windows.yml
vendored
2
.github/workflows/on_windows.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
git clone https://github.com/google/googletest.git
|
git clone https://github.com/google/googletest.git
|
||||||
cd googletest
|
cd googletest
|
||||||
git checkout release-1.11.0
|
git checkout v1.14.0
|
||||||
cmake -S . -B build -Dgtest_force_shared_crt=ON
|
cmake -S . -B build -Dgtest_force_shared_crt=ON
|
||||||
cmake --build build --config Release --target install
|
cmake --build build --config Release --target install
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|||||||
24
CHANGELOG.md
24
CHANGELOG.md
@@ -1,3 +1,27 @@
|
|||||||
|
# [5.2.5](https://github.com/fraillt/bitsery/compare/v5.2.4...v5.2.5) (2025-10-09)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
* fix security issue during deserialization where a crafted payload could cause a shared pointer to be assigned to a different type. More information is [here](https://gist.github.com/TrebledJ/750abc64a826f19dd2d6774724629b71). (huge thanks to [Johnathan](https://github.com/TrebledJ))
|
||||||
|
* fix serialization of shared polymorphic pointer-like types by correctly identifying same object (e.g. the same object serialized through `Base` or `Derived` would otherwise have different pointer addresses).
|
||||||
|
* fix polymorphic type assignment to "observer" by adjusting pointer address.
|
||||||
|
* fix spelling of C++ "likely" attribute. #121 (thanks to [Jules](https://github.com/jules-ai))
|
||||||
|
|
||||||
|
### Other notes
|
||||||
|
* format code that was left unformatted in the previous version.
|
||||||
|
* remove broken patch for GCC 4.8.2 (CentOS 7).
|
||||||
|
|
||||||
|
# [5.2.4](https://github.com/fraillt/bitsery/compare/v5.2.3...v5.2.4) (2024-07-30)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* implement brief syntax for std::optional and std::bitset. #116 (thanks to [Destroyerrrocket](https://github.com/Destroyerrrocket))
|
||||||
|
* improve performance for buffer adapters. #118 (thanks to [Destroyerrrocket](https://github.com/Destroyerrrocket))
|
||||||
|
* check if should swap by taking into account actual type (in addition to configuration). #105 (thanks to [SoftdriveFelix](https://github.com/SoftdriveFelix))
|
||||||
|
* fix compile errors for latest compilers. #106 (thanks to [NBurley93](https://github.com/NBurley93))
|
||||||
|
|
||||||
|
### Other notes
|
||||||
|
* change cmake_minimum_required to 3.25.
|
||||||
|
* change compilers for ubuntu (gcc 14 and clang 18).
|
||||||
|
|
||||||
# [5.2.3](https://github.com/fraillt/bitsery/compare/v5.2.2...v5.2.3) (2022-12-01)
|
# [5.2.3](https://github.com/fraillt/bitsery/compare/v5.2.2...v5.2.3) (2022-12-01)
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.1)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(bitsery
|
project(bitsery
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
VERSION 5.2.2)
|
VERSION 5.2.5)
|
||||||
|
|
||||||
#======== build options ===================================
|
#======== build options ===================================
|
||||||
option(BITSERY_BUILD_EXAMPLES "Build examples" OFF)
|
option(BITSERY_BUILD_EXAMPLES "Build examples" OFF)
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -102,9 +102,13 @@ Works with C++11 compiler, no additional dependencies, include `<bitsery/bitsery
|
|||||||
|
|
||||||
Library is tested on all major compilers on Windows, Linux and macOS.
|
Library is tested on all major compilers on Windows, Linux and macOS.
|
||||||
|
|
||||||
There is a patch that allows using bitsery with non-fully compatible C++11 compilers.
|
|
||||||
* CentOS 7 with gcc 4.8.2.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
**bitsery** is licensed under the [MIT license](LICENSE).
|
**bitsery** is licensed under the [MIT license](LICENSE).
|
||||||
|
|
||||||
|
## 💖 Sponsor Me?
|
||||||
|
|
||||||
|
If you find this project useful or interesting, or just want to say thanks, you can buy me a coffee!
|
||||||
|
Your support keeps me motivated to maintaining and improving this project.
|
||||||
|
|
||||||
|
[**Thank you!**](https://github.com/sponsors/fraillt)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
#SOFTWARE.
|
#SOFTWARE.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.1)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(bitsery_examples CXX)
|
project(bitsery_examples CXX)
|
||||||
|
|
||||||
if (NOT TARGET Bitsery::bitsery)
|
if (NOT TARGET Bitsery::bitsery)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ private:
|
|||||||
template<typename S>
|
template<typename S>
|
||||||
void serialize(S& s)
|
void serialize(S& s)
|
||||||
{
|
{
|
||||||
// forward/backward compatibility for monsters
|
// forward/backward compatibility for weapons
|
||||||
s.ext(*this, bitsery::ext::Growable{}, [](S& s, Weapon& o1) {
|
s.ext(*this, bitsery::ext::Growable{}, [](S& s, Weapon& o1) {
|
||||||
s.text1b(o1.name, 20);
|
s.text1b(o1.name, 20);
|
||||||
s.value2b(o1.damage);
|
s.value2b(o1.damage);
|
||||||
@@ -103,8 +103,6 @@ main()
|
|||||||
|
|
||||||
// create buffer to store data to
|
// create buffer to store data to
|
||||||
Buffer buffer{};
|
Buffer buffer{};
|
||||||
// since we're using different configuration, we cannot use quickSerialization
|
|
||||||
// function.
|
|
||||||
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
||||||
|
|
||||||
MyTypes::Monster res{};
|
MyTypes::Monster res{};
|
||||||
|
|||||||
@@ -95,14 +95,12 @@ namespace bitsery {
|
|||||||
// and Derived2 member fnc we need explicitly select which function to use
|
// and Derived2 member fnc we need explicitly select which function to use
|
||||||
template<>
|
template<>
|
||||||
struct SelectSerializeFnc<Derived2> : UseMemberFnc
|
struct SelectSerializeFnc<Derived2> : UseMemberFnc
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
// multiple inheritance has non-member serialize function defined
|
// multiple inheritance has non-member serialize function defined
|
||||||
template<>
|
template<>
|
||||||
struct SelectSerializeFnc<MultipleInheritance> : UseNonMemberFnc
|
struct SelectSerializeFnc<MultipleInheritance> : UseNonMemberFnc
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// some helper types
|
// some helper types
|
||||||
|
|||||||
@@ -191,14 +191,12 @@ namespace ext {
|
|||||||
template<>
|
template<>
|
||||||
struct PolymorphicBaseClass<Shape>
|
struct PolymorphicBaseClass<Shape>
|
||||||
: PolymorphicDerivedClasses<Circle, Rectangle>
|
: PolymorphicDerivedClasses<Circle, Rectangle>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct PolymorphicBaseClass<Rectangle>
|
struct PolymorphicBaseClass<Rectangle>
|
||||||
: PolymorphicDerivedClasses<RoundedRectangle>
|
: PolymorphicDerivedClasses<RoundedRectangle>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#ifndef BITSERY_ADAPTER_BUFFER_H
|
#ifndef BITSERY_ADAPTER_BUFFER_H
|
||||||
#define BITSERY_ADAPTER_BUFFER_H
|
#define BITSERY_ADAPTER_BUFFER_H
|
||||||
|
|
||||||
|
#include "../bitsery.h"
|
||||||
#include "../details/adapter_bit_packing.h"
|
#include "../details/adapter_bit_packing.h"
|
||||||
#include "../traits/core/traits.h"
|
#include "../traits/core/traits.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -268,16 +269,16 @@ private:
|
|||||||
|
|
||||||
void maybeResize(size_t newOffset, std::true_type)
|
void maybeResize(size_t newOffset, std::true_type)
|
||||||
{
|
{
|
||||||
if (newOffset > _bufferSize) {
|
if (newOffset > _bufferSize)
|
||||||
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(
|
BITSERY_UNLIKELY
|
||||||
*_buffer, _currOffset, newOffset);
|
{
|
||||||
_beginIt = std::begin(*_buffer);
|
doResize(newOffset);
|
||||||
_bufferSize = traits::ContainerTraits<Buffer>::size(*_buffer);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void maybeResize(size_t newOffset, std::false_type)
|
void maybeResize(size_t newOffset, std::false_type)
|
||||||
{
|
{
|
||||||
|
static_cast<void>(newOffset);
|
||||||
assert(newOffset <= _bufferSize);
|
assert(newOffset <= _bufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,6 +289,14 @@ private:
|
|||||||
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
|
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
|
||||||
_currOffset = newOffset;
|
_currOffset = newOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BITSERY_NOINLINE void doResize(size_t newOffset)
|
||||||
|
{
|
||||||
|
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(
|
||||||
|
*_buffer, _currOffset, newOffset);
|
||||||
|
_beginIt = std::begin(*_buffer);
|
||||||
|
_bufferSize = traits::ContainerTraits<Buffer>::size(*_buffer);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
#define BITSERY_MAJOR_VERSION 5
|
#define BITSERY_MAJOR_VERSION 5
|
||||||
#define BITSERY_MINOR_VERSION 2
|
#define BITSERY_MINOR_VERSION 2
|
||||||
#define BITSERY_PATCH_VERSION 2
|
#define BITSERY_PATCH_VERSION 5
|
||||||
|
|
||||||
#define BITSERY_QUOTE_MACRO(name) #name
|
#define BITSERY_QUOTE_MACRO(name) #name
|
||||||
#define BITSERY_BUILD_VERSION_STR(major, minor, patch) \
|
#define BITSERY_BUILD_VERSION_STR(major, minor, patch) \
|
||||||
@@ -36,6 +36,67 @@
|
|||||||
BITSERY_BUILD_VERSION_STR( \
|
BITSERY_BUILD_VERSION_STR( \
|
||||||
BITSERY_MAJOR_VERSION, BITSERY_MINOR_VERSION, BITSERY_PATCH_VERSION)
|
BITSERY_MAJOR_VERSION, BITSERY_MINOR_VERSION, BITSERY_PATCH_VERSION)
|
||||||
|
|
||||||
|
#define BITSERY_DO_PRAGMA(x) _Pragma(#x)
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define BITSERY_DISABLE_WARNINGS(...) \
|
||||||
|
BITSERY_DO_PRAGMA(GCC diagnostic push) \
|
||||||
|
BITSERY_DO_PRAGMA(GCC diagnostic ignored __VA_ARGS__)
|
||||||
|
#define BITSERY_ENABLE_WARNINGS() BITSERY_DO_PRAGMA(GCC diagnostic pop)
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define BITSERY_DISABLE_WARNINGS(...) \
|
||||||
|
BITSERY_DO_PRAGMA(GCC diagnostic push) \
|
||||||
|
BITSERY_DO_PRAGMA(GCC diagnostic ignored __VA_ARGS__) \
|
||||||
|
BITSERY_DO_PRAGMA(GCC diagnostic pop)
|
||||||
|
#define BITSERY_ENABLE_WARNINGS() BITSERY_DO_PRAGMA(GCC diagnostic pop)
|
||||||
|
#else
|
||||||
|
#define BITSERY_DISABLE_WARNINGS(...)
|
||||||
|
#define BITSERY_ENABLE_WARNINGS()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#define BITSERY_ATTRIBUTE(...) \
|
||||||
|
BITSERY_DISABLE_WARNINGS("-Wfuture-attribute-extensions") \
|
||||||
|
[[__VA_ARGS__]] BITSERY_ENABLE_WARNINGS()
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define BITSERY_ATTRIBUTE(...) [[__VA_ARGS__]]
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define BITSERY_ATTRIBUTE(...) [[__VA_ARGS__]]
|
||||||
|
#else
|
||||||
|
#define BITSERY_ATTRIBUTE(...) [[__VA_ARGS__]]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_cpp_attribute(likely)
|
||||||
|
#define BITSERY_LIKELY BITSERY_ATTRIBUTE(likely)
|
||||||
|
#else
|
||||||
|
#define BITSERY_LIKELY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_cpp_attribute(unlikely)
|
||||||
|
#define BITSERY_UNLIKELY BITSERY_ATTRIBUTE(unlikely)
|
||||||
|
#else
|
||||||
|
#define BITSERY_UNLIKELY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC__
|
||||||
|
#define BITSERY_NOINLINE __attribute__((noinline))
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define BITSERY_NOINLINE __declspec(noinline)
|
||||||
|
#else
|
||||||
|
#define BITSERY_NOINLINE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __GNUC__
|
||||||
|
#define BITSERY_ASSUME(cond) \
|
||||||
|
do { \
|
||||||
|
if (!(cond)) \
|
||||||
|
__builtin_unreachable(); \
|
||||||
|
} while (0)
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#define BITSERY_ASSUME(cond) __assume(cond)
|
||||||
|
#else
|
||||||
|
#define BITSERY_ASSUME(cond)
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "deserializer.h"
|
#include "deserializer.h"
|
||||||
#include "serializer.h"
|
#include "serializer.h"
|
||||||
|
|
||||||
|
|||||||
36
include/bitsery/brief_syntax/bitset.h
Normal file
36
include/bitsery/brief_syntax/bitset.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Mindaugas Vinkelis
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_BITSET_H
|
||||||
|
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_BITSET_H
|
||||||
|
|
||||||
|
#include "../ext/std_bitset.h"
|
||||||
|
|
||||||
|
namespace bitsery {
|
||||||
|
template<typename S, size_t N>
|
||||||
|
void
|
||||||
|
serialize(S& s, std::bitset<N>& obj)
|
||||||
|
{
|
||||||
|
s.ext(obj, ext::StdBitset{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
36
include/bitsery/brief_syntax/optional.h
Normal file
36
include/bitsery/brief_syntax/optional.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Mindaugas Vinkelis
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_OPTIONAL_H
|
||||||
|
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_OPTIONAL_H
|
||||||
|
|
||||||
|
#include "../ext/std_optional.h"
|
||||||
|
|
||||||
|
namespace bitsery {
|
||||||
|
template<typename S, typename Ts>
|
||||||
|
void
|
||||||
|
serialize(S& s, std::optional<Ts>& obj)
|
||||||
|
{
|
||||||
|
s.ext(obj, ext::StdOptional{});
|
||||||
|
}
|
||||||
|
} // namespace bitsery
|
||||||
|
#endif
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
@@ -144,10 +145,7 @@ struct SwapImpl
|
|||||||
return static_cast<uint16_t>((value & 0x00ff) << 8 | (value & 0xff00) >> 8);
|
return static_cast<uint16_t>((value & 0x00ff) << 8 | (value & 0xff00) >> 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t exec(uint8_t value)
|
static uint8_t exec(uint8_t value) { return value; }
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename TValue>
|
template<typename TValue>
|
||||||
@@ -194,10 +192,11 @@ getSystemEndianness()
|
|||||||
: EndiannessType::BigEndian;
|
: EndiannessType::BigEndian;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Config>
|
template<typename Config, typename T>
|
||||||
using ShouldSwap =
|
using ShouldSwap =
|
||||||
std::integral_constant<bool,
|
std::integral_constant<bool,
|
||||||
Config::Endianness != details::getSystemEndianness()>;
|
Config::Endianness != details::getSystemEndianness() &&
|
||||||
|
sizeof(T) != 1>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* helper types to work with bits
|
* helper types to work with bits
|
||||||
@@ -287,7 +286,7 @@ struct OutputAdapterBaseCRTP
|
|||||||
{
|
{
|
||||||
static_assert(std::is_integral<T>(), "");
|
static_assert(std::is_integral<T>(), "");
|
||||||
static_assert(sizeof(T) == SIZE, "");
|
static_assert(sizeof(T) == SIZE, "");
|
||||||
writeSwappedValue(&v, ShouldSwap<typename Adapter::TConfig>{});
|
writeSwappedValue(&v, ShouldSwap<typename Adapter::TConfig, T>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t SIZE, typename T>
|
template<size_t SIZE, typename T>
|
||||||
@@ -295,7 +294,7 @@ struct OutputAdapterBaseCRTP
|
|||||||
{
|
{
|
||||||
static_assert(std::is_integral<T>(), "");
|
static_assert(std::is_integral<T>(), "");
|
||||||
static_assert(sizeof(T) == SIZE, "");
|
static_assert(sizeof(T) == SIZE, "");
|
||||||
writeSwappedBuffer(buf, count, ShouldSwap<typename Adapter::TConfig>{});
|
writeSwappedBuffer(buf, count, ShouldSwap<typename Adapter::TConfig, T>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -360,7 +359,7 @@ struct InputAdapterBaseCRTP
|
|||||||
static_assert(sizeof(T) == SIZE, "");
|
static_assert(sizeof(T) == SIZE, "");
|
||||||
static_cast<Adapter*>(this)->template readInternalValue<sizeof(T)>(
|
static_cast<Adapter*>(this)->template readInternalValue<sizeof(T)>(
|
||||||
reinterpret_cast<typename Adapter::TValue*>(&v));
|
reinterpret_cast<typename Adapter::TValue*>(&v));
|
||||||
swapDataBits(v, ShouldSwap<typename Adapter::TConfig>{});
|
swapDataBits(v, ShouldSwap<typename Adapter::TConfig, T>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t SIZE, typename T>
|
template<size_t SIZE, typename T>
|
||||||
@@ -370,7 +369,7 @@ struct InputAdapterBaseCRTP
|
|||||||
static_assert(sizeof(T) == SIZE, "");
|
static_assert(sizeof(T) == SIZE, "");
|
||||||
static_cast<Adapter*>(this)->readInternalBuffer(
|
static_cast<Adapter*>(this)->readInternalBuffer(
|
||||||
reinterpret_cast<typename Adapter::TValue*>(buf), sizeof(T) * count);
|
reinterpret_cast<typename Adapter::TValue*>(buf), sizeof(T) * count);
|
||||||
swapDataBits(buf, count, ShouldSwap<typename Adapter::TConfig>{});
|
swapDataBits(buf, count, ShouldSwap<typename Adapter::TConfig, T>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -62,8 +62,7 @@ struct NotDefinedType
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
struct IsDefined
|
struct IsDefined
|
||||||
: public std::integral_constant<bool, !std::is_same<NotDefinedType, T>::value>
|
: public std::integral_constant<bool, !std::is_same<NotDefinedType, T>::value>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,24 +70,19 @@ struct FtorExtValue : public Ext
|
|||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
struct FtorExtValue1b : FtorExtValue<1, Ext>
|
struct FtorExtValue1b : FtorExtValue<1, Ext>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
struct FtorExtValue2b : FtorExtValue<2, Ext>
|
struct FtorExtValue2b : FtorExtValue<2, Ext>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
struct FtorExtValue4b : FtorExtValue<4, Ext>
|
struct FtorExtValue4b : FtorExtValue<4, Ext>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
struct FtorExtValue8b : FtorExtValue<8, Ext>
|
struct FtorExtValue8b : FtorExtValue<8, Ext>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
struct FtorExtValue16b : FtorExtValue<16, Ext>
|
struct FtorExtValue16b : FtorExtValue<16, Ext>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ext>
|
template<typename Ext>
|
||||||
struct FtorExtObject : public Ext
|
struct FtorExtObject : public Ext
|
||||||
@@ -105,8 +100,7 @@ struct FtorExtObject : public Ext
|
|||||||
// SelectSerializeFnc<MyDerivedClass>:UseMemberFnc {};
|
// SelectSerializeFnc<MyDerivedClass>:UseMemberFnc {};
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct SelectSerializeFnc : std::integral_constant<int, 0>
|
struct SelectSerializeFnc : std::integral_constant<int, 0>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
// types you need to inherit from when specializing SelectSerializeFnc class
|
// types you need to inherit from when specializing SelectSerializeFnc class
|
||||||
struct UseNonMemberFnc : std::integral_constant<int, 1>
|
struct UseNonMemberFnc : std::integral_constant<int, 1>
|
||||||
@@ -120,20 +114,17 @@ namespace details {
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
struct IsContainerTraitsDefined
|
struct IsContainerTraitsDefined
|
||||||
: public IsDefined<typename traits::ContainerTraits<T>::TValue>
|
: public IsDefined<typename traits::ContainerTraits<T>::TValue>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IsTextTraitsDefined
|
struct IsTextTraitsDefined
|
||||||
: public IsDefined<typename traits::TextTraits<T>::TValue>
|
: public IsDefined<typename traits::TextTraits<T>::TValue>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ext, typename T>
|
template<typename Ext, typename T>
|
||||||
struct IsExtensionTraitsDefined
|
struct IsExtensionTraitsDefined
|
||||||
: public IsDefined<typename traits::ExtensionTraits<Ext, T>::TValue>
|
: public IsDefined<typename traits::ExtensionTraits<Ext, T>::TValue>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
// helper types for HasSerializeFunction
|
// helper types for HasSerializeFunction
|
||||||
@@ -151,8 +142,7 @@ struct HasSerializeFunctionHelper
|
|||||||
};
|
};
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
struct HasSerializeFunction : HasSerializeFunctionHelper<S, T>::type
|
struct HasSerializeFunction : HasSerializeFunctionHelper<S, T>::type
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
// helper types for HasSerializeMethod
|
// helper types for HasSerializeMethod
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
@@ -169,8 +159,7 @@ struct HasSerializeMethodHelper
|
|||||||
};
|
};
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
struct HasSerializeMethod : HasSerializeMethodHelper<S, T>::type
|
struct HasSerializeMethod : HasSerializeMethodHelper<S, T>::type
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
// helper types for IsBriefSyntaxIncluded
|
// helper types for IsBriefSyntaxIncluded
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
@@ -188,8 +177,7 @@ struct IsBriefSyntaxIncludedHelper
|
|||||||
|
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
struct IsBriefSyntaxIncluded : IsBriefSyntaxIncludedHelper<S, T>::type
|
struct IsBriefSyntaxIncluded : IsBriefSyntaxIncludedHelper<S, T>::type
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
#else
|
#else
|
||||||
// helper metafunction, that is added to c++17
|
// helper metafunction, that is added to c++17
|
||||||
template<typename... Ts>
|
template<typename... Ts>
|
||||||
@@ -202,8 +190,7 @@ using void_t = typename make_void<Ts...>::type;
|
|||||||
|
|
||||||
template<typename, typename, typename = void>
|
template<typename, typename, typename = void>
|
||||||
struct HasSerializeFunction : std::false_type
|
struct HasSerializeFunction : std::false_type
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
struct HasSerializeFunction<
|
struct HasSerializeFunction<
|
||||||
@@ -211,13 +198,11 @@ struct HasSerializeFunction<
|
|||||||
T,
|
T,
|
||||||
void_t<decltype(serialize(std::declval<S&>(), std::declval<T&>()))>>
|
void_t<decltype(serialize(std::declval<S&>(), std::declval<T&>()))>>
|
||||||
: std::true_type
|
: std::true_type
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename, typename, typename = void>
|
template<typename, typename, typename = void>
|
||||||
struct HasSerializeMethod : std::false_type
|
struct HasSerializeMethod : std::false_type
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
struct HasSerializeMethod<
|
struct HasSerializeMethod<
|
||||||
@@ -225,14 +210,12 @@ struct HasSerializeMethod<
|
|||||||
T,
|
T,
|
||||||
void_t<decltype(Access::serialize(std::declval<S&>(), std::declval<T&>()))>>
|
void_t<decltype(Access::serialize(std::declval<S&>(), std::declval<T&>()))>>
|
||||||
: std::true_type
|
: std::true_type
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
// this solution doesn't work with visual studio, but is more elegant
|
// this solution doesn't work with visual studio, but is more elegant
|
||||||
template<typename, typename, typename = void>
|
template<typename, typename, typename = void>
|
||||||
struct IsBriefSyntaxIncluded : std::false_type
|
struct IsBriefSyntaxIncluded : std::false_type
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
struct IsBriefSyntaxIncluded<
|
struct IsBriefSyntaxIncluded<
|
||||||
@@ -240,8 +223,7 @@ struct IsBriefSyntaxIncluded<
|
|||||||
T,
|
T,
|
||||||
void_t<decltype(processBriefSyntax(std::declval<S&>(), std::declval<T&&>()))>>
|
void_t<decltype(processBriefSyntax(std::declval<S&>(), std::declval<T&&>()))>>
|
||||||
: std::true_type
|
: std::true_type
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// used for extensions when extension TValue = void
|
// used for extensions when extension TValue = void
|
||||||
@@ -257,8 +239,7 @@ struct IsFundamentalType
|
|||||||
std::is_enum<T>::value ||
|
std::is_enum<T>::value ||
|
||||||
std::is_floating_point<T>::value ||
|
std::is_floating_point<T>::value ||
|
||||||
std::is_integral<T>::value>
|
std::is_integral<T>::value>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename Integral = void>
|
template<typename T, typename Integral = void>
|
||||||
struct IntegralFromFundamental
|
struct IntegralFromFundamental
|
||||||
@@ -372,16 +353,14 @@ struct BriefSyntaxFunction
|
|||||||
|
|
||||||
template<int Index, typename... Conds>
|
template<int Index, typename... Conds>
|
||||||
struct FindIndex : std::integral_constant<int, Index>
|
struct FindIndex : std::integral_constant<int, Index>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<int Index, typename Cond, typename... Conds>
|
template<int Index, typename Cond, typename... Conds>
|
||||||
struct FindIndex<Index, Cond, Conds...>
|
struct FindIndex<Index, Cond, Conds...>
|
||||||
: std::conditional<Cond::value,
|
: std::conditional<Cond::value,
|
||||||
std::integral_constant<int, Index>,
|
std::integral_constant<int, Index>,
|
||||||
FindIndex<Index + 1, Conds...>>::type
|
FindIndex<Index + 1, Conds...>>::type
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename Tuple>
|
template<typename T, typename Tuple>
|
||||||
struct GetConvertibleTypeIndexFromTuple;
|
struct GetConvertibleTypeIndexFromTuple;
|
||||||
@@ -389,8 +368,7 @@ struct GetConvertibleTypeIndexFromTuple;
|
|||||||
template<typename T, typename... Us>
|
template<typename T, typename... Us>
|
||||||
struct GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>
|
struct GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>
|
||||||
: FindIndex<0, std::is_convertible<Us&, T&>...>
|
: FindIndex<0, std::is_convertible<Us&, T&>...>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename Tuple>
|
template<typename T, typename Tuple>
|
||||||
struct IsExistsConvertibleTupleType;
|
struct IsExistsConvertibleTupleType;
|
||||||
@@ -401,8 +379,7 @@ struct IsExistsConvertibleTupleType<T, std::tuple<Us...>>
|
|||||||
bool,
|
bool,
|
||||||
GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>::value !=
|
GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>::value !=
|
||||||
sizeof...(Us)>
|
sizeof...(Us)>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get context from internal or external, and check if it's convertible or not
|
* get context from internal or external, and check if it's convertible or not
|
||||||
@@ -549,13 +526,11 @@ protected:
|
|||||||
|
|
||||||
template<typename T, template<typename...> class Template>
|
template<typename T, template<typename...> class Template>
|
||||||
struct IsSpecializationOf : std::false_type
|
struct IsSpecializationOf : std::false_type
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<template<typename...> class Template, typename... Args>
|
template<template<typename...> class Template, typename... Args>
|
||||||
struct IsSpecializationOf<Template<Args...>, Template> : std::true_type
|
struct IsSpecializationOf<Template<Args...>, Template> : std::true_type
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#define BITSERY_EXT_GROWABLE_H
|
#define BITSERY_EXT_GROWABLE_H
|
||||||
|
|
||||||
#include "../traits/core/traits.h"
|
#include "../traits/core/traits.h"
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ struct PtrObserverManager
|
|||||||
|
|
||||||
static void destroyPolymorphic(T& obj,
|
static void destroyPolymorphic(T& obj,
|
||||||
MemResourceBase*,
|
MemResourceBase*,
|
||||||
PolymorphicHandlerBase&)
|
const std::shared_ptr<PolymorphicHandlerBase>&)
|
||||||
{
|
{
|
||||||
obj = nullptr;
|
obj = nullptr;
|
||||||
}
|
}
|
||||||
@@ -130,47 +130,22 @@ struct NonPtrManager
|
|||||||
|
|
||||||
static void create(T&, MemResourceBase*, size_t) {}
|
static void create(T&, MemResourceBase*, size_t) {}
|
||||||
|
|
||||||
static void createPolymorphic(T&, MemResourceBase*, PolymorphicHandlerBase&)
|
static void createPolymorphic(T&,
|
||||||
|
MemResourceBase*,
|
||||||
|
const std::shared_ptr<PolymorphicHandlerBase>&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void destroy(T&, MemResourceBase*, size_t) {}
|
static void destroy(T&, MemResourceBase*, size_t) {}
|
||||||
|
|
||||||
static void destroyPolymorphic(T&, MemResourceBase*, PolymorphicHandlerBase&)
|
static void destroyPolymorphic(T&,
|
||||||
|
MemResourceBase*,
|
||||||
|
const std::shared_ptr<PolymorphicHandlerBase>&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
};
|
};
|
||||||
|
|
||||||
// this class is used by NonPtrManager
|
|
||||||
struct NoRTTI
|
|
||||||
{
|
|
||||||
template<typename TBase>
|
|
||||||
static size_t get(TBase&)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TBase>
|
|
||||||
static constexpr size_t get()
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TBase, typename TDerived>
|
|
||||||
static constexpr TDerived* cast(TBase* obj)
|
|
||||||
{
|
|
||||||
static_assert(!std::is_pointer<TDerived>::value, "");
|
|
||||||
return dynamic_cast<TDerived*>(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TBase>
|
|
||||||
static constexpr bool isPolymorphic()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename RTTI>
|
template<typename RTTI>
|
||||||
@@ -179,31 +154,34 @@ using PointerOwnerBase =
|
|||||||
PolymorphicContext,
|
PolymorphicContext,
|
||||||
RTTI>;
|
RTTI>;
|
||||||
|
|
||||||
using PointerOwner = PointerOwnerBase<StandardRTTI>;
|
template<typename RTTI>
|
||||||
|
using PointerObserverBase =
|
||||||
using PointerObserver =
|
|
||||||
pointer_utils::PointerObjectExtensionBase<pointer_details::PtrObserverManager,
|
pointer_utils::PointerObjectExtensionBase<pointer_details::PtrObserverManager,
|
||||||
PolymorphicContext,
|
PolymorphicContext,
|
||||||
pointer_details::NoRTTI>;
|
RTTI>;
|
||||||
|
|
||||||
// inherit from PointerObjectExtensionBase in order to specify
|
// inherit from PointerObjectExtensionBase in order to specify
|
||||||
// PointerType::NotNull
|
// PointerType::NotNull
|
||||||
class ReferencedByPointer
|
template<typename RTTI>
|
||||||
|
class ReferencedByPointerBase
|
||||||
: public pointer_utils::PointerObjectExtensionBase<
|
: public pointer_utils::PointerObjectExtensionBase<
|
||||||
pointer_details::NonPtrManager,
|
pointer_details::NonPtrManager,
|
||||||
PolymorphicContext,
|
PolymorphicContext,
|
||||||
pointer_details::NoRTTI>
|
RTTI>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ReferencedByPointer()
|
ReferencedByPointerBase()
|
||||||
: pointer_utils::PointerObjectExtensionBase<pointer_details::NonPtrManager,
|
: pointer_utils::PointerObjectExtensionBase<pointer_details::NonPtrManager,
|
||||||
PolymorphicContext,
|
PolymorphicContext,
|
||||||
pointer_details::NoRTTI>(
|
RTTI>(PointerType::NotNull)
|
||||||
PointerType::NotNull)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using PointerOwner = PointerOwnerBase<StandardRTTI>;
|
||||||
|
using PointerObserver = PointerObserverBase<StandardRTTI>;
|
||||||
|
using ReferencedByPointer = ReferencedByPointerBase<StandardRTTI>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace traits {
|
namespace traits {
|
||||||
@@ -219,8 +197,8 @@ struct ExtensionTraits<ext::PointerOwnerBase<RTTI>, T*>
|
|||||||
!RTTI::template isPolymorphic<TValue>();
|
!RTTI::template isPolymorphic<TValue>();
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename RTTI>
|
||||||
struct ExtensionTraits<ext::PointerObserver, T*>
|
struct ExtensionTraits<ext::PointerObserverBase<RTTI>, T*>
|
||||||
{
|
{
|
||||||
// although pointer observer doesn't serialize anything, but we still add
|
// although pointer observer doesn't serialize anything, but we still add
|
||||||
// value overload support to be consistent with pointer owners observer only
|
// value overload support to be consistent with pointer owners observer only
|
||||||
@@ -231,8 +209,8 @@ struct ExtensionTraits<ext::PointerObserver, T*>
|
|||||||
static constexpr bool SupportLambdaOverload = false;
|
static constexpr bool SupportLambdaOverload = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T, typename RTTI>
|
||||||
struct ExtensionTraits<ext::ReferencedByPointer, T>
|
struct ExtensionTraits<ext::ReferencedByPointerBase<RTTI>, T>
|
||||||
{
|
{
|
||||||
// allow everything, because it is serialized as regular type, except it also
|
// allow everything, because it is serialized as regular type, except it also
|
||||||
// creates pointerId that is required by NonOwningPointer to work
|
// creates pointerId that is required by NonOwningPointer to work
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "../traits/core/traits.h"
|
#include "../traits/core/traits.h"
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ struct SmartPtrOwnerManager
|
|||||||
[alloc, typeId](TElement* data) { alloc.deleteObject(data, typeId); },
|
[alloc, typeId](TElement* data) { alloc.deleteObject(data, typeId); },
|
||||||
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
||||||
state.obj = obj;
|
state.obj = obj;
|
||||||
|
state.typeId = typeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void createSharedPolymorphic(
|
static void createSharedPolymorphic(
|
||||||
@@ -162,6 +163,7 @@ struct SmartPtrOwnerManager
|
|||||||
[alloc, handler](TElement* data) { handler->destroy(alloc, data); },
|
[alloc, handler](TElement* data) { handler->destroy(alloc, data); },
|
||||||
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
||||||
state.obj = obj;
|
state.obj = obj;
|
||||||
|
state.typeId = handler->getDerivedTypeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void createShared(TSharedState& state,
|
static void createShared(TSharedState& state,
|
||||||
@@ -176,6 +178,7 @@ struct SmartPtrOwnerManager
|
|||||||
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
||||||
obj = res;
|
obj = res;
|
||||||
state.obj = res;
|
state.obj = res;
|
||||||
|
state.typeId = typeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void createSharedPolymorphic(
|
static void createSharedPolymorphic(
|
||||||
@@ -191,6 +194,7 @@ struct SmartPtrOwnerManager
|
|||||||
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
pointer_utils::StdPolyAlloc<TElement>(memResource));
|
||||||
obj = res;
|
obj = res;
|
||||||
state.obj = res;
|
state.obj = res;
|
||||||
|
state.typeId = handler->getDerivedTypeId();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void saveToSharedState(TSharedState& state, T& obj)
|
static void saveToSharedState(TSharedState& state, T& obj)
|
||||||
@@ -198,10 +202,24 @@ struct SmartPtrOwnerManager
|
|||||||
state.obj = std::shared_ptr<TElement>(obj);
|
state.obj = std::shared_ptr<TElement>(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void saveToSharedStatePolymorphic(TSharedState& state, T& obj)
|
||||||
|
{
|
||||||
|
state.obj = std::shared_ptr<TElement>(obj);
|
||||||
|
}
|
||||||
|
|
||||||
static void loadFromSharedState(TSharedState& state, T& obj)
|
static void loadFromSharedState(TSharedState& state, T& obj)
|
||||||
{
|
{
|
||||||
// reinterpret_pointer_cast is only since c++17
|
auto v = state.obj.get();
|
||||||
auto p = reinterpret_cast<TElement*>(state.obj.get());
|
auto p = static_cast<TElement*>(v);
|
||||||
|
obj = std::shared_ptr<TElement>(state.obj, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void loadFromSharedStatePolymorphic(TSharedState& state,
|
||||||
|
T& obj,
|
||||||
|
const PolymorphicHandlerBase&)
|
||||||
|
{
|
||||||
|
auto v = state.obj.get();
|
||||||
|
auto p = static_cast<TElement*>(v);
|
||||||
obj = std::shared_ptr<TElement>(state.obj, p);
|
obj = std::shared_ptr<TElement>(state.obj, p);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ namespace pointer_utils {
|
|||||||
// this class is used to store context for shared ptr owners
|
// this class is used to store context for shared ptr owners
|
||||||
struct PointerSharedStateBase
|
struct PointerSharedStateBase
|
||||||
{
|
{
|
||||||
|
size_t typeId{};
|
||||||
virtual ~PointerSharedStateBase() = default;
|
virtual ~PointerSharedStateBase() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -117,16 +118,23 @@ struct PLCInfoSerializer : PLCInfo
|
|||||||
size_t id;
|
size_t id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ObserverRef
|
||||||
|
{
|
||||||
|
std::reference_wrapper<void*> obj;
|
||||||
|
size_t baseTypeId;
|
||||||
|
};
|
||||||
|
|
||||||
struct PLCInfoDeserializer : PLCInfo
|
struct PLCInfoDeserializer : PLCInfo
|
||||||
{
|
{
|
||||||
PLCInfoDeserializer(void* ptr,
|
PLCInfoDeserializer(void* ptr,
|
||||||
|
size_t ownerTypeId_,
|
||||||
PointerOwnershipType ownershipType_,
|
PointerOwnershipType ownershipType_,
|
||||||
MemResourceBase* memResource_)
|
MemResourceBase* memResource_)
|
||||||
: PLCInfo(ownershipType_)
|
: PLCInfo(ownershipType_)
|
||||||
, ownerPtr{ ptr }
|
, ownerPtr{ ptr }
|
||||||
|
, ownerTypeId{ ownerTypeId_ }
|
||||||
, memResource{ memResource_ }
|
, memResource{ memResource_ }
|
||||||
, observersList{ StdPolyAlloc<std::reference_wrapper<void*>>{
|
, observersList{ StdPolyAlloc<ObserverRef>{ memResource_ } } {};
|
||||||
memResource_ } } {};
|
|
||||||
|
|
||||||
// need to override these explicitly because we have pointer member
|
// need to override these explicitly because we have pointer member
|
||||||
PLCInfoDeserializer(const PLCInfoDeserializer&) = delete;
|
PLCInfoDeserializer(const PLCInfoDeserializer&) = delete;
|
||||||
@@ -137,30 +145,12 @@ struct PLCInfoDeserializer : PLCInfo
|
|||||||
|
|
||||||
PLCInfoDeserializer& operator=(PLCInfoDeserializer&&) = default;
|
PLCInfoDeserializer& operator=(PLCInfoDeserializer&&) = default;
|
||||||
|
|
||||||
void processOwner(void* ptr)
|
|
||||||
{
|
|
||||||
ownerPtr = ptr;
|
|
||||||
assert(ownershipType != PointerOwnershipType::Observer);
|
|
||||||
for (auto& o : observersList)
|
|
||||||
o.get() = ptr;
|
|
||||||
observersList.clear();
|
|
||||||
observersList.shrink_to_fit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void processObserver(void*(&ptr))
|
|
||||||
{
|
|
||||||
if (ownerPtr) {
|
|
||||||
ptr = ownerPtr;
|
|
||||||
} else {
|
|
||||||
observersList.emplace_back(ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* ownerPtr;
|
void* ownerPtr;
|
||||||
|
// used for polymorphic types in order to identify
|
||||||
|
// if shared objects can be assigned
|
||||||
|
size_t ownerTypeId;
|
||||||
MemResourceBase* memResource;
|
MemResourceBase* memResource;
|
||||||
std::vector<std::reference_wrapper<void*>,
|
std::vector<ObserverRef, StdPolyAlloc<ObserverRef>> observersList;
|
||||||
StdPolyAlloc<std::reference_wrapper<void*>>>
|
|
||||||
observersList;
|
|
||||||
std::unique_ptr<PointerSharedStateBase, PointerSharedStateDeleter>
|
std::unique_ptr<PointerSharedStateBase, PointerSharedStateDeleter>
|
||||||
sharedState{};
|
sharedState{};
|
||||||
};
|
};
|
||||||
@@ -254,8 +244,8 @@ public:
|
|||||||
|
|
||||||
PLCInfoDeserializer& getInfoById(size_t id, PointerOwnershipType ptrType)
|
PLCInfoDeserializer& getInfoById(size_t id, PointerOwnershipType ptrType)
|
||||||
{
|
{
|
||||||
auto res =
|
auto res = _idMap.emplace(
|
||||||
_idMap.emplace(id, PLCInfoDeserializer{ nullptr, ptrType, _memResource });
|
id, PLCInfoDeserializer{ nullptr, 0, ptrType, _memResource });
|
||||||
auto& ptrInfo = res.first->second;
|
auto& ptrInfo = res.first->second;
|
||||||
if (!res.second)
|
if (!res.second)
|
||||||
ptrInfo.update(ptrType);
|
ptrInfo.update(ptrType);
|
||||||
@@ -329,8 +319,7 @@ public:
|
|||||||
: std::integral_constant<
|
: std::integral_constant<
|
||||||
bool,
|
bool,
|
||||||
RTTI::template isPolymorphic<typename TPtrManager<T>::TElement>()>
|
RTTI::template isPolymorphic<typename TPtrManager<T>::TElement>()>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<PointerOwnershipType Value>
|
template<PointerOwnershipType Value>
|
||||||
using OwnershipType = std::integral_constant<PointerOwnershipType, Value>;
|
using OwnershipType = std::integral_constant<PointerOwnershipType, Value>;
|
||||||
@@ -353,8 +342,8 @@ public:
|
|||||||
if (ptr) {
|
if (ptr) {
|
||||||
auto& ctx = ser.template context<
|
auto& ctx = ser.template context<
|
||||||
pointer_utils::PointerLinkingContextSerialization>();
|
pointer_utils::PointerLinkingContextSerialization>();
|
||||||
auto& ptrInfo =
|
auto& ptrInfo = ctx.getInfoByPtr(getRootPtr(ser, ptr, IsPolymorphic<T>{}),
|
||||||
ctx.getInfoByPtr(getBasePtr(ptr), TPtrManager<T>::getOwnership());
|
TPtrManager<T>::getOwnership());
|
||||||
details::writeSize(ser.adapter(), ptrInfo.id);
|
details::writeSize(ser.adapter(), ptrInfo.id);
|
||||||
if (TPtrManager<T>::getOwnership() != PointerOwnershipType::Observer) {
|
if (TPtrManager<T>::getOwnership() != PointerOwnershipType::Observer) {
|
||||||
if (!ptrInfo.isSharedProcessed)
|
if (!ptrInfo.isSharedProcessed)
|
||||||
@@ -412,7 +401,7 @@ private:
|
|||||||
const auto& ctx = des.template context<TPolymorphicContext<RTTI>>();
|
const auto& ctx = des.template context<TPolymorphicContext<RTTI>>();
|
||||||
auto ptr = TPtrManager<TObj>::getPtr(obj);
|
auto ptr = TPtrManager<TObj>::getPtr(obj);
|
||||||
TPtrManager<TObj>::destroyPolymorphic(
|
TPtrManager<TObj>::destroyPolymorphic(
|
||||||
obj, memResource, ctx.getPolymorphicHandler(*ptr));
|
obj, memResource, ctx.getPolymorphicHandler(ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Des, typename TObj>
|
template<typename Des, typename TObj>
|
||||||
@@ -427,16 +416,23 @@ private:
|
|||||||
RTTI::template get<typename TPtrManager<TObj>::TElement>());
|
RTTI::template get<typename TPtrManager<TObj>::TElement>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename Ser, typename T>
|
||||||
const void* getBasePtr(const T* ptr) const
|
const void* getRootPtr(Ser&, const T* ptr, std::false_type) const
|
||||||
{
|
{
|
||||||
// todo implement handling of types with virtual inheritance
|
|
||||||
// this is required to correctly track same object, when one object is
|
|
||||||
// derived and other is base class e.g. shared_ptr<Base> and
|
|
||||||
// weak_ptr<Derived> or pointer observer Base*
|
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// same pointer can be accessed through different types with the same base
|
||||||
|
// e.g. if we have Base class and Derived(Base) we'll get different pointer
|
||||||
|
// address depending if we access it through Base or Derived
|
||||||
|
// this function always returns "root" (Base) pointer.
|
||||||
|
template<typename Ser, typename T>
|
||||||
|
const void* getRootPtr(Ser& ser, const T* ptr, std::true_type) const
|
||||||
|
{
|
||||||
|
const auto& ctx = ser.template context<TPolymorphicContext<RTTI>>();
|
||||||
|
return ctx.getPolymorphicHandler(ptr)->getRootPtr(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Ser, typename TPtr, typename Fnc>
|
template<typename Ser, typename TPtr, typename Fnc>
|
||||||
void serializeImpl(Ser& ser, TPtr& ptr, Fnc&&, std::true_type) const
|
void serializeImpl(Ser& ser, TPtr& ptr, Fnc&&, std::true_type) const
|
||||||
{
|
{
|
||||||
@@ -472,7 +468,13 @@ private:
|
|||||||
memResource](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
memResource](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||||
TPtrManager<T>::destroyPolymorphic(obj, memResource, handler);
|
TPtrManager<T>::destroyPolymorphic(obj, memResource, handler);
|
||||||
});
|
});
|
||||||
ptrInfo.processOwner(TPtrManager<T>::getPtr(obj));
|
auto ptr = TPtrManager<T>::getPtr(obj);
|
||||||
|
// might be null in case data pointer is not valid
|
||||||
|
if (ptr) {
|
||||||
|
ptrInfo.ownerPtr = ptr;
|
||||||
|
ptrInfo.ownerTypeId = ctx.getPolymorphicHandler(ptr)->getDerivedTypeId();
|
||||||
|
processObserverListPolymorphic(des, ptrInfo, ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Des, typename T, typename Fnc>
|
template<typename Des, typename T, typename Fnc>
|
||||||
@@ -485,17 +487,18 @@ private:
|
|||||||
OwnershipType<PointerOwnershipType::Owner>) const
|
OwnershipType<PointerOwnershipType::Owner>) const
|
||||||
{
|
{
|
||||||
auto ptr = TPtrManager<T>::getPtr(obj);
|
auto ptr = TPtrManager<T>::getPtr(obj);
|
||||||
if (ptr) {
|
if (!ptr) {
|
||||||
fnc(des, *ptr);
|
|
||||||
} else {
|
|
||||||
TPtrManager<T>::create(
|
TPtrManager<T>::create(
|
||||||
obj,
|
obj,
|
||||||
memResource,
|
memResource,
|
||||||
RTTI::template get<typename TPtrManager<T>::TElement>());
|
RTTI::template get<typename TPtrManager<T>::TElement>());
|
||||||
ptr = TPtrManager<T>::getPtr(obj);
|
ptr = TPtrManager<T>::getPtr(obj);
|
||||||
fnc(des, *ptr);
|
|
||||||
}
|
}
|
||||||
ptrInfo.processOwner(ptr);
|
fnc(des, *ptr);
|
||||||
|
ptrInfo.ownerPtr = ptr;
|
||||||
|
ptrInfo.ownerTypeId =
|
||||||
|
RTTI::template get<typename TPtrManager<T>::TElement>();
|
||||||
|
processObserverList(des, ptrInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Des, typename T, typename Fnc>
|
template<typename Des, typename T, typename Fnc>
|
||||||
@@ -507,8 +510,11 @@ private:
|
|||||||
std::true_type,
|
std::true_type,
|
||||||
OwnershipType<PointerOwnershipType::SharedOwner>) const
|
OwnershipType<PointerOwnershipType::SharedOwner>) const
|
||||||
{
|
{
|
||||||
|
const auto& ctx = des.template context<TPolymorphicContext<RTTI>>();
|
||||||
|
const size_t baseTypeId =
|
||||||
|
RTTI::template get<typename TPtrManager<T>::TElement>();
|
||||||
|
size_t deserializedTypeId = 0;
|
||||||
if (!ptrInfo.sharedState) {
|
if (!ptrInfo.sharedState) {
|
||||||
const auto& ctx = des.template context<TPolymorphicContext<RTTI>>();
|
|
||||||
ctx.deserialize(
|
ctx.deserialize(
|
||||||
des,
|
des,
|
||||||
TPtrManager<T>::getPtr(obj),
|
TPtrManager<T>::getPtr(obj),
|
||||||
@@ -522,12 +528,28 @@ private:
|
|||||||
memResource](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
memResource](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||||
TPtrManager<T>::destroyPolymorphic(obj, memResource, handler);
|
TPtrManager<T>::destroyPolymorphic(obj, memResource, handler);
|
||||||
});
|
});
|
||||||
if (!ptrInfo.sharedState)
|
if (!ptrInfo.sharedState) {
|
||||||
TPtrManager<T>::saveToSharedState(
|
TPtrManager<T>::saveToSharedStatePolymorphic(
|
||||||
createAndGetSharedStateObj<T>(ptrInfo), obj);
|
createAndGetSharedStateObj<T>(ptrInfo), obj);
|
||||||
|
}
|
||||||
|
ptrInfo.ownerPtr = TPtrManager<T>::getPtr(obj);
|
||||||
|
ptrInfo.ownerTypeId =
|
||||||
|
ctx.getPolymorphicHandler(TPtrManager<T>::getPtr(obj))
|
||||||
|
->getDerivedTypeId();
|
||||||
|
// since we just deserialized an object, we can skip checking hierarchy
|
||||||
|
// chain by assigning baseType id instead of derived type id
|
||||||
|
deserializedTypeId = baseTypeId;
|
||||||
|
} else {
|
||||||
|
deserializedTypeId = ptrInfo.ownerTypeId;
|
||||||
|
}
|
||||||
|
if (auto hndl =
|
||||||
|
ctx.getPolymorphicHandler(baseTypeId, ptrInfo.sharedState->typeId)) {
|
||||||
|
TPtrManager<T>::loadFromSharedStatePolymorphic(
|
||||||
|
getSharedStateObj<T>(ptrInfo), obj, **hndl);
|
||||||
|
processObserverListPolymorphic(des, ptrInfo, ctx);
|
||||||
|
} else {
|
||||||
|
des.adapter().error(ReaderError::InvalidPointer);
|
||||||
}
|
}
|
||||||
TPtrManager<T>::loadFromSharedState(getSharedStateObj<T>(ptrInfo), obj);
|
|
||||||
ptrInfo.processOwner(TPtrManager<T>::getPtr(obj));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Des, typename T, typename Fnc>
|
template<typename Des, typename T, typename Fnc>
|
||||||
@@ -539,6 +561,8 @@ private:
|
|||||||
std::false_type,
|
std::false_type,
|
||||||
OwnershipType<PointerOwnershipType::SharedOwner>) const
|
OwnershipType<PointerOwnershipType::SharedOwner>) const
|
||||||
{
|
{
|
||||||
|
const size_t baseTypeId =
|
||||||
|
RTTI::template get<typename TPtrManager<T>::TElement>();
|
||||||
if (!ptrInfo.sharedState) {
|
if (!ptrInfo.sharedState) {
|
||||||
auto ptr = TPtrManager<T>::getPtr(obj);
|
auto ptr = TPtrManager<T>::getPtr(obj);
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
@@ -553,9 +577,16 @@ private:
|
|||||||
ptr = TPtrManager<T>::getPtr(obj);
|
ptr = TPtrManager<T>::getPtr(obj);
|
||||||
}
|
}
|
||||||
fnc(des, *ptr);
|
fnc(des, *ptr);
|
||||||
|
ptrInfo.ownerTypeId =
|
||||||
|
RTTI::template get<typename TPtrManager<T>::TElement>();
|
||||||
|
ptrInfo.ownerPtr = TPtrManager<T>::getPtr(obj);
|
||||||
|
}
|
||||||
|
if (baseTypeId == ptrInfo.ownerTypeId) {
|
||||||
|
TPtrManager<T>::loadFromSharedState(getSharedStateObj<T>(ptrInfo), obj);
|
||||||
|
processObserverList(des, ptrInfo);
|
||||||
|
} else {
|
||||||
|
des.adapter().error(ReaderError::InvalidPointer);
|
||||||
}
|
}
|
||||||
TPtrManager<T>::loadFromSharedState(getSharedStateObj<T>(ptrInfo), obj);
|
|
||||||
ptrInfo.processOwner(TPtrManager<T>::getPtr(obj));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Des, typename T, typename Fnc, typename isPolymorph>
|
template<typename Des, typename T, typename Fnc, typename isPolymorph>
|
||||||
@@ -577,17 +608,85 @@ private:
|
|||||||
OwnershipType<PointerOwnershipType::SharedOwner>{});
|
OwnershipType<PointerOwnershipType::SharedOwner>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Des, typename T, typename Fnc, typename isPolymorphic>
|
template<typename Des, typename T, typename Fnc>
|
||||||
void deserializeImpl(MemResourceBase*,
|
void deserializeImpl(MemResourceBase*,
|
||||||
PLCInfoDeserializer& ptrInfo,
|
PLCInfoDeserializer& ptrInfo,
|
||||||
Des&,
|
Des& des,
|
||||||
T& obj,
|
T& obj,
|
||||||
Fnc&&,
|
Fnc&&,
|
||||||
isPolymorphic,
|
std::false_type,
|
||||||
OwnershipType<PointerOwnershipType::Observer>) const
|
OwnershipType<PointerOwnershipType::Observer>) const
|
||||||
{
|
{
|
||||||
ptrInfo.processObserver(
|
auto baseTypeId = RTTI::template get<typename TPtrManager<T>::TElement>();
|
||||||
reinterpret_cast<void*&>(TPtrManager<T>::getPtrRef(obj)));
|
void*(&ptr) = reinterpret_cast<void*&>(TPtrManager<T>::getPtrRef(obj));
|
||||||
|
if (ptrInfo.ownerPtr) {
|
||||||
|
if (ptrInfo.ownerTypeId == baseTypeId) {
|
||||||
|
ptr = ptrInfo.ownerPtr;
|
||||||
|
} else {
|
||||||
|
des.adapter().error(ReaderError::InvalidPointer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ptrInfo.observersList.emplace_back(ObserverRef{ ptr, baseTypeId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Des, typename T, typename Fnc>
|
||||||
|
void deserializeImpl(MemResourceBase*,
|
||||||
|
PLCInfoDeserializer& ptrInfo,
|
||||||
|
Des& des,
|
||||||
|
T& obj,
|
||||||
|
Fnc&&,
|
||||||
|
std::true_type,
|
||||||
|
OwnershipType<PointerOwnershipType::Observer>) const
|
||||||
|
{
|
||||||
|
const auto& ctx = des.template context<TPolymorphicContext<RTTI>>();
|
||||||
|
const size_t baseTypeId =
|
||||||
|
RTTI::template get<typename TPtrManager<T>::TElement>();
|
||||||
|
void*(&ptr) = reinterpret_cast<void*&>(TPtrManager<T>::getPtrRef(obj));
|
||||||
|
if (ptrInfo.ownerPtr) {
|
||||||
|
if (auto hndl =
|
||||||
|
ctx.getPolymorphicHandler(baseTypeId, ptrInfo.ownerTypeId)) {
|
||||||
|
ptr = hndl->get()->fromDerivedToBasePtr(ptrInfo.ownerPtr);
|
||||||
|
} else {
|
||||||
|
des.adapter().error(ReaderError::InvalidPointer);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ptrInfo.observersList.emplace_back(ObserverRef{ ptr, baseTypeId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Des>
|
||||||
|
void processObserverList(Des& des, PLCInfoDeserializer& ptrInfo) const
|
||||||
|
{
|
||||||
|
assert(ptrInfo.ownershipType != PointerOwnershipType::Observer);
|
||||||
|
for (auto& o : ptrInfo.observersList) {
|
||||||
|
if (ptrInfo.ownerTypeId == o.baseTypeId) {
|
||||||
|
o.obj.get() = ptrInfo.ownerPtr;
|
||||||
|
} else {
|
||||||
|
des.adapter().error(ReaderError::InvalidPointer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptrInfo.observersList.clear();
|
||||||
|
ptrInfo.observersList.shrink_to_fit();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Des>
|
||||||
|
void processObserverListPolymorphic(
|
||||||
|
Des& des,
|
||||||
|
PLCInfoDeserializer& ptrInfo,
|
||||||
|
const TPolymorphicContext<RTTI>& ctx) const
|
||||||
|
{
|
||||||
|
assert(ptrInfo.ownershipType != PointerOwnershipType::Observer);
|
||||||
|
for (auto& o : ptrInfo.observersList) {
|
||||||
|
if (auto hndl =
|
||||||
|
ctx.getPolymorphicHandler(o.baseTypeId, ptrInfo.ownerTypeId)) {
|
||||||
|
o.obj.get() = hndl->get()->fromDerivedToBasePtr(ptrInfo.ownerPtr);
|
||||||
|
} else {
|
||||||
|
des.adapter().error(ReaderError::InvalidPointer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ptrInfo.observersList.clear();
|
||||||
|
ptrInfo.observersList.shrink_to_fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -35,8 +35,7 @@ namespace ext {
|
|||||||
// helper type, that contains list of types
|
// helper type, that contains list of types
|
||||||
template<typename...>
|
template<typename...>
|
||||||
struct PolymorphicClassesList
|
struct PolymorphicClassesList
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
// specialize for your base class by deriving from PolymorphicDerivedClasses
|
// specialize for your base class by deriving from PolymorphicDerivedClasses
|
||||||
// with list of derivatives that DIRECTLY inherits from your base class.
|
// with list of derivatives that DIRECTLY inherits from your base class.
|
||||||
@@ -75,10 +74,20 @@ public:
|
|||||||
|
|
||||||
virtual void process(void* ser, void* obj) const = 0;
|
virtual void process(void* ser, void* obj) const = 0;
|
||||||
|
|
||||||
|
virtual void* getRootPtr(const void* obj) const = 0;
|
||||||
|
|
||||||
|
virtual void* fromDerivedToBasePtr(void* obj) const = 0;
|
||||||
|
|
||||||
|
virtual size_t getDerivedTypeId() const = 0;
|
||||||
|
|
||||||
virtual ~PolymorphicHandlerBase() = default;
|
virtual ~PolymorphicHandlerBase() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename RTTI, typename TSerializer, typename TBase, typename TDerived>
|
template<typename RTTI,
|
||||||
|
typename TSerializer,
|
||||||
|
typename TRoot,
|
||||||
|
typename TBase,
|
||||||
|
typename TDerived>
|
||||||
class PolymorphicHandler : public PolymorphicHandlerBase
|
class PolymorphicHandler : public PolymorphicHandlerBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -98,6 +107,19 @@ public:
|
|||||||
static_cast<TSerializer*>(ser)->object(*fromBase(obj));
|
static_cast<TSerializer*>(ser)->object(*fromBase(obj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void* getRootPtr(const void* obj) const final
|
||||||
|
{
|
||||||
|
return RTTI::template cast<TBase, TRoot>(
|
||||||
|
static_cast<TBase*>(const_cast<void*>(obj)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void* fromDerivedToBasePtr(void* obj) const final { return toBase(obj); }
|
||||||
|
|
||||||
|
size_t getDerivedTypeId() const final
|
||||||
|
{
|
||||||
|
return RTTI::template get<TDerived>();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TDerived* fromBase(void* obj) const
|
TDerived* fromBase(void* obj) const
|
||||||
{
|
{
|
||||||
@@ -110,6 +132,41 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Even though we don't serialize/deserialize abstract classes
|
||||||
|
// object might still be accessed through abstract class, hence we need this
|
||||||
|
// for type information
|
||||||
|
template<typename RTTI, typename TRoot, typename TBase, typename TDerived>
|
||||||
|
class AbstractPolymorphicHandler : public PolymorphicHandlerBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void* create(const pointer_utils::PolyAllocWithTypeId&) const
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy(const pointer_utils::PolyAllocWithTypeId&, void*) const
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
void process(void*, void*) const { assert(false); }
|
||||||
|
|
||||||
|
void* getRootPtr(const void*) const
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* fromDerivedToBasePtr(void*) const final
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getDerivedTypeId() const { return RTTI::template get<TDerived>(); };
|
||||||
|
};
|
||||||
|
|
||||||
template<typename RTTI>
|
template<typename RTTI>
|
||||||
class PolymorphicContext
|
class PolymorphicContext
|
||||||
{
|
{
|
||||||
@@ -138,18 +195,20 @@ private:
|
|||||||
template<typename TSerializer,
|
template<typename TSerializer,
|
||||||
template<typename>
|
template<typename>
|
||||||
class THierarchy,
|
class THierarchy,
|
||||||
|
typename TRoot,
|
||||||
typename TBase,
|
typename TBase,
|
||||||
typename TDerived>
|
typename TDerived>
|
||||||
void add()
|
void add()
|
||||||
{
|
{
|
||||||
addToMap<TSerializer, TBase, TDerived>(std::is_abstract<TDerived>{});
|
addToMap<TSerializer, TRoot, TBase, TDerived>(std::is_abstract<TDerived>{});
|
||||||
addChilds<TSerializer, THierarchy, TBase, TDerived>(
|
addChilds<TSerializer, THierarchy, TRoot, TBase, TDerived>(
|
||||||
typename THierarchy<TDerived>::Childs{});
|
typename THierarchy<TDerived>::Childs{});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TSerializer,
|
template<typename TSerializer,
|
||||||
template<typename>
|
template<typename>
|
||||||
class THierarchy,
|
class THierarchy,
|
||||||
|
typename TRoot,
|
||||||
typename TBase,
|
typename TBase,
|
||||||
typename TDerived,
|
typename TDerived,
|
||||||
typename T1,
|
typename T1,
|
||||||
@@ -159,26 +218,30 @@ private:
|
|||||||
static_assert(std::is_base_of<TDerived, T1>::value,
|
static_assert(std::is_base_of<TDerived, T1>::value,
|
||||||
"PolymorphicBaseClass<TBase> must derive a list of derived "
|
"PolymorphicBaseClass<TBase> must derive a list of derived "
|
||||||
"classes from TBase.");
|
"classes from TBase.");
|
||||||
add<TSerializer, THierarchy, TBase, T1>();
|
add<TSerializer, THierarchy, TRoot, TBase, T1>();
|
||||||
addChilds<TSerializer, THierarchy, TBase, TDerived>(
|
addChilds<TSerializer, THierarchy, TRoot, TBase, TDerived>(
|
||||||
PolymorphicClassesList<Tn...>{});
|
PolymorphicClassesList<Tn...>{});
|
||||||
// iterate through derived class hierarchy as well
|
add<TSerializer, THierarchy, TRoot, T1, T1>();
|
||||||
add<TSerializer, THierarchy, T1, T1>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TSerializer,
|
template<typename TSerializer,
|
||||||
template<typename>
|
template<typename>
|
||||||
class THierarchy,
|
class THierarchy,
|
||||||
|
typename TRoot,
|
||||||
typename TBase,
|
typename TBase,
|
||||||
typename TDerived>
|
typename TDerived>
|
||||||
void addChilds(PolymorphicClassesList<>)
|
void addChilds(PolymorphicClassesList<>)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TSerializer, typename TBase, typename TDerived>
|
template<typename TSerializer,
|
||||||
|
typename TRoot,
|
||||||
|
typename TBase,
|
||||||
|
typename TDerived>
|
||||||
void addToMap(std::false_type)
|
void addToMap(std::false_type)
|
||||||
{
|
{
|
||||||
using THandler = PolymorphicHandler<RTTI, TSerializer, TBase, TDerived>;
|
using THandler =
|
||||||
|
PolymorphicHandler<RTTI, TSerializer, TRoot, TBase, TDerived>;
|
||||||
BaseToDerivedKey key{ RTTI::template get<TBase>(),
|
BaseToDerivedKey key{ RTTI::template get<TBase>(),
|
||||||
RTTI::template get<TDerived>() };
|
RTTI::template get<TDerived>() };
|
||||||
pointer_utils::StdPolyAlloc<THandler> alloc{ _memResource };
|
pointer_utils::StdPolyAlloc<THandler> alloc{ _memResource };
|
||||||
@@ -204,10 +267,25 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TSerializer, typename TBase, typename TDerived>
|
template<typename TSerializer,
|
||||||
|
typename TRoot,
|
||||||
|
typename TBase,
|
||||||
|
typename TDerived>
|
||||||
void addToMap(std::true_type)
|
void addToMap(std::true_type)
|
||||||
{
|
{
|
||||||
// cannot add abstract class
|
using THandler = AbstractPolymorphicHandler<RTTI, TRoot, TBase, TDerived>;
|
||||||
|
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{},
|
||||||
|
[alloc](THandler* data) mutable {
|
||||||
|
data->~THandler();
|
||||||
|
alloc.deallocate(data, 1);
|
||||||
|
},
|
||||||
|
alloc);
|
||||||
|
_baseToDerivedMap.emplace(key, std::move(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
MemResourceBase* _memResource;
|
MemResourceBase* _memResource;
|
||||||
@@ -270,7 +348,7 @@ public:
|
|||||||
typename... Tn>
|
typename... Tn>
|
||||||
void registerBasesList(PolymorphicClassesList<T1, Tn...>)
|
void registerBasesList(PolymorphicClassesList<T1, Tn...>)
|
||||||
{
|
{
|
||||||
add<TSerializer, THierarchy, T1, T1>();
|
add<TSerializer, THierarchy, T1, T1, T1>();
|
||||||
registerBasesList<TSerializer, THierarchy>(PolymorphicClassesList<Tn...>{});
|
registerBasesList<TSerializer, THierarchy>(PolymorphicClassesList<Tn...>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,18 +357,6 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// optional method, in case you want to construct base class hierarchy your
|
|
||||||
// self
|
|
||||||
template<typename TSerializer, typename TBase, typename TDerived>
|
|
||||||
void registerSingleBaseBranch()
|
|
||||||
{
|
|
||||||
static_assert(std::is_base_of<TBase, TDerived>::value,
|
|
||||||
"TDerived must be derived from TBase");
|
|
||||||
static_assert(!std::is_abstract<TDerived>::value,
|
|
||||||
"TDerived cannot be abstract");
|
|
||||||
addToMap<TSerializer, TBase, TDerived>(std::false_type{});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Serializer, typename TBase>
|
template<typename Serializer, typename TBase>
|
||||||
void serialize(Serializer& ser, TBase& obj) const
|
void serialize(Serializer& ser, TBase& obj) const
|
||||||
{
|
{
|
||||||
@@ -339,7 +405,7 @@ public:
|
|||||||
// if object is null or different type, create new and assign it
|
// if object is null or different type, create new and assign it
|
||||||
if (obj == nullptr || RTTI::template get<TBase>(*obj) != derivedHash) {
|
if (obj == nullptr || RTTI::template get<TBase>(*obj) != derivedHash) {
|
||||||
if (obj) {
|
if (obj) {
|
||||||
destroyFnc(getPolymorphicHandler(*obj));
|
destroyFnc(getPolymorphicHandler(obj));
|
||||||
}
|
}
|
||||||
obj = createFnc(handler);
|
obj = createFnc(handler);
|
||||||
}
|
}
|
||||||
@@ -350,12 +416,33 @@ public:
|
|||||||
|
|
||||||
template<typename TBase>
|
template<typename TBase>
|
||||||
const std::shared_ptr<PolymorphicHandlerBase>& getPolymorphicHandler(
|
const std::shared_ptr<PolymorphicHandlerBase>& getPolymorphicHandler(
|
||||||
TBase& obj) const
|
TBase* obj) const
|
||||||
{
|
{
|
||||||
auto deleteHandlerIt = _baseToDerivedMap.find(BaseToDerivedKey{
|
auto it = _baseToDerivedMap.find(BaseToDerivedKey{
|
||||||
RTTI::template get<TBase>(), RTTI::template get<TBase>(obj) });
|
RTTI::template get<TBase>(), RTTI::template get<TBase>(*obj) });
|
||||||
assert(deleteHandlerIt != _baseToDerivedMap.end());
|
assert(it != _baseToDerivedMap.end());
|
||||||
return deleteHandlerIt->second;
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TBase>
|
||||||
|
const std::shared_ptr<PolymorphicHandlerBase>& getPolymorphicHandler() const
|
||||||
|
{
|
||||||
|
auto it = _baseToDerivedMap.find(BaseToDerivedKey{
|
||||||
|
RTTI::template get<TBase>(), RTTI::template get<TBase>() });
|
||||||
|
assert(it != _baseToDerivedMap.end());
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::shared_ptr<PolymorphicHandlerBase>* getPolymorphicHandler(
|
||||||
|
size_t baseTypeId,
|
||||||
|
size_t derivedTypeId) const
|
||||||
|
{
|
||||||
|
auto it =
|
||||||
|
_baseToDerivedMap.find(BaseToDerivedKey{ baseTypeId, derivedTypeId });
|
||||||
|
if (it == _baseToDerivedMap.end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &it->second;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -32,14 +32,12 @@ namespace traits {
|
|||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
struct ContainerTraits<std::array<T, N>>
|
struct ContainerTraits<std::array<T, N>>
|
||||||
: public StdContainer<std::array<T, N>, false, true>
|
: public StdContainer<std::array<T, N>, false, true>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
struct BufferAdapterTraits<std::array<T, N>>
|
struct BufferAdapterTraits<std::array<T, N>>
|
||||||
: public StdContainerForBufferAdapter<std::array<T, N>>
|
: public StdContainerForBufferAdapter<std::array<T, N>>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
#ifndef BITSERY_TRAITS_CORE_STD_DEFAULTS_H
|
#ifndef BITSERY_TRAITS_CORE_STD_DEFAULTS_H
|
||||||
#define BITSERY_TRAITS_CORE_STD_DEFAULTS_H
|
#define BITSERY_TRAITS_CORE_STD_DEFAULTS_H
|
||||||
|
|
||||||
|
#include "../../bitsery.h"
|
||||||
#include "../../details/serialization_common.h"
|
#include "../../details/serialization_common.h"
|
||||||
#include "traits.h"
|
#include "traits.h"
|
||||||
|
|
||||||
@@ -103,8 +104,11 @@ struct StdContainerForBufferAdapter<T, true>
|
|||||||
static_cast<size_t>(static_cast<double>(container.size()) * 1.5) + 128;
|
static_cast<size_t>(static_cast<double>(container.size()) * 1.5) + 128;
|
||||||
// make data cache friendly
|
// make data cache friendly
|
||||||
newSize -= newSize % 64; // 64 is cache line size
|
newSize -= newSize % 64; // 64 is cache line size
|
||||||
container.resize(
|
auto resize =
|
||||||
(std::max)(newSize > minSize ? newSize : minSize, container.capacity()));
|
(std::max)(newSize > minSize ? newSize : minSize, container.capacity());
|
||||||
|
BITSERY_ASSUME(resize >= container.size());
|
||||||
|
BITSERY_ASSUME(resize >= container.capacity());
|
||||||
|
container.resize(resize);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,7 @@ namespace traits {
|
|||||||
template<typename T, typename Allocator>
|
template<typename T, typename Allocator>
|
||||||
struct ContainerTraits<std::deque<T, Allocator>>
|
struct ContainerTraits<std::deque<T, Allocator>>
|
||||||
: public StdContainer<std::deque<T, Allocator>, true, false>
|
: public StdContainer<std::deque<T, Allocator>, true, false>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,7 @@ namespace traits {
|
|||||||
template<typename T, typename Allocator>
|
template<typename T, typename Allocator>
|
||||||
struct ContainerTraits<std::list<T, Allocator>>
|
struct ContainerTraits<std::list<T, Allocator>>
|
||||||
: public StdContainer<std::list<T, Allocator>, true, false>
|
: public StdContainer<std::list<T, Allocator>, true, false>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,7 @@ namespace traits {
|
|||||||
template<typename CharT, typename Traits, typename Allocator>
|
template<typename CharT, typename Traits, typename Allocator>
|
||||||
struct ContainerTraits<std::basic_string<CharT, Traits, Allocator>>
|
struct ContainerTraits<std::basic_string<CharT, Traits, Allocator>>
|
||||||
: public StdContainer<std::basic_string<CharT, Traits, Allocator>, true, true>
|
: public StdContainer<std::basic_string<CharT, Traits, Allocator>, true, true>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename CharT, typename Traits, typename Allocator>
|
template<typename CharT, typename Traits, typename Allocator>
|
||||||
struct TextTraits<std::basic_string<CharT, Traits, Allocator>>
|
struct TextTraits<std::basic_string<CharT, Traits, Allocator>>
|
||||||
@@ -72,8 +71,7 @@ template<typename CharT, typename Traits, typename Allocator>
|
|||||||
struct BufferAdapterTraits<std::basic_string<CharT, Traits, Allocator>>
|
struct BufferAdapterTraits<std::basic_string<CharT, Traits, Allocator>>
|
||||||
: public StdContainerForBufferAdapter<
|
: public StdContainerForBufferAdapter<
|
||||||
std::basic_string<CharT, Traits, Allocator>>
|
std::basic_string<CharT, Traits, Allocator>>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,21 +32,18 @@ namespace traits {
|
|||||||
template<typename T, typename Allocator>
|
template<typename T, typename Allocator>
|
||||||
struct ContainerTraits<std::vector<T, Allocator>>
|
struct ContainerTraits<std::vector<T, Allocator>>
|
||||||
: public StdContainer<std::vector<T, Allocator>, true, true>
|
: public StdContainer<std::vector<T, Allocator>, true, true>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
// bool vector is not contiguous, do not copy it directly to buffer
|
// bool vector is not contiguous, do not copy it directly to buffer
|
||||||
template<typename Allocator>
|
template<typename Allocator>
|
||||||
struct ContainerTraits<std::vector<bool, Allocator>>
|
struct ContainerTraits<std::vector<bool, Allocator>>
|
||||||
: public StdContainer<std::vector<bool, Allocator>, true, false>
|
: public StdContainer<std::vector<bool, Allocator>, true, false>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename T, typename Allocator>
|
template<typename T, typename Allocator>
|
||||||
struct BufferAdapterTraits<std::vector<T, Allocator>>
|
struct BufferAdapterTraits<std::vector<T, Allocator>>
|
||||||
: public StdContainerForBufferAdapter<std::vector<T, Allocator>>
|
: public StdContainerForBufferAdapter<std::vector<T, Allocator>>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
# 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`.
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
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;
|
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
#SOFTWARE.
|
#SOFTWARE.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.11)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(bitsery_tests
|
project(bitsery_tests
|
||||||
LANGUAGES CXX)
|
LANGUAGES CXX)
|
||||||
|
|
||||||
|
|||||||
@@ -306,8 +306,7 @@ using AdapterInputTypes =
|
|||||||
|
|
||||||
template<typename TConfig>
|
template<typename TConfig>
|
||||||
class InputAll : public AdapterConfig<TConfig>
|
class InputAll : public AdapterConfig<TConfig>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
TYPED_TEST_SUITE(InputAll, AdapterInputTypes, );
|
TYPED_TEST_SUITE(InputAll, AdapterInputTypes, );
|
||||||
|
|
||||||
@@ -476,8 +475,7 @@ using AdapterOutputTypes =
|
|||||||
|
|
||||||
template<typename TConfig>
|
template<typename TConfig>
|
||||||
class OutputAll : public AdapterConfig<TConfig>
|
class OutputAll : public AdapterConfig<TConfig>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
TYPED_TEST_SUITE(OutputAll, AdapterOutputTypes, );
|
TYPED_TEST_SUITE(OutputAll, AdapterOutputTypes, );
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include <bitsery/brief_syntax/list.h>
|
#include <bitsery/brief_syntax/list.h>
|
||||||
#include <bitsery/brief_syntax/map.h>
|
#include <bitsery/brief_syntax/map.h>
|
||||||
#include <bitsery/brief_syntax/memory.h>
|
#include <bitsery/brief_syntax/memory.h>
|
||||||
|
|
||||||
#include <bitsery/brief_syntax/queue.h>
|
#include <bitsery/brief_syntax/queue.h>
|
||||||
#include <bitsery/brief_syntax/set.h>
|
#include <bitsery/brief_syntax/set.h>
|
||||||
#include <bitsery/brief_syntax/stack.h>
|
#include <bitsery/brief_syntax/stack.h>
|
||||||
@@ -37,8 +38,12 @@
|
|||||||
#include <bitsery/brief_syntax/unordered_set.h>
|
#include <bitsery/brief_syntax/unordered_set.h>
|
||||||
#include <bitsery/brief_syntax/vector.h>
|
#include <bitsery/brief_syntax/vector.h>
|
||||||
#if __cplusplus > 201402L
|
#if __cplusplus > 201402L
|
||||||
|
#include <bitsery/brief_syntax/optional.h>
|
||||||
#include <bitsery/brief_syntax/tuple.h>
|
#include <bitsery/brief_syntax/tuple.h>
|
||||||
#include <bitsery/brief_syntax/variant.h>
|
#include <bitsery/brief_syntax/variant.h>
|
||||||
|
#if __cplusplus > 202002L
|
||||||
|
#include <bitsery/brief_syntax/bitset.h>
|
||||||
|
#endif
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
#pragma message( \
|
#pragma message( \
|
||||||
"C++17 and /Zc:__cplusplus option is required to enable std::tuple and std::variant brief syntax tests")
|
"C++17 and /Zc:__cplusplus option is required to enable std::tuple and std::variant brief syntax tests")
|
||||||
@@ -490,6 +495,22 @@ TEST(BriefSyntax, StdVariant)
|
|||||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(BriefSyntax, StdOptional)
|
||||||
|
{
|
||||||
|
std::optional<uint32_t> opt{ 54654 };
|
||||||
|
EXPECT_TRUE(procBriefSyntax(opt) == opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if __cplusplus > 202002L
|
||||||
|
|
||||||
|
TEST(BriefSyntax, StdBitset)
|
||||||
|
{
|
||||||
|
std::bitset<17> bits{ 0b10101010101010101 };
|
||||||
|
EXPECT_TRUE(procBriefSyntax(bits) == bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
TEST(BriefSyntax, NestedTypes)
|
TEST(BriefSyntax, NestedTypes)
|
||||||
|
|||||||
@@ -320,8 +320,7 @@ namespace ext {
|
|||||||
template<>
|
template<>
|
||||||
struct PolymorphicBaseClass<PolymorphicNDCBase>
|
struct PolymorphicBaseClass<PolymorphicNDCBase>
|
||||||
: PolymorphicDerivedClasses<PolymorphicNDC1, PolymorphicNDC2>
|
: PolymorphicDerivedClasses<PolymorphicNDC1, PolymorphicNDC2>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -214,8 +214,7 @@ TYPED_TEST(SerializeContainerFixedSizeArithmeticTypes, ArithmeticValues)
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class SerializeContainerFixedSizeCompositeTypes
|
class SerializeContainerFixedSizeCompositeTypes
|
||||||
: public SerializeContainerFixedSizeArithmeticTypes<T>
|
: public SerializeContainerFixedSizeArithmeticTypes<T>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
using StaticContainersWithCompositeTypes =
|
using StaticContainersWithCompositeTypes =
|
||||||
::testing::Types<std::array<MyStruct1, 4>, MyStruct1[4]>;
|
::testing::Types<std::array<MyStruct1, 4>, MyStruct1[4]>;
|
||||||
|
|||||||
@@ -356,13 +356,11 @@ struct DerivedMemberSerialize : public BaseNonMemberSerialize
|
|||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<>
|
template<>
|
||||||
struct SelectSerializeFnc<DerivedPrivateBase> : UseNonMemberFnc
|
struct SelectSerializeFnc<DerivedPrivateBase> : UseNonMemberFnc
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct SelectSerializeFnc<DerivedMemberSerialize> : UseMemberFnc
|
struct SelectSerializeFnc<DerivedMemberSerialize> : UseMemberFnc
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(
|
TEST(
|
||||||
|
|||||||
@@ -458,6 +458,23 @@ TEST_F(SerializeExtensionPointerDeserialization, PointerObserver)
|
|||||||
EXPECT_THAT(pr3, Eq(&r3));
|
EXPECT_THAT(pr3, Eq(&r3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SerializeExtensionPointerDeserialization,
|
||||||
|
PointerObserverAndOwnerTypeMustBeTheSame)
|
||||||
|
{
|
||||||
|
// serialize as if we have two same objects
|
||||||
|
auto& ser = createSerializer();
|
||||||
|
ser.ext2b(d1, ReferencedByPointer{});
|
||||||
|
ser.ext2b(pd1, PointerObserver{});
|
||||||
|
auto& des = createDeserializer();
|
||||||
|
// but actual implementation expects distinct objects
|
||||||
|
des.ext2b(r1, ReferencedByPointer{});
|
||||||
|
des.ext4b(pr2, PointerObserver{});
|
||||||
|
|
||||||
|
EXPECT_THAT(isPointerContextValid(), Eq(true));
|
||||||
|
EXPECT_THAT(sctx1.des->adapter().error(),
|
||||||
|
Eq(bitsery::ReaderError::InvalidPointer));
|
||||||
|
}
|
||||||
|
|
||||||
struct Test1Data
|
struct Test1Data
|
||||||
{
|
{
|
||||||
std::vector<MyStruct1> vdata;
|
std::vector<MyStruct1> vdata;
|
||||||
|
|||||||
@@ -147,21 +147,17 @@ namespace ext {
|
|||||||
template<>
|
template<>
|
||||||
struct PolymorphicBaseClass<Base>
|
struct PolymorphicBaseClass<Base>
|
||||||
: PolymorphicDerivedClasses<Derived1, Derived2>
|
: PolymorphicDerivedClasses<Derived1, Derived2>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
// this is commented on purpose, to test scenario when base class is registered
|
template<>
|
||||||
// (Base) but using instance of Derived1 which is not registered as base
|
struct PolymorphicBaseClass<Derived1>
|
||||||
// template<>
|
: PolymorphicDerivedClasses<MultipleVirtualInheritance>
|
||||||
// struct PolymorphicBaseClass<Derived1> :
|
{};
|
||||||
// PolymorphicDerivedClasses<MultipleVirtualInheritance> {
|
|
||||||
// };
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct PolymorphicBaseClass<Derived2>
|
struct PolymorphicBaseClass<Derived2>
|
||||||
: PolymorphicDerivedClasses<MultipleVirtualInheritance>
|
: PolymorphicDerivedClasses<MultipleVirtualInheritance>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,3 +369,62 @@ TEST_F(SerializeExtensionPointerPolymorphicTypes,
|
|||||||
EXPECT_THAT(sctx.des->adapter().error(),
|
EXPECT_THAT(sctx.des->adapter().error(),
|
||||||
Eq(bitsery::ReaderError::InvalidPointer));
|
Eq(bitsery::ReaderError::InvalidPointer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SerializeExtensionPointerPolymorphicTypes,
|
||||||
|
SameObjectIsCorrectlyIdentifiedEvenIfObserverHasDifferentBase)
|
||||||
|
{
|
||||||
|
|
||||||
|
MultipleVirtualInheritance md;
|
||||||
|
Derived2* derivedData = &md;
|
||||||
|
EXPECT_THAT(static_cast<void*>(&md),
|
||||||
|
::testing::Ne(static_cast<void*>(derivedData)));
|
||||||
|
|
||||||
|
auto& ser = createSerializer();
|
||||||
|
ser.ext(md, ReferencedByPointer{});
|
||||||
|
ser.ext(derivedData, PointerObserver{});
|
||||||
|
EXPECT_THAT(isPointerContextValid(), Eq(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SerializeExtensionPointerPolymorphicTypes,
|
||||||
|
CheckIfOwnerTypeIsAssignableToObserverType)
|
||||||
|
{
|
||||||
|
|
||||||
|
MultipleVirtualInheritance md;
|
||||||
|
Derived2* derivedData = &md;
|
||||||
|
|
||||||
|
auto& ser = createSerializer();
|
||||||
|
ser.ext(&md, PointerOwner{});
|
||||||
|
ser.ext(derivedData, PointerObserver{});
|
||||||
|
|
||||||
|
MultipleVirtualInheritance* res1 = nullptr;
|
||||||
|
NoRelationshipSpecifiedDerived* res2 = nullptr;
|
||||||
|
auto& des = createDeserializer();
|
||||||
|
des.ext(res1, PointerOwner{});
|
||||||
|
des.ext(res2, PointerObserver{});
|
||||||
|
|
||||||
|
EXPECT_THAT(res1, ::testing::NotNull());
|
||||||
|
EXPECT_THAT(res2, ::testing::IsNull());
|
||||||
|
EXPECT_THAT(sctx.des->adapter().error(),
|
||||||
|
Eq(bitsery::ReaderError::InvalidPointer));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SerializeExtensionPointerPolymorphicTypes, OwnerIsCastObserverType)
|
||||||
|
{
|
||||||
|
|
||||||
|
MultipleVirtualInheritance md{ 1, 2, 3, 4 };
|
||||||
|
Derived2* derivedData = &md;
|
||||||
|
|
||||||
|
auto& ser = createSerializer();
|
||||||
|
ser.ext(&md, PointerOwner{});
|
||||||
|
ser.ext(derivedData, PointerObserver{});
|
||||||
|
|
||||||
|
MultipleVirtualInheritance* res1 = nullptr;
|
||||||
|
Base* res2 = nullptr;
|
||||||
|
auto& des = createDeserializer();
|
||||||
|
des.ext(res1, PointerOwner{});
|
||||||
|
des.ext(res2, PointerObserver{});
|
||||||
|
|
||||||
|
EXPECT_THAT(res1, ::testing::NotNull());
|
||||||
|
EXPECT_THAT(res2, ::testing::NotNull());
|
||||||
|
EXPECT_THAT(res2->x, Eq(1));
|
||||||
|
}
|
||||||
|
|||||||
@@ -152,14 +152,12 @@ namespace ext {
|
|||||||
template<>
|
template<>
|
||||||
struct PolymorphicBaseClass<Base>
|
struct PolymorphicBaseClass<Base>
|
||||||
: PolymorphicDerivedClasses<Derived1, Derived2>
|
: PolymorphicDerivedClasses<Derived1, Derived2>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct PolymorphicBaseClass<PolyPtrWithPolyPtrBase>
|
struct PolymorphicBaseClass<PolyPtrWithPolyPtrBase>
|
||||||
: PolymorphicDerivedClasses<DerivedPolyPtrWithPolyPtr>
|
: PolymorphicDerivedClasses<DerivedPolyPtrWithPolyPtr>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@
|
|||||||
#include <bitsery/ext/inheritance.h>
|
#include <bitsery/ext/inheritance.h>
|
||||||
#include <bitsery/ext/pointer.h>
|
#include <bitsery/ext/pointer.h>
|
||||||
#include <bitsery/ext/std_smart_ptr.h>
|
#include <bitsery/ext/std_smart_ptr.h>
|
||||||
|
#include <bitsery/traits/string.h>
|
||||||
|
#include <bitsery/traits/vector.h>
|
||||||
|
|
||||||
#include "serialization_test_utils.h"
|
#include "serialization_test_utils.h"
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
@@ -77,6 +79,27 @@ serialize(S& s, Derived& o)
|
|||||||
s.value1b(o.y);
|
s.value1b(o.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DerivedSibling : virtual Base
|
||||||
|
{
|
||||||
|
uint32_t y{};
|
||||||
|
|
||||||
|
DerivedSibling() = default;
|
||||||
|
|
||||||
|
DerivedSibling(uint8_t x_, uint32_t y_)
|
||||||
|
{
|
||||||
|
x = x_;
|
||||||
|
y = y_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename S>
|
||||||
|
void
|
||||||
|
serialize(S& s, DerivedSibling& o)
|
||||||
|
{
|
||||||
|
s.ext(o, VirtualBaseClass<Base>{});
|
||||||
|
s.value4b(o.y);
|
||||||
|
}
|
||||||
|
|
||||||
struct MoreDerived : Derived
|
struct MoreDerived : Derived
|
||||||
{
|
{
|
||||||
uint8_t z{};
|
uint8_t z{};
|
||||||
@@ -106,13 +129,11 @@ namespace ext {
|
|||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct PolymorphicBaseClass<Base> : PolymorphicDerivedClasses<Derived>
|
struct PolymorphicBaseClass<Base> : PolymorphicDerivedClasses<Derived>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct PolymorphicBaseClass<Derived> : PolymorphicDerivedClasses<MoreDerived>
|
struct PolymorphicBaseClass<Derived> : PolymorphicDerivedClasses<MoreDerived>
|
||||||
{
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -743,6 +764,103 @@ TEST_F(SerializeExtensionStdSmartSharedPtr,
|
|||||||
EXPECT_THAT(baseRes1.use_count(), Eq(0));
|
EXPECT_THAT(baseRes1.use_count(), Eq(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct MightMatchVecLayout
|
||||||
|
{
|
||||||
|
size_t begin;
|
||||||
|
size_t end;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename S>
|
||||||
|
void
|
||||||
|
serialize(S& s, MightMatchVecLayout& o)
|
||||||
|
{
|
||||||
|
s.template value<sizeof(size_t)>(o.begin);
|
||||||
|
s.template value<sizeof(size_t)>(o.end);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SerializeExtensionStdSmartSharedPtr,
|
||||||
|
NonPolymorphicObservedPointerMustMatchActuallyDeserializedObjectType)
|
||||||
|
{
|
||||||
|
std::shared_ptr<std::vector<uint8_t>> baseData1{ new std::vector<uint8_t>{
|
||||||
|
'a', 'b', 'c' } };
|
||||||
|
std::shared_ptr<MightMatchVecLayout> baseData2{ new MightMatchVecLayout{
|
||||||
|
1, 2 } };
|
||||||
|
auto& ser = createSerializer();
|
||||||
|
ser.ext(baseData1, StdSmartPtr{}, [](auto& ser, std::vector<uint8_t>& o) {
|
||||||
|
ser.container1b(o, 100);
|
||||||
|
});
|
||||||
|
ser.ext(baseData2, StdSmartPtr{});
|
||||||
|
// hack a buffer, so that during deserialization we would point to already
|
||||||
|
// deserialized object
|
||||||
|
sctx.buf[5] = 0x01;
|
||||||
|
|
||||||
|
std::shared_ptr<std::vector<uint8_t>> baseRes1{};
|
||||||
|
std::shared_ptr<MightMatchVecLayout> baseRes2{};
|
||||||
|
auto& des = createDeserializer();
|
||||||
|
des.ext(baseRes1, StdSmartPtr{}, [](auto& ser, std::vector<uint8_t>& o) {
|
||||||
|
ser.container1b(o, 100);
|
||||||
|
});
|
||||||
|
// if we would blindly trust the input (that the object is already
|
||||||
|
// deserialized), we would end up
|
||||||
|
// using memory of that object. In this case, we will get internal
|
||||||
|
// representation of std::vector.
|
||||||
|
// If this object is available to attacker, he'll be able to see leaked
|
||||||
|
// address of that object,
|
||||||
|
// allowing him to bypass ASLR.
|
||||||
|
des.ext(baseRes2, StdSmartPtr{});
|
||||||
|
|
||||||
|
EXPECT_THAT(baseRes2.get(), ::testing::IsNull());
|
||||||
|
auto err = des.adapter().error();
|
||||||
|
EXPECT_THAT(err, Eq(bitsery::ReaderError::InvalidPointer));
|
||||||
|
EXPECT_TRUE(isPointerContextValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(
|
||||||
|
SerializeExtensionStdSmartSharedPtr,
|
||||||
|
PolymorphicObservedPointerMustBeInInheritanceChainOfActuallyDeserializedObjectType1)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Base> baseData1{ new MoreDerived{ 3, 7, 10 } };
|
||||||
|
std::shared_ptr<Base> baseData2{};
|
||||||
|
baseData2 = baseData1;
|
||||||
|
auto& ser = createSerializer();
|
||||||
|
ser.ext(baseData1, StdSmartPtr{});
|
||||||
|
ser.ext(baseData2, StdSmartPtr{});
|
||||||
|
|
||||||
|
std::shared_ptr<Base> baseRes1{};
|
||||||
|
std::shared_ptr<Derived> baseRes2{};
|
||||||
|
auto& des = createDeserializer();
|
||||||
|
des.ext(baseRes1, StdSmartPtr{});
|
||||||
|
des.ext(baseRes2, StdSmartPtr{});
|
||||||
|
|
||||||
|
EXPECT_THAT(baseRes2.get(), ::testing::NotNull());
|
||||||
|
auto err = des.adapter().error();
|
||||||
|
EXPECT_THAT(err, Eq(bitsery::ReaderError::NoError));
|
||||||
|
EXPECT_TRUE(isPointerContextValid());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(
|
||||||
|
SerializeExtensionStdSmartSharedPtr,
|
||||||
|
PolymorphicObservedPointerMustBeInInheritanceChainOfActuallyDeserializedObjectType2)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Base> baseData1{ new MoreDerived{ 3, 7, 10 } };
|
||||||
|
std::shared_ptr<Base> baseData2{};
|
||||||
|
baseData2 = baseData1;
|
||||||
|
auto& ser = createSerializer();
|
||||||
|
ser.ext(baseData1, StdSmartPtr{});
|
||||||
|
ser.ext(baseData2, StdSmartPtr{});
|
||||||
|
|
||||||
|
std::shared_ptr<Base> baseRes1{};
|
||||||
|
std::shared_ptr<DerivedSibling> baseRes2{};
|
||||||
|
auto& des = createDeserializer();
|
||||||
|
des.ext(baseRes1, StdSmartPtr{});
|
||||||
|
des.ext(baseRes2, StdSmartPtr{});
|
||||||
|
|
||||||
|
EXPECT_THAT(baseRes2.get(), ::testing::IsNull());
|
||||||
|
auto err = des.adapter().error();
|
||||||
|
EXPECT_THAT(err, Eq(bitsery::ReaderError::InvalidPointer));
|
||||||
|
EXPECT_TRUE(isPointerContextValid());
|
||||||
|
}
|
||||||
|
|
||||||
struct TestSharedFromThis
|
struct TestSharedFromThis
|
||||||
: public std::enable_shared_from_this<TestSharedFromThis>
|
: public std::enable_shared_from_this<TestSharedFromThis>
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user