19 Commits

Author SHA1 Message Date
Mindaugas Vinkelis
9bebfd4911 prepare for 5.2.5 2025-10-08 21:21:38 +03:00
Mindaugas Vinkelis
5e7ecede9b cast from polymorphic owner pointer-like type to observer during assignment 2025-10-08 20:36:15 +03:00
Mindaugas Vinkelis
ff841d63f6 check type information before assigning to observer pointer 2025-10-08 13:13:20 +03:00
Mindaugas Vinkelis
66d16516e2 Fix shared polymorphic poiner like type serialization/deserialization 2025-10-02 14:20:33 +03:00
Mindaugas Vinkelis
7ea1da0d48 clang-format using ./format.sh 2025-09-09 17:38:23 +03:00
Jules
8bda82576e Fix spelling error of "likely" 2025-02-09 15:21:02 +02:00
Mindaugas Vinkelis
ee992d8b57 changelog update for 5.2.4 2024-07-29 22:34:06 +03:00
anton-kl
4dcdd594da Fix typo in a comment 2024-07-21 11:00:53 +03:00
Pol Marcet Sardà
b714459a2b Implement brief syntax for optional and bitset 2024-07-21 11:00:13 +03:00
Pol Marcet Sardà
be2f295310 Discourage inlining the resize case, as that should happen rather rarely.
If you additionally reuse buffers, this will increase the performance
further.

The metrics based on some internal benchmarks show a speedup of about 1%:

bitsery <dont inline bad cases>
  BigString: 222092ns
  ComplexLittleObjects: 34115ns
  ComplexLittleObjectsBig: 6222801ns

bitsery <original>
  BigString: 242853ns
  ComplexLittleObjects: 35738ns
  ComplexLittleObjectsBig: 6334747ns

The assembly has been checked to be correct: https://godbolt.org/z/Wr7qvfGrK

Additionally, when allocating code, we can tell the compiler that we are
not resizing to a lower size, this saves on gcc 14 a few instructions.
The improvement should be negligible.
2024-07-21 10:58:53 +03:00
Pol Marcet Sardà
cd73aca2f5 Fix compilation errors in clang 17 2024-07-21 10:58:53 +03:00
NBurley93
94f7adaf6c FIX: Build error on GCC 13.x (#106)
Refer to https://gcc.gnu.org/gcc-13/porting_to.html for details on why change was needed
2023-06-06 10:09:26 +03:00
SoftdriveFelix
ceeb189c8b Changes the code path for arrays of bytes in big (#105)
Thanks for PR!
2023-05-09 08:47:18 +03:00
Mindaugas Vinkelis
90243480ec use latests compilers from ubuntu to run tests 2023-05-09 08:40:14 +03:00
Mindaugas Vinkelis
d1a47e06e2 change log update for 5.2.3 2022-12-01 14:25:34 +02:00
Mindaugas Vinkelis
3e02d0ca44 format code base in Mozilla style 2022-12-01 13:50:03 +02:00
Mindaugas Vinkelis
d690908541 reworked bitpacking, to fix measure size (measure size now is not
bit-packing enabled by default)
2022-12-01 13:42:02 +02:00
Mindaugas Vinkelis
d3dd64baaf changed increaseBufferSize signature
simplified adapters implementations
2022-04-21 20:01:58 +03:00
museghost
d24e0ab1b3 fix shadow warning in gcc8 (#1) (#87)
Co-authored-by: brian.kim <brian.kim@beatthemarket.co.kr>
2021-10-22 12:44:38 +03:00
123 changed files with 15668 additions and 12810 deletions

192
.clang-format Normal file
View File

@@ -0,0 +1,192 @@
---
Language: Cpp
# BasedOnStyle: Mozilla
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveMacros: None
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: TopLevel
AlwaysBreakAfterReturnType: TopLevel
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: true
AfterControlStatement: Never
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: false
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Mozilla
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeComma
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: false
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: BinPack
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: false
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: false
IndentCaseLabels: true
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequires: false
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: Signature
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: false
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PenaltyIndentedWhitespace: 0
PointerAlignment: Left
PPIndentWidth: -1
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

8
.github/FUNDING.yml vendored Normal file
View 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"

View File

@@ -9,54 +9,38 @@ on:
jobs:
build:
name: ${{ matrix.config.name }}
runs-on: ubuntu-18.04
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
config:
- name: "Ubuntu 18.04 with Clang 3.9"
cxx_ver: 11
compiler: clang
compiler_ver: 3.9
- name: "Ubuntu 18.04 with GCC 5.0"
cxx_ver: 11
- name: "Ubuntu Latest with GCC 14"
compiler: gcc
compiler_ver: 5
- name: "Ubuntu 18.04 with GCC 11.0"
cxx_ver: 17
compiler: gcc
compiler_ver: 11
- name: "Ubuntu 18.04 with Clang 13"
cxx_ver: 17
compiler_ver: 14
- name: "Ubuntu Latests with Clang 18"
compiler: clang
compiler_ver: 13
compiler_ver: 18
steps:
- name: Prepare specific Clang version
if: ${{ matrix.config.compiler == 'clang' }}
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 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
- name: Prepare specific GCC version
if: ${{ matrix.config.compiler == 'gcc' }}
run: |
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt update
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/cc cc /usr/bin/gcc-${{ matrix.config.compiler_ver}} 100
- name: Installing GTest
run: |
sudo add-apt-repository ppa:team-xbmc/ppa
sudo apt-get update
sudo apt-get install libgmock-dev
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- 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
run: cmake --build build
- name: Run tests
run: ctest --test-dir build/tests
run: ctest --test-dir build

View File

@@ -14,13 +14,13 @@ jobs:
run: |
git clone https://github.com/google/googletest.git
cd googletest
git checkout release-1.11.0
git checkout v1.14.0
cmake -S . -B build
cmake --build build --target install
- uses: actions/checkout@v2
sudo cmake --build build --target install
- uses: actions/checkout@v3
- name: Configure
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17
- name: Build
run: cmake --build build
- name: Run tests
run: ctest --test-dir build/tests
run: ctest --test-dir build

View File

@@ -15,10 +15,10 @@ jobs:
run: |
git clone https://github.com/google/googletest.git
cd googletest
git checkout release-1.11.0
git checkout v1.14.0
cmake -S . -B build -Dgtest_force_shared_crt=ON
cmake --build build --config Release --target install
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Configure
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_FLAGS="/Zc:__cplusplus /permissive- /EHsc"
env:
@@ -26,4 +26,4 @@ jobs:
- name: Build
run: cmake --build build --config Release
- name: Run tests
run: ctest --test-dir build/tests
run: ctest --test-dir build

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
.idea/
.vs/
.vscode/
build/
cmake-build-*
CTestConfig.cmake

View File

@@ -1,70 +0,0 @@
dist: xenial
language: cpp
# CXX_COMPILER and CC_COMPILER is defined, because travis will override CC and CXX environment variables
# We'll need to override them back "before_install"
matrix:
include:
- addons:
apt:
packages:
- g++-5
env:
- CXXSTD=11
- CXX_COMPILER=g++-5
- CC_COMPILER=gcc-5
- addons:
apt:
packages:
- clang-3.9
env:
- CXXSTD=11
- CXX_COMPILER=clang++-3.9
- CC_COMPILER=clang-3.9
- addons:
apt:
packages:
- g++-7
sources:
- ubuntu-toolchain-r-test
env:
- CXXSTD=17
- CXX_COMPILER=g++-7
- CC_COMPILER=gcc-7
- addons:
apt:
packages:
- libstdc++-7-dev
- clang-8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-8
- sourceline: 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
env:
- CXXSTD=17
- CXX_COMPILER=clang++-8
- CC_COMPILER=clang-8
before_install:
- export CXX=$CXX_COMPILER
- export CC=$CC_COMPILER
install:
- wget https://github.com/google/googletest/archive/release-1.10.0.tar.gz
- tar xf release-1.10.0.tar.gz
- cd googletest-release-1.10.0
- cmake -DBUILD_SHARED_LIBS=ON .
- make
- sudo make install
- cd ..
before_script:
- mkdir build
- cd build
  - cmake -DBITSERY_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=$CXXSTD ..
script:
- make
- cd tests
- ctest

View File

@@ -1,3 +1,40 @@
# [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)
### Improvements
* refactored bit-packing implementation to make sure that `MeasureSize` adapter acts as all other adapters and is not bit-packing enabled by default. #91
* `BufferAdapterTraits::increaseBufferSize` now accepts current size and minimum required size in order to better allocate required memory.
### Bug fixes
* fix shadow warning in gcc8 #87 (thanks to [museghost](https://github.com/museghost) and brian.kim)
### Other notes
* format whole code base in Mozilla style.
* simplified adapters implementations
# [5.2.2](https://github.com/fraillt/bitsery/compare/v5.2.1...v5.2.2) (2021-08-31)
### Improvements

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.1)
cmake_minimum_required(VERSION 3.25)
project(bitsery
LANGUAGES CXX
VERSION 5.2.2)
VERSION 5.2.5)
#======== build options ===================================
option(BITSERY_BUILD_EXAMPLES "Build examples" OFF)
@@ -51,6 +51,7 @@ endif()
if (BITSERY_BUILD_TESTS)
message("build bitsery tests")
enable_testing()
add_subdirectory(tests)
else()
message("skip bitsery tests")

View File

@@ -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.
There is a patch that allows using bitsery with non-fully compatible C++11 compilers.
* CentOS 7 with gcc 4.8.2.
## 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)

View File

@@ -20,7 +20,7 @@
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#SOFTWARE.
cmake_minimum_required(VERSION 3.1)
cmake_minimum_required(VERSION 3.25)
project(bitsery_examples CXX)
if (NOT TARGET Bitsery::bitsery)

View File

@@ -1,48 +1,62 @@
//include bitsery.h to get serialization and deserialization classes
// include bitsery.h to get serialization and deserialization classes
#include <bitsery/bitsery.h>
//in ordered to serialize/deserialize data to buffer, include buffer adapter
// in ordered to serialize/deserialize data to buffer, include buffer adapter
#include <bitsery/adapter/buffer.h>
//bitsery itself doesn't is lightweight, and doesnt include any unnessessary files,
//traits helps library to know how to use types correctly,
//in this case we'll be using vector both, to serialize/deserialize data and to store use as a buffer.
// bitsery itself doesn't is lightweight, and doesnt include any unnessessary
// files, traits helps library to know how to use types correctly, in this case
// we'll be using vector both, to serialize/deserialize data and to store use as
// a buffer.
#include <bitsery/traits/vector.h>
enum class MyEnum:uint16_t { V1,V2,V3 };
struct MyStruct {
uint32_t i;
MyEnum e;
std::vector<float> fs;
enum class MyEnum : uint16_t
{
V1,
V2,
V3
};
struct MyStruct
{
uint32_t i;
MyEnum e;
std::vector<float> fs;
};
//define how object should be serialized/deserialized
template <typename S>
void serialize(S& s, MyStruct& o) {
s.value4b(o.i);//fundamental types (ints, floats, enums) of size 4b
s.value2b(o.e);
s.container4b(o.fs, 10);//resizable containers also requires maxSize, to make it safe from buffer-overflow attacks
// define how object should be serialized/deserialized
template<typename S>
void
serialize(S& s, MyStruct& o)
{
s.value4b(o.i); // fundamental types (ints, floats, enums) of size 4b
s.value2b(o.e);
s.container4b(o.fs, 10); // resizable containers also requires maxSize, to
// make it safe from buffer-overflow attacks
}
//some helper types
// some helper types
using Buffer = std::vector<uint8_t>;
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
int main() {
//set some random data
MyStruct data{8941, MyEnum::V2, {15.0f, -8.5f, 0.045f}};
MyStruct res{};
int
main()
{
// set some random data
MyStruct data{ 8941, MyEnum::V2, { 15.0f, -8.5f, 0.045f } };
MyStruct res{};
//create buffer to store data
Buffer buffer;
//use quick serialization function,
//it will use default configuration to setup all the nesessary steps
//and serialize data to container
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
// create buffer to store data
Buffer buffer;
// use quick serialization function,
// it will use default configuration to setup all the nesessary steps
// and serialize data to container
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
//same as serialization, but returns deserialization state as a pair
//first = error code, second = is buffer was successfully read from begin to the end.
auto state = bitsery::quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
// same as serialization, but returns deserialization state as a pair
// first = error code, second = is buffer was successfully read from begin to
// the end.
auto state = bitsery::quickDeserialization<InputAdapter>(
{ buffer.begin(), writtenSize }, res);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(data.fs == res.fs && data.i == res.i && data.e == res.e);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(data.fs == res.fs && data.i == res.i && data.e == res.e);
}

View File

@@ -1,62 +1,74 @@
#include <bitsery/bitsery.h>
#include <bitsery/adapter/buffer.h>
//we'll be using std::array as a buffer type, so include traits for this
#include <bitsery/bitsery.h>
// we'll be using std::array as a buffer type, so include traits for this
#include <bitsery/traits/array.h>
#include <bitsery/traits/string.h>
#include <bitsery/traits/vector.h>
//include extension that will allow to compress our data
// include extension that will allow to compress our data
#include <bitsery/ext/value_range.h>
namespace MyTypes {
struct Vec3 { float x, y, z; };
struct Vec3
{
float x, y, z;
};
struct Monster {
Vec3 pos;
std::vector<Vec3> path;
std::string name;
};
struct Monster
{
Vec3 pos;
std::vector<Vec3> path;
std::string name;
};
template<typename S>
void serialize(S& s, MyTypes::Vec3 &o) {
s.value4b(o.x);
s.value4b(o.y);
s.value4b(o.z);
}
template <typename S>
void serialize (S& s, Monster& o) {
s.text1b(o.name, 20);
s.object(o.pos);
//compress path in a range of -1.0 .. 1.0 with 0.01 precision
//enableBitPacking creates separate serializer/deserializer object, that contains bit packing operations
s.enableBitPacking([&o](typename S::BPEnabledType& sbp) {
sbp.container(o.path, 1000, [](typename S::BPEnabledType& sbp, Vec3& vec3) {
constexpr bitsery::ext::ValueRange<float> range{-1.0f,1.0f, 0.01f};
sbp.ext(vec3.x, range);
sbp.ext(vec3.y, range);
sbp.ext(vec3.z, range);
});
});
}
template<typename S>
void
serialize(S& s, MyTypes::Vec3& o)
{
s.value4b(o.x);
s.value4b(o.y);
s.value4b(o.z);
}
//use fixed-size buffer
template<typename S>
void
serialize(S& s, Monster& o)
{
s.text1b(o.name, 20);
s.object(o.pos);
// compress path in a range of -1.0 .. 1.0 with 0.01 precision
// enableBitPacking creates separate serializer/deserializer object, that
// contains bit packing operations
s.enableBitPacking([&o](typename S::BPEnabledType& sbp) {
sbp.container(o.path, 1000, [](typename S::BPEnabledType& sbp, Vec3& vec3) {
constexpr bitsery::ext::ValueRange<float> range{ -1.0f, 1.0f, 0.01f };
sbp.ext(vec3.x, range);
sbp.ext(vec3.y, range);
sbp.ext(vec3.z, range);
});
});
}
}
// use fixed-size buffer
using Buffer = std::array<uint8_t, 10000>;
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
int main() {
//set some random data
MyTypes::Monster data{};
data.name = "lew";
int
main()
{
// set some random data
MyTypes::Monster data{};
data.name = "lew";
//create buffer to store data to
Buffer buffer{};
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
// create buffer to store data to
Buffer buffer{};
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
MyTypes::Monster res{};
auto state = bitsery::quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
MyTypes::Monster res{};
auto state = bitsery::quickDeserialization<InputAdapter>(
{ buffer.begin(), writtenSize }, res);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(state.first == bitsery::ReaderError::NoError && state.second);
}

View File

@@ -1,44 +1,54 @@
#include <bitsery/bitsery.h>
#include <bitsery/adapter/buffer.h>
//to use brief syntax always include this header
#include <bitsery/bitsery.h>
// to use brief syntax always include this header
#include <bitsery/brief_syntax.h>
//we also need additional traits to work with container types,
//instead of including <bitsery/traits/vector.h> for vector traits, now we also need traits to work with brief_syntax types.
//so include everything from <bitsery/brief_syntax/...> instead of <bitsery/traits/...>
//otherwise we'll get static assert error, saying to define serialize function.
// we also need additional traits to work with container types,
// instead of including <bitsery/traits/vector.h> for vector traits, now we also
// need traits to work with brief_syntax types. so include everything from
// <bitsery/brief_syntax/...> instead of <bitsery/traits/...> otherwise we'll
// get static assert error, saying to define serialize function.
#include <bitsery/brief_syntax/vector.h>
enum class MyEnum:uint16_t { V1,V2,V3 };
struct MyStruct {
uint32_t i;
MyEnum e;
std::vector<float> fs;
//define serialize function as usual
template <typename S>
void serialize(S& s) {
//now we can use brief syntax with
s(i, e, fs);
}
enum class MyEnum : uint16_t
{
V1,
V2,
V3
};
struct MyStruct
{
uint32_t i;
MyEnum e;
std::vector<float> fs;
// define serialize function as usual
template<typename S>
void serialize(S& s)
{
// now we can use brief syntax with
s(i, e, fs);
}
};
//some helper types
// some helper types
using Buffer = std::vector<uint8_t>;
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
int main() {
//set some random data
MyStruct data{8941, MyEnum::V2, {15.0f, -8.5f, 0.045f}};
MyStruct res{};
int
main()
{
// set some random data
MyStruct data{ 8941, MyEnum::V2, { 15.0f, -8.5f, 0.045f } };
MyStruct res{};
//serialization, deserialization flow is unchanged as in basic usage
Buffer buffer;
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
// serialization, deserialization flow is unchanged as in basic usage
Buffer buffer;
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
auto state = bitsery::quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
auto state = bitsery::quickDeserialization<InputAdapter>(
{ buffer.begin(), writtenSize }, res);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(data.fs == res.fs && data.i == res.i && data.e == res.e);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(data.fs == res.fs && data.i == res.i && data.e == res.e);
}

View File

@@ -1,5 +1,5 @@
#include <bitsery/bitsery.h>
#include <bitsery/adapter/buffer.h>
#include <bitsery/bitsery.h>
#include <bitsery/traits/vector.h>
// include extensions to work with tuples and variants
// these extesions only work with C++17
@@ -10,101 +10,126 @@
// let's include this extension to make it more interesting :)
#include <bitsery/ext/compact_value.h>
struct MyStruct {
std::vector<int32_t> v{};
float f{};
struct MyStruct
{
std::vector<int32_t> v{};
float f{};
bool operator==(const MyStruct& rhs) const {
return v == rhs.v && f == rhs.f;
}
bool operator==(const MyStruct& rhs) const
{
return v == rhs.v && f == rhs.f;
}
};
template<typename S>
void serialize(S& s, MyStruct& o) {
s.container4b(o.v, 1000);
s.value4b(o.f);
void
serialize(S& s, MyStruct& o)
{
s.container4b(o.v, 1000);
s.value4b(o.f);
}
// this will be the type that we want to serialize/deserialize
using MyTuple = std::tuple<float, MyStruct>;
using MyVariant = std::variant<int64_t, MyTuple, MyStruct>;
// define default serialize function for MyVariant, so that we could use quickSerialization/Deserialization functions
// define default serialize function for MyVariant, so that we could use
// quickSerialization/Deserialization functions
template<typename S>
void serialize(S& s, MyVariant& o) {
// in order to serialize a variant, it needs to know how to do it for all types
// we can do this simply by providing any callable object, that accepts serializer and type as arguments
s.ext(o, bitsery::ext::StdVariant{
// specify how to serialize tuple by creating a lambda
[](S& s, MyTuple& o) {
// StdTuple is used exactly the same as StdVariant
s.ext(o, bitsery::ext::StdTuple{
// this is convenient callable object to specify integral value size
// it is different equivalent to lambda [](auto& s, float&o) { s.value4b(o);}
bitsery::ext::OverloadValue<float, 4>{},
// it is not required to provide MyStruct overload, because it we have defined 'serialize' function for it
});
},
// this might also be useful if you want to overload using extension
bitsery::ext::OverloadExtValue<int64_t, 8, bitsery::ext::CompactValue>{},
// you can even go further and instead of writing lambda for MyTuple you can as well compose the same functionality
// with OverloadExtObject, like this:
// (comment out MyTuple lambda, and uncomment this)
// ext::OverloadExtObject<MyTuple, ext::StdTuple<ext::OverloadValue<float, 4>>>{},
void
serialize(S& s, MyVariant& o)
{
// in order to serialize a variant, it needs to know how to do it for all
// types we can do this simply by providing any callable object, that accepts
// serializer and type as arguments
s.ext(
o,
bitsery::ext::StdVariant{
// specify how to serialize tuple by creating a lambda
[](S& s, MyTuple& o) {
// StdTuple is used exactly the same as StdVariant
s.ext(
o,
bitsery::ext::StdTuple{
// this is convenient callable object to specify integral value size
// it is different equivalent to lambda [](auto& s, float&o) {
// s.value4b(o);}
bitsery::ext::OverloadValue<float, 4>{},
// it is not required to provide MyStruct overload, because it we
// have defined 'serialize' function for it
});
},
// this might also be useful if you want to overload using extension
bitsery::ext::OverloadExtValue<int64_t, 8, bitsery::ext::CompactValue>{},
// you can even go further and instead of writing lambda for MyTuple you
// can as well compose the same functionality
// with OverloadExtObject, like this:
// (comment out MyTuple lambda, and uncomment this)
// ext::OverloadExtObject<MyTuple, ext::StdTuple<ext::OverloadValue<float,
// 4>>>{},
// we can also override default 'serialize' function by creating an overloading for that type
[](S& s, MyStruct& o) {
s.value4b(o.f);
s.container(o.v, 1000, [](S& s, int32_t& v) {
s.ext4b(v, bitsery::ext::CompactValue{});
});
},
// NOTE.
// it is possible to provide "auto" as type parameter
// this will allow you to override all default 'serialize' functions
// but in this case it will not be called, because we have explicitly provided overloads for all variant types
// also note, that first parameter (serializer) is also "auto", this is required, so that it would be least specialized case
// otherwise it will not compile if you any ext::Overload* helper defined, because it will have ambiguous definitions
// (ext::OverLoad* defines (templated_type& s, concrete_type& o) and lambda would be (concrete_type& s, templated_type& o))
[](auto& , auto&) {
assert(false);
}
});
// we can also override default 'serialize' function by creating an
// overloading for that type
[](S& s, MyStruct& o) {
s.value4b(o.f);
s.container(o.v, 1000, [](S& s, int32_t& v) {
s.ext4b(v, bitsery::ext::CompactValue{});
});
},
// NOTE.
// it is possible to provide "auto" as type parameter
// this will allow you to override all default 'serialize' functions
// but in this case it will not be called, because we have explicitly
// provided overloads for all variant types
// also note, that first parameter (serializer) is also "auto", this is
// required, so that it would be least specialized case
// otherwise it will not compile if you any ext::Overload* helper defined,
// because it will have ambiguous definitions
// (ext::OverLoad* defines (templated_type& s, concrete_type& o) and
// lambda would be (concrete_type& s, templated_type& o))
[](auto&, auto&) { assert(false); } });
}
//some helper types
// some helper types
using Buffer = std::vector<uint8_t>;
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
int main() {
int
main()
{
//set some random data
MyVariant data{ MyTuple{-7549, {{-451, 2, 968, 75, 4, 156, 49}, 874.4f}} };
MyVariant res{};
// set some random data
MyVariant data{ MyTuple{ -7549,
{ { -451, 2, 968, 75, 4, 156, 49 }, 874.4f } } };
MyVariant res{};
//create buffer to store data
Buffer buffer;
//use quick serialization function,
//it will use default configuration to setup all the nesessary steps
//and serialize data to container
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
// create buffer to store data
Buffer buffer;
// use quick serialization function,
// it will use default configuration to setup all the nesessary steps
// and serialize data to container
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
//same as serialization, but returns deserialization state as a pair
//first = error code, second = is buffer was successfully read from begin to the end.
auto state = bitsery::quickDeserialization<InputAdapter>({ buffer.begin(), writtenSize }, res);
// same as serialization, but returns deserialization state as a pair
// first = error code, second = is buffer was successfully read from begin to
// the end.
auto state = bitsery::quickDeserialization<InputAdapter>(
{ buffer.begin(), writtenSize }, res);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(data == res);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(data == res);
}
#else
#if defined(_MSC_VER)
#pragma message("C++17 and /Zc:__cplusplus option is required to enable this example")
#pragma message( \
"C++17 and /Zc:__cplusplus option is required to enable this example")
#else
#pragma message("C++17 is required to enable this example")
#endif
int main() {
return 0;
int
main()
{
return 0;
}
#endif

View File

@@ -1,5 +1,5 @@
#include <bitsery/bitsery.h>
#include <bitsery/adapter/buffer.h>
#include <bitsery/bitsery.h>
#include <bitsery/traits/string.h>
#include <bitsery/traits/vector.h>
@@ -8,91 +8,106 @@
namespace MyTypes {
struct Monster {
Monster() = default;
Monster(std::string _name, uint32_t minDmg, uint32_t maxDmg)
:name{_name}, minDamage{minDmg}, maxDamage{maxDmg} {}
struct Monster
{
Monster() = default;
Monster(std::string _name, uint32_t minDmg, uint32_t maxDmg)
: name{ _name }
, minDamage{ minDmg }
, maxDamage{ maxDmg }
{
}
std::string name{};
uint32_t minDamage{};
uint32_t maxDamage{};
//...
};
std::string name{};
uint32_t minDamage{};
uint32_t maxDamage{};
//...
};
struct GameState {
std::vector<Monster> monsters;
};
struct GameState
{
std::vector<Monster> monsters;
};
//default flow for monster
template <typename S>
void serialize (S& s, Monster& o) {
s.text1b(o.name, 20);
s.value4b(o.minDamage);
s.value4b(o.maxDamage);
}
// default flow for monster
template<typename S>
void
serialize(S& s, Monster& o)
{
s.text1b(o.name, 20);
s.value4b(o.minDamage);
s.value4b(o.maxDamage);
}
template<typename S>
void serialize(S& s, GameState &o) {
//we can have multiple types in context with std::tuple
//if data type doesn't match then it will be compile time error
//NOTE: if context is optional then you can call contextOrNull<T>, and it will return null if T doesn't exists
auto maxMonsters = s.template context<int>();
auto& dmgRange = s.template context<std::pair<uint32_t, uint32_t>>();
template<typename S>
void
serialize(S& s, GameState& o)
{
// we can have multiple types in context with std::tuple
// if data type doesn't match then it will be compile time error
// NOTE: if context is optional then you can call contextOrNull<T>, and it
// will return null if T doesn't exists
auto maxMonsters = s.template context<int>();
auto& dmgRange = s.template context<std::pair<uint32_t, uint32_t>>();
s.container(o.monsters, maxMonsters, [&dmgRange] (S& s, Monster& m) {
s.text1b(m.name, 20);
//we know min/max damage range for monsters, so we can use this range instead of full value
bitsery::ext::ValueRange<uint32_t> range{dmgRange.first, dmgRange.second};
//enable bit packing
s.enableBitPacking([&m, &range](typename S::BPEnabledType& sbp) {
sbp.ext(m.minDamage, range);
sbp.ext(m.maxDamage, range);
});
});
}
s.container(o.monsters, maxMonsters, [&dmgRange](S& s, Monster& m) {
s.text1b(m.name, 20);
// we know min/max damage range for monsters, so we can use this range
// instead of full value
bitsery::ext::ValueRange<uint32_t> range{ dmgRange.first, dmgRange.second };
// enable bit packing
s.enableBitPacking([&m, &range](typename S::BPEnabledType& sbp) {
sbp.ext(m.minDamage, range);
sbp.ext(m.maxDamage, range);
});
});
}
}
//context can contain multiple types by wrapping these types in std::tuple
//in serialization function we can get type that we need like this:
// s.template context<int>();
//this templated version also works if our context is the same as cast:
// struct MyContext {...};
// ...
// s.template context<MyContext>();
//NOTE:
// if your context has no additional usage outside of serialization flow,
// then you can create it internally via configuration (see inheritance.cpp)
// context can contain multiple types by wrapping these types in std::tuple
// in serialization function we can get type that we need like this:
// s.template context<int>();
// this templated version also works if our context is the same as cast:
// struct MyContext {...};
// ...
// s.template context<MyContext>();
// NOTE:
// if your context has no additional usage outside of serialization flow,
// then you can create it internally via configuration (see inheritance.cpp)
using Context = std::tuple<int, std::pair<uint32_t, uint32_t>>;
//use fixed-size buffer
// use fixed-size buffer
using Buffer = std::vector<uint8_t>;
// define adapter types,
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
int main() {
int
main()
{
MyTypes::GameState data{};
data.monsters.push_back({"weaksy", 100, 200});
data.monsters.push_back({"bigsy", 500, 1000});
data.monsters.push_back({"tootoo", 350, 750});
MyTypes::GameState data{};
data.monsters.push_back({ "weaksy", 100, 200 });
data.monsters.push_back({ "bigsy", 500, 1000 });
data.monsters.push_back({ "tootoo", 350, 750 });
//set context
Context ctx{};
//max monsters
std::get<0>(ctx) = 4;
//damage range
std::get<1>(ctx).first = 100;
std::get<1>(ctx).second = 1000;
// set context
Context ctx{};
// max monsters
std::get<0>(ctx) = 4;
// damage range
std::get<1>(ctx).first = 100;
std::get<1>(ctx).second = 1000;
// create buffer to store data to
Buffer buffer{};
auto writtenSize =
bitsery::quickSerialization(ctx, OutputAdapter{ buffer }, data);
//create buffer to store data to
Buffer buffer{};
auto writtenSize = bitsery::quickSerialization(ctx, OutputAdapter{buffer}, data);
MyTypes::GameState res{};
auto state = bitsery::quickDeserialization(
ctx, InputAdapter{ buffer.begin(), writtenSize }, res);
MyTypes::GameState res{};
auto state = bitsery::quickDeserialization(ctx, InputAdapter{buffer.begin(), writtenSize}, res);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(state.first == bitsery::ReaderError::NoError && state.second);
}

View File

@@ -1,55 +1,68 @@
#include <bitsery/bitsery.h>
//in order to work with streams include stream adapter
// in order to work with streams include stream adapter
#include <bitsery/adapter/stream.h>
#include <fstream>
#include <iostream>
enum class MyEnum:uint16_t { V1,V2,V3 };
struct MyStruct {
uint32_t i;
MyEnum e;
double f;
enum class MyEnum : uint16_t
{
V1,
V2,
V3
};
struct MyStruct
{
uint32_t i;
MyEnum e;
double f;
};
//define how object should be serialized/deserialized
template <typename S>
void serialize(S& s, MyStruct& o) {
s.value4b(o.i);
s.value2b(o.e);
s.value8b(o.f);
// define how object should be serialized/deserialized
template<typename S>
void
serialize(S& s, MyStruct& o)
{
s.value4b(o.i);
s.value2b(o.e);
s.value8b(o.f);
}
int main() {
//set some random data
MyStruct data{8941, MyEnum::V2, 0.045};
MyStruct res{};
int
main()
{
// set some random data
MyStruct data{ 8941, MyEnum::V2, 0.045 };
MyStruct res{};
//open file stream for writing and reading
auto fileName = "test_file.bin";
std::fstream s{fileName, s.binary | s.trunc | s.out};
if (!s.is_open()) {
std::cout << "cannot open " << fileName << " for writing\n";
return 0;
}
// open file stream for writing and reading
auto fileName = "test_file.bin";
std::fstream s{ fileName, s.binary | s.trunc | s.out };
if (!s.is_open()) {
std::cout << "cannot open " << fileName << " for writing\n";
return 0;
}
//we cannot use quick serialization function, because streams cannot use writtenBytesCount method
bitsery::Serializer<bitsery::OutputBufferedStreamAdapter> ser{s};
ser.object(data);
//flush to writer
ser.adapter().flush();
s.close();
//reopen for reading
// we cannot use quick serialization function, because streams cannot use
// writtenBytesCount method
bitsery::Serializer<bitsery::OutputBufferedStreamAdapter> ser{ s };
ser.object(data);
// flush to writer
ser.adapter().flush();
s.close();
// reopen for reading
s.open(fileName, s.binary | s.in);
if (!s.is_open()) {
std::cout << "cannot open " << fileName << " for reading\n";
return 0;
}
s.open(fileName, s.binary | s.in);
if (!s.is_open()) {
std::cout << "cannot open " << fileName << " for reading\n";
return 0;
}
//same as serialization, but returns deserialization state as a pair
//first = error code, second = is buffer was successfully read from begin to the end.
auto state = bitsery::quickDeserialization<bitsery::InputStreamAdapter>(s, res);
// same as serialization, but returns deserialization state as a pair
// first = error code, second = is buffer was successfully read from begin to
// the end.
auto state =
bitsery::quickDeserialization<bitsery::InputStreamAdapter>(s, res);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(data.f == res.f && data.i == res.i && data.e == res.e);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(data.f == res.f && data.i == res.i && data.e == res.e);
}

View File

@@ -1,92 +1,114 @@
#include <bitsery/bitsery.h>
#include <bitsery/adapter/buffer.h>
//include traits for types, that we'll be using
#include <bitsery/traits/string.h>
#include <bitsery/bitsery.h>
// include traits for types, that we'll be using
#include <bitsery/traits/array.h>
#include <bitsery/traits/string.h>
#include <bitsery/traits/vector.h>
//include extension that will allow to have backward/forward compatibility
// include extension that will allow to have backward/forward compatibility
#include <bitsery/ext/growable.h>
namespace MyTypes {
//define data
enum Color:uint8_t { Red, Green, Blue };
// define data
enum Color : uint8_t
{
Red,
Green,
Blue
};
struct Vec3 { float x, y, z; };
struct Vec3
{
float x, y, z;
};
struct Weapon {
std::string name{};
int16_t damage{};
Weapon() = default;
Weapon(const std::string& _name, int16_t dmg):name{_name}, damage{dmg} {}
private:
//define serialize function as private, and give access to bitsery
friend bitsery::Access;
template <typename S>
void serialize (S& s) {
//forward/backward compatibility for monsters
s.ext(*this, bitsery::ext::Growable{}, [](S& s, Weapon& o1) {
s.text1b(o1.name, 20);
s.value2b(o1.damage);
});
}
};
struct Weapon
{
std::string name{};
int16_t damage{};
Weapon() = default;
Weapon(const std::string& _name, int16_t dmg)
: name{ _name }
, damage{ dmg }
{
}
struct Monster {
Vec3 pos;
int16_t mana;
int16_t hp;
std::string name;
std::vector<uint8_t> inventory;
Color color;
std::vector<Weapon> weapons;
Weapon equipped;
std::vector<Vec3> path;
};
private:
// define serialize function as private, and give access to bitsery
friend bitsery::Access;
template<typename S>
void serialize(S& s)
{
// forward/backward compatibility for weapons
s.ext(*this, bitsery::ext::Growable{}, [](S& s, Weapon& o1) {
s.text1b(o1.name, 20);
s.value2b(o1.damage);
});
}
};
template <typename S>
void serialize(S& s, Vec3& o) {
s.value4b(o.x);
s.value4b(o.y);
s.value4b(o.z);
}
struct Monster
{
Vec3 pos;
int16_t mana;
int16_t hp;
std::string name;
std::vector<uint8_t> inventory;
Color color;
std::vector<Weapon> weapons;
Weapon equipped;
std::vector<Vec3> path;
};
template <typename S>
void serialize (S& s, Monster& o) {
//forward/backward compatibility for monsters
s.ext(o, bitsery::ext::Growable{}, [](S& s, Monster& o1) {
s.value1b(o1.color);
s.value2b(o1.mana);
s.value2b(o1.hp);
s.object(o1.equipped);
s.object(o1.pos);
s.container(o1.path, 1000);
s.container(o1.weapons, 100);
s.container1b(o1.inventory, 50);
s.text1b(o1.name, 20);
});
}
template<typename S>
void
serialize(S& s, Vec3& o)
{
s.value4b(o.x);
s.value4b(o.y);
s.value4b(o.z);
}
//use fixed-size buffer
template<typename S>
void
serialize(S& s, Monster& o)
{
// forward/backward compatibility for monsters
s.ext(o, bitsery::ext::Growable{}, [](S& s, Monster& o1) {
s.value1b(o1.color);
s.value2b(o1.mana);
s.value2b(o1.hp);
s.object(o1.equipped);
s.object(o1.pos);
s.container(o1.path, 1000);
s.container(o1.weapons, 100);
s.container1b(o1.inventory, 50);
s.text1b(o1.name, 20);
});
}
}
// use fixed-size buffer
using Buffer = std::array<uint8_t, 10000>;
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
int main() {
//set some random data
MyTypes::Monster data{};
data.name = "lew";
data.weapons.push_back(MyTypes::Weapon{"GoodWeapon", 100});
int
main()
{
// set some random data
MyTypes::Monster data{};
data.name = "lew";
data.weapons.push_back(MyTypes::Weapon{ "GoodWeapon", 100 });
//create buffer to store data to
Buffer buffer{};
//since we're using different configuration, we cannot use quickSerialization function.
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
// create buffer to store data to
Buffer buffer{};
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
MyTypes::Monster res{};
//deserialize
auto state = bitsery::quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
MyTypes::Monster res{};
// deserialize
auto state = bitsery::quickDeserialization<InputAdapter>(
{ buffer.begin(), writtenSize }, res);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(state.first == bitsery::ReaderError::NoError && state.second);
}

View File

@@ -1,104 +1,134 @@
//
//this example covers all the corner cases that can happen using inheritance
//in reality virtual inherintance is usually avoided, so your code would look much simpler.
// this example covers all the corner cases that can happen using inheritance
// in reality virtual inherintance is usually avoided, so your code would look
// much simpler.
//
#include <bitsery/bitsery.h>
#include <bitsery/adapter/buffer.h>
#include <bitsery/bitsery.h>
#include <bitsery/traits/vector.h>
//include inheritance extension
//this header contains two extensions, that specifies inheritance type of base class
// BaseClass - normal inheritance
// VirtualBaseClass - when virtual inheritance is used
//in order for virtual inheritance to work, InheritanceContext is required. for normal inheritance it is not required
// include inheritance extension
// this header contains two extensions, that specifies inheritance type of base
// class
// BaseClass - normal inheritance
// VirtualBaseClass - when virtual inheritance is used
// in order for virtual inheritance to work, InheritanceContext is required. for
// normal inheritance it is not required
#include <bitsery/ext/inheritance.h>
using bitsery::ext::BaseClass;
using bitsery::ext::VirtualBaseClass;
struct Base {
uint8_t x{};
//Base doesn't have to be polymorphic class, inheritance works at compile-time.
struct Base
{
uint8_t x{};
// Base doesn't have to be polymorphic class, inheritance works at
// compile-time.
};
template <typename S>
void serialize(S& s, Base& o) {
s.value1b(o.x);
template<typename S>
void
serialize(S& s, Base& o)
{
s.value1b(o.x);
}
struct Derive1:virtual Base {// virtually inherits from base
uint8_t y1{};
struct Derive1 : virtual Base
{ // virtually inherits from base
uint8_t y1{};
};
template <typename S>
void serialize(S& s, Derive1& o) {
//define virtual inheritance, it will not compile if InheritanceContext is not defined in serializer/deserializer
s.ext(o, VirtualBaseClass<Base>{});
s.value1b(o.y1);
template<typename S>
void
serialize(S& s, Derive1& o)
{
// define virtual inheritance, it will not compile if InheritanceContext is
// not defined in serializer/deserializer
s.ext(o, VirtualBaseClass<Base>{});
s.value1b(o.y1);
}
//to make it more interesting, serialize private member
struct Derived2:virtual Base {
explicit Derived2(uint8_t y):y2{y} {}
// to make it more interesting, serialize private member
struct Derived2 : virtual Base
{
explicit Derived2(uint8_t y)
: y2{ y }
{
}
uint8_t getY2() const { return y2; };
uint8_t getY2() const {
return y2;
};
private:
friend bitsery::Access;
uint8_t y2{};
template <typename S>
void serialize(S& s) {
//notice virtual inheritance
s.ext(*this, VirtualBaseClass<Base>{});
s.value1b(y2);
}
friend bitsery::Access;
uint8_t y2{};
template<typename S>
void serialize(S& s)
{
// notice virtual inheritance
s.ext(*this, VirtualBaseClass<Base>{});
s.value1b(y2);
}
};
struct MultipleInheritance: Derive1, Derived2 {
explicit MultipleInheritance(uint8_t y2):Derived2{y2} {}
uint8_t z{};
struct MultipleInheritance
: Derive1
, Derived2
{
explicit MultipleInheritance(uint8_t y2)
: Derived2{ y2 }
{
}
uint8_t z{};
};
template <typename S>
void serialize(S& s, MultipleInheritance& o) {
//has two bases, serialize them separately
s.ext(o, BaseClass<Derive1>{});
s.ext(o, BaseClass<Derived2>{});
s.value1b(o.z);
template<typename S>
void
serialize(S& s, MultipleInheritance& o)
{
// has two bases, serialize them separately
s.ext(o, BaseClass<Derive1>{});
s.ext(o, BaseClass<Derived2>{});
s.value1b(o.z);
}
namespace bitsery {
// call to serialize function with Derived2 and MultipleInheritance is ambiguous,
// it matches two serialize functions: Base classes non-member fnc and Derived2 member fnc
// we need explicitly select which function to use
template <>
struct SelectSerializeFnc<Derived2>:UseMemberFnc {};
// call to serialize function with Derived2 and MultipleInheritance is
// ambiguous, it matches two serialize functions: Base classes non-member fnc
// and Derived2 member fnc we need explicitly select which function to use
template<>
struct SelectSerializeFnc<Derived2> : UseMemberFnc
{};
//multiple inheritance has non-member serialize function defined
template <>
struct SelectSerializeFnc<MultipleInheritance>:UseNonMemberFnc {};
// multiple inheritance has non-member serialize function defined
template<>
struct SelectSerializeFnc<MultipleInheritance> : UseNonMemberFnc
{};
}
//some helper types
// some helper types
using Buffer = std::vector<uint8_t>;
using Writer = bitsery::OutputBufferAdapter<Buffer>;
using Reader = bitsery::InputBufferAdapter<Buffer>;
int main() {
int
main()
{
MultipleInheritance data{98};
data.x = 254;
data.y1 = 47;
data.z = 1;
MultipleInheritance data{ 98 };
data.x = 254;
data.y1 = 47;
data.z = 1;
Buffer buf{};
Buffer buf{};
bitsery::ext::InheritanceContext ctx1;
auto writtenSize = bitsery::quickSerialization(ctx1, Writer{buf}, data);
assert(writtenSize == 4);//base is serialized once, because it is inherited virtually
bitsery::ext::InheritanceContext ctx1;
auto writtenSize = bitsery::quickSerialization(ctx1, Writer{ buf }, data);
assert(writtenSize ==
4); // base is serialized once, because it is inherited virtually
MultipleInheritance res{0};
bitsery::ext::InheritanceContext ctx2;
auto state = bitsery::quickDeserialization(ctx2, Reader{buf.begin(), writtenSize}, res);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(data.x == res.x && data.y1 == res.y1 && data.getY2() == res.getY2() && data.z == res.z);
MultipleInheritance res{ 0 };
bitsery::ext::InheritanceContext ctx2;
auto state = bitsery::quickDeserialization(
ctx2, Reader{ buf.begin(), writtenSize }, res);
assert(state.first == bitsery::ReaderError::NoError && state.second);
assert(data.x == res.x && data.y1 == res.y1 && data.getY2() == res.getY2() &&
data.z == res.z);
}

View File

@@ -2,61 +2,73 @@
// example of how to deserialize non default constructible objects
//
#include <bitsery/bitsery.h>
#include <bitsery/adapter/buffer.h>
#include <bitsery/bitsery.h>
#include <bitsery/traits/vector.h>
class MyData {
//define your private data
float _x{0};
float _y{0};
//make bitsery:Access friend
friend class bitsery::Access;
//create default constructor, don't worry about class invariant, it will be restored in deserialization
MyData() = default;
//define serialize function
class MyData
{
// define your private data
float _x{ 0 };
float _y{ 0 };
// make bitsery:Access friend
friend class bitsery::Access;
// create default constructor, don't worry about class invariant, it will be
// restored in deserialization
MyData() = default;
// define serialize function
template<typename S>
void serialize(S& s)
{
s.value4b(_x);
s.value4b(_y);
}
template <typename S>
void serialize(S& s) {
s.value4b(_x);
s.value4b(_y);
}
public:
//define non default public constructor
MyData(float x, float y):_x{x}, _y{y} {}
//this is for convenience
bool operator ==(const MyData&rhs) const {
return _x == rhs._x && _y == rhs._y;
}
// define non default public constructor
MyData(float x, float y)
: _x{ x }
, _y{ y }
{
}
// this is for convenience
bool operator==(const MyData& rhs) const
{
return _x == rhs._x && _y == rhs._y;
}
};
//some helper types
// some helper types
using Buffer = std::vector<uint8_t>;
using Writer = bitsery::OutputBufferAdapter<Buffer>;
using Reader = bitsery::InputBufferAdapter<Buffer>;
int main() {
int
main()
{
//initialize our data
std::vector<MyData> data{};
data.emplace_back(145.4f, 84.48f);
std::vector<MyData> res{};
// initialize our data
std::vector<MyData> data{};
data.emplace_back(145.4f, 84.48f);
std::vector<MyData> res{};
//create buffer
Buffer buffer{};
// create buffer
Buffer buffer{};
//we cant use quick (de)serialization helper methods, because we ant to serialize container directly
//create writer and serialize container
bitsery::Serializer<Writer> ser{buffer};
ser.container(data, 10);
ser.adapter().flush();
// we cant use quick (de)serialization helper methods, because we ant to
// serialize container directly create writer and serialize container
bitsery::Serializer<Writer> ser{ buffer };
ser.container(data, 10);
ser.adapter().flush();
//create reader and deserialize container
bitsery::Deserializer<Reader> des{buffer.begin(), ser.adapter().writtenBytesCount()};
des.container(res, 10);
// create reader and deserialize container
bitsery::Deserializer<Reader> des{ buffer.begin(),
ser.adapter().writtenBytesCount() };
des.container(res, 10);
//check if everything went ok
assert(des.adapter().error() == bitsery::ReaderError::NoError && des.adapter().isCompletedSuccessfully());
assert(res == data);
// check if everything went ok
assert(des.adapter().error() == bitsery::ReaderError::NoError &&
des.adapter().isCompletedSuccessfully());
assert(res == data);
}

View File

@@ -1,145 +1,166 @@
#include <bitsery/bitsery.h>
#include <bitsery/adapter/buffer.h>
#include <bitsery/bitsery.h>
#include <bitsery/traits/vector.h>
//include pointers extension
//this header contains multiple extensions for different pointer types and pointer linking context,
//that validates pointer ownership and checks if there are and no dangling pointers after serialization/deserialization.
//dangling pointer in this context means, that non-owning pointer points to data, that was not serialized.
// include pointers extension
// this header contains multiple extensions for different pointer types and
// pointer linking context, that validates pointer ownership and checks if there
// are and no dangling pointers after serialization/deserialization. dangling
// pointer in this context means, that non-owning pointer points to data, that
// was not serialized.
#include <bitsery/ext/pointer.h>
using bitsery::ext::ReferencedByPointer;
using bitsery::ext::PointerObserver;
using bitsery::ext::PointerOwner;
using bitsery::ext::PointerType ;
using bitsery::ext::PointerType;
using bitsery::ext::ReferencedByPointer;
enum class MyEnum:uint16_t { V1,V2,V3 };
struct MyStruct {
MyStruct(uint32_t i_, MyEnum e_, std::vector<float> fs_)
:i{i_},
e{e_},
fs{fs_} {}
MyStruct():MyStruct{0, MyEnum::V1, {}} {}
uint32_t i;
MyEnum e;
std::vector<float> fs;
enum class MyEnum : uint16_t
{
V1,
V2,
V3
};
struct MyStruct
{
MyStruct(uint32_t i_, MyEnum e_, std::vector<float> fs_)
: i{ i_ }
, e{ e_ }
, fs{ fs_ }
{
}
MyStruct()
: MyStruct{ 0, MyEnum::V1, {} }
{
}
uint32_t i;
MyEnum e;
std::vector<float> fs;
};
template <typename S>
void serialize(S& s, MyStruct& o) {
s.value4b(o.i);
s.value2b(o.e);
s.container4b(o.fs, 10);
template<typename S>
void
serialize(S& s, MyStruct& o)
{
s.value4b(o.i);
s.value2b(o.e);
s.container4b(o.fs, 10);
}
//our test data
struct Test1Data {
//regular data, nothing fancy here
MyStruct o1;
int32_t i1;
//these container elements can be referenced by pointers
std::vector<MyStruct> vdata;
//container that holds non owning pointers (observers),
std::vector<MyStruct*> vptr;
//treat it as is observer
MyStruct* po1;
//we treat this as owner (responsible for allocation/deallocation
int32_t* pi1;
// our test data
struct Test1Data
{
// regular data, nothing fancy here
MyStruct o1;
int32_t i1;
// these container elements can be referenced by pointers
std::vector<MyStruct> vdata;
// container that holds non owning pointers (observers),
std::vector<MyStruct*> vptr;
// treat it as is observer
MyStruct* po1;
// we treat this as owner (responsible for allocation/deallocation
int32_t* pi1;
private:
friend bitsery::Access;
friend bitsery::Access;
template <typename S>
void serialize(S& s) {
//just a regular fields
s.object(o1);
s.value4b(i1);
template<typename S>
void serialize(S& s)
{
// just a regular fields
s.object(o1);
s.value4b(i1);
//set container elements to be candidates for non-owning pointers
s.container(vdata, 100, [](S& s, MyStruct& d){
s.ext(d, ReferencedByPointer{});
});
//contains non owning pointers
//
//IMPORTANT !!!
//ALWAYS ACCEPT BY REFERENCE like this: T* (&obj)
//if using c++14, then auto& always works.
//
//you can also serialize non owning pointers first, pointer linking context will keep track on them
//and as soon as pointer owner data is deserialized, all non-owning pointers will be updated
s.container(vptr, 100, [](S& s, MyStruct* (&d)){
s.ext(d, PointerObserver{});
});
//observer
s.ext(po1, PointerObserver{});
//owner, mark it as not null
s.ext4b(pi1, PointerOwner{PointerType::NotNull});
}
// set container elements to be candidates for non-owning pointers
s.container(
vdata, 100, [](S& s, MyStruct& d) { s.ext(d, ReferencedByPointer{}); });
// contains non owning pointers
//
// IMPORTANT !!!
// ALWAYS ACCEPT BY REFERENCE like this: T* (&obj)
// if using c++14, then auto& always works.
//
// you can also serialize non owning pointers first, pointer linking context
// will keep track on them and as soon as pointer owner data is
// deserialized, all non-owning pointers will be updated
s.container(
vptr, 100, [](S& s, MyStruct*(&d)) { s.ext(d, PointerObserver{}); });
// observer
s.ext(po1, PointerObserver{});
// owner, mark it as not null
s.ext4b(pi1, PointerOwner{ PointerType::NotNull });
}
};
//some helper types
// some helper types
using Buffer = std::vector<uint8_t>;
using Writer = bitsery::OutputBufferAdapter<Buffer>;
using Reader = bitsery::InputBufferAdapter<Buffer>;
//we will need PointerLinkingContext to work with pointers
//if we would require additional context for our own custom flow, we can define it as tuple like this:
// std::tuple<MyContext,ext::PointerLinkingContext>
//and other code will work as expected as long as it cast to proper type.
//see context_usage.cpp for usage example
// we will need PointerLinkingContext to work with pointers
// if we would require additional context for our own custom flow, we can define
// it as tuple like this:
// std::tuple<MyContext,ext::PointerLinkingContext>
// and other code will work as expected as long as it cast to proper type.
// see context_usage.cpp for usage example
int main() {
//set some random data
Test1Data data{};
data.vdata.emplace_back(8941, MyEnum::V1, std::vector<float>{4.4f});
data.vdata.emplace_back(15478, MyEnum::V2, std::vector<float>{15.0f});
data.vdata.emplace_back(59, MyEnum::V3, std::vector<float>{-8.5f, 0.045f});
//container of non owning pointers (observers)
data.vptr.emplace_back(nullptr);
data.vptr.emplace_back(std::addressof(data.vdata[0]));
data.vptr.emplace_back(std::addressof(data.vdata[2]));
//regular fields
data.o1 = MyStruct{4, MyEnum::V2, {57.078f}};
data.i1 = 9455;
//observer
data.po1 = std::addressof(data.vdata[1]);
//owning pointer
data.pi1 = new int32_t{};
int
main()
{
// set some random data
Test1Data data{};
data.vdata.emplace_back(8941, MyEnum::V1, std::vector<float>{ 4.4f });
data.vdata.emplace_back(15478, MyEnum::V2, std::vector<float>{ 15.0f });
data.vdata.emplace_back(59, MyEnum::V3, std::vector<float>{ -8.5f, 0.045f });
// container of non owning pointers (observers)
data.vptr.emplace_back(nullptr);
data.vptr.emplace_back(std::addressof(data.vdata[0]));
data.vptr.emplace_back(std::addressof(data.vdata[2]));
// regular fields
data.o1 = MyStruct{ 4, MyEnum::V2, { 57.078f } };
data.i1 = 9455;
// observer
data.po1 = std::addressof(data.vdata[1]);
// owning pointer
data.pi1 = new int32_t{};
//create buffer to store data
Buffer buffer{};
size_t writtenSize{};
//in order to use pointers, we need to pass pointer linking context serializer/deserializer
{
bitsery::ext::PointerLinkingContext ctx{};
writtenSize = quickSerialization(ctx, Writer{buffer}, data);
// create buffer to store data
Buffer buffer{};
size_t writtenSize{};
// in order to use pointers, we need to pass pointer linking context
// serializer/deserializer
{
bitsery::ext::PointerLinkingContext ctx{};
writtenSize = quickSerialization(ctx, Writer{ buffer }, data);
//make sure that pointer linking context is valid
//this ensures that all non-owning pointers points to data that has been serialized,
//so we can successfully reconstruct pointers after deserialization
assert(ctx.isValid());
}
// make sure that pointer linking context is valid
// this ensures that all non-owning pointers points to data that has been
// serialized, so we can successfully reconstruct pointers after
// deserialization
assert(ctx.isValid());
}
Test1Data res{};
{
bitsery::ext::PointerLinkingContext ctx{};
auto state = quickDeserialization(ctx, Reader{buffer.begin(), writtenSize}, res);
//check if everything went find
assert(state.first == bitsery::ReaderError::NoError && state.second);
//also check for dangling pointers, after deserialization
assert(ctx.isValid());
}
//owning pointers owns data
assert(*res.pi1 == *data.pi1);
assert(res.pi1 != data.pi1);
//observers, points to other data
assert(res.vptr[0] == nullptr);
assert(res.vptr[1] == std::addressof(res.vdata[0]));
assert(res.vptr[2] == std::addressof(res.vdata[2]));
assert(res.po1 == std::addressof(res.vdata[1]));
Test1Data res{};
{
bitsery::ext::PointerLinkingContext ctx{};
auto state =
quickDeserialization(ctx, Reader{ buffer.begin(), writtenSize }, res);
// check if everything went find
assert(state.first == bitsery::ReaderError::NoError && state.second);
// also check for dangling pointers, after deserialization
assert(ctx.isValid());
}
// owning pointers owns data
assert(*res.pi1 == *data.pi1);
assert(res.pi1 != data.pi1);
// observers, points to other data
assert(res.vptr[0] == nullptr);
assert(res.vptr[1] == std::addressof(res.vdata[0]));
assert(res.vptr[2] == std::addressof(res.vdata[2]));
assert(res.po1 == std::addressof(res.vdata[1]));
//delete raw owning pointers
delete data.pi1;
delete res.pi1;
// delete raw owning pointers
delete data.pi1;
delete res.pi1;
}

View File

@@ -1,269 +1,307 @@
//
// Created by fraillt on 18.4.26.
//
#include <bitsery/adapter/buffer.h>
#include <bitsery/bitsery.h>
#include <bitsery/ext/inheritance.h>
#include <bitsery/ext/pointer.h>
#include <bitsery/ext/std_smart_ptr.h>
#include <bitsery/traits/vector.h>
#include <cassert>
#include <memory>
#include <bitsery/bitsery.h>
#include <bitsery/traits/vector.h>
#include <bitsery/adapter/buffer.h>
#include <bitsery/ext/pointer.h>
#include <bitsery/ext/inheritance.h>
#include <bitsery/ext/std_smart_ptr.h>
//in order to work with polymorphic types, we need to describe few steps:
// 1) describe relationships between base and derived types
// this will allow to know what are possible types reachable from base class
// 2) bind serializer to base class
// this will allow to iterate through all types, and add serialization functions,
// without this step compiler would simply remove functions that are not bound at compile-time even it we use type at runtime.
// in order to work with polymorphic types, we need to describe few steps:
// 1) describe relationships between base and derived types
// this will allow to know what are possible types reachable from base class
// 2) bind serializer to base class
// this will allow to iterate through all types, and add serialization
// functions, without this step compiler would simply remove functions that are
// not bound at compile-time even it we use type at runtime.
using bitsery::ext::BaseClass;
using bitsery::ext::PointerObserver;
using bitsery::ext::StdSmartPtr;
//define our data structures
struct Color {
float r{}, g{}, b{};
bool operator == (const Color& o) const {
return std::tie(r, g, b) ==
std::tie(o.r, o.g, o.b);
}
// define our data structures
struct Color
{
float r{}, g{}, b{};
bool operator==(const Color& o) const
{
return std::tie(r, g, b) == std::tie(o.r, o.g, o.b);
}
};
struct Shape {
Color clr{};
virtual ~Shape() = 0;
struct Shape
{
Color clr{};
virtual ~Shape() = 0;
};
Shape::~Shape() = default;
struct Circle : Shape {
int32_t radius{};
bool operator == (const Circle& o) const {
return std::tie(radius, clr) ==
std::tie(o.radius, o.clr);
}
struct Circle : Shape
{
int32_t radius{};
bool operator==(const Circle& o) const
{
return std::tie(radius, clr) == std::tie(o.radius, o.clr);
}
};
struct Rectangle : Shape {
int32_t width{};
int32_t height{};
bool operator == (const Rectangle& o) const {
return std::tie(width, height, clr) ==
std::tie(o.width, o.height, o.clr);
}
struct Rectangle : Shape
{
int32_t width{};
int32_t height{};
bool operator==(const Rectangle& o) const
{
return std::tie(width, height, clr) == std::tie(o.width, o.height, o.clr);
}
};
struct RoundedRectangle : Rectangle {
int32_t radius{};
bool operator == (const RoundedRectangle& o) const {
return std::tie(radius, static_cast<const Rectangle&>(*this)) ==
std::tie(o.radius, static_cast<const Rectangle&>(o));
}
struct RoundedRectangle : Rectangle
{
int32_t radius{};
bool operator==(const RoundedRectangle& o) const
{
return std::tie(radius, static_cast<const Rectangle&>(*this)) ==
std::tie(o.radius, static_cast<const Rectangle&>(o));
}
};
//define serialization functions
// define serialization functions
template<typename S>
void serialize(S &s, Color &o) {
//in real world scenario, it might be possible to serialize this using ValueRange, to map values in smaller space
//but for the sake of this example keep it simple
s.value4b(o.r);
s.value4b(o.g);
s.value4b(o.b);
void
serialize(S& s, Color& o)
{
// in real world scenario, it might be possible to serialize this using
// ValueRange, to map values in smaller space but for the sake of this example
// keep it simple
s.value4b(o.r);
s.value4b(o.g);
s.value4b(o.b);
}
template<typename S>
void serialize(S &s, Shape &o) {
s.object(o.clr);
void
serialize(S& s, Shape& o)
{
s.object(o.clr);
}
template<typename S>
void serialize(S &s, Circle &o) {
s.ext(o, bitsery::ext::BaseClass<Shape>{});
s.value4b(o.radius);
void
serialize(S& s, Circle& o)
{
s.ext(o, bitsery::ext::BaseClass<Shape>{});
s.value4b(o.radius);
}
template<typename S>
void serialize(S &s, Rectangle &o) {
s.ext(o, bitsery::ext::BaseClass<Shape>{});
s.value4b(o.width);
s.value4b(o.height);
void
serialize(S& s, Rectangle& o)
{
s.ext(o, bitsery::ext::BaseClass<Shape>{});
s.value4b(o.width);
s.value4b(o.height);
}
template<typename S>
void serialize(S &s, RoundedRectangle &o) {
s.ext(o, bitsery::ext::BaseClass<Rectangle>{});
s.value4b(o.radius);
void
serialize(S& s, RoundedRectangle& o)
{
s.ext(o, bitsery::ext::BaseClass<Rectangle>{});
s.value4b(o.radius);
}
//define our test structure
struct SomeShapes {
std::vector<std::shared_ptr<Shape>> sharedList;
std::unique_ptr<Shape> uniquePtr;
//weak ptr and refPtr will point to sharedList
std::weak_ptr<Shape> weakPtr;
Shape* refPtr;
// define our test structure
struct SomeShapes
{
std::vector<std::shared_ptr<Shape>> sharedList;
std::unique_ptr<Shape> uniquePtr;
// weak ptr and refPtr will point to sharedList
std::weak_ptr<Shape> weakPtr;
Shape* refPtr;
};
//creates object, and populates some data
SomeShapes createData() {
SomeShapes data{};
{
auto tmp = new RoundedRectangle{};
tmp->height = 151572;
tmp->width = 488795;
tmp->radius = 898;
tmp->clr.r = 0.5f;
tmp->clr.g = 1.0f;
tmp->clr.b = 1.0f;
data.uniquePtr.reset(tmp);
}
{
auto tmp = new Circle{};
tmp->radius = 75987;
tmp->clr.r = 0.5f;
tmp->clr.g = 0.0f;
tmp->clr.b = 1.0f;
data.sharedList.emplace_back(tmp);
}
{
auto tmp = new Rectangle{};
tmp->height = 15157;
tmp->width = 48879;
tmp->clr.r = 1.0f;
tmp->clr.g = 0.0f;
tmp->clr.b = 0.0f;
data.sharedList.emplace_back(tmp);
}
data.weakPtr = data.sharedList[0];
data.refPtr = data.sharedList[1].get();
// creates object, and populates some data
SomeShapes
createData()
{
SomeShapes data{};
{
auto tmp = new RoundedRectangle{};
tmp->height = 151572;
tmp->width = 488795;
tmp->radius = 898;
tmp->clr.r = 0.5f;
tmp->clr.g = 1.0f;
tmp->clr.b = 1.0f;
data.uniquePtr.reset(tmp);
}
{
auto tmp = new Circle{};
tmp->radius = 75987;
tmp->clr.r = 0.5f;
tmp->clr.g = 0.0f;
tmp->clr.b = 1.0f;
data.sharedList.emplace_back(tmp);
}
{
auto tmp = new Rectangle{};
tmp->height = 15157;
tmp->width = 48879;
tmp->clr.r = 1.0f;
tmp->clr.g = 0.0f;
tmp->clr.b = 0.0f;
data.sharedList.emplace_back(tmp);
}
data.weakPtr = data.sharedList[0];
data.refPtr = data.sharedList[1].get();
return data;
return data;
}
template<typename S>
void serialize(S &s, SomeShapes &o) {
s.ext(o.uniquePtr, StdSmartPtr{});
// to make things more interesting first serialize weakPtr and refPtr,
// even though objects that weakPtr and refPtr is serialized later,
// bitsery will work regardless
s.ext(o.weakPtr, StdSmartPtr{});
s.ext(o.refPtr, PointerObserver{});
s.container(o.sharedList, 100, [](S& s, std::shared_ptr<Shape> &item) {
s.ext(item, StdSmartPtr{});
});
void
serialize(S& s, SomeShapes& o)
{
s.ext(o.uniquePtr, StdSmartPtr{});
// to make things more interesting first serialize weakPtr and refPtr,
// even though objects that weakPtr and refPtr is serialized later,
// bitsery will work regardless
s.ext(o.weakPtr, StdSmartPtr{});
s.ext(o.refPtr, PointerObserver{});
s.container(o.sharedList, 100, [](S& s, std::shared_ptr<Shape>& item) {
s.ext(item, StdSmartPtr{});
});
}
// STEP 1
// define relationships between base and derived classes
namespace bitsery {
namespace ext {
namespace ext {
//for each base class define DIRECTLY derived classes
//e.g. PolymorphicBaseClass<Shape> : PolymorphicDerivedClasses<Circle, Rectangle, RoundedRectangle>
// is incorrect, because RoundedRectangle does not directly derive from Shape
template<>
struct PolymorphicBaseClass<Shape> : PolymorphicDerivedClasses<Circle, Rectangle> {
};
// for each base class define DIRECTLY derived classes
// e.g. PolymorphicBaseClass<Shape> : PolymorphicDerivedClasses<Circle,
// Rectangle, RoundedRectangle>
// is incorrect, because RoundedRectangle does not directly derive from Shape
template<>
struct PolymorphicBaseClass<Shape>
: PolymorphicDerivedClasses<Circle, Rectangle>
{};
template<>
struct PolymorphicBaseClass<Rectangle> : PolymorphicDerivedClasses<RoundedRectangle> {
};
}
template<>
struct PolymorphicBaseClass<Rectangle>
: PolymorphicDerivedClasses<RoundedRectangle>
{};
}
}
// convenient type that stores all our types, so that we could easily register and
// also it automatically ensures, that classes is registered in the same order for serialization and deserialization
using MyPolymorphicClassesForRegistering = bitsery::ext::PolymorphicClassesList<Shape>;
// convenient type that stores all our types, so that we could easily register
// and also it automatically ensures, that classes is registered in the same
// order for serialization and deserialization
using MyPolymorphicClassesForRegistering =
bitsery::ext::PolymorphicClassesList<Shape>;
//some helper types
// some helper types
using Buffer = std::vector<uint8_t>;
using Writer = bitsery::OutputBufferAdapter<Buffer>;
using Reader = bitsery::InputBufferAdapter<Buffer>;
//we need to define few things in order to work with polymorphism
//1) we need pointer linking context to work with pointers
//2) we need polymorphic context to be able to work with polymorphic types
using TContext = std::tuple<
bitsery::ext::PointerLinkingContext,
bitsery::ext::PolymorphicContext<bitsery::ext::StandardRTTI>>;
//NOTE:
// RTTI can be customizable, if you can't use dynamic_cast and typeid, and have 'custom' solution
// we need to define few things in order to work with polymorphism
// 1) we need pointer linking context to work with pointers
// 2) we need polymorphic context to be able to work with polymorphic types
using TContext =
std::tuple<bitsery::ext::PointerLinkingContext,
bitsery::ext::PolymorphicContext<bitsery::ext::StandardRTTI>>;
// NOTE:
// RTTI can be customizable, if you can't use dynamic_cast and typeid, and have
// 'custom' solution
using MySerializer = bitsery::Serializer<Writer, TContext>;
using MyDeserializer = bitsery::Deserializer<Reader, TContext>;
//checks if deserialized data is equal
void assertSameShapes(const SomeShapes &data, const SomeShapes &res) {
{
auto d = dynamic_cast<RoundedRectangle *>(data.uniquePtr.get());
auto r = dynamic_cast<RoundedRectangle *>(res.uniquePtr.get());
assert(r != nullptr);
assert(*d == *r);
}
{
auto d = dynamic_cast<Circle *>(data.sharedList[0].get());
auto r = dynamic_cast<Circle *>(res.sharedList[0].get());
assert(r != nullptr);
assert(*d == *r);
}
{
auto d = dynamic_cast<Rectangle *>(data.sharedList[1].get());
auto r = dynamic_cast<Rectangle *>(res.sharedList[1].get());
assert(r != nullptr);
assert(*d == *r);
}
assert(res.weakPtr.lock().get() == res.sharedList[0].get());
assert(res.refPtr == res.sharedList[1].get());
// checks if deserialized data is equal
void
assertSameShapes(const SomeShapes& data, const SomeShapes& res)
{
{
auto d = dynamic_cast<RoundedRectangle*>(data.uniquePtr.get());
auto r = dynamic_cast<RoundedRectangle*>(res.uniquePtr.get());
assert(r != nullptr);
assert(*d == *r);
}
{
auto d = dynamic_cast<Circle*>(data.sharedList[0].get());
auto r = dynamic_cast<Circle*>(res.sharedList[0].get());
assert(r != nullptr);
assert(*d == *r);
}
{
auto d = dynamic_cast<Rectangle*>(data.sharedList[1].get());
auto r = dynamic_cast<Rectangle*>(res.sharedList[1].get());
assert(r != nullptr);
assert(*d == *r);
}
assert(res.weakPtr.lock().get() == res.sharedList[0].get());
assert(res.refPtr == res.sharedList[1].get());
}
int main() {
int
main()
{
auto data = createData();
auto data = createData();
//create buffer to store data
Buffer buffer{};
size_t writtenSize{};
// we will not use quickSerialization/Deserialization functions to show, that we need to register polymorphic classes, explicitly
{
// create buffer to store data
Buffer buffer{};
size_t writtenSize{};
// we will not use quickSerialization/Deserialization functions to show, that
// we need to register polymorphic classes, explicitly
{
//STEP 2
// before start serialization/deserialization,
// bind it with base polymorphic types, it will go through all reachable classes that is defined in first step.
// NOTE: you dont need to add Rectangle to reach for RoundedRectangle
TContext ctx{};
std::get<1>(ctx).registerBasesList<MySerializer>(MyPolymorphicClassesForRegistering{});
//create writer and serialize
MySerializer ser{ctx, buffer};
ser.object(data);
ser.adapter().flush();
writtenSize = ser.adapter().writtenBytesCount();
// STEP 2
// before start serialization/deserialization,
// bind it with base polymorphic types, it will go through all reachable
// classes that is defined in first step. NOTE: you dont need to add
// Rectangle to reach for RoundedRectangle
TContext ctx{};
std::get<1>(ctx).registerBasesList<MySerializer>(
MyPolymorphicClassesForRegistering{});
// create writer and serialize
MySerializer ser{ ctx, buffer };
ser.object(data);
ser.adapter().flush();
writtenSize = ser.adapter().writtenBytesCount();
//make sure that pointer linking context is valid
//this ensures that all non-owning pointers points to data that has been serialized,
//so we can successfully reconstruct pointers after deserialization
assert(std::get<0>(ctx).isValid());
}
SomeShapes res{};
{
TContext ctx{};
std::get<1>(ctx).registerBasesList<MyDeserializer>(MyPolymorphicClassesForRegistering{});
//deserialize our data
MyDeserializer des{ctx, buffer.begin(), writtenSize};
des.object(res);
assert(des.adapter().error() == bitsery::ReaderError::NoError && des.adapter().isCompletedSuccessfully());
//also check for dangling pointers, after deserialization
assert(std::get<0>(ctx).isValid());
// clear shared state from pointer linking context,
// it is only required if there are any pointers that manage shared state, e.g. std::shared_ptr
assert(res.weakPtr.use_count() == 2);//one in sharedList and one in pointer linking context
std::get<0>(ctx).clearSharedState();
assert(res.weakPtr.use_count() == 1);
}
assertSameShapes(data, res);
return 0;
// make sure that pointer linking context is valid
// this ensures that all non-owning pointers points to data that has been
// serialized, so we can successfully reconstruct pointers after
// deserialization
assert(std::get<0>(ctx).isValid());
}
SomeShapes res{};
{
TContext ctx{};
std::get<1>(ctx).registerBasesList<MyDeserializer>(
MyPolymorphicClassesForRegistering{});
// deserialize our data
MyDeserializer des{ ctx, buffer.begin(), writtenSize };
des.object(res);
assert(des.adapter().error() == bitsery::ReaderError::NoError &&
des.adapter().isCompletedSuccessfully());
// also check for dangling pointers, after deserialization
assert(std::get<0>(ctx).isValid());
// clear shared state from pointer linking context,
// it is only required if there are any pointers that manage shared state,
// e.g. std::shared_ptr
assert(res.weakPtr.use_count() ==
2); // one in sharedList and one in pointer linking context
std::get<0>(ctx).clearSharedState();
assert(res.weakPtr.use_count() == 1);
}
assertSameShapes(data, res);
return 0;
}

3
format.sh Executable file
View File

@@ -0,0 +1,3 @@
find . -regex '.*\.\(cpp\|hpp\|cu\|c\|h\)' -exec clang-format -style=file -i {} \;

View File

@@ -1,334 +1,304 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_ADAPTER_BUFFER_H
#define BITSERY_ADAPTER_BUFFER_H
#include "../details/adapter_common.h"
#include "../bitsery.h"
#include "../details/adapter_bit_packing.h"
#include "../traits/core/traits.h"
#include <algorithm>
#include <cassert>
#include <cstring>
namespace bitsery {
template<typename Buffer, typename Config = DefaultConfig>
class InputBufferAdapter: public details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer,Config>> {
public:
friend details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer,Config>>;
using TConfig = Config;
using TIterator = typename traits::BufferAdapterTraits<typename std::remove_const<Buffer>::type>::TConstIterator;
using TValue = typename traits::BufferAdapterTraits<typename std::remove_const<Buffer>::type>::TValue;
static_assert(details::IsDefined<TValue>::value,
"Please define BufferAdapterTraits or include from <bitsery/traits/...>");
static_assert(traits::ContainerTraits<typename std::remove_const<Buffer>::type>::isContiguous,
"BufferAdapter only works with contiguous containers");
static_assert(sizeof(TValue) == 1, "BufferAdapter underlying type must be 1byte.");
template<typename Buffer, typename Config = DefaultConfig>
class InputBufferAdapter
: public details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer, Config>>
{
public:
friend details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer, Config>>;
InputBufferAdapter(TIterator beginIt, size_t size)
: _beginIt{beginIt},
_currOffset{0},
_endReadOffset{size},
_bufferSize{size} {
};
using BitPackingEnabled =
details::InputAdapterBitPackingWrapper<InputBufferAdapter<Buffer, Config>>;
using TConfig = Config;
using TIterator = typename traits::BufferAdapterTraits<
typename std::remove_const<Buffer>::type>::TConstIterator;
using TValue = typename traits::BufferAdapterTraits<
typename std::remove_const<Buffer>::type>::TValue;
static_assert(
details::IsDefined<TValue>::value,
"Please define BufferAdapterTraits or include from <bitsery/traits/...>");
static_assert(traits::ContainerTraits<
typename std::remove_const<Buffer>::type>::isContiguous,
"BufferAdapter only works with contiguous containers");
static_assert(sizeof(TValue) == 1,
"BufferAdapter underlying type must be 1byte.");
InputBufferAdapter(TIterator beginIt, TIterator endIt)
:InputBufferAdapter(beginIt, static_cast<size_t>(std::distance(beginIt, endIt))) {
}
InputBufferAdapter(TIterator beginIt, size_t size)
: _beginIt{ beginIt }
, _currOffset{ 0 }
, _endReadOffset{ size }
, _bufferSize{ size } {};
InputBufferAdapter(const InputBufferAdapter&) = delete;
InputBufferAdapter& operator=(const InputBufferAdapter&) = delete;
InputBufferAdapter(TIterator beginIt, TIterator endIt)
: InputBufferAdapter(beginIt,
static_cast<size_t>(std::distance(beginIt, endIt)))
{
}
InputBufferAdapter(InputBufferAdapter&&) = default;
InputBufferAdapter& operator = (InputBufferAdapter&&) = default;
InputBufferAdapter(const InputBufferAdapter&) = delete;
InputBufferAdapter& operator=(const InputBufferAdapter&) = delete;
void currentReadPos(size_t pos) {
currentReadPosChecked(pos, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
InputBufferAdapter(InputBufferAdapter&&) = default;
InputBufferAdapter& operator=(InputBufferAdapter&&) = default;
size_t currentReadPos() const {
return currentReadPosChecked(std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void currentReadPos(size_t pos)
{
currentReadPosChecked(
pos, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void currentReadEndPos(size_t pos) {
// assert that CheckAdapterErrors is enabled, otherwise it will simply will not work even if data and buffer is not corrupted
static_assert(Config::CheckAdapterErrors, "Please enable CheckAdapterErrors to use this functionality.");
if (_bufferSize >= pos && error() == ReaderError::NoError) {
_overflowOnReadEndPos = pos == 0;
if (pos == 0)
pos = _bufferSize;
_endReadOffset = pos;
} else {
error(ReaderError::DataOverflow);
}
}
size_t currentReadPos() const
{
return currentReadPosChecked(
std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
size_t currentReadEndPos() const {
if (_overflowOnReadEndPos)
return 0;
return _endReadOffset;
}
void currentReadEndPos(size_t pos)
{
// assert that CheckAdapterErrors is enabled, otherwise it will simply will
// not work even if data and buffer is not corrupted
static_assert(
Config::CheckAdapterErrors,
"Please enable CheckAdapterErrors to use this functionality.");
if (_bufferSize >= pos && error() == ReaderError::NoError) {
_overflowOnReadEndPos = pos == 0;
if (pos == 0)
pos = _bufferSize;
_endReadOffset = pos;
} else {
error(ReaderError::DataOverflow);
}
}
ReaderError error() const {
return _currOffset <= _endReadOffset
? ReaderError::NoError
: static_cast<ReaderError>(_currOffset - _endReadOffset);
}
size_t currentReadEndPos() const
{
if (_overflowOnReadEndPos)
return 0;
return _endReadOffset;
}
void error(ReaderError error) {
if (_currOffset <= _endReadOffset) {
_endReadOffset = 0;
_bufferSize = 0;
_currOffset = static_cast<size_t>(error);
}
}
ReaderError error() const
{
return _currOffset <= _endReadOffset
? ReaderError::NoError
: static_cast<ReaderError>(_currOffset - _endReadOffset);
}
bool isCompletedSuccessfully() const {
return _currOffset == _bufferSize;
}
void error(ReaderError error)
{
if (_currOffset <= _endReadOffset) {
_endReadOffset = 0;
_bufferSize = 0;
_currOffset = static_cast<size_t>(error);
}
}
private:
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
bool isCompletedSuccessfully() const { return _currOffset == _bufferSize; }
template <size_t SIZE>
void readInternalValue(TValue *data) {
readInternalValueChecked<SIZE>(data, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
private:
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
void readInternalBuffer(TValue *data, size_t size) {
readInternalBufferChecked(data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
template<size_t SIZE>
void readInternalValue(TValue* data)
{
readInternalImpl(
data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
template <size_t SIZE>
void readInternalValueChecked(TValue *data, std::false_type) {
const size_t newOffset = _currOffset + SIZE;
assert(newOffset <= _endReadOffset);
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), SIZE, data);
_currOffset = newOffset;
}
void readInternalBuffer(TValue* data, size_t size)
{
readInternalImpl(
data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
template <size_t SIZE>
void readInternalValueChecked(TValue *data, std::true_type) {
const size_t newOffset = _currOffset + SIZE;
if (newOffset <= _endReadOffset) {
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), SIZE, data);
_currOffset = newOffset;
} else {
//set everything to zeros
std::memset(data, 0, SIZE);
if (_overflowOnReadEndPos)
error(ReaderError::DataOverflow);
}
}
void readInternalImpl(TValue* data, size_t size, std::false_type)
{
const size_t newOffset = _currOffset + size;
assert(newOffset <= _endReadOffset);
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
_currOffset = newOffset;
}
void readInternalBufferChecked(TValue *data, size_t size, std::false_type) {
const size_t newOffset = _currOffset + size;
assert(newOffset <= _endReadOffset);
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
_currOffset = newOffset;
}
void readInternalImpl(TValue* data, size_t size, std::true_type)
{
const size_t newOffset = _currOffset + size;
if (newOffset <= _endReadOffset) {
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
_currOffset = newOffset;
} else {
// set everything to zeros
std::memset(data, 0, size);
if (_overflowOnReadEndPos)
error(ReaderError::DataOverflow);
}
}
void readInternalBufferChecked(TValue *data, size_t size, std::true_type) {
const size_t newOffset = _currOffset + size;
if (newOffset <= _endReadOffset) {
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
_currOffset = newOffset;
} else {
//set everything to zeros
std::memset(data, 0, size);
if (_overflowOnReadEndPos)
error(ReaderError::DataOverflow);
}
}
void currentReadPosChecked(size_t pos, std::true_type)
{
if (_bufferSize >= pos && error() == ReaderError::NoError) {
_currOffset = pos;
} else {
error(ReaderError::DataOverflow);
}
}
void currentReadPosChecked(size_t pos, std::true_type) {
if (_bufferSize >= pos && error() == ReaderError::NoError) {
_currOffset = pos;
} else {
error(ReaderError::DataOverflow);
}
}
void currentReadPosChecked(size_t pos, std::false_type) { _currOffset = pos; }
void currentReadPosChecked(size_t pos, std::false_type) {
_currOffset = pos;
}
size_t currentReadPosChecked(std::true_type) const
{
return error() == ReaderError::NoError ? _currOffset : 0;
}
size_t currentReadPosChecked(std::true_type) const {
return error() == ReaderError::NoError ? _currOffset : 0;
}
size_t currentReadPosChecked(std::false_type) const { return _currOffset; }
size_t currentReadPosChecked(std::false_type) const {
return _currOffset;
}
TIterator _beginIt;
size_t _currOffset;
size_t _endReadOffset;
size_t _bufferSize;
bool _overflowOnReadEndPos = true;
};
template<typename Buffer, typename Config = DefaultConfig>
class OutputBufferAdapter
: public details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer, Config>>
{
public:
friend details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer, Config>>;
TIterator _beginIt;
size_t _currOffset;
size_t _endReadOffset;
size_t _bufferSize;
bool _overflowOnReadEndPos = true;
};
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<
OutputBufferAdapter<Buffer, Config>>;
using TConfig = Config;
using TIterator = typename traits::BufferAdapterTraits<Buffer>::TIterator;
using TValue = typename traits::BufferAdapterTraits<Buffer>::TValue;
template<typename Buffer, typename Config = DefaultConfig>
class OutputBufferAdapter: public details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer,Config>> {
public:
friend details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer,Config>>;
using TConfig = Config;
using TIterator = typename traits::BufferAdapterTraits<Buffer>::TIterator;
using TValue = typename traits::BufferAdapterTraits<Buffer>::TValue;
static_assert(
details::IsDefined<TValue>::value,
"Please define BufferAdapterTraits or include from <bitsery/traits/...>");
static_assert(traits::ContainerTraits<Buffer>::isContiguous,
"BufferAdapter only works with contiguous containers");
static_assert(sizeof(TValue) == 1,
"BufferAdapter underlying type must be 1byte.");
static_assert(details::IsDefined<TValue>::value,
"Please define BufferAdapterTraits or include from <bitsery/traits/...>");
static_assert(traits::ContainerTraits<Buffer>::isContiguous,
"BufferAdapter only works with contiguous containers");
static_assert(sizeof(TValue) == 1, "BufferAdapter underlying type must be 1byte.");
OutputBufferAdapter(Buffer& buffer)
: _buffer{ std::addressof(buffer) }
, _beginIt{ std::begin(buffer) }
, _bufferSize{ traits::ContainerTraits<Buffer>::size(buffer) }
{
}
OutputBufferAdapter(Buffer &buffer)
: _buffer{std::addressof(buffer)},
_beginIt{std::begin(buffer)} {
init(TResizable{});
}
OutputBufferAdapter(const OutputBufferAdapter&) = delete;
OutputBufferAdapter& operator=(const OutputBufferAdapter&) = delete;
OutputBufferAdapter(OutputBufferAdapter&&) = default;
OutputBufferAdapter& operator=(OutputBufferAdapter&&) = default;
OutputBufferAdapter(const OutputBufferAdapter&) = delete;
OutputBufferAdapter& operator=(const OutputBufferAdapter&) = delete;
OutputBufferAdapter(OutputBufferAdapter&&) = default;
OutputBufferAdapter& operator = (OutputBufferAdapter&&) = default;
void currentWritePos(size_t pos)
{
const auto maxPos = _currOffset > pos ? _currOffset : pos;
if (maxPos > _biggestCurrentPos) {
_biggestCurrentPos = maxPos;
}
maybeResize(pos, TResizable{});
_currOffset = pos;
}
void currentWritePos(size_t pos) {
const auto maxPos = _currOffset > pos ? _currOffset : pos;
if (maxPos > _biggestCurrentPos) {
_biggestCurrentPos = maxPos;
}
setCurrentWritePos(pos, TResizable{});
}
size_t currentWritePos() const { return _currOffset; }
size_t currentWritePos() const {
return _currOffset;
}
void flush()
{
// this function might be useful for stream adapters
}
void flush() {
//this function might be useful for stream adapters
}
size_t writtenBytesCount() const
{
return _currOffset > _biggestCurrentPos ? _currOffset : _biggestCurrentPos;
}
size_t writtenBytesCount() const {
return _currOffset > _biggestCurrentPos ? _currOffset : _biggestCurrentPos;
}
private:
using TResizable =
std::integral_constant<bool, traits::ContainerTraits<Buffer>::isResizable>;
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
private:
using TResizable = std::integral_constant<bool, traits::ContainerTraits<Buffer>::isResizable>;
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
template<size_t SIZE>
void writeInternalValue(const TValue* data)
{
writeInternalImpl(data, SIZE);
}
template <size_t SIZE>
void writeInternalValue(const TValue *data) {
writeInternalValueImpl<SIZE>(data, TResizable{});
}
void writeInternalBuffer(const TValue* data, size_t size)
{
writeInternalImpl(data, size);
}
void writeInternalBuffer(const TValue *data, size_t size) {
writeInternalBufferImpl(data, size, TResizable{});
}
Buffer* _buffer;
TIterator _beginIt;
size_t _currOffset{ 0 };
size_t _bufferSize{ 0 };
size_t _biggestCurrentPos{ 0 };
Buffer* _buffer;
TIterator _beginIt;
size_t _currOffset{0};
size_t _bufferSize{0};
size_t _biggestCurrentPos{0};
void maybeResize(size_t newOffset, std::true_type)
{
if (newOffset > _bufferSize)
BITSERY_UNLIKELY
{
doResize(newOffset);
}
}
/*
* resizable buffer
*/
void maybeResize(size_t newOffset, std::false_type)
{
static_cast<void>(newOffset);
assert(newOffset <= _bufferSize);
}
void init(std::true_type) {
//resize buffer immediately, because we need output iterator at valid position
if (traits::ContainerTraits<Buffer>::size(*_buffer) == 0u) {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
}
updateIteratorAndSize();
}
void writeInternalImpl(const TValue* data, size_t size)
{
const size_t newOffset = _currOffset + size;
maybeResize(newOffset, TResizable{});
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
}
template <size_t SIZE>
void writeInternalValueImpl(const TValue *data, std::true_type) {
const size_t newOffset = _currOffset + SIZE;
if (newOffset <= _bufferSize) {
std::copy_n(data, SIZE, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
} else {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
updateIteratorAndSize();
writeInternalValueImpl<SIZE>(data, std::true_type{});
}
}
void writeInternalBufferImpl(const TValue *data, const size_t size, std::true_type) {
const size_t newOffset = _currOffset + size;
if (newOffset <= _bufferSize) {
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
} else {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
updateIteratorAndSize();
writeInternalBufferImpl(data, size, std::true_type{});
}
}
void setCurrentWritePos(size_t pos, std::true_type) {
if (pos <= _bufferSize) {
_currOffset = pos;
} else {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
updateIteratorAndSize();
setCurrentWritePos(pos, std::true_type{});
}
}
/*
* non resizable buffer
*/
void init(std::false_type) {
updateIteratorAndSize();
}
template <size_t SIZE>
void writeInternalValueImpl(const TValue *data, std::false_type) {
const size_t newOffset = _currOffset + SIZE;
assert(newOffset <= _bufferSize);
std::copy_n(data, SIZE, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
}
void writeInternalBufferImpl(const TValue *data, size_t size, std::false_type) {
const size_t newOffset = _currOffset + size;
assert(newOffset <= _bufferSize);
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
}
void setCurrentWritePos(size_t pos, std::false_type) {
assert(pos <= _bufferSize);
_currOffset = pos;
}
void updateIteratorAndSize() {
_beginIt = std::begin(*_buffer);
_bufferSize = traits::ContainerTraits<Buffer>::size(*_buffer);
}
};
BITSERY_NOINLINE void doResize(size_t newOffset)
{
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(
*_buffer, _currOffset, newOffset);
_beginIt = std::begin(*_buffer);
_bufferSize = traits::ContainerTraits<Buffer>::size(*_buffer);
}
};
}
#endif //BITSERY_ADAPTER_BUFFER_H
#endif // BITSERY_ADAPTER_BUFFER_H

View File

@@ -1,99 +1,88 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 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:
// 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 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.
// 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_ADAPTER_MEASURE_SIZE_H
#define BITSERY_ADAPTER_MEASURE_SIZE_H
#include "../details/adapter_bit_packing.h"
#include <cstddef>
#include <type_traits>
#include "../details/adapter_common.h"
namespace bitsery {
template<typename Config>
class BasicMeasureSize
{
public:
using BitPackingEnabled =
details::BasicMeasureSizeBitPackingWrapper<BasicMeasureSize<Config>>;
using TConfig = Config;
using TValue = void;
template<typename Config>
class BasicMeasureSize {
public:
template<size_t SIZE, typename T>
void writeBytes(const T&)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
_currPos += SIZE;
}
static constexpr bool BitPackingEnabled = true;
using TConfig = Config;
using TValue = void;
template<size_t SIZE, typename T>
void writeBuffer(const T*, size_t count)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
_currPos += SIZE * count;
}
template<size_t SIZE, typename T>
void writeBytes(const T&) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
_currPosBits += details::BitsSize<T>::value;
}
void currentWritePos(size_t pos)
{
const auto maxPos = _currPos > pos ? _currPos : pos;
if (maxPos > _biggestCurrentPos) {
_biggestCurrentPos = maxPos;
}
_currPos = pos;
}
template<size_t SIZE, typename T>
void writeBuffer(const T*, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
_currPosBits += details::BitsSize<T>::value * count;
}
size_t currentWritePos() const { return _currPos; }
template<typename T>
void writeBits(const T&, size_t bitsCount) {
static_assert(std::is_integral<T>() && std::is_unsigned<T>(), "");
assert(bitsCount <= details::BitsSize<T>::value);
_currPosBits += bitsCount;
}
void align() {}
void currentWritePos(size_t pos) {
align();
const auto newPos = pos * 8;
if (_currPosBits > newPos)
_prevLargestPos = _currPosBits;
_currPosBits = newPos;
}
void flush() {}
size_t currentWritePos() const {
return _currPosBits / 8;
}
// get size in bytes
size_t writtenBytesCount() const
{
return _currPos > _biggestCurrentPos ? _currPos : _biggestCurrentPos;
}
void align() {
auto _scratch = (_currPosBits % 8);
_currPosBits += (8 - _scratch) % 8;
}
private:
size_t _biggestCurrentPos{};
size_t _currPos{};
};
void flush() {
align();
}
//get size in bytes
size_t writtenBytesCount() const {
const auto max = _currPosBits > _prevLargestPos ? _currPosBits : _prevLargestPos;
return max / 8;
}
private:
size_t _prevLargestPos{};
size_t _currPosBits{};
};
//helper type for default config
using MeasureSize = BasicMeasureSize<DefaultConfig>;
// helper type for default config
using MeasureSize = BasicMeasureSize<DefaultConfig>;
}
#endif //BITSERY_ADAPTER_MEASURE_SIZE_H
#endif // BITSERY_ADAPTER_MEASURE_SIZE_H

View File

@@ -1,298 +1,376 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_ADAPTER_STREAM_H
#define BITSERY_ADAPTER_STREAM_H
#include "../details/adapter_common.h"
#include "../details/adapter_bit_packing.h"
#include "../traits/array.h"
#include <algorithm>
#include <cassert>
#include <ios>
#include <limits>
namespace bitsery {
template <typename TChar, typename Config, typename CharTraits>
class BasicInputStreamAdapter: public details::InputAdapterBaseCRTP<BasicInputStreamAdapter<TChar, Config, CharTraits>> {
public:
friend details::InputAdapterBaseCRTP<BasicInputStreamAdapter<TChar, Config, CharTraits>>;
using TConfig = Config;
using TValue = TChar;
template<typename TChar, typename Config, typename CharTraits>
class BasicInputStreamAdapter
: public details::InputAdapterBaseCRTP<
BasicInputStreamAdapter<TChar, Config, CharTraits>>
{
public:
friend details::InputAdapterBaseCRTP<
BasicInputStreamAdapter<TChar, Config, CharTraits>>;
BasicInputStreamAdapter(std::basic_ios<TChar, CharTraits>& istream)
:_ios{std::addressof(istream)} {}
using BitPackingEnabled = details::InputAdapterBitPackingWrapper<
BasicInputStreamAdapter<TChar, Config, CharTraits>>;
using TConfig = Config;
using TValue = TChar;
BasicInputStreamAdapter(const BasicInputStreamAdapter&) = delete;
BasicInputStreamAdapter& operator = (const BasicInputStreamAdapter&) = delete;
BasicInputStreamAdapter(std::basic_ios<TChar, CharTraits>& istream)
: _ios{ std::addressof(istream) }
{
}
BasicInputStreamAdapter(BasicInputStreamAdapter&&) = default;
BasicInputStreamAdapter& operator = (BasicInputStreamAdapter&&) = default;
BasicInputStreamAdapter(const BasicInputStreamAdapter&) = delete;
BasicInputStreamAdapter& operator=(const BasicInputStreamAdapter&) = delete;
void currentReadPos(size_t ) {
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
}
BasicInputStreamAdapter(BasicInputStreamAdapter&&) = default;
BasicInputStreamAdapter& operator=(BasicInputStreamAdapter&&) = default;
size_t currentReadPos() const {
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
return {};
}
void currentReadPos(size_t)
{
static_assert(std::is_void<TChar>::value,
"setting read position is not supported with StreamAdapter");
}
void currentReadEndPos(size_t ) {
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
}
size_t currentReadPos() const
{
static_assert(std::is_void<TChar>::value,
"setting read position is not supported with StreamAdapter");
return {};
}
size_t currentReadEndPos() const {
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
return {};
}
void currentReadEndPos(size_t)
{
static_assert(std::is_void<TChar>::value,
"setting read position is not supported with StreamAdapter");
}
ReaderError error() const {
return _err;
}
size_t currentReadEndPos() const
{
static_assert(std::is_void<TChar>::value,
"setting read position is not supported with StreamAdapter");
return {};
}
bool isCompletedSuccessfully() const {
if (error() == ReaderError::NoError) {
return _ios->rdbuf()->sgetc() == CharTraits::eof();
}
return false;
}
ReaderError error() const { return _err; }
void error(ReaderError error) {
if (_err == ReaderError::NoError) {
_err = error;
_zeroIfNoErrors = std::numeric_limits<size_t>::max();
}
}
bool isCompletedSuccessfully() const
{
if (error() == ReaderError::NoError) {
return _ios->rdbuf()->sgetc() == CharTraits::eof();
}
return false;
}
private:
void error(ReaderError error)
{
if (_err == ReaderError::NoError) {
_err = error;
_zeroIfNoErrors = std::numeric_limits<size_t>::max();
}
}
template <size_t SIZE>
void readInternalValue(TValue* data) {
readChecked(data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
private:
template<size_t SIZE>
void readInternalValue(TValue* data)
{
readChecked(
data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void readInternalBuffer(TValue* data, size_t size) {
readChecked(data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void readInternalBuffer(TValue* data, size_t size)
{
readChecked(
data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void readChecked(TValue* data, size_t size, std::true_type) {
if (size - static_cast<size_t>(_ios->rdbuf()->sgetn(data, static_cast<std::streamsize>(size))) != _zeroIfNoErrors) {
*data = {};
if (_zeroIfNoErrors == 0) {
error(_ios->rdstate() == std::ios_base::badbit
? ReaderError::ReadingError
: ReaderError::DataOverflow);
}
}
}
void readChecked(TValue* data, size_t size, std::true_type)
{
if (size - static_cast<size_t>(_ios->rdbuf()->sgetn(
data, static_cast<std::streamsize>(size))) !=
_zeroIfNoErrors) {
*data = {};
if (_zeroIfNoErrors == 0) {
error(_ios->rdstate() == std::ios_base::badbit
? ReaderError::ReadingError
: ReaderError::DataOverflow);
}
}
}
void readChecked(TValue* data, size_t size, std::false_type) {
_ios->rdbuf()->sgetn(data , static_cast<std::streamsize>(size));
}
void readChecked(TValue* data, size_t size, std::false_type)
{
_ios->rdbuf()->sgetn(data, static_cast<std::streamsize>(size));
}
std::basic_ios<TChar, CharTraits>* _ios;
size_t _zeroIfNoErrors{};
ReaderError _err = ReaderError::NoError;
};
std::basic_ios<TChar, CharTraits>* _ios;
size_t _zeroIfNoErrors{};
ReaderError _err = ReaderError::NoError;
};
template <typename TChar, typename Config, typename CharTraits>
class BasicOutputStreamAdapter: public details::OutputAdapterBaseCRTP<BasicOutputStreamAdapter<TChar, Config, CharTraits>> {
public:
friend details::OutputAdapterBaseCRTP<BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
using TConfig = Config;
using TValue = TChar;
template<typename TChar, typename Config, typename CharTraits>
class BasicOutputStreamAdapter
: public details::OutputAdapterBaseCRTP<
BasicOutputStreamAdapter<TChar, Config, CharTraits>>
{
public:
friend details::OutputAdapterBaseCRTP<
BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
BasicOutputStreamAdapter(std::basic_ostream<TChar, CharTraits>& ostream)
:_ostream{std::addressof(ostream)} {}
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<
BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
using TConfig = Config;
using TValue = TChar;
void currentWritePos(size_t ) {
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
}
BasicOutputStreamAdapter(std::basic_ostream<TChar, CharTraits>& ostream)
: _ostream{ std::addressof(ostream) }
{
}
size_t currentWritePos() const {
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
return {};
}
void currentWritePos(size_t)
{
static_assert(std::is_void<TChar>::value,
"setting write position is not supported with StreamAdapter");
}
void flush() {
_ostream->flush();
}
size_t currentWritePos() const
{
static_assert(std::is_void<TChar>::value,
"setting write position is not supported with StreamAdapter");
return {};
}
size_t writtenBytesCount() const {
static_assert(std::is_void<TChar>::value, "`writtenBytesCount` cannot be used with stream adapter");
//streaming doesn't return written bytes
return 0u;
}
void flush() { _ostream->flush(); }
private:
size_t writtenBytesCount() const
{
static_assert(std::is_void<TChar>::value,
"`writtenBytesCount` cannot be used with stream adapter");
// streaming doesn't return written bytes
return 0u;
}
template <size_t SIZE>
void writeInternalValue(const TValue* data) {
_ostream->rdbuf()->sputn( data , SIZE );
}
private:
template<size_t SIZE>
void writeInternalValue(const TValue* data)
{
_ostream->rdbuf()->sputn(data, SIZE);
}
void writeInternalBuffer(const TValue* data, size_t size) {
_ostream->rdbuf()->sputn( data , size );
}
void writeInternalBuffer(const TValue* data, size_t size)
{
_ostream->rdbuf()->sputn(data, size);
}
std::basic_ostream<TChar, CharTraits>* _ostream;
};
std::basic_ostream<TChar, CharTraits>* _ostream;
};
template <typename TChar, typename Config, typename CharTraits, typename TBuffer = std::array<TChar, 256>>
class BasicBufferedOutputStreamAdapter:
public details::OutputAdapterBaseCRTP<BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>> {
public:
friend details::OutputAdapterBaseCRTP<BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>;
using TConfig = Config;
using Buffer = TBuffer;
using BufferIt = typename traits::BufferAdapterTraits<TBuffer>::TIterator;
static_assert(details::IsDefined<BufferIt>::value, "Please define BufferAdapterTraits or include from <bitsery/traits/...> to use as buffer for BasicBufferedOutputStreamAdapter");
static_assert(traits::ContainerTraits<Buffer>::isContiguous, "BasicBufferedOutputStreamAdapter only works with contiguous containers");
using TValue = TChar;
template<typename TChar,
typename Config,
typename CharTraits,
typename TBuffer = std::array<TChar, 256>>
class BasicBufferedOutputStreamAdapter
: public details::OutputAdapterBaseCRTP<
BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>
{
public:
friend details::OutputAdapterBaseCRTP<
BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>;
//bufferSize is used when buffer is dynamically allocated
BasicBufferedOutputStreamAdapter(std::basic_ostream<TChar, CharTraits>& ostream, size_t bufferSize = 256)
:_ostream(std::addressof(ostream)),
_buf{},
_beginIt{std::begin(_buf)},
_currOffset{0}
{
init(bufferSize, TResizable{});
// buffer size must be atleast 16, because writeIntervalValue expect that at least one value fits to buffer.
assert(_bufferSize >= 16);
}
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<
BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>;
using TConfig = Config;
using Buffer = TBuffer;
using BufferIt = typename traits::BufferAdapterTraits<TBuffer>::TIterator;
static_assert(
details::IsDefined<BufferIt>::value,
"Please define BufferAdapterTraits or include from <bitsery/traits/...> to "
"use as buffer for BasicBufferedOutputStreamAdapter");
static_assert(
traits::ContainerTraits<Buffer>::isContiguous,
"BasicBufferedOutputStreamAdapter only works with contiguous containers");
using TValue = TChar;
//we need to explicitly declare move logic, because after move buffer might be invalidated
BasicBufferedOutputStreamAdapter(const BasicBufferedOutputStreamAdapter&) = delete;
BasicBufferedOutputStreamAdapter& operator = (const BasicBufferedOutputStreamAdapter&) = delete;
// bufferSize is used when buffer is dynamically allocated
BasicBufferedOutputStreamAdapter(
std::basic_ostream<TChar, CharTraits>& ostream,
size_t bufferSize = 256)
: _ostream(std::addressof(ostream))
, _buf{}
, _beginIt{ std::begin(_buf) }
, _currOffset{ 0 }
{
init(bufferSize, TResizable{});
// buffer size must be atleast 16, because writeIntervalValue expect that at
// least one value fits to buffer.
assert(_bufferSize >= 16);
}
BasicBufferedOutputStreamAdapter(BasicBufferedOutputStreamAdapter&& rhs)
: _ostream{rhs._ostream},
_buf{std::move(rhs._buf)},
_beginIt{std::begin(_buf)},
_currOffset{rhs._currOffset},
_bufferSize{rhs._bufferSize}
{
};
// we need to explicitly declare move logic, because after move buffer might
// be invalidated
BasicBufferedOutputStreamAdapter(const BasicBufferedOutputStreamAdapter&) =
delete;
BasicBufferedOutputStreamAdapter& operator=(
const BasicBufferedOutputStreamAdapter&) = delete;
BasicBufferedOutputStreamAdapter& operator = (BasicBufferedOutputStreamAdapter&& rhs) {
_ostream = rhs._ostream;
_buf = std::move(rhs._buf);
_beginIt = std::begin(_buf);
_currOffset = rhs._currOffset;
_bufferSize = rhs._bufferSize;
return *this;
};
BasicBufferedOutputStreamAdapter(BasicBufferedOutputStreamAdapter&& rhs)
: _ostream{ rhs._ostream }
, _buf{ std::move(rhs._buf) }
, _beginIt{ std::begin(_buf) }
, _currOffset{ rhs._currOffset }
, _bufferSize{ rhs._bufferSize } {};
void currentWritePos(size_t ) {
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
}
BasicBufferedOutputStreamAdapter& operator=(
BasicBufferedOutputStreamAdapter&& rhs)
{
_ostream = rhs._ostream;
_buf = std::move(rhs._buf);
_beginIt = std::begin(_buf);
_currOffset = rhs._currOffset;
_bufferSize = rhs._bufferSize;
return *this;
};
size_t currentWritePos() const {
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
return {};
}
void currentWritePos(size_t)
{
static_assert(std::is_void<TChar>::value,
"setting write position is not supported with StreamAdapter");
}
void flush() {
writeBufferToStream();
_ostream->flush();
}
size_t currentWritePos() const
{
static_assert(std::is_void<TChar>::value,
"setting write position is not supported with StreamAdapter");
return {};
}
size_t writtenBytesCount() const {
static_assert(std::is_void<TChar>::value, "`writtenBytesCount` cannot be used with stream adapter");
//streaming doesn't return written bytes
return 0u;
}
void flush()
{
writeBufferToStream();
_ostream->flush();
}
private:
using TResizable = std::integral_constant<bool, traits::ContainerTraits<TBuffer>::isResizable>;
using diff_t = typename std::iterator_traits<BufferIt>::difference_type;
size_t writtenBytesCount() const
{
static_assert(std::is_void<TChar>::value,
"`writtenBytesCount` cannot be used with stream adapter");
// streaming doesn't return written bytes
return 0u;
}
template <size_t SIZE>
void writeInternalValue(const TValue* data) {
auto newOffset = _currOffset + SIZE;
if (newOffset > _bufferSize) {
writeBufferToStream();
newOffset = SIZE;
}
std::copy_n(data, SIZE, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
}
private:
using TResizable =
std::integral_constant<bool, traits::ContainerTraits<TBuffer>::isResizable>;
using diff_t = typename std::iterator_traits<BufferIt>::difference_type;
void writeInternalBuffer(const TValue* data, size_t size) {
const auto newOffset = _currOffset + size;
if (newOffset <= _bufferSize) {
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
} else {
writeBufferToStream();
// write buffer directly to stream
_ostream->rdbuf()->sputn(data, size);
}
}
template<size_t SIZE>
void writeInternalValue(const TValue* data)
{
writeInternalImpl(data, SIZE);
}
void writeBufferToStream() {
_ostream->rdbuf()->sputn(std::addressof(*_beginIt), static_cast<std::streamsize>(_currOffset));
_currOffset = 0;
}
void writeInternalBuffer(const TValue* data, size_t size)
{
writeInternalImpl(data, size);
}
void init (size_t buffSize, std::true_type) {
// resize buffer
_bufferSize = buffSize;
_buf.resize(_bufferSize);
_beginIt = std::begin(_buf);
}
void init (size_t , std::false_type) {
// ignore buffer size parameter, and instead take actual buffer size
_bufferSize = traits::ContainerTraits<Buffer>::size(_buf);
}
void writeInternalImpl(const TValue* data, size_t size)
{
const auto newOffset = _currOffset + size;
if (newOffset <= _bufferSize) {
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
} else {
writeBufferToStream();
// write buffer directly to stream
_ostream->rdbuf()->sputn(data, static_cast<std::streamsize>(size));
}
}
std::basic_ostream<TChar, CharTraits>* _ostream;
TBuffer _buf;
BufferIt _beginIt;
size_t _currOffset;
size_t _bufferSize{0};
};
void writeBufferToStream()
{
_ostream->rdbuf()->sputn(std::addressof(*_beginIt),
static_cast<std::streamsize>(_currOffset));
_currOffset = 0;
}
template <typename TChar, typename Config, typename CharTraits>
class BasicIOStreamAdapter
: public BasicInputStreamAdapter<TChar, Config, CharTraits>
, public BasicOutputStreamAdapter<TChar, Config, CharTraits>
{
public:
using TValue = TChar;
void init(size_t buffSize, std::true_type)
{
// resize buffer
_bufferSize = buffSize;
_buf.resize(_bufferSize);
_beginIt = std::begin(_buf);
}
void init(size_t, std::false_type)
{
// ignore buffer size parameter, and instead take actual buffer size
_bufferSize = traits::ContainerTraits<Buffer>::size(_buf);
}
//both bases contain reference to same iostream, so no need to do anything
BasicIOStreamAdapter(std::basic_iostream<TChar, CharTraits>& iostream)
:BasicInputStreamAdapter<TChar, Config, CharTraits>{iostream}
,BasicOutputStreamAdapter<TChar, Config, CharTraits>{iostream}
{}
};
std::basic_ostream<TChar, CharTraits>* _ostream;
TBuffer _buf;
BufferIt _beginIt;
size_t _currOffset;
size_t _bufferSize{ 0 };
};
//helper types for most common implementations for std streams
using OutputStreamAdapter = BasicOutputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
using InputStreamAdapter = BasicInputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
using IOStreamAdapter = BasicIOStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
template<typename TChar, typename Config, typename CharTraits>
class BasicIOStreamAdapter
: public BasicInputStreamAdapter<TChar, Config, CharTraits>
, public BasicOutputStreamAdapter<TChar, Config, CharTraits>
{
public:
using TValue = TChar;
using OutputBufferedStreamAdapter = BasicBufferedOutputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
// both bases contain reference to same iostream, so no need to do anything
BasicIOStreamAdapter(std::basic_iostream<TChar, CharTraits>& iostream)
: BasicInputStreamAdapter<TChar, Config, CharTraits>{ iostream }
, BasicOutputStreamAdapter<TChar, Config, CharTraits>{ iostream }
{
}
};
// helper types for most common implementations for std streams
using OutputStreamAdapter =
BasicOutputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
using InputStreamAdapter =
BasicInputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
using IOStreamAdapter =
BasicIOStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
using OutputBufferedStreamAdapter =
BasicBufferedOutputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
}
#endif //BITSERY_ADAPTER_STREAM_H
#endif // BITSERY_ADAPTER_STREAM_H

View File

@@ -1,43 +1,103 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_BITSERY_H
#define BITSERY_BITSERY_H
#define BITSERY_MAJOR_VERSION 5
#define BITSERY_MINOR_VERSION 2
#define BITSERY_PATCH_VERSION 2
#define BITSERY_PATCH_VERSION 5
#define BITSERY_QUOTE_MACRO(name) #name
#define BITSERY_BUILD_VERSION_STR(major,minor, patch) \
BITSERY_QUOTE_MACRO(major) "." \
BITSERY_QUOTE_MACRO(minor) "." \
BITSERY_QUOTE_MACRO(patch)
#define BITSERY_BUILD_VERSION_STR(major, minor, patch) \
BITSERY_QUOTE_MACRO(major) \
"." BITSERY_QUOTE_MACRO(minor) "." BITSERY_QUOTE_MACRO(patch)
#define BITSERY_VERSION \
BITSERY_BUILD_VERSION_STR(BITSERY_MAJOR_VERSION, BITSERY_MINOR_VERSION, BITSERY_PATCH_VERSION)
#define BITSERY_VERSION \
BITSERY_BUILD_VERSION_STR( \
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 "serializer.h"
#include "deserializer.h"
#include "serializer.h"
#endif //BITSERY_BITSERY_H
#endif // BITSERY_BITSERY_H

View File

@@ -1,94 +1,126 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_H
#define BITSERY_BRIEF_SYNTAX_H
#include "details/serialization_common.h"
#include "details/brief_syntax_common.h"
#include "details/serialization_common.h"
namespace bitsery {
//define function that enables s(....) usage
template<typename S, typename T>
void processBriefSyntax(S& s, T&& head) {
static_assert(std::is_lvalue_reference<T>::value || std::is_base_of<brief_syntax::ModFnc, T>::value,
"Argument must be either lvalue or subclass of brief_syntax::ModFnc");
s.object(head);
}
// define function that enables s(....) usage
template<typename S, typename T>
void
processBriefSyntax(S& s, T&& head)
{
static_assert(
std::is_lvalue_reference<T>::value ||
std::is_base_of<brief_syntax::ModFnc, T>::value,
"Argument must be either lvalue or subclass of brief_syntax::ModFnc");
s.object(head);
}
//wrapper functions that enables to serialize as container or string
template<typename T, size_t N>
brief_syntax::CArray<T, N, true> asText(T (& str)[N]) {
return {str};
}
// wrapper functions that enables to serialize as container or string
template<typename T, size_t N>
brief_syntax::CArray<T, N, true>
asText(T (&str)[N])
{
return { str };
}
template<typename T, size_t N>
brief_syntax::CArray<T, N, false> asContainer(T (& obj)[N]) {
return {obj};
}
template<typename T, size_t N>
brief_syntax::CArray<T, N, false>
asContainer(T (&obj)[N])
{
return { obj };
}
template<typename T>
brief_syntax::MaxSize<T> maxSize(T& obj, size_t max) {
return {obj, max};
}
template<typename T>
brief_syntax::MaxSize<T>
maxSize(T& obj, size_t max)
{
return { obj, max };
}
//define serialize function for fundamental types
template<typename S>
void serialize(S& s, bool& v) {
s.boolValue(v);
}
// define serialize function for fundamental types
template<typename S>
void
serialize(S& s, bool& v)
{
s.boolValue(v);
}
template<typename S, typename T, typename std::enable_if<details::IsFundamentalType<T>::value>::type * = nullptr>
void serialize(S& s, T& v) {
s.template value<sizeof(T)>(v);
}
template<typename S,
typename T,
typename std::enable_if<details::IsFundamentalType<T>::value>::type* =
nullptr>
void
serialize(S& s, T& v)
{
s.template value<sizeof(T)>(v);
}
//define serialization for c-style container
// define serialization for c-style container
//if array is integral type, specify explicitly how to process: as text or container
template<typename S, typename T, size_t N, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
void serialize(S&, T (&)[N]) {
static_assert(N == 0,
"\nPlease use 'asText(obj)' or 'asContainer(obj)' when using c-style array with integral types\n");
}
// if array is integral type, specify explicitly how to process: as text or
// container
template<typename S,
typename T,
size_t N,
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
void
serialize(S&, T (&)[N])
{
static_assert(N == 0,
"\nPlease use 'asText(obj)' or 'asContainer(obj)' when using "
"c-style array with integral types\n");
}
template<typename S, typename T, size_t N, typename std::enable_if<!std::is_integral<T>::value>::type * = nullptr>
void serialize(S& s, T (& obj)[N]) {
brief_syntax::processContainer(s, obj);
}
template<typename S,
typename T,
size_t N,
typename std::enable_if<!std::is_integral<T>::value>::type* = nullptr>
void
serialize(S& s, T (&obj)[N])
{
brief_syntax::processContainer(s, obj);
}
//this is a helper class that enforce fundamental type sizes, when used on multiple platforms
template<size_t TShort, size_t TInt, size_t TLong, size_t TLongLong>
void assertFundamentalTypeSizes() {
//http://en.cppreference.com/w/cpp/language/types
static_assert(sizeof(short) == TShort, "");
static_assert(sizeof(int) == TInt, "");
static_assert(sizeof(long) == TLong, "");
static_assert(sizeof(long long) == TLongLong, "");
//for completion we also need pointer type size, but serializer doesn't support pointer serialization.
}
// this is a helper class that enforce fundamental type sizes, when used on
// multiple platforms
template<size_t TShort, size_t TInt, size_t TLong, size_t TLongLong>
void
assertFundamentalTypeSizes()
{
// http://en.cppreference.com/w/cpp/language/types
static_assert(sizeof(short) == TShort, "");
static_assert(sizeof(int) == TInt, "");
static_assert(sizeof(long) == TLong, "");
static_assert(sizeof(long long) == TLongLong, "");
// for completion we also need pointer type size, but serializer doesn't
// support pointer serialization.
}
}
#endif //BITSERY_BRIEF_SYNTAX_H
#endif // BITSERY_BRIEF_SYNTAX_H

View File

@@ -1,37 +1,38 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_ARRAY_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_ARRAY_H
#include "../traits/array.h"
#include "../details/brief_syntax_common.h"
#include "../traits/array.h"
namespace bitsery {
template<typename S, typename T, size_t N>
void serialize(S &s, std::array<T, N> &obj) {
brief_syntax::processContainer(s, obj);
}
template<typename S, typename T, size_t N>
void
serialize(S& s, std::array<T, N>& obj)
{
brief_syntax::processContainer(s, obj);
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_ARRAY_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_ARRAY_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2020 Nick Renieris
// Copyright (c) 2020 Nick Renieris
//
//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:
// 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 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.
// 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_ATOMIC_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_ATOMIC_H
@@ -26,10 +26,12 @@
#include "../ext/std_atomic.h"
namespace bitsery {
template<typename S, typename T>
void serialize(S &s, std::atomic<T> &obj) {
s.template ext<sizeof(T)>(obj, ext::StdAtomic{});
}
template<typename S, typename T>
void
serialize(S& s, std::atomic<T>& obj)
{
s.template ext<sizeof(T)>(obj, ext::StdAtomic{});
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_ATOMIC_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_ATOMIC_H

View 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

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 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:
// 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 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.
// 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_CHRONO_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_CHRONO_H
@@ -26,15 +26,19 @@
#include "../ext/std_chrono.h"
namespace bitsery {
template<typename S, typename T, typename P>
void serialize(S &s, std::chrono::duration<T, P> &obj) {
s.template ext<sizeof(T)>(obj, ext::StdDuration{});
}
template<typename S, typename C, typename T, typename P>
void serialize(S &s, std::chrono::time_point<C, std::chrono::duration<T, P>> &obj) {
s.template ext<sizeof(T)>(obj, ext::StdTimePoint{});
}
template<typename S, typename T, typename P>
void
serialize(S& s, std::chrono::duration<T, P>& obj)
{
s.template ext<sizeof(T)>(obj, ext::StdDuration{});
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_CHRONO_H
template<typename S, typename C, typename T, typename P>
void
serialize(S& s, std::chrono::time_point<C, std::chrono::duration<T, P>>& obj)
{
s.template ext<sizeof(T)>(obj, ext::StdTimePoint{});
}
}
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_CHRONO_H

View File

@@ -1,37 +1,38 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_DEQUE_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_DEQUE_H
#include "../traits/deque.h"
#include "../details/brief_syntax_common.h"
#include "../traits/deque.h"
namespace bitsery {
template<typename S, typename T, typename Allocator>
void serialize(S &s, std::deque<T, Allocator> &obj) {
brief_syntax::processContainer(s, obj);
}
template<typename S, typename T, typename Allocator>
void
serialize(S& s, std::deque<T, Allocator>& obj)
{
brief_syntax::processContainer(s, obj);
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_DEQUE_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_DEQUE_H

View File

@@ -1,37 +1,38 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_FORWARD_LIST_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_FORWARD_LIST_H
#include "../traits/forward_list.h"
#include "../details/brief_syntax_common.h"
#include "../traits/forward_list.h"
namespace bitsery {
template<typename S, typename T, typename Allocator>
void serialize(S &s, std::forward_list<T, Allocator> &obj) {
brief_syntax::processContainer(s, obj);
}
template<typename S, typename T, typename Allocator>
void
serialize(S& s, std::forward_list<T, Allocator>& obj)
{
brief_syntax::processContainer(s, obj);
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_FORWARD_LIST_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_FORWARD_LIST_H

View File

@@ -1,37 +1,38 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_LIST_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_LIST_H
#include "../traits/list.h"
#include "../details/brief_syntax_common.h"
#include "../traits/list.h"
namespace bitsery {
template<typename S, typename T, typename Allocator>
void serialize(S &s, std::list<T, Allocator> &obj) {
brief_syntax::processContainer(s, obj);
}
template<typename S, typename T, typename Allocator>
void
serialize(S& s, std::list<T, Allocator>& obj)
{
brief_syntax::processContainer(s, obj);
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_LIST_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_LIST_H

View File

@@ -1,51 +1,64 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_MAP_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_MAP_H
#include <map>
#include <limits>
#include "../ext/std_map.h"
#include <limits>
#include <map>
namespace bitsery {
template<typename S, typename Key, typename T, typename Compare, typename Allocator>
void serialize(S &s, std::map<Key, T, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdMap{maxSize},
[](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
template<typename S, typename Key, typename T, typename Compare, typename Allocator>
void serialize(S &s, std::multimap<Key, T, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdMap{maxSize},
[](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
template<typename S,
typename Key,
typename T,
typename Compare,
typename Allocator>
void
serialize(S& s,
std::map<Key, T, Compare, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdMap{ maxSize }, [](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_MAP_H
template<typename S,
typename Key,
typename T,
typename Compare,
typename Allocator>
void
serialize(S& s,
std::multimap<Key, T, Compare, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdMap{ maxSize }, [](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
}
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_MAP_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2018 Mindaugas Vinkelis
// 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:
// 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 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.
// 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_MEMORY_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_MEMORY_H
@@ -26,20 +26,26 @@
#include "../ext/std_smart_ptr.h"
namespace bitsery {
template<typename S, typename T, typename D>
void serialize(S &s, std::unique_ptr<T, D> &obj) {
s.ext(obj, ext::StdSmartPtr{});
}
template<typename S, typename T>
void serialize(S &s, std::shared_ptr<T> &obj) {
s.ext(obj, ext::StdSmartPtr{});
}
template<typename S, typename T>
void serialize(S &s, std::weak_ptr<T> &obj) {
s.ext(obj, ext::StdSmartPtr{});
}
template<typename S, typename T, typename D>
void
serialize(S& s, std::unique_ptr<T, D>& obj)
{
s.ext(obj, ext::StdSmartPtr{});
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_MEMORY_H
template<typename S, typename T>
void
serialize(S& s, std::shared_ptr<T>& obj)
{
s.ext(obj, ext::StdSmartPtr{});
}
template<typename S, typename T>
void
serialize(S& s, std::weak_ptr<T>& obj)
{
s.ext(obj, ext::StdSmartPtr{});
}
}
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_MEMORY_H

View 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

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_QUEUE_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_QUEUE_H
@@ -28,16 +27,24 @@
#include <limits>
namespace bitsery {
template<typename S, typename T, typename C>
void serialize(S &s, std::queue<T, C> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdQueue{maxSize});
}
template<typename S, typename T, typename C>
void
serialize(S& s,
std::queue<T, C>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdQueue{ maxSize });
}
template<typename S, typename T, typename C, typename Comp>
void serialize(S &s, std::priority_queue<T, C, Comp> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdQueue{maxSize});
}
template<typename S, typename T, typename C, typename Comp>
void
serialize(S& s,
std::priority_queue<T, C, Comp>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdQueue{ maxSize });
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_QUEUE_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_QUEUE_H

View File

@@ -1,44 +1,51 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_SET_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_SET_H
#include <set>
#include <limits>
#include "../ext/std_set.h"
#include <limits>
#include <set>
namespace bitsery {
template<typename S, typename Key, typename Compare, typename Allocator>
void serialize(S &s, std::set<Key, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdSet{maxSize});
}
template<typename S, typename Key, typename Compare, typename Allocator>
void
serialize(S& s,
std::set<Key, Compare, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdSet{ maxSize });
}
template<typename S, typename Key, typename Compare, typename Allocator>
void serialize(S &s, std::multiset<Key, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdSet{maxSize});
}
template<typename S, typename Key, typename Compare, typename Allocator>
void
serialize(S& s,
std::multiset<Key, Compare, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdSet{ maxSize });
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_SET_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_SET_H

View File

@@ -1,37 +1,40 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_STACK_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_STACK_H
#include <limits>
#include "../ext/std_stack.h"
#include <limits>
namespace bitsery {
template<typename S, typename T, typename C>
void serialize(S &s, std::stack<T, C> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdStack{maxSize});
}
template<typename S, typename T, typename C>
void
serialize(S& s,
std::stack<T, C>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdStack{ maxSize });
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_STACK_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_STACK_H

View File

@@ -1,37 +1,38 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_STRING_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_STRING_H
#include "../traits/string.h"
#include "../details/brief_syntax_common.h"
#include "../traits/string.h"
namespace bitsery {
template<typename S, typename CharT, typename Traits, typename Allocator>
void serialize(S &s, std::basic_string<CharT, Traits, Allocator> &str) {
brief_syntax::processContainer(s, str);
}
template<typename S, typename CharT, typename Traits, typename Allocator>
void
serialize(S& s, std::basic_string<CharT, Traits, Allocator>& str)
{
brief_syntax::processContainer(s, str);
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_STRING_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_STRING_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 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:
// 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 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.
// 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_TUPLE_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_TUPLE_H
@@ -26,10 +26,12 @@
#include "../ext/std_tuple.h"
namespace bitsery {
template<typename S, typename ...Ts>
void serialize(S &s, std::tuple<Ts...> &obj) {
s.ext(obj, ext::StdTuple{});
}
template<typename S, typename... Ts>
void
serialize(S& s, std::tuple<Ts...>& obj)
{
s.ext(obj, ext::StdTuple{});
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_TUPLE_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_TUPLE_H

View File

@@ -1,52 +1,67 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_UNORDERED_MAP_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_MAP_H
#include <unordered_map>
#include <limits>
#include "../ext/std_map.h"
#include <limits>
#include <unordered_map>
namespace bitsery {
template<typename S, typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
void serialize(S &s, std::unordered_map<Key, T, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdMap{maxSize},
[](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
template<typename S,
typename Key,
typename T,
typename Hash,
typename KeyEqual,
typename Allocator>
void
serialize(S& s,
std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdMap{ maxSize }, [](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
template<typename S, typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
void serialize(S &s, std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdMap{maxSize},
[](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
template<typename S,
typename Key,
typename T,
typename Hash,
typename KeyEqual,
typename Allocator>
void
serialize(S& s,
std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdMap{ maxSize }, [](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_MAP_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_MAP_H

View File

@@ -1,44 +1,59 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_UNORDERED_SET_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_SET_H
#include "../ext/std_set.h"
#include <limits>
#include <unordered_set>
#include "../ext/std_set.h"
namespace bitsery {
template<typename S, typename Key, typename Hash, typename KeyEqual, typename Allocator>
void serialize(S &s, std::unordered_set<Key, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdSet{maxSize});
}
template<typename S,
typename Key,
typename Hash,
typename KeyEqual,
typename Allocator>
void
serialize(S& s,
std::unordered_set<Key, Hash, KeyEqual, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdSet{ maxSize });
}
template<typename S, typename Key, typename Hash, typename KeyEqual, typename Allocator>
void serialize(S &s, std::unordered_multiset<Key, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdSet{maxSize});
}
template<typename S,
typename Key,
typename Hash,
typename KeyEqual,
typename Allocator>
void
serialize(S& s,
std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdSet{ maxSize });
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_SET_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_SET_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 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:
// 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 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.
// 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_VARIANT_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_VARIANT_H
@@ -26,10 +26,12 @@
#include "../ext/std_variant.h"
namespace bitsery {
template<typename S, typename ...Ts>
void serialize(S &s, std::variant<Ts...> &obj) {
s.ext(obj, ext::StdVariant{});
}
template<typename S, typename... Ts>
void
serialize(S& s, std::variant<Ts...>& obj)
{
s.ext(obj, ext::StdVariant{});
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_VARIANT_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_VARIANT_H

View File

@@ -1,37 +1,38 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_VECTOR_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_VECTOR_H
#include "../traits/vector.h"
#include "../details/brief_syntax_common.h"
#include "../traits/vector.h"
namespace bitsery {
template<typename S, typename T, typename Allocator>
void serialize(S &s, std::vector<T, Allocator> &obj) {
brief_syntax::processContainer(s, obj);
}
template<typename S, typename T, typename Allocator>
void
serialize(S& s, std::vector<T, Allocator>& obj)
{
brief_syntax::processContainer(s, obj);
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_VECTOR_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_VECTOR_H

View File

@@ -1,52 +1,54 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_COMMON_H
#define BITSERY_COMMON_H
#include <tuple>
namespace bitsery {
/*
* endianness
*/
enum class EndiannessType {
LittleEndian,
BigEndian
};
enum class EndiannessType
{
LittleEndian,
BigEndian
};
// default configuration for serialization and deserialization
struct DefaultConfig {
// defines endianness of data that is read from input adapter and written to output adapter.
static constexpr EndiannessType Endianness = EndiannessType::LittleEndian;
// these flags allow to improve deserialization performance if data is trusted
// enables/disables checks for buffer end or stream read errors in input adapter
static constexpr bool CheckAdapterErrors = true;
// enables/disables checks for other errors that can significantly affect performance
static constexpr bool CheckDataErrors = true;
};
// default configuration for serialization and deserialization
struct DefaultConfig
{
// defines endianness of data that is read from input adapter and written to
// output adapter.
static constexpr EndiannessType Endianness = EndiannessType::LittleEndian;
// these flags allow to improve deserialization performance if data is trusted
// enables/disables checks for buffer end or stream read errors in input
// adapter
static constexpr bool CheckAdapterErrors = true;
// enables/disables checks for other errors that can significantly affect
// performance
static constexpr bool CheckDataErrors = true;
};
}
#endif //BITSERY_COMMON_H
#endif // BITSERY_COMMON_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,379 @@
// MIT License
//
// Copyright (c) 2022 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_DETAILS_ADAPTER_BIT_PACKING_H
#define BITSERY_DETAILS_ADAPTER_BIT_PACKING_H
#include "../common.h"
#include "./adapter_common.h"
#include "not_defined_type.h"
#include <limits>
namespace bitsery {
namespace details {
template<typename TAdapter>
class InputAdapterBitPackingWrapper
{
public:
// in order to check if adapter is BP enabled, we use `std::is_same<Adapter,
// typename Adapter::BitPackingEnabled>` so when current implementation is BP
// enabled, we always specify current class as BitPackingEnabled.
using BitPackingEnabled = InputAdapterBitPackingWrapper<TAdapter>;
using TConfig = typename TAdapter::TConfig;
using TValue = typename TAdapter::TValue;
InputAdapterBitPackingWrapper(TAdapter& adapter)
: _wrapped{ adapter }
{
}
~InputAdapterBitPackingWrapper() { align(); }
template<size_t SIZE, typename T>
void readBytes(T& v)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
using UT = typename std::make_unsigned<T>::type;
if (!m_scratchBits)
this->_wrapped.template readBytes<SIZE, T>(v);
else
readBits(reinterpret_cast<UT&>(v), details::BitsSize<T>::value);
}
template<size_t SIZE, typename T>
void readBuffer(T* buf, size_t count)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
if (!m_scratchBits) {
this->_wrapped.template readBuffer<SIZE, T>(buf, count);
} else {
using UT = typename std::make_unsigned<T>::type;
// todo improve implementation
const auto end = buf + count;
for (auto it = buf; it != end; ++it)
readBits(reinterpret_cast<UT&>(*it), details::BitsSize<T>::value);
}
}
template<typename T>
void readBits(T& v, size_t bitsCount)
{
static_assert(std::is_integral<T>() && std::is_unsigned<T>(), "");
readBitsInternal(v, bitsCount);
}
void align()
{
if (m_scratchBits) {
ScratchType tmp{};
readBitsInternal(tmp, m_scratchBits);
handleAlignErrors(
tmp, std::integral_constant<bool, TConfig::CheckDataErrors>{});
}
}
void currentReadPos(size_t pos)
{
align();
this->_wrapped.currentReadPos(pos);
}
size_t currentReadPos() const { return this->_wrapped.currentReadPos(); }
void currentReadEndPos(size_t pos) { this->_wrapped.currentReadEndPos(pos); }
size_t currentReadEndPos() const
{
return this->_wrapped.currentReadEndPos();
}
bool isCompletedSuccessfully() const
{
return this->_wrapped.isCompletedSuccessfully();
}
ReaderError error() const { return this->_wrapped.error(); }
void error(ReaderError error) { this->_wrapped.error(error); }
private:
TAdapter& _wrapped;
using UnsignedValue =
typename std::make_unsigned<typename TAdapter::TValue>::type;
using ScratchType = typename details::ScratchType<UnsignedValue>::type;
ScratchType m_scratch{};
size_t m_scratchBits{};
template<typename T>
void readBitsInternal(T& v, size_t size)
{
auto bitsLeft = size;
using TFast = typename FastType<T>::type;
TFast res{};
while (bitsLeft > 0) {
auto bits = (std::min)(bitsLeft, details::BitsSize<UnsignedValue>::value);
if (m_scratchBits < bits) {
UnsignedValue tmp;
this->_wrapped.template readBytes<sizeof(UnsignedValue), UnsignedValue>(
tmp);
m_scratch |= static_cast<ScratchType>(tmp) << m_scratchBits;
m_scratchBits += details::BitsSize<UnsignedValue>::value;
}
auto shiftedRes =
static_cast<T>(m_scratch & ((static_cast<ScratchType>(1) << bits) - 1))
<< (size - bitsLeft);
res = static_cast<TFast>(res | static_cast<TFast>(shiftedRes));
m_scratch >>= bits;
m_scratchBits -= bits;
bitsLeft -= bits;
}
v = static_cast<T>(res);
}
void handleAlignErrors(ScratchType value, std::true_type)
{
if (value)
error(ReaderError::InvalidData);
}
void handleAlignErrors(ScratchType, std::false_type) {}
};
template<typename TAdapter>
class BasicMeasureSizeBitPackingWrapper
{
public:
using BitPackingEnabled = BasicMeasureSizeBitPackingWrapper<TAdapter>;
using TConfig = typename TAdapter::TConfig;
using TValue = typename TAdapter::TValue;
BasicMeasureSizeBitPackingWrapper(TAdapter& adapter)
: _wrapped{ adapter }
{
}
~BasicMeasureSizeBitPackingWrapper() { align(); }
template<size_t SIZE, typename T>
void writeBytes(const T& value)
{
_wrapped.template writeBytes<SIZE>(value);
}
template<size_t SIZE, typename T>
void writeBuffer(const T* buf, size_t count)
{
_wrapped.template writeBuffer<SIZE>(buf, count);
}
template<typename T>
void writeBits(const T&, size_t bitsCount)
{
_scratchBits += bitsCount;
while (_scratchBits >= 8) {
writeOneByte();
_scratchBits -= 8;
}
}
void align()
{
if (_scratchBits > 0) {
_scratchBits = 0;
writeOneByte();
}
}
void currentWritePos(size_t pos)
{
align();
this->_wrapped.currentWritePos(pos);
}
size_t currentWritePos() const { return this->_wrapped.currentWritePos(); }
void flush()
{
align();
this->_wrapped.flush();
}
size_t writtenBytesCount() const
{
return this->_wrapped.writtenBytesCount();
}
private:
void writeOneByte() { _wrapped.template writeBytes<1>(uint8_t{}); }
TAdapter& _wrapped;
size_t _scratchBits{};
};
template<typename TAdapter>
class OutputAdapterBitPackingWrapper
{
public:
// in order to check if adapter is BP enabled, we use `std::is_same<Adapter,
// typename Adapter::BitPackingEnabled>` so when current implementation is BP
// enabled, we always specify current class as BitPackingEnabled.
using BitPackingEnabled = OutputAdapterBitPackingWrapper<TAdapter>;
using TConfig = typename TAdapter::TConfig;
using TValue = typename TAdapter::TValue;
OutputAdapterBitPackingWrapper(TAdapter& adapter)
: _wrapped{ adapter }
{
}
~OutputAdapterBitPackingWrapper() { align(); }
template<size_t SIZE, typename T>
void writeBytes(const T& v)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
if (!_scratchBits) {
this->_wrapped.template writeBytes<SIZE, T>(v);
} else {
using UT = typename std::make_unsigned<T>::type;
writeBitsInternal(reinterpret_cast<const UT&>(v),
details::BitsSize<T>::value);
}
}
template<size_t SIZE, typename T>
void writeBuffer(const T* buf, size_t count)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
if (!_scratchBits) {
this->_wrapped.template writeBuffer<SIZE, T>(buf, count);
} else {
using UT = typename std::make_unsigned<T>::type;
// todo improve implementation
const auto end = buf + count;
for (auto it = buf; it != end; ++it)
writeBitsInternal(reinterpret_cast<const UT&>(*it),
details::BitsSize<T>::value);
}
}
template<typename T>
void writeBits(const T& v, size_t bitsCount)
{
static_assert(std::is_integral<T>() && std::is_unsigned<T>(), "");
assert(0 < bitsCount && bitsCount <= details::BitsSize<T>::value);
assert(v <= (bitsCount < 64 ? (1ULL << bitsCount) - 1
: (1ULL << (bitsCount - 1)) +
((1ULL << (bitsCount - 1)) - 1)));
writeBitsInternal(v, bitsCount);
}
void align()
{
writeBitsInternal(UnsignedType{},
(details::BitsSize<UnsignedType>::value - _scratchBits) %
8);
}
void currentWritePos(size_t pos)
{
align();
this->_wrapped.currentWritePos(pos);
}
size_t currentWritePos() const { return this->_wrapped.currentWritePos(); }
void flush()
{
align();
this->_wrapped.flush();
}
size_t writtenBytesCount() const
{
return this->_wrapped.writtenBytesCount();
}
private:
TAdapter& _wrapped;
using UnsignedType =
typename std::make_unsigned<typename TAdapter::TValue>::type;
using ScratchType = typename details::ScratchType<UnsignedType>::type;
static_assert(details::IsDefined<ScratchType>::value,
"Underlying adapter value type is not supported");
template<typename T>
void writeBitsInternal(const T& v, size_t size)
{
constexpr size_t valueSize = details::BitsSize<UnsignedType>::value;
T value = v;
size_t bitsLeft = size;
while (bitsLeft > 0) {
auto bits = (std::min)(bitsLeft, valueSize);
_scratch |= static_cast<ScratchType>(value) << _scratchBits;
_scratchBits += bits;
if (_scratchBits >= valueSize) {
auto tmp = static_cast<UnsignedType>(_scratch & _MASK);
this->_wrapped.template writeBytes<sizeof(UnsignedType), UnsignedType>(
tmp);
_scratch >>= valueSize;
_scratchBits -= valueSize;
value = static_cast<T>(value >> valueSize);
}
bitsLeft -= bits;
}
}
// overload for TValue, for better performance
void writeBitsInternal(const UnsignedType& v, size_t size)
{
if (size > 0) {
_scratch |= static_cast<ScratchType>(v) << _scratchBits;
_scratchBits += size;
if (_scratchBits >= details::BitsSize<UnsignedType>::value) {
auto tmp = static_cast<UnsignedType>(_scratch & _MASK);
this->_wrapped.template writeBytes<sizeof(UnsignedType), UnsignedType>(
tmp);
_scratch >>= details::BitsSize<UnsignedType>::value;
_scratchBits -= details::BitsSize<UnsignedType>::value;
}
}
}
const UnsignedType _MASK = (std::numeric_limits<UnsignedType>::max)();
ScratchType _scratch{};
size_t _scratchBits{};
};
}
}
#endif // BITSERY_DETAILS_ADAPTER_BIT_PACKING_H

View File

@@ -1,371 +1,426 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_DETAILS_ADAPTER_COMMON_H
#define BITSERY_DETAILS_ADAPTER_COMMON_H
#include <algorithm>
#include <utility>
#include <cassert>
#include <vector>
#include <stack>
#include <cstring>
#include <climits>
#include "not_defined_type.h"
#include "../common.h"
#include "not_defined_type.h"
#include <algorithm>
#include <cassert>
#include <climits>
#include <cstdint>
namespace bitsery {
enum class ReaderError {
NoError,
ReadingError, // this might be used with stream adapter
DataOverflow,
InvalidData,
InvalidPointer
};
enum class ReaderError
{
NoError,
ReadingError, // this might be used with stream adapter
DataOverflow,
InvalidData,
InvalidPointer
};
namespace details {
namespace details {
/**
* size read/write functions
*/
template <typename Reader, typename TCheckMaxSize>
void readSize(Reader& r, size_t& size, size_t maxSize, TCheckMaxSize) {
uint8_t hb{};
r.template readBytes<1>(hb);
if (hb < 0x80u) {
size = hb;
} else {
uint8_t lb{};
r.template readBytes<1>(lb);
if (hb & 0x40u) {
uint16_t lw{};
r.template readBytes<2>(lw);
size = ((((hb & 0x3Fu) << 8) | lb) << 16) | lw;
} else {
size = ((hb & 0x7Fu) << 8) | lb;
}
}
handleReadMaxSize(r, size, maxSize, TCheckMaxSize{});
}
/**
* size read/write functions
*/
template <typename Reader>
void handleReadMaxSize(Reader& r, size_t& size, size_t maxSize, std::true_type) {
if (size > maxSize) {
r.error(ReaderError::InvalidData);
size = {};
}
}
template <typename Reader>
void handleReadMaxSize(Reader&, size_t&, size_t, std::false_type) {
}
template <typename Writer>
void writeSize(Writer& w, const size_t size) {
if (size < 0x80u) {
w.template writeBytes<1>(static_cast<uint8_t>(size));
} else {
if (size < 0x4000u) {
w.template writeBytes<1>(static_cast<uint8_t>((size >> 8) | 0x80u));
w.template writeBytes<1>(static_cast<uint8_t>(size));
} else {
assert(size < 0x40000000u);
w.template writeBytes<1>(static_cast<uint8_t>((size >> 24) | 0xC0u));
w.template writeBytes<1>(static_cast<uint8_t>(size >> 16));
w.template writeBytes<2>(static_cast<uint16_t>(size));
}
}
}
/**
* swap utils
*/
//add swap functions to class, to avoid compilation warning about unused functions
struct SwapImpl {
static uint64_t exec(uint64_t value) {
#ifdef __GNUC__
return __builtin_bswap64(value);
#else
value = ( value & 0x00000000FFFFFFFF ) << 32 | ( value & 0xFFFFFFFF00000000 ) >> 32;
value = ( value & 0x0000FFFF0000FFFF ) << 16 | ( value & 0xFFFF0000FFFF0000 ) >> 16;
value = ( value & 0x00FF00FF00FF00FF ) << 8 | ( value & 0xFF00FF00FF00FF00 ) >> 8;
return value;
#endif
}
static uint32_t exec(uint32_t value) {
#ifdef __GNUC__
return __builtin_bswap32(value);
#else
return ( value & 0x000000ff ) << 24 | ( value & 0x0000ff00 ) << 8 | ( value & 0x00ff0000 ) >> 8 | ( value & 0xff000000 ) >> 24;
#endif
}
static uint16_t exec(uint16_t value) {
return static_cast<uint16_t>((value & 0x00ff) << 8 | (value & 0xff00) >> 8);
}
static uint8_t exec(uint8_t value) {
return value;
}
};
template<typename TValue>
TValue swap(TValue value) {
constexpr size_t TSize = sizeof(TValue);
using UT = typename std::conditional<TSize == 1, uint8_t,
typename std::conditional<TSize == 2, uint16_t,
typename std::conditional<TSize == 4, uint32_t, uint64_t>::type>::type>::type;
return static_cast<TValue>(SwapImpl::exec(static_cast<UT>(value)));
}
/**
* endianness utils
*/
// add test data in separate struct, because some compilers only support constexpr functions with return-only body
// suppress msvc warnings.
#ifdef _MSC_VER
#pragma warning( disable : 4310 )
#endif
struct EndiannessTestData {
static constexpr uint32_t _sample4Bytes = 0x01020304;
static constexpr uint8_t _sample1stByte = (const uint8_t &) _sample4Bytes;
};
#ifdef _MSC_VER
#pragma warning( default : 4310 )
#endif
constexpr EndiannessType getSystemEndianness() {
static_assert(EndiannessTestData::_sample1stByte == 0x04 || EndiannessTestData::_sample1stByte == 0x01,
"system must be either little or big endian");
return EndiannessTestData::_sample1stByte == 0x04 ? EndiannessType::LittleEndian
: EndiannessType::BigEndian;
}
template <typename Config>
using ShouldSwap = std::integral_constant<bool, Config::Endianness != details::getSystemEndianness()>;
/**
* helper types to work with bits
*/
template<typename T>
struct BitsSize:public std::integral_constant<size_t, sizeof(T) * 8> {
static_assert(CHAR_BIT == 8, "only support systems with byte size of 8 bits");
};
template<typename T>
struct ScratchType {
using type = NotDefinedType;
};
template<>
struct ScratchType<uint8_t> {
using type = uint_fast16_t;
};
template<typename T>
struct FastType {
using type = T;
};
template<>
struct FastType<uint8_t> {
using type = uint_fast8_t;
};
template<>
struct FastType<uint16_t> {
using type = uint_fast16_t;
};
template<>
struct FastType<uint32_t> {
using type = uint_fast32_t;
};
template<>
struct FastType<uint64_t> {
using type = uint_fast64_t;
};
template<>
struct FastType<int8_t> {
using type = int_fast8_t;
};
template<>
struct FastType<int16_t> {
using type = int_fast16_t;
};
template<>
struct FastType<int32_t> {
using type = int_fast32_t;
};
template<>
struct FastType<int64_t> {
using type = int_fast64_t;
};
/**
* output/input adapter base that handles endianness
*/
template<typename Adapter>
struct OutputAdapterBaseCRTP {
static constexpr bool BitPackingEnabled = false;
template<size_t SIZE, typename T>
void writeBytes(const T &v) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
writeSwappedValue(&v, ShouldSwap<typename Adapter::TConfig>{});
}
template<size_t SIZE, typename T>
void writeBuffer(const T *buf, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
writeSwappedBuffer(buf, count, ShouldSwap<typename Adapter::TConfig>{});
}
template<typename T>
void writeBits(const T &, size_t ) {
static_assert(std::is_void<T>::value,
"Bit-packing is not enabled.\nEnable by call to `enableBitPacking`) or create Serializer with bit packing enabled.");
}
void align() {
}
OutputAdapterBaseCRTP() = default;
OutputAdapterBaseCRTP(const OutputAdapterBaseCRTP&) = delete;
OutputAdapterBaseCRTP& operator = (const OutputAdapterBaseCRTP&) = delete;
OutputAdapterBaseCRTP(OutputAdapterBaseCRTP&&) = default;
OutputAdapterBaseCRTP& operator = (OutputAdapterBaseCRTP&&) = default;
private:
template<typename T>
void writeSwappedValue(const T *v, std::true_type) {
const auto res = details::swap(*v);
static_cast<Adapter*>(this)->template writeInternalValue<sizeof(T)>(reinterpret_cast<const typename Adapter::TValue *>(&res));
}
template<typename T>
void writeSwappedValue(const T *v, std::false_type) {
static_cast<Adapter*>(this)->template writeInternalValue<sizeof(T)>(reinterpret_cast<const typename Adapter::TValue *>(v));
}
template<typename T>
void writeSwappedBuffer(const T *v, size_t count, std::true_type) {
std::for_each(v, std::next(v, count), [this](const T &v) {
const auto res = details::swap(v);
static_cast<Adapter*>(this)->template writeInternalValue<sizeof(T)>(reinterpret_cast<const typename Adapter::TValue *>(&res));
});
}
template<typename T>
void writeSwappedBuffer(const T *v, size_t count, std::false_type) {
static_cast<Adapter*>(this)->writeInternalBuffer(reinterpret_cast<const typename Adapter::TValue *>(v), count * sizeof(T));
}
};
template <typename Base>
struct InputAdapterBaseCRTP {
static constexpr bool BitPackingEnabled = false;
template<size_t SIZE, typename T>
void readBytes(T& v) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
static_cast<Base*>(this)->template readInternalValue<sizeof(T)>(reinterpret_cast<typename Base::TValue *>(&v));
swapDataBits(v, ShouldSwap<typename Base::TConfig>{});
}
template<size_t SIZE, typename T>
void readBuffer(T* buf, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
static_cast<Base*>(this)->readInternalBuffer(reinterpret_cast<typename Base::TValue *>(buf), sizeof(T) * count);
swapDataBits(buf, count, ShouldSwap<typename Base::TConfig>{});
}
template<typename T>
void readBits(T&, size_t) {
static_assert(std::is_void<T>::value,
"Bit-packing is not enabled.\nEnable by call to `enableBitPacking`) or create Deserializer with bit packing enabled.");
}
void align() {
}
InputAdapterBaseCRTP() = default;
InputAdapterBaseCRTP(const InputAdapterBaseCRTP&) = delete;
InputAdapterBaseCRTP& operator = (const InputAdapterBaseCRTP&) = delete;
InputAdapterBaseCRTP(InputAdapterBaseCRTP&&) = default;
InputAdapterBaseCRTP& operator = (InputAdapterBaseCRTP&&) = default;
virtual ~InputAdapterBaseCRTP() = default;
private:
template<typename T>
void swapDataBits(T *v, size_t count, std::true_type) {
using diff_t = typename std::iterator_traits<T*>::difference_type;
std::for_each(v, std::next(v, static_cast<diff_t>(count)), [](T &x) { x = details::swap(x); });
}
template<typename T>
void swapDataBits(T *, size_t , std::false_type) {
//empty function because no swap is required
}
template<typename T>
void swapDataBits(T &v, std::true_type) {
v = details::swap(v);
}
template<typename T>
void swapDataBits(T &, std::false_type) {
//empty function because no swap is required
}
};
}
template<typename Reader>
void
handleReadMaxSize(Reader& r, size_t& size, size_t maxSize, std::true_type)
{
if (size > maxSize) {
r.error(ReaderError::InvalidData);
size = {};
}
}
template<typename Reader>
void
handleReadMaxSize(Reader&, size_t&, size_t, std::false_type)
{
}
#endif //BITSERY_DETAILS_ADAPTER_COMMON_H
template<typename Reader, bool CheckMaxSize>
void
readSize(Reader& r,
size_t& size,
size_t maxSize,
std::integral_constant<bool, CheckMaxSize> checkMaxSize)
{
uint8_t hb{};
r.template readBytes<1>(hb);
if (hb < 0x80u) {
size = hb;
} else {
uint8_t lb{};
r.template readBytes<1>(lb);
if (hb & 0x40u) {
uint16_t lw{};
r.template readBytes<2>(lw);
size = ((((hb & 0x3Fu) << 8) | lb) << 16) | lw;
} else {
size = ((hb & 0x7Fu) << 8) | lb;
}
}
handleReadMaxSize(r, size, maxSize, checkMaxSize);
}
template<typename Writer>
void
writeSize(Writer& w, const size_t size)
{
if (size < 0x80u) {
w.template writeBytes<1>(static_cast<uint8_t>(size));
} else {
if (size < 0x4000u) {
w.template writeBytes<1>(static_cast<uint8_t>((size >> 8) | 0x80u));
w.template writeBytes<1>(static_cast<uint8_t>(size));
} else {
assert(size < 0x40000000u);
w.template writeBytes<1>(static_cast<uint8_t>((size >> 24) | 0xC0u));
w.template writeBytes<1>(static_cast<uint8_t>(size >> 16));
w.template writeBytes<2>(static_cast<uint16_t>(size));
}
}
}
/**
* swap utils
*/
// add swap functions to class, to avoid compilation warning about unused
// functions
struct SwapImpl
{
static uint64_t exec(uint64_t value)
{
#ifdef __GNUC__
return __builtin_bswap64(value);
#else
value =
(value & 0x00000000FFFFFFFF) << 32 | (value & 0xFFFFFFFF00000000) >> 32;
value =
(value & 0x0000FFFF0000FFFF) << 16 | (value & 0xFFFF0000FFFF0000) >> 16;
value =
(value & 0x00FF00FF00FF00FF) << 8 | (value & 0xFF00FF00FF00FF00) >> 8;
return value;
#endif
}
static uint32_t exec(uint32_t value)
{
#ifdef __GNUC__
return __builtin_bswap32(value);
#else
return (value & 0x000000ff) << 24 | (value & 0x0000ff00) << 8 |
(value & 0x00ff0000) >> 8 | (value & 0xff000000) >> 24;
#endif
}
static uint16_t exec(uint16_t value)
{
return static_cast<uint16_t>((value & 0x00ff) << 8 | (value & 0xff00) >> 8);
}
static uint8_t exec(uint8_t value) { return value; }
};
template<typename TValue>
TValue
swap(TValue value)
{
constexpr size_t TSize = sizeof(TValue);
using UT = typename std::conditional<
TSize == 1,
uint8_t,
typename std::conditional<
TSize == 2,
uint16_t,
typename std::conditional<TSize == 4, uint32_t, uint64_t>::type>::type>::
type;
return static_cast<TValue>(SwapImpl::exec(static_cast<UT>(value)));
}
/**
* endianness utils
*/
// add test data in separate struct, because some compilers only support
// constexpr functions with return-only body suppress msvc warnings.
#ifdef _MSC_VER
#pragma warning(disable : 4310)
#endif
struct EndiannessTestData
{
static constexpr uint32_t _sample4Bytes = 0x01020304;
static constexpr uint8_t _sample1stByte = (const uint8_t&)_sample4Bytes;
};
#ifdef _MSC_VER
#pragma warning(default : 4310)
#endif
constexpr EndiannessType
getSystemEndianness()
{
static_assert(EndiannessTestData::_sample1stByte == 0x04 ||
EndiannessTestData::_sample1stByte == 0x01,
"system must be either little or big endian");
return EndiannessTestData::_sample1stByte == 0x04
? EndiannessType::LittleEndian
: EndiannessType::BigEndian;
}
template<typename Config, typename T>
using ShouldSwap =
std::integral_constant<bool,
Config::Endianness != details::getSystemEndianness() &&
sizeof(T) != 1>;
/**
* helper types to work with bits
*/
template<typename T>
struct BitsSize : public std::integral_constant<size_t, sizeof(T) * 8>
{
static_assert(CHAR_BIT == 8, "only support systems with byte size of 8 bits");
};
template<typename T>
struct ScratchType
{
using type = NotDefinedType;
};
template<>
struct ScratchType<uint8_t>
{
using type = uint_fast16_t;
};
template<typename T>
struct FastType
{
using type = T;
};
template<>
struct FastType<uint8_t>
{
using type = uint_fast8_t;
};
template<>
struct FastType<uint16_t>
{
using type = uint_fast16_t;
};
template<>
struct FastType<uint32_t>
{
using type = uint_fast32_t;
};
template<>
struct FastType<uint64_t>
{
using type = uint_fast64_t;
};
template<>
struct FastType<int8_t>
{
using type = int_fast8_t;
};
template<>
struct FastType<int16_t>
{
using type = int_fast16_t;
};
template<>
struct FastType<int32_t>
{
using type = int_fast32_t;
};
template<>
struct FastType<int64_t>
{
using type = int_fast64_t;
};
/**
* output/input adapter base that handles endianness
*/
template<typename Adapter>
struct OutputAdapterBaseCRTP
{
template<size_t SIZE, typename T>
void writeBytes(const T& v)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
writeSwappedValue(&v, ShouldSwap<typename Adapter::TConfig, T>{});
}
template<size_t SIZE, typename T>
void writeBuffer(const T* buf, size_t count)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
writeSwappedBuffer(buf, count, ShouldSwap<typename Adapter::TConfig, T>{});
}
template<typename T>
void writeBits(const T&, size_t)
{
static_assert(
std::is_void<T>::value,
"Bit-packing is not enabled.\nEnable by call to `enableBitPacking`) or "
"create Serializer with bit packing enabled.");
}
void align() {}
OutputAdapterBaseCRTP() = default;
OutputAdapterBaseCRTP(const OutputAdapterBaseCRTP&) = delete;
OutputAdapterBaseCRTP& operator=(const OutputAdapterBaseCRTP&) = delete;
OutputAdapterBaseCRTP(OutputAdapterBaseCRTP&&) = default;
OutputAdapterBaseCRTP& operator=(OutputAdapterBaseCRTP&&) = default;
private:
template<typename T>
void writeSwappedValue(const T* v, std::true_type)
{
const auto res = details::swap(*v);
static_cast<Adapter*>(this)->template writeInternalValue<sizeof(T)>(
reinterpret_cast<const typename Adapter::TValue*>(&res));
}
template<typename T>
void writeSwappedValue(const T* v, std::false_type)
{
static_cast<Adapter*>(this)->template writeInternalValue<sizeof(T)>(
reinterpret_cast<const typename Adapter::TValue*>(v));
}
template<typename T>
void writeSwappedBuffer(const T* v, size_t count, std::true_type)
{
std::for_each(v, std::next(v, count), [this](const T& inner_v) {
const auto res = details::swap(inner_v);
static_cast<Adapter*>(this)->template writeInternalValue<sizeof(T)>(
reinterpret_cast<const typename Adapter::TValue*>(&res));
});
}
template<typename T>
void writeSwappedBuffer(const T* v, size_t count, std::false_type)
{
static_cast<Adapter*>(this)->writeInternalBuffer(
reinterpret_cast<const typename Adapter::TValue*>(v), count * sizeof(T));
}
};
template<typename Adapter>
struct InputAdapterBaseCRTP
{
template<size_t SIZE, typename T>
void readBytes(T& v)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
static_cast<Adapter*>(this)->template readInternalValue<sizeof(T)>(
reinterpret_cast<typename Adapter::TValue*>(&v));
swapDataBits(v, ShouldSwap<typename Adapter::TConfig, T>{});
}
template<size_t SIZE, typename T>
void readBuffer(T* buf, size_t count)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
static_cast<Adapter*>(this)->readInternalBuffer(
reinterpret_cast<typename Adapter::TValue*>(buf), sizeof(T) * count);
swapDataBits(buf, count, ShouldSwap<typename Adapter::TConfig, T>{});
}
template<typename T>
void readBits(T&, size_t)
{
static_assert(
std::is_void<T>::value,
"Bit-packing is not enabled.\nEnable by call to `enableBitPacking`) or "
"create Deserializer with bit packing enabled.");
}
void align() {}
InputAdapterBaseCRTP() = default;
InputAdapterBaseCRTP(const InputAdapterBaseCRTP&) = delete;
InputAdapterBaseCRTP& operator=(const InputAdapterBaseCRTP&) = delete;
InputAdapterBaseCRTP(InputAdapterBaseCRTP&&) = default;
InputAdapterBaseCRTP& operator=(InputAdapterBaseCRTP&&) = default;
virtual ~InputAdapterBaseCRTP() = default;
private:
template<typename T>
void swapDataBits(T* v, size_t count, std::true_type)
{
using diff_t = typename std::iterator_traits<T*>::difference_type;
std::for_each(v, std::next(v, static_cast<diff_t>(count)), [](T& x) {
x = details::swap(x);
});
}
template<typename T>
void swapDataBits(T*, size_t, std::false_type)
{
// empty function because no swap is required
}
template<typename T>
void swapDataBits(T& v, std::true_type)
{
v = details::swap(v);
}
template<typename T>
void swapDataBits(T&, std::false_type)
{
// empty function because no swap is required
}
};
}
}
#endif // BITSERY_DETAILS_ADAPTER_COMMON_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_DETAILS_BRIEF_SYNTAX_COMMON_H
#define BITSERY_DETAILS_BRIEF_SYNTAX_COMMON_H
@@ -28,123 +28,173 @@
#include <limits>
namespace bitsery {
namespace brief_syntax {
namespace brief_syntax {
//these function overloads is required to apply maxSize, and optimize for fundamental types
//for contigous arrays of fundamenal types, memcpy will be applied
// these function overloads is required to apply maxSize, and optimize for
// fundamental types for contigous arrays of fundamenal types, memcpy will be
// applied
template<typename S, typename T, typename std::enable_if<
details::IsFundamentalType<typename traits::ContainerTraits<T>::TValue>::value
&& traits::ContainerTraits<T>::isResizable
>::type * = nullptr>
void processContainer(S &s, T &c, size_t maxSize = std::numeric_limits<size_t>::max()) {
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template container<sizeof(TValue)>(c, maxSize);
}
template<typename S, typename T, typename std::enable_if<
!details::IsFundamentalType<typename traits::ContainerTraits<T>::TValue>::value
&& traits::ContainerTraits<T>::isResizable
>::type * = nullptr>
void processContainer(S &s, T &c, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.container(c, maxSize);
}
template<typename S, typename T, typename std::enable_if<
details::IsFundamentalType<typename traits::ContainerTraits<T>::TValue>::value
&& !traits::ContainerTraits<T>::isResizable
>::type * = nullptr>
void processContainer(S &s, T &c) {
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template container<sizeof(TValue)>(c);
}
template<typename S, typename T, typename std::enable_if<
!details::IsFundamentalType<typename traits::ContainerTraits<T>::TValue>::value
&& !traits::ContainerTraits<T>::isResizable
>::type * = nullptr>
void processContainer(S &s, T &c) {
s.container(c);
}
//overloads for text processing to apply maxSize
template<typename S, typename T, typename std::enable_if<
traits::ContainerTraits<T>::isResizable>::type * = nullptr>
void processText(S &s, T &c, size_t maxSize = std::numeric_limits<size_t>::max()) {
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template text<sizeof(TValue)>(c, maxSize);
}
template<typename S, typename T, typename std::enable_if<
!traits::ContainerTraits<T>::isResizable>::type * = nullptr>
void processText(S &s, T &c) {
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template text<sizeof(TValue)>(c);
}
//all wrapper functions, that modify behaviour, should inherit from this
struct ModFnc {
};
//this type is used to differentiate between container and text behaviour
template<typename T, size_t N, bool isText>
struct CArray : public ModFnc {
CArray(T (&data_)[N]) : data{data_} {};
T (&data)[N];
};
template<typename S, typename T, size_t N>
void serialize(S &s, CArray<T, N, true> &str) {
processText(s, str.data);
}
template<typename S, typename T, size_t N>
void serialize(S &s, CArray<T, N, false> &obj) {
processContainer(s, obj.data);
}
//used to set max container size
template<typename T>
struct MaxSize : public ModFnc {
MaxSize(T &data_, size_t maxSize_) : data{data_}, maxSize{maxSize_} {};
T &data;
size_t maxSize;
};
//if container, then call procesContainer, this memcpy for fundamental types contiguous container
template<typename S, typename T>
void processMaxSize(S &s, T& data, size_t maxSize, std::true_type) {
processContainer(s, data, maxSize);
}
//overload for const T&
template<typename S, typename T>
void processMaxSize(S &s, const T& data, size_t maxSize, std::true_type) {
processContainer(s, const_cast<T&>(data), maxSize);
}
//try to call serialize overload with maxsize, extensions use this technique
template<typename S, typename T>
void processMaxSize(S &s, T& data, size_t maxSize, std::false_type) {
serialize(s, data, maxSize);
}
//overload for const T&
template<typename S, typename T>
void processMaxSize(S &s, const T& data, size_t maxSize, std::false_type) {
serialize(s, const_cast<T&>(data), maxSize);
}
template<typename S, typename T>
void serialize(S &s, const MaxSize<T> &ms) {
processMaxSize(s, ms.data, ms.maxSize, details::IsContainerTraitsDefined<typename std::decay<T>::type>{});
}
}
template<typename S,
typename T,
typename std::enable_if<
details::IsFundamentalType<
typename traits::ContainerTraits<T>::TValue>::value &&
traits::ContainerTraits<T>::isResizable>::type* = nullptr>
void
processContainer(S& s,
T& c,
size_t maxSize = std::numeric_limits<size_t>::max())
{
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template container<sizeof(TValue)>(c, maxSize);
}
#endif //BITSERY_DETAILS_BRIEF_SYNTAX_COMMON_H
template<typename S,
typename T,
typename std::enable_if<
!details::IsFundamentalType<
typename traits::ContainerTraits<T>::TValue>::value &&
traits::ContainerTraits<T>::isResizable>::type* = nullptr>
void
processContainer(S& s,
T& c,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.container(c, maxSize);
}
template<typename S,
typename T,
typename std::enable_if<
details::IsFundamentalType<
typename traits::ContainerTraits<T>::TValue>::value &&
!traits::ContainerTraits<T>::isResizable>::type* = nullptr>
void
processContainer(S& s, T& c)
{
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template container<sizeof(TValue)>(c);
}
template<typename S,
typename T,
typename std::enable_if<
!details::IsFundamentalType<
typename traits::ContainerTraits<T>::TValue>::value &&
!traits::ContainerTraits<T>::isResizable>::type* = nullptr>
void
processContainer(S& s, T& c)
{
s.container(c);
}
// overloads for text processing to apply maxSize
template<typename S,
typename T,
typename std::enable_if<
traits::ContainerTraits<T>::isResizable>::type* = nullptr>
void
processText(S& s, T& c, size_t maxSize = std::numeric_limits<size_t>::max())
{
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template text<sizeof(TValue)>(c, maxSize);
}
template<typename S,
typename T,
typename std::enable_if<
!traits::ContainerTraits<T>::isResizable>::type* = nullptr>
void
processText(S& s, T& c)
{
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template text<sizeof(TValue)>(c);
}
// all wrapper functions, that modify behaviour, should inherit from this
struct ModFnc
{};
// this type is used to differentiate between container and text behaviour
template<typename T, size_t N, bool isText>
struct CArray : public ModFnc
{
CArray(T (&data_)[N])
: data{ data_ } {};
T (&data)[N];
};
template<typename S, typename T, size_t N>
void
serialize(S& s, CArray<T, N, true>& str)
{
processText(s, str.data);
}
template<typename S, typename T, size_t N>
void
serialize(S& s, CArray<T, N, false>& obj)
{
processContainer(s, obj.data);
}
// used to set max container size
template<typename T>
struct MaxSize : public ModFnc
{
MaxSize(T& data_, size_t maxSize_)
: data{ data_ }
, maxSize{ maxSize_ } {};
T& data;
size_t maxSize;
};
// if container, then call procesContainer, this memcpy for fundamental types
// contiguous container
template<typename S, typename T>
void
processMaxSize(S& s, T& data, size_t maxSize, std::true_type)
{
processContainer(s, data, maxSize);
}
// overload for const T&
template<typename S, typename T>
void
processMaxSize(S& s, const T& data, size_t maxSize, std::true_type)
{
processContainer(s, const_cast<T&>(data), maxSize);
}
// try to call serialize overload with maxsize, extensions use this technique
template<typename S, typename T>
void
processMaxSize(S& s, T& data, size_t maxSize, std::false_type)
{
serialize(s, data, maxSize);
}
// overload for const T&
template<typename S, typename T>
void
processMaxSize(S& s, const T& data, size_t maxSize, std::false_type)
{
serialize(s, const_cast<T&>(data), maxSize);
}
template<typename S, typename T>
void
serialize(S& s, const MaxSize<T>& ms)
{
processMaxSize(
s,
ms.data,
ms.maxSize,
details::IsContainerTraitsDefined<typename std::decay<T>::type>{});
}
}
}
#endif // BITSERY_DETAILS_BRIEF_SYNTAX_COMMON_H

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_DETAILS_NOT_DEFINED_TYPE_H
#define BITSERY_DETAILS_NOT_DEFINED_TYPE_H
@@ -27,53 +26,56 @@
#include <iterator>
namespace bitsery {
namespace details {
//this type is used to show clearer error messages
struct NotDefinedType {
//just swallow anything that is passed during creating
template <typename ... T>
NotDefinedType(T&& ...){}
NotDefinedType() = default;
//define operators so that we also swallow deeper errors, to reduce error stack
//this time will be used as iterator, so define all operators necessary to work with iterators
friend bool operator == (const NotDefinedType&, const NotDefinedType&) {
return true;
}
friend bool operator != (const NotDefinedType&, const NotDefinedType&) {
return false;
}
NotDefinedType& operator += (int) {
return *this;
}
NotDefinedType& operator -= (int) {
return *this;
}
namespace details {
// this type is used to show clearer error messages
struct NotDefinedType
{
// just swallow anything that is passed during creating
template<typename... T>
NotDefinedType(T&&...)
{
}
NotDefinedType() = default;
// define operators so that we also swallow deeper errors, to reduce error
// stack this time will be used as iterator, so define all operators necessary
// to work with iterators
friend bool operator==(const NotDefinedType&, const NotDefinedType&)
{
return true;
}
friend bool operator!=(const NotDefinedType&, const NotDefinedType&)
{
return false;
}
NotDefinedType& operator+=(int) { return *this; }
NotDefinedType& operator-=(int) { return *this; }
friend int operator - (const NotDefinedType&, const NotDefinedType&) {
return 0;
}
friend int operator-(const NotDefinedType&, const NotDefinedType&)
{
return 0;
}
int& operator*() {
return data;
}
int data{};
};
int& operator*() { return data; }
int data{};
};
template <typename T>
struct IsDefined:public std::integral_constant<bool, !std::is_same<NotDefinedType, T>::value> {
};
}
template<typename T>
struct IsDefined
: public std::integral_constant<bool, !std::is_same<NotDefinedType, T>::value>
{};
}
}
namespace std {
//define iterator traits to work with standart algorithms
template <>
struct iterator_traits<bitsery::details::NotDefinedType> {
using difference_type = int;
using value_type = int;
using pointer = int*;
using reference = int&;
using iterator_category = std::random_access_iterator_tag;
};
// define iterator traits to work with standart algorithms
template<>
struct iterator_traits<bitsery::details::NotDefinedType>
{
using difference_type = int;
using value_type = int;
using pointer = int*;
using reference = int&;
using iterator_category = std::random_access_iterator_tag;
};
}
#endif //BITSERY_DETAILS_NOT_DEFINED_TYPE_H
#endif // BITSERY_DETAILS_NOT_DEFINED_TYPE_H

View File

@@ -1,467 +1,538 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_DETAILS_SERIALIZATION_COMMON_H
#define BITSERY_DETAILS_SERIALIZATION_COMMON_H
#include <type_traits>
#include <utility>
#include <tuple>
#include "adapter_common.h"
#include "../traits/core/traits.h"
#include "adapter_common.h"
#include <tuple>
namespace bitsery {
//this allows to call private serialize method, and construct instance (if no default constructor is provided) for your type
//just make friend it in your class
class Access {
public:
template<typename S, typename T>
static auto serialize(S &s, T &obj) -> decltype(obj.serialize(s)) {
obj.serialize(s);
}
// this allows to call private serialize method, and construct instance (if no
// default constructor is provided) for your type just make friend it in your
// class
class Access
{
public:
template<typename S, typename T>
static auto serialize(S& s, T& obj) -> decltype(obj.serialize(s))
{
obj.serialize(s);
}
template <typename T>
static T create() {
//if you get an error here, please create default constructor
return T{};
}
template <typename T>
static T* create(void* ptr) {
return new(ptr) T{};
}
template<typename T>
static T create()
{
// if you get an error here, please create default constructor
return T{};
}
template<typename T>
static T* create(void* ptr)
{
return new (ptr) T{};
}
};
};
// convenient functors that can be passed as lambda to serializer/deserializer
// instead of writing lambda e.g. instead of writing this: s.container(c, 100,
// [](S& s, float& v) { s.ext4b(v, CompactValue{});}); you can write like this
// s.container(c, 100, FtorExtValue2b<CompactValue>{});
template<size_t N, typename Ext>
struct FtorExtValue : public Ext
{
template<typename S, typename T>
void operator()(S& s, T& v) const
{
s.template ext<N>(v, static_cast<const Ext&>(*this));
}
};
template<typename Ext>
struct FtorExtValue1b : FtorExtValue<1, Ext>
{};
template<typename Ext>
struct FtorExtValue2b : FtorExtValue<2, Ext>
{};
template<typename Ext>
struct FtorExtValue4b : FtorExtValue<4, Ext>
{};
template<typename Ext>
struct FtorExtValue8b : FtorExtValue<8, Ext>
{};
template<typename Ext>
struct FtorExtValue16b : FtorExtValue<16, Ext>
{};
// convenient functors that can be passed as lambda to serializer/deserializer instead of writing lambda
// e.g. instead of writing this:
// s.container(c, 100, [](S& s, float& v) { s.ext4b(v, CompactValue{});});
// you can write like this
// s.container(c, 100, FtorExtValue2b<CompactValue>{});
template<size_t N, typename Ext>
struct FtorExtValue : public Ext {
template <typename S, typename T>
void operator()(S& s, T& v) const {
s.template ext<N>(v, static_cast<const Ext&>(*this));
}
};
template<typename Ext>
struct FtorExtObject : public Ext
{
template<typename S, typename T>
void operator()(S& s, T& v) const
{
s.ext(v, static_cast<const Ext&>(*this));
}
};
template <typename Ext>
struct FtorExtValue1b: FtorExtValue<1, Ext> {};
template <typename Ext>
struct FtorExtValue2b: FtorExtValue<2, Ext> {};
template <typename Ext>
struct FtorExtValue4b: FtorExtValue<4, Ext> {};
template <typename Ext>
struct FtorExtValue8b: FtorExtValue<8, Ext> {};
template <typename Ext>
struct FtorExtValue16b: FtorExtValue<16, Ext> {};
// when call to serialize function is ambiguous (member and non-member serialize
// function exists for a type) specialize this class by inheriting from either
// UseNonMemberFnc or UseMemberFnc e.g. template <> struct
// SelectSerializeFnc<MyDerivedClass>:UseMemberFnc {};
template<typename T>
struct SelectSerializeFnc : std::integral_constant<int, 0>
{};
template<typename Ext>
struct FtorExtObject : public Ext {
template <typename S, typename T>
void operator()(S& s, T& v) const {
s.ext(v, static_cast<const Ext&>(*this));
}
};
// types you need to inherit from when specializing SelectSerializeFnc class
struct UseNonMemberFnc : std::integral_constant<int, 1>
{};
struct UseMemberFnc : std::integral_constant<int, 2>
{};
namespace details {
//when call to serialize function is ambiguous (member and non-member serialize function exists for a type)
//specialize this class by inheriting from either UseNonMemberFnc or UseMemberFnc
//e.g.
//template <> struct SelectSerializeFnc<MyDerivedClass>:UseMemberFnc {};
template<typename T>
struct SelectSerializeFnc : std::integral_constant<int, 0> {
};
// helper types for error handling
template<typename T>
struct IsContainerTraitsDefined
: public IsDefined<typename traits::ContainerTraits<T>::TValue>
{};
//types you need to inherit from when specializing SelectSerializeFnc class
struct UseNonMemberFnc : std::integral_constant<int, 1> {
};
struct UseMemberFnc : std::integral_constant<int, 2> {
};
template<typename T>
struct IsTextTraitsDefined
: public IsDefined<typename traits::TextTraits<T>::TValue>
{};
namespace details {
//helper types for error handling
template<typename T>
struct IsContainerTraitsDefined : public IsDefined<typename traits::ContainerTraits<T>::TValue> {
};
template<typename T>
struct IsTextTraitsDefined : public IsDefined<typename traits::TextTraits<T>::TValue> {
};
template<typename Ext, typename T>
struct IsExtensionTraitsDefined : public IsDefined<typename traits::ExtensionTraits<Ext, T>::TValue> {
};
template<typename Ext, typename T>
struct IsExtensionTraitsDefined
: public IsDefined<typename traits::ExtensionTraits<Ext, T>::TValue>
{};
#ifdef _MSC_VER
//helper types for HasSerializeFunction
template <typename S, typename T>
using TrySerializeFunction = decltype(serialize(std::declval<S &>(), std::declval<T &>()));
// helper types for HasSerializeFunction
template<typename S, typename T>
using TrySerializeFunction =
decltype(serialize(std::declval<S&>(), std::declval<T&>()));
template <typename S, typename T>
struct HasSerializeFunctionHelper {
template <typename Q, typename R, typename = TrySerializeFunction<Q, R>>
static std::true_type tester(Q&&, R&&);
static std::false_type tester(...);
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
};
template <typename S, typename T>
struct HasSerializeFunction :HasSerializeFunctionHelper<S, T>::type {};
template<typename S, typename T>
struct HasSerializeFunctionHelper
{
template<typename Q, typename R, typename = TrySerializeFunction<Q, R>>
static std::true_type tester(Q&&, R&&);
static std::false_type tester(...);
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
};
template<typename S, typename T>
struct HasSerializeFunction : HasSerializeFunctionHelper<S, T>::type
{};
//helper types for HasSerializeMethod
template <typename S, typename T>
using TrySerializeMethod = decltype(Access::serialize(std::declval<S &>(), std::declval<T &>()));
// helper types for HasSerializeMethod
template<typename S, typename T>
using TrySerializeMethod =
decltype(Access::serialize(std::declval<S&>(), std::declval<T&>()));
template <typename S, typename T>
struct HasSerializeMethodHelper {
template <typename Q, typename R, typename = TrySerializeMethod<Q, R>>
static std::true_type tester(Q&&, R&&);
static std::false_type tester(...);
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
};
template <typename S, typename T>
struct HasSerializeMethod :HasSerializeMethodHelper<S, T>::type {};
template<typename S, typename T>
struct HasSerializeMethodHelper
{
template<typename Q, typename R, typename = TrySerializeMethod<Q, R>>
static std::true_type tester(Q&&, R&&);
static std::false_type tester(...);
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
};
template<typename S, typename T>
struct HasSerializeMethod : HasSerializeMethodHelper<S, T>::type
{};
//helper types for IsBriefSyntaxIncluded
template <typename S, typename T>
using TryProcessBriefSyntax = decltype(processBriefSyntax(std::declval<S &>(), std::declval<T &&>()));
// helper types for IsBriefSyntaxIncluded
template<typename S, typename T>
using TryProcessBriefSyntax =
decltype(processBriefSyntax(std::declval<S&>(), std::declval<T&&>()));
template <typename S, typename T>
struct IsBriefSyntaxIncludedHelper {
template <typename Q, typename R, typename = TryProcessBriefSyntax<Q, R>>
static std::true_type tester(Q&&, R&&);
static std::false_type tester(...);
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
};
template<typename S, typename T>
struct IsBriefSyntaxIncludedHelper
{
template<typename Q, typename R, typename = TryProcessBriefSyntax<Q, R>>
static std::true_type tester(Q&&, R&&);
static std::false_type tester(...);
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
};
template <typename S, typename T>
struct IsBriefSyntaxIncluded :IsBriefSyntaxIncludedHelper<S, T>::type {};
template<typename S, typename T>
struct IsBriefSyntaxIncluded : IsBriefSyntaxIncludedHelper<S, T>::type
{};
#else
//helper metafunction, that is added to c++17
template<typename... Ts>
struct make_void {
typedef void type;
};
template<typename... Ts>
using void_t = typename make_void<Ts...>::type;
// helper metafunction, that is added to c++17
template<typename... Ts>
struct make_void
{
typedef void type;
};
template<typename... Ts>
using void_t = typename make_void<Ts...>::type;
template<typename, typename, typename = void>
struct HasSerializeFunction : std::false_type {
};
template<typename, typename, typename = void>
struct HasSerializeFunction : std::false_type
{};
template<typename S, typename T>
struct HasSerializeFunction<S, T,
void_t<decltype(serialize(std::declval<S &>(), std::declval<T &>()))>
> : std::true_type {
};
template<typename S, typename T>
struct HasSerializeFunction<
S,
T,
void_t<decltype(serialize(std::declval<S&>(), std::declval<T&>()))>>
: std::true_type
{};
template<typename, typename, typename = void>
struct HasSerializeMethod : std::false_type
{};
template<typename, typename, typename = void>
struct HasSerializeMethod : std::false_type {
};
template<typename S, typename T>
struct HasSerializeMethod<
S,
T,
void_t<decltype(Access::serialize(std::declval<S&>(), std::declval<T&>()))>>
: std::true_type
{};
template<typename S, typename T>
struct HasSerializeMethod<S, T,
void_t<decltype(Access::serialize(std::declval<S &>(), std::declval<T &>()))>
> : std::true_type {
};
// this solution doesn't work with visual studio, but is more elegant
template<typename, typename, typename = void>
struct IsBriefSyntaxIncluded : std::false_type
{};
//this solution doesn't work with visual studio, but is more elegant
template<typename, typename, typename = void>
struct IsBriefSyntaxIncluded : std::false_type {
};
template<typename S, typename T>
struct IsBriefSyntaxIncluded<S, T,
void_t<decltype(processBriefSyntax(std::declval<S &>(), std::declval<T &&>()))>
> : std::true_type {
};
template<typename S, typename T>
struct IsBriefSyntaxIncluded<
S,
T,
void_t<decltype(processBriefSyntax(std::declval<S&>(), std::declval<T&&>()))>>
: std::true_type
{};
#endif
//used for extensions when extension TValue = void
struct DummyType {
};
// used for extensions when extension TValue = void
struct DummyType
{};
/*
* this includes all integral types, floats and enums(except bool)
*/
template<typename T>
struct IsFundamentalType : std::integral_constant<bool,
std::is_enum<T>::value
|| std::is_floating_point<T>::value
|| std::is_integral<T>::value> {
};
template<typename T>
struct IsFundamentalType
: std::integral_constant<bool,
std::is_enum<T>::value ||
std::is_floating_point<T>::value ||
std::is_integral<T>::value>
{};
template<typename T, typename Integral = void>
struct IntegralFromFundamental {
using TValue = T;
};
template<typename T, typename Integral = void>
struct IntegralFromFundamental
{
using TValue = T;
};
template<typename T>
struct IntegralFromFundamental<T, typename std::enable_if<std::is_enum<T>::value>::type> {
using TValue = typename std::underlying_type<T>::type;
};
template<typename T>
struct IntegralFromFundamental<
T,
typename std::enable_if<std::is_enum<T>::value>::type>
{
using TValue = typename std::underlying_type<T>::type;
};
template<typename T>
struct IntegralFromFundamental<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
using TValue = typename std::conditional<std::is_same<T, float>::value, uint32_t, uint64_t>::type;
};
template<typename T>
struct IntegralFromFundamental<
T,
typename std::enable_if<std::is_floating_point<T>::value>::type>
{
using TValue = typename std::
conditional<std::is_same<T, float>::value, uint32_t, uint64_t>::type;
};
template<typename T>
struct UnsignedFromFundamental {
using type = typename std::make_unsigned<typename IntegralFromFundamental<T>::TValue>::type;
};
template<typename T>
using SameSizeUnsigned = typename UnsignedFromFundamental<T>::type;
template<typename T>
struct UnsignedFromFundamental
{
using type = typename std::make_unsigned<
typename IntegralFromFundamental<T>::TValue>::type;
};
template<typename T>
using SameSizeUnsigned = typename UnsignedFromFundamental<T>::type;
/*
* functions for object serialization
*/
template<typename S, typename T>
struct SerializeFunction {
template<typename S, typename T>
struct SerializeFunction
{
static void invoke(S &s, T &v) {
static_assert(HasSerializeFunction<S, T>::value || HasSerializeMethod<S, T>::value,
"\nPlease define 'serialize' function for your type (inside or outside of class):\n"
" template<typename S>\n"
" void serialize(S& s)\n"
" {\n"
" ...\n"
" }\n");
using TDecayed = typename std::decay<T>::type;
selectSerializeFnc(s, v, SelectSerializeFnc<TDecayed>{});
}
static void invoke(S& s, T& v)
{
static_assert(HasSerializeFunction<S, T>::value ||
HasSerializeMethod<S, T>::value,
"\nPlease define 'serialize' function for your type (inside "
"or outside of class):\n"
" template<typename S>\n"
" void serialize(S& s)\n"
" {\n"
" ...\n"
" }\n");
using TDecayed = typename std::decay<T>::type;
selectSerializeFnc(s, v, SelectSerializeFnc<TDecayed>{});
}
static constexpr bool isDefined() {
return HasSerializeFunction<S, T>::value || HasSerializeMethod<S, T>::value;
}
static constexpr bool isDefined()
{
return HasSerializeFunction<S, T>::value || HasSerializeMethod<S, T>::value;
}
private:
static void selectSerializeFnc(S &s, T &v, std::integral_constant<int, 0>) {
static_assert(!(HasSerializeFunction<S, T>::value && HasSerializeMethod<S, T>::value),
"\nPlease define only one 'serialize' function (member OR free).\n"
"If serialization function is inherited from base class, then explicitly select correct function for your type e.g.:\n"
" template <>\n"
" struct SelectSerializeFnc<DerivedClass>:UseMemberFnc {};\n");
selectSerializeFnc(s, v, std::integral_constant<int,
HasSerializeFunction<S, T>::value ? 1 : 2>{});
}
private:
static void selectSerializeFnc(S& s, T& v, std::integral_constant<int, 0>)
{
static_assert(
!(HasSerializeFunction<S, T>::value && HasSerializeMethod<S, T>::value),
"\nPlease define only one 'serialize' function (member OR free).\n"
"If serialization function is inherited from base class, then explicitly "
"select correct function for your type e.g.:\n"
" template <>\n"
" struct SelectSerializeFnc<DerivedClass>:UseMemberFnc {};\n");
selectSerializeFnc(s,
v,
std::integral_constant < int,
HasSerializeFunction<S, T>::value ? 1 : 2 > {});
}
static void selectSerializeFnc(S &s, T &v, std::integral_constant<int, 1>) {
serialize(s, v);
}
static void selectSerializeFnc(S& s, T& v, std::integral_constant<int, 1>)
{
serialize(s, v);
}
static void selectSerializeFnc(S &s, T &v, std::integral_constant<int, 2>) {
Access::serialize(s, v);
}
};
static void selectSerializeFnc(S& s, T& v, std::integral_constant<int, 2>)
{
Access::serialize(s, v);
}
};
/*
* functions for object serialization
*/
template<typename S, typename T, typename Enabled = void>
struct BriefSyntaxFunction {
template<typename S, typename T, typename Enabled = void>
struct BriefSyntaxFunction
{
static void invoke(S &s, T &&obj) {
static_assert(IsBriefSyntaxIncluded<S, T>::value,
"\nPlease include '<bitsery/brief_syntax.h>' to use operator():\n");
static void invoke(S& s, T&& obj)
{
static_assert(
IsBriefSyntaxIncluded<S, T>::value,
"\nPlease include '<bitsery/brief_syntax.h>' to use operator():\n");
processBriefSyntax(s, std::forward<T>(obj));
}
};
processBriefSyntax(s, std::forward<T>(obj));
}
};
/*
* helper function for getting context from serializer/deserializer
*/
/*
* helper function for getting context from serializer/deserializer
*/
template<int Index, typename... Conds>
struct FindIndex : std::integral_constant<int, Index> {};
template<int Index, typename... Conds>
struct FindIndex : std::integral_constant<int, Index>
{};
template<int Index, typename Cond, typename... Conds>
struct FindIndex<Index, Cond, Conds...> :
std::conditional<Cond::value, std::integral_constant<int, Index>, FindIndex<Index+1, Conds...>>::type
{};
template<int Index, typename Cond, typename... Conds>
struct FindIndex<Index, Cond, Conds...>
: std::conditional<Cond::value,
std::integral_constant<int, Index>,
FindIndex<Index + 1, Conds...>>::type
{};
template <typename T, typename Tuple>
struct GetConvertibleTypeIndexFromTuple;
template<typename T, typename Tuple>
struct GetConvertibleTypeIndexFromTuple;
template <typename T, typename... Us>
struct GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>> : FindIndex<0, std::is_convertible<Us&, T&>...> {};
template<typename T, typename... Us>
struct GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>
: FindIndex<0, std::is_convertible<Us&, T&>...>
{};
template<typename T, typename Tuple>
struct IsExistsConvertibleTupleType;
template <typename T, typename Tuple>
struct IsExistsConvertibleTupleType;
template<typename T, typename... Us>
struct IsExistsConvertibleTupleType<T, std::tuple<Us...>>
: std::integral_constant<
bool,
GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>::value !=
sizeof...(Us)>
{};
template <typename T, typename... Us>
struct IsExistsConvertibleTupleType<T, std::tuple<Us...>> :
std::integral_constant<bool, GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>::value != sizeof...(Us)> {};
/*
* get context from internal or external, and check if it's convertible or not
*/
template<bool AssertExists, typename TCast, typename TContext>
TCast*
getDirectlyIfExists(TContext& ctx, std::true_type)
{
return &static_cast<TCast&>(ctx);
}
/*
* get context from internal or external, and check if it's convertible or not
*/
template<bool AssertExists, typename TCast, typename TContext>
TCast*
getDirectlyIfExists(TContext&, std::false_type)
{
// TCast cannot be convertible from provided context
static_assert(
!AssertExists,
"Invalid context cast. Context type doesn't exists.\nSome functionality "
"requires (de)seserializer to have specific context.");
return nullptr;
}
template<bool AssertExists, typename TCast, typename... TArgs>
TCast*
getFromTupleIfExists(std::tuple<TArgs...>& ctx, std::true_type)
{
using TupleIndex =
GetConvertibleTypeIndexFromTuple<TCast, std::tuple<TArgs...>>;
return &static_cast<TCast&>(std::get<TupleIndex::value>(ctx));
}
template<bool AssertExists, typename TCast, typename TContext>
TCast* getDirectlyIfExists(TContext& ctx, std::true_type) {
return &static_cast<TCast&>(ctx);
}
template<bool AssertExists, typename TCast, typename... TArgs>
TCast*
getFromTupleIfExists(std::tuple<TArgs...>&, std::false_type)
{
// TCast cannot be convertible from provided context
static_assert(
!AssertExists,
"Invalid context cast. Context type doesn't exists.\nSome functionality "
"requires (de)seserializer to have specific context.");
return nullptr;
}
template<bool AssertExists, typename TCast, typename TContext>
TCast* getDirectlyIfExists(TContext& , std::false_type) {
// TCast cannot be convertible from provided context
static_assert(!AssertExists,
"Invalid context cast. Context type doesn't exists.\nSome functionality requires (de)seserializer to have specific context.");
return nullptr;
}
// non tuple context
template<bool AssertExists, typename TCast, typename TContext>
TCast*
getContext(TContext& ctx)
{
return getDirectlyIfExists<AssertExists, TCast>(
ctx, std::is_convertible<TContext&, TCast&>{});
}
// tuple context
template<bool AssertExists, typename TCast, typename... TArgs>
TCast*
getContext(std::tuple<TArgs...>& ctx)
{
return getFromTupleIfExists<AssertExists, TCast>(
ctx, IsExistsConvertibleTupleType<TCast, std::tuple<TArgs...>>{});
}
template<bool AssertExists, typename TCast, typename ... TArgs>
TCast* getFromTupleIfExists(std::tuple<TArgs...>& ctx, std::true_type) {
using TupleIndex = GetConvertibleTypeIndexFromTuple<TCast, std::tuple<TArgs...>>;
return &static_cast<TCast&>(std::get<TupleIndex::value>(ctx));
}
template<typename Adapter, typename Context>
class AdapterAndContextRef
{
public:
static constexpr bool HasContext = true;
using Config = typename Adapter::TConfig;
template<bool AssertExists, typename TCast, typename ... TArgs>
TCast* getFromTupleIfExists(std::tuple<TArgs...>& , std::false_type) {
// TCast cannot be convertible from provided context
static_assert(!AssertExists,
"Invalid context cast. Context type doesn't exists.\nSome functionality requires (de)seserializer to have specific context.");
return nullptr;
}
// constructing adapter in place is important,
// because enableBitPacking might create instance with bit write/read enabled
// adapter wrapper, which has non trivial destructor
template<typename... TArgs>
explicit AdapterAndContextRef(Context& ctx, TArgs&&... args)
: _adapter{ std::forward<TArgs>(args)... }
, _context{ ctx }
{
}
//non tuple context
template<bool AssertExists, typename TCast, typename TContext>
TCast* getContext(TContext& ctx) {
return getDirectlyIfExists<AssertExists, TCast>(ctx, std::is_convertible<TContext&, TCast&>{});
}
/*
* get serialization context.
* this is optional, but might be required for some specific serialization
* flows.
*/
//tuple context
template<bool AssertExists, typename TCast, typename ... TArgs>
TCast* getContext(std::tuple<TArgs...>& ctx) {
return getFromTupleIfExists<AssertExists, TCast>(ctx, IsExistsConvertibleTupleType<TCast, std::tuple<TArgs...>>{});
}
template<typename T>
T& context()
{
return *getContext<true, T>(_context);
}
template <typename Adapter, typename Context>
class AdapterAndContextRef {
public:
static constexpr bool HasContext = true;
using Config = typename Adapter::TConfig;
template<typename T>
T* contextOrNull()
{
return getContext<false, T>(_context);
}
// constructing adapter in place is important,
// because enableBitPacking might create instance with bit write/read enabled adapter wrapper,
// which has non trivial destructor
template <typename ... TArgs>
explicit AdapterAndContextRef(Context& ctx, TArgs&& ... args)
: _adapter{std::forward<TArgs>(args)...},
_context{ctx}
{
}
Adapter& adapter() & { return _adapter; }
/*
* get serialization context.
* this is optional, but might be required for some specific serialization flows.
*/
Adapter adapter() && { return std::move(_adapter); }
template <typename T>
T& context() {
return *getContext<true, T>(_context);
}
protected:
Adapter _adapter;
Context& _context;
};
template <typename T>
T* contextOrNull() {
return getContext<false, T>(_context);
}
template<typename Adapter>
class AdapterAndContextRef<Adapter, void>
{
public:
static constexpr bool HasContext = false;
using Config = typename Adapter::TConfig;
Adapter& adapter() & {
return _adapter;
}
template<typename... TArgs>
explicit AdapterAndContextRef(TArgs&&... args)
: _adapter{ std::forward<TArgs>(args)... }
{
}
Adapter adapter() && {
return std::move(_adapter);
}
template<typename T>
T& context()
{
static_assert(std::is_void<T>::value, "Context is not defined (is void).");
}
protected:
Adapter _adapter;
Context& _context;
};
template<typename T>
T* contextOrNull()
{
return nullptr;
}
template <typename Adapter>
class AdapterAndContextRef<Adapter, void> {
public:
static constexpr bool HasContext = false;
using Config = typename Adapter::TConfig;
Adapter& adapter() & { return _adapter; }
template <typename ... TArgs>
explicit AdapterAndContextRef(TArgs&& ... args)
: _adapter{std::forward<TArgs>(args)...}
{
}
Adapter adapter() && { return std::move(_adapter); }
template <typename T>
T& context() {
static_assert(std::is_void<T>::value, "Context is not defined (is void).");
}
template <typename T>
T* contextOrNull() {
return nullptr;
}
Adapter& adapter() & {
return _adapter;
}
Adapter adapter() && {
return std::move(_adapter);
}
protected:
Adapter _adapter;
};
protected:
Adapter _adapter;
};
/**
* other helper meta-functions
*/
template<typename T, template<typename...> class Template>
struct IsSpecializationOf : std::false_type {
};
template<typename T, template<typename...> class Template>
struct IsSpecializationOf : std::false_type
{};
template<template<typename...> class Template, typename... Args>
struct IsSpecializationOf<Template<Args...>, Template> : std::true_type {
};
template<template<typename...> class Template, typename... Args>
struct IsSpecializationOf<Template<Args...>, Template> : std::true_type
{};
}
}
}
#endif //BITSERY_DETAILS_SERIALIZATION_COMMON_H
#endif // BITSERY_DETAILS_SERIALIZATION_COMMON_H

View File

@@ -1,190 +1,220 @@
//MIT License
// MIT License
//
//Copyright (c) 2018 Mindaugas Vinkelis
// 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:
// 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 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.
// 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_EXT_COMPACT_VALUE_H
#define BITSERY_EXT_COMPACT_VALUE_H
#include "../details/serialization_common.h"
#include "../details/adapter_common.h"
#include <cassert>
namespace bitsery {
namespace details {
namespace details {
template <bool CheckOverflow>
class CompactValueImpl {
public:
template<bool CheckOverflow>
class CompactValueImpl
{
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& s, const T& v, Fnc&&) const
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
using TValue = typename IntegralFromFundamental<T>::TValue;
serializeImpl(s.adapter(),
reinterpret_cast<const TValue&>(v),
std::integral_constant<bool, sizeof(T) != 1>{});
}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &s, const T &v, Fnc &&) const {
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
using TValue = typename IntegralFromFundamental<T>::TValue;
serializeImpl(s.adapter(), reinterpret_cast<const TValue&>(v), std::integral_constant<bool, sizeof(T) != 1>{});
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& d, T& v, Fnc&&) const
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
using TValue = typename IntegralFromFundamental<T>::TValue;
deserializeImpl(d.adapter(),
reinterpret_cast<TValue&>(v),
std::integral_constant<bool, sizeof(T) != 1>{});
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &d, T &v, Fnc &&) const {
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
using TValue = typename IntegralFromFundamental<T>::TValue;
deserializeImpl(d.adapter(), reinterpret_cast<TValue &>(v), std::integral_constant<bool, sizeof(T) != 1>{});
}
private:
// if value is 1byte size, just serialize/ deserialize whole value
template<typename Writer, typename T>
void serializeImpl(Writer& writer, const T& v, std::false_type) const
{
writer.template writeBytes<1>(v);
}
private:
template<typename Reader, typename T>
void deserializeImpl(Reader& reader, T& v, std::false_type) const
{
reader.template readBytes<1>(v);
}
// if value is 1byte size, just serialize/ deserialize whole value
template<typename Writer, typename T>
void serializeImpl(Writer &writer, const T &v, std::false_type) const {
writer.template writeBytes<1>(v);
}
// when value is bigger than 1byte size,
template<typename Writer, typename T>
void serializeImpl(Writer& writer, const T& v, std::true_type) const
{
auto val = zigZagEncode(
v, std::is_signed<typename IntegralFromFundamental<T>::TValue>{});
writeBytes(writer, val);
}
template<typename Reader, typename T>
void deserializeImpl(Reader &reader, T &v, std::false_type) const {
reader.template readBytes<1>(v);
}
template<typename Reader, typename T>
void deserializeImpl(Reader& reader, T& v, std::true_type) const
{
using TUnsigned = SameSizeUnsigned<T>;
TUnsigned res{};
readBytes<Reader::TConfig::CheckDataErrors>(reader, res);
v = zigZagDecode<T>(
res, std::is_signed<typename IntegralFromFundamental<T>::TValue>{});
}
// when value is bigger than 1byte size,
template<typename Writer, typename T>
void serializeImpl(Writer &writer, const T &v, std::true_type) const {
auto val = zigZagEncode(v, std::is_signed<typename IntegralFromFundamental<T>::TValue>{});
writeBytes(writer, val);
}
// zigzag encode signed types
template<typename T>
const SameSizeUnsigned<T>& zigZagEncode(const T& v, std::false_type) const
{
return v;
}
template<typename TResult, typename TUnsigned>
const TResult& zigZagDecode(const TUnsigned& v, std::false_type) const
{
return v;
}
template<typename Reader, typename T>
void deserializeImpl(Reader &reader, T &v, std::true_type) const {
using TUnsigned = SameSizeUnsigned<T>;
TUnsigned res{};
readBytes<Reader::TConfig::CheckDataErrors>(reader, res);
v = zigZagDecode<T>(res, std::is_signed<typename IntegralFromFundamental<T>::TValue>{});
}
template<typename T>
SameSizeUnsigned<T> zigZagEncode(const T& v, std::true_type) const
{
return static_cast<SameSizeUnsigned<T>>((v << 1) ^
(v >> (BitsSize<T>::value - 1)));
}
// zigzag encode signed types
template<typename T>
const SameSizeUnsigned<T> &zigZagEncode(const T &v, std::false_type) const {
return v;
}
template<typename TResult, typename TUnsigned>
const TResult &zigZagDecode(const TUnsigned &v, std::false_type) const{
return v;
}
template<typename T>
SameSizeUnsigned<T> zigZagEncode(const T &v, std::true_type) const {
return static_cast<SameSizeUnsigned<T>>((v << 1) ^ (v >> (BitsSize<T>::value - 1)));
}
template<typename TResult, typename TUnsigned>
TResult zigZagDecode(TUnsigned v, std::true_type) const {
return static_cast<TResult>((v >> 1) ^ (~(v & 1) + 1)); // same as -(v & 1), but no warning on VisualStudio
}
// write/read bytes one by one
template<typename Writer, typename T>
void writeBytes(Writer &w, const T &v) const {
using TFast = typename FastType<T>::type;
auto val= static_cast<TFast>(v);
while(val > 0x7Fu) {
w.template writeBytes<1>(static_cast<uint8_t>(val | 0x80u));
val >>=7u;
}
w.template writeBytes<1>(static_cast<uint8_t>(val));
}
template<bool CheckErrors, typename Reader, typename T>
void readBytes(Reader &r, T &v) const {
using TFast = typename FastType<T>::type;
constexpr auto TBITS = sizeof(T)*8;
uint8_t b1{0x80u};
auto i = 0u;
TFast tmp={};
for (;i < TBITS && b1 > 0x7Fu; i +=7u) {
r.template readBytes<1>(b1);
tmp += static_cast<TFast>(b1 & 0x7Fu) << i;
}
v = static_cast<T>(tmp);
handleReadOverflow<Reader, T>(r, i, b1,
std::integral_constant<bool, CheckOverflow && CheckErrors>{});
}
template <typename Reader, typename T>
void handleReadOverflow(Reader& r, unsigned shiftedBy, uint8_t remainder, std::true_type) const {
constexpr auto TBITS = sizeof(T)*8;
if (shiftedBy > TBITS && remainder >> (TBITS + 7 - shiftedBy)) {
r.error(bitsery::ReaderError::InvalidData);
}
}
template <typename Reader, typename T>
void handleReadOverflow(Reader &, unsigned , uint8_t , std::false_type) const {
}
};
template<typename TResult, typename TUnsigned>
TResult zigZagDecode(TUnsigned v, std::true_type) const
{
return static_cast<TResult>(
(v >> 1) ^
(~(v & 1) + 1)); // same as -(v & 1), but no warning on VisualStudio
}
// write/read bytes one by one
template<typename Writer, typename T>
void writeBytes(Writer& w, const T& v) const
{
using TFast = typename FastType<T>::type;
auto val = static_cast<TFast>(v);
while (val > 0x7Fu) {
w.template writeBytes<1>(static_cast<uint8_t>(val | 0x80u));
val >>= 7u;
}
w.template writeBytes<1>(static_cast<uint8_t>(val));
}
namespace ext {
// this type will use value overload, and do not check if type is sufficiently large during deserialization
class CompactValue: public details::CompactValueImpl<false> {};
// this type will enable object overload, and set DataOverflow if value doesn't fit in type, during deserialization
class CompactValueAsObject: public details::CompactValueImpl<true> {};
template<bool CheckErrors, typename Reader, typename T>
void readBytes(Reader& r, T& v) const
{
using TFast = typename FastType<T>::type;
constexpr auto TBITS = sizeof(T) * 8;
uint8_t b1{ 0x80u };
auto i = 0u;
TFast tmp = {};
for (; i < TBITS && b1 > 0x7Fu; i += 7u) {
r.template readBytes<1>(b1);
tmp += static_cast<TFast>(b1 & 0x7Fu) << i;
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::CompactValue, T> {
using TValue = T;
static constexpr bool SupportValueOverload = true;
// disable object overload, because we don't have implemented serialization function for fundamental types
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
template<typename T>
struct ExtensionTraits<ext::CompactValueAsObject, T> {
// use dummy implemenations for value and object overload
using TValue = void;
// only enable object overload
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
template<typename T, bool Check>
struct ExtensionTraits<details::CompactValueImpl<Check>, T> {
using TValue = T;
static constexpr bool SupportValueOverload = !Check;
static constexpr bool SupportObjectOverload = Check;
static constexpr bool SupportLambdaOverload = false;
};
v = static_cast<T>(tmp);
handleReadOverflow<Reader, T>(r,
i,
b1,
std::integral_constant < bool,
CheckOverflow&& CheckErrors > {});
}
template<typename Reader, typename T>
void handleReadOverflow(Reader& r,
unsigned shiftedBy,
uint8_t remainder,
std::true_type) const
{
constexpr auto TBITS = sizeof(T) * 8;
if (shiftedBy > TBITS && remainder >> (TBITS + 7 - shiftedBy)) {
r.error(bitsery::ReaderError::InvalidData);
}
}
template<typename Reader, typename T>
void handleReadOverflow(Reader&, unsigned, uint8_t, std::false_type) const
{
}
};
}
namespace ext {
#endif //BITSERY_EXT_COMPACT_VALUE_H
// this type will use value overload, and do not check if type is sufficiently
// large during deserialization
class CompactValue : public details::CompactValueImpl<false>
{};
// this type will enable object overload, and set DataOverflow if value doesn't
// fit in type, during deserialization
class CompactValueAsObject : public details::CompactValueImpl<true>
{};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::CompactValue, T>
{
using TValue = T;
static constexpr bool SupportValueOverload = true;
// disable object overload, because we don't have implemented serialization
// function for fundamental types
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
template<typename T>
struct ExtensionTraits<ext::CompactValueAsObject, T>
{
// use dummy implemenations for value and object overload
using TValue = void;
// only enable object overload
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
template<typename T, bool Check>
struct ExtensionTraits<details::CompactValueImpl<Check>, T>
{
using TValue = T;
static constexpr bool SupportValueOverload = !Check;
static constexpr bool SupportObjectOverload = Check;
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif // BITSERY_EXT_COMPACT_VALUE_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_EXT_ENTROPY_H
#define BITSERY_EXT_ENTROPY_H
@@ -27,78 +27,88 @@
namespace bitsery {
namespace details {
template<typename TValue, typename TContainer>
size_t findEntropyIndex(const TValue &v, const TContainer &defValues) {
size_t index{1u};
for (auto &d:defValues) {
if (d == v)
return index;
++index;
}
return 0u;
}
}
namespace details {
template<typename TValue, typename TContainer>
size_t
findEntropyIndex(const TValue& v, const TContainer& defValues)
{
size_t index{ 1u };
for (auto& d : defValues) {
if (d == v)
return index;
++index;
}
return 0u;
}
}
namespace ext {
namespace ext {
template<typename TContainer>
class Entropy {
public:
template<typename TContainer>
class Entropy
{
public:
/**
* Allows entropy-encoding technique, by writing few bits for most common
* values
* @param values list of most common values
* @param alignBeforeData only makes sense when bit-packing enabled, by
* default aligns after writing bits for index
*/
constexpr Entropy(TContainer& values, bool alignBeforeData = true)
: _values{ values }
, _alignBeforeData{ alignBeforeData } {};
/**
* Allows entropy-encoding technique, by writing few bits for most common values
* @param values list of most common values
* @param alignBeforeData only makes sense when bit-packing enabled, by default aligns after writing bits for index
*/
constexpr Entropy(TContainer& values, bool alignBeforeData=true)
: _values{values},
_alignBeforeData{alignBeforeData} {
};
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& s, const T& obj, Fnc&& fnc) const
{
assert(traits::ContainerTraits<TContainer>::size(_values) > 0);
auto index = details::findEntropyIndex(obj, _values);
s.ext(index,
ext::ValueRange<size_t>{
0u, traits::ContainerTraits<TContainer>::size(_values) });
if (_alignBeforeData)
s.adapter().align();
if (!index)
fnc(s, const_cast<T&>(obj));
}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &s, const T &obj, Fnc &&fnc) const {
assert(traits::ContainerTraits<TContainer>::size(_values) > 0);
auto index = details::findEntropyIndex(obj, _values);
s.ext(index, ext::ValueRange<size_t>{0u, traits::ContainerTraits<TContainer>::size(_values)});
if (_alignBeforeData)
s.adapter().align();
if (!index)
fnc(s, const_cast<T &>(obj));
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& d, T& obj, Fnc&& fnc) const
{
assert(traits::ContainerTraits<TContainer>::size(_values) > 0);
size_t index{};
d.ext(index,
ext::ValueRange<size_t>{
0u, traits::ContainerTraits<TContainer>::size(_values) });
if (_alignBeforeData)
d.adapter().align();
if (index) {
using TDiff = typename std::iterator_traits<decltype(std::begin(
_values))>::difference_type;
obj = static_cast<T>(
*std::next(std::begin(_values), static_cast<TDiff>(index - 1)));
} else
fnc(d, obj);
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &d, T &obj, Fnc &&fnc) const {
assert(traits::ContainerTraits<TContainer>::size(_values) > 0);
size_t index{};
d.ext(index, ext::ValueRange<size_t>{0u, traits::ContainerTraits<TContainer>::size(_values)});
if (_alignBeforeData)
d.adapter().align();
if (index) {
using TDiff = typename std::iterator_traits<decltype(std::begin(_values))>::difference_type;
obj = static_cast<T>(*std::next(std::begin(_values), static_cast<TDiff>(index-1)));
}
else
fnc(d, obj);
}
private:
TContainer& _values;
bool _alignBeforeData;
};
}
private:
TContainer& _values;
bool _alignBeforeData;
};
}
namespace traits {
template<typename TContainer, typename T>
struct ExtensionTraits<ext::Entropy<TContainer>, T> {
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
namespace traits {
template<typename TContainer, typename T>
struct ExtensionTraits<ext::Entropy<TContainer>, T>
{
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_ENTROPY_H
#endif // BITSERY_EXT_ENTROPY_H

View File

@@ -1,84 +1,89 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_EXT_GROWABLE_H
#define BITSERY_EXT_GROWABLE_H
#include "../traits/core/traits.h"
#include <cstdint>
namespace bitsery {
namespace ext {
namespace ext {
/*
* enables forward and backward compatibility, by allowing to append additional data at the end of serialization
* old deserialization method will ignore additional data by jumping through it at the end of deserialization flow
* new deserialization method will read all 0 for new fields if there is no data for it
*/
class Growable {
public:
/*
* enables forward and backward compatibility, by allowing to append additional
* data at the end of serialization old deserialization method will ignore
* additional data by jumping through it at the end of deserialization flow new
* deserialization method will read all 0 for new fields if there is no data for
* it
*/
class Growable
{
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
{
auto& writer = ser.adapter();
const auto startPos = writer.currentWritePos();
writer.template writeBytes<4>(static_cast<uint32_t>(0));
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
auto& writer = ser.adapter();
const auto startPos = writer.currentWritePos();
writer.template writeBytes<4>(static_cast<uint32_t>(0));
fnc(ser, const_cast<T&>(obj));
fnc(ser, const_cast<T&>(obj));
const auto endPos = writer.currentWritePos();
writer.currentWritePos(startPos);
writer.template writeBytes<4>(static_cast<uint32_t>(endPos - startPos));
writer.currentWritePos(endPos);
}
const auto endPos = writer.currentWritePos();
writer.currentWritePos(startPos);
writer.template writeBytes<4>(static_cast<uint32_t>(endPos - startPos));
writer.currentWritePos(endPos);
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, T& obj, Fnc&& fnc) const
{
auto& reader = des.adapter();
uint32_t size{};
const auto readEndPos = reader.currentReadEndPos();
const auto startPos = reader.currentReadPos();
reader.template readBytes<4>(size);
reader.currentReadEndPos(startPos + size);
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
auto& reader = des.adapter();
uint32_t size{};
const auto readEndPos = reader.currentReadEndPos();
const auto startPos = reader.currentReadPos();
reader.template readBytes<4>(size);
reader.currentReadEndPos(startPos + size);
fnc(des, obj);
fnc(des, obj);
reader.currentReadPos(startPos + size);
reader.currentReadEndPos(readEndPos);
}
};
}
reader.currentReadPos(startPos + size);
reader.currentReadEndPos(readEndPos);
}
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::Growable, T> {
using TValue = T;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::Growable, T>
{
using TValue = T;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_GROWABLE_H
#endif // BITSERY_EXT_GROWABLE_H

View File

@@ -1,162 +1,169 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_EXT_INHERITANCE_H
#define BITSERY_EXT_INHERITANCE_H
#include <unordered_set>
#include "../traits/core/traits.h"
#include "../ext/utils/memory_resource.h"
#include "../traits/core/traits.h"
#include <unordered_set>
namespace bitsery {
namespace ext {
namespace ext {
//required when virtual inheritance (ext::VirtualBaseClass) exists in serialization flow.
//for standard inheritance (ext::BaseClass) it is optional.
class InheritanceContext {
public:
explicit InheritanceContext(MemResourceBase* memResource = nullptr)
:_virtualBases{pointer_utils::StdPolyAlloc<const void*>{memResource}}
{}
InheritanceContext(const InheritanceContext&) = delete;
InheritanceContext&operator = (const InheritanceContext&) = delete;
InheritanceContext(InheritanceContext&&) = default;
InheritanceContext& operator = (InheritanceContext&&) = default;
template <typename TDerived, typename TBase>
void beginBase(const TDerived &derived, const TBase &) {
if (_depth == 0) {
const void* ptr = std::addressof(derived);
if ( _parentPtr != ptr)
_virtualBases.clear();
_parentPtr = ptr;
}
++_depth;
}
template <typename TDerived, typename TBase>
bool beginVirtualBase(const TDerived &derived, const TBase &base) {
beginBase(derived, base);
return _virtualBases.emplace(std::addressof(base)).second;
}
void end() {
--_depth;
}
private:
//these members are required to know when we can clear _virtualBases
size_t _depth{};
const void* _parentPtr{};
//add virtual bases to the list, as long as we're on the same parent
std::unordered_set<const void*,
std::hash<const void*>, std::equal_to<const void*>,
pointer_utils::StdPolyAlloc<const void*>
> _virtualBases;
};
template <typename TBase>
class BaseClass {
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
auto& resObj = static_cast<const TBase&>(obj);
if (auto ctx = ser.template contextOrNull<InheritanceContext>()) {
ctx->beginBase(obj, resObj);
fnc(ser, const_cast<TBase&>(resObj));
ctx->end();
} else {
fnc(ser, const_cast<TBase&>(resObj));
}
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
auto& resObj = static_cast<TBase&>(obj);
if (auto ctx = des.template contextOrNull<InheritanceContext>()) {
ctx->beginBase(obj, resObj);
fnc(des, resObj);
ctx->end();
} else {
fnc(des, resObj);
}
}
};
//requires InheritanceContext
template <typename TBase>
class VirtualBaseClass {
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
auto& ctx = ser.template context<InheritanceContext>();
auto& resObj = static_cast<const TBase&>(obj);
if (ctx.beginVirtualBase(obj, resObj))
fnc(ser, const_cast<TBase&>(resObj));
ctx.end();
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
auto& ctx = des.template context<InheritanceContext>();
auto& resObj = static_cast<TBase&>(obj);
if (ctx.beginVirtualBase(obj, resObj))
fnc(des, resObj);
ctx.end();
}
};
// required when virtual inheritance (ext::VirtualBaseClass) exists in
// serialization flow. for standard inheritance (ext::BaseClass) it is optional.
class InheritanceContext
{
public:
explicit InheritanceContext(MemResourceBase* memResource = nullptr)
: _virtualBases{ pointer_utils::StdPolyAlloc<const void*>{ memResource } }
{
}
InheritanceContext(const InheritanceContext&) = delete;
InheritanceContext& operator=(const InheritanceContext&) = delete;
InheritanceContext(InheritanceContext&&) = default;
InheritanceContext& operator=(InheritanceContext&&) = default;
template<typename TDerived, typename TBase>
void beginBase(const TDerived& derived, const TBase&)
{
if (_depth == 0) {
const void* ptr = std::addressof(derived);
if (_parentPtr != ptr)
_virtualBases.clear();
_parentPtr = ptr;
}
++_depth;
}
namespace traits {
template<typename TBase, typename T>
struct ExtensionTraits<ext::BaseClass<TBase>, T> {
static_assert(std::is_base_of<TBase, T>::value, "Invalid base class");
template<typename TDerived, typename TBase>
bool beginVirtualBase(const TDerived& derived, const TBase& base)
{
beginBase(derived, base);
return _virtualBases.emplace(std::addressof(base)).second;
}
using TValue = TBase;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
void end() { --_depth; }
template<typename TBase, typename T>
struct ExtensionTraits<ext::VirtualBaseClass<TBase>, T> {
static_assert(std::is_base_of<TBase, T>::value, "Invalid base class");
private:
// these members are required to know when we can clear _virtualBases
size_t _depth{};
const void* _parentPtr{};
// add virtual bases to the list, as long as we're on the same parent
std::unordered_set<const void*,
std::hash<const void*>,
std::equal_to<const void*>,
pointer_utils::StdPolyAlloc<const void*>>
_virtualBases;
};
using TValue = TBase;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
//disable lambda overload, when serializing virtually inherited base class.
//Only one instance of virtual base will be serialized, when using multiple inheritance
//and it will be undefined behaviour if derived classes would have different virtual base class serialization flow.
static constexpr bool SupportLambdaOverload = false;
};
template<typename TBase>
class BaseClass
{
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
{
auto& resObj = static_cast<const TBase&>(obj);
if (auto ctx = ser.template contextOrNull<InheritanceContext>()) {
ctx->beginBase(obj, resObj);
fnc(ser, const_cast<TBase&>(resObj));
ctx->end();
} else {
fnc(ser, const_cast<TBase&>(resObj));
}
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, T& obj, Fnc&& fnc) const
{
auto& resObj = static_cast<TBase&>(obj);
if (auto ctx = des.template contextOrNull<InheritanceContext>()) {
ctx->beginBase(obj, resObj);
fnc(des, resObj);
ctx->end();
} else {
fnc(des, resObj);
}
}
};
// requires InheritanceContext
template<typename TBase>
class VirtualBaseClass
{
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
{
auto& ctx = ser.template context<InheritanceContext>();
auto& resObj = static_cast<const TBase&>(obj);
if (ctx.beginVirtualBase(obj, resObj))
fnc(ser, const_cast<TBase&>(resObj));
ctx.end();
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, T& obj, Fnc&& fnc) const
{
auto& ctx = des.template context<InheritanceContext>();
auto& resObj = static_cast<TBase&>(obj);
if (ctx.beginVirtualBase(obj, resObj))
fnc(des, resObj);
ctx.end();
}
};
}
namespace traits {
template<typename TBase, typename T>
struct ExtensionTraits<ext::BaseClass<TBase>, T>
{
static_assert(std::is_base_of<TBase, T>::value, "Invalid base class");
#endif //BITSERY_EXT_INHERITANCE_H
using TValue = TBase;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
template<typename TBase, typename T>
struct ExtensionTraits<ext::VirtualBaseClass<TBase>, T>
{
static_assert(std::is_base_of<TBase, T>::value, "Invalid base class");
using TValue = TBase;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
// disable lambda overload, when serializing virtually inherited base class.
// Only one instance of virtual base will be serialized, when using multiple
// inheritance and it will be undefined behaviour if derived classes would
// have different virtual base class serialization flow.
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif // BITSERY_EXT_INHERITANCE_H

View File

@@ -1,220 +1,226 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_EXT_POINTER_H
#define BITSERY_EXT_POINTER_H
#include <cassert>
#include "../traits/core/traits.h"
#include "utils/pointer_utils.h"
#include "utils/polymorphism_utils.h"
#include "utils/rtti_utils.h"
#include <cassert>
namespace bitsery {
namespace ext {
namespace ext {
namespace pointer_details {
namespace pointer_details {
template<typename T>
struct PtrOwnerManager {
static_assert(std::is_pointer<T>::value, "");
template<typename T>
struct PtrOwnerManager
{
static_assert(std::is_pointer<T>::value, "");
using TElement = typename std::remove_pointer<T>::type;
using TElement = typename std::remove_pointer<T>::type;
static TElement* getPtr(T& obj) {
return obj;
}
static TElement* getPtr(T& obj) { return obj; }
static constexpr PointerOwnershipType getOwnership() {
return PointerOwnershipType::Owner;
}
static constexpr PointerOwnershipType getOwnership()
{
return PointerOwnershipType::Owner;
}
static void create(T& obj, pointer_utils::PolyAllocWithTypeId alloc, size_t typeId) {
obj = alloc.newObject<TElement>(typeId);
}
static void create(T& obj,
pointer_utils::PolyAllocWithTypeId alloc,
size_t typeId)
{
obj = alloc.newObject<TElement>(typeId);
}
static void createPolymorphic(T& obj, pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
obj = static_cast<TElement*>(handler->create(alloc));
}
static void createPolymorphic(
T& obj,
pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler)
{
obj = static_cast<TElement*>(handler->create(alloc));
}
static void destroy(T& obj, pointer_utils::PolyAllocWithTypeId alloc, size_t typeId) {
alloc.deleteObject(obj, typeId);
obj = nullptr;
}
static void destroy(T& obj,
pointer_utils::PolyAllocWithTypeId alloc,
size_t typeId)
{
alloc.deleteObject(obj, typeId);
obj = nullptr;
}
static void destroyPolymorphic(T& obj, pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
handler->destroy(alloc, obj);
obj = nullptr;
}
static void destroyPolymorphic(
T& obj,
pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler)
{
handler->destroy(alloc, obj);
obj = nullptr;
}
};
};
template<typename T>
struct PtrObserverManager
{
static_assert(std::is_pointer<T>::value, "");
template<typename T>
struct PtrObserverManager {
static_assert(std::is_pointer<T>::value, "");
using TElement = typename std::remove_pointer<T>::type;
using TElement = typename std::remove_pointer<T>::type;
static TElement* getPtr(T& obj) { return obj; }
static TElement* getPtr(T& obj) {
return obj;
}
static constexpr PointerOwnershipType getOwnership()
{
return PointerOwnershipType::Observer;
}
static constexpr PointerOwnershipType getOwnership() {
return PointerOwnershipType::Observer;
}
// pure observer doesn't have create/createPolymorphic methods, but instead
// returns reference to pointer which gets updated later
static TElement*& getPtrRef(T& obj) { return obj; }
//pure observer doesn't have create/createPolymorphic methods, but instead returns reference to pointer
//which gets updated later
static TElement*& getPtrRef(T& obj) {
return obj;
}
static void destroy(T& obj, MemResourceBase*, size_t) { obj = nullptr; }
static void destroy(T& obj, MemResourceBase* , size_t ) {
obj = nullptr;
}
static void destroyPolymorphic(T& obj,
MemResourceBase*,
const std::shared_ptr<PolymorphicHandlerBase>&)
{
obj = nullptr;
}
};
static void destroyPolymorphic(T& obj, MemResourceBase* , PolymorphicHandlerBase& ) {
obj = nullptr;
}
template<typename T>
struct NonPtrManager
{
};
static_assert(!std::is_pointer<T>::value, "");
template<typename T>
struct NonPtrManager {
using TElement = T;
static_assert(!std::is_pointer<T>::value, "");
static TElement* getPtr(T& obj) { return &obj; }
using TElement = T;
static constexpr PointerOwnershipType getOwnership()
{
return PointerOwnershipType::Owner;
}
static TElement* getPtr(T& obj) {
return &obj;
}
// this code is unreachable for reference type, but is necessary to compile
// LCOV_EXCL_START
static constexpr PointerOwnershipType getOwnership() {
return PointerOwnershipType::Owner;
}
static void create(T&, MemResourceBase*, size_t) {}
// this code is unreachable for reference type, but is necessary to compile
// LCOV_EXCL_START
static void createPolymorphic(T&,
MemResourceBase*,
const std::shared_ptr<PolymorphicHandlerBase>&)
{
}
static void create(T& , MemResourceBase* , size_t ) {
static void destroy(T&, MemResourceBase*, size_t) {}
}
static void createPolymorphic(T& , MemResourceBase* , PolymorphicHandlerBase& ) {
}
static void destroy(T& , MemResourceBase* , size_t ) {
}
static void destroyPolymorphic(T& , MemResourceBase* , PolymorphicHandlerBase& ) {
}
// 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>
using PointerOwnerBase = pointer_utils::PointerObjectExtensionBase<
pointer_details::PtrOwnerManager, PolymorphicContext, RTTI>;
using PointerOwner = PointerOwnerBase<StandardRTTI>;
using PointerObserver = pointer_utils::PointerObjectExtensionBase<
pointer_details::PtrObserverManager, PolymorphicContext, pointer_details::NoRTTI>;
//inherit from PointerObjectExtensionBase in order to specify PointerType::NotNull
class ReferencedByPointer : public pointer_utils::PointerObjectExtensionBase<
pointer_details::NonPtrManager, PolymorphicContext, pointer_details::NoRTTI> {
public:
ReferencedByPointer() : pointer_utils::PointerObjectExtensionBase<
pointer_details::NonPtrManager, PolymorphicContext, pointer_details::NoRTTI>(
PointerType::NotNull) {}
};
}
namespace traits {
template<typename T, typename RTTI>
struct ExtensionTraits<ext::PointerOwnerBase<RTTI>, T*> {
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
//if underlying type is not polymorphic, then we can enable lambda syntax
static constexpr bool SupportLambdaOverload = !RTTI::template isPolymorphic<TValue>();
};
template<typename T>
struct ExtensionTraits<ext::PointerObserver, T*> {
//although pointer observer doesn't serialize anything, but we still add value overload support to be consistent with pointer owners
//observer only writes/reads pointer id from pointer linking context
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
template<typename T>
struct ExtensionTraits<ext::ReferencedByPointer, T> {
//allow everything, because it is serialized as regular type, except it also creates pointerId that is required by NonOwningPointer to work
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
static void destroyPolymorphic(T&,
MemResourceBase*,
const std::shared_ptr<PolymorphicHandlerBase>&)
{
}
// LCOV_EXCL_STOP
};
}
#endif //BITSERY_EXT_POINTER_H
template<typename RTTI>
using PointerOwnerBase =
pointer_utils::PointerObjectExtensionBase<pointer_details::PtrOwnerManager,
PolymorphicContext,
RTTI>;
template<typename RTTI>
using PointerObserverBase =
pointer_utils::PointerObjectExtensionBase<pointer_details::PtrObserverManager,
PolymorphicContext,
RTTI>;
// inherit from PointerObjectExtensionBase in order to specify
// PointerType::NotNull
template<typename RTTI>
class ReferencedByPointerBase
: public pointer_utils::PointerObjectExtensionBase<
pointer_details::NonPtrManager,
PolymorphicContext,
RTTI>
{
public:
ReferencedByPointerBase()
: pointer_utils::PointerObjectExtensionBase<pointer_details::NonPtrManager,
PolymorphicContext,
RTTI>(PointerType::NotNull)
{
}
};
using PointerOwner = PointerOwnerBase<StandardRTTI>;
using PointerObserver = PointerObserverBase<StandardRTTI>;
using ReferencedByPointer = ReferencedByPointerBase<StandardRTTI>;
}
namespace traits {
template<typename T, typename RTTI>
struct ExtensionTraits<ext::PointerOwnerBase<RTTI>, T*>
{
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
// if underlying type is not polymorphic, then we can enable lambda syntax
static constexpr bool SupportLambdaOverload =
!RTTI::template isPolymorphic<TValue>();
};
template<typename T, typename RTTI>
struct ExtensionTraits<ext::PointerObserverBase<RTTI>, T*>
{
// although pointer observer doesn't serialize anything, but we still add
// value overload support to be consistent with pointer owners observer only
// writes/reads pointer id from pointer linking context
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
template<typename T, typename RTTI>
struct ExtensionTraits<ext::ReferencedByPointerBase<RTTI>, T>
{
// allow everything, because it is serialized as regular type, except it also
// creates pointerId that is required by NonOwningPointer to work
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif // BITSERY_EXT_POINTER_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2020 Nick Renieris
// Copyright (c) 2020 Nick Renieris
//
//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:
// 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 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.
// 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_EXT_STD_ATOMIC_H
#define BITSERY_EXT_STD_ATOMIC_H
@@ -27,39 +27,41 @@
#include <atomic>
namespace bitsery {
namespace ext {
namespace ext {
class StdAtomic {
public:
class StdAtomic
{
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const std::atomic<T>& obj, Fnc&& fnc) const
{
auto res = obj.load();
fnc(ser, res);
}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const std::atomic<T>& obj, Fnc&& fnc) const {
auto res = obj.load();
fnc(ser, res);
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, std::atomic<T>& obj, Fnc&& fnc) const {
T res{};
fnc(des, res);
obj.store(res);
}
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdAtomic, std::atomic<T>> {
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, std::atomic<T>& obj, Fnc&& fnc) const
{
T res{};
fnc(des, res);
obj.store(res);
}
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdAtomic, std::atomic<T>>
{
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
#endif //BITSERY_EXT_STD_ATOMIC_H
}
}
#endif // BITSERY_EXT_STD_ATOMIC_H

View File

@@ -1,148 +1,164 @@
//MIT License
// MIT License
//
//Copyright (c) 2020 Mindaugas Vinkelis
// Copyright (c) 2020 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:
// 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 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.
// 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_EXT_STD_BITSET_H
#define BITSERY_EXT_STD_BITSET_H
#include "../traits/core/traits.h"
#include <bitset>
#include <cstdint>
namespace bitsery {
namespace ext {
namespace ext {
class StdBitset {
public:
class StdBitset
{
public:
template<typename Ser, typename Fnc, size_t N>
void serialize(Ser& ser, const std::bitset<N>& obj, Fnc&&) const
{
constexpr size_t BYTES = N / 8;
constexpr size_t LEFTOVER = N % 8;
if (BYTES > sizeof(unsigned long long)) {
for (size_t i = 0u; i < BYTES; ++i) {
size_t offset = i * 8;
auto data = obj[offset + 0] + (obj[offset + 1] << 1) +
(obj[offset + 2] << 2) + (obj[offset + 3] << 3) +
(obj[offset + 4] << 4) + (obj[offset + 5] << 5) +
(obj[offset + 6] << 6) + (obj[offset + 7] << 7);
ser.value1b(static_cast<uint8_t>(data));
}
template<typename Ser, typename Fnc, size_t N>
void serialize(Ser &ser, const std::bitset<N> &obj, Fnc &&) const {
constexpr size_t BYTES = N / 8;
constexpr size_t LEFTOVER = N % 8;
if (BYTES > sizeof(unsigned long long)) {
for(size_t i = 0u; i < BYTES; ++i) {
size_t offset = i * 8;
auto data = obj[offset + 0] +
(obj[offset + 1] << 1) +
(obj[offset + 2] << 2) +
(obj[offset + 3] << 3) +
(obj[offset + 4] << 4) +
(obj[offset + 5] << 5) +
(obj[offset + 6] << 6) +
(obj[offset + 7] << 7);
ser.value1b(static_cast<uint8_t>(data));
}
} else {
// more performant way
auto data = obj.to_ullong();
for(size_t i = 0u; i < BYTES; ++i) {
ser.value1b(static_cast<uint8_t>(data & 0xFF));
data >>= 8;
}
}
if (LEFTOVER > 0) {
serializeLeftover(ser.adapter(), obj, N - LEFTOVER, N);
}
}
template<typename Des, typename Fnc, size_t N>
void deserialize(Des &des, std::bitset<N> &obj, Fnc &&) const {
constexpr size_t BYTES = N / 8;
constexpr size_t LEFTOVER = N % 8;
for(size_t i = 0u; i < BYTES; ++i) {
size_t offset = i * 8;
uint8_t data = 0;
des.value1b(data);
obj[offset + 0] = data & 0x01u;
obj[offset + 1] = data & 0x02u;
obj[offset + 2] = data & 0x04u;
obj[offset + 3] = data & 0x08u;
obj[offset + 4] = data & 0x10u;
obj[offset + 5] = data & 0x20u;
obj[offset + 6] = data & 0x40u;
obj[offset + 7] = data & 0x80u;
}
if (LEFTOVER > 0) {
deserializeLeftover(des.adapter(), obj, N - LEFTOVER, N);
}
}
private:
template<typename Writer, size_t N>
void serializeLeftover(Writer& w, const std::bitset<N> &obj, size_t from, size_t to) const {
serializeLeftoverImpl(w, obj, from, to, std::integral_constant<bool, Writer::BitPackingEnabled> {});
}
template<typename Writer, size_t N>
void serializeLeftoverImpl(Writer& w, const std::bitset<N> &obj, size_t from, size_t to, std::integral_constant<bool, false>) const {
auto data = 0;
for (auto i = from; i < to; ++i) {
data += obj[i] << (i - from);
}
w.template writeBytes<1>(static_cast<uint8_t>(data));
}
template<typename Writer, size_t N>
void serializeLeftoverImpl(Writer& w, const std::bitset<N> &obj, size_t from, size_t to, std::integral_constant<bool, true>) const {
for (auto i = from; i < to; ++i) {
w.writeBits(obj[i] ? 1u : 0u, 1);
}
}
template<typename Reader, size_t N>
void deserializeLeftover(Reader& r, std::bitset<N> &obj, size_t from, size_t to) const {
deserializeLeftoverImpl(r, obj, from, to, std::integral_constant<bool, Reader::BitPackingEnabled> {});
}
template<typename Reader, size_t N>
void deserializeLeftoverImpl(Reader& r, std::bitset<N> &obj, size_t from, size_t to, std::integral_constant<bool, false>) const {
uint8_t data = 0u;
r.template readBytes<1>(data);
for (auto i = from; i < to; ++i) {
obj[i] = data & (1u << (i - from));
}
}
template<typename Reader, size_t N>
void deserializeLeftoverImpl(Reader& r, std::bitset<N> &obj, size_t from, size_t to, std::integral_constant<bool, true>) const {
for (auto i = from; i < to; ++i) {
uint8_t res = 0u;
r.readBits(res, 1);
obj[i] = res == 1;
}
}
};
} else {
// more performant way
auto data = obj.to_ullong();
for (size_t i = 0u; i < BYTES; ++i) {
ser.value1b(static_cast<uint8_t>(data & 0xFF));
data >>= 8;
}
}
namespace traits {
template<size_t N>
struct ExtensionTraits<ext::StdBitset, std::bitset<N>> {
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
if (LEFTOVER > 0) {
serializeLeftoverImpl(ser.adapter(),
obj,
N - LEFTOVER,
N,
std::is_same<Ser, typename Ser::BPEnabledType>{});
}
}
template<typename Des, typename Fnc, size_t N>
void deserialize(Des& des, std::bitset<N>& obj, Fnc&&) const
{
constexpr size_t BYTES = N / 8;
constexpr size_t LEFTOVER = N % 8;
for (size_t i = 0u; i < BYTES; ++i) {
size_t offset = i * 8;
uint8_t data = 0;
des.value1b(data);
obj[offset + 0] = data & 0x01u;
obj[offset + 1] = data & 0x02u;
obj[offset + 2] = data & 0x04u;
obj[offset + 3] = data & 0x08u;
obj[offset + 4] = data & 0x10u;
obj[offset + 5] = data & 0x20u;
obj[offset + 6] = data & 0x40u;
obj[offset + 7] = data & 0x80u;
}
if (LEFTOVER > 0) {
deserializeLeftoverImpl(des.adapter(),
obj,
N - LEFTOVER,
N,
std::is_same<Des, typename Des::BPEnabledType>{});
}
}
private:
template<typename Writer, size_t N>
void serializeLeftoverImpl(Writer& w,
const std::bitset<N>& obj,
size_t from,
size_t to,
std::integral_constant<bool, false>) const
{
auto data = 0;
for (auto i = from; i < to; ++i) {
data += obj[i] << (i - from);
}
w.template writeBytes<1>(static_cast<uint8_t>(data));
}
template<typename Writer, size_t N>
void serializeLeftoverImpl(Writer& w,
const std::bitset<N>& obj,
size_t from,
size_t to,
std::integral_constant<bool, true>) const
{
for (auto i = from; i < to; ++i) {
w.writeBits(obj[i] ? 1u : 0u, 1);
}
}
template<typename Reader, size_t N>
void deserializeLeftoverImpl(Reader& r,
std::bitset<N>& obj,
size_t from,
size_t to,
std::integral_constant<bool, false>) const
{
uint8_t data = 0u;
r.template readBytes<1>(data);
for (auto i = from; i < to; ++i) {
obj[i] = data & (1u << (i - from));
}
}
template<typename Reader, size_t N>
void deserializeLeftoverImpl(Reader& r,
std::bitset<N>& obj,
size_t from,
size_t to,
std::integral_constant<bool, true>) const
{
for (auto i = from; i < to; ++i) {
uint8_t res = 0u;
r.readBits(res, 1);
obj[i] = res == 1;
}
}
};
}
namespace traits {
template<size_t N>
struct ExtensionTraits<ext::StdBitset, std::bitset<N>>
{
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif //BITSERY_EXT_STD_BITSET_H
#endif // BITSERY_EXT_STD_BITSET_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 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:
// 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 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.
// 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_EXT_STD_CHRONO_H
#define BITSERY_EXT_STD_CHRONO_H
@@ -27,68 +27,91 @@
#include <chrono>
namespace bitsery {
namespace ext {
namespace ext {
class StdDuration {
public:
class StdDuration
{
public:
template<typename Ser, typename T, typename Period, typename Fnc>
void serialize(Ser& ser,
const std::chrono::duration<T, Period>& obj,
Fnc&& fnc) const
{
auto res = obj.count();
fnc(ser, res);
}
template<typename Ser, typename T, typename Period, typename Fnc>
void serialize(Ser& ser, const std::chrono::duration<T, Period>& obj, Fnc&& fnc) const {
auto res = obj.count();
fnc(ser, res);
}
template<typename Des, typename T, typename Period, typename Fnc>
void deserialize(Des& des,
std::chrono::duration<T, Period>& obj,
Fnc&& fnc) const
{
T res{};
fnc(des, res);
obj = std::chrono::duration<T, Period>{ res };
}
};
template<typename Des, typename T, typename Period, typename Fnc>
void deserialize(Des& des, std::chrono::duration<T, Period>& obj, Fnc&& fnc) const {
T res{};
fnc(des, res);
obj = std::chrono::duration<T, Period>{res};
}
};
class StdTimePoint
{
public:
template<typename Ser,
typename Clock,
typename T,
typename Period,
typename Fnc>
void serialize(
Ser& ser,
const std::chrono::time_point<Clock, std::chrono::duration<T, Period>>& obj,
Fnc&& fnc) const
{
auto res = obj.time_since_epoch().count();
fnc(ser, res);
}
class StdTimePoint {
public:
template<typename Ser, typename Clock, typename T, typename Period, typename Fnc>
void serialize(Ser& ser, const std::chrono::time_point<Clock, std::chrono::duration<T, Period>>& obj,
Fnc&& fnc) const {
auto res = obj.time_since_epoch().count();
fnc(ser, res);
}
template<typename Des, typename Clock, typename T, typename Period, typename Fnc>
void deserialize(Des& des, std::chrono::time_point<Clock, std::chrono::duration<T, Period>>& obj,
Fnc&& fnc) const {
T res{};
fnc(des, res);
auto dur = std::chrono::duration<T, Period>{res};
obj = std::chrono::time_point<Clock, std::chrono::duration<T, Period>>{dur};
}
};
}
namespace traits {
template<typename Rep, typename Period>
struct ExtensionTraits<ext::StdDuration, std::chrono::duration<Rep, Period>> {
using TValue = Rep;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
template<typename Clock, typename Rep, typename Period>
struct ExtensionTraits<ext::StdTimePoint,
std::chrono::time_point<Clock, std::chrono::duration<Rep, Period>>> {
using TValue = Rep;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
}
template<typename Des,
typename Clock,
typename T,
typename Period,
typename Fnc>
void deserialize(
Des& des,
std::chrono::time_point<Clock, std::chrono::duration<T, Period>>& obj,
Fnc&& fnc) const
{
T res{};
fnc(des, res);
auto dur = std::chrono::duration<T, Period>{ res };
obj =
std::chrono::time_point<Clock, std::chrono::duration<T, Period>>{ dur };
}
};
}
namespace traits {
template<typename Rep, typename Period>
struct ExtensionTraits<ext::StdDuration, std::chrono::duration<Rep, Period>>
{
using TValue = Rep;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
#endif //BITSERY_EXT_STD_CHRONO_H
template<typename Clock, typename Rep, typename Period>
struct ExtensionTraits<
ext::StdTimePoint,
std::chrono::time_point<Clock, std::chrono::duration<Rep, Period>>>
{
using TValue = Rep;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif // BITSERY_EXT_STD_CHRONO_H

View File

@@ -1,101 +1,122 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_EXT_STD_MAP_H
#define BITSERY_EXT_STD_MAP_H
#include "../traits/core/traits.h"
#include "../details/adapter_common.h"
#include "../details/serialization_common.h"
//we need this, so we could reserve for non ordered map
#include "../traits/core/traits.h"
// we need this, so we could reserve for non ordered map
#include <unordered_map>
namespace bitsery {
namespace ext {
namespace ext {
class StdMap {
public:
class StdMap
{
public:
constexpr explicit StdMap(size_t maxSize)
: _maxSize{ maxSize }
{
}
constexpr explicit StdMap(size_t maxSize):_maxSize{maxSize} {}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
{
using TKey = typename T::key_type;
using TValue = typename T::mapped_type;
auto size = obj.size();
assert(size <= _maxSize);
details::writeSize(ser.adapter(), size);
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
using TKey = typename T::key_type;
using TValue = typename T::mapped_type;
auto size = obj.size();
assert(size <= _maxSize);
details::writeSize(ser.adapter(), size);
for (auto& v : obj)
fnc(ser, const_cast<TKey&>(v.first), const_cast<TValue&>(v.second));
}
for (auto &v:obj)
fnc(ser, const_cast<TKey &>(v.first), const_cast<TValue &>(v.second));
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, T& obj, Fnc&& fnc) const
{
using TKey = typename T::key_type;
using TValue = typename T::mapped_type;
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
using TKey = typename T::key_type;
using TValue = typename T::mapped_type;
size_t size{};
details::readSize(
des.adapter(),
size,
_maxSize,
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
obj.clear();
reserve(obj, size);
size_t size{};
details::readSize(des.adapter(), size, _maxSize,
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
obj.clear();
reserve(obj, size);
auto hint = obj.begin();
for (auto i = 0u; i < size; ++i) {
auto key = bitsery::Access::create<TKey>();
auto value = bitsery::Access::create<TValue>();
fnc(des, key, value);
hint = obj.emplace_hint(hint, std::move(key), std::move(value));
}
}
private:
template <typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& obj, size_t size) const {
obj.reserve(size);
}
template <typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& obj, size_t size) const {
obj.reserve(size);
}
template <typename T>
void reserve(T& , size_t ) const {
//for ordered container do nothing
}
size_t _maxSize;
};
auto hint = obj.begin();
for (auto i = 0u; i < size; ++i) {
auto key = bitsery::Access::create<TKey>();
auto value = bitsery::Access::create<TValue>();
fnc(des, key, value);
hint = obj.emplace_hint(hint, std::move(key), std::move(value));
}
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdMap, T> {
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = true;
};
}
private:
template<typename Key,
typename T,
typename Hash,
typename KeyEqual,
typename Allocator>
void reserve(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& obj,
size_t size) const
{
obj.reserve(size);
}
template<typename Key,
typename T,
typename Hash,
typename KeyEqual,
typename Allocator>
void reserve(std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& obj,
size_t size) const
{
obj.reserve(size);
}
template<typename T>
void reserve(T&, size_t) const
{
// for ordered container do nothing
}
size_t _maxSize;
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdMap, T>
{
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_MAP_H
#endif // BITSERY_EXT_STD_MAP_H

View File

@@ -1,96 +1,109 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_EXT_STD_OPTIONAL_H
#define BITSERY_EXT_STD_OPTIONAL_H
#include "../traits/core/traits.h"
#include "../details/serialization_common.h"
#include "../traits/core/traits.h"
#include <optional>
namespace bitsery {
namespace ext {
namespace ext {
class StdOptional {
public:
class StdOptional
{
public:
/**
* Works with std::optional types
* @param alignBeforeData only makes sense when bit-packing enabled, by
* default aligns after writing/reading bool state of optional
*/
explicit StdOptional(bool alignBeforeData = true)
: _alignBeforeData{ alignBeforeData }
{
}
/**
* Works with std::optional types
* @param alignBeforeData only makes sense when bit-packing enabled, by default aligns after writing/reading bool state of optional
*/
explicit StdOptional(bool alignBeforeData=true):_alignBeforeData{alignBeforeData} {}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const std::optional<T>& obj, Fnc&& fnc) const
{
ser.boolValue(static_cast<bool>(obj));
if (_alignBeforeData)
ser.adapter().align();
if (obj)
fnc(ser, const_cast<T&>(*obj));
}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const std::optional<T> &obj, Fnc &&fnc) const {
ser.boolValue(static_cast<bool>(obj));
if (_alignBeforeData)
ser.adapter().align();
if (obj)
fnc(ser, const_cast<T&>(*obj));
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, std::optional<T> &obj, Fnc &&fnc) const {
bool exists{};
des.boolValue(exists);
if (_alignBeforeData)
des.adapter().align();
if (exists) {
deserialize_impl(des, obj, fnc, std::is_trivial<T>{});
} else {
obj = std::nullopt;
}
}
private:
template<typename Des, typename T, typename Fnc>
void deserialize_impl(Des &des, std::optional<T> &obj, Fnc &&fnc, std::true_type) const {
obj = ::bitsery::Access::create<T>();
fnc(des, *obj);
}
template<typename Des, typename T, typename Fnc>
void deserialize_impl(Des &des, std::optional<T> &obj, Fnc &&fnc, std::false_type) const {
if (!obj) {
obj = ::bitsery::Access::create<T>();
}
fnc(des, *obj);
}
bool _alignBeforeData;
};
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, std::optional<T>& obj, Fnc&& fnc) const
{
bool exists{};
des.boolValue(exists);
if (_alignBeforeData)
des.adapter().align();
if (exists) {
deserialize_impl(des, obj, fnc, std::is_trivial<T>{});
} else {
obj = std::nullopt;
}
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdOptional, std::optional<T>> {
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
private:
template<typename Des, typename T, typename Fnc>
void deserialize_impl(Des& des,
std::optional<T>& obj,
Fnc&& fnc,
std::true_type) const
{
obj = ::bitsery::Access::create<T>();
fnc(des, *obj);
}
template<typename Des, typename T, typename Fnc>
void deserialize_impl(Des& des,
std::optional<T>& obj,
Fnc&& fnc,
std::false_type) const
{
if (!obj) {
obj = ::bitsery::Access::create<T>();
}
fnc(des, *obj);
}
bool _alignBeforeData;
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdOptional, std::optional<T>>
{
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_OPTIONAL_H
#endif // BITSERY_EXT_STD_OPTIONAL_H

View File

@@ -1,111 +1,127 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_EXT_STD_QUEUE_H
#define BITSERY_EXT_STD_QUEUE_H
#include <type_traits>
#include <queue>
//include type traits for deque and vector, because they are defaults for queue and priority_queue
// include type traits for deque and vector, because they are defaults for queue
// and priority_queue
#include "../traits/deque.h"
#include "../traits/vector.h"
#include <queue>
#include <type_traits>
namespace bitsery {
namespace ext {
namespace ext {
class StdQueue {
private:
//inherit from queue so we could take underlying container
template <typename T, typename C>
struct QueueCnt : public std::queue<T, C>
{
static const C& getContainer(const std::queue<T, C>& s )
{
//get address of underlying container
return s.*(&QueueCnt::c);
}
static C& getContainer(std::queue<T, C>& s )
{
//get address of underlying container
return s.*(&QueueCnt::c);
}
};
//inherit from queue so we could take underlying container
template <typename T, typename Seq, typename Cmp>
struct PriorityQueueCnt : public std::priority_queue<T, Seq, Cmp>
{
static const Seq& getContainer(const std::priority_queue<T, Seq, Cmp>& s )
{
//get address of underlying container
return s.*(&PriorityQueueCnt::c);
}
static Seq& getContainer(std::priority_queue<T, Seq, Cmp>& s )
{
//get address of underlying container
return s.*(&PriorityQueueCnt::c);
}
};
size_t _maxSize;
public:
explicit StdQueue(size_t maxSize):_maxSize{maxSize} {};
//for queue
template<typename Ser, typename T, typename C, typename Fnc>
void serialize(Ser &ser, const std::queue<T,C> &obj, Fnc &&fnc) const {
ser.container(QueueCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename T, typename C, typename Fnc>
void deserialize(Des &des, std::queue<T,C> &obj, Fnc &&fnc) const {
des.container(QueueCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
//for priority_queue
template<typename Ser, typename T, typename C, typename Comp, typename Fnc>
void serialize(Ser &ser, const std::priority_queue<T,C, Comp> &obj, Fnc &&fnc) const {
ser.container(PriorityQueueCnt<T,C, Comp>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename T, typename C, typename Comp, typename Fnc>
void deserialize(Des &des, std::priority_queue<T,C, Comp> &obj, Fnc &&fnc) const {
des.container(PriorityQueueCnt<T,C, Comp>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
};
class StdQueue
{
private:
// inherit from queue so we could take underlying container
template<typename T, typename C>
struct QueueCnt : public std::queue<T, C>
{
static const C& getContainer(const std::queue<T, C>& s)
{
// get address of underlying container
return s.*(&QueueCnt::c);
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdQueue, T> {
using TValue = typename T::value_type;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
static C& getContainer(std::queue<T, C>& s)
{
// get address of underlying container
return s.*(&QueueCnt::c);
}
};
// inherit from queue so we could take underlying container
template<typename T, typename Seq, typename Cmp>
struct PriorityQueueCnt : public std::priority_queue<T, Seq, Cmp>
{
static const Seq& getContainer(const std::priority_queue<T, Seq, Cmp>& s)
{
// get address of underlying container
return s.*(&PriorityQueueCnt::c);
}
static Seq& getContainer(std::priority_queue<T, Seq, Cmp>& s)
{
// get address of underlying container
return s.*(&PriorityQueueCnt::c);
}
};
size_t _maxSize;
public:
explicit StdQueue(size_t maxSize)
: _maxSize{ maxSize } {};
// for queue
template<typename Ser, typename T, typename C, typename Fnc>
void serialize(Ser& ser, const std::queue<T, C>& obj, Fnc&& fnc) const
{
ser.container(
QueueCnt<T, C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename T, typename C, typename Fnc>
void deserialize(Des& des, std::queue<T, C>& obj, Fnc&& fnc) const
{
des.container(
QueueCnt<T, C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
// for priority_queue
template<typename Ser, typename T, typename C, typename Comp, typename Fnc>
void serialize(Ser& ser,
const std::priority_queue<T, C, Comp>& obj,
Fnc&& fnc) const
{
ser.container(PriorityQueueCnt<T, C, Comp>::getContainer(obj),
_maxSize,
std::forward<Fnc>(fnc));
}
template<typename Des, typename T, typename C, typename Comp, typename Fnc>
void deserialize(Des& des,
std::priority_queue<T, C, Comp>& obj,
Fnc&& fnc) const
{
des.container(PriorityQueueCnt<T, C, Comp>::getContainer(obj),
_maxSize,
std::forward<Fnc>(fnc));
}
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdQueue, T>
{
using TValue = typename T::value_type;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_QUEUE_H
#endif // BITSERY_EXT_STD_QUEUE_H

View File

@@ -1,100 +1,109 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_EXT_STD_SET_H
#define BITSERY_EXT_STD_SET_H
#include <cassert>
#include "../details/adapter_common.h"
#include "../details/serialization_common.h"
//we need this, so we could reserve for non ordered set
#include <unordered_set>
namespace bitsery {
namespace ext {
namespace ext {
class StdSet {
public:
class StdSet
{
public:
constexpr explicit StdSet(size_t maxSize)
: _maxSize{ maxSize }
{
}
constexpr explicit StdSet(size_t maxSize):_maxSize{maxSize} {}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
{
using TKey = typename T::key_type;
auto size = obj.size();
assert(size <= _maxSize);
details::writeSize(ser.adapter(), size);
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
using TKey = typename T::key_type;
auto size = obj.size();
assert(size <= _maxSize);
details::writeSize(ser.adapter(), size);
for (auto& v : obj)
fnc(ser, const_cast<TKey&>(v));
}
for (auto &v:obj)
fnc(ser, const_cast<TKey &>(v));
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, T& obj, Fnc&& fnc) const
{
using TKey = typename T::key_type;
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
using TKey = typename T::key_type;
size_t size{};
details::readSize(des.adapter(), size, _maxSize, std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
obj.clear();
reserve(obj, size);
auto hint = obj.begin();
for (auto i = 0u; i < size; ++i) {
auto key = bitsery::Access::create<TKey>();
fnc(des, key);
hint = obj.emplace_hint(hint, std::move(key));
}
}
private:
template <typename Key, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_set<Key, Hash, KeyEqual, Allocator>& obj, size_t size) const {
obj.reserve(size);
}
template <typename Key, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& obj, size_t size) const {
obj.reserve(size);
}
template <typename T>
void reserve(T& , size_t ) const {
//for ordered container do nothing
}
size_t _maxSize;
};
size_t size{};
details::readSize(
des.adapter(),
size,
_maxSize,
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
obj.clear();
reserve(obj, size);
auto hint = obj.begin();
for (auto i = 0u; i < size; ++i) {
auto key = bitsery::Access::create<TKey>();
fnc(des, key);
hint = obj.emplace_hint(hint, std::move(key));
}
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdSet, T> {
using TValue = typename T::key_type;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
private:
template<typename Key, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_set<Key, Hash, KeyEqual, Allocator>& obj,
size_t size) const
{
obj.reserve(size);
}
template<typename Key, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& obj,
size_t size) const
{
obj.reserve(size);
}
template<typename T>
void reserve(T&, size_t) const
{
// for ordered container do nothing
}
size_t _maxSize;
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdSet, T>
{
using TValue = typename T::key_type;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_SET_H
#endif // BITSERY_EXT_STD_SET_H

View File

@@ -1,29 +1,28 @@
//MIT License
// MIT License
//
//Copyright (c) 2018 Mindaugas Vinkelis
// 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:
// 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 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.
// 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_EXT_STD_SMART_PTR_H
#define BITSERY_EXT_STD_SMART_PTR_H
#include <cassert>
#include "../traits/core/traits.h"
#include "utils/pointer_utils.h"
#include "utils/polymorphism_utils.h"
@@ -31,168 +30,227 @@
#include <memory>
namespace bitsery {
namespace ext {
namespace ext {
namespace smart_ptr_details {
namespace smart_ptr_details {
//further code is for managing shared ownership
//do not nest this type in pointer manager class itself, because it will be different type for different T
struct SharedPtrSharedState : pointer_utils::PointerSharedStateBase {
std::shared_ptr<void> obj{};
};
// further code is for managing shared ownership
// do not nest this type in pointer manager class itself, because it will be
// different type for different T
struct SharedPtrSharedState : pointer_utils::PointerSharedStateBase
{
std::shared_ptr<void> obj{};
};
template<typename T>
struct SmartPtrOwnerManager {
template<typename T>
struct SmartPtrOwnerManager
{
using TElement = typename T::element_type;
using TElement = typename T::element_type;
template<typename TDeleter>
static TElement* getPtr(std::unique_ptr<TElement, TDeleter>& obj) {
return obj.get();
}
template<typename TDeleter>
static TElement* getPtr(std::unique_ptr<TElement, TDeleter>& obj)
{
return obj.get();
}
static TElement* getPtr(std::shared_ptr<TElement>& obj) {
return obj.get();
}
static TElement* getPtr(std::shared_ptr<TElement>& obj) { return obj.get(); }
static TElement* getPtr(std::weak_ptr<TElement>& obj) {
if (auto ptr = obj.lock())
return ptr.get();
return nullptr;
}
static TElement* getPtr(std::weak_ptr<TElement>& obj)
{
if (auto ptr = obj.lock())
return ptr.get();
return nullptr;
}
static constexpr PointerOwnershipType getOwnership() {
return ::bitsery::details::IsSpecializationOf<T, std::unique_ptr>::value
? PointerOwnershipType::Owner
: std::is_same<std::shared_ptr<TElement>, T>::value
? PointerOwnershipType::SharedOwner
: PointerOwnershipType::SharedObserver;
}
static constexpr PointerOwnershipType getOwnership()
{
return ::bitsery::details::IsSpecializationOf<T, std::unique_ptr>::value
? PointerOwnershipType::Owner
: std::is_same<std::shared_ptr<TElement>, T>::value
? PointerOwnershipType::SharedOwner
: PointerOwnershipType::SharedObserver;
}
template<typename TDeleter>
static void create(std::unique_ptr<TElement, TDeleter>& obj, pointer_utils::PolyAllocWithTypeId alloc,
size_t typeId) {
obj.reset(alloc.newObject<TElement>(typeId));
}
template<typename TDeleter>
static void create(std::unique_ptr<TElement, TDeleter>& obj,
pointer_utils::PolyAllocWithTypeId alloc,
size_t typeId)
{
obj.reset(alloc.newObject<TElement>(typeId));
}
template<typename TDeleter>
static void createPolymorphic(std::unique_ptr<TElement, TDeleter>& obj, pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
obj.reset(static_cast<TElement*>(handler->create(alloc)));
}
template<typename TDeleter>
static void createPolymorphic(
std::unique_ptr<TElement, TDeleter>& obj,
pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler)
{
obj.reset(static_cast<TElement*>(handler->create(alloc)));
}
template<typename TDel>
static void destroy(std::unique_ptr<TElement, TDel>& obj, pointer_utils::PolyAllocWithTypeId alloc, size_t typeId) {
auto ptr = obj.release();
alloc.deleteObject(ptr, typeId);
}
template<typename TDel>
static void destroy(std::unique_ptr<TElement, TDel>& obj,
pointer_utils::PolyAllocWithTypeId alloc,
size_t typeId)
{
auto ptr = obj.release();
alloc.deleteObject(ptr, typeId);
}
template<typename TDel>
static void destroyPolymorphic(std::unique_ptr<TElement, TDel>& obj, pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
auto ptr = obj.release();
handler->destroy(alloc, ptr);
}
template<typename TDel>
static void destroyPolymorphic(
std::unique_ptr<TElement, TDel>& obj,
pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler)
{
auto ptr = obj.release();
handler->destroy(alloc, ptr);
}
static void destroy(std::shared_ptr<TElement>& obj, MemResourceBase*, size_t) {
obj.reset();
}
static void destroy(std::shared_ptr<TElement>& obj, MemResourceBase*, size_t)
{
obj.reset();
}
static void destroyPolymorphic(std::shared_ptr<TElement>& obj, MemResourceBase*,
const std::shared_ptr<PolymorphicHandlerBase>&) {
obj.reset();
}
static void destroyPolymorphic(std::shared_ptr<TElement>& obj,
MemResourceBase*,
const std::shared_ptr<PolymorphicHandlerBase>&)
{
obj.reset();
}
static void destroy(std::weak_ptr<TElement>& obj, MemResourceBase*, size_t) {
obj.reset();
}
static void destroy(std::weak_ptr<TElement>& obj, MemResourceBase*, size_t)
{
obj.reset();
}
static void destroyPolymorphic(std::weak_ptr<TElement>& obj, MemResourceBase*,
const std::shared_ptr<PolymorphicHandlerBase>&) {
obj.reset();
}
static void destroyPolymorphic(std::weak_ptr<TElement>& obj,
MemResourceBase*,
const std::shared_ptr<PolymorphicHandlerBase>&)
{
obj.reset();
}
// define a type that will store shared state for shared and weak ptrs
using TSharedState = SharedPtrSharedState;
// define a type that will store shared state for shared and weak ptrs
using TSharedState = SharedPtrSharedState;
static void createShared(TSharedState& state,
std::shared_ptr<TElement>& obj, MemResourceBase* memResource, size_t typeId) {
// capture deleter parameters by value
pointer_utils::PolyAllocWithTypeId alloc{memResource};
obj.reset(alloc.newObject<TElement>(typeId), [alloc, typeId](TElement* data) {
alloc.deleteObject(data, typeId);
}, pointer_utils::StdPolyAlloc<TElement>(memResource));
state.obj = obj;
}
static void createShared(TSharedState& state,
std::shared_ptr<TElement>& obj,
MemResourceBase* memResource,
size_t typeId)
{
// capture deleter parameters by value
pointer_utils::PolyAllocWithTypeId alloc{ memResource };
obj.reset(
alloc.newObject<TElement>(typeId),
[alloc, typeId](TElement* data) { alloc.deleteObject(data, typeId); },
pointer_utils::StdPolyAlloc<TElement>(memResource));
state.obj = obj;
state.typeId = typeId;
}
static void createSharedPolymorphic(TSharedState& state,
std::shared_ptr<TElement>& obj, MemResourceBase* memResource,
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
// capture deleter parameters by value
pointer_utils::PolyAllocWithTypeId alloc{memResource};
obj.reset(static_cast<TElement*>(handler->create(alloc)), [alloc, handler](TElement* data) {
handler->destroy(alloc, data);
}, pointer_utils::StdPolyAlloc<TElement>(memResource));
state.obj = obj;
}
static void createSharedPolymorphic(
TSharedState& state,
std::shared_ptr<TElement>& obj,
MemResourceBase* memResource,
const std::shared_ptr<PolymorphicHandlerBase>& handler)
{
// capture deleter parameters by value
pointer_utils::PolyAllocWithTypeId alloc{ memResource };
obj.reset(
static_cast<TElement*>(handler->create(alloc)),
[alloc, handler](TElement* data) { handler->destroy(alloc, data); },
pointer_utils::StdPolyAlloc<TElement>(memResource));
state.obj = obj;
state.typeId = handler->getDerivedTypeId();
}
static void createShared(TSharedState& state,
std::weak_ptr<TElement>& obj, MemResourceBase* memResource, size_t typeId) {
pointer_utils::PolyAllocWithTypeId alloc{memResource};
std::shared_ptr<TElement> res(alloc.newObject<TElement>(typeId),[alloc, typeId](TElement* data) {
alloc.deleteObject(data, typeId);
}, pointer_utils::StdPolyAlloc<TElement>(memResource));
obj = res;
state.obj = res;
}
static void createShared(TSharedState& state,
std::weak_ptr<TElement>& obj,
MemResourceBase* memResource,
size_t typeId)
{
pointer_utils::PolyAllocWithTypeId alloc{ memResource };
std::shared_ptr<TElement> res(
alloc.newObject<TElement>(typeId),
[alloc, typeId](TElement* data) { alloc.deleteObject(data, typeId); },
pointer_utils::StdPolyAlloc<TElement>(memResource));
obj = res;
state.obj = res;
state.typeId = typeId;
}
static void createSharedPolymorphic(TSharedState& state,
std::weak_ptr<TElement>& obj, MemResourceBase* memResource,
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
pointer_utils::PolyAllocWithTypeId alloc{memResource};
std::shared_ptr<TElement> res(static_cast<TElement*>(handler->create(alloc)),
[alloc, handler](TElement* data) {
handler->destroy(alloc, data);
}, pointer_utils::StdPolyAlloc<TElement>(memResource));
obj = res;
state.obj = res;
}
static void createSharedPolymorphic(
TSharedState& state,
std::weak_ptr<TElement>& obj,
MemResourceBase* memResource,
const std::shared_ptr<PolymorphicHandlerBase>& handler)
{
pointer_utils::PolyAllocWithTypeId alloc{ memResource };
std::shared_ptr<TElement> res(
static_cast<TElement*>(handler->create(alloc)),
[alloc, handler](TElement* data) { handler->destroy(alloc, data); },
pointer_utils::StdPolyAlloc<TElement>(memResource));
obj = res;
state.obj = res;
state.typeId = handler->getDerivedTypeId();
}
static void saveToSharedState(TSharedState& state, T& obj) {
state.obj = std::shared_ptr<TElement>(obj);
}
static void saveToSharedState(TSharedState& state, T& obj)
{
state.obj = std::shared_ptr<TElement>(obj);
}
static void loadFromSharedState(TSharedState& state, T& obj) {
//reinterpret_pointer_cast is only since c++17
auto p = reinterpret_cast<TElement*>(state.obj.get());
obj = std::shared_ptr<TElement>(state.obj, p);
}
static void saveToSharedStatePolymorphic(TSharedState& state, T& obj)
{
state.obj = std::shared_ptr<TElement>(obj);
}
};
}
static void loadFromSharedState(TSharedState& state, T& obj)
{
auto v = state.obj.get();
auto p = static_cast<TElement*>(v);
obj = std::shared_ptr<TElement>(state.obj, p);
}
template<typename RTTI>
using StdSmartPtrBase = pointer_utils::PointerObjectExtensionBase<
smart_ptr_details::SmartPtrOwnerManager, PolymorphicContext, RTTI>;
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);
}
};
}
//helper type for convienience
using StdSmartPtr = StdSmartPtrBase<StandardRTTI>;
template<typename RTTI>
using StdSmartPtrBase = pointer_utils::PointerObjectExtensionBase<
smart_ptr_details::SmartPtrOwnerManager,
PolymorphicContext,
RTTI>;
}
namespace traits {
template<typename T, typename RTTI>
struct ExtensionTraits<ext::StdSmartPtrBase<RTTI>, T> {
using TValue = typename T::element_type;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
//if underlying type is not polymorphic, then we can enable lambda syntax
static constexpr bool SupportLambdaOverload = !RTTI::template isPolymorphic<TValue>();
};
}
// helper type for convienience
using StdSmartPtr = StdSmartPtrBase<StandardRTTI>;
}
#endif //BITSERY_EXT_STD_SMART_PTR_H
namespace traits {
template<typename T, typename RTTI>
struct ExtensionTraits<ext::StdSmartPtrBase<RTTI>, T>
{
using TValue = typename T::element_type;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
// if underlying type is not polymorphic, then we can enable lambda syntax
static constexpr bool SupportLambdaOverload =
!RTTI::template isPolymorphic<TValue>();
};
}
}
#endif // BITSERY_EXT_STD_SMART_PTR_H

View File

@@ -1,82 +1,85 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_EXT_STD_STACK_H
#define BITSERY_EXT_STD_STACK_H
#include <type_traits>
#include <stack>
//include type traits for deque, because stack default underlying container is deque
#include "../traits/deque.h"
#include <stack>
namespace bitsery {
namespace ext {
namespace ext {
class StdStack {
private:
//inherit from stack so we could take underlying container
template <typename T, typename C>
struct StackCnt : public std::stack<T, C>
{
static const C& getContainer(const std::stack<T, C>& s )
{
//get address of underlying container
return s.*(&StackCnt::c);
}
static C& getContainer(std::stack<T, C>& s )
{
//get address of underlying container
return s.*(&StackCnt::c);
}
};
size_t _maxSize;
public:
explicit StdStack(size_t maxSize):_maxSize{maxSize} {};
template<typename Ser, typename T, typename C, typename Fnc>
void serialize(Ser &ser, const std::stack<T,C> &obj, Fnc &&fnc) const {
ser.container(StackCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename T, typename C, typename Fnc>
void deserialize(Des &des, std::stack<T,C> &obj, Fnc &&fnc) const {
des.container(StackCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
};
class StdStack
{
private:
// inherit from stack so we could take underlying container
template<typename T, typename C>
struct StackCnt : public std::stack<T, C>
{
static const C& getContainer(const std::stack<T, C>& s)
{
// get address of underlying container
return s.*(&StackCnt::c);
}
namespace traits {
template<typename T, typename Seq>
struct ExtensionTraits<ext::StdStack, std::stack<T, Seq>> {
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
static C& getContainer(std::stack<T, C>& s)
{
// get address of underlying container
return s.*(&StackCnt::c);
}
};
size_t _maxSize;
public:
explicit StdStack(size_t maxSize)
: _maxSize{ maxSize } {};
template<typename Ser, typename T, typename C, typename Fnc>
void serialize(Ser& ser, const std::stack<T, C>& obj, Fnc&& fnc) const
{
ser.container(
StackCnt<T, C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename T, typename C, typename Fnc>
void deserialize(Des& des, std::stack<T, C>& obj, Fnc&& fnc) const
{
des.container(
StackCnt<T, C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
};
}
namespace traits {
template<typename T, typename Seq>
struct ExtensionTraits<ext::StdStack, std::stack<T, Seq>>
{
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_STACK_H
#endif // BITSERY_EXT_STD_STACK_H

View File

@@ -1,81 +1,83 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 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:
// 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 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.
// 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_EXT_STD_TUPLE_H
#define BITSERY_EXT_STD_TUPLE_H
#include "utils/composite_type_overloads.h"
#include "../traits/core/traits.h"
#include "utils/composite_type_overloads.h"
#include <tuple>
namespace bitsery {
namespace ext {
namespace ext {
template<typename ...Overloads>
class StdTuple : public details::CompositeTypeOverloadsUtils<std::tuple, Overloads...> {
public:
template<typename... Overloads>
class StdTuple
: public details::CompositeTypeOverloadsUtils<std::tuple, Overloads...>
{
public:
template<typename Ser, typename Fnc, typename... Ts>
void serialize(Ser& ser, const std::tuple<Ts...>& obj, Fnc&&) const
{
serializeAll(ser, const_cast<std::tuple<Ts...>&>(obj));
}
template<typename Ser, typename Fnc, typename ...Ts>
void serialize(Ser& ser, const std::tuple<Ts...>& obj, Fnc&&) const {
serializeAll(ser, const_cast<std::tuple<Ts...>&>(obj));
}
template<typename Des, typename Fnc, typename... Ts>
void deserialize(Des& des, std::tuple<Ts...>& obj, Fnc&&) const
{
serializeAll(des, obj);
}
template<typename Des, typename Fnc, typename ...Ts>
void deserialize(Des& des, std::tuple<Ts...>& obj, Fnc&&) const {
serializeAll(des, obj);
}
private:
template<typename S, typename... Ts>
void serializeAll(S& s, std::tuple<Ts...>& obj) const
{
this->execAll(obj, [this, &s](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
this->serializeType(s, std::get<Index>(data));
});
}
};
private:
template<typename S, typename ...Ts>
void serializeAll(S& s, std::tuple<Ts...>& obj) const {
this->execAll(obj, [this, &s](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
this->serializeType(s, std::get<Index>(data));
});
}
};
// deduction guide
template<typename... Overloads>
StdTuple(Overloads...) -> StdTuple<Overloads...>;
}
// deduction guide
template<typename ...Overloads>
StdTuple(Overloads...) -> StdTuple<Overloads...>;
}
namespace traits {
namespace traits {
template<typename Tuple, typename ... Overloads>
struct ExtensionTraits<ext::StdTuple<Overloads...>, Tuple> {
static_assert(bitsery::details::IsSpecializationOf<Tuple, std::tuple>::value,
"StdTuple only works with std::tuple");
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
template<typename Tuple, typename... Overloads>
struct ExtensionTraits<ext::StdTuple<Overloads...>, Tuple>
{
static_assert(bitsery::details::IsSpecializationOf<Tuple, std::tuple>::value,
"StdTuple only works with std::tuple");
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif //BITSERY_EXT_STD_TUPLE_H
#endif // BITSERY_EXT_STD_TUPLE_H

View File

@@ -1,102 +1,114 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 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:
// 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 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.
// 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_EXT_STD_VARIANT_H
#define BITSERY_EXT_STD_VARIANT_H
#include "utils/composite_type_overloads.h"
#include "../traits/core/traits.h"
#include "utils/composite_type_overloads.h"
#include <variant>
namespace bitsery {
namespace ext {
namespace ext {
template<typename ...Overloads>
class StdVariant : public details::CompositeTypeOverloadsUtils<std::variant, Overloads...> {
public:
template<typename... Overloads>
class StdVariant
: public details::CompositeTypeOverloadsUtils<std::variant, Overloads...>
{
public:
template<typename Ser, typename Fnc, typename... Ts>
void serialize(Ser& ser, const std::variant<Ts...>& obj, Fnc&&) const
{
auto index = obj.index();
assert(index != std::variant_npos);
details::writeSize(ser.adapter(), index);
this->execIndex(index,
const_cast<std::variant<Ts...>&>(obj),
[this, &ser](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
this->serializeType(ser, std::get<Index>(data));
});
}
template<typename Ser, typename Fnc, typename ...Ts>
void serialize(Ser& ser, const std::variant<Ts...>& obj, Fnc&&) const {
auto index = obj.index();
assert(index != std::variant_npos);
details::writeSize(ser.adapter(), index);
this->execIndex(index, const_cast<std::variant<Ts...>&>(obj), [this, &ser](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
this->serializeType(ser, std::get<Index>(data));
});
}
template<typename Des, typename Fnc, typename... Ts>
void deserialize(Des& des, std::variant<Ts...>& obj, Fnc&&) const
{
size_t index{};
details::readSize(
des.adapter(),
index,
sizeof...(Ts),
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
this->execIndex(index, obj, [this, &des](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
using TElem =
typename std::variant_alternative<Index, std::variant<Ts...>>::type;
template<typename Des, typename Fnc, typename ...Ts>
void deserialize(Des& des, std::variant<Ts...>& obj, Fnc&&) const {
size_t index{};
details::readSize(des.adapter(), index, sizeof...(Ts), std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
this->execIndex(index, obj, [this, &des](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
using TElem = typename std::variant_alternative<Index, std::variant<Ts...>>::type;
// Reinitializing nontrivial types may be expensive especially when they
// reference heap data, so if `data` is already holding the requested
// variant then we'll deserialize into the existing object
if constexpr (!std::is_trivial_v<TElem>) {
if (auto item = std::get_if<Index>(&data)) {
this->serializeType(des, *item);
return;
}
}
// Reinitializing nontrivial types may be expensive especially when they
// reference heap data, so if `data` is already holding the requested
// variant then we'll deserialize into the existing object
if constexpr (!std::is_trivial_v<TElem>) {
if (auto item = std::get_if<Index>(&data)) {
this->serializeType(des, *item);
return;
}
}
TElem item = ::bitsery::Access::create<TElem>();
this->serializeType(des, item);
data =
std::variant<Ts...>(std::in_place_index_t<Index>{}, std::move(item));
});
}
};
TElem item = ::bitsery::Access::create<TElem>();
this->serializeType(des, item);
data = std::variant<Ts...>(std::in_place_index_t<Index>{}, std::move(item));
});
}
// deduction guide
template<typename... Overloads>
StdVariant(Overloads...) -> StdVariant<Overloads...>;
}
};
// defines empty fuction, that handles monostate
template<typename S>
void
serialize(S&, std::monostate&)
{
}
// deduction guide
template<typename ...Overloads>
StdVariant(Overloads...) -> StdVariant<Overloads...>;
}
namespace traits {
//defines empty fuction, that handles monostate
template <typename S>
void serialize(S& , std::monostate&) {}
namespace traits {
template<typename Variant, typename ... Overloads>
struct ExtensionTraits<ext::StdVariant<Overloads...>, Variant> {
static_assert(bitsery::details::IsSpecializationOf<Variant, std::variant>::value,
"StdVariant only works with std::variant");
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
template<typename Variant, typename... Overloads>
struct ExtensionTraits<ext::StdVariant<Overloads...>, Variant>
{
static_assert(
bitsery::details::IsSpecializationOf<Variant, std::variant>::value,
"StdVariant only works with std::variant");
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif //BITSERY_EXT_STD_VARIANT_H
#endif // BITSERY_EXT_STD_VARIANT_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 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:
// 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 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.
// 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_EXT_COMPOSITE_TYPE_OVERLOADS_H
#define BITSERY_EXT_COMPOSITE_TYPE_OVERLOADS_H
@@ -29,108 +29,131 @@
#if __cplusplus < 201703L
#error these utils requires c++17
// in theory, it could be implemented using C++11
// but without class template argument deduction guides that would be very inconvenient to use
// these are very helpul for sum types (e.g. std::variant),
// but for product types (e.g. std::tuple) you can you can easily do it your self with lambda, without extension
// but without class template argument deduction guides that would be very
// inconvenient to use these are very helpul for sum types (e.g. std::variant),
// but for product types (e.g. std::tuple) you can you can easily do it your
// self with lambda, without extension
#endif
namespace bitsery {
namespace ext {
// might be usable, when you want to have one overload set for different composite types,
// e.g. variant, tuple and pair
template<class... Ts>
struct CompositeTypeOverloads : Ts ... {
using Ts::operator()...;
};
namespace ext {
// might be usable, when you want to have one overload set for different
// composite types, e.g. variant, tuple and pair
template<class... Ts>
struct CompositeTypeOverloads : Ts...
{
using Ts::operator()...;
};
template<typename ...Overloads>
CompositeTypeOverloads(Overloads...) -> CompositeTypeOverloads<Overloads...>;
template<typename... Overloads>
CompositeTypeOverloads(Overloads...) -> CompositeTypeOverloads<Overloads...>;
// convenient way to invoke s.value<N>, shorter than specifying a lambda
template<typename T, size_t N>
struct OverloadValue {
template <typename S>
void operator()(S& s, T& v) const {
s.template value<N>(v);
}
};
// convenient way to invoke s.value<N>, shorter than specifying a lambda
template<typename T, size_t N>
struct OverloadValue
{
template<typename S>
void operator()(S& s, T& v) const
{
s.template value<N>(v);
}
};
// convenient way to invoke other extension using value or object overloads
// there is no reason to write OverloadExtLambda,
// because you'll need to specify lambda type, which is very inconvenient and it will be much
// easier to simple write a lambda with extension inside it,
// in order to implement it in a convenient way, i need a way to deduce only last template parameter (lambda type)
// but this is not possible with deduction guides at the moment
// convenient way to invoke other extension using value or object overloads
// there is no reason to write OverloadExtLambda,
// because you'll need to specify lambda type, which is very inconvenient and it
// will be much easier to simple write a lambda with extension inside it, in
// order to implement it in a convenient way, i need a way to deduce only last
// template parameter (lambda type) but this is not possible with deduction
// guides at the moment
template<typename T, size_t N, typename Ext>
struct OverloadExtValue : public Ext {
template <typename S>
void operator()(S& s, T& v) const {
s.template ext<N>(v, static_cast<const Ext&>(*this));
}
};
template<typename T, size_t N, typename Ext>
struct OverloadExtValue : public Ext
{
template<typename S>
void operator()(S& s, T& v) const
{
s.template ext<N>(v, static_cast<const Ext&>(*this));
}
};
template<typename T, typename Ext>
struct OverloadExtObject : public Ext {
template <typename S>
void operator()(S& s, T& v) const {
s.ext(v, static_cast<const Ext&>(*this));
}
};
}
namespace details {
template<template<typename ...> typename CompositeType, typename ...Overloads>
class CompositeTypeOverloadsUtils : public ext::CompositeTypeOverloads<Overloads...> {
protected:
// converts run-time index to compile-time index,
// by calling lambda with std::integral_constant<size_t, INDEX>
template<typename Fnc, typename ... Ts>
void execIndex(size_t index, CompositeType<Ts...>& obj, Fnc&& fnc) const {
execIndexImpl(index, obj, std::forward<Fnc>(fnc), std::index_sequence_for<Ts...>{});
}
// call lambda for all indexes in composite type
template<typename Fnc, typename ... Ts>
void execAll(CompositeType<Ts...>& obj, Fnc&& fnc) const {
execAllImpl(obj, std::forward<Fnc>(fnc), std::index_sequence_for<Ts...>{});
}
// serialize a type, by using overload first
template<typename S, typename T>
void serializeType(S& s, T& v) const {
// first check if overload exists, otherwise try to call serialize method
if constexpr (hasOverload<S, T>()) {
std::invoke(*this, s, v);
} else {
static_assert(details::SerializeFunction<S, T>::isDefined(),
"Please define overload or 'serialize' function for your type.");
s.object(v);
}
}
private:
template<typename S, typename T>
static constexpr bool hasOverload() {
return std::is_invocable<ext::CompositeTypeOverloads<Overloads...>,
std::add_lvalue_reference_t<S>, std::add_lvalue_reference_t<T>>::value;
}
template<typename Variant, typename Fnc, size_t ...Is>
void execIndexImpl(size_t index, Variant& obj, Fnc&& fnc, std::index_sequence<Is...>) const {
((index == Is ? fnc(obj, std::integral_constant<size_t, Is>{}), 0 : 0), ...);
}
template<typename Variant, typename Fnc, size_t ...Is>
void execAllImpl(Variant& obj, Fnc&& fnc, std::index_sequence<Is...>) const {
(fnc(obj, std::integral_constant<size_t, Is>{}), ...);
}
};
}
template<typename T, typename Ext>
struct OverloadExtObject : public Ext
{
template<typename S>
void operator()(S& s, T& v) const
{
s.ext(v, static_cast<const Ext&>(*this));
}
};
}
#endif //BITSERY_EXT_COMPOSITE_TYPE_OVERLOADS_H
namespace details {
template<template<typename...> typename CompositeType, typename... Overloads>
class CompositeTypeOverloadsUtils
: public ext::CompositeTypeOverloads<Overloads...>
{
protected:
// converts run-time index to compile-time index,
// by calling lambda with std::integral_constant<size_t, INDEX>
template<typename Fnc, typename... Ts>
void execIndex(size_t index, CompositeType<Ts...>& obj, Fnc&& fnc) const
{
execIndexImpl(
index, obj, std::forward<Fnc>(fnc), std::index_sequence_for<Ts...>{});
}
// call lambda for all indexes in composite type
template<typename Fnc, typename... Ts>
void execAll(CompositeType<Ts...>& obj, Fnc&& fnc) const
{
execAllImpl(obj, std::forward<Fnc>(fnc), std::index_sequence_for<Ts...>{});
}
// serialize a type, by using overload first
template<typename S, typename T>
void serializeType(S& s, T& v) const
{
// first check if overload exists, otherwise try to call serialize method
if constexpr (hasOverload<S, T>()) {
std::invoke(*this, s, v);
} else {
static_assert(
details::SerializeFunction<S, T>::isDefined(),
"Please define overload or 'serialize' function for your type.");
s.object(v);
}
}
private:
template<typename S, typename T>
static constexpr bool hasOverload()
{
return std::is_invocable<ext::CompositeTypeOverloads<Overloads...>,
std::add_lvalue_reference_t<S>,
std::add_lvalue_reference_t<T>>::value;
}
template<typename Variant, typename Fnc, size_t... Is>
void execIndexImpl(size_t index,
Variant& obj,
Fnc&& fnc,
std::index_sequence<Is...>) const
{
((index == Is ? fnc(obj, std::integral_constant<size_t, Is>{}), 0 : 0),
...);
}
template<typename Variant, typename Fnc, size_t... Is>
void execAllImpl(Variant& obj, Fnc&& fnc, std::index_sequence<Is...>) const
{
(fnc(obj, std::integral_constant<size_t, Is>{}), ...);
}
};
}
}
#endif // BITSERY_EXT_COMPOSITE_TYPE_OVERLOADS_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2018 Mindaugas Vinkelis
// 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:
// 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 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.
// 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_EXT_MEMORY_RESOURCE_H
#define BITSERY_EXT_MEMORY_RESOURCE_H
@@ -27,145 +27,170 @@
#include <new>
namespace bitsery {
namespace ext {
// these are very similar to c++17 polymorphic allocator and memory resource classes
// but i don't want to enforce users to use c++17 if they want to use pointers
// plus this has additional information from RTTI about runtime type information,
// might be useful working with polymorphic types.
// The same memory resource is used to allocate internal data in various contexts,
// (typeId is always 0 for internal data allocation in contexts).
namespace ext {
// these are very similar to c++17 polymorphic allocator and memory resource
// classes but i don't want to enforce users to use c++17 if they want to use
// pointers plus this has additional information from RTTI about runtime type
// information, might be useful working with polymorphic types. The same memory
// resource is used to allocate internal data in various contexts, (typeId is
// always 0 for internal data allocation in contexts).
class MemResourceBase {
public:
virtual void* allocate(size_t bytes, size_t alignment, size_t typeId) = 0;
class MemResourceBase
{
public:
virtual void* allocate(size_t bytes, size_t alignment, size_t typeId) = 0;
virtual void deallocate(void* ptr, size_t bytes, size_t alignment, size_t typeId) noexcept = 0;
virtual void deallocate(void* ptr,
size_t bytes,
size_t alignment,
size_t typeId) noexcept = 0;
virtual ~MemResourceBase() noexcept = default;
};
virtual ~MemResourceBase() noexcept = default;
};
// default implementation for MemResourceBase using new and delete
class MemResourceNewDelete final: public MemResourceBase {
public:
inline void* allocate(size_t bytes, size_t /*alignment*/, size_t /*typeId*/) final {
return (::operator new(bytes));
}
// default implementation for MemResourceBase using new and delete
class MemResourceNewDelete final : public MemResourceBase
{
public:
inline void* allocate(size_t bytes,
size_t /*alignment*/,
size_t /*typeId*/) final
{
return (::operator new(bytes));
}
inline void
deallocate(void* ptr, size_t /*bytes*/, size_t /*alignment*/, size_t /*typeId*/) noexcept final {
(::operator delete(ptr));
}
inline void deallocate(void* ptr,
size_t /*bytes*/,
size_t /*alignment*/,
size_t /*typeId*/) noexcept final
{
(::operator delete(ptr));
}
~MemResourceNewDelete() noexcept final = default;
};
~MemResourceNewDelete() noexcept final = default;
};
// these classes are used internally by bitsery extensions and and pointer utils
namespace pointer_utils {
// this is helper class that stores memory resource and knows how to construct/destroy objects
// capture this by value for custom deleters, because during deserialization mem resource can be changed
class PolyAllocWithTypeId final {
public:
// these classes are used internally by bitsery extensions and and pointer utils
namespace pointer_utils {
// this is helper class that stores memory resource and knows how to
// construct/destroy objects capture this by value for custom deleters, because
// during deserialization mem resource can be changed
class PolyAllocWithTypeId final
{
public:
constexpr PolyAllocWithTypeId(MemResourceBase* memResource = nullptr)
: _resource{ memResource }
{
}
constexpr PolyAllocWithTypeId(MemResourceBase* memResource = nullptr)
:_resource{memResource} {}
template<typename T>
T* allocate(size_t n, size_t typeId) const
{
const auto bytes = sizeof(T) * n;
constexpr auto alignment = std::alignment_of<T>::value;
void* ptr =
_resource
? _resource->allocate(bytes, alignment, typeId)
: ext::MemResourceNewDelete{}.allocate(bytes, alignment, typeId);
return static_cast<T*>(ptr);
}
template<typename T>
T* allocate(size_t n, size_t typeId) const {
const auto bytes = sizeof(T) * n;
constexpr auto alignment = std::alignment_of<T>::value;
void* ptr = _resource
? _resource->allocate(bytes, alignment, typeId)
: ext::MemResourceNewDelete{}.allocate(bytes, alignment, typeId);
return static_cast<T*>(ptr);
}
template<typename T>
void deallocate(T* ptr, size_t n, size_t typeId) const noexcept
{
const auto bytes = sizeof(T) * n;
constexpr auto alignment = std::alignment_of<T>::value;
_resource
? _resource->deallocate(ptr, bytes, alignment, typeId)
: ext::MemResourceNewDelete{}.deallocate(ptr, bytes, alignment, typeId);
}
template<typename T>
void deallocate(T* ptr, size_t n, size_t typeId) const noexcept {
const auto bytes = sizeof(T) * n;
constexpr auto alignment = std::alignment_of<T>::value;
_resource
? _resource->deallocate(ptr, bytes, alignment, typeId)
: ext::MemResourceNewDelete{}.deallocate(ptr, bytes, alignment, typeId);
}
template<typename T>
T* newObject(size_t typeId) const
{
auto ptr = allocate<T>(1, typeId);
return ::bitsery::Access::create<T>(ptr);
}
template<typename T>
T* newObject(size_t typeId) const {
auto ptr = allocate<T>(1, typeId);
return ::bitsery::Access::create<T>(ptr);
}
template<typename T>
void deleteObject(T* obj, size_t typeId) const
{
obj->~T();
deallocate(obj, 1, typeId);
}
template<typename T>
void deleteObject(T* obj, size_t typeId) const {
obj->~T();
deallocate(obj, 1, typeId);
}
void setMemResource(ext::MemResourceBase* resource) { _resource = resource; }
void setMemResource(ext::MemResourceBase* resource) {
_resource = resource;
}
ext::MemResourceBase* getMemResource() const { return _resource; }
ext::MemResourceBase* getMemResource() const {
return _resource;
}
bool operator==(const PolyAllocWithTypeId& rhs) const noexcept
{
return _resource == rhs._resource;
}
bool operator==(const PolyAllocWithTypeId& rhs) const noexcept {
return _resource == rhs._resource;
}
bool operator!=(const PolyAllocWithTypeId& rhs) const noexcept
{
return !(*this == rhs);
}
bool operator!=(const PolyAllocWithTypeId& rhs) const noexcept {
return !(*this == rhs);
}
private:
ext::MemResourceBase* _resource;
};
private:
ext::MemResourceBase* _resource;
};
// this is very similar to c++17 PolymorphicAllocator
// it just wraps our PolyAllocWithTypeId and pass 0 as typeId
// and defines core functions for c++ Allocator concept,
template<class T>
class StdPolyAlloc
{
public:
using value_type = T;
// this is very similar to c++17 PolymorphicAllocator
// it just wraps our PolyAllocWithTypeId and pass 0 as typeId
// and defines core functions for c++ Allocator concept,
template<class T>
class StdPolyAlloc {
public:
using value_type = T;
explicit constexpr StdPolyAlloc(MemResourceBase* memResource)
: _alloc{ memResource }
{
}
explicit constexpr StdPolyAlloc(PolyAllocWithTypeId alloc)
: _alloc{ alloc }
{
}
explicit constexpr StdPolyAlloc(MemResourceBase* memResource)
:_alloc{memResource} {}
explicit constexpr StdPolyAlloc(PolyAllocWithTypeId alloc) : _alloc{alloc} {}
template<typename U>
friend class StdPolyAlloc;
template <typename U>
friend class StdPolyAlloc;
template<class U>
constexpr explicit StdPolyAlloc(const StdPolyAlloc<U>& other) noexcept
: _alloc{ other._alloc }
{
}
template<class U>
constexpr explicit StdPolyAlloc(const StdPolyAlloc<U>& other) noexcept
:_alloc{other._alloc} {
}
T* allocate(std::size_t n) { return _alloc.allocate<T>(n, 0); }
T* allocate(std::size_t n) {
return _alloc.allocate<T>(n, 0);
}
void deallocate(T* p, std::size_t n) noexcept
{
return _alloc.deallocate(p, n, 0);
}
void deallocate(T* p, std::size_t n) noexcept {
return _alloc.deallocate(p, n, 0);
}
template<class U>
friend bool operator==(const StdPolyAlloc<T>& lhs,
const StdPolyAlloc<U>& rhs) noexcept
{
return lhs._alloc == rhs._alloc;
}
template<class U>
friend bool operator==(const StdPolyAlloc<T>& lhs,
const StdPolyAlloc<U>& rhs) noexcept {
return lhs._alloc == rhs._alloc;
}
template<class U>
friend bool operator!=(const StdPolyAlloc<T>& lhs,
const StdPolyAlloc<U>& rhs) noexcept
{
return !(lhs == rhs);
}
template<class U>
friend bool operator!=(const StdPolyAlloc<T>& lhs,
const StdPolyAlloc<U>& rhs) noexcept {
return !(lhs == rhs);
}
private:
PolyAllocWithTypeId _alloc;
};
}
}
private:
PolyAllocWithTypeId _alloc;
};
}
#endif //BITSERY_EXT_MEMORY_RESOURCE_H
}
}
#endif // BITSERY_EXT_MEMORY_RESOURCE_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,287 +1,453 @@
//MIT License
// MIT License
//
//Copyright (c) 2018 Mindaugas Vinkelis
// 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:
// 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 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.
// 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_EXT_POLYMORPHISM_UTILS_H
#define BITSERY_EXT_POLYMORPHISM_UTILS_H
#include <unordered_map>
#include <memory>
#include "memory_resource.h"
#include "../../details/adapter_common.h"
#include "../../details/serialization_common.h"
#include <memory>
#include <unordered_map>
#include <vector>
namespace bitsery {
namespace ext {
namespace ext {
//helper type, that contains list of types
template<typename ...>
struct PolymorphicClassesList {
};
// helper type, that contains list of types
template<typename...>
struct PolymorphicClassesList
{};
//specialize for your base class by deriving from PolymorphicDerivedClasses with list of derivatives that DIRECTLY inherits from your base class.
//e.g.
// template <> PolymorphicBaseClass<Animal>: PolymorphicDerivedClasses<Dog, Cat>{};
// template <> PolymorphicBaseClass<Dog>: PolymorphicDerivedClasses<Bulldog, GoldenRetriever> {};
// IMPORTANT !!!
// although you can add all derivates to same base like this:
// template <> PolymorphicBaseClass<Animal>:PolymorphicDerivedClasses<Dog, Cat, Bulldog, GoldenRetriever>{};
// it will not work when you try to serialize Dog*, because it will not find Bulldog and GoldenRetriever
template<typename TBase>
struct PolymorphicBaseClass {
using Childs = PolymorphicClassesList<>;
};
// specialize for your base class by deriving from PolymorphicDerivedClasses
// with list of derivatives that DIRECTLY inherits from your base class.
// e.g.
// template <> PolymorphicBaseClass<Animal>: PolymorphicDerivedClasses<Dog,
// Cat>{}; template <> PolymorphicBaseClass<Dog>:
// PolymorphicDerivedClasses<Bulldog, GoldenRetriever> {}; IMPORTANT !!!
// although you can add all derivates to same base like this:
// template <> PolymorphicBaseClass<Animal>:PolymorphicDerivedClasses<Dog, Cat,
// Bulldog, GoldenRetriever>{}; it will not work when you try to serialize
// Dog*, because it will not find Bulldog and GoldenRetriever
template<typename TBase>
struct PolymorphicBaseClass
{
using Childs = PolymorphicClassesList<>;
};
//derive from this class when specifying childs for your base class, atleast one child must exists, hence T1
//e.g.
// template <> PolymorphicBaseClass<Animal>: PolymorphicDerivedClasses<Dog, Cat>{};
template<typename T1, typename ... Tn>
struct PolymorphicDerivedClasses {
using Childs = PolymorphicClassesList<T1, Tn...>;
};
// derive from this class when specifying childs for your base class, atleast
// one child must exists, hence T1 e.g.
// template <> PolymorphicBaseClass<Animal>: PolymorphicDerivedClasses<Dog,
// Cat>{};
template<typename T1, typename... Tn>
struct PolymorphicDerivedClasses
{
using Childs = PolymorphicClassesList<T1, Tn...>;
};
class PolymorphicHandlerBase {
public:
virtual void* create(const pointer_utils::PolyAllocWithTypeId& alloc) const = 0;
class PolymorphicHandlerBase
{
public:
virtual void* create(
const pointer_utils::PolyAllocWithTypeId& alloc) const = 0;
virtual void destroy(const pointer_utils::PolyAllocWithTypeId& alloc, void* ptr) const = 0;
virtual void destroy(const pointer_utils::PolyAllocWithTypeId& alloc,
void* ptr) const = 0;
virtual void process(void* ser, void* obj) const = 0;
virtual void process(void* ser, void* obj) const = 0;
virtual ~PolymorphicHandlerBase() = default;
};
virtual void* getRootPtr(const void* obj) const = 0;
template<typename RTTI, typename TSerializer, typename TBase, typename TDerived>
class PolymorphicHandler : public PolymorphicHandlerBase {
public:
virtual void* fromDerivedToBasePtr(void* obj) const = 0;
void* create(const pointer_utils::PolyAllocWithTypeId& alloc) const final {
return toBase(alloc.newObject<TDerived>(RTTI::template get<TDerived>()));
}
virtual size_t getDerivedTypeId() const = 0;
void destroy(const pointer_utils::PolyAllocWithTypeId& alloc, void* ptr) const final {
alloc.deleteObject<TDerived>(fromBase(ptr), RTTI::template get<TDerived>());
}
virtual ~PolymorphicHandlerBase() = default;
};
void process(void* ser, void* obj) const final {
static_cast<TSerializer*>(ser)->object(*fromBase(obj));
}
template<typename RTTI,
typename TSerializer,
typename TRoot,
typename TBase,
typename TDerived>
class PolymorphicHandler : public PolymorphicHandlerBase
{
public:
void* create(const pointer_utils::PolyAllocWithTypeId& alloc) const final
{
return toBase(alloc.newObject<TDerived>(RTTI::template get<TDerived>()));
}
private:
void destroy(const pointer_utils::PolyAllocWithTypeId& alloc,
void* ptr) const final
{
alloc.deleteObject<TDerived>(fromBase(ptr), RTTI::template get<TDerived>());
}
TDerived* fromBase(void* obj) const {
return RTTI::template cast<TBase, TDerived>(static_cast<TBase*>(obj));
}
void process(void* ser, void* obj) const final
{
static_cast<TSerializer*>(ser)->object(*fromBase(obj));
}
TBase* toBase(void* obj) const {
return RTTI::template cast<TDerived, TBase>(static_cast<TDerived*>(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); }
template<typename RTTI>
class PolymorphicContext {
private:
size_t getDerivedTypeId() const final
{
return RTTI::template get<TDerived>();
}
struct BaseToDerivedKey {
private:
TDerived* fromBase(void* obj) const
{
return RTTI::template cast<TBase, TDerived>(static_cast<TBase*>(obj));
}
std::size_t baseHash;
std::size_t derivedHash;
TBase* toBase(void* obj) const
{
return RTTI::template cast<TDerived, TBase>(static_cast<TDerived*>(obj));
}
};
bool operator==(const BaseToDerivedKey& other) const {
return baseHash == other.baseHash && derivedHash == other.derivedHash;
}
};
// 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;
}
struct BaseToDerivedKeyHashier {
size_t operator()(const BaseToDerivedKey& key) const {
return (key.baseHash + (key.baseHash << 6) + (key.derivedHash >> 2)) ^ key.derivedHash;
}
};
void destroy(const pointer_utils::PolyAllocWithTypeId&, void*) const
{
assert(false);
};
template<typename TSerializer, template<typename> class THierarchy, typename TBase, typename TDerived>
void add() {
addToMap<TSerializer, TBase, TDerived>(std::is_abstract<TDerived>{});
addChilds<TSerializer, THierarchy, TBase, TDerived>(typename THierarchy<TDerived>::Childs{});
}
void process(void*, void*) const { assert(false); }
template<typename TSerializer, template<typename> class THierarchy, typename TBase, typename TDerived, typename T1, typename ... Tn>
void addChilds(PolymorphicClassesList<T1, Tn...>) {
static_assert(std::is_base_of<TDerived, T1>::value,
"PolymorphicBaseClass<TBase> must derive a list of derived classes from TBase.");
add<TSerializer, THierarchy, TBase, T1>();
addChilds<TSerializer, THierarchy, TBase, TDerived>(PolymorphicClassesList<Tn...>{});
//iterate through derived class hierarchy as well
add<TSerializer, THierarchy, T1, T1>();
}
void* getRootPtr(const void*) const
{
assert(false);
return nullptr;
}
template<typename TSerializer, template<typename> class THierarchy, typename TBase, typename TDerived>
void addChilds(PolymorphicClassesList<>) {
}
void* fromDerivedToBasePtr(void*) const final
{
assert(false);
return nullptr;
}
template<typename TSerializer, typename TBase, typename TDerived>
void addToMap(std::false_type) {
using THandler = PolymorphicHandler<RTTI, TSerializer, TBase, TDerived>;
BaseToDerivedKey key{RTTI::template get<TBase>(), RTTI::template get<TDerived>()};
pointer_utils::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);
if (_baseToDerivedMap
.emplace(key, std::move(handler))
.second) {
auto it = _baseToDerivedArray.find(key.baseHash);
if (it == _baseToDerivedArray.end()) {
it = _baseToDerivedArray.emplace(
std::piecewise_construct,
std::forward_as_tuple(key.baseHash),
std::forward_as_tuple(pointer_utils::StdPolyAlloc<size_t>{_memResource})).first;
}
it->second.push_back(key.derivedHash);
}
}
size_t getDerivedTypeId() const { return RTTI::template get<TDerived>(); };
};
template<typename TSerializer, typename TBase, typename TDerived>
void addToMap(std::true_type) {
//cannot add abstract class
}
template<typename RTTI>
class PolymorphicContext
{
private:
struct BaseToDerivedKey
{
MemResourceBase* _memResource;
// store shared ptr to polymorphic handler, because it might be copied to "smart pointer" deleter
std::unordered_map<BaseToDerivedKey, std::shared_ptr<PolymorphicHandlerBase>,
BaseToDerivedKeyHashier, std::equal_to<BaseToDerivedKey>,
pointer_utils::StdPolyAlloc<std::pair<const BaseToDerivedKey, std::shared_ptr<PolymorphicHandlerBase>>>
> _baseToDerivedMap;
// this will allow convert from platform specific type information, to platform independent base->derived index
// this only works if all polymorphic relationships (PolymorphicBaseClass<TBase> -> PolymorphicDerivedClasses<TDerived...>)
// is equal between platforms.
std::unordered_map<size_t, std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>,
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>>>>
> _baseToDerivedArray;
public:
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}}
{}
PolymorphicContext(const PolymorphicContext& ) = delete;
PolymorphicContext& operator = (const PolymorphicContext&) = delete;
PolymorphicContext(PolymorphicContext&& ) = default;
PolymorphicContext& operator = (PolymorphicContext&&) = default;
void clear() {
_baseToDerivedMap.clear();
_baseToDerivedArray.clear();
}
// THierarchy is the name of class, that defines hierarchy
// PolymorphicBaseClass is defined as default parameter, so that at instantiation time
// it will get unique symbol in translation unit for PolymorphicBaseClass (which is defined in anonymous namespace)
// https://github.com/fraillt/bitsery/issues/9
template<typename TSerializer, template<typename> class THierarchy = PolymorphicBaseClass, typename T1, typename ...Tn>
void registerBasesList(PolymorphicClassesList<T1, Tn...>) {
add<TSerializer, THierarchy, T1, T1>();
registerBasesList<TSerializer, THierarchy>(PolymorphicClassesList<Tn...>{});
}
template<typename TSerializer, template<typename> class THierarchy>
void registerBasesList(PolymorphicClassesList<>) {
}
// 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>
void serialize(Serializer& ser, TBase& obj) const {
//get derived key
BaseToDerivedKey key{RTTI::template get<TBase>(), RTTI::template get<TBase>(obj)};
auto it = _baseToDerivedMap.find(key);
assert(it != _baseToDerivedMap.end());
//convert derived hash to derived index, to make it work in cross-platform environment
auto& vec = _baseToDerivedArray.find(key.baseHash)->second;
auto derivedIndex = static_cast<size_t>(std::distance(vec.begin(), std::find(vec.begin(), vec.end(),
key.derivedHash)));
details::writeSize(ser.adapter(), derivedIndex);
//serialize
it->second->process(&ser, &obj);
}
template<typename Deserializer, typename TBase, typename TCreateFnc, typename TDestroyFnc>
void deserialize(Deserializer& des, TBase* obj,
TCreateFnc createFnc, TDestroyFnc destroyFnc) const {
size_t derivedIndex{};
details::readSize(des.adapter(), derivedIndex, 0, std::false_type{});
auto baseToDerivedVecIt = _baseToDerivedArray.find(RTTI::template get<TBase>());
//base class is known at compile time, so we can assert on this one
assert(baseToDerivedVecIt != _baseToDerivedArray.end());
if (baseToDerivedVecIt->second.size() > derivedIndex) {
//convert derived index to derived hash, to make it work in cross-platform environment
auto derivedHash = baseToDerivedVecIt->second[derivedIndex];
auto& handler = _baseToDerivedMap.find(
BaseToDerivedKey{RTTI::template get<TBase>(), derivedHash})->second;
//if object is null or different type, create new and assign it
if (obj == nullptr || RTTI::template get<TBase>(*obj) != derivedHash) {
if (obj) {
destroyFnc(getPolymorphicHandler(*obj));
}
obj = createFnc(handler);
}
handler->process(&des, obj);
} else
des.adapter().error(ReaderError::InvalidPointer);
}
template<typename TBase>
const std::shared_ptr<PolymorphicHandlerBase>& getPolymorphicHandler(TBase& obj) const {
auto deleteHandlerIt = _baseToDerivedMap.find(
BaseToDerivedKey{RTTI::template get<TBase>(), RTTI::template get<TBase>(obj)});
assert(deleteHandlerIt != _baseToDerivedMap.end());
return deleteHandlerIt->second;
}
};
std::size_t baseHash;
std::size_t derivedHash;
bool operator==(const BaseToDerivedKey& other) const
{
return baseHash == other.baseHash && derivedHash == other.derivedHash;
}
};
struct BaseToDerivedKeyHashier
{
size_t operator()(const BaseToDerivedKey& key) const
{
return (key.baseHash + (key.baseHash << 6) + (key.derivedHash >> 2)) ^
key.derivedHash;
}
};
template<typename TSerializer,
template<typename>
class THierarchy,
typename TRoot,
typename TBase,
typename TDerived>
void add()
{
addToMap<TSerializer, TRoot, TBase, TDerived>(std::is_abstract<TDerived>{});
addChilds<TSerializer, THierarchy, TRoot, TBase, TDerived>(
typename THierarchy<TDerived>::Childs{});
}
template<typename TSerializer,
template<typename>
class THierarchy,
typename TRoot,
typename TBase,
typename TDerived,
typename T1,
typename... Tn>
void addChilds(PolymorphicClassesList<T1, Tn...>)
{
static_assert(std::is_base_of<TDerived, T1>::value,
"PolymorphicBaseClass<TBase> must derive a list of derived "
"classes from TBase.");
add<TSerializer, THierarchy, TRoot, TBase, T1>();
addChilds<TSerializer, THierarchy, TRoot, TBase, TDerived>(
PolymorphicClassesList<Tn...>{});
add<TSerializer, THierarchy, TRoot, T1, T1>();
}
template<typename TSerializer,
template<typename>
class THierarchy,
typename TRoot,
typename TBase,
typename TDerived>
void addChilds(PolymorphicClassesList<>)
{
}
template<typename TSerializer,
typename TRoot,
typename TBase,
typename TDerived>
void addToMap(std::false_type)
{
using THandler =
PolymorphicHandler<RTTI, TSerializer, 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);
if (_baseToDerivedMap.emplace(key, std::move(handler)).second) {
auto it = _baseToDerivedArray.find(key.baseHash);
if (it == _baseToDerivedArray.end()) {
it = _baseToDerivedArray
.emplace(std::piecewise_construct,
std::forward_as_tuple(key.baseHash),
std::forward_as_tuple(
pointer_utils::StdPolyAlloc<size_t>{ _memResource }))
.first;
}
it->second.push_back(key.derivedHash);
}
}
template<typename TSerializer,
typename TRoot,
typename TBase,
typename TDerived>
void addToMap(std::true_type)
{
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;
// store shared ptr to polymorphic handler, because it might be copied to
// "smart pointer" deleter
std::unordered_map<BaseToDerivedKey,
std::shared_ptr<PolymorphicHandlerBase>,
BaseToDerivedKeyHashier,
std::equal_to<BaseToDerivedKey>,
pointer_utils::StdPolyAlloc<
std::pair<const BaseToDerivedKey,
std::shared_ptr<PolymorphicHandlerBase>>>>
_baseToDerivedMap;
// this will allow convert from platform specific type information, to
// platform independent base->derived index this only works if all polymorphic
// relationships (PolymorphicBaseClass<TBase> ->
// PolymorphicDerivedClasses<TDerived...>) is equal between platforms.
std::unordered_map<
size_t,
std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>,
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>>>>>
_baseToDerivedArray;
public:
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 } }
{
}
PolymorphicContext(const PolymorphicContext&) = delete;
PolymorphicContext& operator=(const PolymorphicContext&) = delete;
PolymorphicContext(PolymorphicContext&&) = default;
PolymorphicContext& operator=(PolymorphicContext&&) = default;
void clear()
{
_baseToDerivedMap.clear();
_baseToDerivedArray.clear();
}
// THierarchy is the name of class, that defines hierarchy
// PolymorphicBaseClass is defined as default parameter, so that at
// instantiation time it will get unique symbol in translation unit for
// PolymorphicBaseClass (which is defined in anonymous namespace)
// https://github.com/fraillt/bitsery/issues/9
template<typename TSerializer,
template<typename> class THierarchy = PolymorphicBaseClass,
typename T1,
typename... Tn>
void registerBasesList(PolymorphicClassesList<T1, Tn...>)
{
add<TSerializer, THierarchy, T1, T1, T1>();
registerBasesList<TSerializer, THierarchy>(PolymorphicClassesList<Tn...>{});
}
template<typename TSerializer, template<typename> class THierarchy>
void registerBasesList(PolymorphicClassesList<>)
{
}
template<typename Serializer, typename TBase>
void serialize(Serializer& ser, TBase& obj) const
{
// get derived key
BaseToDerivedKey key{ RTTI::template get<TBase>(),
RTTI::template get<TBase>(obj) };
auto it = _baseToDerivedMap.find(key);
assert(it != _baseToDerivedMap.end());
// convert derived hash to derived index, to make it work in cross-platform
// environment
auto& vec = _baseToDerivedArray.find(key.baseHash)->second;
auto derivedIndex = static_cast<size_t>(std::distance(
vec.begin(), std::find(vec.begin(), vec.end(), key.derivedHash)));
details::writeSize(ser.adapter(), derivedIndex);
// serialize
it->second->process(&ser, &obj);
}
template<typename Deserializer,
typename TBase,
typename TCreateFnc,
typename TDestroyFnc>
void deserialize(Deserializer& des,
TBase* obj,
TCreateFnc createFnc,
TDestroyFnc destroyFnc) const
{
size_t derivedIndex{};
details::readSize(des.adapter(), derivedIndex, 0, std::false_type{});
auto baseToDerivedVecIt =
_baseToDerivedArray.find(RTTI::template get<TBase>());
// base class is known at compile time, so we can assert on this one
assert(baseToDerivedVecIt != _baseToDerivedArray.end());
if (baseToDerivedVecIt->second.size() > derivedIndex) {
// convert derived index to derived hash, to make it work in
// cross-platform environment
auto derivedHash = baseToDerivedVecIt->second[derivedIndex];
auto& handler =
_baseToDerivedMap
.find(BaseToDerivedKey{ RTTI::template get<TBase>(), derivedHash })
->second;
// if object is null or different type, create new and assign it
if (obj == nullptr || RTTI::template get<TBase>(*obj) != derivedHash) {
if (obj) {
destroyFnc(getPolymorphicHandler(obj));
}
obj = createFnc(handler);
}
handler->process(&des, obj);
} else
des.adapter().error(ReaderError::InvalidPointer);
}
template<typename TBase>
const std::shared_ptr<PolymorphicHandlerBase>& getPolymorphicHandler(
TBase* obj) const
{
auto it = _baseToDerivedMap.find(BaseToDerivedKey{
RTTI::template get<TBase>(), RTTI::template get<TBase>(*obj) });
assert(it != _baseToDerivedMap.end());
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;
}
};
}
#endif //BITSERY_EXT_POLYMORPHISM_UTILS_H
}
#endif // BITSERY_EXT_POLYMORPHISM_UTILS_H

View File

@@ -1,65 +1,65 @@
//MIT License
// MIT License
//
//Copyright (c) 2018 Mindaugas Vinkelis
// 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:
// 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 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.
// 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_RTTI_UTILS_H
#define BITSERY_RTTI_UTILS_H
#include <typeinfo>
#include <type_traits>
#include <cstddef>
#include <type_traits>
#include <typeinfo>
namespace bitsery {
namespace ext {
namespace ext {
struct StandardRTTI {
struct StandardRTTI
{
// static_assert(!std::is_pointer<TBase>::value &&
// !std::is_const<TBase>::value &&
// !std::is_volatile<TBase>::value, "");
template<typename TBase>
static size_t get(TBase& obj)
{
return typeid(obj).hash_code();
}
template<typename TBase>
static size_t get(TBase& obj) {
return typeid(obj).hash_code();
}
template<typename TBase>
static constexpr size_t get()
{
return typeid(TBase).hash_code();
}
template<typename TBase>
static constexpr size_t get() {
return typeid(TBase).hash_code();
}
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, 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 std::is_polymorphic<TBase>::value;
}
};
template<typename TBase>
static constexpr bool isPolymorphic() {
return std::is_polymorphic<TBase>::value;
}
};
}
}
}
#endif //BITSERY_RTTI_UTILS_H
#endif // BITSERY_RTTI_UTILS_H

View File

@@ -1,219 +1,268 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_EXT_VALUE_RANGE_H
#define BITSERY_EXT_VALUE_RANGE_H
#include "../details/serialization_common.h"
#include "../details/adapter_common.h"
#include <cassert>
namespace bitsery {
namespace ext {
//this class is used to make default RangeSpec float specialization always prefer constructor with precision
struct BitsConstraint {
explicit constexpr BitsConstraint(size_t bits) : value{bits} {}
namespace ext {
// this class is used to make default RangeSpec float specialization always
// prefer constructor with precision
struct BitsConstraint
{
explicit constexpr BitsConstraint(size_t bits)
: value{ bits }
{
}
const size_t value;
};
const size_t value;
};
}
// implementation details for range functionality
namespace details {
template<typename T>
constexpr size_t
getSize(T v, size_t s)
{
return v > 0 ? getSize(v / 2, s + 1) : s;
}
template<typename T>
constexpr size_t
calcRequiredBits(T min, T max)
{
// call recursive function, because some compilers only support constexpr
// functions with return-only body
return getSize(max - min, 0);
}
template<typename T, typename Enable = void>
struct RangeSpec
{
constexpr RangeSpec(T minValue, T maxValue)
: min{ minValue }
, max{ maxValue }
, bitsRequired{ calcRequiredBits(min, max) }
{
}
const T min;
const T max;
const size_t bitsRequired;
};
template<typename T>
struct RangeSpec<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
constexpr RangeSpec(T minValue, T maxValue)
: min{ minValue }
, max{ maxValue }
, bitsRequired{ calcRequiredBits(
static_cast<typename std::underlying_type<T>::type>(min),
static_cast<typename std::underlying_type<T>::type>(max)) }
{
}
const T min;
const T max;
const size_t bitsRequired;
};
template<typename T>
struct RangeSpec<
T,
typename std::enable_if<std::is_floating_point<T>::value>::type>
{
constexpr RangeSpec(T minValue, T maxValue, ext::BitsConstraint bits)
: min{ minValue }
, max{ maxValue }
, bitsRequired{ bits.value }
{
}
constexpr RangeSpec(T minValue, T maxValue, T precision)
: min{ minValue }
, max{ maxValue }
, bitsRequired{ calcRequiredBits<details::SameSizeUnsigned<T>>(
{},
static_cast<details::SameSizeUnsigned<T>>((max - min) / precision)) }
{
}
const T min;
const T max;
const size_t bitsRequired;
};
template<typename T,
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
details::SameSizeUnsigned<T>
getRangeValue(const T& v, const RangeSpec<T>& r)
{
return static_cast<details::SameSizeUnsigned<T>>(v - r.min);
}
template<typename T,
typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
details::SameSizeUnsigned<T>
getRangeValue(const T& v, const RangeSpec<T>& r)
{
using VT = details::SameSizeUnsigned<T>;
return static_cast<VT>(static_cast<VT>(v) - static_cast<VT>(r.min));
}
template<
typename T,
typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
details::SameSizeUnsigned<T>
getRangeValue(const T& v, const RangeSpec<T>& r)
{
using VT = details::SameSizeUnsigned<T>;
const VT maxUint = (static_cast<VT>(1) << r.bitsRequired) - 1;
const T ratio = (v - r.min) / (r.max - r.min);
return static_cast<VT>(ratio * static_cast<T>(maxUint));
}
template<typename T,
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
void
setRangeValue(T& v, const RangeSpec<T>& r)
{
v += r.min;
}
template<typename T,
typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
void
setRangeValue(T& v, const RangeSpec<T>& r)
{
using VT = typename std::underlying_type<T>::type;
reinterpret_cast<VT&>(v) += static_cast<VT>(r.min);
}
template<
typename T,
typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
void
setRangeValue(T& v, const RangeSpec<T>& r)
{
using UIT = details::SameSizeUnsigned<T>;
const auto intRep = reinterpret_cast<UIT&>(v);
const UIT maxUint = (static_cast<UIT>(1) << r.bitsRequired) - 1;
v = r.min +
(static_cast<T>(intRep) / static_cast<T>(maxUint)) * (r.max - r.min);
}
template<typename T,
typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
bool
isRangeValid(const T& v, const RangeSpec<T>& r)
{
return !(r.min > v || v > r.max);
}
template<typename T,
typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
bool
isRangeValid(const T& v, const RangeSpec<T>& r)
{
using VT = typename std::underlying_type<T>::type;
return !(static_cast<VT>(r.min) > static_cast<VT>(v) ||
static_cast<VT>(v) > static_cast<VT>(r.max));
}
}
namespace ext {
template<typename TValue>
class ValueRange
{
public:
template<typename... Args>
constexpr ValueRange(const TValue& min, const TValue& max, Args&&... args)
: _range{ min, max, std::forward<Args>(args)... }
{
}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const T& v, Fnc&&) const
{
assert(details::isRangeValid(v, _range));
using BT = decltype(details::getRangeValue(v, _range));
ser.adapter().template writeBits<BT>(details::getRangeValue(v, _range),
_range.bitsRequired);
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, T& v, Fnc&&) const
{
auto& reader = des.adapter();
reader.readBits(reinterpret_cast<details::SameSizeUnsigned<T>&>(v),
_range.bitsRequired);
details::setRangeValue(v, _range);
handleInvalidRange(
reader, v, std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
}
constexpr size_t getRequiredBits() const { return _range.bitsRequired; };
private:
template<typename Reader, typename T>
void handleInvalidRange(Reader& reader, T& v, std::true_type) const
{
if (!details::isRangeValid(v, _range)) {
reader.error(ReaderError::InvalidData);
v = _range.min;
}
}
//implementation details for range functionality
namespace details {
template<typename Reader, typename T>
void handleInvalidRange(Reader&, T&, std::false_type) const
{
}
template<typename T>
constexpr size_t getSize(T v, size_t s) {
return v > 0 ? getSize(v / 2, s + 1) : s;
}
details::RangeSpec<TValue> _range;
};
}
template<typename T>
constexpr size_t calcRequiredBits(T min, T max) {
//call recursive function, because some compilers only support constexpr functions with return-only body
return getSize(max - min, 0);
}
template<typename T, typename Enable = void>
struct RangeSpec {
constexpr RangeSpec(T minValue, T maxValue)
: min{minValue},
max{maxValue},
bitsRequired{calcRequiredBits(min, max)} {
}
const T min;
const T max;
const size_t bitsRequired;
};
template<typename T>
struct RangeSpec<T, typename std::enable_if<std::is_enum<T>::value>::type> {
constexpr RangeSpec(T minValue, T maxValue) :
min{minValue},
max{maxValue},
bitsRequired{calcRequiredBits(
static_cast<typename std::underlying_type<T>::type>(min),
static_cast<typename std::underlying_type<T>::type>(max))} {
}
const T min;
const T max;
const size_t bitsRequired;
};
template<typename T>
struct RangeSpec<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
constexpr RangeSpec(T minValue, T maxValue, ext::BitsConstraint bits) :
min{minValue},
max{maxValue},
bitsRequired{bits.value} {
}
constexpr RangeSpec(T minValue, T maxValue, T precision) :
min{minValue},
max{maxValue},
bitsRequired{calcRequiredBits<details::SameSizeUnsigned<T>>(
{}, static_cast<details::SameSizeUnsigned<T>>((max - min) / precision))} {
}
const T min;
const T max;
const size_t bitsRequired;
};
template<typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
details::SameSizeUnsigned<T> getRangeValue(const T &v, const RangeSpec<T> &r) {
return static_cast<details::SameSizeUnsigned<T>>(v - r.min);
}
template<typename T, typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
details::SameSizeUnsigned<T> getRangeValue(const T &v, const RangeSpec<T> &r) {
using VT = details::SameSizeUnsigned<T>;
return static_cast<VT>(static_cast<VT>(v) - static_cast<VT>(r.min));
}
template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
details::SameSizeUnsigned<T> getRangeValue(const T &v, const RangeSpec<T> &r) {
using VT = details::SameSizeUnsigned<T>;
const VT maxUint = (static_cast<VT>(1) << r.bitsRequired) - 1;
const T ratio = (v - r.min) / (r.max - r.min);
return static_cast<VT>(ratio * static_cast<T>(maxUint));
}
template<typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
void setRangeValue(T &v, const RangeSpec<T> &r) {
v += r.min;
}
template<typename T, typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
void setRangeValue(T &v, const RangeSpec<T> &r) {
using VT = typename std::underlying_type<T>::type;
reinterpret_cast<VT &>(v) += static_cast<VT>(r.min);
}
template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
void setRangeValue(T &v, const RangeSpec<T> &r) {
using UIT = details::SameSizeUnsigned<T>;
const auto intRep = reinterpret_cast<UIT &>(v);
const UIT maxUint = (static_cast<UIT>(1) << r.bitsRequired) - 1;
v = r.min + (static_cast<T>(intRep) / static_cast<T>(maxUint)) * (r.max - r.min);
}
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type * = nullptr>
bool isRangeValid(const T &v, const RangeSpec<T> &r) {
return !(r.min > v || v > r.max);
}
template<typename T, typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
bool isRangeValid(const T &v, const RangeSpec<T> &r) {
using VT = typename std::underlying_type<T>::type;
return !(static_cast<VT>(r.min) > static_cast<VT>(v)
|| static_cast<VT>(v) > static_cast<VT>(r.max));
}
}
namespace ext {
template<typename TValue>
class ValueRange {
public:
template<typename ... Args>
constexpr ValueRange(const TValue& min, const TValue& max, Args &&... args)
:_range{min, max, std::forward<Args>(args)...} {}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &v, Fnc &&) const {
assert(details::isRangeValid(v, _range));
using BT = decltype(details::getRangeValue(v, _range));
ser.adapter().template writeBits<BT>(details::getRangeValue(v, _range), _range.bitsRequired);
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &v, Fnc &&) const {
auto& reader = des.adapter();
reader.readBits(reinterpret_cast<details::SameSizeUnsigned<T> &>(v), _range.bitsRequired);
details::setRangeValue(v, _range);
handleInvalidRange(reader, v, std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
}
constexpr size_t getRequiredBits() const {
return _range.bitsRequired;
};
private:
template <typename Reader, typename T>
void handleInvalidRange(Reader& reader, T& v, std::true_type) const {
if (!details::isRangeValid(v, _range)) {
reader.error(ReaderError::InvalidData);
v = _range.min;
}
}
template <typename Reader, typename T>
void handleInvalidRange(Reader&, T&, std::false_type) const {
}
details::RangeSpec<TValue> _range;
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::ValueRange<T>, T> {
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::ValueRange<T>, T>
{
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif //BITSERY_EXT_VALUE_RANGE_H
#endif // BITSERY_EXT_VALUE_RANGE_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_TRAITS_STD_ARRAY_H
#define BITSERY_TRAITS_STD_ARRAY_H
@@ -29,16 +28,18 @@
namespace bitsery {
namespace traits {
template<typename T, size_t N>
struct ContainerTraits<std::array<T, N>>
:public StdContainer<std::array<T, N>, false, true> {};
namespace traits {
template<typename T, size_t N>
struct ContainerTraits<std::array<T, N>>
: public StdContainer<std::array<T, N>, false, true>
{};
template<typename T, size_t N>
struct BufferAdapterTraits<std::array<T, N>>
:public StdContainerForBufferAdapter<std::array<T, N>> {};
}
template<typename T, size_t N>
struct BufferAdapterTraits<std::array<T, N>>
: public StdContainerForBufferAdapter<std::array<T, N>>
{};
}
}
#endif //BITSERY_TYPE_TRAITS_STD_ARRAY_H
#endif // BITSERY_TYPE_TRAITS_STD_ARRAY_H

View File

@@ -1,103 +1,118 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_TRAITS_CORE_STD_DEFAULTS_H
#define BITSERY_TRAITS_CORE_STD_DEFAULTS_H
#include "traits.h"
#include "../../bitsery.h"
#include "../../details/serialization_common.h"
#include "traits.h"
namespace bitsery {
namespace traits {
namespace traits {
/*
* these are helper types, to easier write specializations for std types
*/
/*
* these are helper types, to easier write specializations for std types
*/
template<typename T, bool Resizable, bool Contiguous>
struct StdContainer {
using TValue = typename T::value_type;
static constexpr bool isResizable = Resizable;
static constexpr bool isContiguous = Contiguous;
static size_t size(const T& container) {
return container.size();
}
};
template<typename T, bool Resizable, bool Contiguous>
struct StdContainer
{
using TValue = typename T::value_type;
static constexpr bool isResizable = Resizable;
static constexpr bool isContiguous = Contiguous;
static size_t size(const T& container) { return container.size(); }
};
//specialization for resizable
template<typename T, bool Contiguous>
struct StdContainer<T, true, Contiguous> {
using TValue = typename T::value_type;
static constexpr bool isResizable = true;
static constexpr bool isContiguous = Contiguous;
static size_t size(const T& container) {
return container.size();
}
static void resize(T& container, size_t size) {
resizeImpl(container, size, std::is_default_constructible<TValue>{});
}
private:
using diff_t = typename T::difference_type;
// specialization for resizable
template<typename T, bool Contiguous>
struct StdContainer<T, true, Contiguous>
{
using TValue = typename T::value_type;
static constexpr bool isResizable = true;
static constexpr bool isContiguous = Contiguous;
static size_t size(const T& container) { return container.size(); }
static void resize(T& container, size_t size)
{
resizeImpl(container, size, std::is_default_constructible<TValue>{});
}
static void resizeImpl(T& container, size_t size, std::true_type) {
container.resize(size);
}
static void resizeImpl(T& container, size_t newSize, std::false_type) {
const auto oldSize = size(container);
for (auto it = oldSize; it < newSize; ++it) {
container.push_back(::bitsery::Access::create<TValue>());
}
if (oldSize > newSize) {
container.erase(std::next(std::begin(container), static_cast<diff_t>(newSize)), std::end(container));
}
}
};
template <typename T, bool Resizable = ContainerTraits<T>::isResizable>
struct StdContainerForBufferAdapter {
using TIterator = typename T::iterator;
using TConstIterator = typename T::const_iterator;
using TValue = typename ContainerTraits<T>::TValue;
};
//specialization for resizable buffers
template <typename T>
struct StdContainerForBufferAdapter<T, true> {
static void increaseBufferSize(T& container) {
//since we're writing to buffer use different resize strategy than default implementation
//when small size grow faster, to avoid thouse 2/4/8/16... byte allocations
auto newSize = static_cast<size_t>(static_cast<double>(container.size()) * 1.5) + 128;
//make data cache friendly
newSize -= newSize % 64;//64 is cache line size
container.resize((std::max)(newSize, container.capacity()));
}
using TIterator = typename T::iterator;
using TConstIterator = typename T::const_iterator;
using TValue = typename ContainerTraits<T>::TValue;
};
private:
using diff_t = typename T::difference_type;
static void resizeImpl(T& container, size_t size, std::true_type)
{
container.resize(size);
}
static void resizeImpl(T& container, size_t newSize, std::false_type)
{
const auto oldSize = size(container);
for (auto it = oldSize; it < newSize; ++it) {
container.push_back(::bitsery::Access::create<TValue>());
}
if (oldSize > newSize) {
container.erase(
std::next(std::begin(container), static_cast<diff_t>(newSize)),
std::end(container));
}
}
};
template<typename T, bool Resizable = ContainerTraits<T>::isResizable>
struct StdContainerForBufferAdapter
{
using TIterator = typename T::iterator;
using TConstIterator = typename T::const_iterator;
using TValue = typename ContainerTraits<T>::TValue;
};
// specialization for resizable buffers
template<typename T>
struct StdContainerForBufferAdapter<T, true>
{
using TIterator = typename T::iterator;
using TConstIterator = typename T::const_iterator;
using TValue = typename ContainerTraits<T>::TValue;
static void increaseBufferSize(T& container,
size_t /*currSize*/,
size_t minSize)
{
// since we're writing to buffer use different resize strategy than default
// implementation when small size grow faster, to avoid thouse 2/4/8/16...
// byte allocations
auto newSize =
static_cast<size_t>(static_cast<double>(container.size()) * 1.5) + 128;
// make data cache friendly
newSize -= newSize % 64; // 64 is cache line size
auto resize =
(std::max)(newSize > minSize ? newSize : minSize, container.capacity());
BITSERY_ASSUME(resize >= container.size());
BITSERY_ASSUME(resize >= container.capacity());
container.resize(resize);
}
};
}
}
#endif //BITSERY_TRAITS_CORE_STD_DEFAULTS_H
#endif // BITSERY_TRAITS_CORE_STD_DEFAULTS_H

View File

@@ -1,187 +1,208 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_TRAITS_CORE_TRAITS_H
#define BITSERY_TRAITS_CORE_TRAITS_H
#include <type_traits>
#include "../../details/not_defined_type.h"
#include <type_traits>
namespace bitsery {
namespace traits {
namespace traits {
/*
* core library traits, used to extend library for custom types
*/
/*
* core library traits, used to extend library for custom types
*/
//traits for extension
template<typename Extension, typename T>
struct ExtensionTraits {
//this type is used, when using extesion without custom lambda
// eg.: extension4b>(obj, myextension{}) will call s.value4b(obj) for TValue
// or extesion(obj, myextension{}) will call s.object(obj) for TValue
//when this is void, it will compile, but value and object overloads will do nothing.
using TValue = details::NotDefinedType;
// traits for extension
template<typename Extension, typename T>
struct ExtensionTraits
{
// this type is used, when using extesion without custom lambda
// eg.: extension4b>(obj, myextension{}) will call s.value4b(obj) for TValue
// or extesion(obj, myextension{}) will call s.object(obj) for TValue
// when this is void, it will compile, but value and object overloads will do
// nothing.
using TValue = details::NotDefinedType;
//does extension support ext<N>(...) syntax, by calling value<N> with TValue
static constexpr bool SupportValueOverload = false;
//does extension support ext(...) syntax, by calling object with TValue
static constexpr bool SupportObjectOverload = false;
//does extension support ext(..., lambda)
static constexpr bool SupportLambdaOverload = false;
};
// does extension support ext<N>(...) syntax, by calling value<N> with TValue
static constexpr bool SupportValueOverload = false;
// does extension support ext(...) syntax, by calling object with TValue
static constexpr bool SupportObjectOverload = false;
// does extension support ext(..., lambda)
static constexpr bool SupportLambdaOverload = false;
};
//primary traits for containers
template<typename T>
struct ContainerTraits {
// primary traits for containers
template<typename T>
struct ContainerTraits
{
using TValue = details::NotDefinedType;
using TValue = details::NotDefinedType;
static constexpr bool isResizable = false;
//contiguous arrays has oppurtunity to memcpy whole buffer directly when using funtamental types
//contiguous doesn't nesessary equal to random access iterator.
//contiguous hopefully will be available in c++20
static constexpr bool isContiguous = false;
//resize function, called only if container is resizable
static void resize(T& , size_t ) {
static_assert(std::is_void<T>::value,
"Define ContainerTraits or include from <bitsery/traits/...> to use as container");
}
//get container size
static size_t size(const T& ) {
static_assert(std::is_void<T>::value,
"Define ContainerTraits or include from <bitsery/traits/...> to use as container");
return 0u;
}
};
static constexpr bool isResizable = false;
// contiguous arrays has oppurtunity to memcpy whole buffer directly when
// using funtamental types contiguous doesn't nesessary equal to random access
// iterator. contiguous hopefully will be available in c++20
static constexpr bool isContiguous = false;
// resize function, called only if container is resizable
static void resize(T&, size_t)
{
static_assert(std::is_void<T>::value,
"Define ContainerTraits or include from <bitsery/traits/...> "
"to use as container");
}
// get container size
static size_t size(const T&)
{
static_assert(std::is_void<T>::value,
"Define ContainerTraits or include from <bitsery/traits/...> "
"to use as container");
return 0u;
}
};
//specialization for C style array
template<typename T, size_t N>
struct ContainerTraits<T[N]> {
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const T (&)[N]) {
return N;
}
};
// specialization for C style array
template<typename T, size_t N>
struct ContainerTraits<T[N]>
{
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const T (&)[N]) { return N; }
};
//specialization for initializer list.
//only serializer can use it
template<typename T>
struct ContainerTraits<std::initializer_list<T>> {
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const std::initializer_list<T>& container) {
return container.size();
}
};
// specialization for initializer list.
// only serializer can use it
template<typename T>
struct ContainerTraits<std::initializer_list<T>>
{
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const std::initializer_list<T>& container)
{
return container.size();
}
};
//specialization for pointer type buffer
//only deserializer can use it
template <typename T>
struct ContainerTraits<const T*> {
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const T* ) {
static_assert(std::is_void<T>::value, "cannot get size for container of type T*");
return 0u;
}
};
// specialization for pointer type buffer
// only deserializer can use it
template<typename T>
struct ContainerTraits<const T*>
{
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const T*)
{
static_assert(std::is_void<T>::value,
"cannot get size for container of type T*");
return 0u;
}
};
template <typename T>
struct ContainerTraits<T*> {
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const T* ) {
static_assert(std::is_void<T>::value, "cannot get size for container of type T*");
return 0u;
}
};
template<typename T>
struct ContainerTraits<T*>
{
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const T*)
{
static_assert(std::is_void<T>::value,
"cannot get size for container of type T*");
return 0u;
}
};
// traits for text, default adds null-terminated character at the end
template<typename T>
struct TextTraits
{
using TValue = details::NotDefinedType;
// if container is not null-terminated by default, add NUL at the end
static constexpr bool addNUL = true;
// get length of null terminated container
static size_t length(const T&)
{
static_assert(
std::is_void<T>::value,
"Define TextTraits or include from <bitsery/traits/...> to use as text");
return 0u;
}
};
//traits for text, default adds null-terminated character at the end
template<typename T>
struct TextTraits {
using TValue = details::NotDefinedType;
//if container is not null-terminated by default, add NUL at the end
static constexpr bool addNUL = true;
// traits only for buffer adapters
template<typename T>
struct BufferAdapterTraits
{
using TIterator = details::NotDefinedType;
using TConstIterator = details::NotDefinedType;
using TValue = typename ContainerTraits<T>::TValue;
//get length of null terminated container
static size_t length(const T& ) {
static_assert(std::is_void<T>::value,
"Define TextTraits or include from <bitsery/traits/...> to use as text");
return 0u;
}
};
// this function is only applies to resizable containers
//traits only for buffer adapters
template <typename T>
struct BufferAdapterTraits {
//this function is only applies to resizable containers
// this function is only used by Writer, when writing data to buffer,
// it is called only current buffer size is not enough to write.
// it is used to dramaticaly improve performance by updating buffer directly
// instead of using back_insert_iterator to append each byte to buffer.
//this function is only used by Writer, when writing data to buffer,
//it is called only current buffer size is not enough to write.
//it is used to dramaticaly improve performance by updating buffer directly
//instead of using back_insert_iterator to append each byte to buffer.
static void increaseBufferSize(T&, size_t, size_t)
{
static_assert(std::is_void<T>::value,
"Define BufferAdapterTraits or include from "
"<bitsery/traits/...> to use as buffer adapter container");
}
};
static void increaseBufferSize(T& ) {
static_assert(std::is_void<T>::value,
"Define BufferAdapterTraits or include from <bitsery/traits/...> to use as buffer adapter container");
}
// specialization for c-style buffer
template<typename T, size_t N>
struct BufferAdapterTraits<T[N]>
{
using TIterator = T*;
using TConstIterator = const T*;
using TValue = T;
};
using TIterator = details::NotDefinedType;
using TConstIterator = details::NotDefinedType;
using TValue = typename ContainerTraits<T>::TValue;
};
// specialization for pointer type buffer
template<typename T>
struct BufferAdapterTraits<const T*>
{
using TIterator = const T*;
using TConstIterator = const T*;
using TValue = T;
};
//specialization for c-style buffer
template <typename T, size_t N>
struct BufferAdapterTraits<T[N]> {
using TIterator = T*;
using TConstIterator = const T*;
using TValue = T;
};
template<typename T>
struct BufferAdapterTraits<T*>
{
using TIterator = T*;
using TConstIterator = const T*;
using TValue = T;
};
//specialization for pointer type buffer
template <typename T>
struct BufferAdapterTraits<const T*> {
using TIterator = const T*;
using TConstIterator = const T*;
using TValue = T;
};
template <typename T>
struct BufferAdapterTraits<T*> {
using TIterator = T*;
using TConstIterator = const T*;
using TValue = T;
};
}
}
}
#endif //BITSERY_TRAITS_CORE_TRAITS_H
#endif // BITSERY_TRAITS_CORE_TRAITS_H

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_TRAITS_STD_DEQUE_H
#define BITSERY_TRAITS_STD_DEQUE_H
@@ -29,14 +28,15 @@
namespace bitsery {
namespace traits {
namespace traits {
template<typename T, typename Allocator>
struct ContainerTraits<std::deque<T, Allocator>>
: public StdContainer<std::deque<T, Allocator>, true, false> {};
}
template<typename T, typename Allocator>
struct ContainerTraits<std::deque<T, Allocator>>
: public StdContainer<std::deque<T, Allocator>, true, false>
{};
}
#endif //BITSERY_TRAITS_STD_DEQUE_H
}
#endif // BITSERY_TRAITS_STD_DEQUE_H

View File

@@ -1,69 +1,79 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_TRAITS_STD_FORWARD_LIST_H
#define BITSERY_TRAITS_STD_FORWARD_LIST_H
#include "core/traits.h"
#include "../details/serialization_common.h"
#include "core/traits.h"
#include <forward_list>
namespace bitsery {
namespace traits {
namespace traits {
template<typename T, typename Allocator>
struct ContainerTraits<std::forward_list<T, Allocator>> {
using TValue = T;
static constexpr bool isResizable = true;
static constexpr bool isContiguous = false;
static size_t size(const std::forward_list<T, Allocator>& container) {
return static_cast<size_t>(std::distance(container.begin(), container.end()));
}
static void resize(std::forward_list<T, Allocator>& container, size_t size) {
resizeImpl(container, size, std::is_default_constructible<TValue>{});
}
private:
using diff_t = typename std::forward_list<T, Allocator>::difference_type;
static void resizeImpl(std::forward_list<T, Allocator>& container, size_t size, std::true_type) {
container.resize(size);
}
static void resizeImpl(std::forward_list<T, Allocator>& container, size_t newSize, std::false_type) {
const auto oldSize = size(container);
for (auto it = oldSize; it < newSize; ++it) {
container.push_front(::bitsery::Access::create<TValue>());
}
if (oldSize > newSize) {
//erase_after must have atleast one element to work
if (newSize > 0)
container.erase_after(std::next(std::begin(container), static_cast<diff_t>(newSize-1)));
else
container.clear();
}
}
};
template<typename T, typename Allocator>
struct ContainerTraits<std::forward_list<T, Allocator>>
{
using TValue = T;
static constexpr bool isResizable = true;
static constexpr bool isContiguous = false;
static size_t size(const std::forward_list<T, Allocator>& container)
{
return static_cast<size_t>(
std::distance(container.begin(), container.end()));
}
static void resize(std::forward_list<T, Allocator>& container, size_t size)
{
resizeImpl(container, size, std::is_default_constructible<TValue>{});
}
private:
using diff_t = typename std::forward_list<T, Allocator>::difference_type;
static void resizeImpl(std::forward_list<T, Allocator>& container,
size_t size,
std::true_type)
{
container.resize(size);
}
static void resizeImpl(std::forward_list<T, Allocator>& container,
size_t newSize,
std::false_type)
{
const auto oldSize = size(container);
for (auto it = oldSize; it < newSize; ++it) {
container.push_front(::bitsery::Access::create<TValue>());
}
if (oldSize > newSize) {
// erase_after must have atleast one element to work
if (newSize > 0)
container.erase_after(
std::next(std::begin(container), static_cast<diff_t>(newSize - 1)));
else
container.clear();
}
}
};
}
}
#endif //BITSERY_TRAITS_STD_FORWARD_LIST_H
#endif // BITSERY_TRAITS_STD_FORWARD_LIST_H

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_TRAITS_STD_LIST_H
#define BITSERY_TRAITS_STD_LIST_H
@@ -29,14 +28,15 @@
namespace bitsery {
namespace traits {
namespace traits {
template<typename T, typename Allocator>
struct ContainerTraits<std::list<T, Allocator>>
: public StdContainer<std::list<T, Allocator>, true, false> {};
}
template<typename T, typename Allocator>
struct ContainerTraits<std::list<T, Allocator>>
: public StdContainer<std::list<T, Allocator>, true, false>
{};
}
#endif //BITSERY_TRAITS_STD_LIST_H
}
#endif // BITSERY_TRAITS_STD_LIST_H

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_TRAITS_STD_STRING_H
#define BITSERY_TRAITS_STD_STRING_H
@@ -29,43 +28,53 @@
namespace bitsery {
namespace traits {
namespace traits {
// specialization for string, because string is already included for std::char_traits
// specialization for string, because string is already included for
// std::char_traits
template<typename CharT, typename Traits, typename Allocator>
struct ContainerTraits<std::basic_string<CharT, Traits, Allocator>>
:public StdContainer<std::basic_string<CharT, Traits, Allocator>, true, true> {};
template<typename CharT, typename Traits, typename Allocator>
struct ContainerTraits<std::basic_string<CharT, Traits, Allocator>>
: public StdContainer<std::basic_string<CharT, Traits, Allocator>, true, true>
{};
template <typename CharT, typename Traits, typename Allocator>
struct TextTraits<std::basic_string<CharT, Traits, Allocator>> {
using TValue = typename ContainerTraits<std::basic_string<CharT, Traits, Allocator>>::TValue;
//string is automatically null-terminated
static constexpr bool addNUL = false;
template<typename CharT, typename Traits, typename Allocator>
struct TextTraits<std::basic_string<CharT, Traits, Allocator>>
{
using TValue = typename ContainerTraits<
std::basic_string<CharT, Traits, Allocator>>::TValue;
// string is automatically null-terminated
static constexpr bool addNUL = false;
//is is not 100% accurate, but for performance reasons assume that string stores text, not binary data
static size_t length(const std::basic_string<CharT, Traits, Allocator>& str) {
return str.size();
}
};
// is is not 100% accurate, but for performance reasons assume that string
// stores text, not binary data
static size_t length(const std::basic_string<CharT, Traits, Allocator>& str)
{
return str.size();
}
};
//specialization for c-array
template <typename T, size_t N>
struct TextTraits<T[N]> {
using TValue = T;
static constexpr bool addNUL = true;
// specialization for c-array
template<typename T, size_t N>
struct TextTraits<T[N]>
{
using TValue = T;
static constexpr bool addNUL = true;
static size_t length(const T (&container)[N]) {
return std::char_traits<T>::length(container);
}
};
static size_t length(const T (&container)[N])
{
return std::char_traits<T>::length(container);
}
};
template<typename CharT, typename Traits, typename Allocator>
struct BufferAdapterTraits<std::basic_string<CharT, Traits, Allocator>>
:public StdContainerForBufferAdapter<std::basic_string<CharT, Traits, Allocator>> {};
}
template<typename CharT, typename Traits, typename Allocator>
struct BufferAdapterTraits<std::basic_string<CharT, Traits, Allocator>>
: public StdContainerForBufferAdapter<
std::basic_string<CharT, Traits, Allocator>>
{};
}
#endif //BITSERY_TRAITS_VECTOR_H
}
#endif // BITSERY_TRAITS_VECTOR_H

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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_TRAITS_STD_VECTOR_H
#define BITSERY_TRAITS_STD_VECTOR_H
@@ -29,22 +28,25 @@
namespace bitsery {
namespace traits {
template<typename T, typename Allocator>
struct ContainerTraits<std::vector<T, Allocator>>
:public StdContainer<std::vector<T, Allocator>, true, true> {};
namespace traits {
template<typename T, typename Allocator>
struct ContainerTraits<std::vector<T, Allocator>>
: public StdContainer<std::vector<T, Allocator>, true, true>
{};
//bool vector is not contiguous, do not copy it directly to buffer
template<typename Allocator>
struct ContainerTraits<std::vector<bool, Allocator>>
:public StdContainer<std::vector<bool, Allocator>, true, false> {};
// bool vector is not contiguous, do not copy it directly to buffer
template<typename Allocator>
struct ContainerTraits<std::vector<bool, Allocator>>
: public StdContainer<std::vector<bool, Allocator>, true, false>
{};
template<typename T, typename Allocator>
struct BufferAdapterTraits<std::vector<T, Allocator>>
:public StdContainerForBufferAdapter<std::vector<T, Allocator>> {};
}
template<typename T, typename Allocator>
struct BufferAdapterTraits<std::vector<T, Allocator>>
: public StdContainerForBufferAdapter<std::vector<T, Allocator>>
{};
}
#endif //BITSERY_TRAITS_STD_VECTOR_H
}
#endif // BITSERY_TRAITS_STD_VECTOR_H

View File

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

View File

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

View File

@@ -14,6 +14,6 @@ configure_file(CTestConfig.cmake ${CTEST_SOURCE_DIRECTORY}/CTestConfig.cmake)
ctest_start("Continuous")
ctest_configure(OPTIONS "-DBITSERY_BUILD_EXAMPLES=OFF;-DBITSERY_BUILD_TESTS=ON")
ctest_build()
ctest_test(BUILD ${CTEST_BINARY_DIRECTORY}/tests)
ctest_test()
ctest_coverage()
#ctest_submit()

0
scripts/show_coverage.sh Normal file → Executable file
View File

View File

@@ -20,7 +20,7 @@
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#SOFTWARE.
cmake_minimum_required(VERSION 3.11)
cmake_minimum_required(VERSION 3.25)
project(bitsery_tests
LANGUAGES CXX)
@@ -32,8 +32,6 @@ endif()
file(GLOB TestSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
enable_testing()
foreach (TestFile ${TestSourceFiles})
get_filename_component(TestName ${TestFile} NAME_WE)
set(TestName bitsery.test.${TestName})

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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.
#include <bitsery/brief_syntax.h>
#include <bitsery/brief_syntax/array.h>
@@ -29,6 +29,7 @@
#include <bitsery/brief_syntax/list.h>
#include <bitsery/brief_syntax/map.h>
#include <bitsery/brief_syntax/memory.h>
#include <bitsery/brief_syntax/queue.h>
#include <bitsery/brief_syntax/set.h>
#include <bitsery/brief_syntax/stack.h>
@@ -37,424 +38,487 @@
#include <bitsery/brief_syntax/unordered_set.h>
#include <bitsery/brief_syntax/vector.h>
#if __cplusplus > 201402L
#include <bitsery/brief_syntax/optional.h>
#include <bitsery/brief_syntax/tuple.h>
#include <bitsery/brief_syntax/variant.h>
#if __cplusplus > 202002L
#include <bitsery/brief_syntax/bitset.h>
#endif
#elif defined(_MSC_VER)
#pragma message("C++17 and /Zc:__cplusplus option is required to enable std::tuple and std::variant brief syntax tests")
#pragma message( \
"C++17 and /Zc:__cplusplus option is required to enable std::tuple and std::variant brief syntax tests")
#else
#pragma message("C++17 is required to enable std::tuple and std::variant brief syntax tests")
#pragma message( \
"C++17 is required to enable std::tuple and std::variant brief syntax tests")
#endif
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
#include <atomic>
#include <utility>
using testing::Eq;
TEST(BriefSyntax, FundamentalTypesAndBool) {
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double td = -454184.48445;
bool tb = true;
SerializationContext ctx{};
ctx.createSerializer()(ti, te, tf, td, tb);
TEST(BriefSyntax, FundamentalTypesAndBool)
{
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double td = -454184.48445;
bool tb = true;
SerializationContext ctx{};
ctx.createSerializer()(ti, te, tf, td, tb);
//result
int ri{};
MyEnumClass re{};
float rf{};
double rd{};
bool rb{};
ctx.createDeserializer()(ri, re, rf, rd, rb);
// result
int ri{};
MyEnumClass re{};
float rf{};
double rd{};
bool rb{};
ctx.createDeserializer()(ri, re, rf, rd, rb);
//test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
// test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
}
TEST(BriefSyntax, UseObjectFncInsteadOfValueN) {
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double td = -454184.48445;
bool tb = true;
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.object(ti);
ser.object(te);
ser.object(tf);
ser.object(td);
ser.object(tb);
TEST(BriefSyntax, UseObjectFncInsteadOfValueN)
{
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double td = -454184.48445;
bool tb = true;
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.object(ti);
ser.object(te);
ser.object(tf);
ser.object(td);
ser.object(tb);
//result
int ri{};
MyEnumClass re{};
float rf{};
double rd{};
bool rb{};
auto& des = ctx.createDeserializer();
des.object(ri);
des.object(re);
des.object(rf);
des.object(rd);
des.object(rb);
// result
int ri{};
MyEnumClass re{};
float rf{};
double rd{};
bool rb{};
auto& des = ctx.createDeserializer();
des.object(ri);
des.object(re);
des.object(rf);
des.object(rd);
des.object(rb);
//test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
// test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
}
TEST(BriefSyntax, MixDifferentSyntax) {
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double td = -454184.48445;
bool tb = true;
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.value<sizeof(ti)>(ti);
ser(te, tf, td);
ser.object(tb);
TEST(BriefSyntax, MixDifferentSyntax)
{
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double td = -454184.48445;
bool tb = true;
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.value<sizeof(ti)>(ti);
ser(te, tf, td);
ser.object(tb);
//result
int ri{};
MyEnumClass re{};
float rf{};
double rd{};
bool rb{};
auto& des = ctx.createDeserializer();
des(ri, re, rf);
des.value8b(rd);
des.object(rb);
// result
int ri{};
MyEnumClass re{};
float rf{};
double rd{};
bool rb{};
auto& des = ctx.createDeserializer();
des(ri, re, rf);
des.value8b(rd);
des.object(rb);
//test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
// test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
}
template<typename T>
T procBriefSyntax(const T& testData) {
SerializationContext ctx;
ctx.createSerializer()(testData);
T res{};
ctx.createDeserializer()(res);
return res;
T
procBriefSyntax(const T& testData)
{
SerializationContext ctx;
ctx.createSerializer()(testData);
T res{};
ctx.createDeserializer()(res);
return res;
}
template<typename T>
T&& procBriefSyntaxRvalue(T&& init_value, const T& testData) {
SerializationContext ctx;
ctx.createSerializer()(testData);
ctx.createDeserializer()(init_value);
return std::move(init_value);
T&&
procBriefSyntaxRvalue(T&& init_value, const T& testData)
{
SerializationContext ctx;
ctx.createSerializer()(testData);
ctx.createDeserializer()(init_value);
return std::move(init_value);
}
template<typename T>
T procBriefSyntaxWithMaxSize(const T& testData) {
SerializationContext ctx;
ctx.createSerializer()(bitsery::maxSize(testData, 100));
T res{};
ctx.createDeserializer()(bitsery::maxSize(res, 100));
return res;
T
procBriefSyntaxWithMaxSize(const T& testData)
{
SerializationContext ctx;
ctx.createSerializer()(bitsery::maxSize(testData, 100));
T res{};
ctx.createDeserializer()(bitsery::maxSize(res, 100));
return res;
}
TEST(BriefSyntax, CStyleArrayForValueTypesAsContainer) {
const int t1[3]{8748, -484, 45};
int r1[3]{0, 0, 0};
TEST(BriefSyntax, CStyleArrayForValueTypesAsContainer)
{
const int t1[3]{ 8748, -484, 45 };
int r1[3]{ 0, 0, 0 };
SerializationContext ctx;
ctx.createSerializer()(bitsery::asContainer(t1));
ctx.createDeserializer()(bitsery::asContainer(r1));
SerializationContext ctx;
ctx.createSerializer()(bitsery::asContainer(t1));
ctx.createDeserializer()(bitsery::asContainer(r1));
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
}
TEST(BriefSyntax, CStyleArrayForIntegralTypesAsText) {
const char t1[3]{"hi"};
char r1[3]{0, 0, 0};
TEST(BriefSyntax, CStyleArrayForIntegralTypesAsText)
{
const char t1[3]{ "hi" };
char r1[3]{ 0, 0, 0 };
SerializationContext ctx;
ctx.createSerializer()(bitsery::asText(t1));
ctx.createDeserializer()(bitsery::asText(r1));
SerializationContext ctx;
ctx.createSerializer()(bitsery::asText(t1));
ctx.createDeserializer()(bitsery::asText(r1));
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
}
TEST(BriefSyntax, CStyleArray) {
const MyEnumClass t1[3]{MyEnumClass::E1, MyEnumClass::E4, MyEnumClass::E2};
MyEnumClass r1[3]{};
TEST(BriefSyntax, CStyleArray)
{
const MyEnumClass t1[3]{ MyEnumClass::E1, MyEnumClass::E4, MyEnumClass::E2 };
MyEnumClass r1[3]{};
SerializationContext ctx;
ctx.createSerializer()(t1);
ctx.createDeserializer()(r1);
SerializationContext ctx;
ctx.createSerializer()(t1);
ctx.createDeserializer()(r1);
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
}
TEST(BriefSyntax, StdString) {
std::string t1{"my nice string"};
std::string t2{};
TEST(BriefSyntax, StdString)
{
std::string t1{ "my nice string" };
std::string t2{};
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
}
TEST(BriefSyntax, StdArray) {
std::array<int, 3> t1{8748, -484, 45};
std::array<int, 0> t2{};
TEST(BriefSyntax, StdArray)
{
std::array<int, 3> t1{ 8748, -484, 45 };
std::array<int, 0> t2{};
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
}
TEST(BriefSyntax, StdVector) {
std::vector<int> t1{8748, -484, 45};
std::vector<float> t2{5.f, 0.198f};
TEST(BriefSyntax, StdVector)
{
std::vector<int> t1{ 8748, -484, 45 };
std::vector<float> t2{ 5.f, 0.198f };
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
}
TEST(BriefSyntax, StdList) {
std::list<int> t1{8748, -484, 45};
std::list<float> t2{5.f, 0.198f};
TEST(BriefSyntax, StdList)
{
std::list<int> t1{ 8748, -484, 45 };
std::list<float> t2{ 5.f, 0.198f };
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
}
TEST(BriefSyntax, StdForwardList) {
std::forward_list<int> t1{8748, -484, 45};
std::forward_list<float> t2{5.f, 0.198f};
TEST(BriefSyntax, StdForwardList)
{
std::forward_list<int> t1{ 8748, -484, 45 };
std::forward_list<float> t2{ 5.f, 0.198f };
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
}
TEST(BriefSyntax, StdDeque) {
std::deque<int> t1{8748, -484, 45};
std::deque<float> t2{5.f, 0.198f};
TEST(BriefSyntax, StdDeque)
{
std::deque<int> t1{ 8748, -484, 45 };
std::deque<float> t2{ 5.f, 0.198f };
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
}
TEST(BriefSyntax, StdQueue) {
std::queue<std::string> t1;
t1.push("first");
t1.push("second string");
TEST(BriefSyntax, StdQueue)
{
std::queue<std::string> t1;
t1.push("first");
t1.push("second string");
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
}
TEST(BriefSyntax, StdPriorityQueue) {
std::priority_queue<std::string> t1;
t1.push("first");
t1.push("second string");
t1.push("third");
t1.push("fourth");
auto r1 = procBriefSyntax(t1);
//we cannot compare priority queue directly
TEST(BriefSyntax, StdPriorityQueue)
{
std::priority_queue<std::string> t1;
t1.push("first");
t1.push("second string");
t1.push("third");
t1.push("fourth");
auto r1 = procBriefSyntax(t1);
// we cannot compare priority queue directly
EXPECT_THAT(r1.size(), Eq(t1.size()));
for (auto i = 0u; i < r1.size(); ++i) {
EXPECT_THAT(r1.top(), Eq(t1.top()));
r1.pop();
t1.pop();
}
EXPECT_THAT(r1.size(), Eq(t1.size()));
for (auto i = 0u; i < r1.size(); ++i) {
EXPECT_THAT(r1.top(), Eq(t1.top()));
r1.pop();
t1.pop();
}
}
TEST(BriefSyntax, StdStack) {
std::stack<std::string> t1;
t1.push("first");
t1.push("second string");
TEST(BriefSyntax, StdStack)
{
std::stack<std::string> t1;
t1.push("first");
t1.push("second string");
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
}
TEST(BriefSyntax, StdUnorderedMap) {
std::unordered_map<int, int> t1;
t1.emplace(3423, 624);
t1.emplace(-5484, -845);
TEST(BriefSyntax, StdUnorderedMap)
{
std::unordered_map<int, int> t1;
t1.emplace(3423, 624);
t1.emplace(-5484, -845);
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
}
TEST(BriefSyntax, StdUnorderedMultiMap) {
std::unordered_multimap<std::string, int> t1;
t1.emplace("one", 624);
t1.emplace("two", -845);
t1.emplace("one", 897);
TEST(BriefSyntax, StdUnorderedMultiMap)
{
std::unordered_multimap<std::string, int> t1;
t1.emplace("one", 624);
t1.emplace("two", -845);
t1.emplace("one", 897);
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
}
TEST(BriefSyntax, StdMap) {
std::map<int, int> t1;
t1.emplace(3423, 624);
t1.emplace(-5484, -845);
TEST(BriefSyntax, StdMap)
{
std::map<int, int> t1;
t1.emplace(3423, 624);
t1.emplace(-5484, -845);
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
}
TEST(BriefSyntax, StdMultiMap) {
std::multimap<std::string, int> t1;
t1.emplace("one", 624);
t1.emplace("two", -845);
t1.emplace("one", 897);
TEST(BriefSyntax, StdMultiMap)
{
std::multimap<std::string, int> t1;
t1.emplace("one", 624);
t1.emplace("two", -845);
t1.emplace("one", 897);
auto res = procBriefSyntax(t1);
//same key values is not ordered, and operator == compares each element at same position
//so we need to compare our selves
EXPECT_THAT(res.size(), Eq(3));
for (auto it = t1.begin(); it != t1.end();) {
const auto lr = t1.equal_range(it->first);
const auto rr = res.equal_range(it->first);
EXPECT_TRUE(std::distance(lr.first, lr.second) == std::distance(rr.first, rr.second));
EXPECT_TRUE(std::is_permutation(lr.first, lr.second, rr.first));
it = lr.second;
}
auto res = procBriefSyntax(t1);
// same key values is not ordered, and operator == compares each element at
// same position so we need to compare our selves
EXPECT_THAT(res.size(), Eq(3));
for (auto it = t1.begin(); it != t1.end();) {
const auto lr = t1.equal_range(it->first);
const auto rr = res.equal_range(it->first);
EXPECT_TRUE(std::distance(lr.first, lr.second) ==
std::distance(rr.first, rr.second));
EXPECT_TRUE(std::is_permutation(lr.first, lr.second, rr.first));
it = lr.second;
}
}
TEST(BriefSyntax, StdUnorderedSet) {
std::unordered_set<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
TEST(BriefSyntax, StdUnorderedSet)
{
std::unordered_set<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
}
TEST(BriefSyntax, StdUnorderedMultiSet) {
std::unordered_multiset<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
t1.emplace("one");
TEST(BriefSyntax, StdUnorderedMultiSet)
{
std::unordered_multiset<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
t1.emplace("one");
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
}
TEST(BriefSyntax, StdSet) {
std::set<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
TEST(BriefSyntax, StdSet)
{
std::set<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
}
TEST(BriefSyntax, StdMultiSet) {
std::multiset<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
t1.emplace("one");
t1.emplace("two");
TEST(BriefSyntax, StdMultiSet)
{
std::multiset<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
t1.emplace("one");
t1.emplace("two");
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
}
TEST(BriefSyntax, StdSmartPtr) {
std::shared_ptr<int> dataShared1(new int{4});
std::weak_ptr<int> dataWeak1(dataShared1);
std::unique_ptr<std::string> dataUnique1{new std::string{"hello world"}};
TEST(BriefSyntax, StdSmartPtr)
{
std::shared_ptr<int> dataShared1(new int{ 4 });
std::weak_ptr<int> dataWeak1(dataShared1);
std::unique_ptr<std::string> dataUnique1{ new std::string{ "hello world" } };
bitsery::ext::PointerLinkingContext plctx1{};
BasicSerializationContext<bitsery::ext::PointerLinkingContext> ctx;
ctx.createSerializer(plctx1)(dataShared1, dataWeak1, dataUnique1);
bitsery::ext::PointerLinkingContext plctx1{};
BasicSerializationContext<bitsery::ext::PointerLinkingContext> ctx;
ctx.createSerializer(plctx1)(dataShared1, dataWeak1, dataUnique1);
std::shared_ptr<int> resShared1{};
std::weak_ptr<int> resWeak1{};
std::unique_ptr<std::string> resUnique1{};
ctx.createDeserializer(plctx1)(resShared1, resWeak1, resUnique1);
//clear shared state from pointer linking context
plctx1.clearSharedState();
std::shared_ptr<int> resShared1{};
std::weak_ptr<int> resWeak1{};
std::unique_ptr<std::string> resUnique1{};
ctx.createDeserializer(plctx1)(resShared1, resWeak1, resUnique1);
// clear shared state from pointer linking context
plctx1.clearSharedState();
EXPECT_TRUE(plctx1.isValid());
EXPECT_THAT(*resShared1, Eq(*dataShared1));
EXPECT_THAT(*resWeak1.lock(), Eq(*dataWeak1.lock()));
EXPECT_THAT(*resUnique1, Eq(*dataUnique1));
EXPECT_TRUE(plctx1.isValid());
EXPECT_THAT(*resShared1, Eq(*dataShared1));
EXPECT_THAT(*resWeak1.lock(), Eq(*dataWeak1.lock()));
EXPECT_THAT(*resUnique1, Eq(*dataUnique1));
}
TEST(BriefSyntax, StdDuration) {
std::chrono::duration<int64_t, std::milli> t1{54654};
EXPECT_TRUE(procBriefSyntax(t1) == t1);
TEST(BriefSyntax, StdDuration)
{
std::chrono::duration<int64_t, std::milli> t1{ 54654 };
EXPECT_TRUE(procBriefSyntax(t1) == t1);
}
TEST(BriefSyntax, StdTimePoint) {
using Duration = std::chrono::duration<double, std::milli>;
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
TEST(BriefSyntax, StdTimePoint)
{
using Duration = std::chrono::duration<double, std::milli>;
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
TP data{Duration{874656.4798}};
EXPECT_TRUE(procBriefSyntax(data) == data);
TP data{ Duration{ 874656.4798 } };
EXPECT_TRUE(procBriefSyntax(data) == data);
}
TEST(BriefSyntax, StdAtomic) {
std::atomic<int32_t> atm0{54654};
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<int32_t>{}, atm0) == atm0);
TEST(BriefSyntax, StdAtomic)
{
std::atomic<int32_t> atm0{ 54654 };
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<int32_t>{}, atm0) == atm0);
std::atomic<bool> atm1{false};
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm1) == atm1);
std::atomic<bool> atm1{ false };
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm1) == atm1);
std::atomic<bool> atm2{true};
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm2) == atm2);
std::atomic<bool> atm2{ true };
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm2) == atm2);
std::atomic<uint16_t> atm3;
atm3.store(0x1337);
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<uint16_t>{}, atm3).load() == 0x1337);
std::atomic<uint16_t> atm3;
atm3.store(0x1337);
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<uint16_t>{}, atm3).load() ==
0x1337);
}
#if __cplusplus > 201402L
TEST(BriefSyntax, StdTuple) {
std::tuple<int, std::string, std::vector<char>> t1{5,"hello hello", {'A','B','C'}};
EXPECT_TRUE(procBriefSyntax(t1) == t1);
TEST(BriefSyntax, StdTuple)
{
std::tuple<int, std::string, std::vector<char>> t1{ 5,
"hello hello",
{ 'A', 'B', 'C' } };
EXPECT_TRUE(procBriefSyntax(t1) == t1);
}
TEST(BriefSyntax, StdVariant) {
std::variant<float, std::string, std::chrono::milliseconds> t1{std::string("hello hello")};
EXPECT_TRUE(procBriefSyntax(t1) == t1);
TEST(BriefSyntax, StdVariant)
{
std::variant<float, std::string, std::chrono::milliseconds> t1{ std::string(
"hello hello") };
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
TEST(BriefSyntax, NestedTypes) {
std::unordered_map<std::string, std::vector<std::string>> t1;
t1.emplace("my key", std::vector<std::string>{"very", "nice", "string"});
t1.emplace("other key", std::vector<std::string>{"just a string"});
#endif
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
TEST(BriefSyntax, NestedTypes)
{
std::unordered_map<std::string, std::vector<std::string>> t1;
t1.emplace("my key", std::vector<std::string>{ "very", "nice", "string" });
t1.emplace("other key", std::vector<std::string>{ "just a string" });
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
}

View File

@@ -1,184 +1,195 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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.
#include "serialization_test_utils.h"
#include <bitsery/deserializer.h>
#include <bitsery/ext/value_range.h>
#include <bitsery/serializer.h>
#include <bitsery/deserializer.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::Eq;
using testing::ContainerEq;
using bitsery::EndiannessType;
using bitsery::DefaultConfig;
using bitsery::EndiannessType;
using testing::ContainerEq;
using testing::Eq;
constexpr EndiannessType getInverseEndianness(EndiannessType e) {
return e == EndiannessType::LittleEndian
? EndiannessType::BigEndian
: EndiannessType::LittleEndian;
constexpr EndiannessType
getInverseEndianness(EndiannessType e)
{
return e == EndiannessType::LittleEndian ? EndiannessType::BigEndian
: EndiannessType::LittleEndian;
}
struct InverseEndiannessConfig {
static constexpr bitsery::EndiannessType Endianness = getInverseEndianness(DefaultConfig::Endianness);
static constexpr bool CheckDataErrors = true;
static constexpr bool CheckAdapterErrors = true;
struct InverseEndiannessConfig
{
static constexpr bitsery::EndiannessType Endianness =
getInverseEndianness(DefaultConfig::Endianness);
static constexpr bool CheckDataErrors = true;
static constexpr bool CheckAdapterErrors = true;
};
struct IntegralTypes {
int64_t a;
uint32_t b;
int16_t c;
uint8_t d;
int8_t e;
struct IntegralTypes
{
int64_t a;
uint32_t b;
int16_t c;
uint8_t d;
int8_t e;
};
using InverseReader = bitsery::InputBufferAdapter<Buffer, InverseEndiannessConfig>;
using InverseReader =
bitsery::InputBufferAdapter<Buffer, InverseEndiannessConfig>;
TEST(DataEndianness, WhenWriteBytesThenBytesAreSwapped)
{
// fill initial values
IntegralTypes src{};
src.a = static_cast<int64_t>(0x1122334455667788u);
src.b = 0xBBCCDDEEu;
src.c = static_cast<int16_t>(0xCCDDu);
src.d = static_cast<uint8_t>(0xDDu);
src.e = static_cast<int8_t>(0xEEu);
TEST(DataEndianness, WhenWriteBytesThenBytesAreSwapped) {
//fill initial values
IntegralTypes src{};
src.a = static_cast<int64_t>(0x1122334455667788u);
src.b = 0xBBCCDDEEu;
src.c = static_cast<int16_t>(0xCCDDu);
src.d = static_cast<uint8_t>(0xDDu);
src.e = static_cast<int8_t>(0xEEu);
// fill expected result after swap
IntegralTypes resInv{};
resInv.a = static_cast<int64_t>(0x8877665544332211u);
resInv.b = 0xEEDDCCBBu;
resInv.c = static_cast<int16_t>(0xDDCCu);
resInv.d = static_cast<uint8_t>(0xDDu);
resInv.e = static_cast<int8_t>(0xEEu);
//fill expected result after swap
IntegralTypes resInv{};
resInv.a = static_cast<int64_t>(0x8877665544332211u);
resInv.b = 0xEEDDCCBBu;
resInv.c = static_cast<int16_t>(0xDDCCu);
resInv.d = static_cast<uint8_t>(0xDDu);
resInv.e = static_cast<int8_t>(0xEEu);
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBytes<8>(src.a);
bw.writeBytes<4>(src.b);
bw.writeBytes<2>(src.c);
bw.writeBytes<1>(src.d);
bw.writeBytes<1>(src.e);
bw.flush();
//read from buffer using inverse endianness config
InverseReader br{buf.begin(), bw.writtenBytesCount()};
IntegralTypes res{};
br.readBytes<8>(res.a);
br.readBytes<4>(res.b);
br.readBytes<2>(res.c);
br.readBytes<1>(res.d);
br.readBytes<1>(res.e);
//check results
EXPECT_THAT(res.a, Eq(resInv.a));
EXPECT_THAT(res.b, Eq(resInv.b));
EXPECT_THAT(res.c, Eq(resInv.c));
EXPECT_THAT(res.d, Eq(resInv.d));
EXPECT_THAT(res.e, Eq(resInv.e));
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
bw.writeBytes<8>(src.a);
bw.writeBytes<4>(src.b);
bw.writeBytes<2>(src.c);
bw.writeBytes<1>(src.d);
bw.writeBytes<1>(src.e);
bw.flush();
// read from buffer using inverse endianness config
InverseReader br{ buf.begin(), bw.writtenBytesCount() };
IntegralTypes res{};
br.readBytes<8>(res.a);
br.readBytes<4>(res.b);
br.readBytes<2>(res.c);
br.readBytes<1>(res.d);
br.readBytes<1>(res.e);
// check results
EXPECT_THAT(res.a, Eq(resInv.a));
EXPECT_THAT(res.b, Eq(resInv.b));
EXPECT_THAT(res.c, Eq(resInv.c));
EXPECT_THAT(res.d, Eq(resInv.d));
EXPECT_THAT(res.e, Eq(resInv.e));
}
TEST(DataEndianness, WhenWrite1ByteValuesThenEndiannessIsIgnored) {
//fill initial values
constexpr size_t SIZE = 4;
uint8_t src[SIZE] = {0xAA, 0xBB, 0xCC, 0xDD};
uint8_t res[SIZE] = {};
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBuffer<1>(src, SIZE);
bw.flush();
//read from buffer using inverse endianness config
InverseReader br{buf.begin(), bw.writtenBytesCount()};
br.readBuffer<1>(res, SIZE);
//result is identical, because we write separate values, of size 1byte, that requires no swapping
//check results
EXPECT_THAT(res, ContainerEq(src));
TEST(DataEndianness, WhenWrite1ByteValuesThenEndiannessIsIgnored)
{
// fill initial values
constexpr size_t SIZE = 4;
uint8_t src[SIZE] = { 0xAA, 0xBB, 0xCC, 0xDD };
uint8_t res[SIZE] = {};
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
bw.writeBuffer<1>(src, SIZE);
bw.flush();
// read from buffer using inverse endianness config
InverseReader br{ buf.begin(), bw.writtenBytesCount() };
br.readBuffer<1>(res, SIZE);
// result is identical, because we write separate values, of size 1byte, that
// requires no swapping check results
EXPECT_THAT(res, ContainerEq(src));
}
TEST(DataEndianness, WhenWriteMoreThan1ByteValuesThenValuesAreSwapped) {
//fill initial values
constexpr size_t SIZE = 4;
uint16_t src[SIZE] = {0xAA00, 0xBB11, 0xCC22, 0xDD33};
uint16_t resInv[SIZE] = {0x00AA, 0x11BB, 0x22CC, 0x33DD};
uint16_t res[SIZE] = {};
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBuffer<2>(src, SIZE);
bw.flush();
//read from buffer using inverse endianness config
InverseReader br{buf.begin(), bw.writtenBytesCount()};
br.readBuffer<2>(res, SIZE);
//result is identical, because we write separate values, of size 1byte, that requires no swapping
//check results
EXPECT_THAT(res, ContainerEq(resInv));
TEST(DataEndianness, WhenWriteMoreThan1ByteValuesThenValuesAreSwapped)
{
// fill initial values
constexpr size_t SIZE = 4;
uint16_t src[SIZE] = { 0xAA00, 0xBB11, 0xCC22, 0xDD33 };
uint16_t resInv[SIZE] = { 0x00AA, 0x11BB, 0x22CC, 0x33DD };
uint16_t res[SIZE] = {};
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
bw.writeBuffer<2>(src, SIZE);
bw.flush();
// read from buffer using inverse endianness config
InverseReader br{ buf.begin(), bw.writtenBytesCount() };
br.readBuffer<2>(res, SIZE);
// result is identical, because we write separate values, of size 1byte, that
// requires no swapping check results
EXPECT_THAT(res, ContainerEq(resInv));
}
template <typename T>
constexpr size_t getBits(T v) {
return bitsery::details::calcRequiredBits<T>({}, v);
template<typename T>
constexpr size_t
getBits(T v)
{
return bitsery::details::calcRequiredBits<T>({}, v);
}
struct IntegralUnsignedTypes {
uint64_t a;
uint32_t b;
uint16_t c;
uint8_t d;
struct IntegralUnsignedTypes
{
uint64_t a;
uint32_t b;
uint16_t c;
uint8_t d;
};
TEST(DataEndianness, WhenValueTypeIs1ByteThenBitOperationsIsNotAffectedByEndianness) {
//fill initial values
constexpr IntegralUnsignedTypes src {
0x0000334455667788,
0x00CCDDEE,
0x00DD,
0x0F,
};
TEST(DataEndianness,
WhenValueTypeIs1ByteThenBitOperationsIsNotAffectedByEndianness)
{
// fill initial values
constexpr IntegralUnsignedTypes src{
0x0000334455667788,
0x00CCDDEE,
0x00DD,
0x0F,
};
constexpr size_t aBITS = getBits(src.a) + 8;
constexpr size_t bBITS = getBits(src.b) + 0;
constexpr size_t cBITS = getBits(src.c) + 5;
constexpr size_t dBITS = getBits(src.d) + 2;
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bitsery::details::OutputAdapterBitPackingWrapper<Writer> bpw{bw};
bpw.writeBits(src.a, aBITS);
bpw.writeBits(src.b, bBITS);
bpw.writeBits(src.c, cBITS);
bpw.writeBits(src.d, dBITS);
bpw.flush();
//read from buffer using inverse endianness config
InverseReader br{buf.begin(), bpw.writtenBytesCount()};
bitsery::details::InputAdapterBitPackingWrapper<InverseReader> bpr{br};
IntegralUnsignedTypes res{};
bpr.readBits(res.a, aBITS);
bpr.readBits(res.b, bBITS);
bpr.readBits(res.c, cBITS);
bpr.readBits(res.d, dBITS);
//check results
EXPECT_THAT(res.a, Eq(src.a));
EXPECT_THAT(res.b, Eq(src.b));
EXPECT_THAT(res.c, Eq(src.c));
EXPECT_THAT(res.d, Eq(src.d));
constexpr size_t aBITS = getBits(src.a) + 8;
constexpr size_t bBITS = getBits(src.b) + 0;
constexpr size_t cBITS = getBits(src.c) + 5;
constexpr size_t dBITS = getBits(src.d) + 2;
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
bitsery::details::OutputAdapterBitPackingWrapper<Writer> bpw{ bw };
bpw.writeBits(src.a, aBITS);
bpw.writeBits(src.b, bBITS);
bpw.writeBits(src.c, cBITS);
bpw.writeBits(src.d, dBITS);
bpw.flush();
// read from buffer using inverse endianness config
InverseReader br{ buf.begin(), bpw.writtenBytesCount() };
bitsery::details::InputAdapterBitPackingWrapper<InverseReader> bpr{ br };
IntegralUnsignedTypes res{};
bpr.readBits(res.a, aBITS);
bpr.readBits(res.b, bBITS);
bpr.readBits(res.c, cBITS);
bpr.readBits(res.d, dBITS);
// check results
EXPECT_THAT(res.a, Eq(src.a));
EXPECT_THAT(res.b, Eq(src.b));
EXPECT_THAT(res.c, Eq(src.c));
EXPECT_THAT(res.d, Eq(src.d));
}

View File

@@ -1,410 +1,419 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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.
#include "serialization_test_utils.h"
#include <bitsery/deserializer.h>
#include <bitsery/ext/value_range.h>
#include <bitsery/serializer.h>
#include <bitsery/deserializer.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
using testing::Eq;
using testing::ContainerEq;
using testing::Eq;
using AdapterBitPackingWriter = bitsery::details::OutputAdapterBitPackingWrapper<Writer>;
using AdapterBitPackingReader = bitsery::details::InputAdapterBitPackingWrapper<Reader>;
using AdapterBitPackingWriter =
bitsery::details::OutputAdapterBitPackingWrapper<Writer>;
using AdapterBitPackingReader =
bitsery::details::InputAdapterBitPackingWrapper<Reader>;
struct IntegralUnsignedTypes {
uint32_t a;
uint16_t b;
uint8_t c;
uint8_t d;
uint64_t e;
struct IntegralUnsignedTypes
{
uint32_t a;
uint16_t b;
uint8_t c;
uint8_t d;
uint64_t e;
};
template <typename T>
constexpr size_t getBits(T v) {
return bitsery::details::calcRequiredBits<T>({}, v);
template<typename T>
constexpr size_t
getBits(T v)
{
return bitsery::details::calcRequiredBits<T>({}, v);
}
// *** bits operations
TEST(DataBitsAndBytesOperations, WriteAndReadBitsMaxTypeValues) {
Buffer buf;
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
bpw.writeBits(std::numeric_limits<uint64_t>::max(), 64);
bpw.writeBits(std::numeric_limits<uint32_t>::max(), 32);
bpw.writeBits(std::numeric_limits<uint16_t>::max(), 16);
bpw.writeBits(std::numeric_limits<uint8_t>::max(), 8);
bpw.flush();
TEST(DataBitsAndBytesOperations, WriteAndReadBitsMaxTypeValues)
{
Buffer buf;
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBits(std::numeric_limits<uint64_t>::max(), 64);
bpw.writeBits(std::numeric_limits<uint32_t>::max(), 32);
bpw.writeBits(std::numeric_limits<uint16_t>::max(), 16);
bpw.writeBits(std::numeric_limits<uint8_t>::max(), 8);
bpw.flush();
Reader br{buf.begin(), bpw.writtenBytesCount()};
AdapterBitPackingReader bpr{br};
uint64_t v64{};
uint32_t v32{};
uint16_t v16{};
uint8_t v8{};
bpr.readBits(v64, 64);
bpr.readBits(v32, 32);
bpr.readBits(v16, 16);
bpr.readBits(v8, 8);
Reader br{ buf.begin(), bpw.writtenBytesCount() };
AdapterBitPackingReader bpr{ br };
uint64_t v64{};
uint32_t v32{};
uint16_t v16{};
uint8_t v8{};
bpr.readBits(v64, 64);
bpr.readBits(v32, 32);
bpr.readBits(v16, 16);
bpr.readBits(v8, 8);
EXPECT_THAT(v64, Eq(std::numeric_limits<uint64_t>::max()));
EXPECT_THAT(v32, Eq(std::numeric_limits<uint32_t>::max()));
EXPECT_THAT(v16, Eq(std::numeric_limits<uint16_t>::max()));
EXPECT_THAT(v8, Eq(std::numeric_limits<uint8_t>::max()));
EXPECT_THAT(v64, Eq(std::numeric_limits<uint64_t>::max()));
EXPECT_THAT(v32, Eq(std::numeric_limits<uint32_t>::max()));
EXPECT_THAT(v16, Eq(std::numeric_limits<uint16_t>::max()));
EXPECT_THAT(v8, Eq(std::numeric_limits<uint8_t>::max()));
}
TEST(DataBitsAndBytesOperations, WriteAndReadBits) {
//setup data
constexpr IntegralUnsignedTypes data{
485454,//bits 19
45978,//bits 16
0,//bits 1
36,//bits 6
479845648946//bits 39
};
TEST(DataBitsAndBytesOperations, WriteAndReadBits)
{
// setup data
constexpr IntegralUnsignedTypes data{
485454, // bits 19
45978, // bits 16
0, // bits 1
36, // bits 6
479845648946 // bits 39
};
constexpr size_t aBITS = getBits(data.a) + 2;
constexpr size_t bBITS = getBits(data.b) + 0;
constexpr size_t cBITS = getBits(data.c) + 2;
constexpr size_t dBITS = getBits(data.d) + 1;
constexpr size_t eBITS = getBits(data.e) + 8;
constexpr size_t aBITS = getBits(data.a) + 2;
constexpr size_t bBITS = getBits(data.b) + 0;
constexpr size_t cBITS = getBits(data.c) + 2;
constexpr size_t dBITS = getBits(data.d) + 1;
constexpr size_t eBITS = getBits(data.e) + 8;
//create and write to buffer
Buffer buf;
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
// create and write to buffer
Buffer buf;
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBits(data.a, aBITS);
bpw.writeBits(data.b, bBITS);
bpw.writeBits(data.c, cBITS);
bpw.writeBits(data.d, dBITS);
bpw.writeBits(data.e, eBITS);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
auto bytesCount = ((aBITS + bBITS + cBITS + dBITS + eBITS) / 8) +1 ;
EXPECT_THAT(writtenSize, Eq(bytesCount));
//read from buffer
Reader br{buf.begin(), writtenSize};
AdapterBitPackingReader bpr{br};
bpw.writeBits(data.a, aBITS);
bpw.writeBits(data.b, bBITS);
bpw.writeBits(data.c, cBITS);
bpw.writeBits(data.d, dBITS);
bpw.writeBits(data.e, eBITS);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
auto bytesCount = ((aBITS + bBITS + cBITS + dBITS + eBITS) / 8) + 1;
EXPECT_THAT(writtenSize, Eq(bytesCount));
// read from buffer
Reader br{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr{ br };
IntegralUnsignedTypes res{};
IntegralUnsignedTypes res{};
bpr.readBits(res.a, aBITS);
bpr.readBits(res.b, bBITS);
bpr.readBits(res.c, cBITS);
bpr.readBits(res.d, dBITS);
bpr.readBits(res.e, eBITS);
EXPECT_THAT(res.a, Eq(data.a));
EXPECT_THAT(res.b, Eq(data.b));
EXPECT_THAT(res.c, Eq(data.c));
EXPECT_THAT(res.d, Eq(data.d));
EXPECT_THAT(res.e, Eq(data.e));
bpr.readBits(res.a, aBITS);
bpr.readBits(res.b, bBITS);
bpr.readBits(res.c, cBITS);
bpr.readBits(res.d, dBITS);
bpr.readBits(res.e, eBITS);
EXPECT_THAT(res.a, Eq(data.a));
EXPECT_THAT(res.b, Eq(data.b));
EXPECT_THAT(res.c, Eq(data.c));
EXPECT_THAT(res.d, Eq(data.d));
EXPECT_THAT(res.e, Eq(data.e));
}
TEST(DataBitsAndBytesOperations, WrittenSizeIsCountedPerByteNotPerBit) {
//setup data
TEST(DataBitsAndBytesOperations, WrittenSizeIsCountedPerByteNotPerBit)
{
// setup data
//create and write to buffer
Buffer buf;
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
// create and write to buffer
Buffer buf;
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBits(7u,3);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(1));
bpw.writeBits(7u, 3);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(1));
//read from buffer
Reader br{buf.begin(), writtenSize};
AdapterBitPackingReader bpr{br};
uint16_t tmp;
bpr.readBits(tmp,4);
bpr.readBits(tmp,2);
bpr.readBits(tmp,2);
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
bpr.readBits(tmp,2);
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::DataOverflow));//false
// read from buffer
Reader br{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr{ br };
uint16_t tmp;
bpr.readBits(tmp, 4);
bpr.readBits(tmp, 2);
bpr.readBits(tmp, 2);
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
bpr.readBits(tmp, 2);
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::DataOverflow)); // false
//part of next byte
Reader br1{buf.begin(), writtenSize};
AdapterBitPackingReader bpr1{br1};
bpr1.readBits(tmp,2);
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::NoError));
bpr1.readBits(tmp,7);
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::DataOverflow));//false
// part of next byte
Reader br1{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr1{ br1 };
bpr1.readBits(tmp, 2);
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::NoError));
bpr1.readBits(tmp, 7);
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::DataOverflow)); // false
//bigger than byte
Reader br2{buf.begin(), writtenSize};
AdapterBitPackingReader bpr2{br2};
bpr2.readBits(tmp,9);
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::DataOverflow));//false
// bigger than byte
Reader br2{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr2{ br2 };
bpr2.readBits(tmp, 9);
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::DataOverflow)); // false
}
TEST(DataBitsAndBytesOperations, ConsecutiveCallsToAlignHasNoEffect) {
Buffer buf;
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
TEST(DataBitsAndBytesOperations, ConsecutiveCallsToAlignHasNoEffect)
{
Buffer buf;
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBits(3u, 2);
//3 calls to align after 1st data
bpw.align();
bpw.align();
bpw.align();
bpw.writeBits(7u, 3);
//1 call to align after 2nd data
bpw.align();
bpw.writeBits(15u, 4);
bpw.flush();
bpw.writeBits(3u, 2);
// 3 calls to align after 1st data
bpw.align();
bpw.align();
bpw.align();
bpw.writeBits(7u, 3);
// 1 call to align after 2nd data
bpw.align();
bpw.writeBits(15u, 4);
bpw.flush();
unsigned char tmp;
Reader br{buf.begin(), bpw.writtenBytesCount()};
AdapterBitPackingReader bpr{br};
bpr.readBits(tmp,2);
EXPECT_THAT(tmp, Eq(3u));
bpr.align();
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
bpr.readBits(tmp,3);
bpr.align();
bpr.align();
bpr.align();
EXPECT_THAT(tmp, Eq(7u));
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
unsigned char tmp;
Reader br{ buf.begin(), bpw.writtenBytesCount() };
AdapterBitPackingReader bpr{ br };
bpr.readBits(tmp, 2);
EXPECT_THAT(tmp, Eq(3u));
bpr.align();
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
bpr.readBits(tmp, 3);
bpr.align();
bpr.align();
bpr.align();
EXPECT_THAT(tmp, Eq(7u));
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
bpr.readBits(tmp,4);
EXPECT_THAT(tmp, Eq(15u));
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
bpr.readBits(tmp, 4);
EXPECT_THAT(tmp, Eq(15u));
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
}
TEST(DataBitsAndBytesOperations, AlignWritesZerosBits) {
//setup data
TEST(DataBitsAndBytesOperations, AlignWritesZerosBits)
{
// setup data
//create and write to buffer
Buffer buf;
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
// create and write to buffer
Buffer buf;
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
//write 2 bits and align
bpw.writeBits(3u, 2);
bpw.align();
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(1));
unsigned char tmp;
Reader br1{buf.begin(), writtenSize};
AdapterBitPackingReader bpr1{br1};
bpr1.readBits(tmp,2);
//read aligned bits
bpr1.readBits(tmp,6);
EXPECT_THAT(tmp, Eq(0));
// write 2 bits and align
bpw.writeBits(3u, 2);
bpw.align();
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(1));
unsigned char tmp;
Reader br1{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr1{ br1 };
bpr1.readBits(tmp, 2);
// read aligned bits
bpr1.readBits(tmp, 6);
EXPECT_THAT(tmp, Eq(0));
Reader br2{buf.begin(), writtenSize};
AdapterBitPackingReader bpr2{br2};
//read 2 bits
bpr2.readBits(tmp,2);
bpr2.align();
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::NoError));
Reader br2{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr2{ br2 };
// read 2 bits
bpr2.readBits(tmp, 2);
bpr2.align();
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::NoError));
}
// *** bytes operations
struct IntegralTypes {
int64_t a;
uint32_t b;
int16_t c;
uint8_t d;
int8_t e;
int8_t f[2];
struct IntegralTypes
{
int64_t a;
uint32_t b;
int16_t c;
uint8_t d;
int8_t e;
int8_t f[2];
};
TEST(DataBitsAndBytesOperations, WriteAndReadBytes) {
//setup data
IntegralTypes data;
data.a = -4894541654564;
data.b = 94545646;
data.c = -8778;
data.d = 200;
data.e = -98;
data.f[0] = 43;
data.f[1] = -45;
TEST(DataBitsAndBytesOperations, WriteAndReadBytes)
{
// setup data
IntegralTypes data;
data.a = -4894541654564;
data.b = 94545646;
data.c = -8778;
data.d = 200;
data.e = -98;
data.f[0] = 43;
data.f[1] = -45;
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBytes<4>(data.b);
bw.writeBytes<2>(data.c);
bw.writeBytes<1>(data.d);
bw.writeBytes<8>(data.a);
bw.writeBytes<1>(data.e);
bw.writeBuffer<1>(data.f, 2);
bw.flush();
auto writtenSize = bw.writtenBytesCount();
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
bw.writeBytes<4>(data.b);
bw.writeBytes<2>(data.c);
bw.writeBytes<1>(data.d);
bw.writeBytes<8>(data.a);
bw.writeBytes<1>(data.e);
bw.writeBuffer<1>(data.f, 2);
bw.flush();
auto writtenSize = bw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(18));
//read from buffer
Reader br{buf.begin(), writtenSize};
IntegralTypes res{};
br.readBytes<4>(res.b);
br.readBytes<2>(res.c);
br.readBytes<1>(res.d);
br.readBytes<8>(res.a);
br.readBytes<1>(res.e);
br.readBuffer<1>(res.f, 2);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
//assert results
EXPECT_THAT(data.a, Eq(res.a));
EXPECT_THAT(data.b, Eq(res.b));
EXPECT_THAT(data.c, Eq(res.c));
EXPECT_THAT(data.d, Eq(res.d));
EXPECT_THAT(data.e, Eq(res.e));
EXPECT_THAT(data.f, ContainerEq(res.f));
EXPECT_THAT(writtenSize, Eq(18));
// read from buffer
Reader br{ buf.begin(), writtenSize };
IntegralTypes res{};
br.readBytes<4>(res.b);
br.readBytes<2>(res.c);
br.readBytes<1>(res.d);
br.readBytes<8>(res.a);
br.readBytes<1>(res.e);
br.readBuffer<1>(res.f, 2);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
// assert results
EXPECT_THAT(data.a, Eq(res.a));
EXPECT_THAT(data.b, Eq(res.b));
EXPECT_THAT(data.c, Eq(res.c));
EXPECT_THAT(data.d, Eq(res.d));
EXPECT_THAT(data.e, Eq(res.e));
EXPECT_THAT(data.f, ContainerEq(res.f));
}
TEST(DataBitsAndBytesOperations, WriteAndReadBytesWithBitPackingWrapper) {
//setup data
IntegralTypes data;
data.a = -4894541654564;
data.b = 94545646;
data.c = -8778;
data.d = 200;
data.e = -98;
data.f[0] = 43;
data.f[1] = -45;
TEST(DataBitsAndBytesOperations, WriteAndReadBytesWithBitPackingWrapper)
{
// setup data
IntegralTypes data;
data.a = -4894541654564;
data.b = 94545646;
data.c = -8778;
data.d = 200;
data.e = -98;
data.f[0] = 43;
data.f[1] = -45;
//create and write to buffer
Buffer buf{};
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
bpw.writeBytes<4>(data.b);
bpw.writeBytes<2>(data.c);
bpw.writeBytes<1>(data.d);
bpw.writeBytes<8>(data.a);
bpw.writeBytes<1>(data.e);
bpw.writeBuffer<1>(data.f, 2);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBytes<4>(data.b);
bpw.writeBytes<2>(data.c);
bpw.writeBytes<1>(data.d);
bpw.writeBytes<8>(data.a);
bpw.writeBytes<1>(data.e);
bpw.writeBuffer<1>(data.f, 2);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(18));
//read from buffer
Reader br{buf.begin(), writtenSize};
AdapterBitPackingReader bpr{br};
IntegralTypes res{};
bpr.readBytes<4>(res.b);
bpr.readBytes<2>(res.c);
bpr.readBytes<1>(res.d);
bpr.readBytes<8>(res.a);
bpr.readBytes<1>(res.e);
bpr.readBuffer<1>(res.f, 2);
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
//assert results
EXPECT_THAT(data.a, Eq(res.a));
EXPECT_THAT(data.b, Eq(res.b));
EXPECT_THAT(data.c, Eq(res.c));
EXPECT_THAT(data.d, Eq(res.d));
EXPECT_THAT(data.e, Eq(res.e));
EXPECT_THAT(data.f, ContainerEq(res.f));
EXPECT_THAT(writtenSize, Eq(18));
// read from buffer
Reader br{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr{ br };
IntegralTypes res{};
bpr.readBytes<4>(res.b);
bpr.readBytes<2>(res.c);
bpr.readBytes<1>(res.d);
bpr.readBytes<8>(res.a);
bpr.readBytes<1>(res.e);
bpr.readBuffer<1>(res.f, 2);
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
// assert results
EXPECT_THAT(data.a, Eq(res.a));
EXPECT_THAT(data.b, Eq(res.b));
EXPECT_THAT(data.c, Eq(res.c));
EXPECT_THAT(data.d, Eq(res.d));
EXPECT_THAT(data.e, Eq(res.e));
EXPECT_THAT(data.f, ContainerEq(res.f));
}
TEST(DataBitsAndBytesOperations, ReadWriteFncCanAcceptSignedData) {
//setup data
constexpr size_t DATA_SIZE = 3;
int16_t src[DATA_SIZE] {54,-4877,30067};
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBuffer<2>(src, DATA_SIZE);
bw.flush();
//read from buffer
Reader br1{buf.begin(), bw.writtenBytesCount()};
int16_t dst[DATA_SIZE]{};
br1.readBuffer<2>(dst, DATA_SIZE);
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(dst, ContainerEq(src));
TEST(DataBitsAndBytesOperations, ReadWriteFncCanAcceptSignedData)
{
// setup data
constexpr size_t DATA_SIZE = 3;
int16_t src[DATA_SIZE]{ 54, -4877, 30067 };
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
bw.writeBuffer<2>(src, DATA_SIZE);
bw.flush();
// read from buffer
Reader br1{ buf.begin(), bw.writtenBytesCount() };
int16_t dst[DATA_SIZE]{};
br1.readBuffer<2>(dst, DATA_SIZE);
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(dst, ContainerEq(src));
}
TEST(DataBitsAndBytesOperations, ReadWriteCanWorkOnUnalignedData) {
//setup data
constexpr size_t DATA_SIZE = 3;
int16_t src[DATA_SIZE] {54,-4877,30067};
//create and write to buffer
Buffer buf{};
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
bpw.writeBits(15u, 4);
bpw.writeBuffer<2>(src, DATA_SIZE);
bpw.writeBits(12u, 4);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(sizeof(src) + 1));
TEST(DataBitsAndBytesOperations, ReadWriteCanWorkOnUnalignedData)
{
// setup data
constexpr size_t DATA_SIZE = 3;
int16_t src[DATA_SIZE]{ 54, -4877, 30067 };
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBits(15u, 4);
bpw.writeBuffer<2>(src, DATA_SIZE);
bpw.writeBits(12u, 4);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(sizeof(src) + 1));
//read from buffer
Reader br1{buf.begin(), writtenSize};
AdapterBitPackingReader bpr1{br1};
int16_t dst[DATA_SIZE]{};
uint8_t tmp{};
bpr1.readBits(tmp, 4);
EXPECT_THAT(tmp, Eq(15));
bpr1.readBuffer<2>(dst, DATA_SIZE);
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(dst, ContainerEq(src));
bpr1.readBits(tmp, 4);
EXPECT_THAT(tmp, Eq(12));
// read from buffer
Reader br1{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr1{ br1 };
int16_t dst[DATA_SIZE]{};
uint8_t tmp{};
bpr1.readBits(tmp, 4);
EXPECT_THAT(tmp, Eq(15));
bpr1.readBuffer<2>(dst, DATA_SIZE);
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(dst, ContainerEq(src));
bpr1.readBits(tmp, 4);
EXPECT_THAT(tmp, Eq(12));
}
TEST(DataBitsAndBytesOperations, RegressionTestReadBytesAfterReadBitsWithLotsOfZeroBits) {
//setup data
int16_t data[2]{0x0000, 0x7FFF};
int16_t res[2]{};
//create and write to buffer
Buffer buf{};
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
bpw.writeBits(2u, 2);
bpw.writeBytes<2>(data[0]);
bpw.writeBytes<2>(data[1]);
bpw.align();
bpw.flush();
TEST(DataBitsAndBytesOperations,
RegressionTestReadBytesAfterReadBitsWithLotsOfZeroBits)
{
// setup data
int16_t data[2]{ 0x0000, 0x7FFF };
int16_t res[2]{};
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBits(2u, 2);
bpw.writeBytes<2>(data[0]);
bpw.writeBytes<2>(data[1]);
bpw.align();
bpw.flush();
//read from buffer
Reader br{buf.begin(), bpw.writtenBytesCount()};
AdapterBitPackingReader bpr{br};
uint8_t tmp{};
bpr.readBits(tmp, 2);
EXPECT_THAT(tmp, Eq(2));
bpr.readBytes<2>(res[0]);
bpr.readBytes<2>(res[1]);
bpr.align();
EXPECT_THAT(res[0], Eq(data[0]));
EXPECT_THAT(res[1], Eq(data[1]));
// read from buffer
Reader br{ buf.begin(), bpw.writtenBytesCount() };
AdapterBitPackingReader bpr{ br };
uint8_t tmp{};
bpr.readBits(tmp, 2);
EXPECT_THAT(tmp, Eq(2));
bpr.readBytes<2>(res[0]);
bpr.readBytes<2>(res[1]);
bpr.align();
EXPECT_THAT(res[0], Eq(data[0]));
EXPECT_THAT(res[1], Eq(data[1]));
}

View File

@@ -1,111 +1,117 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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.
#include <bitsery/details/serialization_common.h>
#include <bitsery/traits/array.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::Eq;
using testing::ContainerEq;
using bitsery::EndiannessType;
using testing::ContainerEq;
using testing::Eq;
template <typename BufType>
class DataWriting:public testing::Test {
template<typename BufType>
class DataWriting : public testing::Test
{
public:
using TWriter = bitsery::OutputBufferAdapter<BufType>;
using TBuffer = BufType;
using TWriter = bitsery::OutputBufferAdapter<BufType>;
using TBuffer = BufType;
};
using NonFixedContainer = std::vector<uint8_t>;
using FixedContainer = std::array<uint8_t, 100>;
using ContainerTypes = ::testing::Types<FixedContainer,NonFixedContainer>;
using ContainerTypes = ::testing::Types<FixedContainer, NonFixedContainer>;
TYPED_TEST_SUITE(DataWriting, ContainerTypes,);
TYPED_TEST_SUITE(DataWriting, ContainerTypes, );
static constexpr size_t DATA_SIZE = 14u;
template <typename BW>
void writeData(BW& bw) {
uint16_t tmp1{45}, tmp2{6543}, tmp3{46533};
uint32_t tmp4{8979445}, tmp5{7987564};
bw.template writeBytes<2>(tmp1);
bw.template writeBytes<2>(tmp2);
bw.template writeBytes<2>(tmp3);
bw.template writeBytes<4>(tmp4);
bw.template writeBytes<4>(tmp5);
template<typename BW>
void
writeData(BW& bw)
{
uint16_t tmp1{ 45 }, tmp2{ 6543 }, tmp3{ 46533 };
uint32_t tmp4{ 8979445 }, tmp5{ 7987564 };
bw.template writeBytes<2>(tmp1);
bw.template writeBytes<2>(tmp2);
bw.template writeBytes<2>(tmp3);
bw.template writeBytes<4>(tmp4);
bw.template writeBytes<4>(tmp5);
}
TYPED_TEST(DataWriting, GetWrittenBytesCountReturnsActualBytesWritten) {
using TWriter = typename TestFixture::TWriter;
using TBuffer = typename TestFixture::TBuffer;
TBuffer buf{};
TWriter bw{buf};
writeData(bw);
bw.flush();
auto writtenSize = bw.writtenBytesCount();
EXPECT_THAT(writtenSize, DATA_SIZE);
EXPECT_THAT(buf.size(), ::testing::Ge(DATA_SIZE));
TYPED_TEST(DataWriting, GetWrittenBytesCountReturnsActualBytesWritten)
{
using TWriter = typename TestFixture::TWriter;
using TBuffer = typename TestFixture::TBuffer;
TBuffer buf{};
TWriter bw{ buf };
writeData(bw);
bw.flush();
auto writtenSize = bw.writtenBytesCount();
EXPECT_THAT(writtenSize, DATA_SIZE);
EXPECT_THAT(buf.size(), ::testing::Ge(DATA_SIZE));
}
TYPED_TEST(DataWriting, WhenWritingBitsThenMustFlushWriter) {
using TWriter = typename TestFixture::TWriter;
using TBuffer = typename TestFixture::TBuffer;
TBuffer buf{};
TWriter bw{buf};
bitsery::details::OutputAdapterBitPackingWrapper<TWriter> bpw{bw};
bpw.writeBits(3u, 2);
auto writtenSize1 = bpw.writtenBytesCount();
bpw.flush();
auto writtenSize2 = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize1, Eq(0));
EXPECT_THAT(writtenSize2, Eq(1));
TYPED_TEST(DataWriting, WhenWritingBitsThenMustFlushWriter)
{
using TWriter = typename TestFixture::TWriter;
using TBuffer = typename TestFixture::TBuffer;
TBuffer buf{};
TWriter bw{ buf };
bitsery::details::OutputAdapterBitPackingWrapper<TWriter> bpw{ bw };
bpw.writeBits(3u, 2);
auto writtenSize1 = bpw.writtenBytesCount();
bpw.flush();
auto writtenSize2 = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize1, Eq(0));
EXPECT_THAT(writtenSize2, Eq(1));
}
TYPED_TEST(DataWriting, WhenDataAlignedThenFlushHasNoEffect) {
using TWriter = typename TestFixture::TWriter;
using TBuffer = typename TestFixture::TBuffer;
TBuffer buf{};
TWriter bw{buf};
bitsery::details::OutputAdapterBitPackingWrapper<TWriter> bpw{bw};
bpw.writeBits(3u, 2);
bpw.align();
auto writtenSize1 = bpw.writtenBytesCount();
bpw.flush();
auto writtenSize2 = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize1, Eq(1));
EXPECT_THAT(writtenSize2, Eq(1));
TYPED_TEST(DataWriting, WhenDataAlignedThenFlushHasNoEffect)
{
using TWriter = typename TestFixture::TWriter;
using TBuffer = typename TestFixture::TBuffer;
TBuffer buf{};
TWriter bw{ buf };
bitsery::details::OutputAdapterBitPackingWrapper<TWriter> bpw{ bw };
bpw.writeBits(3u, 2);
bpw.align();
auto writtenSize1 = bpw.writtenBytesCount();
bpw.flush();
auto writtenSize2 = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize1, Eq(1));
EXPECT_THAT(writtenSize2, Eq(1));
}
TEST(DataWritingNonFixedBufferContainer, ContainerIsAlwaysResizedToCapacity) {
NonFixedContainer buf{};
bitsery::OutputBufferAdapter<NonFixedContainer> bw{buf};
for (auto i = 0; i < 5; ++i) {
uint32_t tmp{};
bw.writeBytes<4>(tmp);
bw.writeBytes<4>(tmp);
EXPECT_TRUE(buf.size() == buf.capacity());
}
TEST(DataWritingNonFixedBufferContainer, ContainerIsAlwaysResizedToCapacity)
{
NonFixedContainer buf{};
bitsery::OutputBufferAdapter<NonFixedContainer> bw{ buf };
for (auto i = 0; i < 5; ++i) {
uint32_t tmp{};
bw.writeBytes<4>(tmp);
bw.writeBytes<4>(tmp);
EXPECT_TRUE(buf.size() == buf.capacity());
}
}

View File

@@ -1,351 +1,393 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 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:
// 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 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.
// 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.
#include <forward_list>
#include <bitsery/traits/forward_list.h>
#include <bitsery/ext/std_set.h>
#include <bitsery/ext/std_map.h>
#include <bitsery/ext/pointer.h>
#include <bitsery/ext/std_map.h>
#include <bitsery/ext/std_set.h>
#include <bitsery/ext/std_smart_ptr.h>
#include <bitsery/traits/forward_list.h>
#include <forward_list>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::ContainerEq;
using testing::Eq;
//forward declare, for testing with std::unordered_map
// forward declare, for testing with std::unordered_map
class HasherForNonDefaultConstructible;
class NonDefaultConstructible {
int32_t i{0};
friend class HasherForNonDefaultConstructible;
class NonDefaultConstructible
{
int32_t i{ 0 };
friend class HasherForNonDefaultConstructible;
friend class bitsery::Access;
NonDefaultConstructible() = default;
friend class bitsery::Access;
NonDefaultConstructible() = default;
template <typename S>
void serialize(S& s) {
s.value4b(i);
}
template<typename S>
void serialize(S& s)
{
s.value4b(i);
}
public:
explicit NonDefaultConstructible(int32_t v)
: i{ v }
{
}
explicit NonDefaultConstructible(int32_t v):i{v} {}
bool operator==(const NonDefaultConstructible& other) const
{
return i == other.i;
}
bool operator == (const NonDefaultConstructible& other) const {
return i == other.i;
}
bool operator < (const NonDefaultConstructible& other) const {
return i < other.i;
}
bool operator<(const NonDefaultConstructible& other) const
{
return i < other.i;
}
};
class HasherForNonDefaultConstructible {
class HasherForNonDefaultConstructible
{
public:
size_t operator()(const NonDefaultConstructible& o) const {
return std::hash<int32_t>()(o.i);
}
size_t operator()(const NonDefaultConstructible& o) const
{
return std::hash<int32_t>()(o.i);
}
};
TEST(DeserializeNonDefaultConstructible, Container)
{
SerializationContext ctx{};
std::vector<NonDefaultConstructible> data{};
data.emplace_back(1);
data.emplace_back(2);
data.emplace_back(3);
std::vector<NonDefaultConstructible> res{};
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
EXPECT_THAT(res, ContainerEq(data));
}
// this test is here, because when object is not constructible we cannot simple
// "resize" container
TEST(DeserializeNonDefaultConstructible, ResultContainerShouldShrink)
{
SerializationContext ctx{};
std::vector<NonDefaultConstructible> data{};
data.emplace_back(1);
std::vector<NonDefaultConstructible> res{};
res.emplace_back(2);
res.emplace_back(3);
res.emplace_back(4);
TEST(DeserializeNonDefaultConstructible, Container) {
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
EXPECT_THAT(res, ContainerEq(data));
}
TEST(DeserializeNonDefaultConstructible, ResultStdForwardListShouldShrink)
{
// forward list doesn't have .erase function, bet has erase_after
// in this case, if new size is 0 it must call clear, so we need to check two
// cases
{
// 1) when result should have more than 0 elements
SerializationContext ctx{};
std::vector<NonDefaultConstructible> data{};
data.emplace_back(1);
data.emplace_back(2);
data.emplace_back(3);
std::vector<NonDefaultConstructible> res{};
std::forward_list<NonDefaultConstructible> data{};
data.push_front(NonDefaultConstructible{ 1 });
std::forward_list<NonDefaultConstructible> res{};
res.push_front(NonDefaultConstructible{ 21 });
res.push_front(NonDefaultConstructible{ 14 });
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
EXPECT_THAT(res, ContainerEq(data));
}
//this test is here, because when object is not constructible we cannot simple "resize" container
TEST(DeserializeNonDefaultConstructible, ResultContainerShouldShrink) {
auto resIt = res.begin();
for (auto it = data.begin(); it != data.end(); ++it, ++resIt) {
EXPECT_THAT(*resIt, Eq(*it));
}
EXPECT_THAT(resIt, Eq(res.end()));
}
{
// 1) when result should have 0 elements
SerializationContext ctx{};
std::vector<NonDefaultConstructible> data{};
data.emplace_back(1);
std::vector<NonDefaultConstructible> res{};
res.emplace_back(2);
res.emplace_back(3);
res.emplace_back(4);
std::forward_list<NonDefaultConstructible> data{};
std::forward_list<NonDefaultConstructible> res{};
res.push_front(NonDefaultConstructible{ 1 });
res.push_front(NonDefaultConstructible{ 14 });
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
EXPECT_THAT(res, ContainerEq(data));
}
EXPECT_THAT(res.begin(), Eq(res.end()));
}
TEST(DeserializeNonDefaultConstructible, ResultStdForwardListShouldShrink) {
// forward list doesn't have .erase function, bet has erase_after
// in this case, if new size is 0 it must call clear, so we need to check two cases
{
// 1) when result should have more than 0 elements
SerializationContext ctx{};
std::forward_list<NonDefaultConstructible> data{};
data.push_front(NonDefaultConstructible{1});
std::forward_list<NonDefaultConstructible> res{};
res.push_front(NonDefaultConstructible{21});
res.push_front(NonDefaultConstructible{14});
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
auto resIt = res.begin();
for (auto it = data.begin(); it != data.end(); ++it, ++resIt) {
EXPECT_THAT(*resIt, Eq(*it));
}
EXPECT_THAT(resIt, Eq(res.end()));
}
{
// 1) when result should have 0 elements
SerializationContext ctx{};
std::forward_list<NonDefaultConstructible> data{};
std::forward_list<NonDefaultConstructible> res{};
res.push_front(NonDefaultConstructible{1});
res.push_front(NonDefaultConstructible{14});
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
EXPECT_THAT(res.begin(), Eq(res.end()));
}
{
// also check if correctly expands if source is bigger than destination
SerializationContext ctx{};
std::forward_list<NonDefaultConstructible> data{};
data.push_front(NonDefaultConstructible{1});
data.push_front(NonDefaultConstructible{14});
std::forward_list<NonDefaultConstructible> res{};
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
auto resIt = res.begin();
for (auto it = data.begin(); it != data.end(); ++it, ++resIt) {
EXPECT_THAT(*resIt, Eq(*it));
}
EXPECT_THAT(resIt, Eq(res.end()));
}
}
TEST(DeserializeNonDefaultConstructible, StdSet) {
{
// also check if correctly expands if source is bigger than destination
SerializationContext ctx{};
std::set<NonDefaultConstructible> data;
data.insert(NonDefaultConstructible{1});
data.insert(NonDefaultConstructible{2});
std::set<NonDefaultConstructible> res{};
data.insert(NonDefaultConstructible{3});
std::forward_list<NonDefaultConstructible> data{};
data.push_front(NonDefaultConstructible{ 1 });
data.push_front(NonDefaultConstructible{ 14 });
std::forward_list<NonDefaultConstructible> res{};
ctx.createSerializer().ext(data, bitsery::ext::StdSet{10});
ctx.createDeserializer().ext(res, bitsery::ext::StdSet{10});
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
EXPECT_THAT(res, ContainerEq(data));
auto resIt = res.begin();
for (auto it = data.begin(); it != data.end(); ++it, ++resIt) {
EXPECT_THAT(*resIt, Eq(*it));
}
EXPECT_THAT(resIt, Eq(res.end()));
}
}
TEST(DeserializeNonDefaultConstructible, StdMap) {
SerializationContext ctx{};
std::unordered_map<NonDefaultConstructible, NonDefaultConstructible, HasherForNonDefaultConstructible> data;
data.emplace(NonDefaultConstructible{2}, NonDefaultConstructible{3});
TEST(DeserializeNonDefaultConstructible, StdSet)
{
SerializationContext ctx{};
std::set<NonDefaultConstructible> data;
data.insert(NonDefaultConstructible{ 1 });
data.insert(NonDefaultConstructible{ 2 });
std::set<NonDefaultConstructible> res{};
data.insert(NonDefaultConstructible{ 3 });
std::unordered_map<NonDefaultConstructible, NonDefaultConstructible, HasherForNonDefaultConstructible> res{};
data.emplace(NonDefaultConstructible{2}, NonDefaultConstructible{3});
data.emplace(NonDefaultConstructible{4}, NonDefaultConstructible{4});
ctx.createSerializer().ext(data, bitsery::ext::StdSet{ 10 });
ctx.createDeserializer().ext(res, bitsery::ext::StdSet{ 10 });
auto& ser = ctx.createSerializer();
ser.ext(data, bitsery::ext::StdMap{10},[](decltype(ser)& ser, NonDefaultConstructible& key, NonDefaultConstructible& value) {
ser.object(key);
ser.object(value);
});
auto& des = ctx.createDeserializer();
des.ext(res, bitsery::ext::StdMap{10},[](decltype(des)& des, NonDefaultConstructible& key, NonDefaultConstructible& value) {
des.object(key);
des.object(value);
});
EXPECT_THAT(res, ContainerEq(data));
EXPECT_THAT(res, ContainerEq(data));
}
TEST(DeserializeNonDefaultConstructible, StdMap)
{
SerializationContext ctx{};
std::unordered_map<NonDefaultConstructible,
NonDefaultConstructible,
HasherForNonDefaultConstructible>
data;
data.emplace(NonDefaultConstructible{ 2 }, NonDefaultConstructible{ 3 });
struct NonPolymorphicPointers {
NonDefaultConstructible* pp;
std::unique_ptr<NonDefaultConstructible> up;
std::shared_ptr<NonDefaultConstructible> sp;
std::weak_ptr<NonDefaultConstructible> wp;
std::unordered_map<NonDefaultConstructible,
NonDefaultConstructible,
HasherForNonDefaultConstructible>
res{};
data.emplace(NonDefaultConstructible{ 2 }, NonDefaultConstructible{ 3 });
data.emplace(NonDefaultConstructible{ 4 }, NonDefaultConstructible{ 4 });
auto& ser = ctx.createSerializer();
ser.ext(data,
bitsery::ext::StdMap{ 10 },
[](decltype(ser)& ser,
NonDefaultConstructible& key,
NonDefaultConstructible& value) {
ser.object(key);
ser.object(value);
});
auto& des = ctx.createDeserializer();
des.ext(res,
bitsery::ext::StdMap{ 10 },
[](decltype(des)& des,
NonDefaultConstructible& key,
NonDefaultConstructible& value) {
des.object(key);
des.object(value);
});
EXPECT_THAT(res, ContainerEq(data));
}
struct NonPolymorphicPointers
{
NonDefaultConstructible* pp;
std::unique_ptr<NonDefaultConstructible> up;
std::shared_ptr<NonDefaultConstructible> sp;
std::weak_ptr<NonDefaultConstructible> wp;
};
template <typename S>
void serialize(S& s, NonPolymorphicPointers& o) {
s.ext(o.pp, bitsery::ext::PointerOwner{});
s.ext(o.up, bitsery::ext::StdSmartPtr{});
s.ext(o.sp, bitsery::ext::StdSmartPtr{});
s.ext(o.wp, bitsery::ext::StdSmartPtr{});
template<typename S>
void
serialize(S& s, NonPolymorphicPointers& o)
{
s.ext(o.pp, bitsery::ext::PointerOwner{});
s.ext(o.up, bitsery::ext::StdSmartPtr{});
s.ext(o.sp, bitsery::ext::StdSmartPtr{});
s.ext(o.wp, bitsery::ext::StdSmartPtr{});
}
TEST(DeserializeNonDefaultConstructible, NonPolymorphicPointerAndSmartPointer) {
using SerContext = BasicSerializationContext<bitsery::ext::PointerLinkingContext>;
SerContext ctx{};
NonPolymorphicPointers data{};
data.pp = new NonDefaultConstructible{3};
data.up = std::unique_ptr<NonDefaultConstructible>(new NonDefaultConstructible{54});
data.sp = std::shared_ptr<NonDefaultConstructible>(new NonDefaultConstructible{-481});
data.wp = data.sp;
TEST(DeserializeNonDefaultConstructible, NonPolymorphicPointerAndSmartPointer)
{
using SerContext =
BasicSerializationContext<bitsery::ext::PointerLinkingContext>;
SerContext ctx{};
NonPolymorphicPointers data{};
data.pp = new NonDefaultConstructible{ 3 };
data.up =
std::unique_ptr<NonDefaultConstructible>(new NonDefaultConstructible{ 54 });
data.sp = std::shared_ptr<NonDefaultConstructible>(
new NonDefaultConstructible{ -481 });
data.wp = data.sp;
NonPolymorphicPointers res{};
bitsery::ext::PointerLinkingContext plctx1{};
ctx.createSerializer(plctx1).object(data);
ctx.createDeserializer(plctx1).object(res);
NonPolymorphicPointers res{};
bitsery::ext::PointerLinkingContext plctx1{};
ctx.createSerializer(plctx1).object(data);
ctx.createDeserializer(plctx1).object(res);
EXPECT_THAT(*res.pp, Eq(*data.pp));
delete res.pp;
delete data.pp;
EXPECT_THAT(*res.up, Eq(*data.up));
EXPECT_THAT(*res.sp, Eq(*data.sp));
EXPECT_THAT(*(res.wp.lock()), Eq(*(data.wp.lock())));
EXPECT_THAT(*res.pp, Eq(*data.pp));
delete res.pp;
delete data.pp;
EXPECT_THAT(*res.up, Eq(*data.up));
EXPECT_THAT(*res.sp, Eq(*data.sp));
EXPECT_THAT(*(res.wp.lock()), Eq(*(data.wp.lock())));
}
class PolymorphicNDCBase {
class PolymorphicNDCBase
{
public:
virtual ~PolymorphicNDCBase() = 0;
template <typename S>
void serialize(S& ) {}
virtual ~PolymorphicNDCBase() = 0;
template<typename S>
void serialize(S&)
{
}
};
PolymorphicNDCBase::~PolymorphicNDCBase() = default;
class PolymorphicNDC1:public PolymorphicNDCBase {
int8_t i{};
friend class bitsery::Access;
class PolymorphicNDC1 : public PolymorphicNDCBase
{
int8_t i{};
friend class bitsery::Access;
template<typename S>
void serialize(S& s)
{
s.value1b(i);
}
template <typename S>
void serialize(S& s) {
s.value1b(i);
}
public:
PolymorphicNDC1() = default;
PolymorphicNDC1(int8_t v):i{v} {}
bool operator == (const PolymorphicNDC1& other) const {
return i == other.i;
}
PolymorphicNDC1() = default;
PolymorphicNDC1(int8_t v)
: i{ v }
{
}
bool operator==(const PolymorphicNDC1& other) const { return i == other.i; }
};
class PolymorphicNDC2:public PolymorphicNDCBase {
uint16_t ui{};
class PolymorphicNDC2 : public PolymorphicNDCBase
{
uint16_t ui{};
friend class bitsery::Access;
friend class bitsery::Access;
template<typename S>
void serialize(S& s)
{
s.value2b(ui);
}
template <typename S>
void serialize(S& s) {
s.value2b(ui);
}
public:
PolymorphicNDC2() = default;
PolymorphicNDC2(uint16_t v):ui{v} {}
bool operator == (const PolymorphicNDC2& other) const {
return ui == other.ui;
}
PolymorphicNDC2() = default;
PolymorphicNDC2(uint16_t v)
: ui{ v }
{
}
bool operator==(const PolymorphicNDC2& other) const { return ui == other.ui; }
};
namespace bitsery {
namespace ext {
namespace ext {
template<>
struct PolymorphicBaseClass<PolymorphicNDCBase> : PolymorphicDerivedClasses<PolymorphicNDC1, PolymorphicNDC2> {
};
}
template<>
struct PolymorphicBaseClass<PolymorphicNDCBase>
: PolymorphicDerivedClasses<PolymorphicNDC1, PolymorphicNDC2>
{};
}
}
struct PolymorphicPointers {
PolymorphicNDCBase* pp;
std::unique_ptr<PolymorphicNDCBase> up;
std::shared_ptr<PolymorphicNDCBase> sp;
std::weak_ptr<PolymorphicNDCBase> wp;
struct PolymorphicPointers
{
PolymorphicNDCBase* pp;
std::unique_ptr<PolymorphicNDCBase> up;
std::shared_ptr<PolymorphicNDCBase> sp;
std::weak_ptr<PolymorphicNDCBase> wp;
};
template <typename S>
void serialize(S& s, PolymorphicPointers& o) {
s.ext(o.pp, bitsery::ext::PointerOwner{});
s.ext(o.up, bitsery::ext::StdSmartPtr{});
s.ext(o.sp, bitsery::ext::StdSmartPtr{});
s.ext(o.wp, bitsery::ext::StdSmartPtr{});
template<typename S>
void
serialize(S& s, PolymorphicPointers& o)
{
s.ext(o.pp, bitsery::ext::PointerOwner{});
s.ext(o.up, bitsery::ext::StdSmartPtr{});
s.ext(o.sp, bitsery::ext::StdSmartPtr{});
s.ext(o.wp, bitsery::ext::StdSmartPtr{});
}
TEST(DeserializeNonDefaultConstructible, PolymorphicPointerAndSmartPointer) {
using TContext = std::tuple<bitsery::ext::PointerLinkingContext, bitsery::ext::PolymorphicContext<bitsery::ext::StandardRTTI>>;
using SerContext = BasicSerializationContext<TContext>;
SerContext ctx{};
PolymorphicPointers data{};
data.pp = new PolymorphicNDC1{-4};
data.up = std::unique_ptr<PolymorphicNDCBase>(new PolymorphicNDC2{54});
data.sp = std::shared_ptr<PolymorphicNDCBase>(new PolymorphicNDC1{15});
data.wp = data.sp;
TEST(DeserializeNonDefaultConstructible, PolymorphicPointerAndSmartPointer)
{
using TContext =
std::tuple<bitsery::ext::PointerLinkingContext,
bitsery::ext::PolymorphicContext<bitsery::ext::StandardRTTI>>;
using SerContext = BasicSerializationContext<TContext>;
SerContext ctx{};
PolymorphicPointers data{};
data.pp = new PolymorphicNDC1{ -4 };
data.up = std::unique_ptr<PolymorphicNDCBase>(new PolymorphicNDC2{ 54 });
data.sp = std::shared_ptr<PolymorphicNDCBase>(new PolymorphicNDC1{ 15 });
data.wp = data.sp;
PolymorphicPointers res{};
PolymorphicPointers res{};
TContext serCtx{};
TContext desCtx{};
TContext serCtx{};
TContext desCtx{};
std::get<1>(serCtx).registerBasesList<typename SerContext::TSerializer>(bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
std::get<1>(desCtx).registerBasesList<typename SerContext::TDeserializer>(bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
std::get<1>(serCtx).registerBasesList<typename SerContext::TSerializer>(
bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
std::get<1>(desCtx).registerBasesList<typename SerContext::TDeserializer>(
bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
ctx.createSerializer(serCtx).object(data);
ctx.createDeserializer(desCtx).object(res);
auto respp = dynamic_cast<PolymorphicNDC1*>(res.pp);
auto resup = dynamic_cast<PolymorphicNDC2*>(res.up.get());
auto ressp = dynamic_cast<PolymorphicNDC1*>(res.sp.get());
auto reswp = dynamic_cast<PolymorphicNDC1*>(res.wp.lock().get());
ctx.createSerializer(serCtx).object(data);
ctx.createDeserializer(desCtx).object(res);
auto respp = dynamic_cast<PolymorphicNDC1*>(res.pp);
auto resup = dynamic_cast<PolymorphicNDC2*>(res.up.get());
auto ressp = dynamic_cast<PolymorphicNDC1*>(res.sp.get());
auto reswp = dynamic_cast<PolymorphicNDC1*>(res.wp.lock().get());
auto datapp = dynamic_cast<PolymorphicNDC1*>(data.pp);
auto dataup = dynamic_cast<PolymorphicNDC2*>(data.up.get());
auto datasp = dynamic_cast<PolymorphicNDC1*>(data.sp.get());
auto datawp = dynamic_cast<PolymorphicNDC1*>(data.wp.lock().get());
auto datapp = dynamic_cast<PolymorphicNDC1*>(data.pp);
auto dataup = dynamic_cast<PolymorphicNDC2*>(data.up.get());
auto datasp = dynamic_cast<PolymorphicNDC1*>(data.sp.get());
auto datawp = dynamic_cast<PolymorphicNDC1*>(data.wp.lock().get());
EXPECT_THAT(respp, ::testing::Ne(nullptr));
EXPECT_THAT(resup, ::testing::Ne(nullptr));
EXPECT_THAT(ressp, ::testing::Ne(nullptr));
EXPECT_THAT(reswp, ::testing::Ne(nullptr));
EXPECT_THAT(respp, ::testing::Ne(nullptr));
EXPECT_THAT(resup, ::testing::Ne(nullptr));
EXPECT_THAT(ressp, ::testing::Ne(nullptr));
EXPECT_THAT(reswp, ::testing::Ne(nullptr));
EXPECT_THAT(*respp, Eq(*datapp));
delete res.pp;
delete data.pp;
EXPECT_THAT(*resup, Eq(*dataup));
EXPECT_THAT(*ressp, Eq(*datasp));
EXPECT_THAT(*reswp, Eq(*datawp));
std::get<0>(serCtx).clearSharedState();
std::get<0>(desCtx).clearSharedState();
EXPECT_THAT(*respp, Eq(*datapp));
delete res.pp;
delete data.pp;
EXPECT_THAT(*resup, Eq(*dataup));
EXPECT_THAT(*ressp, Eq(*datasp));
EXPECT_THAT(*reswp, Eq(*datawp));
std::get<0>(serCtx).clearSharedState();
std::get<0>(desCtx).clearSharedState();
}

View File

@@ -1,48 +1,48 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 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:
// 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 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.
// 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.
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::Eq;
TEST(Serialization, AdapterCanBeMovedInAndOut) {
Buffer buf{};
bitsery::Serializer<Writer> ser1{buf};
ser1.object(MyStruct1{1, 2});
auto writeAdapter = std::move(ser1).adapter();
bitsery::Serializer<Writer> ser2(std::move(writeAdapter));
ser2.object(MyStruct1{3, 4});
auto writtenBytesCount = ser2.adapter().writtenBytesCount();
EXPECT_THAT(writtenBytesCount, Eq(MyStruct1::SIZE + MyStruct1::SIZE));
TEST(Serialization, AdapterCanBeMovedInAndOut)
{
Buffer buf{};
bitsery::Serializer<Writer> ser1{ buf };
ser1.object(MyStruct1{ 1, 2 });
auto writeAdapter = std::move(ser1).adapter();
bitsery::Serializer<Writer> ser2(std::move(writeAdapter));
ser2.object(MyStruct1{ 3, 4 });
auto writtenBytesCount = ser2.adapter().writtenBytesCount();
EXPECT_THAT(writtenBytesCount, Eq(MyStruct1::SIZE + MyStruct1::SIZE));
MyStruct1 res{};
bitsery::Deserializer<Reader> des1{buf.begin(), writtenBytesCount};
des1.object(res);
EXPECT_THAT(res, Eq(MyStruct1{1, 2}));
auto readerAdapter = std::move(des1).adapter();
bitsery::Deserializer<Reader> des2(std::move(readerAdapter));
des2.object(res);
EXPECT_THAT(res, Eq(MyStruct1{3, 4}));
EXPECT_TRUE(des2.adapter().isCompletedSuccessfully());
MyStruct1 res{};
bitsery::Deserializer<Reader> des1{ buf.begin(), writtenBytesCount };
des1.object(res);
EXPECT_THAT(res, Eq(MyStruct1{ 1, 2 }));
auto readerAdapter = std::move(des1).adapter();
bitsery::Deserializer<Reader> des2(std::move(readerAdapter));
des2.object(res);
EXPECT_THAT(res, Eq(MyStruct1{ 3, 4 }));
EXPECT_TRUE(des2.adapter().isCompletedSuccessfully());
}

View File

@@ -1,83 +1,88 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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.
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::Eq;
TEST(SerializeBooleans, BoolAsBit)
{
TEST(SerializeBooleans, BoolAsBit) {
SerializationContext ctx{};
bool t1{true};
bool t2{false};
bool res1;
bool res2;
auto& ser = ctx.createSerializer();
ser.enableBitPacking([&t1, &t2](SerializationContext::TSerializerBPEnabled& sbp) {
sbp.boolValue(t1);
sbp.boolValue(t2);
SerializationContext ctx{};
bool t1{ true };
bool t2{ false };
bool res1;
bool res2;
auto& ser = ctx.createSerializer();
ser.enableBitPacking(
[&t1, &t2](SerializationContext::TSerializerBPEnabled& sbp) {
sbp.boolValue(t1);
sbp.boolValue(t2);
});
auto& des = ctx.createDeserializer();
des.enableBitPacking([&res1, &res2](SerializationContext::TDeserializerBPEnabled& sbp) {
sbp.boolValue(res1);
sbp.boolValue(res2);
auto& des = ctx.createDeserializer();
des.enableBitPacking(
[&res1, &res2](SerializationContext::TDeserializerBPEnabled& sbp) {
sbp.boolValue(res1);
sbp.boolValue(res2);
});
EXPECT_THAT(res1, Eq(t1));
EXPECT_THAT(res2, Eq(t2));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(res1, Eq(t1));
EXPECT_THAT(res2, Eq(t2));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
}
TEST(SerializeBooleans, BoolAsByte) {
SerializationContext ctx;
bool t1{true};
bool t2{false};
bool res1;
bool res2;
auto& ser = ctx.createSerializer();
ser.boolValue(t1);
ser.boolValue(t2);
auto& des = ctx.createDeserializer();
des.boolValue(res1);
des.boolValue(res2);
TEST(SerializeBooleans, BoolAsByte)
{
SerializationContext ctx;
bool t1{ true };
bool t2{ false };
bool res1;
bool res2;
auto& ser = ctx.createSerializer();
ser.boolValue(t1);
ser.boolValue(t2);
auto& des = ctx.createDeserializer();
des.boolValue(res1);
des.boolValue(res2);
EXPECT_THAT(res1, Eq(t1));
EXPECT_THAT(res2, Eq(t2));
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
EXPECT_THAT(res1, Eq(t1));
EXPECT_THAT(res2, Eq(t2));
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
}
TEST(SerializeBooleans, WhenReadingBoolByteReadsMoreThanOneThenInvalidDataErrorAndResultIsFalse) {
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.value1b(uint8_t{1});
ser.value1b(uint8_t{2});
bool res{};
auto& des = ctx.createDeserializer();
des.boolValue(res);
EXPECT_THAT(res, Eq(true));
des.boolValue(res);
EXPECT_THAT(res, Eq(false));
EXPECT_THAT(ctx.des->adapter().error(), Eq(bitsery::ReaderError::InvalidData));
TEST(SerializeBooleans,
WhenReadingBoolByteReadsMoreThanOneThenInvalidDataErrorAndResultIsFalse)
{
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.value1b(uint8_t{ 1 });
ser.value1b(uint8_t{ 2 });
bool res{};
auto& des = ctx.createDeserializer();
des.boolValue(res);
EXPECT_THAT(res, Eq(true));
des.boolValue(res);
EXPECT_THAT(res, Eq(false));
EXPECT_THAT(ctx.des->adapter().error(),
Eq(bitsery::ReaderError::InvalidData));
}

View File

@@ -1,74 +1,68 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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.
#include <bitsery/traits/array.h>
#include <bitsery/traits/list.h>
#include <bitsery/traits/deque.h>
#include <bitsery/traits/forward_list.h>
#include <bitsery/traits/list.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::ContainerEq;
using testing::Eq;
/*
* overload to get container of types
*/
template<typename Container>
Container getFilledContainer() {
return {1, 2, 3, 4, 5, 78, 456, 8, 54};
Container
getFilledContainer()
{
return { 1, 2, 3, 4, 5, 78, 456, 8, 54 };
}
template<>
std::vector<MyStruct1> getFilledContainer<std::vector<MyStruct1>>() {
return {
{0, 1},
{2, 3},
{4, 5},
{6, 7},
{8, 9},
{11, 34},
{5134, 1532}
};
std::vector<MyStruct1>
getFilledContainer<std::vector<MyStruct1>>()
{
return { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
{ 8, 9 }, { 11, 34 }, { 5134, 1532 } };
}
template<>
std::list<MyStruct2> getFilledContainer<std::list<MyStruct2>>() {
return {
{MyStruct2::V1, {0, 1}},
{MyStruct2::V3, {-45, 45}}
};
std::list<MyStruct2>
getFilledContainer<std::list<MyStruct2>>()
{
return { { MyStruct2::V1, { 0, 1 } }, { MyStruct2::V3, { -45, 45 } } };
}
struct EmptyFtor {
template <typename S, typename T>
void operator() (S& , T& ) {
}
struct EmptyFtor
{
template<typename S, typename T>
void operator()(S&, T&)
{
}
};
/*
@@ -76,197 +70,227 @@ struct EmptyFtor {
*/
template<typename T>
class SerializeContainerDynamicSizeArthmeticTypes : public testing::Test {
class SerializeContainerDynamicSizeArthmeticTypes : public testing::Test
{
public:
using TContainer = T;
using TValue = typename T::value_type;
using TContainer = T;
using TValue = typename T::value_type;
const TContainer src = getFilledContainer<TContainer>();
TContainer res{};
const TContainer src = getFilledContainer<TContainer>();
TContainer res{};
size_t getExpectedBufSize(const SerializationContext &ctx) const {
auto size = bitsery::traits::ContainerTraits<TContainer>::size(src);
return ctx.containerSizeSerializedBytesCount(size) + size * sizeof(TValue);
}
size_t getExpectedBufSize(const SerializationContext& ctx) const
{
auto size = bitsery::traits::ContainerTraits<TContainer>::size(src);
return ctx.containerSizeSerializedBytesCount(size) + size * sizeof(TValue);
}
};
//std::forward_list is not supported, because it doesn't have size() method
using SequenceContainersWithArthmeticTypes = ::testing::Types<
std::vector<int>,
std::list<float>,
std::forward_list<int>,
std::deque<unsigned short>>;
// std::forward_list is not supported, because it doesn't have size() method
using SequenceContainersWithArthmeticTypes =
::testing::Types<std::vector<int>,
std::list<float>,
std::forward_list<int>,
std::deque<unsigned short>>;
TYPED_TEST_SUITE(SerializeContainerDynamicSizeArthmeticTypes, SequenceContainersWithArthmeticTypes,);
TYPED_TEST_SUITE(SerializeContainerDynamicSizeArthmeticTypes,
SequenceContainersWithArthmeticTypes, );
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, Values) {
SerializationContext ctx{};
using TValue = typename TestFixture::TValue;
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, Values)
{
SerializationContext ctx{};
using TValue = typename TestFixture::TValue;
ctx.createSerializer().container<sizeof(TValue)>(this->src, 1000);
ctx.createDeserializer().container<sizeof(TValue)>(this->res, 1000);
ctx.createSerializer().container<sizeof(TValue)>(this->src, 1000);
ctx.createDeserializer().container<sizeof(TValue)>(this->res, 1000);
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
}
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, CustomFunctionIncrements) {
SerializationContext ctx{};
using TValue = typename TestFixture::TValue;
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes,
CustomFunctionIncrements)
{
SerializationContext ctx{};
using TValue = typename TestFixture::TValue;
auto& ser = ctx.createSerializer();
ser.container(this->src, 1000, [](decltype(ser)& ser, TValue& v) {
ser.template value<sizeof(v)>(v);
});
auto& des = ctx.createDeserializer();
des.container(this->res, 1000, [](decltype(des)& des, TValue &v) {
des.template value<sizeof(v)>(v);
//increment by 1 after reading
v++;
});
//decrement result by 1, before comparing for eq
for (auto &v:this->res)
v = static_cast<TValue>(v-1);
auto& ser = ctx.createSerializer();
ser.container(this->src, 1000, [](decltype(ser)& ser, TValue& v) {
ser.template value<sizeof(v)>(v);
});
auto& des = ctx.createDeserializer();
des.container(this->res, 1000, [](decltype(des)& des, TValue& v) {
des.template value<sizeof(v)>(v);
// increment by 1 after reading
v++;
});
// decrement result by 1, before comparing for eq
for (auto& v : this->res)
v = static_cast<TValue>(v - 1);
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
}
template<typename T>
class SerializeContainerDynamicSizeCompositeTypes : public testing::Test {
public:
using TContainer = T;
using TValue = typename T::value_type;
const TContainer src = getFilledContainer<TContainer>();
TContainer res{};
size_t getExpectedBufSize(const SerializationContext &ctx) const {
return ctx.containerSizeSerializedBytesCount(src.size()) + src.size() * TValue::SIZE;
}
};
using SerializeContainerDynamicSizeWithCompositeTypes = ::testing::Types<
std::vector<MyStruct1>,
std::list<MyStruct2>>;
TYPED_TEST_SUITE(SerializeContainerDynamicSizeCompositeTypes, SerializeContainerDynamicSizeWithCompositeTypes,);
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes, DefaultSerializeFunction) {
SerializationContext ctx{};
ctx.createSerializer().container(this->src, 1000);
ctx.createDeserializer().container(this->res, 1000);
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
}
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes, CustomFunctionThatDoNothing) {
SerializationContext ctx{};
ctx.createSerializer().container(this->src, 1000, EmptyFtor{});
ctx.createDeserializer().container(this->res, 1000, EmptyFtor{});
EXPECT_THAT(ctx.getBufferSize(), Eq(ctx.containerSizeSerializedBytesCount(this->src.size())));
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
}
template<typename T>
class SerializeContainerFixedSizeArithmeticTypes : public testing::Test {
class SerializeContainerDynamicSizeCompositeTypes : public testing::Test
{
public:
using TContainer = T;
using TContainer = T;
using TValue = typename T::value_type;
size_t getContainerSize() {
T tmp{};
return static_cast<size_t>(std::distance(std::begin(tmp), std::end(tmp)));
}
const TContainer src = getFilledContainer<TContainer>();
TContainer res{};
size_t getExpectedBufSize(const SerializationContext& ctx) const
{
return ctx.containerSizeSerializedBytesCount(src.size()) +
src.size() * TValue::SIZE;
}
};
using StaticContainersWithIntegralTypes = ::testing::Types<
std::array<int16_t, 4>,
int16_t[4]>;
using SerializeContainerDynamicSizeWithCompositeTypes =
::testing::Types<std::vector<MyStruct1>, std::list<MyStruct2>>;
TYPED_TEST_SUITE(SerializeContainerFixedSizeArithmeticTypes, StaticContainersWithIntegralTypes,);
TYPED_TEST_SUITE(SerializeContainerDynamicSizeCompositeTypes,
SerializeContainerDynamicSizeWithCompositeTypes, );
TYPED_TEST(SerializeContainerFixedSizeArithmeticTypes, ArithmeticValues) {
using Container = typename TestFixture::TContainer;
Container src{5, 9, 15, -459};
Container res{};
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes,
DefaultSerializeFunction)
{
SerializationContext ctx{};
SerializationContext ctx;
ctx.createSerializer().container<2>(src);
ctx.createDeserializer().container<2>(res);
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * 2));
EXPECT_THAT(res, ContainerEq(src));
ctx.createSerializer().container(this->src, 1000);
ctx.createDeserializer().container(this->res, 1000);
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
}
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes,
CustomFunctionThatDoNothing)
{
SerializationContext ctx{};
ctx.createSerializer().container(this->src, 1000, EmptyFtor{});
ctx.createDeserializer().container(this->res, 1000, EmptyFtor{});
EXPECT_THAT(ctx.getBufferSize(),
Eq(ctx.containerSizeSerializedBytesCount(this->src.size())));
}
template<typename T>
class SerializeContainerFixedSizeCompositeTypes : public SerializeContainerFixedSizeArithmeticTypes<T> {
class SerializeContainerFixedSizeArithmeticTypes : public testing::Test
{
public:
using TContainer = T;
size_t getContainerSize()
{
T tmp{};
return static_cast<size_t>(std::distance(std::begin(tmp), std::end(tmp)));
}
};
using StaticContainersWithCompositeTypes = ::testing::Types<
std::array<MyStruct1, 4>, MyStruct1[4]>;
using StaticContainersWithIntegralTypes =
::testing::Types<std::array<int16_t, 4>, int16_t[4]>;
TYPED_TEST_SUITE(SerializeContainerFixedSizeCompositeTypes, StaticContainersWithCompositeTypes,);
TYPED_TEST_SUITE(SerializeContainerFixedSizeArithmeticTypes,
StaticContainersWithIntegralTypes, );
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, DefaultSerializationFunction) {
using Container = typename TestFixture::TContainer;
Container src{MyStruct1{0, 1}, MyStruct1{8, 9}, MyStruct1{11, 34}, MyStruct1{5134, 1532}};
Container res{};
TYPED_TEST(SerializeContainerFixedSizeArithmeticTypes, ArithmeticValues)
{
using Container = typename TestFixture::TContainer;
Container src{ 5, 9, 15, -459 };
Container res{};
SerializationContext ctx{};
ctx.createSerializer().container(src);
ctx.createDeserializer().container(res);
SerializationContext ctx;
ctx.createSerializer().container<2>(src);
ctx.createDeserializer().container<2>(res);
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * MyStruct1::SIZE));
EXPECT_THAT(res, ContainerEq(src));
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * 2));
EXPECT_THAT(res, ContainerEq(src));
}
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, CustomFunctionThatSerializesAnEmptyByteEveryElement) {
using Container = typename TestFixture::TContainer;
Container src{MyStruct1{0, 1}, MyStruct1{2, 3}, MyStruct1{4, 5}, MyStruct1{5134, 1532}};
Container res{};
template<typename T>
class SerializeContainerFixedSizeCompositeTypes
: public SerializeContainerFixedSizeArithmeticTypes<T>
{};
using TValue = decltype(*std::begin(res));
using StaticContainersWithCompositeTypes =
::testing::Types<std::array<MyStruct1, 4>, MyStruct1[4]>;
SerializationContext ctx{};
auto& ser = ctx.createSerializer();
ser.container(src, [](decltype(ser)& ser, TValue &v) {
char tmp{};
ser.object(v);
ser.value1b(tmp);
});
auto& des = ctx.createDeserializer();
des.container(res, [](decltype(des)& des, TValue &v) {
char tmp{};
des.object(v);
des.value1b(tmp);
});
TYPED_TEST_SUITE(SerializeContainerFixedSizeCompositeTypes,
StaticContainersWithCompositeTypes, );
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * (MyStruct1::SIZE + sizeof(char))));
EXPECT_THAT(res, ContainerEq(src));
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes,
DefaultSerializationFunction)
{
using Container = typename TestFixture::TContainer;
Container src{ MyStruct1{ 0, 1 },
MyStruct1{ 8, 9 },
MyStruct1{ 11, 34 },
MyStruct1{ 5134, 1532 } };
Container res{};
SerializationContext ctx{};
ctx.createSerializer().container(src);
ctx.createDeserializer().container(res);
EXPECT_THAT(ctx.getBufferSize(),
Eq(this->getContainerSize() * MyStruct1::SIZE));
EXPECT_THAT(res, ContainerEq(src));
}
class SerializeContainer : public ::testing::TestWithParam<size_t> {
};
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes,
CustomFunctionThatSerializesAnEmptyByteEveryElement)
{
using Container = typename TestFixture::TContainer;
Container src{ MyStruct1{ 0, 1 },
MyStruct1{ 2, 3 },
MyStruct1{ 4, 5 },
MyStruct1{ 5134, 1532 } };
Container res{};
TEST_P(SerializeContainer, SizeHasVariableLength) {
SerializationContext ctx{};
using TValue = decltype(*std::begin(res));
std::vector<uint8_t > src(GetParam());
std::vector<uint8_t > res{};
ctx.createSerializer().container(src, std::numeric_limits<size_t>::max(), EmptyFtor{});
ctx.createDeserializer().container(res, std::numeric_limits<size_t>::max(), EmptyFtor{});
SerializationContext ctx{};
auto& ser = ctx.createSerializer();
ser.container(src, [](decltype(ser)& ser, TValue& v) {
char tmp{};
ser.object(v);
ser.value1b(tmp);
});
auto& des = ctx.createDeserializer();
des.container(res, [](decltype(des)& des, TValue& v) {
char tmp{};
des.object(v);
des.value1b(tmp);
});
EXPECT_THAT(res.size(), Eq(src.size()));
EXPECT_THAT(ctx.getBufferSize(), Eq(ctx.containerSizeSerializedBytesCount(src.size())));
EXPECT_THAT(ctx.getBufferSize(),
Eq(this->getContainerSize() * (MyStruct1::SIZE + sizeof(char))));
EXPECT_THAT(res, ContainerEq(src));
}
INSTANTIATE_TEST_SUITE_P(LargeContainerSize, SerializeContainer, ::testing::Values(0x01, 0x80, 0x4000));
class SerializeContainer : public ::testing::TestWithParam<size_t>
{};
TEST_P(SerializeContainer, SizeHasVariableLength)
{
SerializationContext ctx{};
std::vector<uint8_t> src(GetParam());
std::vector<uint8_t> res{};
ctx.createSerializer().container(
src, std::numeric_limits<size_t>::max(), EmptyFtor{});
ctx.createDeserializer().container(
res, std::numeric_limits<size_t>::max(), EmptyFtor{});
EXPECT_THAT(res.size(), Eq(src.size()));
EXPECT_THAT(ctx.getBufferSize(),
Eq(ctx.containerSizeSerializedBytesCount(src.size())));
}
INSTANTIATE_TEST_SUITE_P(LargeContainerSize,
SerializeContainer,
::testing::Values(0x01, 0x80, 0x4000));

View File

@@ -1,28 +1,27 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 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:
// 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 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.
// 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.
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::Eq;
@@ -31,78 +30,89 @@ using bitsery::DefaultConfig;
using SingleTypeContext = int;
using MultipleTypesContext = std::tuple<int, float, char>;
TEST(SerializationContext, WhenContextIsNotTupleThenReturnThisContext) {
SingleTypeContext ctx{54};
BasicSerializationContext<SingleTypeContext> c1;
auto& ser1 = c1.createSerializer(ctx);
TEST(SerializationContext, WhenContextIsNotTupleThenReturnThisContext)
{
SingleTypeContext ctx{ 54 };
BasicSerializationContext<SingleTypeContext> c1;
auto& ser1 = c1.createSerializer(ctx);
EXPECT_THAT(ser1.context<SingleTypeContext>(), Eq(ctx));
EXPECT_THAT(ser1.context<SingleTypeContext>(), Eq(ctx));
}
TEST(SerializationContext, WhenContextIsTupleThenReturnsTupleElements) {
TEST(SerializationContext, WhenContextIsTupleThenReturnsTupleElements)
{
MultipleTypesContext ctx{5, 798.654f, 'F'};
BasicSerializationContext<MultipleTypesContext> c1;
auto& ser1 = c1.createSerializer(ctx);
MultipleTypesContext ctx{ 5, 798.654f, 'F' };
BasicSerializationContext<MultipleTypesContext> c1;
auto& ser1 = c1.createSerializer(ctx);
EXPECT_THAT(ser1.context<int>(), std::get<0>(ctx));
EXPECT_THAT(ser1.context<float>(), std::get<1>(ctx));
EXPECT_THAT(ser1.context<char>(), std::get<2>(ctx));
EXPECT_THAT(ser1.context<int>(), std::get<0>(ctx));
EXPECT_THAT(ser1.context<float>(), std::get<1>(ctx));
EXPECT_THAT(ser1.context<char>(), std::get<2>(ctx));
}
TEST(SerializationContext, WhenContextDoesntExistsThenContextOrNullReturnsNull) {
SingleTypeContext ctx1= 32;
BasicSerializationContext<SingleTypeContext> c1;
TEST(SerializationContext, WhenContextDoesntExistsThenContextOrNullReturnsNull)
{
SingleTypeContext ctx1 = 32;
BasicSerializationContext<SingleTypeContext> c1;
auto& ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.contextOrNull<char>(), ::testing::IsNull());
EXPECT_THAT(ser.contextOrNull<int>(), ::testing::NotNull());
*ser.contextOrNull<int>() = 2;
EXPECT_THAT(ctx1, Eq(2));
MultipleTypesContext ctx2{ 5, 798.654f, 'F' };
BasicSerializationContext<MultipleTypesContext> c2;
auto& des = c2.createDeserializer(ctx2);
EXPECT_THAT(des.contextOrNull<double>(), ::testing::IsNull());
EXPECT_THAT(des.contextOrNull<int>(), ::testing::NotNull());
EXPECT_THAT(*des.contextOrNull<char>(), Eq('F'));
EXPECT_THAT(*des.contextOrNull<int>(), Eq(5));
}
struct Base
{
int value{};
};
struct Derived : Base
{};
TEST(SerializationContext, ContextWillTryToConvertIfTypeIsConvertible)
{
Derived ctx1{};
BasicSerializationContext<Derived> c1;
auto& ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.contextOrNull<Derived>(), ::testing::NotNull());
EXPECT_THAT(ser.contextOrNull<Base>(), ::testing::NotNull());
ser.context<Derived>();
ser.context<Base>();
}
TEST(SerializationContext,
WhenMultipleConvertibleTypesExistsThenFirstMatchIsTaken)
{
{
using CTX1 = std::tuple<Base, int, Derived>;
CTX1 ctx1{};
std::get<0>(ctx1).value = 1;
std::get<2>(ctx1).value = 2;
BasicSerializationContext<CTX1> c1;
auto& ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.contextOrNull<char>(), ::testing::IsNull());
EXPECT_THAT(ser.contextOrNull<int>(), ::testing::NotNull());
*ser.contextOrNull<int>() = 2;
EXPECT_THAT(ctx1, Eq(2));
EXPECT_THAT(ser.context<Derived>().value, Eq(std::get<2>(ctx1).value));
EXPECT_THAT(ser.context<Base>().value, Eq(std::get<0>(ctx1).value));
}
MultipleTypesContext ctx2{5, 798.654f, 'F'};
BasicSerializationContext<MultipleTypesContext> c2;
auto& des = c2.createDeserializer(ctx2);
EXPECT_THAT(des.contextOrNull<double>(), ::testing::IsNull());
EXPECT_THAT(des.contextOrNull<int>(), ::testing::NotNull());
EXPECT_THAT(*des.contextOrNull<char>(), Eq('F'));
EXPECT_THAT(*des.contextOrNull<int>(), Eq(5));
}
struct Base { int value{}; };
struct Derived: Base{};
TEST(SerializationContext, ContextWillTryToConvertIfTypeIsConvertible) {
Derived ctx1{};
BasicSerializationContext<Derived> c1;
auto& ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.contextOrNull<Derived>(), ::testing::NotNull());
EXPECT_THAT(ser.contextOrNull<Base>(), ::testing::NotNull());
ser.context<Derived>();
ser.context<Base>();
}
TEST(SerializationContext, WhenMultipleConvertibleTypesExistsThenFirstMatchIsTaken) {
{
using CTX1 = std::tuple<Base, int, Derived>;
CTX1 ctx1{};
std::get<0>(ctx1).value = 1;
std::get<2>(ctx1).value = 2;
BasicSerializationContext<CTX1> c1;
auto& ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.context<Derived>().value, Eq(std::get<2>(ctx1).value));
EXPECT_THAT(ser.context<Base>().value, Eq(std::get<0>(ctx1).value));
}
{
using CTX2 = std::tuple<float, Derived, Base>;
CTX2 ctx2{};
std::get<1>(ctx2).value = 1;
std::get<2>(ctx2).value = 2;
BasicSerializationContext<CTX2> c2;
auto& des = c2.createSerializer(ctx2);
EXPECT_THAT(des.context<Derived>().value, Eq(std::get<1>(ctx2).value));
//Base will not be accessable in this case, because Derived is first valid match
EXPECT_THAT(des.context<Base>().value, Eq(std::get<1>(ctx2).value));
}
{
using CTX2 = std::tuple<float, Derived, Base>;
CTX2 ctx2{};
std::get<1>(ctx2).value = 1;
std::get<2>(ctx2).value = 2;
BasicSerializationContext<CTX2> c2;
auto& des = c2.createSerializer(ctx2);
EXPECT_THAT(des.context<Derived>().value, Eq(std::get<1>(ctx2).value));
// Base will not be accessable in this case, because Derived is first valid
// match
EXPECT_THAT(des.context<Base>().value, Eq(std::get<1>(ctx2).value));
}
}

Some files were not shown because too many files have changed in this diff Show More