mirror of
https://github.com/fraillt/bitsery.git
synced 2026-06-19 21:59:05 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bebfd4911 | ||
|
|
5e7ecede9b | ||
|
|
ff841d63f6 | ||
|
|
66d16516e2 | ||
|
|
7ea1da0d48 | ||
|
|
8bda82576e | ||
|
|
ee992d8b57 | ||
|
|
4dcdd594da | ||
|
|
b714459a2b | ||
|
|
be2f295310 | ||
|
|
cd73aca2f5 | ||
|
|
94f7adaf6c | ||
|
|
ceeb189c8b | ||
|
|
90243480ec | ||
|
|
d1a47e06e2 | ||
|
|
3e02d0ca44 | ||
|
|
d690908541 | ||
|
|
d3dd64baaf | ||
|
|
d24e0ab1b3 |
192
.clang-format
Normal file
192
.clang-format
Normal 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
8
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
github: fraillt
|
||||||
|
buy_me_a_coffee: fraillt
|
||||||
|
custom:
|
||||||
|
- "https://www.paypal.com/paypalme/fraillt"
|
||||||
|
- "https://explorer.solana.com/address/5uHU32nBuniRxg6RZu4tsLWrXGFFz4pwMGHGuCLmkGJQ"
|
||||||
|
- "https://etherscan.io/address/0xe51cb417d1BFcd3EE4cfad9fa11b05631823AADb"
|
||||||
|
- "https://polygonscan.com/address/0xe51cb417d1BFcd3EE4cfad9fa11b05631823AADb"
|
||||||
32
.github/workflows/on_linux.yml
vendored
32
.github/workflows/on_linux.yml
vendored
@@ -9,54 +9,38 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: ${{ matrix.config.name }}
|
name: ${{ matrix.config.name }}
|
||||||
runs-on: ubuntu-18.04
|
runs-on: ubuntu-24.04
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
config:
|
config:
|
||||||
- name: "Ubuntu 18.04 with Clang 3.9"
|
- name: "Ubuntu Latest with GCC 14"
|
||||||
cxx_ver: 11
|
|
||||||
compiler: clang
|
|
||||||
compiler_ver: 3.9
|
|
||||||
- name: "Ubuntu 18.04 with GCC 5.0"
|
|
||||||
cxx_ver: 11
|
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
compiler_ver: 5
|
compiler_ver: 14
|
||||||
- name: "Ubuntu 18.04 with GCC 11.0"
|
- name: "Ubuntu Latests with Clang 18"
|
||||||
cxx_ver: 17
|
|
||||||
compiler: gcc
|
|
||||||
compiler_ver: 11
|
|
||||||
- name: "Ubuntu 18.04 with Clang 13"
|
|
||||||
cxx_ver: 17
|
|
||||||
compiler: clang
|
compiler: clang
|
||||||
compiler_ver: 13
|
compiler_ver: 18
|
||||||
steps:
|
steps:
|
||||||
- name: Prepare specific Clang version
|
- name: Prepare specific Clang version
|
||||||
if: ${{ matrix.config.compiler == 'clang' }}
|
if: ${{ matrix.config.compiler == 'clang' }}
|
||||||
run: |
|
run: |
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
|
||||||
sudo apt-add-repository "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-13 main"
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install clang-${{ matrix.config.compiler_ver}}
|
sudo apt install clang-${{ matrix.config.compiler_ver}}
|
||||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${{ matrix.config.compiler_ver}} 100
|
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${{ matrix.config.compiler_ver}} 100
|
||||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${{ matrix.config.compiler_ver}} 100
|
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${{ matrix.config.compiler_ver}} 100
|
||||||
- name: Prepare specific GCC version
|
- name: Prepare specific GCC version
|
||||||
if: ${{ matrix.config.compiler == 'gcc' }}
|
if: ${{ matrix.config.compiler == 'gcc' }}
|
||||||
run: |
|
run: |
|
||||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
|
|
||||||
sudo apt update
|
|
||||||
sudo apt install g++-${{ matrix.config.compiler_ver}}
|
sudo apt install g++-${{ matrix.config.compiler_ver}}
|
||||||
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-${{ matrix.config.compiler_ver}} 100
|
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-${{ matrix.config.compiler_ver}} 100
|
||||||
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-${{ matrix.config.compiler_ver}} 100
|
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-${{ matrix.config.compiler_ver}} 100
|
||||||
- name: Installing GTest
|
- name: Installing GTest
|
||||||
run: |
|
run: |
|
||||||
sudo add-apt-repository ppa:team-xbmc/ppa
|
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install libgmock-dev
|
sudo apt-get install libgmock-dev
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=${{ matrix.config.cxx_ver }}
|
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build
|
run: cmake --build build
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: ctest --test-dir build/tests
|
run: ctest --test-dir build
|
||||||
|
|||||||
8
.github/workflows/on_mac.yml
vendored
8
.github/workflows/on_mac.yml
vendored
@@ -14,13 +14,13 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
git clone https://github.com/google/googletest.git
|
git clone https://github.com/google/googletest.git
|
||||||
cd googletest
|
cd googletest
|
||||||
git checkout release-1.11.0
|
git checkout v1.14.0
|
||||||
cmake -S . -B build
|
cmake -S . -B build
|
||||||
cmake --build build --target install
|
sudo cmake --build build --target install
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17
|
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build
|
run: cmake --build build
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: ctest --test-dir build/tests
|
run: ctest --test-dir build
|
||||||
|
|||||||
6
.github/workflows/on_windows.yml
vendored
6
.github/workflows/on_windows.yml
vendored
@@ -15,10 +15,10 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
git clone https://github.com/google/googletest.git
|
git clone https://github.com/google/googletest.git
|
||||||
cd googletest
|
cd googletest
|
||||||
git checkout release-1.11.0
|
git checkout v1.14.0
|
||||||
cmake -S . -B build -Dgtest_force_shared_crt=ON
|
cmake -S . -B build -Dgtest_force_shared_crt=ON
|
||||||
cmake --build build --config Release --target install
|
cmake --build build --config Release --target install
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v3
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_FLAGS="/Zc:__cplusplus /permissive- /EHsc"
|
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:
|
env:
|
||||||
@@ -26,4 +26,4 @@ jobs:
|
|||||||
- name: Build
|
- name: Build
|
||||||
run: cmake --build build --config Release
|
run: cmake --build build --config Release
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: ctest --test-dir build/tests
|
run: ctest --test-dir build
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
.idea/
|
.idea/
|
||||||
.vs/
|
.vs/
|
||||||
|
.vscode/
|
||||||
build/
|
build/
|
||||||
cmake-build-*
|
cmake-build-*
|
||||||
CTestConfig.cmake
|
CTestConfig.cmake
|
||||||
|
|||||||
70
.travis.yml
70
.travis.yml
@@ -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
|
|
||||||
37
CHANGELOG.md
37
CHANGELOG.md
@@ -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)
|
# [5.2.2](https://github.com/fraillt/bitsery/compare/v5.2.1...v5.2.2) (2021-08-31)
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
cmake_minimum_required(VERSION 3.1)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(bitsery
|
project(bitsery
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
VERSION 5.2.2)
|
VERSION 5.2.5)
|
||||||
|
|
||||||
#======== build options ===================================
|
#======== build options ===================================
|
||||||
option(BITSERY_BUILD_EXAMPLES "Build examples" OFF)
|
option(BITSERY_BUILD_EXAMPLES "Build examples" OFF)
|
||||||
@@ -51,6 +51,7 @@ endif()
|
|||||||
|
|
||||||
if (BITSERY_BUILD_TESTS)
|
if (BITSERY_BUILD_TESTS)
|
||||||
message("build bitsery tests")
|
message("build bitsery tests")
|
||||||
|
enable_testing()
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
else()
|
else()
|
||||||
message("skip bitsery tests")
|
message("skip bitsery tests")
|
||||||
|
|||||||
10
README.md
10
README.md
@@ -102,9 +102,13 @@ Works with C++11 compiler, no additional dependencies, include `<bitsery/bitsery
|
|||||||
|
|
||||||
Library is tested on all major compilers on Windows, Linux and macOS.
|
Library is tested on all major compilers on Windows, Linux and macOS.
|
||||||
|
|
||||||
There is a patch that allows using bitsery with non-fully compatible C++11 compilers.
|
|
||||||
* CentOS 7 with gcc 4.8.2.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
**bitsery** is licensed under the [MIT license](LICENSE).
|
**bitsery** is licensed under the [MIT license](LICENSE).
|
||||||
|
|
||||||
|
## 💖 Sponsor Me?
|
||||||
|
|
||||||
|
If you find this project useful or interesting, or just want to say thanks, you can buy me a coffee!
|
||||||
|
Your support keeps me motivated to maintaining and improving this project.
|
||||||
|
|
||||||
|
[**Thank you!**](https://github.com/sponsors/fraillt)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
#SOFTWARE.
|
#SOFTWARE.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.1)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(bitsery_examples CXX)
|
project(bitsery_examples CXX)
|
||||||
|
|
||||||
if (NOT TARGET Bitsery::bitsery)
|
if (NOT TARGET Bitsery::bitsery)
|
||||||
|
|||||||
@@ -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>
|
#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>
|
#include <bitsery/adapter/buffer.h>
|
||||||
//bitsery itself doesn't is lightweight, and doesnt include any unnessessary files,
|
// bitsery itself doesn't is lightweight, and doesnt include any unnessessary
|
||||||
//traits helps library to know how to use types correctly,
|
// files, traits helps library to know how to use types correctly, in this case
|
||||||
//in this case we'll be using vector both, to serialize/deserialize data and to store use as a buffer.
|
// we'll be using vector both, to serialize/deserialize data and to store use as
|
||||||
|
// a buffer.
|
||||||
#include <bitsery/traits/vector.h>
|
#include <bitsery/traits/vector.h>
|
||||||
|
|
||||||
enum class MyEnum:uint16_t { V1,V2,V3 };
|
enum class MyEnum : uint16_t
|
||||||
struct MyStruct {
|
{
|
||||||
uint32_t i;
|
V1,
|
||||||
MyEnum e;
|
V2,
|
||||||
std::vector<float> fs;
|
V3
|
||||||
|
};
|
||||||
|
struct MyStruct
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
MyEnum e;
|
||||||
|
std::vector<float> fs;
|
||||||
};
|
};
|
||||||
|
|
||||||
//define how object should be serialized/deserialized
|
// define how object should be serialized/deserialized
|
||||||
template <typename S>
|
template<typename S>
|
||||||
void serialize(S& s, MyStruct& o) {
|
void
|
||||||
s.value4b(o.i);//fundamental types (ints, floats, enums) of size 4b
|
serialize(S& s, MyStruct& o)
|
||||||
s.value2b(o.e);
|
{
|
||||||
s.container4b(o.fs, 10);//resizable containers also requires maxSize, to make it safe from buffer-overflow attacks
|
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 Buffer = std::vector<uint8_t>;
|
||||||
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
int main() {
|
int
|
||||||
//set some random data
|
main()
|
||||||
MyStruct data{8941, MyEnum::V2, {15.0f, -8.5f, 0.045f}};
|
{
|
||||||
MyStruct res{};
|
// set some random data
|
||||||
|
MyStruct data{ 8941, MyEnum::V2, { 15.0f, -8.5f, 0.045f } };
|
||||||
|
MyStruct res{};
|
||||||
|
|
||||||
//create buffer to store data
|
// create buffer to store data
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
//use quick serialization function,
|
// use quick serialization function,
|
||||||
//it will use default configuration to setup all the nesessary steps
|
// it will use default configuration to setup all the nesessary steps
|
||||||
//and serialize data to container
|
// and serialize data to container
|
||||||
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
||||||
|
|
||||||
//same as serialization, but returns deserialization state as a pair
|
// same as serialization, but returns deserialization state as a pair
|
||||||
//first = error code, second = is buffer was successfully read from begin to the end.
|
// first = error code, second = is buffer was successfully read from begin to
|
||||||
auto state = bitsery::quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
|
// the end.
|
||||||
|
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);
|
||||||
assert(data.fs == res.fs && data.i == res.i && data.e == res.e);
|
assert(data.fs == res.fs && data.i == res.i && data.e == res.e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,62 +1,74 @@
|
|||||||
#include <bitsery/bitsery.h>
|
|
||||||
#include <bitsery/adapter/buffer.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/array.h>
|
||||||
#include <bitsery/traits/string.h>
|
#include <bitsery/traits/string.h>
|
||||||
#include <bitsery/traits/vector.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>
|
#include <bitsery/ext/value_range.h>
|
||||||
|
|
||||||
namespace MyTypes {
|
namespace MyTypes {
|
||||||
|
|
||||||
struct Vec3 { float x, y, z; };
|
struct Vec3
|
||||||
|
{
|
||||||
|
float x, y, z;
|
||||||
|
};
|
||||||
|
|
||||||
struct Monster {
|
struct Monster
|
||||||
Vec3 pos;
|
{
|
||||||
std::vector<Vec3> path;
|
Vec3 pos;
|
||||||
std::string name;
|
std::vector<Vec3> path;
|
||||||
};
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
void serialize(S& s, MyTypes::Vec3 &o) {
|
void
|
||||||
s.value4b(o.x);
|
serialize(S& s, MyTypes::Vec3& o)
|
||||||
s.value4b(o.y);
|
{
|
||||||
s.value4b(o.z);
|
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//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 Buffer = std::array<uint8_t, 10000>;
|
||||||
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
int main() {
|
int
|
||||||
//set some random data
|
main()
|
||||||
MyTypes::Monster data{};
|
{
|
||||||
data.name = "lew";
|
// set some random data
|
||||||
|
MyTypes::Monster data{};
|
||||||
|
data.name = "lew";
|
||||||
|
|
||||||
//create buffer to store data to
|
// create buffer to store data to
|
||||||
Buffer buffer{};
|
Buffer buffer{};
|
||||||
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
||||||
|
|
||||||
MyTypes::Monster res{};
|
MyTypes::Monster res{};
|
||||||
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(state.first == bitsery::ReaderError::NoError && state.second);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +1,54 @@
|
|||||||
#include <bitsery/bitsery.h>
|
|
||||||
#include <bitsery/adapter/buffer.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>
|
#include <bitsery/brief_syntax.h>
|
||||||
//we also need additional traits to work with container types,
|
// 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.
|
// instead of including <bitsery/traits/vector.h> for vector traits, now we also
|
||||||
//so include everything from <bitsery/brief_syntax/...> instead of <bitsery/traits/...>
|
// need traits to work with brief_syntax types. so include everything from
|
||||||
//otherwise we'll get static assert error, saying to define serialize function.
|
// <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>
|
#include <bitsery/brief_syntax/vector.h>
|
||||||
|
|
||||||
enum class MyEnum:uint16_t { V1,V2,V3 };
|
enum class MyEnum : uint16_t
|
||||||
struct MyStruct {
|
{
|
||||||
uint32_t i;
|
V1,
|
||||||
MyEnum e;
|
V2,
|
||||||
std::vector<float> fs;
|
V3
|
||||||
|
};
|
||||||
//define serialize function as usual
|
struct MyStruct
|
||||||
template <typename S>
|
{
|
||||||
void serialize(S& s) {
|
uint32_t i;
|
||||||
//now we can use brief syntax with
|
MyEnum e;
|
||||||
s(i, e, fs);
|
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 Buffer = std::vector<uint8_t>;
|
||||||
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
int main() {
|
int
|
||||||
//set some random data
|
main()
|
||||||
MyStruct data{8941, MyEnum::V2, {15.0f, -8.5f, 0.045f}};
|
{
|
||||||
MyStruct res{};
|
// 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
|
// serialization, deserialization flow is unchanged as in basic usage
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
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(state.first == bitsery::ReaderError::NoError && state.second);
|
||||||
assert(data.fs == res.fs && data.i == res.i && data.e == res.e);
|
assert(data.fs == res.fs && data.i == res.i && data.e == res.e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <bitsery/bitsery.h>
|
|
||||||
#include <bitsery/adapter/buffer.h>
|
#include <bitsery/adapter/buffer.h>
|
||||||
|
#include <bitsery/bitsery.h>
|
||||||
#include <bitsery/traits/vector.h>
|
#include <bitsery/traits/vector.h>
|
||||||
// include extensions to work with tuples and variants
|
// include extensions to work with tuples and variants
|
||||||
// these extesions only work with C++17
|
// these extesions only work with C++17
|
||||||
@@ -10,101 +10,126 @@
|
|||||||
// let's include this extension to make it more interesting :)
|
// let's include this extension to make it more interesting :)
|
||||||
#include <bitsery/ext/compact_value.h>
|
#include <bitsery/ext/compact_value.h>
|
||||||
|
|
||||||
struct MyStruct {
|
struct MyStruct
|
||||||
std::vector<int32_t> v{};
|
{
|
||||||
float f{};
|
std::vector<int32_t> v{};
|
||||||
|
float f{};
|
||||||
|
|
||||||
bool operator==(const MyStruct& rhs) const {
|
bool operator==(const MyStruct& rhs) const
|
||||||
return v == rhs.v && f == rhs.f;
|
{
|
||||||
}
|
return v == rhs.v && f == rhs.f;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
void serialize(S& s, MyStruct& o) {
|
void
|
||||||
s.container4b(o.v, 1000);
|
serialize(S& s, MyStruct& o)
|
||||||
s.value4b(o.f);
|
{
|
||||||
|
s.container4b(o.v, 1000);
|
||||||
|
s.value4b(o.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this will be the type that we want to serialize/deserialize
|
// this will be the type that we want to serialize/deserialize
|
||||||
using MyTuple = std::tuple<float, MyStruct>;
|
using MyTuple = std::tuple<float, MyStruct>;
|
||||||
using MyVariant = std::variant<int64_t, MyTuple, 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>
|
template<typename S>
|
||||||
void serialize(S& s, MyVariant& o) {
|
void
|
||||||
// in order to serialize a variant, it needs to know how to do it for all types
|
serialize(S& s, MyVariant& o)
|
||||||
// we can do this simply by providing any callable object, that accepts serializer and type as arguments
|
{
|
||||||
s.ext(o, bitsery::ext::StdVariant{
|
// in order to serialize a variant, it needs to know how to do it for all
|
||||||
// specify how to serialize tuple by creating a lambda
|
// types we can do this simply by providing any callable object, that accepts
|
||||||
[](S& s, MyTuple& o) {
|
// serializer and type as arguments
|
||||||
// StdTuple is used exactly the same as StdVariant
|
s.ext(
|
||||||
s.ext(o, bitsery::ext::StdTuple{
|
o,
|
||||||
// this is convenient callable object to specify integral value size
|
bitsery::ext::StdVariant{
|
||||||
// it is different equivalent to lambda [](auto& s, float&o) { s.value4b(o);}
|
// specify how to serialize tuple by creating a lambda
|
||||||
bitsery::ext::OverloadValue<float, 4>{},
|
[](S& s, MyTuple& o) {
|
||||||
// it is not required to provide MyStruct overload, because it we have defined 'serialize' function for it
|
// StdTuple is used exactly the same as StdVariant
|
||||||
});
|
s.ext(
|
||||||
},
|
o,
|
||||||
// this might also be useful if you want to overload using extension
|
bitsery::ext::StdTuple{
|
||||||
bitsery::ext::OverloadExtValue<int64_t, 8, bitsery::ext::CompactValue>{},
|
// this is convenient callable object to specify integral value size
|
||||||
// you can even go further and instead of writing lambda for MyTuple you can as well compose the same functionality
|
// it is different equivalent to lambda [](auto& s, float&o) {
|
||||||
// with OverloadExtObject, like this:
|
// s.value4b(o);}
|
||||||
// (comment out MyTuple lambda, and uncomment this)
|
bitsery::ext::OverloadValue<float, 4>{},
|
||||||
// ext::OverloadExtObject<MyTuple, ext::StdTuple<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
|
// we can also override default 'serialize' function by creating an
|
||||||
[](S& s, MyStruct& o) {
|
// overloading for that type
|
||||||
s.value4b(o.f);
|
[](S& s, MyStruct& o) {
|
||||||
s.container(o.v, 1000, [](S& s, int32_t& v) {
|
s.value4b(o.f);
|
||||||
s.ext4b(v, bitsery::ext::CompactValue{});
|
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
|
// NOTE.
|
||||||
// this will allow you to override all default 'serialize' functions
|
// it is possible to provide "auto" as type parameter
|
||||||
// but in this case it will not be called, because we have explicitly provided overloads for all variant types
|
// this will allow you to override all default 'serialize' functions
|
||||||
// also note, that first parameter (serializer) is also "auto", this is required, so that it would be least specialized case
|
// but in this case it will not be called, because we have explicitly
|
||||||
// otherwise it will not compile if you any ext::Overload* helper defined, because it will have ambiguous definitions
|
// provided overloads for all variant types
|
||||||
// (ext::OverLoad* defines (templated_type& s, concrete_type& o) and lambda would be (concrete_type& s, templated_type& o))
|
// also note, that first parameter (serializer) is also "auto", this is
|
||||||
[](auto& , auto&) {
|
// required, so that it would be least specialized case
|
||||||
assert(false);
|
// 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 Buffer = std::vector<uint8_t>;
|
||||||
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
int main() {
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
|
||||||
//set some random data
|
// set some random data
|
||||||
MyVariant data{ MyTuple{-7549, {{-451, 2, 968, 75, 4, 156, 49}, 874.4f}} };
|
MyVariant data{ MyTuple{ -7549,
|
||||||
MyVariant res{};
|
{ { -451, 2, 968, 75, 4, 156, 49 }, 874.4f } } };
|
||||||
|
MyVariant res{};
|
||||||
|
|
||||||
//create buffer to store data
|
// create buffer to store data
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
//use quick serialization function,
|
// use quick serialization function,
|
||||||
//it will use default configuration to setup all the nesessary steps
|
// it will use default configuration to setup all the nesessary steps
|
||||||
//and serialize data to container
|
// and serialize data to container
|
||||||
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
||||||
|
|
||||||
//same as serialization, but returns deserialization state as a pair
|
// same as serialization, but returns deserialization state as a pair
|
||||||
//first = error code, second = is buffer was successfully read from begin to the end.
|
// first = error code, second = is buffer was successfully read from begin to
|
||||||
auto state = bitsery::quickDeserialization<InputAdapter>({ buffer.begin(), writtenSize }, res);
|
// the end.
|
||||||
|
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);
|
||||||
assert(data == res);
|
assert(data == res);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#if defined(_MSC_VER)
|
#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
|
#else
|
||||||
#pragma message("C++17 is required to enable this example")
|
#pragma message("C++17 is required to enable this example")
|
||||||
#endif
|
#endif
|
||||||
int main() {
|
int
|
||||||
return 0;
|
main()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#include <bitsery/bitsery.h>
|
|
||||||
#include <bitsery/adapter/buffer.h>
|
#include <bitsery/adapter/buffer.h>
|
||||||
|
#include <bitsery/bitsery.h>
|
||||||
|
|
||||||
#include <bitsery/traits/string.h>
|
#include <bitsery/traits/string.h>
|
||||||
#include <bitsery/traits/vector.h>
|
#include <bitsery/traits/vector.h>
|
||||||
@@ -8,91 +8,106 @@
|
|||||||
|
|
||||||
namespace MyTypes {
|
namespace MyTypes {
|
||||||
|
|
||||||
struct Monster {
|
struct Monster
|
||||||
Monster() = default;
|
{
|
||||||
Monster(std::string _name, uint32_t minDmg, uint32_t maxDmg)
|
Monster() = default;
|
||||||
:name{_name}, minDamage{minDmg}, maxDamage{maxDmg} {}
|
Monster(std::string _name, uint32_t minDmg, uint32_t maxDmg)
|
||||||
|
: name{ _name }
|
||||||
|
, minDamage{ minDmg }
|
||||||
|
, maxDamage{ maxDmg }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
std::string name{};
|
std::string name{};
|
||||||
uint32_t minDamage{};
|
uint32_t minDamage{};
|
||||||
uint32_t maxDamage{};
|
uint32_t maxDamage{};
|
||||||
//...
|
//...
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GameState {
|
struct GameState
|
||||||
std::vector<Monster> monsters;
|
{
|
||||||
};
|
std::vector<Monster> monsters;
|
||||||
|
};
|
||||||
|
|
||||||
//default flow for monster
|
// default flow for monster
|
||||||
template <typename S>
|
template<typename S>
|
||||||
void serialize (S& s, Monster& o) {
|
void
|
||||||
s.text1b(o.name, 20);
|
serialize(S& s, Monster& o)
|
||||||
s.value4b(o.minDamage);
|
{
|
||||||
s.value4b(o.maxDamage);
|
s.text1b(o.name, 20);
|
||||||
}
|
s.value4b(o.minDamage);
|
||||||
|
s.value4b(o.maxDamage);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
void serialize(S& s, GameState &o) {
|
void
|
||||||
//we can have multiple types in context with std::tuple
|
serialize(S& s, GameState& o)
|
||||||
//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
|
// we can have multiple types in context with std::tuple
|
||||||
auto maxMonsters = s.template context<int>();
|
// if data type doesn't match then it will be compile time error
|
||||||
auto& dmgRange = s.template context<std::pair<uint32_t, uint32_t>>();
|
// 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.container(o.monsters, maxMonsters, [&dmgRange](S& s, Monster& m) {
|
||||||
s.text1b(m.name, 20);
|
s.text1b(m.name, 20);
|
||||||
//we know min/max damage range for monsters, so we can use this range instead of full value
|
// we know min/max damage range for monsters, so we can use this range
|
||||||
bitsery::ext::ValueRange<uint32_t> range{dmgRange.first, dmgRange.second};
|
// instead of full value
|
||||||
//enable bit packing
|
bitsery::ext::ValueRange<uint32_t> range{ dmgRange.first, dmgRange.second };
|
||||||
s.enableBitPacking([&m, &range](typename S::BPEnabledType& sbp) {
|
// enable bit packing
|
||||||
sbp.ext(m.minDamage, range);
|
s.enableBitPacking([&m, &range](typename S::BPEnabledType& sbp) {
|
||||||
sbp.ext(m.maxDamage, range);
|
sbp.ext(m.minDamage, range);
|
||||||
});
|
sbp.ext(m.maxDamage, range);
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//context can contain multiple types by wrapping these types in std::tuple
|
// context can contain multiple types by wrapping these types in std::tuple
|
||||||
//in serialization function we can get type that we need like this:
|
// in serialization function we can get type that we need like this:
|
||||||
// s.template context<int>();
|
// s.template context<int>();
|
||||||
//this templated version also works if our context is the same as cast:
|
// this templated version also works if our context is the same as cast:
|
||||||
// struct MyContext {...};
|
// struct MyContext {...};
|
||||||
// ...
|
// ...
|
||||||
// s.template context<MyContext>();
|
// s.template context<MyContext>();
|
||||||
//NOTE:
|
// NOTE:
|
||||||
// if your context has no additional usage outside of serialization flow,
|
// if your context has no additional usage outside of serialization flow,
|
||||||
// then you can create it internally via configuration (see inheritance.cpp)
|
// then you can create it internally via configuration (see inheritance.cpp)
|
||||||
using Context = std::tuple<int, std::pair<uint32_t, uint32_t>>;
|
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>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
// define adapter types,
|
// define adapter types,
|
||||||
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
int main() {
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
|
||||||
MyTypes::GameState data{};
|
MyTypes::GameState data{};
|
||||||
data.monsters.push_back({"weaksy", 100, 200});
|
data.monsters.push_back({ "weaksy", 100, 200 });
|
||||||
data.monsters.push_back({"bigsy", 500, 1000});
|
data.monsters.push_back({ "bigsy", 500, 1000 });
|
||||||
data.monsters.push_back({"tootoo", 350, 750});
|
data.monsters.push_back({ "tootoo", 350, 750 });
|
||||||
|
|
||||||
//set context
|
// set context
|
||||||
Context ctx{};
|
Context ctx{};
|
||||||
//max monsters
|
// max monsters
|
||||||
std::get<0>(ctx) = 4;
|
std::get<0>(ctx) = 4;
|
||||||
//damage range
|
// damage range
|
||||||
std::get<1>(ctx).first = 100;
|
std::get<1>(ctx).first = 100;
|
||||||
std::get<1>(ctx).second = 1000;
|
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
|
MyTypes::GameState res{};
|
||||||
Buffer buffer{};
|
auto state = bitsery::quickDeserialization(
|
||||||
auto writtenSize = bitsery::quickSerialization(ctx, OutputAdapter{buffer}, data);
|
ctx, InputAdapter{ buffer.begin(), writtenSize }, res);
|
||||||
|
|
||||||
MyTypes::GameState res{};
|
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
||||||
auto state = bitsery::quickDeserialization(ctx, InputAdapter{buffer.begin(), writtenSize}, res);
|
|
||||||
|
|
||||||
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +1,68 @@
|
|||||||
#include <bitsery/bitsery.h>
|
#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 <bitsery/adapter/stream.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
enum class MyEnum:uint16_t { V1,V2,V3 };
|
enum class MyEnum : uint16_t
|
||||||
struct MyStruct {
|
{
|
||||||
uint32_t i;
|
V1,
|
||||||
MyEnum e;
|
V2,
|
||||||
double f;
|
V3
|
||||||
|
};
|
||||||
|
struct MyStruct
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
MyEnum e;
|
||||||
|
double f;
|
||||||
};
|
};
|
||||||
|
|
||||||
//define how object should be serialized/deserialized
|
// define how object should be serialized/deserialized
|
||||||
template <typename S>
|
template<typename S>
|
||||||
void serialize(S& s, MyStruct& o) {
|
void
|
||||||
s.value4b(o.i);
|
serialize(S& s, MyStruct& o)
|
||||||
s.value2b(o.e);
|
{
|
||||||
s.value8b(o.f);
|
s.value4b(o.i);
|
||||||
|
s.value2b(o.e);
|
||||||
|
s.value8b(o.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int
|
||||||
//set some random data
|
main()
|
||||||
MyStruct data{8941, MyEnum::V2, 0.045};
|
{
|
||||||
MyStruct res{};
|
// set some random data
|
||||||
|
MyStruct data{ 8941, MyEnum::V2, 0.045 };
|
||||||
|
MyStruct res{};
|
||||||
|
|
||||||
//open file stream for writing and reading
|
// open file stream for writing and reading
|
||||||
auto fileName = "test_file.bin";
|
auto fileName = "test_file.bin";
|
||||||
std::fstream s{fileName, s.binary | s.trunc | s.out};
|
std::fstream s{ fileName, s.binary | s.trunc | s.out };
|
||||||
if (!s.is_open()) {
|
if (!s.is_open()) {
|
||||||
std::cout << "cannot open " << fileName << " for writing\n";
|
std::cout << "cannot open " << fileName << " for writing\n";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//we cannot use quick serialization function, because streams cannot use writtenBytesCount method
|
// we cannot use quick serialization function, because streams cannot use
|
||||||
bitsery::Serializer<bitsery::OutputBufferedStreamAdapter> ser{s};
|
// writtenBytesCount method
|
||||||
ser.object(data);
|
bitsery::Serializer<bitsery::OutputBufferedStreamAdapter> ser{ s };
|
||||||
//flush to writer
|
ser.object(data);
|
||||||
ser.adapter().flush();
|
// flush to writer
|
||||||
s.close();
|
ser.adapter().flush();
|
||||||
//reopen for reading
|
s.close();
|
||||||
|
// reopen for reading
|
||||||
|
|
||||||
s.open(fileName, s.binary | s.in);
|
s.open(fileName, s.binary | s.in);
|
||||||
if (!s.is_open()) {
|
if (!s.is_open()) {
|
||||||
std::cout << "cannot open " << fileName << " for reading\n";
|
std::cout << "cannot open " << fileName << " for reading\n";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//same as serialization, but returns deserialization state as a pair
|
// same as serialization, but returns deserialization state as a pair
|
||||||
//first = error code, second = is buffer was successfully read from begin to the end.
|
// first = error code, second = is buffer was successfully read from begin to
|
||||||
auto state = bitsery::quickDeserialization<bitsery::InputStreamAdapter>(s, res);
|
// the end.
|
||||||
|
auto state =
|
||||||
|
bitsery::quickDeserialization<bitsery::InputStreamAdapter>(s, res);
|
||||||
|
|
||||||
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
||||||
assert(data.f == res.f && data.i == res.i && data.e == res.e);
|
assert(data.f == res.f && data.i == res.i && data.e == res.e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,92 +1,114 @@
|
|||||||
#include <bitsery/bitsery.h>
|
|
||||||
#include <bitsery/adapter/buffer.h>
|
#include <bitsery/adapter/buffer.h>
|
||||||
//include traits for types, that we'll be using
|
#include <bitsery/bitsery.h>
|
||||||
#include <bitsery/traits/string.h>
|
// include traits for types, that we'll be using
|
||||||
#include <bitsery/traits/array.h>
|
#include <bitsery/traits/array.h>
|
||||||
|
#include <bitsery/traits/string.h>
|
||||||
#include <bitsery/traits/vector.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>
|
#include <bitsery/ext/growable.h>
|
||||||
|
|
||||||
namespace MyTypes {
|
namespace MyTypes {
|
||||||
|
|
||||||
//define data
|
// define data
|
||||||
enum Color:uint8_t { Red, Green, Blue };
|
enum Color : uint8_t
|
||||||
|
{
|
||||||
|
Red,
|
||||||
|
Green,
|
||||||
|
Blue
|
||||||
|
};
|
||||||
|
|
||||||
struct Vec3 { float x, y, z; };
|
struct Vec3
|
||||||
|
{
|
||||||
|
float x, y, z;
|
||||||
|
};
|
||||||
|
|
||||||
struct Weapon {
|
struct Weapon
|
||||||
std::string name{};
|
{
|
||||||
int16_t damage{};
|
std::string name{};
|
||||||
Weapon() = default;
|
int16_t damage{};
|
||||||
Weapon(const std::string& _name, int16_t dmg):name{_name}, damage{dmg} {}
|
Weapon() = default;
|
||||||
private:
|
Weapon(const std::string& _name, int16_t dmg)
|
||||||
//define serialize function as private, and give access to bitsery
|
: name{ _name }
|
||||||
friend bitsery::Access;
|
, damage{ dmg }
|
||||||
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 Monster {
|
private:
|
||||||
Vec3 pos;
|
// define serialize function as private, and give access to bitsery
|
||||||
int16_t mana;
|
friend bitsery::Access;
|
||||||
int16_t hp;
|
template<typename S>
|
||||||
std::string name;
|
void serialize(S& s)
|
||||||
std::vector<uint8_t> inventory;
|
{
|
||||||
Color color;
|
// forward/backward compatibility for weapons
|
||||||
std::vector<Weapon> weapons;
|
s.ext(*this, bitsery::ext::Growable{}, [](S& s, Weapon& o1) {
|
||||||
Weapon equipped;
|
s.text1b(o1.name, 20);
|
||||||
std::vector<Vec3> path;
|
s.value2b(o1.damage);
|
||||||
};
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename S>
|
struct Monster
|
||||||
void serialize(S& s, Vec3& o) {
|
{
|
||||||
s.value4b(o.x);
|
Vec3 pos;
|
||||||
s.value4b(o.y);
|
int16_t mana;
|
||||||
s.value4b(o.z);
|
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>
|
template<typename S>
|
||||||
void serialize (S& s, Monster& o) {
|
void
|
||||||
//forward/backward compatibility for monsters
|
serialize(S& s, Vec3& o)
|
||||||
s.ext(o, bitsery::ext::Growable{}, [](S& s, Monster& o1) {
|
{
|
||||||
s.value1b(o1.color);
|
s.value4b(o.x);
|
||||||
s.value2b(o1.mana);
|
s.value4b(o.y);
|
||||||
s.value2b(o1.hp);
|
s.value4b(o.z);
|
||||||
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
|
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 Buffer = std::array<uint8_t, 10000>;
|
||||||
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
int main() {
|
int
|
||||||
//set some random data
|
main()
|
||||||
MyTypes::Monster data{};
|
{
|
||||||
data.name = "lew";
|
// set some random data
|
||||||
data.weapons.push_back(MyTypes::Weapon{"GoodWeapon", 100});
|
MyTypes::Monster data{};
|
||||||
|
data.name = "lew";
|
||||||
|
data.weapons.push_back(MyTypes::Weapon{ "GoodWeapon", 100 });
|
||||||
|
|
||||||
//create buffer to store data to
|
// create buffer to store data to
|
||||||
Buffer buffer{};
|
Buffer buffer{};
|
||||||
//since we're using different configuration, we cannot use quickSerialization function.
|
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
||||||
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
|
||||||
|
|
||||||
MyTypes::Monster res{};
|
MyTypes::Monster res{};
|
||||||
//deserialize
|
// deserialize
|
||||||
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(state.first == bitsery::ReaderError::NoError && state.second);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,104 +1,134 @@
|
|||||||
//
|
//
|
||||||
//this example covers all the corner cases that can happen using inheritance
|
// 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.
|
// 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/adapter/buffer.h>
|
||||||
|
#include <bitsery/bitsery.h>
|
||||||
#include <bitsery/traits/vector.h>
|
#include <bitsery/traits/vector.h>
|
||||||
|
|
||||||
//include inheritance extension
|
// include inheritance extension
|
||||||
//this header contains two extensions, that specifies inheritance type of base class
|
// this header contains two extensions, that specifies inheritance type of base
|
||||||
// BaseClass - normal inheritance
|
// class
|
||||||
// VirtualBaseClass - when virtual inheritance is used
|
// BaseClass - normal inheritance
|
||||||
//in order for virtual inheritance to work, InheritanceContext is required. for normal inheritance it is not required
|
// 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>
|
#include <bitsery/ext/inheritance.h>
|
||||||
|
|
||||||
using bitsery::ext::BaseClass;
|
using bitsery::ext::BaseClass;
|
||||||
using bitsery::ext::VirtualBaseClass;
|
using bitsery::ext::VirtualBaseClass;
|
||||||
|
|
||||||
struct Base {
|
struct Base
|
||||||
uint8_t x{};
|
{
|
||||||
//Base doesn't have to be polymorphic class, inheritance works at compile-time.
|
uint8_t x{};
|
||||||
|
// Base doesn't have to be polymorphic class, inheritance works at
|
||||||
|
// compile-time.
|
||||||
};
|
};
|
||||||
template <typename S>
|
template<typename S>
|
||||||
void serialize(S& s, Base& o) {
|
void
|
||||||
s.value1b(o.x);
|
serialize(S& s, Base& o)
|
||||||
|
{
|
||||||
|
s.value1b(o.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Derive1:virtual Base {// virtually inherits from base
|
struct Derive1 : virtual Base
|
||||||
uint8_t y1{};
|
{ // virtually inherits from base
|
||||||
|
uint8_t y1{};
|
||||||
};
|
};
|
||||||
template <typename S>
|
template<typename S>
|
||||||
void serialize(S& s, Derive1& o) {
|
void
|
||||||
//define virtual inheritance, it will not compile if InheritanceContext is not defined in serializer/deserializer
|
serialize(S& s, Derive1& o)
|
||||||
s.ext(o, VirtualBaseClass<Base>{});
|
{
|
||||||
s.value1b(o.y1);
|
// 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
|
// to make it more interesting, serialize private member
|
||||||
struct Derived2:virtual Base {
|
struct Derived2 : virtual Base
|
||||||
explicit Derived2(uint8_t y):y2{y} {}
|
{
|
||||||
|
explicit Derived2(uint8_t y)
|
||||||
|
: y2{ y }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t getY2() const { return y2; };
|
||||||
|
|
||||||
uint8_t getY2() const {
|
|
||||||
return y2;
|
|
||||||
};
|
|
||||||
private:
|
private:
|
||||||
friend bitsery::Access;
|
friend bitsery::Access;
|
||||||
uint8_t y2{};
|
uint8_t y2{};
|
||||||
template <typename S>
|
template<typename S>
|
||||||
void serialize(S& s) {
|
void serialize(S& s)
|
||||||
//notice virtual inheritance
|
{
|
||||||
s.ext(*this, VirtualBaseClass<Base>{});
|
// notice virtual inheritance
|
||||||
s.value1b(y2);
|
s.ext(*this, VirtualBaseClass<Base>{});
|
||||||
}
|
s.value1b(y2);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MultipleInheritance: Derive1, Derived2 {
|
struct MultipleInheritance
|
||||||
explicit MultipleInheritance(uint8_t y2):Derived2{y2} {}
|
: Derive1
|
||||||
uint8_t z{};
|
, Derived2
|
||||||
|
{
|
||||||
|
explicit MultipleInheritance(uint8_t y2)
|
||||||
|
: Derived2{ y2 }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
uint8_t z{};
|
||||||
};
|
};
|
||||||
template <typename S>
|
template<typename S>
|
||||||
void serialize(S& s, MultipleInheritance& o) {
|
void
|
||||||
//has two bases, serialize them separately
|
serialize(S& s, MultipleInheritance& o)
|
||||||
s.ext(o, BaseClass<Derive1>{});
|
{
|
||||||
s.ext(o, BaseClass<Derived2>{});
|
// has two bases, serialize them separately
|
||||||
s.value1b(o.z);
|
s.ext(o, BaseClass<Derive1>{});
|
||||||
|
s.ext(o, BaseClass<Derived2>{});
|
||||||
|
s.value1b(o.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
// call to serialize function with Derived2 and MultipleInheritance is ambiguous,
|
// call to serialize function with Derived2 and MultipleInheritance is
|
||||||
// it matches two serialize functions: Base classes non-member fnc and Derived2 member fnc
|
// ambiguous, it matches two serialize functions: Base classes non-member fnc
|
||||||
// we need explicitly select which function to use
|
// and Derived2 member fnc we need explicitly select which function to use
|
||||||
template <>
|
template<>
|
||||||
struct SelectSerializeFnc<Derived2>:UseMemberFnc {};
|
struct SelectSerializeFnc<Derived2> : UseMemberFnc
|
||||||
|
{};
|
||||||
|
|
||||||
//multiple inheritance has non-member serialize function defined
|
// multiple inheritance has non-member serialize function defined
|
||||||
template <>
|
template<>
|
||||||
struct SelectSerializeFnc<MultipleInheritance>:UseNonMemberFnc {};
|
struct SelectSerializeFnc<MultipleInheritance> : UseNonMemberFnc
|
||||||
|
{};
|
||||||
}
|
}
|
||||||
|
|
||||||
//some helper types
|
// some helper types
|
||||||
using Buffer = std::vector<uint8_t>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
using Writer = bitsery::OutputBufferAdapter<Buffer>;
|
using Writer = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using Reader = bitsery::InputBufferAdapter<Buffer>;
|
using Reader = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
int main() {
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
|
||||||
MultipleInheritance data{98};
|
MultipleInheritance data{ 98 };
|
||||||
data.x = 254;
|
data.x = 254;
|
||||||
data.y1 = 47;
|
data.y1 = 47;
|
||||||
data.z = 1;
|
data.z = 1;
|
||||||
|
|
||||||
Buffer buf{};
|
Buffer buf{};
|
||||||
|
|
||||||
bitsery::ext::InheritanceContext ctx1;
|
bitsery::ext::InheritanceContext ctx1;
|
||||||
auto writtenSize = bitsery::quickSerialization(ctx1, Writer{buf}, data);
|
auto writtenSize = bitsery::quickSerialization(ctx1, Writer{ buf }, data);
|
||||||
assert(writtenSize == 4);//base is serialized once, because it is inherited virtually
|
assert(writtenSize ==
|
||||||
|
4); // base is serialized once, because it is inherited virtually
|
||||||
|
|
||||||
MultipleInheritance res{0};
|
MultipleInheritance res{ 0 };
|
||||||
bitsery::ext::InheritanceContext ctx2;
|
bitsery::ext::InheritanceContext ctx2;
|
||||||
auto state = bitsery::quickDeserialization(ctx2, Reader{buf.begin(), writtenSize}, res);
|
auto state = bitsery::quickDeserialization(
|
||||||
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
ctx2, Reader{ buf.begin(), writtenSize }, res);
|
||||||
assert(data.x == res.x && data.y1 == res.y1 && data.getY2() == res.getY2() && data.z == res.z);
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,61 +2,73 @@
|
|||||||
// example of how to deserialize non default constructible objects
|
// example of how to deserialize non default constructible objects
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <bitsery/bitsery.h>
|
|
||||||
#include <bitsery/adapter/buffer.h>
|
#include <bitsery/adapter/buffer.h>
|
||||||
|
#include <bitsery/bitsery.h>
|
||||||
#include <bitsery/traits/vector.h>
|
#include <bitsery/traits/vector.h>
|
||||||
|
|
||||||
class MyData {
|
class MyData
|
||||||
//define your private data
|
{
|
||||||
float _x{0};
|
// define your private data
|
||||||
float _y{0};
|
float _x{ 0 };
|
||||||
//make bitsery:Access friend
|
float _y{ 0 };
|
||||||
friend class bitsery::Access;
|
// make bitsery:Access friend
|
||||||
//create default constructor, don't worry about class invariant, it will be restored in deserialization
|
friend class bitsery::Access;
|
||||||
MyData() = default;
|
// create default constructor, don't worry about class invariant, it will be
|
||||||
//define serialize function
|
// 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:
|
public:
|
||||||
//define non default public constructor
|
// define non default public constructor
|
||||||
MyData(float x, float y):_x{x}, _y{y} {}
|
MyData(float x, float y)
|
||||||
//this is for convenience
|
: _x{ x }
|
||||||
bool operator ==(const MyData&rhs) const {
|
, _y{ y }
|
||||||
return _x == rhs._x && _y == rhs._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 Buffer = std::vector<uint8_t>;
|
||||||
using Writer = bitsery::OutputBufferAdapter<Buffer>;
|
using Writer = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using Reader = bitsery::InputBufferAdapter<Buffer>;
|
using Reader = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
int main() {
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
|
||||||
//initialize our data
|
// initialize our data
|
||||||
std::vector<MyData> data{};
|
std::vector<MyData> data{};
|
||||||
data.emplace_back(145.4f, 84.48f);
|
data.emplace_back(145.4f, 84.48f);
|
||||||
std::vector<MyData> res{};
|
std::vector<MyData> res{};
|
||||||
|
|
||||||
//create buffer
|
// create buffer
|
||||||
Buffer buffer{};
|
Buffer buffer{};
|
||||||
|
|
||||||
//we cant use quick (de)serialization helper methods, because we ant to serialize container directly
|
// we cant use quick (de)serialization helper methods, because we ant to
|
||||||
//create writer and serialize container
|
// serialize container directly create writer and serialize container
|
||||||
bitsery::Serializer<Writer> ser{buffer};
|
bitsery::Serializer<Writer> ser{ buffer };
|
||||||
ser.container(data, 10);
|
ser.container(data, 10);
|
||||||
ser.adapter().flush();
|
ser.adapter().flush();
|
||||||
|
|
||||||
//create reader and deserialize container
|
// create reader and deserialize container
|
||||||
bitsery::Deserializer<Reader> des{buffer.begin(), ser.adapter().writtenBytesCount()};
|
bitsery::Deserializer<Reader> des{ buffer.begin(),
|
||||||
des.container(res, 10);
|
ser.adapter().writtenBytesCount() };
|
||||||
|
des.container(res, 10);
|
||||||
|
|
||||||
//check if everything went ok
|
// check if everything went ok
|
||||||
assert(des.adapter().error() == bitsery::ReaderError::NoError && des.adapter().isCompletedSuccessfully());
|
assert(des.adapter().error() == bitsery::ReaderError::NoError &&
|
||||||
assert(res == data);
|
des.adapter().isCompletedSuccessfully());
|
||||||
|
assert(res == data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,145 +1,166 @@
|
|||||||
#include <bitsery/bitsery.h>
|
|
||||||
#include <bitsery/adapter/buffer.h>
|
#include <bitsery/adapter/buffer.h>
|
||||||
|
#include <bitsery/bitsery.h>
|
||||||
#include <bitsery/traits/vector.h>
|
#include <bitsery/traits/vector.h>
|
||||||
|
|
||||||
//include pointers extension
|
// include pointers extension
|
||||||
//this header contains multiple extensions for different pointer types and pointer linking context,
|
// this header contains multiple extensions for different pointer types and
|
||||||
//that validates pointer ownership and checks if there are and no dangling pointers after serialization/deserialization.
|
// pointer linking context, that validates pointer ownership and checks if there
|
||||||
//dangling pointer in this context means, that non-owning pointer points to data, that was not serialized.
|
// 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>
|
#include <bitsery/ext/pointer.h>
|
||||||
|
|
||||||
using bitsery::ext::ReferencedByPointer;
|
|
||||||
using bitsery::ext::PointerObserver;
|
using bitsery::ext::PointerObserver;
|
||||||
using bitsery::ext::PointerOwner;
|
using bitsery::ext::PointerOwner;
|
||||||
using bitsery::ext::PointerType ;
|
using bitsery::ext::PointerType;
|
||||||
|
using bitsery::ext::ReferencedByPointer;
|
||||||
|
|
||||||
enum class MyEnum:uint16_t { V1,V2,V3 };
|
enum class MyEnum : uint16_t
|
||||||
struct MyStruct {
|
{
|
||||||
MyStruct(uint32_t i_, MyEnum e_, std::vector<float> fs_)
|
V1,
|
||||||
:i{i_},
|
V2,
|
||||||
e{e_},
|
V3
|
||||||
fs{fs_} {}
|
};
|
||||||
MyStruct():MyStruct{0, MyEnum::V1, {}} {}
|
struct MyStruct
|
||||||
uint32_t i;
|
{
|
||||||
MyEnum e;
|
MyStruct(uint32_t i_, MyEnum e_, std::vector<float> fs_)
|
||||||
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>
|
template<typename S>
|
||||||
void serialize(S& s, MyStruct& o) {
|
void
|
||||||
s.value4b(o.i);
|
serialize(S& s, MyStruct& o)
|
||||||
s.value2b(o.e);
|
{
|
||||||
s.container4b(o.fs, 10);
|
s.value4b(o.i);
|
||||||
|
s.value2b(o.e);
|
||||||
|
s.container4b(o.fs, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
//our test data
|
// our test data
|
||||||
struct Test1Data {
|
struct Test1Data
|
||||||
//regular data, nothing fancy here
|
{
|
||||||
MyStruct o1;
|
// regular data, nothing fancy here
|
||||||
int32_t i1;
|
MyStruct o1;
|
||||||
//these container elements can be referenced by pointers
|
int32_t i1;
|
||||||
std::vector<MyStruct> vdata;
|
// these container elements can be referenced by pointers
|
||||||
//container that holds non owning pointers (observers),
|
std::vector<MyStruct> vdata;
|
||||||
std::vector<MyStruct*> vptr;
|
// container that holds non owning pointers (observers),
|
||||||
//treat it as is observer
|
std::vector<MyStruct*> vptr;
|
||||||
MyStruct* po1;
|
// treat it as is observer
|
||||||
//we treat this as owner (responsible for allocation/deallocation
|
MyStruct* po1;
|
||||||
int32_t* pi1;
|
// we treat this as owner (responsible for allocation/deallocation
|
||||||
|
int32_t* pi1;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend bitsery::Access;
|
friend bitsery::Access;
|
||||||
|
|
||||||
template <typename S>
|
template<typename S>
|
||||||
void serialize(S& s) {
|
void serialize(S& s)
|
||||||
//just a regular fields
|
{
|
||||||
s.object(o1);
|
// just a regular fields
|
||||||
s.value4b(i1);
|
s.object(o1);
|
||||||
|
s.value4b(i1);
|
||||||
|
|
||||||
//set container elements to be candidates for non-owning pointers
|
// set container elements to be candidates for non-owning pointers
|
||||||
s.container(vdata, 100, [](S& s, MyStruct& d){
|
s.container(
|
||||||
s.ext(d, ReferencedByPointer{});
|
vdata, 100, [](S& s, MyStruct& d) { s.ext(d, ReferencedByPointer{}); });
|
||||||
});
|
// contains non owning pointers
|
||||||
//contains non owning pointers
|
//
|
||||||
//
|
// IMPORTANT !!!
|
||||||
//IMPORTANT !!!
|
// ALWAYS ACCEPT BY REFERENCE like this: T* (&obj)
|
||||||
//ALWAYS ACCEPT BY REFERENCE like this: T* (&obj)
|
// if using c++14, then auto& always works.
|
||||||
//if using c++14, then auto& always works.
|
//
|
||||||
//
|
// you can also serialize non owning pointers first, pointer linking context
|
||||||
//you can also serialize non owning pointers first, pointer linking context will keep track on them
|
// will keep track on them and as soon as pointer owner data is
|
||||||
//and as soon as pointer owner data is deserialized, all non-owning pointers will be updated
|
// deserialized, all non-owning pointers will be updated
|
||||||
s.container(vptr, 100, [](S& s, MyStruct* (&d)){
|
s.container(
|
||||||
s.ext(d, PointerObserver{});
|
vptr, 100, [](S& s, MyStruct*(&d)) { s.ext(d, PointerObserver{}); });
|
||||||
});
|
// observer
|
||||||
//observer
|
s.ext(po1, PointerObserver{});
|
||||||
s.ext(po1, PointerObserver{});
|
// owner, mark it as not null
|
||||||
//owner, mark it as not null
|
s.ext4b(pi1, PointerOwner{ PointerType::NotNull });
|
||||||
s.ext4b(pi1, PointerOwner{PointerType::NotNull});
|
}
|
||||||
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//some helper types
|
// some helper types
|
||||||
using Buffer = std::vector<uint8_t>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
using Writer = bitsery::OutputBufferAdapter<Buffer>;
|
using Writer = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using Reader = bitsery::InputBufferAdapter<Buffer>;
|
using Reader = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
//we will need PointerLinkingContext to work with pointers
|
// 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:
|
// if we would require additional context for our own custom flow, we can define
|
||||||
// std::tuple<MyContext,ext::PointerLinkingContext>
|
// it as tuple like this:
|
||||||
//and other code will work as expected as long as it cast to proper type.
|
// std::tuple<MyContext,ext::PointerLinkingContext>
|
||||||
//see context_usage.cpp for usage example
|
// and other code will work as expected as long as it cast to proper type.
|
||||||
|
// see context_usage.cpp for usage example
|
||||||
|
|
||||||
int main() {
|
int
|
||||||
//set some random data
|
main()
|
||||||
Test1Data data{};
|
{
|
||||||
data.vdata.emplace_back(8941, MyEnum::V1, std::vector<float>{4.4f});
|
// set some random data
|
||||||
data.vdata.emplace_back(15478, MyEnum::V2, std::vector<float>{15.0f});
|
Test1Data data{};
|
||||||
data.vdata.emplace_back(59, MyEnum::V3, std::vector<float>{-8.5f, 0.045f});
|
data.vdata.emplace_back(8941, MyEnum::V1, std::vector<float>{ 4.4f });
|
||||||
//container of non owning pointers (observers)
|
data.vdata.emplace_back(15478, MyEnum::V2, std::vector<float>{ 15.0f });
|
||||||
data.vptr.emplace_back(nullptr);
|
data.vdata.emplace_back(59, MyEnum::V3, std::vector<float>{ -8.5f, 0.045f });
|
||||||
data.vptr.emplace_back(std::addressof(data.vdata[0]));
|
// container of non owning pointers (observers)
|
||||||
data.vptr.emplace_back(std::addressof(data.vdata[2]));
|
data.vptr.emplace_back(nullptr);
|
||||||
//regular fields
|
data.vptr.emplace_back(std::addressof(data.vdata[0]));
|
||||||
data.o1 = MyStruct{4, MyEnum::V2, {57.078f}};
|
data.vptr.emplace_back(std::addressof(data.vdata[2]));
|
||||||
data.i1 = 9455;
|
// regular fields
|
||||||
//observer
|
data.o1 = MyStruct{ 4, MyEnum::V2, { 57.078f } };
|
||||||
data.po1 = std::addressof(data.vdata[1]);
|
data.i1 = 9455;
|
||||||
//owning pointer
|
// observer
|
||||||
data.pi1 = new int32_t{};
|
data.po1 = std::addressof(data.vdata[1]);
|
||||||
|
// owning pointer
|
||||||
|
data.pi1 = new int32_t{};
|
||||||
|
|
||||||
//create buffer to store data
|
// create buffer to store data
|
||||||
Buffer buffer{};
|
Buffer buffer{};
|
||||||
size_t writtenSize{};
|
size_t writtenSize{};
|
||||||
//in order to use pointers, we need to pass pointer linking context serializer/deserializer
|
// in order to use pointers, we need to pass pointer linking context
|
||||||
{
|
// serializer/deserializer
|
||||||
bitsery::ext::PointerLinkingContext ctx{};
|
{
|
||||||
writtenSize = quickSerialization(ctx, Writer{buffer}, data);
|
bitsery::ext::PointerLinkingContext ctx{};
|
||||||
|
writtenSize = quickSerialization(ctx, Writer{ buffer }, data);
|
||||||
|
|
||||||
//make sure that pointer linking context is valid
|
// make sure that pointer linking context is valid
|
||||||
//this ensures that all non-owning pointers points to data that has been serialized,
|
// this ensures that all non-owning pointers points to data that has been
|
||||||
//so we can successfully reconstruct pointers after deserialization
|
// serialized, so we can successfully reconstruct pointers after
|
||||||
assert(ctx.isValid());
|
// deserialization
|
||||||
}
|
assert(ctx.isValid());
|
||||||
|
}
|
||||||
|
|
||||||
Test1Data res{};
|
Test1Data res{};
|
||||||
{
|
{
|
||||||
bitsery::ext::PointerLinkingContext ctx{};
|
bitsery::ext::PointerLinkingContext ctx{};
|
||||||
auto state = quickDeserialization(ctx, Reader{buffer.begin(), writtenSize}, res);
|
auto state =
|
||||||
//check if everything went find
|
quickDeserialization(ctx, Reader{ buffer.begin(), writtenSize }, res);
|
||||||
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
// check if everything went find
|
||||||
//also check for dangling pointers, after deserialization
|
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
||||||
assert(ctx.isValid());
|
// also check for dangling pointers, after deserialization
|
||||||
}
|
assert(ctx.isValid());
|
||||||
//owning pointers owns data
|
}
|
||||||
assert(*res.pi1 == *data.pi1);
|
// owning pointers owns data
|
||||||
assert(res.pi1 != data.pi1);
|
assert(*res.pi1 == *data.pi1);
|
||||||
//observers, points to other data
|
assert(res.pi1 != data.pi1);
|
||||||
assert(res.vptr[0] == nullptr);
|
// observers, points to other data
|
||||||
assert(res.vptr[1] == std::addressof(res.vdata[0]));
|
assert(res.vptr[0] == nullptr);
|
||||||
assert(res.vptr[2] == std::addressof(res.vdata[2]));
|
assert(res.vptr[1] == std::addressof(res.vdata[0]));
|
||||||
assert(res.po1 == std::addressof(res.vdata[1]));
|
assert(res.vptr[2] == std::addressof(res.vdata[2]));
|
||||||
|
assert(res.po1 == std::addressof(res.vdata[1]));
|
||||||
|
|
||||||
//delete raw owning pointers
|
// delete raw owning pointers
|
||||||
delete data.pi1;
|
delete data.pi1;
|
||||||
delete res.pi1;
|
delete res.pi1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,269 +1,307 @@
|
|||||||
//
|
//
|
||||||
// Created by fraillt on 18.4.26.
|
// 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 <cassert>
|
||||||
#include <memory>
|
#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:
|
// in order to work with polymorphic types, we need to describe few steps:
|
||||||
// 1) describe relationships between base and derived types
|
// 1) describe relationships between base and derived types
|
||||||
// this will allow to know what are possible types reachable from base class
|
// this will allow to know what are possible types reachable from base class
|
||||||
// 2) bind serializer to base class
|
// 2) bind serializer to base class
|
||||||
// this will allow to iterate through all types, and add serialization functions,
|
// this will allow to iterate through all types, and add serialization
|
||||||
// without this step compiler would simply remove functions that are not bound at compile-time even it we use type at runtime.
|
// 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::BaseClass;
|
||||||
|
|
||||||
using bitsery::ext::PointerObserver;
|
using bitsery::ext::PointerObserver;
|
||||||
using bitsery::ext::StdSmartPtr;
|
using bitsery::ext::StdSmartPtr;
|
||||||
|
|
||||||
//define our data structures
|
// define our data structures
|
||||||
struct Color {
|
struct Color
|
||||||
float r{}, g{}, b{};
|
{
|
||||||
bool operator == (const Color& o) const {
|
float r{}, g{}, b{};
|
||||||
return std::tie(r, g, b) ==
|
bool operator==(const Color& o) const
|
||||||
std::tie(o.r, o.g, o.b);
|
{
|
||||||
}
|
return std::tie(r, g, b) == std::tie(o.r, o.g, o.b);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Shape {
|
struct Shape
|
||||||
Color clr{};
|
{
|
||||||
virtual ~Shape() = 0;
|
Color clr{};
|
||||||
|
virtual ~Shape() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Shape::~Shape() = default;
|
Shape::~Shape() = default;
|
||||||
|
|
||||||
struct Circle : Shape {
|
struct Circle : Shape
|
||||||
int32_t radius{};
|
{
|
||||||
bool operator == (const Circle& o) const {
|
int32_t radius{};
|
||||||
return std::tie(radius, clr) ==
|
bool operator==(const Circle& o) const
|
||||||
std::tie(o.radius, o.clr);
|
{
|
||||||
}
|
return std::tie(radius, clr) == std::tie(o.radius, o.clr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Rectangle : Shape {
|
struct Rectangle : Shape
|
||||||
int32_t width{};
|
{
|
||||||
int32_t height{};
|
int32_t width{};
|
||||||
bool operator == (const Rectangle& o) const {
|
int32_t height{};
|
||||||
return std::tie(width, height, clr) ==
|
bool operator==(const Rectangle& o) const
|
||||||
std::tie(o.width, o.height, o.clr);
|
{
|
||||||
}
|
return std::tie(width, height, clr) == std::tie(o.width, o.height, o.clr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RoundedRectangle : Rectangle {
|
struct RoundedRectangle : Rectangle
|
||||||
int32_t radius{};
|
{
|
||||||
bool operator == (const RoundedRectangle& o) const {
|
int32_t radius{};
|
||||||
return std::tie(radius, static_cast<const Rectangle&>(*this)) ==
|
bool operator==(const RoundedRectangle& o) const
|
||||||
std::tie(o.radius, static_cast<const Rectangle&>(o));
|
{
|
||||||
}
|
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>
|
template<typename S>
|
||||||
void serialize(S &s, Color &o) {
|
void
|
||||||
//in real world scenario, it might be possible to serialize this using ValueRange, to map values in smaller space
|
serialize(S& s, Color& o)
|
||||||
//but for the sake of this example keep it simple
|
{
|
||||||
s.value4b(o.r);
|
// in real world scenario, it might be possible to serialize this using
|
||||||
s.value4b(o.g);
|
// ValueRange, to map values in smaller space but for the sake of this example
|
||||||
s.value4b(o.b);
|
// keep it simple
|
||||||
|
s.value4b(o.r);
|
||||||
|
s.value4b(o.g);
|
||||||
|
s.value4b(o.b);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
void serialize(S &s, Shape &o) {
|
void
|
||||||
s.object(o.clr);
|
serialize(S& s, Shape& o)
|
||||||
|
{
|
||||||
|
s.object(o.clr);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
void serialize(S &s, Circle &o) {
|
void
|
||||||
s.ext(o, bitsery::ext::BaseClass<Shape>{});
|
serialize(S& s, Circle& o)
|
||||||
s.value4b(o.radius);
|
{
|
||||||
|
s.ext(o, bitsery::ext::BaseClass<Shape>{});
|
||||||
|
s.value4b(o.radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
void serialize(S &s, Rectangle &o) {
|
void
|
||||||
s.ext(o, bitsery::ext::BaseClass<Shape>{});
|
serialize(S& s, Rectangle& o)
|
||||||
s.value4b(o.width);
|
{
|
||||||
s.value4b(o.height);
|
s.ext(o, bitsery::ext::BaseClass<Shape>{});
|
||||||
|
s.value4b(o.width);
|
||||||
|
s.value4b(o.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
void serialize(S &s, RoundedRectangle &o) {
|
void
|
||||||
s.ext(o, bitsery::ext::BaseClass<Rectangle>{});
|
serialize(S& s, RoundedRectangle& o)
|
||||||
s.value4b(o.radius);
|
{
|
||||||
|
s.ext(o, bitsery::ext::BaseClass<Rectangle>{});
|
||||||
|
s.value4b(o.radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
//define our test structure
|
// define our test structure
|
||||||
struct SomeShapes {
|
struct SomeShapes
|
||||||
std::vector<std::shared_ptr<Shape>> sharedList;
|
{
|
||||||
std::unique_ptr<Shape> uniquePtr;
|
std::vector<std::shared_ptr<Shape>> sharedList;
|
||||||
//weak ptr and refPtr will point to sharedList
|
std::unique_ptr<Shape> uniquePtr;
|
||||||
std::weak_ptr<Shape> weakPtr;
|
// weak ptr and refPtr will point to sharedList
|
||||||
Shape* refPtr;
|
std::weak_ptr<Shape> weakPtr;
|
||||||
|
Shape* refPtr;
|
||||||
};
|
};
|
||||||
|
|
||||||
//creates object, and populates some data
|
// creates object, and populates some data
|
||||||
SomeShapes createData() {
|
SomeShapes
|
||||||
SomeShapes data{};
|
createData()
|
||||||
{
|
{
|
||||||
auto tmp = new RoundedRectangle{};
|
SomeShapes data{};
|
||||||
tmp->height = 151572;
|
{
|
||||||
tmp->width = 488795;
|
auto tmp = new RoundedRectangle{};
|
||||||
tmp->radius = 898;
|
tmp->height = 151572;
|
||||||
tmp->clr.r = 0.5f;
|
tmp->width = 488795;
|
||||||
tmp->clr.g = 1.0f;
|
tmp->radius = 898;
|
||||||
tmp->clr.b = 1.0f;
|
tmp->clr.r = 0.5f;
|
||||||
data.uniquePtr.reset(tmp);
|
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;
|
auto tmp = new Circle{};
|
||||||
tmp->clr.g = 0.0f;
|
tmp->radius = 75987;
|
||||||
tmp->clr.b = 1.0f;
|
tmp->clr.r = 0.5f;
|
||||||
data.sharedList.emplace_back(tmp);
|
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;
|
auto tmp = new Rectangle{};
|
||||||
tmp->clr.r = 1.0f;
|
tmp->height = 15157;
|
||||||
tmp->clr.g = 0.0f;
|
tmp->width = 48879;
|
||||||
tmp->clr.b = 0.0f;
|
tmp->clr.r = 1.0f;
|
||||||
data.sharedList.emplace_back(tmp);
|
tmp->clr.g = 0.0f;
|
||||||
}
|
tmp->clr.b = 0.0f;
|
||||||
data.weakPtr = data.sharedList[0];
|
data.sharedList.emplace_back(tmp);
|
||||||
data.refPtr = data.sharedList[1].get();
|
}
|
||||||
|
data.weakPtr = data.sharedList[0];
|
||||||
|
data.refPtr = data.sharedList[1].get();
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename S>
|
template<typename S>
|
||||||
void serialize(S &s, SomeShapes &o) {
|
void
|
||||||
s.ext(o.uniquePtr, StdSmartPtr{});
|
serialize(S& s, SomeShapes& o)
|
||||||
// to make things more interesting first serialize weakPtr and refPtr,
|
{
|
||||||
// even though objects that weakPtr and refPtr is serialized later,
|
s.ext(o.uniquePtr, StdSmartPtr{});
|
||||||
// bitsery will work regardless
|
// to make things more interesting first serialize weakPtr and refPtr,
|
||||||
s.ext(o.weakPtr, StdSmartPtr{});
|
// even though objects that weakPtr and refPtr is serialized later,
|
||||||
s.ext(o.refPtr, PointerObserver{});
|
// bitsery will work regardless
|
||||||
s.container(o.sharedList, 100, [](S& s, std::shared_ptr<Shape> &item) {
|
s.ext(o.weakPtr, StdSmartPtr{});
|
||||||
s.ext(item, StdSmartPtr{});
|
s.ext(o.refPtr, PointerObserver{});
|
||||||
});
|
s.container(o.sharedList, 100, [](S& s, std::shared_ptr<Shape>& item) {
|
||||||
|
s.ext(item, StdSmartPtr{});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// STEP 1
|
// STEP 1
|
||||||
// define relationships between base and derived classes
|
// define relationships between base and derived classes
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
//for each base class define DIRECTLY derived classes
|
// for each base class define DIRECTLY derived classes
|
||||||
//e.g. PolymorphicBaseClass<Shape> : PolymorphicDerivedClasses<Circle, Rectangle, RoundedRectangle>
|
// e.g. PolymorphicBaseClass<Shape> : PolymorphicDerivedClasses<Circle,
|
||||||
// is incorrect, because RoundedRectangle does not directly derive from Shape
|
// Rectangle, RoundedRectangle>
|
||||||
template<>
|
// is incorrect, because RoundedRectangle does not directly derive from Shape
|
||||||
struct PolymorphicBaseClass<Shape> : PolymorphicDerivedClasses<Circle, Rectangle> {
|
template<>
|
||||||
};
|
struct PolymorphicBaseClass<Shape>
|
||||||
|
: PolymorphicDerivedClasses<Circle, Rectangle>
|
||||||
|
{};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct PolymorphicBaseClass<Rectangle> : PolymorphicDerivedClasses<RoundedRectangle> {
|
struct PolymorphicBaseClass<Rectangle>
|
||||||
};
|
: PolymorphicDerivedClasses<RoundedRectangle>
|
||||||
}
|
{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// convenient type that stores all our types, so that we could easily register and
|
// convenient type that stores all our types, so that we could easily register
|
||||||
// also it automatically ensures, that classes is registered in the same order for serialization and deserialization
|
// and also it automatically ensures, that classes is registered in the same
|
||||||
using MyPolymorphicClassesForRegistering = bitsery::ext::PolymorphicClassesList<Shape>;
|
// order for serialization and deserialization
|
||||||
|
using MyPolymorphicClassesForRegistering =
|
||||||
|
bitsery::ext::PolymorphicClassesList<Shape>;
|
||||||
|
|
||||||
//some helper types
|
// some helper types
|
||||||
using Buffer = std::vector<uint8_t>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
using Writer = bitsery::OutputBufferAdapter<Buffer>;
|
using Writer = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using Reader = bitsery::InputBufferAdapter<Buffer>;
|
using Reader = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
//we need to define few things in order to work with polymorphism
|
// we need to define few things in order to work with polymorphism
|
||||||
//1) we need pointer linking context to work with pointers
|
// 1) we need pointer linking context to work with pointers
|
||||||
//2) we need polymorphic context to be able to work with polymorphic types
|
// 2) we need polymorphic context to be able to work with polymorphic types
|
||||||
using TContext = std::tuple<
|
using TContext =
|
||||||
bitsery::ext::PointerLinkingContext,
|
std::tuple<bitsery::ext::PointerLinkingContext,
|
||||||
bitsery::ext::PolymorphicContext<bitsery::ext::StandardRTTI>>;
|
bitsery::ext::PolymorphicContext<bitsery::ext::StandardRTTI>>;
|
||||||
//NOTE:
|
// NOTE:
|
||||||
// RTTI can be customizable, if you can't use dynamic_cast and typeid, and have 'custom' solution
|
// RTTI can be customizable, if you can't use dynamic_cast and typeid, and have
|
||||||
|
// 'custom' solution
|
||||||
using MySerializer = bitsery::Serializer<Writer, TContext>;
|
using MySerializer = bitsery::Serializer<Writer, TContext>;
|
||||||
using MyDeserializer = bitsery::Deserializer<Reader, TContext>;
|
using MyDeserializer = bitsery::Deserializer<Reader, TContext>;
|
||||||
|
|
||||||
//checks if deserialized data is equal
|
// checks if deserialized data is equal
|
||||||
void assertSameShapes(const SomeShapes &data, const SomeShapes &res) {
|
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);
|
auto d = dynamic_cast<RoundedRectangle*>(data.uniquePtr.get());
|
||||||
assert(*d == *r);
|
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);
|
auto d = dynamic_cast<Circle*>(data.sharedList[0].get());
|
||||||
assert(*d == *r);
|
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);
|
auto d = dynamic_cast<Rectangle*>(data.sharedList[1].get());
|
||||||
assert(*d == *r);
|
auto r = dynamic_cast<Rectangle*>(res.sharedList[1].get());
|
||||||
}
|
assert(r != nullptr);
|
||||||
assert(res.weakPtr.lock().get() == res.sharedList[0].get());
|
assert(*d == *r);
|
||||||
assert(res.refPtr == res.sharedList[1].get());
|
}
|
||||||
|
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
|
// create buffer to store data
|
||||||
Buffer buffer{};
|
Buffer buffer{};
|
||||||
size_t writtenSize{};
|
size_t writtenSize{};
|
||||||
// we will not use quickSerialization/Deserialization functions to show, that we need to register polymorphic classes, explicitly
|
// we will not use quickSerialization/Deserialization functions to show, that
|
||||||
{
|
// we need to register polymorphic classes, explicitly
|
||||||
|
{
|
||||||
|
|
||||||
//STEP 2
|
// STEP 2
|
||||||
// before start serialization/deserialization,
|
// before start serialization/deserialization,
|
||||||
// bind it with base polymorphic types, it will go through all reachable classes that is defined in first step.
|
// bind it with base polymorphic types, it will go through all reachable
|
||||||
// NOTE: you dont need to add Rectangle to reach for RoundedRectangle
|
// classes that is defined in first step. NOTE: you dont need to add
|
||||||
TContext ctx{};
|
// Rectangle to reach for RoundedRectangle
|
||||||
std::get<1>(ctx).registerBasesList<MySerializer>(MyPolymorphicClassesForRegistering{});
|
TContext ctx{};
|
||||||
//create writer and serialize
|
std::get<1>(ctx).registerBasesList<MySerializer>(
|
||||||
MySerializer ser{ctx, buffer};
|
MyPolymorphicClassesForRegistering{});
|
||||||
ser.object(data);
|
// create writer and serialize
|
||||||
ser.adapter().flush();
|
MySerializer ser{ ctx, buffer };
|
||||||
writtenSize = ser.adapter().writtenBytesCount();
|
ser.object(data);
|
||||||
|
ser.adapter().flush();
|
||||||
|
writtenSize = ser.adapter().writtenBytesCount();
|
||||||
|
|
||||||
//make sure that pointer linking context is valid
|
// make sure that pointer linking context is valid
|
||||||
//this ensures that all non-owning pointers points to data that has been serialized,
|
// this ensures that all non-owning pointers points to data that has been
|
||||||
//so we can successfully reconstruct pointers after deserialization
|
// serialized, so we can successfully reconstruct pointers after
|
||||||
assert(std::get<0>(ctx).isValid());
|
// deserialization
|
||||||
}
|
assert(std::get<0>(ctx).isValid());
|
||||||
SomeShapes res{};
|
}
|
||||||
{
|
SomeShapes res{};
|
||||||
TContext ctx{};
|
{
|
||||||
std::get<1>(ctx).registerBasesList<MyDeserializer>(MyPolymorphicClassesForRegistering{});
|
TContext ctx{};
|
||||||
//deserialize our data
|
std::get<1>(ctx).registerBasesList<MyDeserializer>(
|
||||||
MyDeserializer des{ctx, buffer.begin(), writtenSize};
|
MyPolymorphicClassesForRegistering{});
|
||||||
des.object(res);
|
// deserialize our data
|
||||||
assert(des.adapter().error() == bitsery::ReaderError::NoError && des.adapter().isCompletedSuccessfully());
|
MyDeserializer des{ ctx, buffer.begin(), writtenSize };
|
||||||
//also check for dangling pointers, after deserialization
|
des.object(res);
|
||||||
assert(std::get<0>(ctx).isValid());
|
assert(des.adapter().error() == bitsery::ReaderError::NoError &&
|
||||||
// clear shared state from pointer linking context,
|
des.adapter().isCompletedSuccessfully());
|
||||||
// it is only required if there are any pointers that manage shared state, e.g. std::shared_ptr
|
// also check for dangling pointers, after deserialization
|
||||||
assert(res.weakPtr.use_count() == 2);//one in sharedList and one in pointer linking context
|
assert(std::get<0>(ctx).isValid());
|
||||||
std::get<0>(ctx).clearSharedState();
|
// clear shared state from pointer linking context,
|
||||||
assert(res.weakPtr.use_count() == 1);
|
// it is only required if there are any pointers that manage shared state,
|
||||||
}
|
// e.g. std::shared_ptr
|
||||||
assertSameShapes(data, res);
|
assert(res.weakPtr.use_count() ==
|
||||||
return 0;
|
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
3
format.sh
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
find . -regex '.*\.\(cpp\|hpp\|cu\|c\|h\)' -exec clang-format -style=file -i {} \;
|
||||||
|
|
||||||
|
|
||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_ADAPTER_BUFFER_H
|
#ifndef BITSERY_ADAPTER_BUFFER_H
|
||||||
#define 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 "../traits/core/traits.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
template<typename Buffer, typename Config = DefaultConfig>
|
template<typename Buffer, typename Config = DefaultConfig>
|
||||||
class InputBufferAdapter: public details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer,Config>> {
|
class InputBufferAdapter
|
||||||
public:
|
: public details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer, Config>>
|
||||||
friend details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer,Config>>;
|
{
|
||||||
using TConfig = Config;
|
public:
|
||||||
using TIterator = typename traits::BufferAdapterTraits<typename std::remove_const<Buffer>::type>::TConstIterator;
|
friend details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer, Config>>;
|
||||||
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, size_t size)
|
using BitPackingEnabled =
|
||||||
: _beginIt{beginIt},
|
details::InputAdapterBitPackingWrapper<InputBufferAdapter<Buffer, Config>>;
|
||||||
_currOffset{0},
|
using TConfig = Config;
|
||||||
_endReadOffset{size},
|
using TIterator = typename traits::BufferAdapterTraits<
|
||||||
_bufferSize{size} {
|
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(TIterator beginIt, size_t size)
|
||||||
:InputBufferAdapter(beginIt, static_cast<size_t>(std::distance(beginIt, endIt))) {
|
: _beginIt{ beginIt }
|
||||||
}
|
, _currOffset{ 0 }
|
||||||
|
, _endReadOffset{ size }
|
||||||
|
, _bufferSize{ size } {};
|
||||||
|
|
||||||
InputBufferAdapter(const InputBufferAdapter&) = delete;
|
InputBufferAdapter(TIterator beginIt, TIterator endIt)
|
||||||
InputBufferAdapter& operator=(const InputBufferAdapter&) = delete;
|
: InputBufferAdapter(beginIt,
|
||||||
|
static_cast<size_t>(std::distance(beginIt, endIt)))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
InputBufferAdapter(InputBufferAdapter&&) = default;
|
InputBufferAdapter(const InputBufferAdapter&) = delete;
|
||||||
InputBufferAdapter& operator = (InputBufferAdapter&&) = default;
|
InputBufferAdapter& operator=(const InputBufferAdapter&) = delete;
|
||||||
|
|
||||||
void currentReadPos(size_t pos) {
|
InputBufferAdapter(InputBufferAdapter&&) = default;
|
||||||
currentReadPosChecked(pos, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
InputBufferAdapter& operator=(InputBufferAdapter&&) = default;
|
||||||
}
|
|
||||||
|
|
||||||
size_t currentReadPos() const {
|
void currentReadPos(size_t pos)
|
||||||
return currentReadPosChecked(std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
{
|
||||||
}
|
currentReadPosChecked(
|
||||||
|
pos, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||||
|
}
|
||||||
|
|
||||||
void currentReadEndPos(size_t pos) {
|
size_t currentReadPos() const
|
||||||
// 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.");
|
return currentReadPosChecked(
|
||||||
if (_bufferSize >= pos && error() == ReaderError::NoError) {
|
std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||||
_overflowOnReadEndPos = pos == 0;
|
}
|
||||||
if (pos == 0)
|
|
||||||
pos = _bufferSize;
|
|
||||||
_endReadOffset = pos;
|
|
||||||
} else {
|
|
||||||
error(ReaderError::DataOverflow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t currentReadEndPos() const {
|
void currentReadEndPos(size_t pos)
|
||||||
if (_overflowOnReadEndPos)
|
{
|
||||||
return 0;
|
// assert that CheckAdapterErrors is enabled, otherwise it will simply will
|
||||||
return _endReadOffset;
|
// 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 {
|
size_t currentReadEndPos() const
|
||||||
return _currOffset <= _endReadOffset
|
{
|
||||||
? ReaderError::NoError
|
if (_overflowOnReadEndPos)
|
||||||
: static_cast<ReaderError>(_currOffset - _endReadOffset);
|
return 0;
|
||||||
}
|
return _endReadOffset;
|
||||||
|
}
|
||||||
|
|
||||||
void error(ReaderError error) {
|
ReaderError error() const
|
||||||
if (_currOffset <= _endReadOffset) {
|
{
|
||||||
_endReadOffset = 0;
|
return _currOffset <= _endReadOffset
|
||||||
_bufferSize = 0;
|
? ReaderError::NoError
|
||||||
_currOffset = static_cast<size_t>(error);
|
: static_cast<ReaderError>(_currOffset - _endReadOffset);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool isCompletedSuccessfully() const {
|
void error(ReaderError error)
|
||||||
return _currOffset == _bufferSize;
|
{
|
||||||
}
|
if (_currOffset <= _endReadOffset) {
|
||||||
|
_endReadOffset = 0;
|
||||||
|
_bufferSize = 0;
|
||||||
|
_currOffset = static_cast<size_t>(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
bool isCompletedSuccessfully() const { return _currOffset == _bufferSize; }
|
||||||
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
|
|
||||||
|
|
||||||
template <size_t SIZE>
|
private:
|
||||||
void readInternalValue(TValue *data) {
|
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
|
||||||
readInternalValueChecked<SIZE>(data, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
|
||||||
}
|
|
||||||
|
|
||||||
void readInternalBuffer(TValue *data, size_t size) {
|
template<size_t SIZE>
|
||||||
readInternalBufferChecked(data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
void readInternalValue(TValue* data)
|
||||||
}
|
{
|
||||||
|
readInternalImpl(
|
||||||
|
data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||||
|
}
|
||||||
|
|
||||||
template <size_t SIZE>
|
void readInternalBuffer(TValue* data, size_t size)
|
||||||
void readInternalValueChecked(TValue *data, std::false_type) {
|
{
|
||||||
const size_t newOffset = _currOffset + SIZE;
|
readInternalImpl(
|
||||||
assert(newOffset <= _endReadOffset);
|
data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||||
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), SIZE, data);
|
}
|
||||||
_currOffset = newOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t SIZE>
|
void readInternalImpl(TValue* data, size_t size, std::false_type)
|
||||||
void readInternalValueChecked(TValue *data, std::true_type) {
|
{
|
||||||
const size_t newOffset = _currOffset + SIZE;
|
const size_t newOffset = _currOffset + size;
|
||||||
if (newOffset <= _endReadOffset) {
|
assert(newOffset <= _endReadOffset);
|
||||||
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), SIZE, data);
|
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
|
||||||
_currOffset = newOffset;
|
_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::false_type) {
|
void readInternalImpl(TValue* data, size_t size, std::true_type)
|
||||||
const size_t newOffset = _currOffset + size;
|
{
|
||||||
assert(newOffset <= _endReadOffset);
|
const size_t newOffset = _currOffset + size;
|
||||||
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
|
if (newOffset <= _endReadOffset) {
|
||||||
_currOffset = newOffset;
|
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) {
|
void currentReadPosChecked(size_t pos, std::true_type)
|
||||||
const size_t newOffset = _currOffset + size;
|
{
|
||||||
if (newOffset <= _endReadOffset) {
|
if (_bufferSize >= pos && error() == ReaderError::NoError) {
|
||||||
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
|
_currOffset = pos;
|
||||||
_currOffset = newOffset;
|
} else {
|
||||||
} else {
|
error(ReaderError::DataOverflow);
|
||||||
//set everything to zeros
|
}
|
||||||
std::memset(data, 0, size);
|
}
|
||||||
if (_overflowOnReadEndPos)
|
|
||||||
error(ReaderError::DataOverflow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void currentReadPosChecked(size_t pos, std::true_type) {
|
void currentReadPosChecked(size_t pos, std::false_type) { _currOffset = pos; }
|
||||||
if (_bufferSize >= pos && error() == ReaderError::NoError) {
|
|
||||||
_currOffset = pos;
|
|
||||||
} else {
|
|
||||||
error(ReaderError::DataOverflow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void currentReadPosChecked(size_t pos, std::false_type) {
|
size_t currentReadPosChecked(std::true_type) const
|
||||||
_currOffset = pos;
|
{
|
||||||
}
|
return error() == ReaderError::NoError ? _currOffset : 0;
|
||||||
|
}
|
||||||
|
|
||||||
size_t currentReadPosChecked(std::true_type) const {
|
size_t currentReadPosChecked(std::false_type) const { return _currOffset; }
|
||||||
return error() == ReaderError::NoError ? _currOffset : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t currentReadPosChecked(std::false_type) const {
|
TIterator _beginIt;
|
||||||
return _currOffset;
|
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;
|
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<
|
||||||
size_t _currOffset;
|
OutputBufferAdapter<Buffer, Config>>;
|
||||||
size_t _endReadOffset;
|
using TConfig = Config;
|
||||||
size_t _bufferSize;
|
using TIterator = typename traits::BufferAdapterTraits<Buffer>::TIterator;
|
||||||
bool _overflowOnReadEndPos = true;
|
using TValue = typename traits::BufferAdapterTraits<Buffer>::TValue;
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Buffer, typename Config = DefaultConfig>
|
static_assert(
|
||||||
class OutputBufferAdapter: public details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer,Config>> {
|
details::IsDefined<TValue>::value,
|
||||||
public:
|
"Please define BufferAdapterTraits or include from <bitsery/traits/...>");
|
||||||
friend details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer,Config>>;
|
static_assert(traits::ContainerTraits<Buffer>::isContiguous,
|
||||||
using TConfig = Config;
|
"BufferAdapter only works with contiguous containers");
|
||||||
using TIterator = typename traits::BufferAdapterTraits<Buffer>::TIterator;
|
static_assert(sizeof(TValue) == 1,
|
||||||
using TValue = typename traits::BufferAdapterTraits<Buffer>::TValue;
|
"BufferAdapter underlying type must be 1byte.");
|
||||||
|
|
||||||
static_assert(details::IsDefined<TValue>::value,
|
OutputBufferAdapter(Buffer& buffer)
|
||||||
"Please define BufferAdapterTraits or include from <bitsery/traits/...>");
|
: _buffer{ std::addressof(buffer) }
|
||||||
static_assert(traits::ContainerTraits<Buffer>::isContiguous,
|
, _beginIt{ std::begin(buffer) }
|
||||||
"BufferAdapter only works with contiguous containers");
|
, _bufferSize{ traits::ContainerTraits<Buffer>::size(buffer) }
|
||||||
static_assert(sizeof(TValue) == 1, "BufferAdapter underlying type must be 1byte.");
|
{
|
||||||
|
}
|
||||||
|
|
||||||
OutputBufferAdapter(Buffer &buffer)
|
OutputBufferAdapter(const OutputBufferAdapter&) = delete;
|
||||||
: _buffer{std::addressof(buffer)},
|
OutputBufferAdapter& operator=(const OutputBufferAdapter&) = delete;
|
||||||
_beginIt{std::begin(buffer)} {
|
OutputBufferAdapter(OutputBufferAdapter&&) = default;
|
||||||
init(TResizable{});
|
OutputBufferAdapter& operator=(OutputBufferAdapter&&) = default;
|
||||||
}
|
|
||||||
|
|
||||||
OutputBufferAdapter(const OutputBufferAdapter&) = delete;
|
void currentWritePos(size_t pos)
|
||||||
OutputBufferAdapter& operator=(const OutputBufferAdapter&) = delete;
|
{
|
||||||
OutputBufferAdapter(OutputBufferAdapter&&) = default;
|
const auto maxPos = _currOffset > pos ? _currOffset : pos;
|
||||||
OutputBufferAdapter& operator = (OutputBufferAdapter&&) = default;
|
if (maxPos > _biggestCurrentPos) {
|
||||||
|
_biggestCurrentPos = maxPos;
|
||||||
|
}
|
||||||
|
maybeResize(pos, TResizable{});
|
||||||
|
_currOffset = pos;
|
||||||
|
}
|
||||||
|
|
||||||
void currentWritePos(size_t pos) {
|
size_t currentWritePos() const { return _currOffset; }
|
||||||
const auto maxPos = _currOffset > pos ? _currOffset : pos;
|
|
||||||
if (maxPos > _biggestCurrentPos) {
|
|
||||||
_biggestCurrentPos = maxPos;
|
|
||||||
}
|
|
||||||
setCurrentWritePos(pos, TResizable{});
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t currentWritePos() const {
|
void flush()
|
||||||
return _currOffset;
|
{
|
||||||
}
|
// this function might be useful for stream adapters
|
||||||
|
}
|
||||||
|
|
||||||
void flush() {
|
size_t writtenBytesCount() const
|
||||||
//this function might be useful for stream adapters
|
{
|
||||||
}
|
return _currOffset > _biggestCurrentPos ? _currOffset : _biggestCurrentPos;
|
||||||
|
}
|
||||||
|
|
||||||
size_t writtenBytesCount() const {
|
private:
|
||||||
return _currOffset > _biggestCurrentPos ? _currOffset : _biggestCurrentPos;
|
using TResizable =
|
||||||
}
|
std::integral_constant<bool, traits::ContainerTraits<Buffer>::isResizable>;
|
||||||
|
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
|
||||||
|
|
||||||
private:
|
template<size_t SIZE>
|
||||||
using TResizable = std::integral_constant<bool, traits::ContainerTraits<Buffer>::isResizable>;
|
void writeInternalValue(const TValue* data)
|
||||||
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
|
{
|
||||||
|
writeInternalImpl(data, SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
template <size_t SIZE>
|
void writeInternalBuffer(const TValue* data, size_t size)
|
||||||
void writeInternalValue(const TValue *data) {
|
{
|
||||||
writeInternalValueImpl<SIZE>(data, TResizable{});
|
writeInternalImpl(data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeInternalBuffer(const TValue *data, size_t size) {
|
Buffer* _buffer;
|
||||||
writeInternalBufferImpl(data, size, TResizable{});
|
TIterator _beginIt;
|
||||||
}
|
size_t _currOffset{ 0 };
|
||||||
|
size_t _bufferSize{ 0 };
|
||||||
|
size_t _biggestCurrentPos{ 0 };
|
||||||
|
|
||||||
Buffer* _buffer;
|
void maybeResize(size_t newOffset, std::true_type)
|
||||||
TIterator _beginIt;
|
{
|
||||||
size_t _currOffset{0};
|
if (newOffset > _bufferSize)
|
||||||
size_t _bufferSize{0};
|
BITSERY_UNLIKELY
|
||||||
size_t _biggestCurrentPos{0};
|
{
|
||||||
|
doResize(newOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
void maybeResize(size_t newOffset, std::false_type)
|
||||||
* resizable buffer
|
{
|
||||||
*/
|
static_cast<void>(newOffset);
|
||||||
|
assert(newOffset <= _bufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
void init(std::true_type) {
|
void writeInternalImpl(const TValue* data, size_t size)
|
||||||
//resize buffer immediately, because we need output iterator at valid position
|
{
|
||||||
if (traits::ContainerTraits<Buffer>::size(*_buffer) == 0u) {
|
const size_t newOffset = _currOffset + size;
|
||||||
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
|
maybeResize(newOffset, TResizable{});
|
||||||
}
|
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
|
||||||
updateIteratorAndSize();
|
_currOffset = newOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t SIZE>
|
BITSERY_NOINLINE void doResize(size_t newOffset)
|
||||||
void writeInternalValueImpl(const TValue *data, std::true_type) {
|
{
|
||||||
const size_t newOffset = _currOffset + SIZE;
|
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(
|
||||||
if (newOffset <= _bufferSize) {
|
*_buffer, _currOffset, newOffset);
|
||||||
std::copy_n(data, SIZE, _beginIt + static_cast<diff_t>(_currOffset));
|
_beginIt = std::begin(*_buffer);
|
||||||
_currOffset = newOffset;
|
_bufferSize = traits::ContainerTraits<Buffer>::size(*_buffer);
|
||||||
} 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);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //BITSERY_ADAPTER_BUFFER_H
|
#endif // BITSERY_ADAPTER_BUFFER_H
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_ADAPTER_MEASURE_SIZE_H
|
#ifndef BITSERY_ADAPTER_MEASURE_SIZE_H
|
||||||
#define BITSERY_ADAPTER_MEASURE_SIZE_H
|
#define BITSERY_ADAPTER_MEASURE_SIZE_H
|
||||||
|
|
||||||
|
#include "../details/adapter_bit_packing.h"
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include "../details/adapter_common.h"
|
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
|
template<typename Config>
|
||||||
|
class BasicMeasureSize
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using BitPackingEnabled =
|
||||||
|
details::BasicMeasureSizeBitPackingWrapper<BasicMeasureSize<Config>>;
|
||||||
|
using TConfig = Config;
|
||||||
|
using TValue = void;
|
||||||
|
|
||||||
template<typename Config>
|
template<size_t SIZE, typename T>
|
||||||
class BasicMeasureSize {
|
void writeBytes(const T&)
|
||||||
public:
|
{
|
||||||
|
static_assert(std::is_integral<T>(), "");
|
||||||
|
static_assert(sizeof(T) == SIZE, "");
|
||||||
|
_currPos += SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr bool BitPackingEnabled = true;
|
template<size_t SIZE, typename T>
|
||||||
using TConfig = Config;
|
void writeBuffer(const T*, size_t count)
|
||||||
using TValue = void;
|
{
|
||||||
|
static_assert(std::is_integral<T>(), "");
|
||||||
|
static_assert(sizeof(T) == SIZE, "");
|
||||||
|
_currPos += SIZE * count;
|
||||||
|
}
|
||||||
|
|
||||||
template<size_t SIZE, typename T>
|
void currentWritePos(size_t pos)
|
||||||
void writeBytes(const T&) {
|
{
|
||||||
static_assert(std::is_integral<T>(), "");
|
const auto maxPos = _currPos > pos ? _currPos : pos;
|
||||||
static_assert(sizeof(T) == SIZE, "");
|
if (maxPos > _biggestCurrentPos) {
|
||||||
_currPosBits += details::BitsSize<T>::value;
|
_biggestCurrentPos = maxPos;
|
||||||
}
|
}
|
||||||
|
_currPos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
template<size_t SIZE, typename T>
|
size_t currentWritePos() const { return _currPos; }
|
||||||
void writeBuffer(const T*, size_t count) {
|
|
||||||
static_assert(std::is_integral<T>(), "");
|
|
||||||
static_assert(sizeof(T) == SIZE, "");
|
|
||||||
_currPosBits += details::BitsSize<T>::value * count;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
void align() {}
|
||||||
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 currentWritePos(size_t pos) {
|
void flush() {}
|
||||||
align();
|
|
||||||
const auto newPos = pos * 8;
|
|
||||||
if (_currPosBits > newPos)
|
|
||||||
_prevLargestPos = _currPosBits;
|
|
||||||
_currPosBits = newPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t currentWritePos() const {
|
// get size in bytes
|
||||||
return _currPosBits / 8;
|
size_t writtenBytesCount() const
|
||||||
}
|
{
|
||||||
|
return _currPos > _biggestCurrentPos ? _currPos : _biggestCurrentPos;
|
||||||
|
}
|
||||||
|
|
||||||
void align() {
|
private:
|
||||||
auto _scratch = (_currPosBits % 8);
|
size_t _biggestCurrentPos{};
|
||||||
_currPosBits += (8 - _scratch) % 8;
|
size_t _currPos{};
|
||||||
}
|
};
|
||||||
|
|
||||||
void flush() {
|
// helper type for default config
|
||||||
align();
|
using MeasureSize = BasicMeasureSize<DefaultConfig>;
|
||||||
}
|
|
||||||
|
|
||||||
//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>;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //BITSERY_ADAPTER_MEASURE_SIZE_H
|
#endif // BITSERY_ADAPTER_MEASURE_SIZE_H
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_ADAPTER_STREAM_H
|
#ifndef BITSERY_ADAPTER_STREAM_H
|
||||||
#define 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 "../traits/array.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
#include <ios>
|
#include <ios>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
template <typename TChar, typename Config, typename CharTraits>
|
template<typename TChar, typename Config, typename CharTraits>
|
||||||
class BasicInputStreamAdapter: public details::InputAdapterBaseCRTP<BasicInputStreamAdapter<TChar, Config, CharTraits>> {
|
class BasicInputStreamAdapter
|
||||||
public:
|
: public details::InputAdapterBaseCRTP<
|
||||||
friend details::InputAdapterBaseCRTP<BasicInputStreamAdapter<TChar, Config, CharTraits>>;
|
BasicInputStreamAdapter<TChar, Config, CharTraits>>
|
||||||
using TConfig = Config;
|
{
|
||||||
using TValue = TChar;
|
public:
|
||||||
|
friend details::InputAdapterBaseCRTP<
|
||||||
|
BasicInputStreamAdapter<TChar, Config, CharTraits>>;
|
||||||
|
|
||||||
BasicInputStreamAdapter(std::basic_ios<TChar, CharTraits>& istream)
|
using BitPackingEnabled = details::InputAdapterBitPackingWrapper<
|
||||||
:_ios{std::addressof(istream)} {}
|
BasicInputStreamAdapter<TChar, Config, CharTraits>>;
|
||||||
|
using TConfig = Config;
|
||||||
|
using TValue = TChar;
|
||||||
|
|
||||||
BasicInputStreamAdapter(const BasicInputStreamAdapter&) = delete;
|
BasicInputStreamAdapter(std::basic_ios<TChar, CharTraits>& istream)
|
||||||
BasicInputStreamAdapter& operator = (const BasicInputStreamAdapter&) = delete;
|
: _ios{ std::addressof(istream) }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
BasicInputStreamAdapter(BasicInputStreamAdapter&&) = default;
|
BasicInputStreamAdapter(const BasicInputStreamAdapter&) = delete;
|
||||||
BasicInputStreamAdapter& operator = (BasicInputStreamAdapter&&) = default;
|
BasicInputStreamAdapter& operator=(const BasicInputStreamAdapter&) = delete;
|
||||||
|
|
||||||
void currentReadPos(size_t ) {
|
BasicInputStreamAdapter(BasicInputStreamAdapter&&) = default;
|
||||||
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
|
BasicInputStreamAdapter& operator=(BasicInputStreamAdapter&&) = default;
|
||||||
}
|
|
||||||
|
|
||||||
size_t currentReadPos() const {
|
void currentReadPos(size_t)
|
||||||
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
|
{
|
||||||
return {};
|
static_assert(std::is_void<TChar>::value,
|
||||||
}
|
"setting read position is not supported with StreamAdapter");
|
||||||
|
}
|
||||||
|
|
||||||
void currentReadEndPos(size_t ) {
|
size_t currentReadPos() const
|
||||||
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
|
{
|
||||||
}
|
static_assert(std::is_void<TChar>::value,
|
||||||
|
"setting read position is not supported with StreamAdapter");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
size_t currentReadEndPos() const {
|
void currentReadEndPos(size_t)
|
||||||
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
|
{
|
||||||
return {};
|
static_assert(std::is_void<TChar>::value,
|
||||||
}
|
"setting read position is not supported with StreamAdapter");
|
||||||
|
}
|
||||||
|
|
||||||
ReaderError error() const {
|
size_t currentReadEndPos() const
|
||||||
return _err;
|
{
|
||||||
}
|
static_assert(std::is_void<TChar>::value,
|
||||||
|
"setting read position is not supported with StreamAdapter");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
bool isCompletedSuccessfully() const {
|
ReaderError error() const { return _err; }
|
||||||
if (error() == ReaderError::NoError) {
|
|
||||||
return _ios->rdbuf()->sgetc() == CharTraits::eof();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void error(ReaderError error) {
|
bool isCompletedSuccessfully() const
|
||||||
if (_err == ReaderError::NoError) {
|
{
|
||||||
_err = error;
|
if (error() == ReaderError::NoError) {
|
||||||
_zeroIfNoErrors = std::numeric_limits<size_t>::max();
|
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>
|
private:
|
||||||
void readInternalValue(TValue* data) {
|
template<size_t SIZE>
|
||||||
readChecked(data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
void readInternalValue(TValue* data)
|
||||||
}
|
{
|
||||||
|
readChecked(
|
||||||
|
data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||||
|
}
|
||||||
|
|
||||||
void readInternalBuffer(TValue* data, size_t size) {
|
void readInternalBuffer(TValue* data, size_t size)
|
||||||
readChecked(data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
{
|
||||||
}
|
readChecked(
|
||||||
|
data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||||
|
}
|
||||||
|
|
||||||
void readChecked(TValue* data, size_t size, std::true_type) {
|
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 (size - static_cast<size_t>(_ios->rdbuf()->sgetn(
|
||||||
if (_zeroIfNoErrors == 0) {
|
data, static_cast<std::streamsize>(size))) !=
|
||||||
error(_ios->rdstate() == std::ios_base::badbit
|
_zeroIfNoErrors) {
|
||||||
? ReaderError::ReadingError
|
*data = {};
|
||||||
: ReaderError::DataOverflow);
|
if (_zeroIfNoErrors == 0) {
|
||||||
}
|
error(_ios->rdstate() == std::ios_base::badbit
|
||||||
}
|
? ReaderError::ReadingError
|
||||||
}
|
: ReaderError::DataOverflow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void readChecked(TValue* data, size_t size, std::false_type) {
|
void readChecked(TValue* data, size_t size, std::false_type)
|
||||||
_ios->rdbuf()->sgetn(data , static_cast<std::streamsize>(size));
|
{
|
||||||
}
|
_ios->rdbuf()->sgetn(data, static_cast<std::streamsize>(size));
|
||||||
|
}
|
||||||
|
|
||||||
std::basic_ios<TChar, CharTraits>* _ios;
|
std::basic_ios<TChar, CharTraits>* _ios;
|
||||||
size_t _zeroIfNoErrors{};
|
size_t _zeroIfNoErrors{};
|
||||||
ReaderError _err = ReaderError::NoError;
|
ReaderError _err = ReaderError::NoError;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TChar, typename Config, typename CharTraits>
|
template<typename TChar, typename Config, typename CharTraits>
|
||||||
class BasicOutputStreamAdapter: public details::OutputAdapterBaseCRTP<BasicOutputStreamAdapter<TChar, Config, CharTraits>> {
|
class BasicOutputStreamAdapter
|
||||||
public:
|
: public details::OutputAdapterBaseCRTP<
|
||||||
friend details::OutputAdapterBaseCRTP<BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
|
BasicOutputStreamAdapter<TChar, Config, CharTraits>>
|
||||||
using TConfig = Config;
|
{
|
||||||
using TValue = TChar;
|
public:
|
||||||
|
friend details::OutputAdapterBaseCRTP<
|
||||||
|
BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
|
||||||
|
|
||||||
BasicOutputStreamAdapter(std::basic_ostream<TChar, CharTraits>& ostream)
|
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<
|
||||||
:_ostream{std::addressof(ostream)} {}
|
BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
|
||||||
|
using TConfig = Config;
|
||||||
|
using TValue = TChar;
|
||||||
|
|
||||||
void currentWritePos(size_t ) {
|
BasicOutputStreamAdapter(std::basic_ostream<TChar, CharTraits>& ostream)
|
||||||
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
|
: _ostream{ std::addressof(ostream) }
|
||||||
}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
size_t currentWritePos() const {
|
void currentWritePos(size_t)
|
||||||
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
|
{
|
||||||
return {};
|
static_assert(std::is_void<TChar>::value,
|
||||||
}
|
"setting write position is not supported with StreamAdapter");
|
||||||
|
}
|
||||||
|
|
||||||
void flush() {
|
size_t currentWritePos() const
|
||||||
_ostream->flush();
|
{
|
||||||
}
|
static_assert(std::is_void<TChar>::value,
|
||||||
|
"setting write position is not supported with StreamAdapter");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
size_t writtenBytesCount() const {
|
void flush() { _ostream->flush(); }
|
||||||
static_assert(std::is_void<TChar>::value, "`writtenBytesCount` cannot be used with stream adapter");
|
|
||||||
//streaming doesn't return written bytes
|
|
||||||
return 0u;
|
|
||||||
}
|
|
||||||
|
|
||||||
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>
|
private:
|
||||||
void writeInternalValue(const TValue* data) {
|
template<size_t SIZE>
|
||||||
_ostream->rdbuf()->sputn( data , SIZE );
|
void writeInternalValue(const TValue* data)
|
||||||
}
|
{
|
||||||
|
_ostream->rdbuf()->sputn(data, SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
void writeInternalBuffer(const TValue* data, size_t size) {
|
void writeInternalBuffer(const TValue* data, size_t size)
|
||||||
_ostream->rdbuf()->sputn( data , 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>>
|
template<typename TChar,
|
||||||
class BasicBufferedOutputStreamAdapter:
|
typename Config,
|
||||||
public details::OutputAdapterBaseCRTP<BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>> {
|
typename CharTraits,
|
||||||
public:
|
typename TBuffer = std::array<TChar, 256>>
|
||||||
friend details::OutputAdapterBaseCRTP<BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>;
|
class BasicBufferedOutputStreamAdapter
|
||||||
using TConfig = Config;
|
: public details::OutputAdapterBaseCRTP<
|
||||||
using Buffer = TBuffer;
|
BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, 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");
|
public:
|
||||||
static_assert(traits::ContainerTraits<Buffer>::isContiguous, "BasicBufferedOutputStreamAdapter only works with contiguous containers");
|
friend details::OutputAdapterBaseCRTP<
|
||||||
using TValue = TChar;
|
BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>;
|
||||||
|
|
||||||
//bufferSize is used when buffer is dynamically allocated
|
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<
|
||||||
BasicBufferedOutputStreamAdapter(std::basic_ostream<TChar, CharTraits>& ostream, size_t bufferSize = 256)
|
BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>;
|
||||||
:_ostream(std::addressof(ostream)),
|
using TConfig = Config;
|
||||||
_buf{},
|
using Buffer = TBuffer;
|
||||||
_beginIt{std::begin(_buf)},
|
using BufferIt = typename traits::BufferAdapterTraits<TBuffer>::TIterator;
|
||||||
_currOffset{0}
|
static_assert(
|
||||||
{
|
details::IsDefined<BufferIt>::value,
|
||||||
init(bufferSize, TResizable{});
|
"Please define BufferAdapterTraits or include from <bitsery/traits/...> to "
|
||||||
// buffer size must be atleast 16, because writeIntervalValue expect that at least one value fits to buffer.
|
"use as buffer for BasicBufferedOutputStreamAdapter");
|
||||||
assert(_bufferSize >= 16);
|
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
|
// bufferSize is used when buffer is dynamically allocated
|
||||||
BasicBufferedOutputStreamAdapter(const BasicBufferedOutputStreamAdapter&) = delete;
|
BasicBufferedOutputStreamAdapter(
|
||||||
BasicBufferedOutputStreamAdapter& operator = (const BasicBufferedOutputStreamAdapter&) = delete;
|
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)
|
// we need to explicitly declare move logic, because after move buffer might
|
||||||
: _ostream{rhs._ostream},
|
// be invalidated
|
||||||
_buf{std::move(rhs._buf)},
|
BasicBufferedOutputStreamAdapter(const BasicBufferedOutputStreamAdapter&) =
|
||||||
_beginIt{std::begin(_buf)},
|
delete;
|
||||||
_currOffset{rhs._currOffset},
|
BasicBufferedOutputStreamAdapter& operator=(
|
||||||
_bufferSize{rhs._bufferSize}
|
const BasicBufferedOutputStreamAdapter&) = delete;
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
BasicBufferedOutputStreamAdapter& operator = (BasicBufferedOutputStreamAdapter&& rhs) {
|
BasicBufferedOutputStreamAdapter(BasicBufferedOutputStreamAdapter&& rhs)
|
||||||
_ostream = rhs._ostream;
|
: _ostream{ rhs._ostream }
|
||||||
_buf = std::move(rhs._buf);
|
, _buf{ std::move(rhs._buf) }
|
||||||
_beginIt = std::begin(_buf);
|
, _beginIt{ std::begin(_buf) }
|
||||||
_currOffset = rhs._currOffset;
|
, _currOffset{ rhs._currOffset }
|
||||||
_bufferSize = rhs._bufferSize;
|
, _bufferSize{ rhs._bufferSize } {};
|
||||||
return *this;
|
|
||||||
};
|
|
||||||
|
|
||||||
void currentWritePos(size_t ) {
|
BasicBufferedOutputStreamAdapter& operator=(
|
||||||
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
|
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 {
|
void currentWritePos(size_t)
|
||||||
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
|
{
|
||||||
return {};
|
static_assert(std::is_void<TChar>::value,
|
||||||
}
|
"setting write position is not supported with StreamAdapter");
|
||||||
|
}
|
||||||
|
|
||||||
void flush() {
|
size_t currentWritePos() const
|
||||||
writeBufferToStream();
|
{
|
||||||
_ostream->flush();
|
static_assert(std::is_void<TChar>::value,
|
||||||
}
|
"setting write position is not supported with StreamAdapter");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
size_t writtenBytesCount() const {
|
void flush()
|
||||||
static_assert(std::is_void<TChar>::value, "`writtenBytesCount` cannot be used with stream adapter");
|
{
|
||||||
//streaming doesn't return written bytes
|
writeBufferToStream();
|
||||||
return 0u;
|
_ostream->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
size_t writtenBytesCount() const
|
||||||
using TResizable = std::integral_constant<bool, traits::ContainerTraits<TBuffer>::isResizable>;
|
{
|
||||||
using diff_t = typename std::iterator_traits<BufferIt>::difference_type;
|
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>
|
private:
|
||||||
void writeInternalValue(const TValue* data) {
|
using TResizable =
|
||||||
auto newOffset = _currOffset + SIZE;
|
std::integral_constant<bool, traits::ContainerTraits<TBuffer>::isResizable>;
|
||||||
if (newOffset > _bufferSize) {
|
using diff_t = typename std::iterator_traits<BufferIt>::difference_type;
|
||||||
writeBufferToStream();
|
|
||||||
newOffset = SIZE;
|
|
||||||
}
|
|
||||||
std::copy_n(data, SIZE, _beginIt + static_cast<diff_t>(_currOffset));
|
|
||||||
_currOffset = newOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeInternalBuffer(const TValue* data, size_t size) {
|
template<size_t SIZE>
|
||||||
const auto newOffset = _currOffset + size;
|
void writeInternalValue(const TValue* data)
|
||||||
if (newOffset <= _bufferSize) {
|
{
|
||||||
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
|
writeInternalImpl(data, SIZE);
|
||||||
_currOffset = newOffset;
|
}
|
||||||
} else {
|
|
||||||
writeBufferToStream();
|
|
||||||
// write buffer directly to stream
|
|
||||||
_ostream->rdbuf()->sputn(data, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeBufferToStream() {
|
void writeInternalBuffer(const TValue* data, size_t size)
|
||||||
_ostream->rdbuf()->sputn(std::addressof(*_beginIt), static_cast<std::streamsize>(_currOffset));
|
{
|
||||||
_currOffset = 0;
|
writeInternalImpl(data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init (size_t buffSize, std::true_type) {
|
void writeInternalImpl(const TValue* data, size_t size)
|
||||||
// resize buffer
|
{
|
||||||
_bufferSize = buffSize;
|
const auto newOffset = _currOffset + size;
|
||||||
_buf.resize(_bufferSize);
|
if (newOffset <= _bufferSize) {
|
||||||
_beginIt = std::begin(_buf);
|
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
|
||||||
}
|
_currOffset = newOffset;
|
||||||
void init (size_t , std::false_type) {
|
} else {
|
||||||
// ignore buffer size parameter, and instead take actual buffer size
|
writeBufferToStream();
|
||||||
_bufferSize = traits::ContainerTraits<Buffer>::size(_buf);
|
// write buffer directly to stream
|
||||||
}
|
_ostream->rdbuf()->sputn(data, static_cast<std::streamsize>(size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::basic_ostream<TChar, CharTraits>* _ostream;
|
void writeBufferToStream()
|
||||||
TBuffer _buf;
|
{
|
||||||
BufferIt _beginIt;
|
_ostream->rdbuf()->sputn(std::addressof(*_beginIt),
|
||||||
size_t _currOffset;
|
static_cast<std::streamsize>(_currOffset));
|
||||||
size_t _bufferSize{0};
|
_currOffset = 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
template <typename TChar, typename Config, typename CharTraits>
|
void init(size_t buffSize, std::true_type)
|
||||||
class BasicIOStreamAdapter
|
{
|
||||||
: public BasicInputStreamAdapter<TChar, Config, CharTraits>
|
// resize buffer
|
||||||
, public BasicOutputStreamAdapter<TChar, Config, CharTraits>
|
_bufferSize = buffSize;
|
||||||
{
|
_buf.resize(_bufferSize);
|
||||||
public:
|
_beginIt = std::begin(_buf);
|
||||||
using TValue = TChar;
|
}
|
||||||
|
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
|
std::basic_ostream<TChar, CharTraits>* _ostream;
|
||||||
BasicIOStreamAdapter(std::basic_iostream<TChar, CharTraits>& iostream)
|
TBuffer _buf;
|
||||||
:BasicInputStreamAdapter<TChar, Config, CharTraits>{iostream}
|
BufferIt _beginIt;
|
||||||
,BasicOutputStreamAdapter<TChar, Config, CharTraits>{iostream}
|
size_t _currOffset;
|
||||||
{}
|
size_t _bufferSize{ 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
//helper types for most common implementations for std streams
|
template<typename TChar, typename Config, typename CharTraits>
|
||||||
using OutputStreamAdapter = BasicOutputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
|
class BasicIOStreamAdapter
|
||||||
using InputStreamAdapter = BasicInputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
|
: public BasicInputStreamAdapter<TChar, Config, CharTraits>
|
||||||
using IOStreamAdapter = BasicIOStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
|
, 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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BITSERY_H
|
#ifndef BITSERY_BITSERY_H
|
||||||
#define BITSERY_BITSERY_H
|
#define BITSERY_BITSERY_H
|
||||||
|
|
||||||
#define BITSERY_MAJOR_VERSION 5
|
#define BITSERY_MAJOR_VERSION 5
|
||||||
#define BITSERY_MINOR_VERSION 2
|
#define BITSERY_MINOR_VERSION 2
|
||||||
#define BITSERY_PATCH_VERSION 2
|
#define BITSERY_PATCH_VERSION 5
|
||||||
|
|
||||||
#define BITSERY_QUOTE_MACRO(name) #name
|
#define BITSERY_QUOTE_MACRO(name) #name
|
||||||
#define BITSERY_BUILD_VERSION_STR(major,minor, patch) \
|
#define BITSERY_BUILD_VERSION_STR(major, minor, patch) \
|
||||||
BITSERY_QUOTE_MACRO(major) "." \
|
BITSERY_QUOTE_MACRO(major) \
|
||||||
BITSERY_QUOTE_MACRO(minor) "." \
|
"." BITSERY_QUOTE_MACRO(minor) "." BITSERY_QUOTE_MACRO(patch)
|
||||||
BITSERY_QUOTE_MACRO(patch)
|
|
||||||
|
|
||||||
#define BITSERY_VERSION \
|
#define BITSERY_VERSION \
|
||||||
BITSERY_BUILD_VERSION_STR(BITSERY_MAJOR_VERSION, BITSERY_MINOR_VERSION, BITSERY_PATCH_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 "deserializer.h"
|
||||||
|
#include "serializer.h"
|
||||||
|
|
||||||
#endif //BITSERY_BITSERY_H
|
#endif // BITSERY_BITSERY_H
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_H
|
#ifndef BITSERY_BRIEF_SYNTAX_H
|
||||||
#define BITSERY_BRIEF_SYNTAX_H
|
#define BITSERY_BRIEF_SYNTAX_H
|
||||||
|
|
||||||
#include "details/serialization_common.h"
|
|
||||||
#include "details/brief_syntax_common.h"
|
#include "details/brief_syntax_common.h"
|
||||||
|
#include "details/serialization_common.h"
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
//define function that enables s(....) usage
|
// define function that enables s(....) usage
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
void processBriefSyntax(S& s, T&& head) {
|
void
|
||||||
static_assert(std::is_lvalue_reference<T>::value || std::is_base_of<brief_syntax::ModFnc, T>::value,
|
processBriefSyntax(S& s, T&& head)
|
||||||
"Argument must be either lvalue or subclass of brief_syntax::ModFnc");
|
{
|
||||||
s.object(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
|
// wrapper functions that enables to serialize as container or string
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
brief_syntax::CArray<T, N, true> asText(T (& str)[N]) {
|
brief_syntax::CArray<T, N, true>
|
||||||
return {str};
|
asText(T (&str)[N])
|
||||||
}
|
{
|
||||||
|
return { str };
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
brief_syntax::CArray<T, N, false> asContainer(T (& obj)[N]) {
|
brief_syntax::CArray<T, N, false>
|
||||||
return {obj};
|
asContainer(T (&obj)[N])
|
||||||
}
|
{
|
||||||
|
return { obj };
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
brief_syntax::MaxSize<T> maxSize(T& obj, size_t max) {
|
brief_syntax::MaxSize<T>
|
||||||
return {obj, max};
|
maxSize(T& obj, size_t max)
|
||||||
}
|
{
|
||||||
|
return { obj, max };
|
||||||
|
}
|
||||||
|
|
||||||
//define serialize function for fundamental types
|
// define serialize function for fundamental types
|
||||||
template<typename S>
|
template<typename S>
|
||||||
void serialize(S& s, bool& v) {
|
void
|
||||||
s.boolValue(v);
|
serialize(S& s, bool& v)
|
||||||
}
|
{
|
||||||
|
s.boolValue(v);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename S, typename T, typename std::enable_if<details::IsFundamentalType<T>::value>::type * = nullptr>
|
template<typename S,
|
||||||
void serialize(S& s, T& v) {
|
typename T,
|
||||||
s.template value<sizeof(T)>(v);
|
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
|
// if array is integral type, specify explicitly how to process: as text or
|
||||||
template<typename S, typename T, size_t N, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
|
// container
|
||||||
void serialize(S&, T (&)[N]) {
|
template<typename S,
|
||||||
static_assert(N == 0,
|
typename T,
|
||||||
"\nPlease use 'asText(obj)' or 'asContainer(obj)' when using c-style array with integral types\n");
|
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>
|
template<typename S,
|
||||||
void serialize(S& s, T (& obj)[N]) {
|
typename T,
|
||||||
brief_syntax::processContainer(s, obj);
|
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
|
// this is a helper class that enforce fundamental type sizes, when used on
|
||||||
template<size_t TShort, size_t TInt, size_t TLong, size_t TLongLong>
|
// multiple platforms
|
||||||
void assertFundamentalTypeSizes() {
|
template<size_t TShort, size_t TInt, size_t TLong, size_t TLongLong>
|
||||||
//http://en.cppreference.com/w/cpp/language/types
|
void
|
||||||
static_assert(sizeof(short) == TShort, "");
|
assertFundamentalTypeSizes()
|
||||||
static_assert(sizeof(int) == TInt, "");
|
{
|
||||||
static_assert(sizeof(long) == TLong, "");
|
// http://en.cppreference.com/w/cpp/language/types
|
||||||
static_assert(sizeof(long long) == TLongLong, "");
|
static_assert(sizeof(short) == TShort, "");
|
||||||
//for completion we also need pointer type size, but serializer doesn't support pointer serialization.
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_ARRAY_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_ARRAY_H
|
||||||
#define 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 "../details/brief_syntax_common.h"
|
||||||
|
#include "../traits/array.h"
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename T, size_t N>
|
template<typename S, typename T, size_t N>
|
||||||
void serialize(S &s, std::array<T, N> &obj) {
|
void
|
||||||
brief_syntax::processContainer(s, obj);
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_ATOMIC_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_ATOMIC_H
|
||||||
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_ATOMIC_H
|
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_ATOMIC_H
|
||||||
@@ -26,10 +26,12 @@
|
|||||||
#include "../ext/std_atomic.h"
|
#include "../ext/std_atomic.h"
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
void serialize(S &s, std::atomic<T> &obj) {
|
void
|
||||||
s.template ext<sizeof(T)>(obj, ext::StdAtomic{});
|
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
|
||||||
|
|||||||
36
include/bitsery/brief_syntax/bitset.h
Normal file
36
include/bitsery/brief_syntax/bitset.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Mindaugas Vinkelis
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_BITSET_H
|
||||||
|
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_BITSET_H
|
||||||
|
|
||||||
|
#include "../ext/std_bitset.h"
|
||||||
|
|
||||||
|
namespace bitsery {
|
||||||
|
template<typename S, size_t N>
|
||||||
|
void
|
||||||
|
serialize(S& s, std::bitset<N>& obj)
|
||||||
|
{
|
||||||
|
s.ext(obj, ext::StdBitset{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_CHRONO_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_CHRONO_H
|
||||||
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_CHRONO_H
|
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_CHRONO_H
|
||||||
@@ -26,15 +26,19 @@
|
|||||||
#include "../ext/std_chrono.h"
|
#include "../ext/std_chrono.h"
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename T, typename P>
|
template<typename S, typename T, typename P>
|
||||||
void serialize(S &s, std::chrono::duration<T, P> &obj) {
|
void
|
||||||
s.template ext<sizeof(T)>(obj, ext::StdDuration{});
|
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{});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_DEQUE_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_DEQUE_H
|
||||||
#define 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 "../details/brief_syntax_common.h"
|
||||||
|
#include "../traits/deque.h"
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename T, typename Allocator>
|
template<typename S, typename T, typename Allocator>
|
||||||
void serialize(S &s, std::deque<T, Allocator> &obj) {
|
void
|
||||||
brief_syntax::processContainer(s, obj);
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_FORWARD_LIST_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_FORWARD_LIST_H
|
||||||
#define 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 "../details/brief_syntax_common.h"
|
||||||
|
#include "../traits/forward_list.h"
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename T, typename Allocator>
|
template<typename S, typename T, typename Allocator>
|
||||||
void serialize(S &s, std::forward_list<T, Allocator> &obj) {
|
void
|
||||||
brief_syntax::processContainer(s, obj);
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_LIST_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_LIST_H
|
||||||
#define 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 "../details/brief_syntax_common.h"
|
||||||
|
#include "../traits/list.h"
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename T, typename Allocator>
|
template<typename S, typename T, typename Allocator>
|
||||||
void serialize(S &s, std::list<T, Allocator> &obj) {
|
void
|
||||||
brief_syntax::processContainer(s, obj);
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_MAP_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_MAP_H
|
||||||
#define 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 "../ext/std_map.h"
|
||||||
|
#include <limits>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename Key, typename T, typename Compare, typename Allocator>
|
template<typename S,
|
||||||
void serialize(S &s, std::map<Key, T, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
|
typename Key,
|
||||||
s.ext(obj, ext::StdMap{maxSize},
|
typename T,
|
||||||
[](S& s, Key& key, T& value) {
|
typename Compare,
|
||||||
s.object(key);
|
typename Allocator>
|
||||||
s.object(value);
|
void
|
||||||
});
|
serialize(S& s,
|
||||||
}
|
std::map<Key, T, Compare, Allocator>& obj,
|
||||||
|
size_t maxSize = std::numeric_limits<size_t>::max())
|
||||||
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.ext(obj, ext::StdMap{maxSize},
|
s.object(key);
|
||||||
[](S& s, Key& key, T& value) {
|
s.object(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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_MEMORY_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_MEMORY_H
|
||||||
#define 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"
|
#include "../ext/std_smart_ptr.h"
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename T, typename D>
|
template<typename S, typename T, typename D>
|
||||||
void serialize(S &s, std::unique_ptr<T, D> &obj) {
|
void
|
||||||
s.ext(obj, ext::StdSmartPtr{});
|
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{});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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
|
||||||
|
|||||||
36
include/bitsery/brief_syntax/optional.h
Normal file
36
include/bitsery/brief_syntax/optional.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2018 Mindaugas Vinkelis
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_OPTIONAL_H
|
||||||
|
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_OPTIONAL_H
|
||||||
|
|
||||||
|
#include "../ext/std_optional.h"
|
||||||
|
|
||||||
|
namespace bitsery {
|
||||||
|
template<typename S, typename Ts>
|
||||||
|
void
|
||||||
|
serialize(S& s, std::optional<Ts>& obj)
|
||||||
|
{
|
||||||
|
s.ext(obj, ext::StdOptional{});
|
||||||
|
}
|
||||||
|
} // namespace bitsery
|
||||||
|
#endif
|
||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_QUEUE_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_QUEUE_H
|
||||||
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_QUEUE_H
|
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_QUEUE_H
|
||||||
@@ -28,16 +27,24 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename T, typename C>
|
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()) {
|
void
|
||||||
s.ext(obj, ext::StdQueue{maxSize});
|
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>
|
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()) {
|
void
|
||||||
s.ext(obj, ext::StdQueue{maxSize});
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_SET_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_SET_H
|
||||||
#define 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 "../ext/std_set.h"
|
||||||
|
#include <limits>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename Key, typename Compare, typename Allocator>
|
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()) {
|
void
|
||||||
s.ext(obj, ext::StdSet{maxSize});
|
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>
|
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()) {
|
void
|
||||||
s.ext(obj, ext::StdSet{maxSize});
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_STACK_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_STACK_H
|
||||||
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_STACK_H
|
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_STACK_H
|
||||||
|
|
||||||
#include <limits>
|
|
||||||
#include "../ext/std_stack.h"
|
#include "../ext/std_stack.h"
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename T, typename C>
|
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()) {
|
void
|
||||||
s.ext(obj, ext::StdStack{maxSize});
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_STRING_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_STRING_H
|
||||||
#define 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 "../details/brief_syntax_common.h"
|
||||||
|
#include "../traits/string.h"
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename CharT, typename Traits, typename Allocator>
|
template<typename S, typename CharT, typename Traits, typename Allocator>
|
||||||
void serialize(S &s, std::basic_string<CharT, Traits, Allocator> &str) {
|
void
|
||||||
brief_syntax::processContainer(s, str);
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_TUPLE_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_TUPLE_H
|
||||||
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_TUPLE_H
|
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_TUPLE_H
|
||||||
@@ -26,10 +26,12 @@
|
|||||||
#include "../ext/std_tuple.h"
|
#include "../ext/std_tuple.h"
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename ...Ts>
|
template<typename S, typename... Ts>
|
||||||
void serialize(S &s, std::tuple<Ts...> &obj) {
|
void
|
||||||
s.ext(obj, ext::StdTuple{});
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_MAP_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_MAP_H
|
||||||
#define 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 "../ext/std_map.h"
|
||||||
|
#include <limits>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
|
template<typename S,
|
||||||
void serialize(S &s, std::unordered_map<Key, T, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
|
typename Key,
|
||||||
s.ext(obj, ext::StdMap{maxSize},
|
typename T,
|
||||||
[](S& s, Key& key, T& value) {
|
typename Hash,
|
||||||
s.object(key);
|
typename KeyEqual,
|
||||||
s.object(value);
|
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>
|
template<typename S,
|
||||||
void serialize(S &s, std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
|
typename Key,
|
||||||
s.ext(obj, ext::StdMap{maxSize},
|
typename T,
|
||||||
[](S& s, Key& key, T& value) {
|
typename Hash,
|
||||||
s.object(key);
|
typename KeyEqual,
|
||||||
s.object(value);
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_SET_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_SET_H
|
||||||
#define 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 <limits>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include "../ext/std_set.h"
|
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename Key, typename Hash, typename KeyEqual, typename Allocator>
|
template<typename S,
|
||||||
void serialize(S &s, std::unordered_set<Key, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
|
typename Key,
|
||||||
s.ext(obj, ext::StdSet{maxSize});
|
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>
|
template<typename S,
|
||||||
void serialize(S &s, std::unordered_multiset<Key, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
|
typename Key,
|
||||||
s.ext(obj, ext::StdSet{maxSize});
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_VARIANT_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_VARIANT_H
|
||||||
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_VARIANT_H
|
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_VARIANT_H
|
||||||
@@ -26,10 +26,12 @@
|
|||||||
#include "../ext/std_variant.h"
|
#include "../ext/std_variant.h"
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename ...Ts>
|
template<typename S, typename... Ts>
|
||||||
void serialize(S &s, std::variant<Ts...> &obj) {
|
void
|
||||||
s.ext(obj, ext::StdVariant{});
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_VECTOR_H
|
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_VECTOR_H
|
||||||
#define 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 "../details/brief_syntax_common.h"
|
||||||
|
#include "../traits/vector.h"
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
template<typename S, typename T, typename Allocator>
|
template<typename S, typename T, typename Allocator>
|
||||||
void serialize(S &s, std::vector<T, Allocator> &obj) {
|
void
|
||||||
brief_syntax::processContainer(s, obj);
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_COMMON_H
|
#ifndef BITSERY_COMMON_H
|
||||||
#define BITSERY_COMMON_H
|
#define BITSERY_COMMON_H
|
||||||
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* endianness
|
* endianness
|
||||||
*/
|
*/
|
||||||
enum class EndiannessType {
|
enum class EndiannessType
|
||||||
LittleEndian,
|
{
|
||||||
BigEndian
|
LittleEndian,
|
||||||
};
|
BigEndian
|
||||||
|
};
|
||||||
|
|
||||||
// default configuration for serialization and deserialization
|
// default configuration for serialization and deserialization
|
||||||
struct DefaultConfig {
|
struct DefaultConfig
|
||||||
// defines endianness of data that is read from input adapter and written to output adapter.
|
{
|
||||||
static constexpr EndiannessType Endianness = EndiannessType::LittleEndian;
|
// defines endianness of data that is read from input adapter and written to
|
||||||
// these flags allow to improve deserialization performance if data is trusted
|
// output adapter.
|
||||||
// enables/disables checks for buffer end or stream read errors in input adapter
|
static constexpr EndiannessType Endianness = EndiannessType::LittleEndian;
|
||||||
static constexpr bool CheckAdapterErrors = true;
|
// these flags allow to improve deserialization performance if data is trusted
|
||||||
// enables/disables checks for other errors that can significantly affect performance
|
// enables/disables checks for buffer end or stream read errors in input
|
||||||
static constexpr bool CheckDataErrors = true;
|
// 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
379
include/bitsery/details/adapter_bit_packing.h
Normal file
379
include/bitsery/details/adapter_bit_packing.h
Normal 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
|
||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_DETAILS_ADAPTER_COMMON_H
|
#ifndef BITSERY_DETAILS_ADAPTER_COMMON_H
|
||||||
#define 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 "../common.h"
|
||||||
|
#include "not_defined_type.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <climits>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
enum class ReaderError {
|
enum class ReaderError
|
||||||
NoError,
|
{
|
||||||
ReadingError, // this might be used with stream adapter
|
NoError,
|
||||||
DataOverflow,
|
ReadingError, // this might be used with stream adapter
|
||||||
InvalidData,
|
DataOverflow,
|
||||||
InvalidPointer
|
InvalidData,
|
||||||
};
|
InvalidPointer
|
||||||
|
};
|
||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* size read/write functions
|
* 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{});
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Reader>
|
template<typename Reader>
|
||||||
void handleReadMaxSize(Reader& r, size_t& size, size_t maxSize, std::true_type) {
|
void
|
||||||
if (size > maxSize) {
|
handleReadMaxSize(Reader& r, size_t& size, size_t maxSize, std::true_type)
|
||||||
r.error(ReaderError::InvalidData);
|
{
|
||||||
size = {};
|
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&, 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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_DETAILS_BRIEF_SYNTAX_COMMON_H
|
#ifndef BITSERY_DETAILS_BRIEF_SYNTAX_COMMON_H
|
||||||
#define BITSERY_DETAILS_BRIEF_SYNTAX_COMMON_H
|
#define BITSERY_DETAILS_BRIEF_SYNTAX_COMMON_H
|
||||||
@@ -28,123 +28,173 @@
|
|||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace brief_syntax {
|
namespace brief_syntax {
|
||||||
|
|
||||||
//these function overloads is required to apply maxSize, and optimize for fundamental types
|
// these function overloads is required to apply maxSize, and optimize for
|
||||||
//for contigous arrays of fundamenal types, memcpy will be applied
|
// fundamental types for contigous arrays of fundamenal types, memcpy will be
|
||||||
|
// applied
|
||||||
|
|
||||||
template<typename S, typename T, typename std::enable_if<
|
template<typename S,
|
||||||
details::IsFundamentalType<typename traits::ContainerTraits<T>::TValue>::value
|
typename T,
|
||||||
&& traits::ContainerTraits<T>::isResizable
|
typename std::enable_if<
|
||||||
>::type * = nullptr>
|
details::IsFundamentalType<
|
||||||
void processContainer(S &s, T &c, size_t maxSize = std::numeric_limits<size_t>::max()) {
|
typename traits::ContainerTraits<T>::TValue>::value &&
|
||||||
using TValue = typename traits::ContainerTraits<T>::TValue;
|
traits::ContainerTraits<T>::isResizable>::type* = nullptr>
|
||||||
s.template container<sizeof(TValue)>(c, maxSize);
|
void
|
||||||
}
|
processContainer(S& s,
|
||||||
|
T& c,
|
||||||
template<typename S, typename T, typename std::enable_if<
|
size_t maxSize = std::numeric_limits<size_t>::max())
|
||||||
!details::IsFundamentalType<typename traits::ContainerTraits<T>::TValue>::value
|
{
|
||||||
&& traits::ContainerTraits<T>::isResizable
|
using TValue = typename traits::ContainerTraits<T>::TValue;
|
||||||
>::type * = nullptr>
|
s.template container<sizeof(TValue)>(c, maxSize);
|
||||||
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
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_DETAILS_NOT_DEFINED_TYPE_H
|
#ifndef BITSERY_DETAILS_NOT_DEFINED_TYPE_H
|
||||||
#define BITSERY_DETAILS_NOT_DEFINED_TYPE_H
|
#define BITSERY_DETAILS_NOT_DEFINED_TYPE_H
|
||||||
@@ -27,53 +26,56 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace details {
|
namespace details {
|
||||||
//this type is used to show clearer error messages
|
// this type is used to show clearer error messages
|
||||||
struct NotDefinedType {
|
struct NotDefinedType
|
||||||
//just swallow anything that is passed during creating
|
{
|
||||||
template <typename ... T>
|
// just swallow anything that is passed during creating
|
||||||
NotDefinedType(T&& ...){}
|
template<typename... T>
|
||||||
NotDefinedType() = default;
|
NotDefinedType(T&&...)
|
||||||
//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&) {
|
NotDefinedType() = default;
|
||||||
return true;
|
// 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
|
||||||
friend bool operator != (const NotDefinedType&, const NotDefinedType&) {
|
// to work with iterators
|
||||||
return false;
|
friend bool operator==(const NotDefinedType&, const NotDefinedType&)
|
||||||
}
|
{
|
||||||
NotDefinedType& operator += (int) {
|
return true;
|
||||||
return *this;
|
}
|
||||||
}
|
friend bool operator!=(const NotDefinedType&, const NotDefinedType&)
|
||||||
NotDefinedType& operator -= (int) {
|
{
|
||||||
return *this;
|
return false;
|
||||||
}
|
}
|
||||||
|
NotDefinedType& operator+=(int) { return *this; }
|
||||||
|
NotDefinedType& operator-=(int) { return *this; }
|
||||||
|
|
||||||
friend int operator - (const NotDefinedType&, const NotDefinedType&) {
|
friend int operator-(const NotDefinedType&, const NotDefinedType&)
|
||||||
return 0;
|
{
|
||||||
}
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int& operator*() {
|
int& operator*() { return data; }
|
||||||
return data;
|
int data{};
|
||||||
}
|
};
|
||||||
int data{};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template<typename T>
|
||||||
struct IsDefined:public std::integral_constant<bool, !std::is_same<NotDefinedType, T>::value> {
|
struct IsDefined
|
||||||
};
|
: public std::integral_constant<bool, !std::is_same<NotDefinedType, T>::value>
|
||||||
}
|
{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
//define iterator traits to work with standart algorithms
|
// define iterator traits to work with standart algorithms
|
||||||
template <>
|
template<>
|
||||||
struct iterator_traits<bitsery::details::NotDefinedType> {
|
struct iterator_traits<bitsery::details::NotDefinedType>
|
||||||
using difference_type = int;
|
{
|
||||||
using value_type = int;
|
using difference_type = int;
|
||||||
using pointer = int*;
|
using value_type = int;
|
||||||
using reference = int&;
|
using pointer = int*;
|
||||||
using iterator_category = std::random_access_iterator_tag;
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_DETAILS_SERIALIZATION_COMMON_H
|
#ifndef BITSERY_DETAILS_SERIALIZATION_COMMON_H
|
||||||
#define 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 "../traits/core/traits.h"
|
||||||
|
#include "adapter_common.h"
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
//this allows to call private serialize method, and construct instance (if no default constructor is provided) for your type
|
// this allows to call private serialize method, and construct instance (if no
|
||||||
//just make friend it in your class
|
// default constructor is provided) for your type just make friend it in your
|
||||||
class Access {
|
// class
|
||||||
public:
|
class Access
|
||||||
template<typename S, typename T>
|
{
|
||||||
static auto serialize(S &s, T &obj) -> decltype(obj.serialize(s)) {
|
public:
|
||||||
obj.serialize(s);
|
template<typename S, typename T>
|
||||||
}
|
static auto serialize(S& s, T& obj) -> decltype(obj.serialize(s))
|
||||||
|
{
|
||||||
|
obj.serialize(s);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
template<typename T>
|
||||||
static T create() {
|
static T create()
|
||||||
//if you get an error here, please create default constructor
|
{
|
||||||
return T{};
|
// if you get an error here, please create default constructor
|
||||||
}
|
return T{};
|
||||||
template <typename T>
|
}
|
||||||
static T* create(void* ptr) {
|
template<typename T>
|
||||||
return new(ptr) 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
|
template<typename Ext>
|
||||||
// e.g. instead of writing this:
|
struct FtorExtObject : public Ext
|
||||||
// s.container(c, 100, [](S& s, float& v) { s.ext4b(v, CompactValue{});});
|
{
|
||||||
// you can write like this
|
template<typename S, typename T>
|
||||||
// s.container(c, 100, FtorExtValue2b<CompactValue>{});
|
void operator()(S& s, T& v) const
|
||||||
template<size_t N, typename Ext>
|
{
|
||||||
struct FtorExtValue : public Ext {
|
s.ext(v, static_cast<const Ext&>(*this));
|
||||||
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>
|
// when call to serialize function is ambiguous (member and non-member serialize
|
||||||
struct FtorExtValue1b: FtorExtValue<1, Ext> {};
|
// function exists for a type) specialize this class by inheriting from either
|
||||||
template <typename Ext>
|
// UseNonMemberFnc or UseMemberFnc e.g. template <> struct
|
||||||
struct FtorExtValue2b: FtorExtValue<2, Ext> {};
|
// SelectSerializeFnc<MyDerivedClass>:UseMemberFnc {};
|
||||||
template <typename Ext>
|
template<typename T>
|
||||||
struct FtorExtValue4b: FtorExtValue<4, Ext> {};
|
struct SelectSerializeFnc : std::integral_constant<int, 0>
|
||||||
template <typename Ext>
|
{};
|
||||||
struct FtorExtValue8b: FtorExtValue<8, Ext> {};
|
|
||||||
template <typename Ext>
|
|
||||||
struct FtorExtValue16b: FtorExtValue<16, Ext> {};
|
|
||||||
|
|
||||||
template<typename Ext>
|
// types you need to inherit from when specializing SelectSerializeFnc class
|
||||||
struct FtorExtObject : public Ext {
|
struct UseNonMemberFnc : std::integral_constant<int, 1>
|
||||||
template <typename S, typename T>
|
{};
|
||||||
void operator()(S& s, T& v) const {
|
struct UseMemberFnc : std::integral_constant<int, 2>
|
||||||
s.ext(v, static_cast<const Ext&>(*this));
|
{};
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
namespace details {
|
||||||
|
|
||||||
//when call to serialize function is ambiguous (member and non-member serialize function exists for a type)
|
// helper types for error handling
|
||||||
//specialize this class by inheriting from either UseNonMemberFnc or UseMemberFnc
|
template<typename T>
|
||||||
//e.g.
|
struct IsContainerTraitsDefined
|
||||||
//template <> struct SelectSerializeFnc<MyDerivedClass>:UseMemberFnc {};
|
: public IsDefined<typename traits::ContainerTraits<T>::TValue>
|
||||||
template<typename T>
|
{};
|
||||||
struct SelectSerializeFnc : std::integral_constant<int, 0> {
|
|
||||||
};
|
|
||||||
|
|
||||||
//types you need to inherit from when specializing SelectSerializeFnc class
|
template<typename T>
|
||||||
struct UseNonMemberFnc : std::integral_constant<int, 1> {
|
struct IsTextTraitsDefined
|
||||||
};
|
: public IsDefined<typename traits::TextTraits<T>::TValue>
|
||||||
struct UseMemberFnc : std::integral_constant<int, 2> {
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
namespace details {
|
template<typename Ext, typename T>
|
||||||
|
struct IsExtensionTraitsDefined
|
||||||
//helper types for error handling
|
: public IsDefined<typename traits::ExtensionTraits<Ext, T>::TValue>
|
||||||
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> {
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
//helper types for HasSerializeFunction
|
// helper types for HasSerializeFunction
|
||||||
template <typename S, typename T>
|
template<typename S, typename T>
|
||||||
using TrySerializeFunction = decltype(serialize(std::declval<S &>(), std::declval<T &>()));
|
using TrySerializeFunction =
|
||||||
|
decltype(serialize(std::declval<S&>(), std::declval<T&>()));
|
||||||
|
|
||||||
template <typename S, typename T>
|
template<typename S, typename T>
|
||||||
struct HasSerializeFunctionHelper {
|
struct HasSerializeFunctionHelper
|
||||||
template <typename Q, typename R, typename = TrySerializeFunction<Q, R>>
|
{
|
||||||
static std::true_type tester(Q&&, R&&);
|
template<typename Q, typename R, typename = TrySerializeFunction<Q, R>>
|
||||||
static std::false_type tester(...);
|
static std::true_type tester(Q&&, R&&);
|
||||||
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
|
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 HasSerializeFunction : HasSerializeFunctionHelper<S, T>::type
|
||||||
|
{};
|
||||||
|
|
||||||
//helper types for HasSerializeMethod
|
// helper types for HasSerializeMethod
|
||||||
template <typename S, typename T>
|
template<typename S, typename T>
|
||||||
using TrySerializeMethod = decltype(Access::serialize(std::declval<S &>(), std::declval<T &>()));
|
using TrySerializeMethod =
|
||||||
|
decltype(Access::serialize(std::declval<S&>(), std::declval<T&>()));
|
||||||
|
|
||||||
template <typename S, typename T>
|
template<typename S, typename T>
|
||||||
struct HasSerializeMethodHelper {
|
struct HasSerializeMethodHelper
|
||||||
template <typename Q, typename R, typename = TrySerializeMethod<Q, R>>
|
{
|
||||||
static std::true_type tester(Q&&, R&&);
|
template<typename Q, typename R, typename = TrySerializeMethod<Q, R>>
|
||||||
static std::false_type tester(...);
|
static std::true_type tester(Q&&, R&&);
|
||||||
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
|
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 HasSerializeMethod : HasSerializeMethodHelper<S, T>::type
|
||||||
|
{};
|
||||||
|
|
||||||
//helper types for IsBriefSyntaxIncluded
|
// helper types for IsBriefSyntaxIncluded
|
||||||
template <typename S, typename T>
|
template<typename S, typename T>
|
||||||
using TryProcessBriefSyntax = decltype(processBriefSyntax(std::declval<S &>(), std::declval<T &&>()));
|
using TryProcessBriefSyntax =
|
||||||
|
decltype(processBriefSyntax(std::declval<S&>(), std::declval<T&&>()));
|
||||||
|
|
||||||
template <typename S, typename T>
|
template<typename S, typename T>
|
||||||
struct IsBriefSyntaxIncludedHelper {
|
struct IsBriefSyntaxIncludedHelper
|
||||||
template <typename Q, typename R, typename = TryProcessBriefSyntax<Q, R>>
|
{
|
||||||
static std::true_type tester(Q&&, R&&);
|
template<typename Q, typename R, typename = TryProcessBriefSyntax<Q, R>>
|
||||||
static std::false_type tester(...);
|
static std::true_type tester(Q&&, R&&);
|
||||||
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
|
static std::false_type tester(...);
|
||||||
};
|
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
|
||||||
|
};
|
||||||
|
|
||||||
template <typename S, typename T>
|
template<typename S, typename T>
|
||||||
struct IsBriefSyntaxIncluded :IsBriefSyntaxIncludedHelper<S, T>::type {};
|
struct IsBriefSyntaxIncluded : IsBriefSyntaxIncludedHelper<S, T>::type
|
||||||
|
{};
|
||||||
#else
|
#else
|
||||||
//helper metafunction, that is added to c++17
|
// helper metafunction, that is added to c++17
|
||||||
template<typename... Ts>
|
template<typename... Ts>
|
||||||
struct make_void {
|
struct make_void
|
||||||
typedef void type;
|
{
|
||||||
};
|
typedef void type;
|
||||||
template<typename... Ts>
|
};
|
||||||
using void_t = typename make_void<Ts...>::type;
|
template<typename... Ts>
|
||||||
|
using void_t = typename make_void<Ts...>::type;
|
||||||
|
|
||||||
template<typename, typename, typename = void>
|
template<typename, typename, typename = void>
|
||||||
struct HasSerializeFunction : std::false_type {
|
struct HasSerializeFunction : std::false_type
|
||||||
};
|
{};
|
||||||
|
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
struct HasSerializeFunction<S, T,
|
struct HasSerializeFunction<
|
||||||
void_t<decltype(serialize(std::declval<S &>(), std::declval<T &>()))>
|
S,
|
||||||
> : std::true_type {
|
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>
|
template<typename S, typename T>
|
||||||
struct HasSerializeMethod : std::false_type {
|
struct HasSerializeMethod<
|
||||||
};
|
S,
|
||||||
|
T,
|
||||||
|
void_t<decltype(Access::serialize(std::declval<S&>(), std::declval<T&>()))>>
|
||||||
|
: std::true_type
|
||||||
|
{};
|
||||||
|
|
||||||
template<typename S, typename T>
|
// this solution doesn't work with visual studio, but is more elegant
|
||||||
struct HasSerializeMethod<S, T,
|
template<typename, typename, typename = void>
|
||||||
void_t<decltype(Access::serialize(std::declval<S &>(), std::declval<T &>()))>
|
struct IsBriefSyntaxIncluded : std::false_type
|
||||||
> : std::true_type {
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
//this solution doesn't work with visual studio, but is more elegant
|
template<typename S, typename T>
|
||||||
template<typename, typename, typename = void>
|
struct IsBriefSyntaxIncluded<
|
||||||
struct IsBriefSyntaxIncluded : std::false_type {
|
S,
|
||||||
};
|
T,
|
||||||
|
void_t<decltype(processBriefSyntax(std::declval<S&>(), std::declval<T&&>()))>>
|
||||||
template<typename S, typename T>
|
: std::true_type
|
||||||
struct IsBriefSyntaxIncluded<S, T,
|
{};
|
||||||
void_t<decltype(processBriefSyntax(std::declval<S &>(), std::declval<T &&>()))>
|
|
||||||
> : std::true_type {
|
|
||||||
};
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// used for extensions when extension TValue = void
|
||||||
//used for extensions when extension TValue = void
|
struct DummyType
|
||||||
struct DummyType {
|
{};
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* this includes all integral types, floats and enums(except bool)
|
* this includes all integral types, floats and enums(except bool)
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IsFundamentalType : std::integral_constant<bool,
|
struct IsFundamentalType
|
||||||
std::is_enum<T>::value
|
: std::integral_constant<bool,
|
||||||
|| std::is_floating_point<T>::value
|
std::is_enum<T>::value ||
|
||||||
|| std::is_integral<T>::value> {
|
std::is_floating_point<T>::value ||
|
||||||
};
|
std::is_integral<T>::value>
|
||||||
|
{};
|
||||||
|
|
||||||
template<typename T, typename Integral = void>
|
template<typename T, typename Integral = void>
|
||||||
struct IntegralFromFundamental {
|
struct IntegralFromFundamental
|
||||||
using TValue = T;
|
{
|
||||||
};
|
using TValue = T;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IntegralFromFundamental<T, typename std::enable_if<std::is_enum<T>::value>::type> {
|
struct IntegralFromFundamental<
|
||||||
using TValue = typename std::underlying_type<T>::type;
|
T,
|
||||||
};
|
typename std::enable_if<std::is_enum<T>::value>::type>
|
||||||
|
{
|
||||||
|
using TValue = typename std::underlying_type<T>::type;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IntegralFromFundamental<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
|
struct IntegralFromFundamental<
|
||||||
using TValue = typename std::conditional<std::is_same<T, float>::value, uint32_t, uint64_t>::type;
|
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>
|
template<typename T>
|
||||||
struct UnsignedFromFundamental {
|
struct UnsignedFromFundamental
|
||||||
using type = typename std::make_unsigned<typename IntegralFromFundamental<T>::TValue>::type;
|
{
|
||||||
};
|
using type = typename std::make_unsigned<
|
||||||
|
typename IntegralFromFundamental<T>::TValue>::type;
|
||||||
template<typename T>
|
};
|
||||||
using SameSizeUnsigned = typename UnsignedFromFundamental<T>::type;
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
using SameSizeUnsigned = typename UnsignedFromFundamental<T>::type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* functions for object serialization
|
* functions for object serialization
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename S, typename T>
|
template<typename S, typename T>
|
||||||
struct SerializeFunction {
|
struct SerializeFunction
|
||||||
|
{
|
||||||
|
|
||||||
static void invoke(S &s, T &v) {
|
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"
|
static_assert(HasSerializeFunction<S, T>::value ||
|
||||||
" template<typename S>\n"
|
HasSerializeMethod<S, T>::value,
|
||||||
" void serialize(S& s)\n"
|
"\nPlease define 'serialize' function for your type (inside "
|
||||||
" {\n"
|
"or outside of class):\n"
|
||||||
" ...\n"
|
" template<typename S>\n"
|
||||||
" }\n");
|
" void serialize(S& s)\n"
|
||||||
using TDecayed = typename std::decay<T>::type;
|
" {\n"
|
||||||
selectSerializeFnc(s, v, SelectSerializeFnc<TDecayed>{});
|
" ...\n"
|
||||||
}
|
" }\n");
|
||||||
|
using TDecayed = typename std::decay<T>::type;
|
||||||
|
selectSerializeFnc(s, v, SelectSerializeFnc<TDecayed>{});
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr bool isDefined() {
|
static constexpr bool isDefined()
|
||||||
return HasSerializeFunction<S, T>::value || HasSerializeMethod<S, T>::value;
|
{
|
||||||
}
|
return HasSerializeFunction<S, T>::value || HasSerializeMethod<S, T>::value;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void selectSerializeFnc(S &s, T &v, std::integral_constant<int, 0>) {
|
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"
|
static_assert(
|
||||||
"If serialization function is inherited from base class, then explicitly select correct function for your type e.g.:\n"
|
!(HasSerializeFunction<S, T>::value && HasSerializeMethod<S, T>::value),
|
||||||
" template <>\n"
|
"\nPlease define only one 'serialize' function (member OR free).\n"
|
||||||
" struct SelectSerializeFnc<DerivedClass>:UseMemberFnc {};\n");
|
"If serialization function is inherited from base class, then explicitly "
|
||||||
selectSerializeFnc(s, v, std::integral_constant<int,
|
"select correct function for your type e.g.:\n"
|
||||||
HasSerializeFunction<S, T>::value ? 1 : 2>{});
|
" 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>) {
|
static void selectSerializeFnc(S& s, T& v, std::integral_constant<int, 1>)
|
||||||
serialize(s, v);
|
{
|
||||||
}
|
serialize(s, v);
|
||||||
|
}
|
||||||
|
|
||||||
static void selectSerializeFnc(S &s, T &v, std::integral_constant<int, 2>) {
|
static void selectSerializeFnc(S& s, T& v, std::integral_constant<int, 2>)
|
||||||
Access::serialize(s, v);
|
{
|
||||||
}
|
Access::serialize(s, v);
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* functions for object serialization
|
* functions for object serialization
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename S, typename T, typename Enabled = void>
|
template<typename S, typename T, typename Enabled = void>
|
||||||
struct BriefSyntaxFunction {
|
struct BriefSyntaxFunction
|
||||||
|
{
|
||||||
|
|
||||||
static void invoke(S &s, T &&obj) {
|
static void invoke(S& s, T&& obj)
|
||||||
static_assert(IsBriefSyntaxIncluded<S, T>::value,
|
{
|
||||||
"\nPlease include '<bitsery/brief_syntax.h>' to use operator():\n");
|
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>
|
template<int Index, typename... Conds>
|
||||||
struct FindIndex : std::integral_constant<int, Index> {};
|
struct FindIndex : std::integral_constant<int, Index>
|
||||||
|
{};
|
||||||
|
|
||||||
template<int Index, typename Cond, typename... Conds>
|
template<int Index, typename Cond, typename... Conds>
|
||||||
struct FindIndex<Index, Cond, Conds...> :
|
struct FindIndex<Index, Cond, Conds...>
|
||||||
std::conditional<Cond::value, std::integral_constant<int, Index>, FindIndex<Index+1, Conds...>>::type
|
: std::conditional<Cond::value,
|
||||||
{};
|
std::integral_constant<int, Index>,
|
||||||
|
FindIndex<Index + 1, Conds...>>::type
|
||||||
|
{};
|
||||||
|
|
||||||
template <typename T, typename Tuple>
|
template<typename T, typename Tuple>
|
||||||
struct GetConvertibleTypeIndexFromTuple;
|
struct GetConvertibleTypeIndexFromTuple;
|
||||||
|
|
||||||
template <typename T, typename... Us>
|
template<typename T, typename... Us>
|
||||||
struct GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>> : FindIndex<0, std::is_convertible<Us&, T&>...> {};
|
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>
|
template<typename T, typename... Us>
|
||||||
struct IsExistsConvertibleTupleType;
|
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...>> :
|
* get context from internal or external, and check if it's convertible or not
|
||||||
std::integral_constant<bool, GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>::value != sizeof...(Us)> {};
|
*/
|
||||||
|
|
||||||
|
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 TContext>
|
||||||
* get context from internal or external, and check if it's convertible or not
|
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>
|
template<bool AssertExists, typename TCast, typename... TArgs>
|
||||||
TCast* getDirectlyIfExists(TContext& ctx, std::true_type) {
|
TCast*
|
||||||
return &static_cast<TCast&>(ctx);
|
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>
|
// non tuple context
|
||||||
TCast* getDirectlyIfExists(TContext& , std::false_type) {
|
template<bool AssertExists, typename TCast, typename TContext>
|
||||||
// TCast cannot be convertible from provided context
|
TCast*
|
||||||
static_assert(!AssertExists,
|
getContext(TContext& ctx)
|
||||||
"Invalid context cast. Context type doesn't exists.\nSome functionality requires (de)seserializer to have specific context.");
|
{
|
||||||
return nullptr;
|
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>
|
template<typename Adapter, typename Context>
|
||||||
TCast* getFromTupleIfExists(std::tuple<TArgs...>& ctx, std::true_type) {
|
class AdapterAndContextRef
|
||||||
using TupleIndex = GetConvertibleTypeIndexFromTuple<TCast, std::tuple<TArgs...>>;
|
{
|
||||||
return &static_cast<TCast&>(std::get<TupleIndex::value>(ctx));
|
public:
|
||||||
}
|
static constexpr bool HasContext = true;
|
||||||
|
using Config = typename Adapter::TConfig;
|
||||||
|
|
||||||
template<bool AssertExists, typename TCast, typename ... TArgs>
|
// constructing adapter in place is important,
|
||||||
TCast* getFromTupleIfExists(std::tuple<TArgs...>& , std::false_type) {
|
// because enableBitPacking might create instance with bit write/read enabled
|
||||||
// TCast cannot be convertible from provided context
|
// adapter wrapper, which has non trivial destructor
|
||||||
static_assert(!AssertExists,
|
template<typename... TArgs>
|
||||||
"Invalid context cast. Context type doesn't exists.\nSome functionality requires (de)seserializer to have specific context.");
|
explicit AdapterAndContextRef(Context& ctx, TArgs&&... args)
|
||||||
return nullptr;
|
: _adapter{ std::forward<TArgs>(args)... }
|
||||||
}
|
, _context{ ctx }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
//non tuple context
|
/*
|
||||||
template<bool AssertExists, typename TCast, typename TContext>
|
* get serialization context.
|
||||||
TCast* getContext(TContext& ctx) {
|
* this is optional, but might be required for some specific serialization
|
||||||
return getDirectlyIfExists<AssertExists, TCast>(ctx, std::is_convertible<TContext&, TCast&>{});
|
* flows.
|
||||||
}
|
*/
|
||||||
|
|
||||||
//tuple context
|
template<typename T>
|
||||||
template<bool AssertExists, typename TCast, typename ... TArgs>
|
T& context()
|
||||||
TCast* getContext(std::tuple<TArgs...>& ctx) {
|
{
|
||||||
return getFromTupleIfExists<AssertExists, TCast>(ctx, IsExistsConvertibleTupleType<TCast, std::tuple<TArgs...>>{});
|
return *getContext<true, T>(_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Adapter, typename Context>
|
template<typename T>
|
||||||
class AdapterAndContextRef {
|
T* contextOrNull()
|
||||||
public:
|
{
|
||||||
static constexpr bool HasContext = true;
|
return getContext<false, T>(_context);
|
||||||
using Config = typename Adapter::TConfig;
|
}
|
||||||
|
|
||||||
// constructing adapter in place is important,
|
Adapter& adapter() & { return _adapter; }
|
||||||
// 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 std::move(_adapter); }
|
||||||
* get serialization context.
|
|
||||||
* this is optional, but might be required for some specific serialization flows.
|
|
||||||
*/
|
|
||||||
|
|
||||||
template <typename T>
|
protected:
|
||||||
T& context() {
|
Adapter _adapter;
|
||||||
return *getContext<true, T>(_context);
|
Context& _context;
|
||||||
}
|
};
|
||||||
|
|
||||||
template <typename T>
|
template<typename Adapter>
|
||||||
T* contextOrNull() {
|
class AdapterAndContextRef<Adapter, void>
|
||||||
return getContext<false, T>(_context);
|
{
|
||||||
}
|
public:
|
||||||
|
static constexpr bool HasContext = false;
|
||||||
|
using Config = typename Adapter::TConfig;
|
||||||
|
|
||||||
Adapter& adapter() & {
|
template<typename... TArgs>
|
||||||
return _adapter;
|
explicit AdapterAndContextRef(TArgs&&... args)
|
||||||
}
|
: _adapter{ std::forward<TArgs>(args)... }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
Adapter adapter() && {
|
template<typename T>
|
||||||
return std::move(_adapter);
|
T& context()
|
||||||
}
|
{
|
||||||
|
static_assert(std::is_void<T>::value, "Context is not defined (is void).");
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
template<typename T>
|
||||||
Adapter _adapter;
|
T* contextOrNull()
|
||||||
Context& _context;
|
{
|
||||||
};
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Adapter>
|
Adapter& adapter() & { return _adapter; }
|
||||||
class AdapterAndContextRef<Adapter, void> {
|
|
||||||
public:
|
|
||||||
static constexpr bool HasContext = false;
|
|
||||||
using Config = typename Adapter::TConfig;
|
|
||||||
|
|
||||||
template <typename ... TArgs>
|
Adapter adapter() && { return std::move(_adapter); }
|
||||||
explicit AdapterAndContextRef(TArgs&& ... args)
|
|
||||||
: _adapter{std::forward<TArgs>(args)...}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
protected:
|
||||||
T& context() {
|
Adapter _adapter;
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* other helper meta-functions
|
* other helper meta-functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T, template<typename...> class Template>
|
template<typename T, template<typename...> class Template>
|
||||||
struct IsSpecializationOf : std::false_type {
|
struct IsSpecializationOf : std::false_type
|
||||||
};
|
{};
|
||||||
|
|
||||||
template<template<typename...> class Template, typename... Args>
|
template<template<typename...> class Template, typename... Args>
|
||||||
struct IsSpecializationOf<Template<Args...>, Template> : std::true_type {
|
struct IsSpecializationOf<Template<Args...>, Template> : std::true_type
|
||||||
};
|
{};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //BITSERY_DETAILS_SERIALIZATION_COMMON_H
|
#endif // BITSERY_DETAILS_SERIALIZATION_COMMON_H
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_COMPACT_VALUE_H
|
#ifndef BITSERY_EXT_COMPACT_VALUE_H
|
||||||
#define BITSERY_EXT_COMPACT_VALUE_H
|
#define BITSERY_EXT_COMPACT_VALUE_H
|
||||||
|
|
||||||
#include "../details/serialization_common.h"
|
#include "../details/serialization_common.h"
|
||||||
#include "../details/adapter_common.h"
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
template <bool CheckOverflow>
|
template<bool CheckOverflow>
|
||||||
class CompactValueImpl {
|
class CompactValueImpl
|
||||||
public:
|
{
|
||||||
|
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>
|
template<typename Des, typename T, typename Fnc>
|
||||||
void serialize(Ser &s, const T &v, Fnc &&) const {
|
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;
|
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
|
||||||
serializeImpl(s.adapter(), reinterpret_cast<const TValue&>(v), std::integral_constant<bool, sizeof(T) != 1>{});
|
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>
|
private:
|
||||||
void deserialize(Des &d, T &v, Fnc &&) const {
|
// if value is 1byte size, just serialize/ deserialize whole value
|
||||||
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
|
template<typename Writer, typename T>
|
||||||
using TValue = typename IntegralFromFundamental<T>::TValue;
|
void serializeImpl(Writer& writer, const T& v, std::false_type) const
|
||||||
deserializeImpl(d.adapter(), reinterpret_cast<TValue &>(v), std::integral_constant<bool, sizeof(T) != 1>{});
|
{
|
||||||
}
|
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
|
// when value is bigger than 1byte size,
|
||||||
template<typename Writer, typename T>
|
template<typename Writer, typename T>
|
||||||
void serializeImpl(Writer &writer, const T &v, std::false_type) const {
|
void serializeImpl(Writer& writer, const T& v, std::true_type) const
|
||||||
writer.template writeBytes<1>(v);
|
{
|
||||||
}
|
auto val = zigZagEncode(
|
||||||
|
v, std::is_signed<typename IntegralFromFundamental<T>::TValue>{});
|
||||||
|
writeBytes(writer, val);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Reader, typename T>
|
template<typename Reader, typename T>
|
||||||
void deserializeImpl(Reader &reader, T &v, std::false_type) const {
|
void deserializeImpl(Reader& reader, T& v, std::true_type) const
|
||||||
reader.template readBytes<1>(v);
|
{
|
||||||
}
|
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,
|
// zigzag encode signed types
|
||||||
template<typename Writer, typename T>
|
template<typename T>
|
||||||
void serializeImpl(Writer &writer, const T &v, std::true_type) const {
|
const SameSizeUnsigned<T>& zigZagEncode(const T& v, std::false_type) const
|
||||||
auto val = zigZagEncode(v, std::is_signed<typename IntegralFromFundamental<T>::TValue>{});
|
{
|
||||||
writeBytes(writer, val);
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename TResult, typename TUnsigned>
|
||||||
|
const TResult& zigZagDecode(const TUnsigned& v, std::false_type) const
|
||||||
|
{
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Reader, typename T>
|
template<typename T>
|
||||||
void deserializeImpl(Reader &reader, T &v, std::true_type) const {
|
SameSizeUnsigned<T> zigZagEncode(const T& v, std::true_type) const
|
||||||
using TUnsigned = SameSizeUnsigned<T>;
|
{
|
||||||
TUnsigned res{};
|
return static_cast<SameSizeUnsigned<T>>((v << 1) ^
|
||||||
readBytes<Reader::TConfig::CheckDataErrors>(reader, res);
|
(v >> (BitsSize<T>::value - 1)));
|
||||||
v = zigZagDecode<T>(res, std::is_signed<typename IntegralFromFundamental<T>::TValue>{});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// zigzag encode signed types
|
template<typename TResult, typename TUnsigned>
|
||||||
template<typename T>
|
TResult zigZagDecode(TUnsigned v, std::true_type) const
|
||||||
const SameSizeUnsigned<T> &zigZagEncode(const T &v, std::false_type) const {
|
{
|
||||||
return v;
|
return static_cast<TResult>(
|
||||||
}
|
(v >> 1) ^
|
||||||
|
(~(v & 1) + 1)); // same as -(v & 1), but no warning on VisualStudio
|
||||||
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 {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// 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 {
|
template<bool CheckErrors, typename Reader, typename T>
|
||||||
|
void readBytes(Reader& r, T& v) const
|
||||||
// this type will use value overload, and do not check if type is sufficiently large during deserialization
|
{
|
||||||
class CompactValue: public details::CompactValueImpl<false> {};
|
using TFast = typename FastType<T>::type;
|
||||||
|
constexpr auto TBITS = sizeof(T) * 8;
|
||||||
// this type will enable object overload, and set DataOverflow if value doesn't fit in type, during deserialization
|
uint8_t b1{ 0x80u };
|
||||||
class CompactValueAsObject: public details::CompactValueImpl<true> {};
|
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);
|
||||||
namespace traits {
|
handleReadOverflow<Reader, T>(r,
|
||||||
|
i,
|
||||||
template<typename T>
|
b1,
|
||||||
struct ExtensionTraits<ext::CompactValue, T> {
|
std::integral_constant < bool,
|
||||||
using TValue = T;
|
CheckOverflow&& CheckErrors > {});
|
||||||
static constexpr bool SupportValueOverload = true;
|
}
|
||||||
// disable object overload, because we don't have implemented serialization function for fundamental types
|
template<typename Reader, typename T>
|
||||||
static constexpr bool SupportObjectOverload = false;
|
void handleReadOverflow(Reader& r,
|
||||||
static constexpr bool SupportLambdaOverload = false;
|
unsigned shiftedBy,
|
||||||
};
|
uint8_t remainder,
|
||||||
|
std::true_type) const
|
||||||
template<typename T>
|
{
|
||||||
struct ExtensionTraits<ext::CompactValueAsObject, T> {
|
constexpr auto TBITS = sizeof(T) * 8;
|
||||||
// use dummy implemenations for value and object overload
|
if (shiftedBy > TBITS && remainder >> (TBITS + 7 - shiftedBy)) {
|
||||||
using TValue = void;
|
r.error(bitsery::ReaderError::InvalidData);
|
||||||
// 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_ENTROPY_H
|
#ifndef BITSERY_EXT_ENTROPY_H
|
||||||
#define BITSERY_EXT_ENTROPY_H
|
#define BITSERY_EXT_ENTROPY_H
|
||||||
@@ -27,78 +27,88 @@
|
|||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace details {
|
namespace details {
|
||||||
template<typename TValue, typename TContainer>
|
template<typename TValue, typename TContainer>
|
||||||
size_t findEntropyIndex(const TValue &v, const TContainer &defValues) {
|
size_t
|
||||||
size_t index{1u};
|
findEntropyIndex(const TValue& v, const TContainer& defValues)
|
||||||
for (auto &d:defValues) {
|
{
|
||||||
if (d == v)
|
size_t index{ 1u };
|
||||||
return index;
|
for (auto& d : defValues) {
|
||||||
++index;
|
if (d == v)
|
||||||
}
|
return index;
|
||||||
return 0u;
|
++index;
|
||||||
}
|
}
|
||||||
}
|
return 0u;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
template<typename TContainer>
|
template<typename TContainer>
|
||||||
class Entropy {
|
class Entropy
|
||||||
public:
|
{
|
||||||
|
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 } {};
|
||||||
|
|
||||||
/**
|
template<typename Ser, typename T, typename Fnc>
|
||||||
* Allows entropy-encoding technique, by writing few bits for most common values
|
void serialize(Ser& s, const T& obj, Fnc&& fnc) const
|
||||||
* @param values list of most common values
|
{
|
||||||
* @param alignBeforeData only makes sense when bit-packing enabled, by default aligns after writing bits for index
|
assert(traits::ContainerTraits<TContainer>::size(_values) > 0);
|
||||||
*/
|
auto index = details::findEntropyIndex(obj, _values);
|
||||||
constexpr Entropy(TContainer& values, bool alignBeforeData=true)
|
s.ext(index,
|
||||||
: _values{values},
|
ext::ValueRange<size_t>{
|
||||||
_alignBeforeData{alignBeforeData} {
|
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>
|
template<typename Des, typename T, typename Fnc>
|
||||||
void serialize(Ser &s, const T &obj, Fnc &&fnc) const {
|
void deserialize(Des& d, T& obj, Fnc&& fnc) const
|
||||||
assert(traits::ContainerTraits<TContainer>::size(_values) > 0);
|
{
|
||||||
auto index = details::findEntropyIndex(obj, _values);
|
assert(traits::ContainerTraits<TContainer>::size(_values) > 0);
|
||||||
s.ext(index, ext::ValueRange<size_t>{0u, traits::ContainerTraits<TContainer>::size(_values)});
|
size_t index{};
|
||||||
if (_alignBeforeData)
|
d.ext(index,
|
||||||
s.adapter().align();
|
ext::ValueRange<size_t>{
|
||||||
if (!index)
|
0u, traits::ContainerTraits<TContainer>::size(_values) });
|
||||||
fnc(s, const_cast<T &>(obj));
|
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>
|
private:
|
||||||
void deserialize(Des &d, T &obj, Fnc &&fnc) const {
|
TContainer& _values;
|
||||||
assert(traits::ContainerTraits<TContainer>::size(_values) > 0);
|
bool _alignBeforeData;
|
||||||
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:
|
namespace traits {
|
||||||
TContainer& _values;
|
template<typename TContainer, typename T>
|
||||||
bool _alignBeforeData;
|
struct ExtensionTraits<ext::Entropy<TContainer>, T>
|
||||||
};
|
{
|
||||||
}
|
using TValue = T;
|
||||||
|
static constexpr bool SupportValueOverload = true;
|
||||||
namespace traits {
|
static constexpr bool SupportObjectOverload = true;
|
||||||
template<typename TContainer, typename T>
|
static constexpr bool SupportLambdaOverload = true;
|
||||||
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
|
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_GROWABLE_H
|
#ifndef BITSERY_EXT_GROWABLE_H
|
||||||
#define BITSERY_EXT_GROWABLE_H
|
#define BITSERY_EXT_GROWABLE_H
|
||||||
|
|
||||||
#include "../traits/core/traits.h"
|
#include "../traits/core/traits.h"
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* enables forward and backward compatibility, by allowing to append additional data at the end of serialization
|
* enables forward and backward compatibility, by allowing to append additional
|
||||||
* old deserialization method will ignore additional data by jumping through it at the end of deserialization flow
|
* data at the end of serialization old deserialization method will ignore
|
||||||
* new deserialization method will read all 0 for new fields if there is no data for it
|
* 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
|
||||||
class Growable {
|
* it
|
||||||
public:
|
*/
|
||||||
|
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>
|
fnc(ser, const_cast<T&>(obj));
|
||||||
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));
|
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();
|
template<typename Des, typename T, typename Fnc>
|
||||||
writer.currentWritePos(startPos);
|
void deserialize(Des& des, T& obj, Fnc&& fnc) const
|
||||||
writer.template writeBytes<4>(static_cast<uint32_t>(endPos - startPos));
|
{
|
||||||
writer.currentWritePos(endPos);
|
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>
|
fnc(des, obj);
|
||||||
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);
|
reader.currentReadPos(startPos + size);
|
||||||
|
reader.currentReadEndPos(readEndPos);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
reader.currentReadPos(startPos + size);
|
namespace traits {
|
||||||
reader.currentReadEndPos(readEndPos);
|
template<typename T>
|
||||||
}
|
struct ExtensionTraits<ext::Growable, T>
|
||||||
};
|
{
|
||||||
}
|
using TValue = T;
|
||||||
|
static constexpr bool SupportValueOverload = false;
|
||||||
namespace traits {
|
static constexpr bool SupportObjectOverload = true;
|
||||||
template<typename T>
|
static constexpr bool SupportLambdaOverload = true;
|
||||||
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
|
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_INHERITANCE_H
|
#ifndef BITSERY_EXT_INHERITANCE_H
|
||||||
#define BITSERY_EXT_INHERITANCE_H
|
#define BITSERY_EXT_INHERITANCE_H
|
||||||
|
|
||||||
#include <unordered_set>
|
|
||||||
#include "../traits/core/traits.h"
|
|
||||||
#include "../ext/utils/memory_resource.h"
|
#include "../ext/utils/memory_resource.h"
|
||||||
|
#include "../traits/core/traits.h"
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
//required when virtual inheritance (ext::VirtualBaseClass) exists in serialization flow.
|
// required when virtual inheritance (ext::VirtualBaseClass) exists in
|
||||||
//for standard inheritance (ext::BaseClass) it is optional.
|
// serialization flow. for standard inheritance (ext::BaseClass) it is optional.
|
||||||
class InheritanceContext {
|
class InheritanceContext
|
||||||
public:
|
{
|
||||||
explicit InheritanceContext(MemResourceBase* memResource = nullptr)
|
public:
|
||||||
:_virtualBases{pointer_utils::StdPolyAlloc<const void*>{memResource}}
|
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(const InheritanceContext&) = delete;
|
||||||
InheritanceContext& operator = (InheritanceContext&&) = default;
|
InheritanceContext& operator=(const InheritanceContext&) = delete;
|
||||||
|
InheritanceContext(InheritanceContext&&) = default;
|
||||||
template <typename TDerived, typename TBase>
|
InheritanceContext& operator=(InheritanceContext&&) = default;
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
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 TDerived, typename TBase>
|
||||||
template<typename TBase, typename T>
|
bool beginVirtualBase(const TDerived& derived, const TBase& base)
|
||||||
struct ExtensionTraits<ext::BaseClass<TBase>, T> {
|
{
|
||||||
static_assert(std::is_base_of<TBase, T>::value, "Invalid base class");
|
beginBase(derived, base);
|
||||||
|
return _virtualBases.emplace(std::addressof(base)).second;
|
||||||
|
}
|
||||||
|
|
||||||
using TValue = TBase;
|
void end() { --_depth; }
|
||||||
static constexpr bool SupportValueOverload = false;
|
|
||||||
static constexpr bool SupportObjectOverload = true;
|
|
||||||
static constexpr bool SupportLambdaOverload = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename TBase, typename T>
|
private:
|
||||||
struct ExtensionTraits<ext::VirtualBaseClass<TBase>, T> {
|
// these members are required to know when we can clear _virtualBases
|
||||||
static_assert(std::is_base_of<TBase, T>::value, "Invalid base class");
|
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;
|
template<typename TBase>
|
||||||
static constexpr bool SupportValueOverload = false;
|
class BaseClass
|
||||||
static constexpr bool SupportObjectOverload = true;
|
{
|
||||||
//disable lambda overload, when serializing virtually inherited base class.
|
public:
|
||||||
//Only one instance of virtual base will be serialized, when using multiple inheritance
|
template<typename Ser, typename T, typename Fnc>
|
||||||
//and it will be undefined behaviour if derived classes would have different virtual base class serialization flow.
|
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
|
||||||
static constexpr bool SupportLambdaOverload = false;
|
{
|
||||||
};
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_POINTER_H
|
#ifndef BITSERY_EXT_POINTER_H
|
||||||
#define BITSERY_EXT_POINTER_H
|
#define BITSERY_EXT_POINTER_H
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include "../traits/core/traits.h"
|
#include "../traits/core/traits.h"
|
||||||
#include "utils/pointer_utils.h"
|
#include "utils/pointer_utils.h"
|
||||||
#include "utils/polymorphism_utils.h"
|
#include "utils/polymorphism_utils.h"
|
||||||
#include "utils/rtti_utils.h"
|
#include "utils/rtti_utils.h"
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
namespace pointer_details {
|
namespace pointer_details {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct PtrOwnerManager {
|
struct PtrOwnerManager
|
||||||
static_assert(std::is_pointer<T>::value, "");
|
{
|
||||||
|
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) {
|
static TElement* getPtr(T& obj) { return obj; }
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr PointerOwnershipType getOwnership() {
|
static constexpr PointerOwnershipType getOwnership()
|
||||||
return PointerOwnershipType::Owner;
|
{
|
||||||
}
|
return PointerOwnershipType::Owner;
|
||||||
|
}
|
||||||
|
|
||||||
static void create(T& obj, pointer_utils::PolyAllocWithTypeId alloc, size_t typeId) {
|
static void create(T& obj,
|
||||||
obj = alloc.newObject<TElement>(typeId);
|
pointer_utils::PolyAllocWithTypeId alloc,
|
||||||
}
|
size_t typeId)
|
||||||
|
{
|
||||||
|
obj = alloc.newObject<TElement>(typeId);
|
||||||
|
}
|
||||||
|
|
||||||
static void createPolymorphic(T& obj, pointer_utils::PolyAllocWithTypeId alloc,
|
static void createPolymorphic(
|
||||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
T& obj,
|
||||||
obj = static_cast<TElement*>(handler->create(alloc));
|
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) {
|
static void destroy(T& obj,
|
||||||
alloc.deleteObject(obj, typeId);
|
pointer_utils::PolyAllocWithTypeId alloc,
|
||||||
obj = nullptr;
|
size_t typeId)
|
||||||
}
|
{
|
||||||
|
alloc.deleteObject(obj, typeId);
|
||||||
|
obj = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
static void destroyPolymorphic(T& obj, pointer_utils::PolyAllocWithTypeId alloc,
|
static void destroyPolymorphic(
|
||||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
T& obj,
|
||||||
handler->destroy(alloc, obj);
|
pointer_utils::PolyAllocWithTypeId alloc,
|
||||||
obj = nullptr;
|
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>
|
using TElement = typename std::remove_pointer<T>::type;
|
||||||
struct PtrObserverManager {
|
|
||||||
static_assert(std::is_pointer<T>::value, "");
|
|
||||||
|
|
||||||
using TElement = typename std::remove_pointer<T>::type;
|
static TElement* getPtr(T& obj) { return obj; }
|
||||||
|
|
||||||
static TElement* getPtr(T& obj) {
|
static constexpr PointerOwnershipType getOwnership()
|
||||||
return obj;
|
{
|
||||||
}
|
return PointerOwnershipType::Observer;
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr PointerOwnershipType getOwnership() {
|
// pure observer doesn't have create/createPolymorphic methods, but instead
|
||||||
return PointerOwnershipType::Observer;
|
// 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
|
static void destroy(T& obj, MemResourceBase*, size_t) { obj = nullptr; }
|
||||||
//which gets updated later
|
|
||||||
static TElement*& getPtrRef(T& obj) {
|
|
||||||
return obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void destroy(T& obj, MemResourceBase* , size_t ) {
|
static void destroyPolymorphic(T& obj,
|
||||||
obj = nullptr;
|
MemResourceBase*,
|
||||||
}
|
const std::shared_ptr<PolymorphicHandlerBase>&)
|
||||||
|
{
|
||||||
|
obj = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static void destroyPolymorphic(T& obj, MemResourceBase* , PolymorphicHandlerBase& ) {
|
template<typename T>
|
||||||
obj = nullptr;
|
struct NonPtrManager
|
||||||
}
|
{
|
||||||
|
|
||||||
};
|
static_assert(!std::is_pointer<T>::value, "");
|
||||||
|
|
||||||
template<typename T>
|
using TElement = T;
|
||||||
struct NonPtrManager {
|
|
||||||
|
|
||||||
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) {
|
// this code is unreachable for reference type, but is necessary to compile
|
||||||
return &obj;
|
// LCOV_EXCL_START
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr PointerOwnershipType getOwnership() {
|
static void create(T&, MemResourceBase*, size_t) {}
|
||||||
return PointerOwnershipType::Owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this code is unreachable for reference type, but is necessary to compile
|
static void createPolymorphic(T&,
|
||||||
// LCOV_EXCL_START
|
MemResourceBase*,
|
||||||
|
const std::shared_ptr<PolymorphicHandlerBase>&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
static void create(T& , MemResourceBase* , size_t ) {
|
static void destroy(T&, MemResourceBase*, size_t) {}
|
||||||
|
|
||||||
}
|
static void destroyPolymorphic(T&,
|
||||||
|
MemResourceBase*,
|
||||||
static void createPolymorphic(T& , MemResourceBase* , PolymorphicHandlerBase& ) {
|
const std::shared_ptr<PolymorphicHandlerBase>&)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
// LCOV_EXCL_STOP
|
||||||
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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_STD_ATOMIC_H
|
#ifndef BITSERY_EXT_STD_ATOMIC_H
|
||||||
#define BITSERY_EXT_STD_ATOMIC_H
|
#define BITSERY_EXT_STD_ATOMIC_H
|
||||||
@@ -27,39 +27,41 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
class StdAtomic {
|
class StdAtomic
|
||||||
public:
|
{
|
||||||
|
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>
|
template<typename Des, typename T, typename Fnc>
|
||||||
void serialize(Ser& ser, const std::atomic<T>& obj, Fnc&& fnc) const {
|
void deserialize(Des& des, std::atomic<T>& obj, Fnc&& fnc) const
|
||||||
auto res = obj.load();
|
{
|
||||||
fnc(ser, res);
|
T res{};
|
||||||
}
|
fnc(des, res);
|
||||||
|
obj.store(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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_STD_BITSET_H
|
#ifndef BITSERY_EXT_STD_BITSET_H
|
||||||
#define BITSERY_EXT_STD_BITSET_H
|
#define BITSERY_EXT_STD_BITSET_H
|
||||||
|
|
||||||
#include "../traits/core/traits.h"
|
#include "../traits/core/traits.h"
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
class StdBitset {
|
class StdBitset
|
||||||
public:
|
{
|
||||||
|
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>
|
} else {
|
||||||
void serialize(Ser &ser, const std::bitset<N> &obj, Fnc &&) const {
|
// more performant way
|
||||||
constexpr size_t BYTES = N / 8;
|
auto data = obj.to_ullong();
|
||||||
constexpr size_t LEFTOVER = N % 8;
|
for (size_t i = 0u; i < BYTES; ++i) {
|
||||||
if (BYTES > sizeof(unsigned long long)) {
|
ser.value1b(static_cast<uint8_t>(data & 0xFF));
|
||||||
for(size_t i = 0u; i < BYTES; ++i) {
|
data >>= 8;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
if (LEFTOVER > 0) {
|
||||||
namespace traits {
|
serializeLeftoverImpl(ser.adapter(),
|
||||||
template<size_t N>
|
obj,
|
||||||
struct ExtensionTraits<ext::StdBitset, std::bitset<N>> {
|
N - LEFTOVER,
|
||||||
using TValue = void;
|
N,
|
||||||
static constexpr bool SupportValueOverload = false;
|
std::is_same<Ser, typename Ser::BPEnabledType>{});
|
||||||
static constexpr bool SupportObjectOverload = true;
|
|
||||||
static constexpr bool SupportLambdaOverload = false;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_STD_CHRONO_H
|
#ifndef BITSERY_EXT_STD_CHRONO_H
|
||||||
#define BITSERY_EXT_STD_CHRONO_H
|
#define BITSERY_EXT_STD_CHRONO_H
|
||||||
@@ -27,68 +27,91 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
class StdDuration {
|
class StdDuration
|
||||||
public:
|
{
|
||||||
|
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>
|
template<typename Des, typename T, typename Period, typename Fnc>
|
||||||
void serialize(Ser& ser, const std::chrono::duration<T, Period>& obj, Fnc&& fnc) const {
|
void deserialize(Des& des,
|
||||||
auto res = obj.count();
|
std::chrono::duration<T, Period>& obj,
|
||||||
fnc(ser, res);
|
Fnc&& fnc) const
|
||||||
}
|
{
|
||||||
|
T res{};
|
||||||
|
fnc(des, res);
|
||||||
|
obj = std::chrono::duration<T, Period>{ res };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename Des, typename T, typename Period, typename Fnc>
|
class StdTimePoint
|
||||||
void deserialize(Des& des, std::chrono::duration<T, Period>& obj, Fnc&& fnc) const {
|
{
|
||||||
T res{};
|
public:
|
||||||
fnc(des, res);
|
template<typename Ser,
|
||||||
obj = std::chrono::duration<T, Period>{res};
|
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 {
|
template<typename Des,
|
||||||
public:
|
typename Clock,
|
||||||
|
typename T,
|
||||||
template<typename Ser, typename Clock, typename T, typename Period, typename Fnc>
|
typename Period,
|
||||||
void serialize(Ser& ser, const std::chrono::time_point<Clock, std::chrono::duration<T, Period>>& obj,
|
typename Fnc>
|
||||||
Fnc&& fnc) const {
|
void deserialize(
|
||||||
auto res = obj.time_since_epoch().count();
|
Des& des,
|
||||||
fnc(ser, res);
|
std::chrono::time_point<Clock, std::chrono::duration<T, Period>>& obj,
|
||||||
}
|
Fnc&& fnc) const
|
||||||
|
{
|
||||||
template<typename Des, typename Clock, typename T, typename Period, typename Fnc>
|
T res{};
|
||||||
void deserialize(Des& des, std::chrono::time_point<Clock, std::chrono::duration<T, Period>>& obj,
|
fnc(des, res);
|
||||||
Fnc&& fnc) const {
|
auto dur = std::chrono::duration<T, Period>{ res };
|
||||||
T res{};
|
obj =
|
||||||
fnc(des, res);
|
std::chrono::time_point<Clock, std::chrono::duration<T, Period>>{ dur };
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_STD_MAP_H
|
#ifndef BITSERY_EXT_STD_MAP_H
|
||||||
#define 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"
|
#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>
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
class StdMap {
|
class StdMap
|
||||||
public:
|
{
|
||||||
|
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>
|
for (auto& v : obj)
|
||||||
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
|
fnc(ser, const_cast<TKey&>(v.first), const_cast<TValue&>(v.second));
|
||||||
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)
|
template<typename Des, typename T, typename Fnc>
|
||||||
fnc(ser, const_cast<TKey &>(v.first), const_cast<TValue &>(v.second));
|
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>
|
size_t size{};
|
||||||
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
|
details::readSize(
|
||||||
using TKey = typename T::key_type;
|
des.adapter(),
|
||||||
using TValue = typename T::mapped_type;
|
size,
|
||||||
|
_maxSize,
|
||||||
|
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
|
||||||
|
obj.clear();
|
||||||
|
reserve(obj, size);
|
||||||
|
|
||||||
size_t size{};
|
auto hint = obj.begin();
|
||||||
details::readSize(des.adapter(), size, _maxSize,
|
for (auto i = 0u; i < size; ++i) {
|
||||||
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
|
auto key = bitsery::Access::create<TKey>();
|
||||||
obj.clear();
|
auto value = bitsery::Access::create<TValue>();
|
||||||
reserve(obj, size);
|
fnc(des, key, value);
|
||||||
|
hint = obj.emplace_hint(hint, std::move(key), std::move(value));
|
||||||
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;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace traits {
|
private:
|
||||||
template<typename T>
|
template<typename Key,
|
||||||
struct ExtensionTraits<ext::StdMap, T> {
|
typename T,
|
||||||
using TValue = void;
|
typename Hash,
|
||||||
static constexpr bool SupportValueOverload = false;
|
typename KeyEqual,
|
||||||
static constexpr bool SupportObjectOverload = false;
|
typename Allocator>
|
||||||
static constexpr bool SupportLambdaOverload = true;
|
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
|
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_STD_OPTIONAL_H
|
#ifndef BITSERY_EXT_STD_OPTIONAL_H
|
||||||
#define BITSERY_EXT_STD_OPTIONAL_H
|
#define BITSERY_EXT_STD_OPTIONAL_H
|
||||||
|
|
||||||
#include "../traits/core/traits.h"
|
|
||||||
#include "../details/serialization_common.h"
|
#include "../details/serialization_common.h"
|
||||||
|
#include "../traits/core/traits.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
class StdOptional {
|
class StdOptional
|
||||||
public:
|
{
|
||||||
|
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 }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
template<typename Ser, typename T, typename Fnc>
|
||||||
* Works with std::optional types
|
void serialize(Ser& ser, const std::optional<T>& obj, Fnc&& fnc) const
|
||||||
* @param alignBeforeData only makes sense when bit-packing enabled, by default aligns after writing/reading bool state of optional
|
{
|
||||||
*/
|
ser.boolValue(static_cast<bool>(obj));
|
||||||
explicit StdOptional(bool alignBeforeData=true):_alignBeforeData{alignBeforeData} {}
|
if (_alignBeforeData)
|
||||||
|
ser.adapter().align();
|
||||||
|
if (obj)
|
||||||
|
fnc(ser, const_cast<T&>(*obj));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Ser, typename T, typename Fnc>
|
template<typename Des, typename T, typename Fnc>
|
||||||
void serialize(Ser &ser, const std::optional<T> &obj, Fnc &&fnc) const {
|
void deserialize(Des& des, std::optional<T>& obj, Fnc&& fnc) const
|
||||||
ser.boolValue(static_cast<bool>(obj));
|
{
|
||||||
if (_alignBeforeData)
|
bool exists{};
|
||||||
ser.adapter().align();
|
des.boolValue(exists);
|
||||||
if (obj)
|
if (_alignBeforeData)
|
||||||
fnc(ser, const_cast<T&>(*obj));
|
des.adapter().align();
|
||||||
}
|
if (exists) {
|
||||||
|
deserialize_impl(des, obj, fnc, std::is_trivial<T>{});
|
||||||
template<typename Des, typename T, typename Fnc>
|
} else {
|
||||||
void deserialize(Des &des, std::optional<T> &obj, Fnc &&fnc) const {
|
obj = std::nullopt;
|
||||||
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;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace traits {
|
private:
|
||||||
template<typename T>
|
template<typename Des, typename T, typename Fnc>
|
||||||
struct ExtensionTraits<ext::StdOptional, std::optional<T>> {
|
void deserialize_impl(Des& des,
|
||||||
using TValue = T;
|
std::optional<T>& obj,
|
||||||
static constexpr bool SupportValueOverload = true;
|
Fnc&& fnc,
|
||||||
static constexpr bool SupportObjectOverload = true;
|
std::true_type) const
|
||||||
static constexpr bool SupportLambdaOverload = true;
|
{
|
||||||
};
|
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
|
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_STD_QUEUE_H
|
#ifndef BITSERY_EXT_STD_QUEUE_H
|
||||||
#define BITSERY_EXT_STD_QUEUE_H
|
#define BITSERY_EXT_STD_QUEUE_H
|
||||||
|
|
||||||
#include <type_traits>
|
// include type traits for deque and vector, because they are defaults for queue
|
||||||
#include <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/deque.h"
|
||||||
#include "../traits/vector.h"
|
#include "../traits/vector.h"
|
||||||
|
#include <queue>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
class StdQueue {
|
class StdQueue
|
||||||
private:
|
{
|
||||||
//inherit from queue so we could take underlying container
|
private:
|
||||||
template <typename T, typename C>
|
// inherit from queue so we could take underlying container
|
||||||
struct QueueCnt : public std::queue<T, C>
|
template<typename T, typename C>
|
||||||
{
|
struct QueueCnt : public std::queue<T, C>
|
||||||
static const C& getContainer(const std::queue<T, C>& s )
|
{
|
||||||
{
|
static const C& getContainer(const std::queue<T, C>& s)
|
||||||
//get address of underlying container
|
{
|
||||||
return s.*(&QueueCnt::c);
|
// 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
static C& getContainer(std::queue<T, C>& s)
|
||||||
namespace traits {
|
{
|
||||||
template<typename T>
|
// get address of underlying container
|
||||||
struct ExtensionTraits<ext::StdQueue, T> {
|
return s.*(&QueueCnt::c);
|
||||||
using TValue = typename T::value_type;
|
|
||||||
static constexpr bool SupportValueOverload = true;
|
|
||||||
static constexpr bool SupportObjectOverload = true;
|
|
||||||
static constexpr bool SupportLambdaOverload = true;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
// 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
|
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_STD_SET_H
|
#ifndef BITSERY_EXT_STD_SET_H
|
||||||
#define BITSERY_EXT_STD_SET_H
|
#define BITSERY_EXT_STD_SET_H
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include "../details/adapter_common.h"
|
|
||||||
#include "../details/serialization_common.h"
|
#include "../details/serialization_common.h"
|
||||||
//we need this, so we could reserve for non ordered set
|
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
class StdSet {
|
class StdSet
|
||||||
public:
|
{
|
||||||
|
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>
|
for (auto& v : obj)
|
||||||
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
|
fnc(ser, const_cast<TKey&>(v));
|
||||||
using TKey = typename T::key_type;
|
}
|
||||||
auto size = obj.size();
|
|
||||||
assert(size <= _maxSize);
|
|
||||||
details::writeSize(ser.adapter(), size);
|
|
||||||
|
|
||||||
for (auto &v:obj)
|
template<typename Des, typename T, typename Fnc>
|
||||||
fnc(ser, const_cast<TKey &>(v));
|
void deserialize(Des& des, T& obj, Fnc&& fnc) const
|
||||||
}
|
{
|
||||||
|
using TKey = typename T::key_type;
|
||||||
|
|
||||||
template<typename Des, typename T, typename Fnc>
|
size_t size{};
|
||||||
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
|
details::readSize(
|
||||||
using TKey = typename T::key_type;
|
des.adapter(),
|
||||||
|
size,
|
||||||
size_t size{};
|
_maxSize,
|
||||||
details::readSize(des.adapter(), size, _maxSize, std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
|
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
|
||||||
obj.clear();
|
obj.clear();
|
||||||
reserve(obj, size);
|
reserve(obj, size);
|
||||||
auto hint = obj.begin();
|
auto hint = obj.begin();
|
||||||
for (auto i = 0u; i < size; ++i) {
|
for (auto i = 0u; i < size; ++i) {
|
||||||
auto key = bitsery::Access::create<TKey>();
|
auto key = bitsery::Access::create<TKey>();
|
||||||
fnc(des, key);
|
fnc(des, key);
|
||||||
hint = obj.emplace_hint(hint, std::move(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;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace traits {
|
private:
|
||||||
template<typename T>
|
template<typename Key, typename Hash, typename KeyEqual, typename Allocator>
|
||||||
struct ExtensionTraits<ext::StdSet, T> {
|
void reserve(std::unordered_set<Key, Hash, KeyEqual, Allocator>& obj,
|
||||||
using TValue = typename T::key_type;
|
size_t size) const
|
||||||
static constexpr bool SupportValueOverload = true;
|
{
|
||||||
static constexpr bool SupportObjectOverload = true;
|
obj.reserve(size);
|
||||||
static constexpr bool SupportLambdaOverload = true;
|
}
|
||||||
};
|
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
|
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_STD_SMART_PTR_H
|
#ifndef BITSERY_EXT_STD_SMART_PTR_H
|
||||||
#define BITSERY_EXT_STD_SMART_PTR_H
|
#define BITSERY_EXT_STD_SMART_PTR_H
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include "../traits/core/traits.h"
|
#include "../traits/core/traits.h"
|
||||||
#include "utils/pointer_utils.h"
|
#include "utils/pointer_utils.h"
|
||||||
#include "utils/polymorphism_utils.h"
|
#include "utils/polymorphism_utils.h"
|
||||||
@@ -31,168 +30,227 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
namespace smart_ptr_details {
|
namespace smart_ptr_details {
|
||||||
|
|
||||||
//further code is for managing shared ownership
|
// 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
|
// do not nest this type in pointer manager class itself, because it will be
|
||||||
struct SharedPtrSharedState : pointer_utils::PointerSharedStateBase {
|
// different type for different T
|
||||||
std::shared_ptr<void> obj{};
|
struct SharedPtrSharedState : pointer_utils::PointerSharedStateBase
|
||||||
};
|
{
|
||||||
|
std::shared_ptr<void> obj{};
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct SmartPtrOwnerManager {
|
struct SmartPtrOwnerManager
|
||||||
|
{
|
||||||
|
|
||||||
using TElement = typename T::element_type;
|
using TElement = typename T::element_type;
|
||||||
|
|
||||||
template<typename TDeleter>
|
template<typename TDeleter>
|
||||||
static TElement* getPtr(std::unique_ptr<TElement, TDeleter>& obj) {
|
static TElement* getPtr(std::unique_ptr<TElement, TDeleter>& obj)
|
||||||
return obj.get();
|
{
|
||||||
}
|
return obj.get();
|
||||||
|
}
|
||||||
|
|
||||||
static TElement* getPtr(std::shared_ptr<TElement>& obj) {
|
static TElement* getPtr(std::shared_ptr<TElement>& obj) { return obj.get(); }
|
||||||
return obj.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
static TElement* getPtr(std::weak_ptr<TElement>& obj) {
|
static TElement* getPtr(std::weak_ptr<TElement>& obj)
|
||||||
if (auto ptr = obj.lock())
|
{
|
||||||
return ptr.get();
|
if (auto ptr = obj.lock())
|
||||||
return nullptr;
|
return ptr.get();
|
||||||
}
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr PointerOwnershipType getOwnership() {
|
static constexpr PointerOwnershipType getOwnership()
|
||||||
return ::bitsery::details::IsSpecializationOf<T, std::unique_ptr>::value
|
{
|
||||||
? PointerOwnershipType::Owner
|
return ::bitsery::details::IsSpecializationOf<T, std::unique_ptr>::value
|
||||||
: std::is_same<std::shared_ptr<TElement>, T>::value
|
? PointerOwnershipType::Owner
|
||||||
? PointerOwnershipType::SharedOwner
|
: std::is_same<std::shared_ptr<TElement>, T>::value
|
||||||
: PointerOwnershipType::SharedObserver;
|
? PointerOwnershipType::SharedOwner
|
||||||
}
|
: PointerOwnershipType::SharedObserver;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename TDeleter>
|
template<typename TDeleter>
|
||||||
static void create(std::unique_ptr<TElement, TDeleter>& obj, pointer_utils::PolyAllocWithTypeId alloc,
|
static void create(std::unique_ptr<TElement, TDeleter>& obj,
|
||||||
size_t typeId) {
|
pointer_utils::PolyAllocWithTypeId alloc,
|
||||||
obj.reset(alloc.newObject<TElement>(typeId));
|
size_t typeId)
|
||||||
}
|
{
|
||||||
|
obj.reset(alloc.newObject<TElement>(typeId));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename TDeleter>
|
template<typename TDeleter>
|
||||||
static void createPolymorphic(std::unique_ptr<TElement, TDeleter>& obj, pointer_utils::PolyAllocWithTypeId alloc,
|
static void createPolymorphic(
|
||||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
std::unique_ptr<TElement, TDeleter>& obj,
|
||||||
obj.reset(static_cast<TElement*>(handler->create(alloc)));
|
pointer_utils::PolyAllocWithTypeId alloc,
|
||||||
}
|
const std::shared_ptr<PolymorphicHandlerBase>& handler)
|
||||||
|
{
|
||||||
|
obj.reset(static_cast<TElement*>(handler->create(alloc)));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename TDel>
|
template<typename TDel>
|
||||||
static void destroy(std::unique_ptr<TElement, TDel>& obj, pointer_utils::PolyAllocWithTypeId alloc, size_t typeId) {
|
static void destroy(std::unique_ptr<TElement, TDel>& obj,
|
||||||
auto ptr = obj.release();
|
pointer_utils::PolyAllocWithTypeId alloc,
|
||||||
alloc.deleteObject(ptr, typeId);
|
size_t typeId)
|
||||||
}
|
{
|
||||||
|
auto ptr = obj.release();
|
||||||
|
alloc.deleteObject(ptr, typeId);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename TDel>
|
template<typename TDel>
|
||||||
static void destroyPolymorphic(std::unique_ptr<TElement, TDel>& obj, pointer_utils::PolyAllocWithTypeId alloc,
|
static void destroyPolymorphic(
|
||||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
std::unique_ptr<TElement, TDel>& obj,
|
||||||
auto ptr = obj.release();
|
pointer_utils::PolyAllocWithTypeId alloc,
|
||||||
handler->destroy(alloc, ptr);
|
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) {
|
static void destroy(std::shared_ptr<TElement>& obj, MemResourceBase*, size_t)
|
||||||
obj.reset();
|
{
|
||||||
}
|
obj.reset();
|
||||||
|
}
|
||||||
|
|
||||||
static void destroyPolymorphic(std::shared_ptr<TElement>& obj, MemResourceBase*,
|
static void destroyPolymorphic(std::shared_ptr<TElement>& obj,
|
||||||
const std::shared_ptr<PolymorphicHandlerBase>&) {
|
MemResourceBase*,
|
||||||
obj.reset();
|
const std::shared_ptr<PolymorphicHandlerBase>&)
|
||||||
}
|
{
|
||||||
|
obj.reset();
|
||||||
|
}
|
||||||
|
|
||||||
static void destroy(std::weak_ptr<TElement>& obj, MemResourceBase*, size_t) {
|
static void destroy(std::weak_ptr<TElement>& obj, MemResourceBase*, size_t)
|
||||||
obj.reset();
|
{
|
||||||
}
|
obj.reset();
|
||||||
|
}
|
||||||
|
|
||||||
static void destroyPolymorphic(std::weak_ptr<TElement>& obj, MemResourceBase*,
|
static void destroyPolymorphic(std::weak_ptr<TElement>& obj,
|
||||||
const std::shared_ptr<PolymorphicHandlerBase>&) {
|
MemResourceBase*,
|
||||||
obj.reset();
|
const std::shared_ptr<PolymorphicHandlerBase>&)
|
||||||
}
|
{
|
||||||
|
obj.reset();
|
||||||
|
}
|
||||||
|
|
||||||
// define a type that will store shared state for shared and weak ptrs
|
// define a type that will store shared state for shared and weak ptrs
|
||||||
using TSharedState = SharedPtrSharedState;
|
using TSharedState = SharedPtrSharedState;
|
||||||
|
|
||||||
static void createShared(TSharedState& state,
|
static void createShared(TSharedState& state,
|
||||||
std::shared_ptr<TElement>& obj, MemResourceBase* memResource, size_t typeId) {
|
std::shared_ptr<TElement>& obj,
|
||||||
// capture deleter parameters by value
|
MemResourceBase* memResource,
|
||||||
pointer_utils::PolyAllocWithTypeId alloc{memResource};
|
size_t typeId)
|
||||||
obj.reset(alloc.newObject<TElement>(typeId), [alloc, typeId](TElement* data) {
|
{
|
||||||
alloc.deleteObject(data, typeId);
|
// capture deleter parameters by value
|
||||||
}, pointer_utils::StdPolyAlloc<TElement>(memResource));
|
pointer_utils::PolyAllocWithTypeId alloc{ memResource };
|
||||||
state.obj = obj;
|
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,
|
static void createSharedPolymorphic(
|
||||||
std::shared_ptr<TElement>& obj, MemResourceBase* memResource,
|
TSharedState& state,
|
||||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
std::shared_ptr<TElement>& obj,
|
||||||
// capture deleter parameters by value
|
MemResourceBase* memResource,
|
||||||
pointer_utils::PolyAllocWithTypeId alloc{memResource};
|
const std::shared_ptr<PolymorphicHandlerBase>& handler)
|
||||||
obj.reset(static_cast<TElement*>(handler->create(alloc)), [alloc, handler](TElement* data) {
|
{
|
||||||
handler->destroy(alloc, data);
|
// capture deleter parameters by value
|
||||||
}, pointer_utils::StdPolyAlloc<TElement>(memResource));
|
pointer_utils::PolyAllocWithTypeId alloc{ memResource };
|
||||||
state.obj = obj;
|
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,
|
static void createShared(TSharedState& state,
|
||||||
std::weak_ptr<TElement>& obj, MemResourceBase* memResource, size_t typeId) {
|
std::weak_ptr<TElement>& obj,
|
||||||
pointer_utils::PolyAllocWithTypeId alloc{memResource};
|
MemResourceBase* memResource,
|
||||||
std::shared_ptr<TElement> res(alloc.newObject<TElement>(typeId),[alloc, typeId](TElement* data) {
|
size_t typeId)
|
||||||
alloc.deleteObject(data, typeId);
|
{
|
||||||
}, pointer_utils::StdPolyAlloc<TElement>(memResource));
|
pointer_utils::PolyAllocWithTypeId alloc{ memResource };
|
||||||
obj = res;
|
std::shared_ptr<TElement> res(
|
||||||
state.obj = 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,
|
static void createSharedPolymorphic(
|
||||||
std::weak_ptr<TElement>& obj, MemResourceBase* memResource,
|
TSharedState& state,
|
||||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
std::weak_ptr<TElement>& obj,
|
||||||
pointer_utils::PolyAllocWithTypeId alloc{memResource};
|
MemResourceBase* memResource,
|
||||||
std::shared_ptr<TElement> res(static_cast<TElement*>(handler->create(alloc)),
|
const std::shared_ptr<PolymorphicHandlerBase>& handler)
|
||||||
[alloc, handler](TElement* data) {
|
{
|
||||||
handler->destroy(alloc, data);
|
pointer_utils::PolyAllocWithTypeId alloc{ memResource };
|
||||||
}, pointer_utils::StdPolyAlloc<TElement>(memResource));
|
std::shared_ptr<TElement> res(
|
||||||
obj = res;
|
static_cast<TElement*>(handler->create(alloc)),
|
||||||
state.obj = res;
|
[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) {
|
static void saveToSharedState(TSharedState& state, T& obj)
|
||||||
state.obj = std::shared_ptr<TElement>(obj);
|
{
|
||||||
}
|
state.obj = std::shared_ptr<TElement>(obj);
|
||||||
|
}
|
||||||
|
|
||||||
static void loadFromSharedState(TSharedState& state, T& obj) {
|
static void saveToSharedStatePolymorphic(TSharedState& state, T& obj)
|
||||||
//reinterpret_pointer_cast is only since c++17
|
{
|
||||||
auto p = reinterpret_cast<TElement*>(state.obj.get());
|
state.obj = std::shared_ptr<TElement>(obj);
|
||||||
obj = std::shared_ptr<TElement>(state.obj, p);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
};
|
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>
|
static void loadFromSharedStatePolymorphic(TSharedState& state,
|
||||||
using StdSmartPtrBase = pointer_utils::PointerObjectExtensionBase<
|
T& obj,
|
||||||
smart_ptr_details::SmartPtrOwnerManager, PolymorphicContext, RTTI>;
|
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
|
template<typename RTTI>
|
||||||
using StdSmartPtr = StdSmartPtrBase<StandardRTTI>;
|
using StdSmartPtrBase = pointer_utils::PointerObjectExtensionBase<
|
||||||
|
smart_ptr_details::SmartPtrOwnerManager,
|
||||||
|
PolymorphicContext,
|
||||||
|
RTTI>;
|
||||||
|
|
||||||
}
|
// helper type for convienience
|
||||||
|
using StdSmartPtr = StdSmartPtrBase<StandardRTTI>;
|
||||||
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
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_STD_STACK_H
|
#ifndef BITSERY_EXT_STD_STACK_H
|
||||||
#define 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 "../traits/deque.h"
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
class StdStack {
|
class StdStack
|
||||||
private:
|
{
|
||||||
//inherit from stack so we could take underlying container
|
private:
|
||||||
template <typename T, typename C>
|
// inherit from stack so we could take underlying container
|
||||||
struct StackCnt : public std::stack<T, C>
|
template<typename T, typename C>
|
||||||
{
|
struct StackCnt : public std::stack<T, C>
|
||||||
static const C& getContainer(const std::stack<T, C>& s )
|
{
|
||||||
{
|
static const C& getContainer(const std::stack<T, C>& s)
|
||||||
//get address of underlying container
|
{
|
||||||
return s.*(&StackCnt::c);
|
// 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));
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
static C& getContainer(std::stack<T, C>& s)
|
||||||
namespace traits {
|
{
|
||||||
template<typename T, typename Seq>
|
// get address of underlying container
|
||||||
struct ExtensionTraits<ext::StdStack, std::stack<T, Seq>> {
|
return s.*(&StackCnt::c);
|
||||||
using TValue = T;
|
|
||||||
static constexpr bool SupportValueOverload = true;
|
|
||||||
static constexpr bool SupportObjectOverload = true;
|
|
||||||
static constexpr bool SupportLambdaOverload = true;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
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
|
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_STD_TUPLE_H
|
#ifndef BITSERY_EXT_STD_TUPLE_H
|
||||||
#define BITSERY_EXT_STD_TUPLE_H
|
#define BITSERY_EXT_STD_TUPLE_H
|
||||||
|
|
||||||
|
|
||||||
#include "utils/composite_type_overloads.h"
|
|
||||||
#include "../traits/core/traits.h"
|
#include "../traits/core/traits.h"
|
||||||
|
#include "utils/composite_type_overloads.h"
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
template<typename ...Overloads>
|
template<typename... Overloads>
|
||||||
class StdTuple : public details::CompositeTypeOverloadsUtils<std::tuple, Overloads...> {
|
class StdTuple
|
||||||
public:
|
: 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>
|
template<typename Des, typename Fnc, typename... Ts>
|
||||||
void serialize(Ser& ser, const std::tuple<Ts...>& obj, Fnc&&) const {
|
void deserialize(Des& des, std::tuple<Ts...>& obj, Fnc&&) const
|
||||||
serializeAll(ser, const_cast<std::tuple<Ts...>&>(obj));
|
{
|
||||||
}
|
serializeAll(des, obj);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Des, typename Fnc, typename ...Ts>
|
private:
|
||||||
void deserialize(Des& des, std::tuple<Ts...>& obj, Fnc&&) const {
|
template<typename S, typename... Ts>
|
||||||
serializeAll(des, obj);
|
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:
|
// deduction guide
|
||||||
template<typename S, typename ...Ts>
|
template<typename... Overloads>
|
||||||
void serializeAll(S& s, std::tuple<Ts...>& obj) const {
|
StdTuple(Overloads...) -> StdTuple<Overloads...>;
|
||||||
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
|
namespace traits {
|
||||||
template<typename ...Overloads>
|
|
||||||
StdTuple(Overloads...) -> StdTuple<Overloads...>;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace traits {
|
template<typename Tuple, typename... Overloads>
|
||||||
|
struct ExtensionTraits<ext::StdTuple<Overloads...>, Tuple>
|
||||||
template<typename Tuple, typename ... Overloads>
|
{
|
||||||
struct ExtensionTraits<ext::StdTuple<Overloads...>, Tuple> {
|
static_assert(bitsery::details::IsSpecializationOf<Tuple, std::tuple>::value,
|
||||||
static_assert(bitsery::details::IsSpecializationOf<Tuple, std::tuple>::value,
|
"StdTuple only works with std::tuple");
|
||||||
"StdTuple only works with std::tuple");
|
using TValue = void;
|
||||||
using TValue = void;
|
static constexpr bool SupportValueOverload = false;
|
||||||
static constexpr bool SupportValueOverload = false;
|
static constexpr bool SupportObjectOverload = true;
|
||||||
static constexpr bool SupportObjectOverload = true;
|
static constexpr bool SupportLambdaOverload = false;
|
||||||
static constexpr bool SupportLambdaOverload = false;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#endif //BITSERY_EXT_STD_TUPLE_H
|
#endif // BITSERY_EXT_STD_TUPLE_H
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_STD_VARIANT_H
|
#ifndef BITSERY_EXT_STD_VARIANT_H
|
||||||
#define BITSERY_EXT_STD_VARIANT_H
|
#define BITSERY_EXT_STD_VARIANT_H
|
||||||
|
|
||||||
|
|
||||||
#include "utils/composite_type_overloads.h"
|
|
||||||
#include "../traits/core/traits.h"
|
#include "../traits/core/traits.h"
|
||||||
|
#include "utils/composite_type_overloads.h"
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
template<typename ...Overloads>
|
template<typename... Overloads>
|
||||||
class StdVariant : public details::CompositeTypeOverloadsUtils<std::variant, Overloads...> {
|
class StdVariant
|
||||||
public:
|
: 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>
|
template<typename Des, typename Fnc, typename... Ts>
|
||||||
void serialize(Ser& ser, const std::variant<Ts...>& obj, Fnc&&) const {
|
void deserialize(Des& des, std::variant<Ts...>& obj, Fnc&&) const
|
||||||
auto index = obj.index();
|
{
|
||||||
assert(index != std::variant_npos);
|
size_t index{};
|
||||||
details::writeSize(ser.adapter(), index);
|
details::readSize(
|
||||||
this->execIndex(index, const_cast<std::variant<Ts...>&>(obj), [this, &ser](auto& data, auto index) {
|
des.adapter(),
|
||||||
constexpr size_t Index = decltype(index)::value;
|
index,
|
||||||
this->serializeType(ser, std::get<Index>(data));
|
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>
|
// Reinitializing nontrivial types may be expensive especially when they
|
||||||
void deserialize(Des& des, std::variant<Ts...>& obj, Fnc&&) const {
|
// reference heap data, so if `data` is already holding the requested
|
||||||
size_t index{};
|
// variant then we'll deserialize into the existing object
|
||||||
details::readSize(des.adapter(), index, sizeof...(Ts), std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
|
if constexpr (!std::is_trivial_v<TElem>) {
|
||||||
this->execIndex(index, obj, [this, &des](auto& data, auto index) {
|
if (auto item = std::get_if<Index>(&data)) {
|
||||||
constexpr size_t Index = decltype(index)::value;
|
this->serializeType(des, *item);
|
||||||
using TElem = typename std::variant_alternative<Index, std::variant<Ts...>>::type;
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reinitializing nontrivial types may be expensive especially when they
|
TElem item = ::bitsery::Access::create<TElem>();
|
||||||
// reference heap data, so if `data` is already holding the requested
|
this->serializeType(des, item);
|
||||||
// variant then we'll deserialize into the existing object
|
data =
|
||||||
if constexpr (!std::is_trivial_v<TElem>) {
|
std::variant<Ts...>(std::in_place_index_t<Index>{}, std::move(item));
|
||||||
if (auto item = std::get_if<Index>(&data)) {
|
});
|
||||||
this->serializeType(des, *item);
|
}
|
||||||
return;
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TElem item = ::bitsery::Access::create<TElem>();
|
// deduction guide
|
||||||
this->serializeType(des, item);
|
template<typename... Overloads>
|
||||||
data = std::variant<Ts...>(std::in_place_index_t<Index>{}, std::move(item));
|
StdVariant(Overloads...) -> StdVariant<Overloads...>;
|
||||||
});
|
}
|
||||||
}
|
|
||||||
|
|
||||||
};
|
// defines empty fuction, that handles monostate
|
||||||
|
template<typename S>
|
||||||
|
void
|
||||||
|
serialize(S&, std::monostate&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// deduction guide
|
namespace traits {
|
||||||
template<typename ...Overloads>
|
|
||||||
StdVariant(Overloads...) -> StdVariant<Overloads...>;
|
|
||||||
}
|
|
||||||
|
|
||||||
//defines empty fuction, that handles monostate
|
template<typename Variant, typename... Overloads>
|
||||||
template <typename S>
|
struct ExtensionTraits<ext::StdVariant<Overloads...>, Variant>
|
||||||
void serialize(S& , std::monostate&) {}
|
{
|
||||||
|
static_assert(
|
||||||
namespace traits {
|
bitsery::details::IsSpecializationOf<Variant, std::variant>::value,
|
||||||
|
"StdVariant only works with std::variant");
|
||||||
template<typename Variant, typename ... Overloads>
|
using TValue = void;
|
||||||
struct ExtensionTraits<ext::StdVariant<Overloads...>, Variant> {
|
static constexpr bool SupportValueOverload = false;
|
||||||
static_assert(bitsery::details::IsSpecializationOf<Variant, std::variant>::value,
|
static constexpr bool SupportObjectOverload = true;
|
||||||
"StdVariant only works with std::variant");
|
static constexpr bool SupportLambdaOverload = false;
|
||||||
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_COMPOSITE_TYPE_OVERLOADS_H
|
#ifndef BITSERY_EXT_COMPOSITE_TYPE_OVERLOADS_H
|
||||||
#define BITSERY_EXT_COMPOSITE_TYPE_OVERLOADS_H
|
#define BITSERY_EXT_COMPOSITE_TYPE_OVERLOADS_H
|
||||||
@@ -29,108 +29,131 @@
|
|||||||
#if __cplusplus < 201703L
|
#if __cplusplus < 201703L
|
||||||
#error these utils requires c++17
|
#error these utils requires c++17
|
||||||
// in theory, it could be implemented using C++11
|
// in theory, it could be implemented using C++11
|
||||||
// but without class template argument deduction guides that would be very inconvenient to use
|
// but without class template argument deduction guides that would be very
|
||||||
// these are very helpul for sum types (e.g. std::variant),
|
// 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 for product types (e.g. std::tuple) you can you can easily do it your
|
||||||
|
// self with lambda, without extension
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace ext {
|
namespace ext {
|
||||||
// might be usable, when you want to have one overload set for different composite types,
|
// might be usable, when you want to have one overload set for different
|
||||||
// e.g. variant, tuple and pair
|
// composite types, e.g. variant, tuple and pair
|
||||||
template<class... Ts>
|
template<class... Ts>
|
||||||
struct CompositeTypeOverloads : Ts ... {
|
struct CompositeTypeOverloads : Ts...
|
||||||
using Ts::operator()...;
|
{
|
||||||
};
|
using Ts::operator()...;
|
||||||
|
};
|
||||||
|
|
||||||
template<typename ...Overloads>
|
template<typename... Overloads>
|
||||||
CompositeTypeOverloads(Overloads...) -> CompositeTypeOverloads<Overloads...>;
|
CompositeTypeOverloads(Overloads...) -> CompositeTypeOverloads<Overloads...>;
|
||||||
|
|
||||||
// convenient way to invoke s.value<N>, shorter than specifying a lambda
|
// convenient way to invoke s.value<N>, shorter than specifying a lambda
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
struct OverloadValue {
|
struct OverloadValue
|
||||||
template <typename S>
|
{
|
||||||
void operator()(S& s, T& v) const {
|
template<typename S>
|
||||||
s.template value<N>(v);
|
void operator()(S& s, T& v) const
|
||||||
}
|
{
|
||||||
};
|
s.template value<N>(v);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// convenient way to invoke other extension using value or object overloads
|
// convenient way to invoke other extension using value or object overloads
|
||||||
// there is no reason to write OverloadExtLambda,
|
// there is no reason to write OverloadExtLambda,
|
||||||
// because you'll need to specify lambda type, which is very inconvenient and it will be much
|
// because you'll need to specify lambda type, which is very inconvenient and it
|
||||||
// easier to simple write a lambda with extension inside it,
|
// will be much easier to simple write a lambda with extension inside it, in
|
||||||
// in order to implement it in a convenient way, i need a way to deduce only last template parameter (lambda type)
|
// order to implement it in a convenient way, i need a way to deduce only last
|
||||||
// but this is not possible with deduction guides at the moment
|
// template parameter (lambda type) but this is not possible with deduction
|
||||||
|
// guides at the moment
|
||||||
|
|
||||||
template<typename T, size_t N, typename Ext>
|
template<typename T, size_t N, typename Ext>
|
||||||
struct OverloadExtValue : public Ext {
|
struct OverloadExtValue : public Ext
|
||||||
template <typename S>
|
{
|
||||||
void operator()(S& s, T& v) const {
|
template<typename S>
|
||||||
s.template ext<N>(v, static_cast<const Ext&>(*this));
|
void operator()(S& s, T& v) const
|
||||||
}
|
{
|
||||||
};
|
s.template ext<N>(v, static_cast<const Ext&>(*this));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T, typename Ext>
|
template<typename T, typename Ext>
|
||||||
struct OverloadExtObject : public Ext {
|
struct OverloadExtObject : public Ext
|
||||||
template <typename S>
|
{
|
||||||
void operator()(S& s, T& v) const {
|
template<typename S>
|
||||||
s.ext(v, static_cast<const Ext&>(*this));
|
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>{}), ...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_MEMORY_RESOURCE_H
|
#ifndef BITSERY_EXT_MEMORY_RESOURCE_H
|
||||||
#define BITSERY_EXT_MEMORY_RESOURCE_H
|
#define BITSERY_EXT_MEMORY_RESOURCE_H
|
||||||
@@ -27,145 +27,170 @@
|
|||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
// these are very similar to c++17 polymorphic allocator and memory resource classes
|
// these are very similar to c++17 polymorphic allocator and memory resource
|
||||||
// but i don't want to enforce users to use c++17 if they want to use pointers
|
// classes but i don't want to enforce users to use c++17 if they want to use
|
||||||
// plus this has additional information from RTTI about runtime type information,
|
// pointers plus this has additional information from RTTI about runtime type
|
||||||
// might be useful working with polymorphic types.
|
// information, might be useful working with polymorphic types. The same memory
|
||||||
// The same memory resource is used to allocate internal data in various contexts,
|
// resource is used to allocate internal data in various contexts, (typeId is
|
||||||
// (typeId is always 0 for internal data allocation in contexts).
|
// always 0 for internal data allocation in contexts).
|
||||||
|
|
||||||
class MemResourceBase {
|
class MemResourceBase
|
||||||
public:
|
{
|
||||||
virtual void* allocate(size_t bytes, size_t alignment, size_t typeId) = 0;
|
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
|
// default implementation for MemResourceBase using new and delete
|
||||||
class MemResourceNewDelete final: public MemResourceBase {
|
class MemResourceNewDelete final : public MemResourceBase
|
||||||
public:
|
{
|
||||||
inline void* allocate(size_t bytes, size_t /*alignment*/, size_t /*typeId*/) final {
|
public:
|
||||||
return (::operator new(bytes));
|
inline void* allocate(size_t bytes,
|
||||||
}
|
size_t /*alignment*/,
|
||||||
|
size_t /*typeId*/) final
|
||||||
|
{
|
||||||
|
return (::operator new(bytes));
|
||||||
|
}
|
||||||
|
|
||||||
inline void
|
inline void deallocate(void* ptr,
|
||||||
deallocate(void* ptr, size_t /*bytes*/, size_t /*alignment*/, size_t /*typeId*/) noexcept final {
|
size_t /*bytes*/,
|
||||||
(::operator delete(ptr));
|
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
|
// these classes are used internally by bitsery extensions and and pointer utils
|
||||||
namespace pointer_utils {
|
namespace pointer_utils {
|
||||||
// this is helper class that stores memory resource and knows how to construct/destroy objects
|
// this is helper class that stores memory resource and knows how to
|
||||||
// capture this by value for custom deleters, because during deserialization mem resource can be changed
|
// construct/destroy objects capture this by value for custom deleters, because
|
||||||
class PolyAllocWithTypeId final {
|
// during deserialization mem resource can be changed
|
||||||
public:
|
class PolyAllocWithTypeId final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
constexpr PolyAllocWithTypeId(MemResourceBase* memResource = nullptr)
|
||||||
|
: _resource{ memResource }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
constexpr PolyAllocWithTypeId(MemResourceBase* memResource = nullptr)
|
template<typename T>
|
||||||
:_resource{memResource} {}
|
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>
|
template<typename T>
|
||||||
T* allocate(size_t n, size_t typeId) const {
|
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;
|
const auto bytes = sizeof(T) * n;
|
||||||
void* ptr = _resource
|
constexpr auto alignment = std::alignment_of<T>::value;
|
||||||
? _resource->allocate(bytes, alignment, typeId)
|
_resource
|
||||||
: ext::MemResourceNewDelete{}.allocate(bytes, alignment, typeId);
|
? _resource->deallocate(ptr, bytes, alignment, typeId)
|
||||||
return static_cast<T*>(ptr);
|
: ext::MemResourceNewDelete{}.deallocate(ptr, bytes, alignment, typeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void deallocate(T* ptr, size_t n, size_t typeId) const noexcept {
|
T* newObject(size_t typeId) const
|
||||||
const auto bytes = sizeof(T) * n;
|
{
|
||||||
constexpr auto alignment = std::alignment_of<T>::value;
|
auto ptr = allocate<T>(1, typeId);
|
||||||
_resource
|
return ::bitsery::Access::create<T>(ptr);
|
||||||
? _resource->deallocate(ptr, bytes, alignment, typeId)
|
}
|
||||||
: ext::MemResourceNewDelete{}.deallocate(ptr, bytes, alignment, typeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T* newObject(size_t typeId) const {
|
void deleteObject(T* obj, size_t typeId) const
|
||||||
auto ptr = allocate<T>(1, typeId);
|
{
|
||||||
return ::bitsery::Access::create<T>(ptr);
|
obj->~T();
|
||||||
}
|
deallocate(obj, 1, typeId);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
void setMemResource(ext::MemResourceBase* resource) { _resource = resource; }
|
||||||
void deleteObject(T* obj, size_t typeId) const {
|
|
||||||
obj->~T();
|
|
||||||
deallocate(obj, 1, typeId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setMemResource(ext::MemResourceBase* resource) {
|
ext::MemResourceBase* getMemResource() const { return _resource; }
|
||||||
_resource = resource;
|
|
||||||
}
|
|
||||||
|
|
||||||
ext::MemResourceBase* getMemResource() const {
|
bool operator==(const PolyAllocWithTypeId& rhs) const noexcept
|
||||||
return _resource;
|
{
|
||||||
}
|
return _resource == rhs._resource;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const PolyAllocWithTypeId& rhs) const noexcept {
|
bool operator!=(const PolyAllocWithTypeId& rhs) const noexcept
|
||||||
return _resource == rhs._resource;
|
{
|
||||||
}
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
bool operator!=(const PolyAllocWithTypeId& rhs) const noexcept {
|
private:
|
||||||
return !(*this == rhs);
|
ext::MemResourceBase* _resource;
|
||||||
}
|
};
|
||||||
|
|
||||||
private:
|
// this is very similar to c++17 PolymorphicAllocator
|
||||||
ext::MemResourceBase* _resource;
|
// 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
|
explicit constexpr StdPolyAlloc(MemResourceBase* memResource)
|
||||||
// it just wraps our PolyAllocWithTypeId and pass 0 as typeId
|
: _alloc{ memResource }
|
||||||
// and defines core functions for c++ Allocator concept,
|
{
|
||||||
template<class T>
|
}
|
||||||
class StdPolyAlloc {
|
explicit constexpr StdPolyAlloc(PolyAllocWithTypeId alloc)
|
||||||
public:
|
: _alloc{ alloc }
|
||||||
using value_type = T;
|
{
|
||||||
|
}
|
||||||
|
|
||||||
explicit constexpr StdPolyAlloc(MemResourceBase* memResource)
|
template<typename U>
|
||||||
:_alloc{memResource} {}
|
friend class StdPolyAlloc;
|
||||||
explicit constexpr StdPolyAlloc(PolyAllocWithTypeId alloc) : _alloc{alloc} {}
|
|
||||||
|
|
||||||
template <typename U>
|
template<class U>
|
||||||
friend class StdPolyAlloc;
|
constexpr explicit StdPolyAlloc(const StdPolyAlloc<U>& other) noexcept
|
||||||
|
: _alloc{ other._alloc }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
template<class U>
|
T* allocate(std::size_t n) { return _alloc.allocate<T>(n, 0); }
|
||||||
constexpr explicit StdPolyAlloc(const StdPolyAlloc<U>& other) noexcept
|
|
||||||
:_alloc{other._alloc} {
|
|
||||||
}
|
|
||||||
|
|
||||||
T* allocate(std::size_t n) {
|
void deallocate(T* p, std::size_t n) noexcept
|
||||||
return _alloc.allocate<T>(n, 0);
|
{
|
||||||
}
|
return _alloc.deallocate(p, n, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void deallocate(T* p, std::size_t n) noexcept {
|
template<class U>
|
||||||
return _alloc.deallocate(p, n, 0);
|
friend bool operator==(const StdPolyAlloc<T>& lhs,
|
||||||
}
|
const StdPolyAlloc<U>& rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs._alloc == rhs._alloc;
|
||||||
|
}
|
||||||
|
|
||||||
template<class U>
|
template<class U>
|
||||||
friend bool operator==(const StdPolyAlloc<T>& lhs,
|
friend bool operator!=(const StdPolyAlloc<T>& lhs,
|
||||||
const StdPolyAlloc<U>& rhs) noexcept {
|
const StdPolyAlloc<U>& rhs) noexcept
|
||||||
return lhs._alloc == rhs._alloc;
|
{
|
||||||
}
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
template<class U>
|
private:
|
||||||
friend bool operator!=(const StdPolyAlloc<T>& lhs,
|
PolyAllocWithTypeId _alloc;
|
||||||
const StdPolyAlloc<U>& rhs) noexcept {
|
};
|
||||||
return !(lhs == rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
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
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_POLYMORPHISM_UTILS_H
|
#ifndef BITSERY_EXT_POLYMORPHISM_UTILS_H
|
||||||
#define BITSERY_EXT_POLYMORPHISM_UTILS_H
|
#define BITSERY_EXT_POLYMORPHISM_UTILS_H
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <memory>
|
|
||||||
#include "memory_resource.h"
|
#include "memory_resource.h"
|
||||||
#include "../../details/adapter_common.h"
|
#include <memory>
|
||||||
#include "../../details/serialization_common.h"
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
//helper type, that contains list of types
|
// helper type, that contains list of types
|
||||||
template<typename ...>
|
template<typename...>
|
||||||
struct PolymorphicClassesList {
|
struct PolymorphicClassesList
|
||||||
};
|
{};
|
||||||
|
|
||||||
//specialize for your base class by deriving from PolymorphicDerivedClasses with list of derivatives that DIRECTLY inherits from your base class.
|
// specialize for your base class by deriving from PolymorphicDerivedClasses
|
||||||
//e.g.
|
// with list of derivatives that DIRECTLY inherits from your base class.
|
||||||
// template <> PolymorphicBaseClass<Animal>: PolymorphicDerivedClasses<Dog, Cat>{};
|
// e.g.
|
||||||
// template <> PolymorphicBaseClass<Dog>: PolymorphicDerivedClasses<Bulldog, GoldenRetriever> {};
|
// template <> PolymorphicBaseClass<Animal>: PolymorphicDerivedClasses<Dog,
|
||||||
// IMPORTANT !!!
|
// Cat>{}; template <> PolymorphicBaseClass<Dog>:
|
||||||
// although you can add all derivates to same base like this:
|
// PolymorphicDerivedClasses<Bulldog, GoldenRetriever> {}; IMPORTANT !!!
|
||||||
// template <> PolymorphicBaseClass<Animal>:PolymorphicDerivedClasses<Dog, Cat, Bulldog, GoldenRetriever>{};
|
// although you can add all derivates to same base like this:
|
||||||
// it will not work when you try to serialize Dog*, because it will not find Bulldog and GoldenRetriever
|
// template <> PolymorphicBaseClass<Animal>:PolymorphicDerivedClasses<Dog, Cat,
|
||||||
template<typename TBase>
|
// Bulldog, GoldenRetriever>{}; it will not work when you try to serialize
|
||||||
struct PolymorphicBaseClass {
|
// Dog*, because it will not find Bulldog and GoldenRetriever
|
||||||
using Childs = PolymorphicClassesList<>;
|
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
|
// derive from this class when specifying childs for your base class, atleast
|
||||||
//e.g.
|
// one child must exists, hence T1 e.g.
|
||||||
// template <> PolymorphicBaseClass<Animal>: PolymorphicDerivedClasses<Dog, Cat>{};
|
// template <> PolymorphicBaseClass<Animal>: PolymorphicDerivedClasses<Dog,
|
||||||
template<typename T1, typename ... Tn>
|
// Cat>{};
|
||||||
struct PolymorphicDerivedClasses {
|
template<typename T1, typename... Tn>
|
||||||
using Childs = PolymorphicClassesList<T1, Tn...>;
|
struct PolymorphicDerivedClasses
|
||||||
};
|
{
|
||||||
|
using Childs = PolymorphicClassesList<T1, Tn...>;
|
||||||
|
};
|
||||||
|
|
||||||
class PolymorphicHandlerBase {
|
class PolymorphicHandlerBase
|
||||||
public:
|
{
|
||||||
virtual void* create(const pointer_utils::PolyAllocWithTypeId& alloc) const = 0;
|
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>
|
virtual void* fromDerivedToBasePtr(void* obj) const = 0;
|
||||||
class PolymorphicHandler : public PolymorphicHandlerBase {
|
|
||||||
public:
|
|
||||||
|
|
||||||
void* create(const pointer_utils::PolyAllocWithTypeId& alloc) const final {
|
virtual size_t getDerivedTypeId() const = 0;
|
||||||
return toBase(alloc.newObject<TDerived>(RTTI::template get<TDerived>()));
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy(const pointer_utils::PolyAllocWithTypeId& alloc, void* ptr) const final {
|
virtual ~PolymorphicHandlerBase() = default;
|
||||||
alloc.deleteObject<TDerived>(fromBase(ptr), RTTI::template get<TDerived>());
|
};
|
||||||
}
|
|
||||||
|
|
||||||
void process(void* ser, void* obj) const final {
|
template<typename RTTI,
|
||||||
static_cast<TSerializer*>(ser)->object(*fromBase(obj));
|
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 {
|
void process(void* ser, void* obj) const final
|
||||||
return RTTI::template cast<TBase, TDerived>(static_cast<TBase*>(obj));
|
{
|
||||||
}
|
static_cast<TSerializer*>(ser)->object(*fromBase(obj));
|
||||||
|
}
|
||||||
|
|
||||||
TBase* toBase(void* obj) const {
|
void* getRootPtr(const void* obj) const final
|
||||||
return RTTI::template cast<TDerived, TBase>(static_cast<TDerived*>(obj));
|
{
|
||||||
}
|
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>
|
size_t getDerivedTypeId() const final
|
||||||
class PolymorphicContext {
|
{
|
||||||
private:
|
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;
|
TBase* toBase(void* obj) const
|
||||||
std::size_t derivedHash;
|
{
|
||||||
|
return RTTI::template cast<TDerived, TBase>(static_cast<TDerived*>(obj));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
bool operator==(const BaseToDerivedKey& other) const {
|
// Even though we don't serialize/deserialize abstract classes
|
||||||
return baseHash == other.baseHash && derivedHash == other.derivedHash;
|
// 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 {
|
void destroy(const pointer_utils::PolyAllocWithTypeId&, void*) const
|
||||||
size_t operator()(const BaseToDerivedKey& key) const {
|
{
|
||||||
return (key.baseHash + (key.baseHash << 6) + (key.derivedHash >> 2)) ^ key.derivedHash;
|
assert(false);
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
template<typename TSerializer, template<typename> class THierarchy, typename TBase, typename TDerived>
|
void process(void*, void*) const { assert(false); }
|
||||||
void add() {
|
|
||||||
addToMap<TSerializer, TBase, TDerived>(std::is_abstract<TDerived>{});
|
|
||||||
addChilds<TSerializer, THierarchy, TBase, TDerived>(typename THierarchy<TDerived>::Childs{});
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TSerializer, template<typename> class THierarchy, typename TBase, typename TDerived, typename T1, typename ... Tn>
|
void* getRootPtr(const void*) const
|
||||||
void addChilds(PolymorphicClassesList<T1, Tn...>) {
|
{
|
||||||
static_assert(std::is_base_of<TDerived, T1>::value,
|
assert(false);
|
||||||
"PolymorphicBaseClass<TBase> must derive a list of derived classes from TBase.");
|
return nullptr;
|
||||||
add<TSerializer, THierarchy, TBase, T1>();
|
}
|
||||||
addChilds<TSerializer, THierarchy, TBase, TDerived>(PolymorphicClassesList<Tn...>{});
|
|
||||||
//iterate through derived class hierarchy as well
|
|
||||||
add<TSerializer, THierarchy, T1, T1>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TSerializer, template<typename> class THierarchy, typename TBase, typename TDerived>
|
void* fromDerivedToBasePtr(void*) const final
|
||||||
void addChilds(PolymorphicClassesList<>) {
|
{
|
||||||
}
|
assert(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename TSerializer, typename TBase, typename TDerived>
|
size_t getDerivedTypeId() const { return RTTI::template get<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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TSerializer, typename TBase, typename TDerived>
|
template<typename RTTI>
|
||||||
void addToMap(std::true_type) {
|
class PolymorphicContext
|
||||||
//cannot add abstract class
|
{
|
||||||
}
|
private:
|
||||||
|
struct BaseToDerivedKey
|
||||||
|
{
|
||||||
|
|
||||||
MemResourceBase* _memResource;
|
std::size_t baseHash;
|
||||||
// store shared ptr to polymorphic handler, because it might be copied to "smart pointer" deleter
|
std::size_t derivedHash;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_RTTI_UTILS_H
|
#ifndef BITSERY_RTTI_UTILS_H
|
||||||
#define BITSERY_RTTI_UTILS_H
|
#define BITSERY_RTTI_UTILS_H
|
||||||
|
|
||||||
#include <typeinfo>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <typeinfo>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
struct StandardRTTI {
|
struct StandardRTTI
|
||||||
|
{
|
||||||
|
|
||||||
// static_assert(!std::is_pointer<TBase>::value &&
|
template<typename TBase>
|
||||||
// !std::is_const<TBase>::value &&
|
static size_t get(TBase& obj)
|
||||||
// !std::is_volatile<TBase>::value, "");
|
{
|
||||||
|
return typeid(obj).hash_code();
|
||||||
|
}
|
||||||
|
|
||||||
template<typename TBase>
|
template<typename TBase>
|
||||||
static size_t get(TBase& obj) {
|
static constexpr size_t get()
|
||||||
return typeid(obj).hash_code();
|
{
|
||||||
}
|
return typeid(TBase).hash_code();
|
||||||
|
}
|
||||||
|
|
||||||
template<typename TBase>
|
template<typename TBase, typename TDerived>
|
||||||
static constexpr size_t get() {
|
static constexpr TDerived* cast(TBase* obj)
|
||||||
return typeid(TBase).hash_code();
|
{
|
||||||
}
|
static_assert(!std::is_pointer<TDerived>::value, "");
|
||||||
|
return dynamic_cast<TDerived*>(obj);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename TBase, typename TDerived>
|
template<typename TBase>
|
||||||
static constexpr TDerived* cast(TBase* obj) {
|
static constexpr bool isPolymorphic()
|
||||||
static_assert(!std::is_pointer<TDerived>::value, "");
|
{
|
||||||
return dynamic_cast<TDerived*>(obj);
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_EXT_VALUE_RANGE_H
|
#ifndef BITSERY_EXT_VALUE_RANGE_H
|
||||||
#define BITSERY_EXT_VALUE_RANGE_H
|
#define BITSERY_EXT_VALUE_RANGE_H
|
||||||
|
|
||||||
#include "../details/serialization_common.h"
|
#include "../details/serialization_common.h"
|
||||||
#include "../details/adapter_common.h"
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace ext {
|
namespace ext {
|
||||||
//this class is used to make default RangeSpec float specialization always prefer constructor with precision
|
// this class is used to make default RangeSpec float specialization always
|
||||||
struct BitsConstraint {
|
// prefer constructor with precision
|
||||||
explicit constexpr BitsConstraint(size_t bits) : value{bits} {}
|
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
|
template<typename Reader, typename T>
|
||||||
namespace details {
|
void handleInvalidRange(Reader&, T&, std::false_type) const
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T>
|
details::RangeSpec<TValue> _range;
|
||||||
constexpr size_t getSize(T v, size_t s) {
|
};
|
||||||
return v > 0 ? getSize(v / 2, s + 1) : s;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
namespace traits {
|
||||||
constexpr size_t calcRequiredBits(T min, T max) {
|
template<typename T>
|
||||||
//call recursive function, because some compilers only support constexpr functions with return-only body
|
struct ExtensionTraits<ext::ValueRange<T>, T>
|
||||||
return getSize(max - min, 0);
|
{
|
||||||
}
|
using TValue = void;
|
||||||
|
static constexpr bool SupportValueOverload = false;
|
||||||
template<typename T, typename Enable = void>
|
static constexpr bool SupportObjectOverload = true;
|
||||||
struct RangeSpec {
|
static constexpr bool SupportLambdaOverload = false;
|
||||||
|
};
|
||||||
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;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // BITSERY_EXT_VALUE_RANGE_H
|
||||||
#endif //BITSERY_EXT_VALUE_RANGE_H
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_TRAITS_STD_ARRAY_H
|
#ifndef BITSERY_TRAITS_STD_ARRAY_H
|
||||||
#define BITSERY_TRAITS_STD_ARRAY_H
|
#define BITSERY_TRAITS_STD_ARRAY_H
|
||||||
@@ -29,16 +28,18 @@
|
|||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace traits {
|
namespace traits {
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
struct ContainerTraits<std::array<T, N>>
|
struct ContainerTraits<std::array<T, N>>
|
||||||
:public StdContainer<std::array<T, N>, false, true> {};
|
: public StdContainer<std::array<T, N>, false, true>
|
||||||
|
{};
|
||||||
|
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
struct BufferAdapterTraits<std::array<T, N>>
|
struct BufferAdapterTraits<std::array<T, N>>
|
||||||
:public StdContainerForBufferAdapter<std::array<T, N>> {};
|
: public StdContainerForBufferAdapter<std::array<T, N>>
|
||||||
}
|
{};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //BITSERY_TYPE_TRAITS_STD_ARRAY_H
|
#endif // BITSERY_TYPE_TRAITS_STD_ARRAY_H
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_TRAITS_CORE_STD_DEFAULTS_H
|
#ifndef BITSERY_TRAITS_CORE_STD_DEFAULTS_H
|
||||||
#define BITSERY_TRAITS_CORE_STD_DEFAULTS_H
|
#define BITSERY_TRAITS_CORE_STD_DEFAULTS_H
|
||||||
|
|
||||||
#include "traits.h"
|
#include "../../bitsery.h"
|
||||||
#include "../../details/serialization_common.h"
|
#include "../../details/serialization_common.h"
|
||||||
|
#include "traits.h"
|
||||||
|
|
||||||
namespace bitsery {
|
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>
|
template<typename T, bool Resizable, bool Contiguous>
|
||||||
struct StdContainer {
|
struct StdContainer
|
||||||
using TValue = typename T::value_type;
|
{
|
||||||
static constexpr bool isResizable = Resizable;
|
using TValue = typename T::value_type;
|
||||||
static constexpr bool isContiguous = Contiguous;
|
static constexpr bool isResizable = Resizable;
|
||||||
static size_t size(const T& container) {
|
static constexpr bool isContiguous = Contiguous;
|
||||||
return container.size();
|
static size_t size(const T& container) { return container.size(); }
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
//specialization for resizable
|
// specialization for resizable
|
||||||
template<typename T, bool Contiguous>
|
template<typename T, bool Contiguous>
|
||||||
struct StdContainer<T, true, Contiguous> {
|
struct StdContainer<T, true, Contiguous>
|
||||||
using TValue = typename T::value_type;
|
{
|
||||||
static constexpr bool isResizable = true;
|
using TValue = typename T::value_type;
|
||||||
static constexpr bool isContiguous = Contiguous;
|
static constexpr bool isResizable = true;
|
||||||
static size_t size(const T& container) {
|
static constexpr bool isContiguous = Contiguous;
|
||||||
return container.size();
|
static size_t size(const T& container) { return container.size(); }
|
||||||
}
|
static void resize(T& container, size_t size)
|
||||||
static void resize(T& container, size_t size) {
|
{
|
||||||
resizeImpl(container, size, std::is_default_constructible<TValue>{});
|
resizeImpl(container, size, std::is_default_constructible<TValue>{});
|
||||||
}
|
}
|
||||||
private:
|
|
||||||
using diff_t = typename T::difference_type;
|
|
||||||
|
|
||||||
static void resizeImpl(T& container, size_t size, std::true_type) {
|
private:
|
||||||
container.resize(size);
|
using diff_t = typename T::difference_type;
|
||||||
}
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#ifndef BITSERY_TRAITS_CORE_TRAITS_H
|
#ifndef BITSERY_TRAITS_CORE_TRAITS_H
|
||||||
#define BITSERY_TRAITS_CORE_TRAITS_H
|
#define BITSERY_TRAITS_CORE_TRAITS_H
|
||||||
|
|
||||||
#include <type_traits>
|
|
||||||
#include "../../details/not_defined_type.h"
|
#include "../../details/not_defined_type.h"
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace bitsery {
|
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
|
// traits for extension
|
||||||
template<typename Extension, typename T>
|
template<typename Extension, typename T>
|
||||||
struct ExtensionTraits {
|
struct ExtensionTraits
|
||||||
//this type is used, when using extesion without custom lambda
|
{
|
||||||
// eg.: extension4b>(obj, myextension{}) will call s.value4b(obj) for TValue
|
// this type is used, when using extesion without custom lambda
|
||||||
// or extesion(obj, myextension{}) will call s.object(obj) for TValue
|
// eg.: extension4b>(obj, myextension{}) will call s.value4b(obj) for TValue
|
||||||
//when this is void, it will compile, but value and object overloads will do nothing.
|
// or extesion(obj, myextension{}) will call s.object(obj) for TValue
|
||||||
using TValue = details::NotDefinedType;
|
// 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
|
// does extension support ext<N>(...) syntax, by calling value<N> with TValue
|
||||||
static constexpr bool SupportValueOverload = false;
|
static constexpr bool SupportValueOverload = false;
|
||||||
//does extension support ext(...) syntax, by calling object with TValue
|
// does extension support ext(...) syntax, by calling object with TValue
|
||||||
static constexpr bool SupportObjectOverload = false;
|
static constexpr bool SupportObjectOverload = false;
|
||||||
//does extension support ext(..., lambda)
|
// does extension support ext(..., lambda)
|
||||||
static constexpr bool SupportLambdaOverload = false;
|
static constexpr bool SupportLambdaOverload = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
//primary traits for containers
|
// primary traits for containers
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct ContainerTraits {
|
struct ContainerTraits
|
||||||
|
{
|
||||||
|
|
||||||
using TValue = details::NotDefinedType;
|
using TValue = details::NotDefinedType;
|
||||||
|
|
||||||
static constexpr bool isResizable = false;
|
static constexpr bool isResizable = false;
|
||||||
//contiguous arrays has oppurtunity to memcpy whole buffer directly when using funtamental types
|
// contiguous arrays has oppurtunity to memcpy whole buffer directly when
|
||||||
//contiguous doesn't nesessary equal to random access iterator.
|
// using funtamental types contiguous doesn't nesessary equal to random access
|
||||||
//contiguous hopefully will be available in c++20
|
// iterator. contiguous hopefully will be available in c++20
|
||||||
static constexpr bool isContiguous = false;
|
static constexpr bool isContiguous = false;
|
||||||
//resize function, called only if container is resizable
|
// resize function, called only if container is resizable
|
||||||
static void resize(T& , size_t ) {
|
static void resize(T&, size_t)
|
||||||
static_assert(std::is_void<T>::value,
|
{
|
||||||
"Define ContainerTraits or include from <bitsery/traits/...> to use as container");
|
static_assert(std::is_void<T>::value,
|
||||||
}
|
"Define ContainerTraits or include from <bitsery/traits/...> "
|
||||||
//get container size
|
"to use as container");
|
||||||
static size_t size(const T& ) {
|
}
|
||||||
static_assert(std::is_void<T>::value,
|
// get container size
|
||||||
"Define ContainerTraits or include from <bitsery/traits/...> to use as container");
|
static size_t size(const T&)
|
||||||
return 0u;
|
{
|
||||||
}
|
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
|
// specialization for C style array
|
||||||
template<typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
struct ContainerTraits<T[N]> {
|
struct ContainerTraits<T[N]>
|
||||||
using TValue = T;
|
{
|
||||||
static constexpr bool isResizable = false;
|
using TValue = T;
|
||||||
static constexpr bool isContiguous = true;
|
static constexpr bool isResizable = false;
|
||||||
static size_t size(const T (&)[N]) {
|
static constexpr bool isContiguous = true;
|
||||||
return N;
|
static size_t size(const T (&)[N]) { return N; }
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
//specialization for initializer list.
|
// specialization for initializer list.
|
||||||
//only serializer can use it
|
// only serializer can use it
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct ContainerTraits<std::initializer_list<T>> {
|
struct ContainerTraits<std::initializer_list<T>>
|
||||||
using TValue = T;
|
{
|
||||||
static constexpr bool isResizable = false;
|
using TValue = T;
|
||||||
static constexpr bool isContiguous = true;
|
static constexpr bool isResizable = false;
|
||||||
static size_t size(const std::initializer_list<T>& container) {
|
static constexpr bool isContiguous = true;
|
||||||
return container.size();
|
static size_t size(const std::initializer_list<T>& container)
|
||||||
}
|
{
|
||||||
};
|
return container.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//specialization for pointer type buffer
|
// specialization for pointer type buffer
|
||||||
//only deserializer can use it
|
// only deserializer can use it
|
||||||
template <typename T>
|
template<typename T>
|
||||||
struct ContainerTraits<const T*> {
|
struct ContainerTraits<const T*>
|
||||||
using TValue = T;
|
{
|
||||||
static constexpr bool isResizable = false;
|
using TValue = T;
|
||||||
static constexpr bool isContiguous = true;
|
static constexpr bool isResizable = false;
|
||||||
static size_t size(const T* ) {
|
static constexpr bool isContiguous = true;
|
||||||
static_assert(std::is_void<T>::value, "cannot get size for container of type T*");
|
static size_t size(const T*)
|
||||||
return 0u;
|
{
|
||||||
}
|
static_assert(std::is_void<T>::value,
|
||||||
};
|
"cannot get size for container of type T*");
|
||||||
|
return 0u;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T>
|
template<typename T>
|
||||||
struct ContainerTraits<T*> {
|
struct ContainerTraits<T*>
|
||||||
using TValue = T;
|
{
|
||||||
static constexpr bool isResizable = false;
|
using TValue = T;
|
||||||
static constexpr bool isContiguous = true;
|
static constexpr bool isResizable = false;
|
||||||
static size_t size(const T* ) {
|
static constexpr bool isContiguous = true;
|
||||||
static_assert(std::is_void<T>::value, "cannot get size for container of type T*");
|
static size_t size(const T*)
|
||||||
return 0u;
|
{
|
||||||
}
|
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
|
// traits only for buffer adapters
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct TextTraits {
|
struct BufferAdapterTraits
|
||||||
using TValue = details::NotDefinedType;
|
{
|
||||||
//if container is not null-terminated by default, add NUL at the end
|
using TIterator = details::NotDefinedType;
|
||||||
static constexpr bool addNUL = true;
|
using TConstIterator = details::NotDefinedType;
|
||||||
|
using TValue = typename ContainerTraits<T>::TValue;
|
||||||
|
|
||||||
//get length of null terminated container
|
// this function is only applies to resizable containers
|
||||||
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 only for buffer adapters
|
// this function is only used by Writer, when writing data to buffer,
|
||||||
template <typename T>
|
// it is called only current buffer size is not enough to write.
|
||||||
struct BufferAdapterTraits {
|
// it is used to dramaticaly improve performance by updating buffer directly
|
||||||
//this function is only applies to resizable containers
|
// instead of using back_insert_iterator to append each byte to buffer.
|
||||||
|
|
||||||
//this function is only used by Writer, when writing data to buffer,
|
static void increaseBufferSize(T&, size_t, size_t)
|
||||||
//it is called only current buffer size is not enough to write.
|
{
|
||||||
//it is used to dramaticaly improve performance by updating buffer directly
|
static_assert(std::is_void<T>::value,
|
||||||
//instead of using back_insert_iterator to append each byte to buffer.
|
"Define BufferAdapterTraits or include from "
|
||||||
|
"<bitsery/traits/...> to use as buffer adapter container");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
static void increaseBufferSize(T& ) {
|
// specialization for c-style buffer
|
||||||
static_assert(std::is_void<T>::value,
|
template<typename T, size_t N>
|
||||||
"Define BufferAdapterTraits or include from <bitsery/traits/...> to use as buffer adapter container");
|
struct BufferAdapterTraits<T[N]>
|
||||||
}
|
{
|
||||||
|
using TIterator = T*;
|
||||||
|
using TConstIterator = const T*;
|
||||||
|
using TValue = T;
|
||||||
|
};
|
||||||
|
|
||||||
using TIterator = details::NotDefinedType;
|
// specialization for pointer type buffer
|
||||||
using TConstIterator = details::NotDefinedType;
|
template<typename T>
|
||||||
using TValue = typename ContainerTraits<T>::TValue;
|
struct BufferAdapterTraits<const T*>
|
||||||
};
|
{
|
||||||
|
using TIterator = const T*;
|
||||||
|
using TConstIterator = const T*;
|
||||||
|
using TValue = T;
|
||||||
|
};
|
||||||
|
|
||||||
//specialization for c-style buffer
|
template<typename T>
|
||||||
template <typename T, size_t N>
|
struct BufferAdapterTraits<T*>
|
||||||
struct BufferAdapterTraits<T[N]> {
|
{
|
||||||
using TIterator = T*;
|
using TIterator = T*;
|
||||||
using TConstIterator = const T*;
|
using TConstIterator = const T*;
|
||||||
using TValue = 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
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_TRAITS_STD_DEQUE_H
|
#ifndef BITSERY_TRAITS_STD_DEQUE_H
|
||||||
#define BITSERY_TRAITS_STD_DEQUE_H
|
#define BITSERY_TRAITS_STD_DEQUE_H
|
||||||
@@ -29,14 +28,15 @@
|
|||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace traits {
|
namespace traits {
|
||||||
|
|
||||||
template<typename T, typename Allocator>
|
template<typename T, typename Allocator>
|
||||||
struct ContainerTraits<std::deque<T, Allocator>>
|
struct ContainerTraits<std::deque<T, Allocator>>
|
||||||
: public StdContainer<std::deque<T, Allocator>, true, false> {};
|
: public StdContainer<std::deque<T, Allocator>, true, false>
|
||||||
|
{};
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //BITSERY_TRAITS_STD_DEQUE_H
|
}
|
||||||
|
|
||||||
|
#endif // BITSERY_TRAITS_STD_DEQUE_H
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_TRAITS_STD_FORWARD_LIST_H
|
#ifndef BITSERY_TRAITS_STD_FORWARD_LIST_H
|
||||||
#define BITSERY_TRAITS_STD_FORWARD_LIST_H
|
#define BITSERY_TRAITS_STD_FORWARD_LIST_H
|
||||||
|
|
||||||
#include "core/traits.h"
|
|
||||||
#include "../details/serialization_common.h"
|
#include "../details/serialization_common.h"
|
||||||
|
#include "core/traits.h"
|
||||||
#include <forward_list>
|
#include <forward_list>
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace traits {
|
namespace traits {
|
||||||
|
|
||||||
template<typename T, typename Allocator>
|
template<typename T, typename Allocator>
|
||||||
struct ContainerTraits<std::forward_list<T, Allocator>> {
|
struct ContainerTraits<std::forward_list<T, Allocator>>
|
||||||
using TValue = T;
|
{
|
||||||
static constexpr bool isResizable = true;
|
using TValue = T;
|
||||||
static constexpr bool isContiguous = false;
|
static constexpr bool isResizable = true;
|
||||||
static size_t size(const std::forward_list<T, Allocator>& container) {
|
static constexpr bool isContiguous = false;
|
||||||
return static_cast<size_t>(std::distance(container.begin(), container.end()));
|
static size_t size(const std::forward_list<T, Allocator>& container)
|
||||||
}
|
{
|
||||||
static void resize(std::forward_list<T, Allocator>& container, size_t size) {
|
return static_cast<size_t>(
|
||||||
resizeImpl(container, size, std::is_default_constructible<TValue>{});
|
std::distance(container.begin(), container.end()));
|
||||||
}
|
}
|
||||||
private:
|
static void resize(std::forward_list<T, Allocator>& container, size_t size)
|
||||||
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) {
|
resizeImpl(container, size, std::is_default_constructible<TValue>{});
|
||||||
container.resize(size);
|
}
|
||||||
}
|
|
||||||
static void resizeImpl(std::forward_list<T, Allocator>& container, size_t newSize, std::false_type) {
|
private:
|
||||||
const auto oldSize = size(container);
|
using diff_t = typename std::forward_list<T, Allocator>::difference_type;
|
||||||
for (auto it = oldSize; it < newSize; ++it) {
|
static void resizeImpl(std::forward_list<T, Allocator>& container,
|
||||||
container.push_front(::bitsery::Access::create<TValue>());
|
size_t size,
|
||||||
}
|
std::true_type)
|
||||||
if (oldSize > newSize) {
|
{
|
||||||
//erase_after must have atleast one element to work
|
container.resize(size);
|
||||||
if (newSize > 0)
|
}
|
||||||
container.erase_after(std::next(std::begin(container), static_cast<diff_t>(newSize-1)));
|
static void resizeImpl(std::forward_list<T, Allocator>& container,
|
||||||
else
|
size_t newSize,
|
||||||
container.clear();
|
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
|
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_TRAITS_STD_LIST_H
|
#ifndef BITSERY_TRAITS_STD_LIST_H
|
||||||
#define BITSERY_TRAITS_STD_LIST_H
|
#define BITSERY_TRAITS_STD_LIST_H
|
||||||
@@ -29,14 +28,15 @@
|
|||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace traits {
|
namespace traits {
|
||||||
|
|
||||||
template<typename T, typename Allocator>
|
template<typename T, typename Allocator>
|
||||||
struct ContainerTraits<std::list<T, Allocator>>
|
struct ContainerTraits<std::list<T, Allocator>>
|
||||||
: public StdContainer<std::list<T, Allocator>, true, false> {};
|
: public StdContainer<std::list<T, Allocator>, true, false>
|
||||||
|
{};
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //BITSERY_TRAITS_STD_LIST_H
|
}
|
||||||
|
|
||||||
|
#endif // BITSERY_TRAITS_STD_LIST_H
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_TRAITS_STD_STRING_H
|
#ifndef BITSERY_TRAITS_STD_STRING_H
|
||||||
#define BITSERY_TRAITS_STD_STRING_H
|
#define BITSERY_TRAITS_STD_STRING_H
|
||||||
@@ -29,43 +28,53 @@
|
|||||||
|
|
||||||
namespace bitsery {
|
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>
|
template<typename CharT, typename Traits, typename Allocator>
|
||||||
struct ContainerTraits<std::basic_string<CharT, Traits, Allocator>>
|
struct ContainerTraits<std::basic_string<CharT, Traits, Allocator>>
|
||||||
:public StdContainer<std::basic_string<CharT, Traits, Allocator>, true, true> {};
|
: public StdContainer<std::basic_string<CharT, Traits, Allocator>, true, true>
|
||||||
|
{};
|
||||||
|
|
||||||
template <typename CharT, typename Traits, typename Allocator>
|
template<typename CharT, typename Traits, typename Allocator>
|
||||||
struct TextTraits<std::basic_string<CharT, Traits, Allocator>> {
|
struct TextTraits<std::basic_string<CharT, Traits, Allocator>>
|
||||||
using TValue = typename ContainerTraits<std::basic_string<CharT, Traits, Allocator>>::TValue;
|
{
|
||||||
//string is automatically null-terminated
|
using TValue = typename ContainerTraits<
|
||||||
static constexpr bool addNUL = false;
|
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
|
// is is not 100% accurate, but for performance reasons assume that string
|
||||||
static size_t length(const std::basic_string<CharT, Traits, Allocator>& str) {
|
// stores text, not binary data
|
||||||
return str.size();
|
static size_t length(const std::basic_string<CharT, Traits, Allocator>& str)
|
||||||
}
|
{
|
||||||
};
|
return str.size();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//specialization for c-array
|
// specialization for c-array
|
||||||
template <typename T, size_t N>
|
template<typename T, size_t N>
|
||||||
struct TextTraits<T[N]> {
|
struct TextTraits<T[N]>
|
||||||
using TValue = T;
|
{
|
||||||
static constexpr bool addNUL = true;
|
using TValue = T;
|
||||||
|
static constexpr bool addNUL = true;
|
||||||
|
|
||||||
static size_t length(const T (&container)[N]) {
|
static size_t length(const T (&container)[N])
|
||||||
return std::char_traits<T>::length(container);
|
{
|
||||||
}
|
return std::char_traits<T>::length(container);
|
||||||
};
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename CharT, typename Traits, typename Allocator>
|
template<typename CharT, typename Traits, typename Allocator>
|
||||||
struct BufferAdapterTraits<std::basic_string<CharT, Traits, Allocator>>
|
struct BufferAdapterTraits<std::basic_string<CharT, Traits, Allocator>>
|
||||||
:public StdContainerForBufferAdapter<std::basic_string<CharT, Traits, Allocator>> {};
|
: public StdContainerForBufferAdapter<
|
||||||
|
std::basic_string<CharT, Traits, Allocator>>
|
||||||
}
|
{};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //BITSERY_TRAITS_VECTOR_H
|
}
|
||||||
|
|
||||||
|
#endif // BITSERY_TRAITS_VECTOR_H
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#ifndef BITSERY_TRAITS_STD_VECTOR_H
|
#ifndef BITSERY_TRAITS_STD_VECTOR_H
|
||||||
#define BITSERY_TRAITS_STD_VECTOR_H
|
#define BITSERY_TRAITS_STD_VECTOR_H
|
||||||
@@ -29,22 +28,25 @@
|
|||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
|
|
||||||
namespace traits {
|
namespace traits {
|
||||||
template<typename T, typename Allocator>
|
template<typename T, typename Allocator>
|
||||||
struct ContainerTraits<std::vector<T, Allocator>>
|
struct ContainerTraits<std::vector<T, Allocator>>
|
||||||
:public StdContainer<std::vector<T, Allocator>, true, true> {};
|
: public StdContainer<std::vector<T, Allocator>, true, true>
|
||||||
|
{};
|
||||||
|
|
||||||
//bool vector is not contiguous, do not copy it directly to buffer
|
// bool vector is not contiguous, do not copy it directly to buffer
|
||||||
template<typename Allocator>
|
template<typename Allocator>
|
||||||
struct ContainerTraits<std::vector<bool, Allocator>>
|
struct ContainerTraits<std::vector<bool, Allocator>>
|
||||||
:public StdContainer<std::vector<bool, Allocator>, true, false> {};
|
: public StdContainer<std::vector<bool, Allocator>, true, false>
|
||||||
|
{};
|
||||||
|
|
||||||
template<typename T, typename Allocator>
|
template<typename T, typename Allocator>
|
||||||
struct BufferAdapterTraits<std::vector<T, Allocator>>
|
struct BufferAdapterTraits<std::vector<T, Allocator>>
|
||||||
:public StdContainerForBufferAdapter<std::vector<T, Allocator>> {};
|
: public StdContainerForBufferAdapter<std::vector<T, Allocator>>
|
||||||
|
{};
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //BITSERY_TRAITS_STD_VECTOR_H
|
}
|
||||||
|
|
||||||
|
#endif // BITSERY_TRAITS_STD_VECTOR_H
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
# Compiler specific patches
|
|
||||||
|
|
||||||
This folder will provide patches for various C++ compilers that are not C++11 compatible yet. This allows providing any fix for any compiler, without polluting core library with compiler-specific fixes.
|
|
||||||
|
|
||||||
A patch can be applied either with `git apply` or `patch` command, like this:
|
|
||||||
```bash
|
|
||||||
git apply patches/<patch_name>
|
|
||||||
patch -p1 < patches/<patch_name>
|
|
||||||
```
|
|
||||||
|
|
||||||
* [centos7_gcc4.8.2.diff](centos7_gcc4.8.2.diff) in this version, unordered_map is not fully C++11 compatible yet. It is lacking some constructors that accept allocator, and isn't using `std::allocator_traits`.
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
diff --git a/include/bitsery/details/serialization_common.h b/include/bitsery/details/serialization_common.h
|
|
||||||
index 6d5a441..462cee2 100644
|
|
||||||
--- a/include/bitsery/details/serialization_common.h
|
|
||||||
+++ b/include/bitsery/details/serialization_common.h
|
|
||||||
@@ -380,7 +380,7 @@ namespace bitsery {
|
|
||||||
template <typename ... TArgs>
|
|
||||||
explicit AdapterAndContextRef(Context& ctx, TArgs&& ... args)
|
|
||||||
: _adapter{std::forward<TArgs>(args)...},
|
|
||||||
- _context{ctx}
|
|
||||||
+ _context(ctx)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/include/bitsery/ext/inheritance.h b/include/bitsery/ext/inheritance.h
|
|
||||||
index f4c6655..5cd44ab 100644
|
|
||||||
--- a/include/bitsery/ext/inheritance.h
|
|
||||||
+++ b/include/bitsery/ext/inheritance.h
|
|
||||||
@@ -36,7 +36,7 @@ namespace bitsery {
|
|
||||||
class InheritanceContext {
|
|
||||||
public:
|
|
||||||
explicit InheritanceContext(MemResourceBase* memResource = nullptr)
|
|
||||||
- :_virtualBases{pointer_utils::StdPolyAlloc<const void*>{memResource}}
|
|
||||||
+ :_virtualBases{0, std::hash<const void*>{}, std::equal_to<const void*>{}, pointer_utils::StdPolyAlloc<const void*>{memResource}}
|
|
||||||
{}
|
|
||||||
InheritanceContext(const InheritanceContext&) = delete;
|
|
||||||
InheritanceContext&operator = (const InheritanceContext&) = delete;
|
|
||||||
diff --git a/include/bitsery/ext/utils/memory_resource.h b/include/bitsery/ext/utils/memory_resource.h
|
|
||||||
index 472965a..18b3f31 100644
|
|
||||||
--- a/include/bitsery/ext/utils/memory_resource.h
|
|
||||||
+++ b/include/bitsery/ext/utils/memory_resource.h
|
|
||||||
@@ -24,6 +24,7 @@
|
|
||||||
#define BITSERY_EXT_MEMORY_RESOURCE_H
|
|
||||||
|
|
||||||
#include "../../details/serialization_common.h"
|
|
||||||
+#include <cstddef>
|
|
||||||
#include <new>
|
|
||||||
|
|
||||||
namespace bitsery {
|
|
||||||
@@ -128,6 +129,40 @@ namespace bitsery {
|
|
||||||
public:
|
|
||||||
using value_type = T;
|
|
||||||
|
|
||||||
+ using pointer = T*;
|
|
||||||
+ using const_pointer = const T*;
|
|
||||||
+ using reference = T&;
|
|
||||||
+ using const_reference = const T&;
|
|
||||||
+ using size_type = size_t;
|
|
||||||
+ using difference_type = ptrdiff_t;
|
|
||||||
+
|
|
||||||
+ size_t max_size() const noexcept {
|
|
||||||
+ return std::numeric_limits<size_t>::max() / sizeof(value_type);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ void construct(T *p, const T &val) {
|
|
||||||
+ new((void *) p) T(val);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ template<class U, class... Args>
|
|
||||||
+ void construct(U *p, Args &&... args) {
|
|
||||||
+ new((void *) p) U(std::forward<Args>(args)...);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ void destroy(T *p) {
|
|
||||||
+ p->~T();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ template<class U>
|
|
||||||
+ void destroy(U *p) {
|
|
||||||
+ p->~U();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ template<typename U>
|
|
||||||
+ struct rebind {
|
|
||||||
+ using other = StdPolyAlloc<U>;
|
|
||||||
+ };
|
|
||||||
+
|
|
||||||
explicit constexpr StdPolyAlloc(MemResourceBase* memResource)
|
|
||||||
:_alloc{memResource} {}
|
|
||||||
explicit constexpr StdPolyAlloc(PolyAllocWithTypeId alloc) : _alloc{alloc} {}
|
|
||||||
diff --git a/include/bitsery/ext/utils/pointer_utils.h b/include/bitsery/ext/utils/pointer_utils.h
|
|
||||||
index f6f90da..6b65600 100644
|
|
||||||
--- a/include/bitsery/ext/utils/pointer_utils.h
|
|
||||||
+++ b/include/bitsery/ext/utils/pointer_utils.h
|
|
||||||
@@ -153,7 +153,7 @@ namespace bitsery {
|
|
||||||
public:
|
|
||||||
explicit PointerLinkingContextSerialization(MemResourceBase* memResource = nullptr)
|
|
||||||
: _currId{0},
|
|
||||||
- _ptrMap{StdPolyAlloc<std::pair<const void* const, PLCInfoSerializer>>{memResource}} {}
|
|
||||||
+ _ptrMap{0, std::hash<const void*>{}, std::equal_to<const void*>{}, StdPolyAlloc<std::pair<const void* const, PLCInfoSerializer>>{memResource}} {}
|
|
||||||
|
|
||||||
PointerLinkingContextSerialization(const PointerLinkingContextSerialization&) = delete;
|
|
||||||
|
|
||||||
@@ -198,7 +198,7 @@ namespace bitsery {
|
|
||||||
public:
|
|
||||||
explicit PointerLinkingContextDeserialization(MemResourceBase* memResource = nullptr)
|
|
||||||
: _memResource{memResource},
|
|
||||||
- _idMap{StdPolyAlloc<std::pair<const size_t, PLCInfoDeserializer>>{memResource}} {}
|
|
||||||
+ _idMap{0, std::hash<size_t>{}, std::equal_to<size_t>{}, StdPolyAlloc<std::pair<const size_t, PLCInfoDeserializer>>{memResource}} {}
|
|
||||||
|
|
||||||
PointerLinkingContextDeserialization(const PointerLinkingContextDeserialization&) = delete;
|
|
||||||
|
|
||||||
diff --git a/include/bitsery/ext/utils/polymorphism_utils.h b/include/bitsery/ext/utils/polymorphism_utils.h
|
|
||||||
index 6678230..a2cef4d 100644
|
|
||||||
--- a/include/bitsery/ext/utils/polymorphism_utils.h
|
|
||||||
+++ b/include/bitsery/ext/utils/polymorphism_utils.h
|
|
||||||
@@ -185,11 +185,8 @@ namespace bitsery {
|
|
||||||
|
|
||||||
explicit PolymorphicContext(MemResourceBase* memResource = nullptr)
|
|
||||||
:_memResource{memResource},
|
|
||||||
- _baseToDerivedMap{pointer_utils::StdPolyAlloc<std::pair<const BaseToDerivedKey,
|
|
||||||
- std::shared_ptr<PolymorphicHandlerBase>>>{memResource}},
|
|
||||||
- _baseToDerivedArray{pointer_utils::StdPolyAlloc<std::pair<const size_t,
|
|
||||||
- std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>{memResource}}
|
|
||||||
- {}
|
|
||||||
+ _baseToDerivedMap{0, BaseToDerivedKeyHashier{}, std::equal_to<BaseToDerivedKey>{}, pointer_utils::StdPolyAlloc<std::pair<const BaseToDerivedKey, std::shared_ptr<PolymorphicHandlerBase>>>{memResource}},
|
|
||||||
+ _baseToDerivedArray{0, std::hash<size_t>{}, std::equal_to<size_t>{}, pointer_utils::StdPolyAlloc<std::pair<const size_t, std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>{memResource}} {}
|
|
||||||
|
|
||||||
PolymorphicContext(const PolymorphicContext& ) = delete;
|
|
||||||
PolymorphicContext& operator = (const PolymorphicContext&) = delete;
|
|
||||||
@@ -14,6 +14,6 @@ configure_file(CTestConfig.cmake ${CTEST_SOURCE_DIRECTORY}/CTestConfig.cmake)
|
|||||||
ctest_start("Continuous")
|
ctest_start("Continuous")
|
||||||
ctest_configure(OPTIONS "-DBITSERY_BUILD_EXAMPLES=OFF;-DBITSERY_BUILD_TESTS=ON")
|
ctest_configure(OPTIONS "-DBITSERY_BUILD_EXAMPLES=OFF;-DBITSERY_BUILD_TESTS=ON")
|
||||||
ctest_build()
|
ctest_build()
|
||||||
ctest_test(BUILD ${CTEST_BINARY_DIRECTORY}/tests)
|
ctest_test()
|
||||||
ctest_coverage()
|
ctest_coverage()
|
||||||
#ctest_submit()
|
#ctest_submit()
|
||||||
|
|||||||
0
scripts/show_coverage.sh
Normal file → Executable file
0
scripts/show_coverage.sh
Normal file → Executable file
@@ -20,7 +20,7 @@
|
|||||||
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
#SOFTWARE.
|
#SOFTWARE.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.11)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(bitsery_tests
|
project(bitsery_tests
|
||||||
LANGUAGES CXX)
|
LANGUAGES CXX)
|
||||||
|
|
||||||
@@ -32,8 +32,6 @@ endif()
|
|||||||
|
|
||||||
file(GLOB TestSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
file(GLOB TestSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
|
||||||
|
|
||||||
enable_testing()
|
|
||||||
|
|
||||||
foreach (TestFile ${TestSourceFiles})
|
foreach (TestFile ${TestSourceFiles})
|
||||||
get_filename_component(TestName ${TestFile} NAME_WE)
|
get_filename_component(TestName ${TestFile} NAME_WE)
|
||||||
set(TestName bitsery.test.${TestName})
|
set(TestName bitsery.test.${TestName})
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#include <bitsery/brief_syntax.h>
|
#include <bitsery/brief_syntax.h>
|
||||||
#include <bitsery/brief_syntax/array.h>
|
#include <bitsery/brief_syntax/array.h>
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
#include <bitsery/brief_syntax/list.h>
|
#include <bitsery/brief_syntax/list.h>
|
||||||
#include <bitsery/brief_syntax/map.h>
|
#include <bitsery/brief_syntax/map.h>
|
||||||
#include <bitsery/brief_syntax/memory.h>
|
#include <bitsery/brief_syntax/memory.h>
|
||||||
|
|
||||||
#include <bitsery/brief_syntax/queue.h>
|
#include <bitsery/brief_syntax/queue.h>
|
||||||
#include <bitsery/brief_syntax/set.h>
|
#include <bitsery/brief_syntax/set.h>
|
||||||
#include <bitsery/brief_syntax/stack.h>
|
#include <bitsery/brief_syntax/stack.h>
|
||||||
@@ -37,424 +38,487 @@
|
|||||||
#include <bitsery/brief_syntax/unordered_set.h>
|
#include <bitsery/brief_syntax/unordered_set.h>
|
||||||
#include <bitsery/brief_syntax/vector.h>
|
#include <bitsery/brief_syntax/vector.h>
|
||||||
#if __cplusplus > 201402L
|
#if __cplusplus > 201402L
|
||||||
|
#include <bitsery/brief_syntax/optional.h>
|
||||||
#include <bitsery/brief_syntax/tuple.h>
|
#include <bitsery/brief_syntax/tuple.h>
|
||||||
#include <bitsery/brief_syntax/variant.h>
|
#include <bitsery/brief_syntax/variant.h>
|
||||||
|
#if __cplusplus > 202002L
|
||||||
|
#include <bitsery/brief_syntax/bitset.h>
|
||||||
|
#endif
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
#pragma message("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
|
#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
|
#endif
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
|
||||||
#include "serialization_test_utils.h"
|
#include "serialization_test_utils.h"
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
using testing::Eq;
|
using testing::Eq;
|
||||||
|
|
||||||
TEST(BriefSyntax, FundamentalTypesAndBool) {
|
TEST(BriefSyntax, FundamentalTypesAndBool)
|
||||||
int ti = 8745;
|
{
|
||||||
MyEnumClass te = MyEnumClass::E4;
|
int ti = 8745;
|
||||||
float tf = 485.042f;
|
MyEnumClass te = MyEnumClass::E4;
|
||||||
double td = -454184.48445;
|
float tf = 485.042f;
|
||||||
bool tb = true;
|
double td = -454184.48445;
|
||||||
SerializationContext ctx{};
|
bool tb = true;
|
||||||
ctx.createSerializer()(ti, te, tf, td, tb);
|
SerializationContext ctx{};
|
||||||
|
ctx.createSerializer()(ti, te, tf, td, tb);
|
||||||
|
|
||||||
//result
|
// result
|
||||||
int ri{};
|
int ri{};
|
||||||
MyEnumClass re{};
|
MyEnumClass re{};
|
||||||
float rf{};
|
float rf{};
|
||||||
double rd{};
|
double rd{};
|
||||||
bool rb{};
|
bool rb{};
|
||||||
ctx.createDeserializer()(ri, re, rf, rd, rb);
|
ctx.createDeserializer()(ri, re, rf, rd, rb);
|
||||||
|
|
||||||
//test
|
// test
|
||||||
EXPECT_THAT(ri, Eq(ti));
|
EXPECT_THAT(ri, Eq(ti));
|
||||||
EXPECT_THAT(re, Eq(te));
|
EXPECT_THAT(re, Eq(te));
|
||||||
EXPECT_THAT(rf, Eq(tf));
|
EXPECT_THAT(rf, Eq(tf));
|
||||||
EXPECT_THAT(rd, Eq(td));
|
EXPECT_THAT(rd, Eq(td));
|
||||||
EXPECT_THAT(rb, Eq(tb));
|
EXPECT_THAT(rb, Eq(tb));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, UseObjectFncInsteadOfValueN) {
|
TEST(BriefSyntax, UseObjectFncInsteadOfValueN)
|
||||||
int ti = 8745;
|
{
|
||||||
MyEnumClass te = MyEnumClass::E4;
|
int ti = 8745;
|
||||||
float tf = 485.042f;
|
MyEnumClass te = MyEnumClass::E4;
|
||||||
double td = -454184.48445;
|
float tf = 485.042f;
|
||||||
bool tb = true;
|
double td = -454184.48445;
|
||||||
SerializationContext ctx;
|
bool tb = true;
|
||||||
auto& ser = ctx.createSerializer();
|
SerializationContext ctx;
|
||||||
ser.object(ti);
|
auto& ser = ctx.createSerializer();
|
||||||
ser.object(te);
|
ser.object(ti);
|
||||||
ser.object(tf);
|
ser.object(te);
|
||||||
ser.object(td);
|
ser.object(tf);
|
||||||
ser.object(tb);
|
ser.object(td);
|
||||||
|
ser.object(tb);
|
||||||
|
|
||||||
//result
|
// result
|
||||||
int ri{};
|
int ri{};
|
||||||
MyEnumClass re{};
|
MyEnumClass re{};
|
||||||
float rf{};
|
float rf{};
|
||||||
double rd{};
|
double rd{};
|
||||||
bool rb{};
|
bool rb{};
|
||||||
auto& des = ctx.createDeserializer();
|
auto& des = ctx.createDeserializer();
|
||||||
des.object(ri);
|
des.object(ri);
|
||||||
des.object(re);
|
des.object(re);
|
||||||
des.object(rf);
|
des.object(rf);
|
||||||
des.object(rd);
|
des.object(rd);
|
||||||
des.object(rb);
|
des.object(rb);
|
||||||
|
|
||||||
//test
|
// test
|
||||||
EXPECT_THAT(ri, Eq(ti));
|
EXPECT_THAT(ri, Eq(ti));
|
||||||
EXPECT_THAT(re, Eq(te));
|
EXPECT_THAT(re, Eq(te));
|
||||||
EXPECT_THAT(rf, Eq(tf));
|
EXPECT_THAT(rf, Eq(tf));
|
||||||
EXPECT_THAT(rd, Eq(td));
|
EXPECT_THAT(rd, Eq(td));
|
||||||
EXPECT_THAT(rb, Eq(tb));
|
EXPECT_THAT(rb, Eq(tb));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, MixDifferentSyntax) {
|
TEST(BriefSyntax, MixDifferentSyntax)
|
||||||
int ti = 8745;
|
{
|
||||||
MyEnumClass te = MyEnumClass::E4;
|
int ti = 8745;
|
||||||
float tf = 485.042f;
|
MyEnumClass te = MyEnumClass::E4;
|
||||||
double td = -454184.48445;
|
float tf = 485.042f;
|
||||||
bool tb = true;
|
double td = -454184.48445;
|
||||||
SerializationContext ctx;
|
bool tb = true;
|
||||||
auto& ser = ctx.createSerializer();
|
SerializationContext ctx;
|
||||||
ser.value<sizeof(ti)>(ti);
|
auto& ser = ctx.createSerializer();
|
||||||
ser(te, tf, td);
|
ser.value<sizeof(ti)>(ti);
|
||||||
ser.object(tb);
|
ser(te, tf, td);
|
||||||
|
ser.object(tb);
|
||||||
|
|
||||||
//result
|
// result
|
||||||
int ri{};
|
int ri{};
|
||||||
MyEnumClass re{};
|
MyEnumClass re{};
|
||||||
float rf{};
|
float rf{};
|
||||||
double rd{};
|
double rd{};
|
||||||
bool rb{};
|
bool rb{};
|
||||||
auto& des = ctx.createDeserializer();
|
auto& des = ctx.createDeserializer();
|
||||||
des(ri, re, rf);
|
des(ri, re, rf);
|
||||||
des.value8b(rd);
|
des.value8b(rd);
|
||||||
des.object(rb);
|
des.object(rb);
|
||||||
|
|
||||||
//test
|
// test
|
||||||
EXPECT_THAT(ri, Eq(ti));
|
EXPECT_THAT(ri, Eq(ti));
|
||||||
EXPECT_THAT(re, Eq(te));
|
EXPECT_THAT(re, Eq(te));
|
||||||
EXPECT_THAT(rf, Eq(tf));
|
EXPECT_THAT(rf, Eq(tf));
|
||||||
EXPECT_THAT(rd, Eq(td));
|
EXPECT_THAT(rd, Eq(td));
|
||||||
EXPECT_THAT(rb, Eq(tb));
|
EXPECT_THAT(rb, Eq(tb));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T procBriefSyntax(const T& testData) {
|
T
|
||||||
SerializationContext ctx;
|
procBriefSyntax(const T& testData)
|
||||||
ctx.createSerializer()(testData);
|
{
|
||||||
T res{};
|
SerializationContext ctx;
|
||||||
ctx.createDeserializer()(res);
|
ctx.createSerializer()(testData);
|
||||||
return res;
|
T res{};
|
||||||
|
ctx.createDeserializer()(res);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T&& procBriefSyntaxRvalue(T&& init_value, const T& testData) {
|
T&&
|
||||||
SerializationContext ctx;
|
procBriefSyntaxRvalue(T&& init_value, const T& testData)
|
||||||
ctx.createSerializer()(testData);
|
{
|
||||||
ctx.createDeserializer()(init_value);
|
SerializationContext ctx;
|
||||||
return std::move(init_value);
|
ctx.createSerializer()(testData);
|
||||||
|
ctx.createDeserializer()(init_value);
|
||||||
|
return std::move(init_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T procBriefSyntaxWithMaxSize(const T& testData) {
|
T
|
||||||
SerializationContext ctx;
|
procBriefSyntaxWithMaxSize(const T& testData)
|
||||||
ctx.createSerializer()(bitsery::maxSize(testData, 100));
|
{
|
||||||
T res{};
|
SerializationContext ctx;
|
||||||
ctx.createDeserializer()(bitsery::maxSize(res, 100));
|
ctx.createSerializer()(bitsery::maxSize(testData, 100));
|
||||||
return res;
|
T res{};
|
||||||
|
ctx.createDeserializer()(bitsery::maxSize(res, 100));
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, CStyleArrayForValueTypesAsContainer) {
|
TEST(BriefSyntax, CStyleArrayForValueTypesAsContainer)
|
||||||
const int t1[3]{8748, -484, 45};
|
{
|
||||||
int r1[3]{0, 0, 0};
|
const int t1[3]{ 8748, -484, 45 };
|
||||||
|
int r1[3]{ 0, 0, 0 };
|
||||||
|
|
||||||
SerializationContext ctx;
|
SerializationContext ctx;
|
||||||
ctx.createSerializer()(bitsery::asContainer(t1));
|
ctx.createSerializer()(bitsery::asContainer(t1));
|
||||||
ctx.createDeserializer()(bitsery::asContainer(r1));
|
ctx.createDeserializer()(bitsery::asContainer(r1));
|
||||||
|
|
||||||
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, CStyleArrayForIntegralTypesAsText) {
|
TEST(BriefSyntax, CStyleArrayForIntegralTypesAsText)
|
||||||
const char t1[3]{"hi"};
|
{
|
||||||
char r1[3]{0, 0, 0};
|
const char t1[3]{ "hi" };
|
||||||
|
char r1[3]{ 0, 0, 0 };
|
||||||
|
|
||||||
SerializationContext ctx;
|
SerializationContext ctx;
|
||||||
ctx.createSerializer()(bitsery::asText(t1));
|
ctx.createSerializer()(bitsery::asText(t1));
|
||||||
ctx.createDeserializer()(bitsery::asText(r1));
|
ctx.createDeserializer()(bitsery::asText(r1));
|
||||||
|
|
||||||
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, CStyleArray) {
|
TEST(BriefSyntax, CStyleArray)
|
||||||
const MyEnumClass t1[3]{MyEnumClass::E1, MyEnumClass::E4, MyEnumClass::E2};
|
{
|
||||||
MyEnumClass r1[3]{};
|
const MyEnumClass t1[3]{ MyEnumClass::E1, MyEnumClass::E4, MyEnumClass::E2 };
|
||||||
|
MyEnumClass r1[3]{};
|
||||||
|
|
||||||
SerializationContext ctx;
|
SerializationContext ctx;
|
||||||
ctx.createSerializer()(t1);
|
ctx.createSerializer()(t1);
|
||||||
ctx.createDeserializer()(r1);
|
ctx.createDeserializer()(r1);
|
||||||
|
|
||||||
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdString) {
|
TEST(BriefSyntax, StdString)
|
||||||
std::string t1{"my nice string"};
|
{
|
||||||
std::string t2{};
|
std::string t1{ "my nice string" };
|
||||||
|
std::string t2{};
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdArray) {
|
TEST(BriefSyntax, StdArray)
|
||||||
std::array<int, 3> t1{8748, -484, 45};
|
{
|
||||||
std::array<int, 0> t2{};
|
std::array<int, 3> t1{ 8748, -484, 45 };
|
||||||
|
std::array<int, 0> t2{};
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdVector) {
|
TEST(BriefSyntax, StdVector)
|
||||||
std::vector<int> t1{8748, -484, 45};
|
{
|
||||||
std::vector<float> t2{5.f, 0.198f};
|
std::vector<int> t1{ 8748, -484, 45 };
|
||||||
|
std::vector<float> t2{ 5.f, 0.198f };
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdList) {
|
TEST(BriefSyntax, StdList)
|
||||||
std::list<int> t1{8748, -484, 45};
|
{
|
||||||
std::list<float> t2{5.f, 0.198f};
|
std::list<int> t1{ 8748, -484, 45 };
|
||||||
|
std::list<float> t2{ 5.f, 0.198f };
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdForwardList) {
|
TEST(BriefSyntax, StdForwardList)
|
||||||
std::forward_list<int> t1{8748, -484, 45};
|
{
|
||||||
std::forward_list<float> t2{5.f, 0.198f};
|
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(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdDeque) {
|
TEST(BriefSyntax, StdDeque)
|
||||||
std::deque<int> t1{8748, -484, 45};
|
{
|
||||||
std::deque<float> t2{5.f, 0.198f};
|
std::deque<int> t1{ 8748, -484, 45 };
|
||||||
|
std::deque<float> t2{ 5.f, 0.198f };
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdQueue) {
|
TEST(BriefSyntax, StdQueue)
|
||||||
std::queue<std::string> t1;
|
{
|
||||||
t1.push("first");
|
std::queue<std::string> t1;
|
||||||
t1.push("second string");
|
t1.push("first");
|
||||||
|
t1.push("second string");
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdPriorityQueue) {
|
TEST(BriefSyntax, StdPriorityQueue)
|
||||||
std::priority_queue<std::string> t1;
|
{
|
||||||
t1.push("first");
|
std::priority_queue<std::string> t1;
|
||||||
t1.push("second string");
|
t1.push("first");
|
||||||
t1.push("third");
|
t1.push("second string");
|
||||||
t1.push("fourth");
|
t1.push("third");
|
||||||
auto r1 = procBriefSyntax(t1);
|
t1.push("fourth");
|
||||||
//we cannot compare priority queue directly
|
auto r1 = procBriefSyntax(t1);
|
||||||
|
// we cannot compare priority queue directly
|
||||||
|
|
||||||
EXPECT_THAT(r1.size(), Eq(t1.size()));
|
EXPECT_THAT(r1.size(), Eq(t1.size()));
|
||||||
for (auto i = 0u; i < r1.size(); ++i) {
|
for (auto i = 0u; i < r1.size(); ++i) {
|
||||||
EXPECT_THAT(r1.top(), Eq(t1.top()));
|
EXPECT_THAT(r1.top(), Eq(t1.top()));
|
||||||
r1.pop();
|
r1.pop();
|
||||||
t1.pop();
|
t1.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdStack) {
|
TEST(BriefSyntax, StdStack)
|
||||||
std::stack<std::string> t1;
|
{
|
||||||
t1.push("first");
|
std::stack<std::string> t1;
|
||||||
t1.push("second string");
|
t1.push("first");
|
||||||
|
t1.push("second string");
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdUnorderedMap) {
|
TEST(BriefSyntax, StdUnorderedMap)
|
||||||
std::unordered_map<int, int> t1;
|
{
|
||||||
t1.emplace(3423, 624);
|
std::unordered_map<int, int> t1;
|
||||||
t1.emplace(-5484, -845);
|
t1.emplace(3423, 624);
|
||||||
|
t1.emplace(-5484, -845);
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdUnorderedMultiMap) {
|
TEST(BriefSyntax, StdUnorderedMultiMap)
|
||||||
std::unordered_multimap<std::string, int> t1;
|
{
|
||||||
t1.emplace("one", 624);
|
std::unordered_multimap<std::string, int> t1;
|
||||||
t1.emplace("two", -845);
|
t1.emplace("one", 624);
|
||||||
t1.emplace("one", 897);
|
t1.emplace("two", -845);
|
||||||
|
t1.emplace("one", 897);
|
||||||
|
|
||||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
||||||
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdMap) {
|
TEST(BriefSyntax, StdMap)
|
||||||
std::map<int, int> t1;
|
{
|
||||||
t1.emplace(3423, 624);
|
std::map<int, int> t1;
|
||||||
t1.emplace(-5484, -845);
|
t1.emplace(3423, 624);
|
||||||
|
t1.emplace(-5484, -845);
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdMultiMap) {
|
TEST(BriefSyntax, StdMultiMap)
|
||||||
std::multimap<std::string, int> t1;
|
{
|
||||||
t1.emplace("one", 624);
|
std::multimap<std::string, int> t1;
|
||||||
t1.emplace("two", -845);
|
t1.emplace("one", 624);
|
||||||
t1.emplace("one", 897);
|
t1.emplace("two", -845);
|
||||||
|
t1.emplace("one", 897);
|
||||||
|
|
||||||
auto res = procBriefSyntax(t1);
|
auto res = procBriefSyntax(t1);
|
||||||
//same key values is not ordered, and operator == compares each element at same position
|
// same key values is not ordered, and operator == compares each element at
|
||||||
//so we need to compare our selves
|
// same position so we need to compare our selves
|
||||||
EXPECT_THAT(res.size(), Eq(3));
|
EXPECT_THAT(res.size(), Eq(3));
|
||||||
for (auto it = t1.begin(); it != t1.end();) {
|
for (auto it = t1.begin(); it != t1.end();) {
|
||||||
const auto lr = t1.equal_range(it->first);
|
const auto lr = t1.equal_range(it->first);
|
||||||
const auto rr = res.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::distance(lr.first, lr.second) ==
|
||||||
EXPECT_TRUE(std::is_permutation(lr.first, lr.second, rr.first));
|
std::distance(rr.first, rr.second));
|
||||||
it = lr.second;
|
EXPECT_TRUE(std::is_permutation(lr.first, lr.second, rr.first));
|
||||||
}
|
it = lr.second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdUnorderedSet) {
|
TEST(BriefSyntax, StdUnorderedSet)
|
||||||
std::unordered_set<std::string> t1;
|
{
|
||||||
t1.emplace("one");
|
std::unordered_set<std::string> t1;
|
||||||
t1.emplace("two");
|
t1.emplace("one");
|
||||||
t1.emplace("three");
|
t1.emplace("two");
|
||||||
|
t1.emplace("three");
|
||||||
|
|
||||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
||||||
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdUnorderedMultiSet) {
|
TEST(BriefSyntax, StdUnorderedMultiSet)
|
||||||
std::unordered_multiset<std::string> t1;
|
{
|
||||||
t1.emplace("one");
|
std::unordered_multiset<std::string> t1;
|
||||||
t1.emplace("two");
|
t1.emplace("one");
|
||||||
t1.emplace("three");
|
t1.emplace("two");
|
||||||
t1.emplace("one");
|
t1.emplace("three");
|
||||||
|
t1.emplace("one");
|
||||||
|
|
||||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
||||||
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdSet) {
|
TEST(BriefSyntax, StdSet)
|
||||||
std::set<std::string> t1;
|
{
|
||||||
t1.emplace("one");
|
std::set<std::string> t1;
|
||||||
t1.emplace("two");
|
t1.emplace("one");
|
||||||
t1.emplace("three");
|
t1.emplace("two");
|
||||||
|
t1.emplace("three");
|
||||||
|
|
||||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
||||||
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdMultiSet) {
|
TEST(BriefSyntax, StdMultiSet)
|
||||||
std::multiset<std::string> t1;
|
{
|
||||||
t1.emplace("one");
|
std::multiset<std::string> t1;
|
||||||
t1.emplace("two");
|
t1.emplace("one");
|
||||||
t1.emplace("three");
|
t1.emplace("two");
|
||||||
t1.emplace("one");
|
t1.emplace("three");
|
||||||
t1.emplace("two");
|
t1.emplace("one");
|
||||||
|
t1.emplace("two");
|
||||||
|
|
||||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
||||||
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdSmartPtr) {
|
TEST(BriefSyntax, StdSmartPtr)
|
||||||
std::shared_ptr<int> dataShared1(new int{4});
|
{
|
||||||
std::weak_ptr<int> dataWeak1(dataShared1);
|
std::shared_ptr<int> dataShared1(new int{ 4 });
|
||||||
std::unique_ptr<std::string> dataUnique1{new std::string{"hello world"}};
|
std::weak_ptr<int> dataWeak1(dataShared1);
|
||||||
|
std::unique_ptr<std::string> dataUnique1{ new std::string{ "hello world" } };
|
||||||
|
|
||||||
bitsery::ext::PointerLinkingContext plctx1{};
|
bitsery::ext::PointerLinkingContext plctx1{};
|
||||||
BasicSerializationContext<bitsery::ext::PointerLinkingContext> ctx;
|
BasicSerializationContext<bitsery::ext::PointerLinkingContext> ctx;
|
||||||
ctx.createSerializer(plctx1)(dataShared1, dataWeak1, dataUnique1);
|
ctx.createSerializer(plctx1)(dataShared1, dataWeak1, dataUnique1);
|
||||||
|
|
||||||
std::shared_ptr<int> resShared1{};
|
std::shared_ptr<int> resShared1{};
|
||||||
std::weak_ptr<int> resWeak1{};
|
std::weak_ptr<int> resWeak1{};
|
||||||
std::unique_ptr<std::string> resUnique1{};
|
std::unique_ptr<std::string> resUnique1{};
|
||||||
ctx.createDeserializer(plctx1)(resShared1, resWeak1, resUnique1);
|
ctx.createDeserializer(plctx1)(resShared1, resWeak1, resUnique1);
|
||||||
//clear shared state from pointer linking context
|
// clear shared state from pointer linking context
|
||||||
plctx1.clearSharedState();
|
plctx1.clearSharedState();
|
||||||
|
|
||||||
EXPECT_TRUE(plctx1.isValid());
|
EXPECT_TRUE(plctx1.isValid());
|
||||||
EXPECT_THAT(*resShared1, Eq(*dataShared1));
|
EXPECT_THAT(*resShared1, Eq(*dataShared1));
|
||||||
EXPECT_THAT(*resWeak1.lock(), Eq(*dataWeak1.lock()));
|
EXPECT_THAT(*resWeak1.lock(), Eq(*dataWeak1.lock()));
|
||||||
EXPECT_THAT(*resUnique1, Eq(*dataUnique1));
|
EXPECT_THAT(*resUnique1, Eq(*dataUnique1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdDuration) {
|
TEST(BriefSyntax, StdDuration)
|
||||||
std::chrono::duration<int64_t, std::milli> t1{54654};
|
{
|
||||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
std::chrono::duration<int64_t, std::milli> t1{ 54654 };
|
||||||
|
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdTimePoint) {
|
TEST(BriefSyntax, StdTimePoint)
|
||||||
using Duration = std::chrono::duration<double, std::milli>;
|
{
|
||||||
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
|
using Duration = std::chrono::duration<double, std::milli>;
|
||||||
|
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
|
||||||
|
|
||||||
TP data{Duration{874656.4798}};
|
TP data{ Duration{ 874656.4798 } };
|
||||||
EXPECT_TRUE(procBriefSyntax(data) == data);
|
EXPECT_TRUE(procBriefSyntax(data) == data);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdAtomic) {
|
TEST(BriefSyntax, StdAtomic)
|
||||||
std::atomic<int32_t> atm0{54654};
|
{
|
||||||
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<int32_t>{}, atm0) == atm0);
|
std::atomic<int32_t> atm0{ 54654 };
|
||||||
|
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<int32_t>{}, atm0) == atm0);
|
||||||
|
|
||||||
std::atomic<bool> atm1{false};
|
std::atomic<bool> atm1{ false };
|
||||||
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm1) == atm1);
|
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm1) == atm1);
|
||||||
|
|
||||||
std::atomic<bool> atm2{true};
|
std::atomic<bool> atm2{ true };
|
||||||
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm2) == atm2);
|
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm2) == atm2);
|
||||||
|
|
||||||
std::atomic<uint16_t> atm3;
|
std::atomic<uint16_t> atm3;
|
||||||
atm3.store(0x1337);
|
atm3.store(0x1337);
|
||||||
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<uint16_t>{}, atm3).load() == 0x1337);
|
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<uint16_t>{}, atm3).load() ==
|
||||||
|
0x1337);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if __cplusplus > 201402L
|
#if __cplusplus > 201402L
|
||||||
|
|
||||||
TEST(BriefSyntax, StdTuple) {
|
TEST(BriefSyntax, StdTuple)
|
||||||
std::tuple<int, std::string, std::vector<char>> t1{5,"hello hello", {'A','B','C'}};
|
{
|
||||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
std::tuple<int, std::string, std::vector<char>> t1{ 5,
|
||||||
|
"hello hello",
|
||||||
|
{ 'A', 'B', 'C' } };
|
||||||
|
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdVariant) {
|
TEST(BriefSyntax, StdVariant)
|
||||||
std::variant<float, std::string, std::chrono::milliseconds> t1{std::string("hello hello")};
|
{
|
||||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
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
|
#endif
|
||||||
|
|
||||||
TEST(BriefSyntax, NestedTypes) {
|
#endif
|
||||||
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));
|
TEST(BriefSyntax, NestedTypes)
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
{
|
||||||
|
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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
#include "serialization_test_utils.h"
|
||||||
|
#include <bitsery/deserializer.h>
|
||||||
#include <bitsery/ext/value_range.h>
|
#include <bitsery/ext/value_range.h>
|
||||||
#include <bitsery/serializer.h>
|
#include <bitsery/serializer.h>
|
||||||
#include <bitsery/deserializer.h>
|
|
||||||
#include "serialization_test_utils.h"
|
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
using testing::Eq;
|
|
||||||
using testing::ContainerEq;
|
|
||||||
using bitsery::EndiannessType;
|
|
||||||
using bitsery::DefaultConfig;
|
using bitsery::DefaultConfig;
|
||||||
|
using bitsery::EndiannessType;
|
||||||
|
using testing::ContainerEq;
|
||||||
|
using testing::Eq;
|
||||||
|
|
||||||
constexpr EndiannessType getInverseEndianness(EndiannessType e) {
|
constexpr EndiannessType
|
||||||
return e == EndiannessType::LittleEndian
|
getInverseEndianness(EndiannessType e)
|
||||||
? EndiannessType::BigEndian
|
{
|
||||||
: EndiannessType::LittleEndian;
|
return e == EndiannessType::LittleEndian ? EndiannessType::BigEndian
|
||||||
|
: EndiannessType::LittleEndian;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InverseEndiannessConfig {
|
struct InverseEndiannessConfig
|
||||||
static constexpr bitsery::EndiannessType Endianness = getInverseEndianness(DefaultConfig::Endianness);
|
{
|
||||||
static constexpr bool CheckDataErrors = true;
|
static constexpr bitsery::EndiannessType Endianness =
|
||||||
static constexpr bool CheckAdapterErrors = true;
|
getInverseEndianness(DefaultConfig::Endianness);
|
||||||
|
static constexpr bool CheckDataErrors = true;
|
||||||
|
static constexpr bool CheckAdapterErrors = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IntegralTypes {
|
struct IntegralTypes
|
||||||
int64_t a;
|
{
|
||||||
uint32_t b;
|
int64_t a;
|
||||||
int16_t c;
|
uint32_t b;
|
||||||
uint8_t d;
|
int16_t c;
|
||||||
int8_t e;
|
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 expected result after swap
|
||||||
//fill initial values
|
IntegralTypes resInv{};
|
||||||
IntegralTypes src{};
|
resInv.a = static_cast<int64_t>(0x8877665544332211u);
|
||||||
src.a = static_cast<int64_t>(0x1122334455667788u);
|
resInv.b = 0xEEDDCCBBu;
|
||||||
src.b = 0xBBCCDDEEu;
|
resInv.c = static_cast<int16_t>(0xDDCCu);
|
||||||
src.c = static_cast<int16_t>(0xCCDDu);
|
resInv.d = static_cast<uint8_t>(0xDDu);
|
||||||
src.d = static_cast<uint8_t>(0xDDu);
|
resInv.e = static_cast<int8_t>(0xEEu);
|
||||||
src.e = static_cast<int8_t>(0xEEu);
|
|
||||||
|
|
||||||
//fill expected result after swap
|
// create and write to buffer
|
||||||
IntegralTypes resInv{};
|
Buffer buf{};
|
||||||
resInv.a = static_cast<int64_t>(0x8877665544332211u);
|
Writer bw{ buf };
|
||||||
resInv.b = 0xEEDDCCBBu;
|
bw.writeBytes<8>(src.a);
|
||||||
resInv.c = static_cast<int16_t>(0xDDCCu);
|
bw.writeBytes<4>(src.b);
|
||||||
resInv.d = static_cast<uint8_t>(0xDDu);
|
bw.writeBytes<2>(src.c);
|
||||||
resInv.e = static_cast<int8_t>(0xEEu);
|
bw.writeBytes<1>(src.d);
|
||||||
|
bw.writeBytes<1>(src.e);
|
||||||
//create and write to buffer
|
bw.flush();
|
||||||
Buffer buf{};
|
// read from buffer using inverse endianness config
|
||||||
Writer bw{buf};
|
InverseReader br{ buf.begin(), bw.writtenBytesCount() };
|
||||||
bw.writeBytes<8>(src.a);
|
IntegralTypes res{};
|
||||||
bw.writeBytes<4>(src.b);
|
br.readBytes<8>(res.a);
|
||||||
bw.writeBytes<2>(src.c);
|
br.readBytes<4>(res.b);
|
||||||
bw.writeBytes<1>(src.d);
|
br.readBytes<2>(res.c);
|
||||||
bw.writeBytes<1>(src.e);
|
br.readBytes<1>(res.d);
|
||||||
bw.flush();
|
br.readBytes<1>(res.e);
|
||||||
//read from buffer using inverse endianness config
|
// check results
|
||||||
InverseReader br{buf.begin(), bw.writtenBytesCount()};
|
EXPECT_THAT(res.a, Eq(resInv.a));
|
||||||
IntegralTypes res{};
|
EXPECT_THAT(res.b, Eq(resInv.b));
|
||||||
br.readBytes<8>(res.a);
|
EXPECT_THAT(res.c, Eq(resInv.c));
|
||||||
br.readBytes<4>(res.b);
|
EXPECT_THAT(res.d, Eq(resInv.d));
|
||||||
br.readBytes<2>(res.c);
|
EXPECT_THAT(res.e, Eq(resInv.e));
|
||||||
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) {
|
TEST(DataEndianness, WhenWrite1ByteValuesThenEndiannessIsIgnored)
|
||||||
//fill initial values
|
{
|
||||||
constexpr size_t SIZE = 4;
|
// fill initial values
|
||||||
uint8_t src[SIZE] = {0xAA, 0xBB, 0xCC, 0xDD};
|
constexpr size_t SIZE = 4;
|
||||||
uint8_t res[SIZE] = {};
|
uint8_t src[SIZE] = { 0xAA, 0xBB, 0xCC, 0xDD };
|
||||||
//create and write to buffer
|
uint8_t res[SIZE] = {};
|
||||||
Buffer buf{};
|
// create and write to buffer
|
||||||
Writer bw{buf};
|
Buffer buf{};
|
||||||
bw.writeBuffer<1>(src, SIZE);
|
Writer bw{ buf };
|
||||||
bw.flush();
|
bw.writeBuffer<1>(src, SIZE);
|
||||||
//read from buffer using inverse endianness config
|
bw.flush();
|
||||||
InverseReader br{buf.begin(), bw.writtenBytesCount()};
|
// read from buffer using inverse endianness config
|
||||||
br.readBuffer<1>(res, SIZE);
|
InverseReader br{ buf.begin(), bw.writtenBytesCount() };
|
||||||
//result is identical, because we write separate values, of size 1byte, that requires no swapping
|
br.readBuffer<1>(res, SIZE);
|
||||||
//check results
|
// result is identical, because we write separate values, of size 1byte, that
|
||||||
EXPECT_THAT(res, ContainerEq(src));
|
// requires no swapping check results
|
||||||
|
EXPECT_THAT(res, ContainerEq(src));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DataEndianness, WhenWriteMoreThan1ByteValuesThenValuesAreSwapped) {
|
TEST(DataEndianness, WhenWriteMoreThan1ByteValuesThenValuesAreSwapped)
|
||||||
//fill initial values
|
{
|
||||||
constexpr size_t SIZE = 4;
|
// fill initial values
|
||||||
uint16_t src[SIZE] = {0xAA00, 0xBB11, 0xCC22, 0xDD33};
|
constexpr size_t SIZE = 4;
|
||||||
uint16_t resInv[SIZE] = {0x00AA, 0x11BB, 0x22CC, 0x33DD};
|
uint16_t src[SIZE] = { 0xAA00, 0xBB11, 0xCC22, 0xDD33 };
|
||||||
uint16_t res[SIZE] = {};
|
uint16_t resInv[SIZE] = { 0x00AA, 0x11BB, 0x22CC, 0x33DD };
|
||||||
//create and write to buffer
|
uint16_t res[SIZE] = {};
|
||||||
Buffer buf{};
|
// create and write to buffer
|
||||||
Writer bw{buf};
|
Buffer buf{};
|
||||||
bw.writeBuffer<2>(src, SIZE);
|
Writer bw{ buf };
|
||||||
bw.flush();
|
bw.writeBuffer<2>(src, SIZE);
|
||||||
//read from buffer using inverse endianness config
|
bw.flush();
|
||||||
InverseReader br{buf.begin(), bw.writtenBytesCount()};
|
// read from buffer using inverse endianness config
|
||||||
br.readBuffer<2>(res, SIZE);
|
InverseReader br{ buf.begin(), bw.writtenBytesCount() };
|
||||||
//result is identical, because we write separate values, of size 1byte, that requires no swapping
|
br.readBuffer<2>(res, SIZE);
|
||||||
//check results
|
// result is identical, because we write separate values, of size 1byte, that
|
||||||
EXPECT_THAT(res, ContainerEq(resInv));
|
// requires no swapping check results
|
||||||
|
EXPECT_THAT(res, ContainerEq(resInv));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
template <typename T>
|
constexpr size_t
|
||||||
constexpr size_t getBits(T v) {
|
getBits(T v)
|
||||||
return bitsery::details::calcRequiredBits<T>({}, v);
|
{
|
||||||
|
return bitsery::details::calcRequiredBits<T>({}, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IntegralUnsignedTypes {
|
struct IntegralUnsignedTypes
|
||||||
uint64_t a;
|
{
|
||||||
uint32_t b;
|
uint64_t a;
|
||||||
uint16_t c;
|
uint32_t b;
|
||||||
uint8_t d;
|
uint16_t c;
|
||||||
|
uint8_t d;
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(DataEndianness, WhenValueTypeIs1ByteThenBitOperationsIsNotAffectedByEndianness) {
|
TEST(DataEndianness,
|
||||||
//fill initial values
|
WhenValueTypeIs1ByteThenBitOperationsIsNotAffectedByEndianness)
|
||||||
constexpr IntegralUnsignedTypes src {
|
{
|
||||||
0x0000334455667788,
|
// fill initial values
|
||||||
0x00CCDDEE,
|
constexpr IntegralUnsignedTypes src{
|
||||||
0x00DD,
|
0x0000334455667788,
|
||||||
0x0F,
|
0x00CCDDEE,
|
||||||
};
|
0x00DD,
|
||||||
|
0x0F,
|
||||||
|
};
|
||||||
|
|
||||||
constexpr size_t aBITS = getBits(src.a) + 8;
|
constexpr size_t aBITS = getBits(src.a) + 8;
|
||||||
constexpr size_t bBITS = getBits(src.b) + 0;
|
constexpr size_t bBITS = getBits(src.b) + 0;
|
||||||
constexpr size_t cBITS = getBits(src.c) + 5;
|
constexpr size_t cBITS = getBits(src.c) + 5;
|
||||||
constexpr size_t dBITS = getBits(src.d) + 2;
|
constexpr size_t dBITS = getBits(src.d) + 2;
|
||||||
//create and write to buffer
|
// create and write to buffer
|
||||||
Buffer buf{};
|
Buffer buf{};
|
||||||
Writer bw{buf};
|
Writer bw{ buf };
|
||||||
bitsery::details::OutputAdapterBitPackingWrapper<Writer> bpw{bw};
|
bitsery::details::OutputAdapterBitPackingWrapper<Writer> bpw{ bw };
|
||||||
bpw.writeBits(src.a, aBITS);
|
bpw.writeBits(src.a, aBITS);
|
||||||
bpw.writeBits(src.b, bBITS);
|
bpw.writeBits(src.b, bBITS);
|
||||||
bpw.writeBits(src.c, cBITS);
|
bpw.writeBits(src.c, cBITS);
|
||||||
bpw.writeBits(src.d, dBITS);
|
bpw.writeBits(src.d, dBITS);
|
||||||
bpw.flush();
|
bpw.flush();
|
||||||
//read from buffer using inverse endianness config
|
// read from buffer using inverse endianness config
|
||||||
InverseReader br{buf.begin(), bpw.writtenBytesCount()};
|
InverseReader br{ buf.begin(), bpw.writtenBytesCount() };
|
||||||
bitsery::details::InputAdapterBitPackingWrapper<InverseReader> bpr{br};
|
bitsery::details::InputAdapterBitPackingWrapper<InverseReader> bpr{ br };
|
||||||
IntegralUnsignedTypes res{};
|
IntegralUnsignedTypes res{};
|
||||||
bpr.readBits(res.a, aBITS);
|
bpr.readBits(res.a, aBITS);
|
||||||
bpr.readBits(res.b, bBITS);
|
bpr.readBits(res.b, bBITS);
|
||||||
bpr.readBits(res.c, cBITS);
|
bpr.readBits(res.c, cBITS);
|
||||||
bpr.readBits(res.d, dBITS);
|
bpr.readBits(res.d, dBITS);
|
||||||
//check results
|
// check results
|
||||||
EXPECT_THAT(res.a, Eq(src.a));
|
EXPECT_THAT(res.a, Eq(src.a));
|
||||||
EXPECT_THAT(res.b, Eq(src.b));
|
EXPECT_THAT(res.b, Eq(src.b));
|
||||||
EXPECT_THAT(res.c, Eq(src.c));
|
EXPECT_THAT(res.c, Eq(src.c));
|
||||||
EXPECT_THAT(res.d, Eq(src.d));
|
EXPECT_THAT(res.d, Eq(src.d));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
#include "serialization_test_utils.h"
|
||||||
|
#include <bitsery/deserializer.h>
|
||||||
#include <bitsery/ext/value_range.h>
|
#include <bitsery/ext/value_range.h>
|
||||||
#include <bitsery/serializer.h>
|
#include <bitsery/serializer.h>
|
||||||
#include <bitsery/deserializer.h>
|
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
#include "serialization_test_utils.h"
|
|
||||||
|
|
||||||
|
|
||||||
using testing::Eq;
|
|
||||||
using testing::ContainerEq;
|
using testing::ContainerEq;
|
||||||
|
using testing::Eq;
|
||||||
|
|
||||||
using AdapterBitPackingWriter = bitsery::details::OutputAdapterBitPackingWrapper<Writer>;
|
using AdapterBitPackingWriter =
|
||||||
using AdapterBitPackingReader = bitsery::details::InputAdapterBitPackingWrapper<Reader>;
|
bitsery::details::OutputAdapterBitPackingWrapper<Writer>;
|
||||||
|
using AdapterBitPackingReader =
|
||||||
|
bitsery::details::InputAdapterBitPackingWrapper<Reader>;
|
||||||
|
|
||||||
|
struct IntegralUnsignedTypes
|
||||||
struct IntegralUnsignedTypes {
|
{
|
||||||
uint32_t a;
|
uint32_t a;
|
||||||
uint16_t b;
|
uint16_t b;
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
uint8_t d;
|
uint8_t d;
|
||||||
uint64_t e;
|
uint64_t e;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template<typename T>
|
||||||
constexpr size_t getBits(T v) {
|
constexpr size_t
|
||||||
return bitsery::details::calcRequiredBits<T>({}, v);
|
getBits(T v)
|
||||||
|
{
|
||||||
|
return bitsery::details::calcRequiredBits<T>({}, v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// *** bits operations
|
// *** bits operations
|
||||||
|
|
||||||
TEST(DataBitsAndBytesOperations, WriteAndReadBitsMaxTypeValues) {
|
TEST(DataBitsAndBytesOperations, WriteAndReadBitsMaxTypeValues)
|
||||||
Buffer buf;
|
{
|
||||||
Writer bw{buf};
|
Buffer buf;
|
||||||
AdapterBitPackingWriter bpw{bw};
|
Writer bw{ buf };
|
||||||
bpw.writeBits(std::numeric_limits<uint64_t>::max(), 64);
|
AdapterBitPackingWriter bpw{ bw };
|
||||||
bpw.writeBits(std::numeric_limits<uint32_t>::max(), 32);
|
bpw.writeBits(std::numeric_limits<uint64_t>::max(), 64);
|
||||||
bpw.writeBits(std::numeric_limits<uint16_t>::max(), 16);
|
bpw.writeBits(std::numeric_limits<uint32_t>::max(), 32);
|
||||||
bpw.writeBits(std::numeric_limits<uint8_t>::max(), 8);
|
bpw.writeBits(std::numeric_limits<uint16_t>::max(), 16);
|
||||||
bpw.flush();
|
bpw.writeBits(std::numeric_limits<uint8_t>::max(), 8);
|
||||||
|
bpw.flush();
|
||||||
|
|
||||||
Reader br{buf.begin(), bpw.writtenBytesCount()};
|
Reader br{ buf.begin(), bpw.writtenBytesCount() };
|
||||||
AdapterBitPackingReader bpr{br};
|
AdapterBitPackingReader bpr{ br };
|
||||||
uint64_t v64{};
|
uint64_t v64{};
|
||||||
uint32_t v32{};
|
uint32_t v32{};
|
||||||
uint16_t v16{};
|
uint16_t v16{};
|
||||||
uint8_t v8{};
|
uint8_t v8{};
|
||||||
bpr.readBits(v64, 64);
|
bpr.readBits(v64, 64);
|
||||||
bpr.readBits(v32, 32);
|
bpr.readBits(v32, 32);
|
||||||
bpr.readBits(v16, 16);
|
bpr.readBits(v16, 16);
|
||||||
bpr.readBits(v8, 8);
|
bpr.readBits(v8, 8);
|
||||||
|
|
||||||
EXPECT_THAT(v64, Eq(std::numeric_limits<uint64_t>::max()));
|
EXPECT_THAT(v64, Eq(std::numeric_limits<uint64_t>::max()));
|
||||||
EXPECT_THAT(v32, Eq(std::numeric_limits<uint32_t>::max()));
|
EXPECT_THAT(v32, Eq(std::numeric_limits<uint32_t>::max()));
|
||||||
EXPECT_THAT(v16, Eq(std::numeric_limits<uint16_t>::max()));
|
EXPECT_THAT(v16, Eq(std::numeric_limits<uint16_t>::max()));
|
||||||
EXPECT_THAT(v8, Eq(std::numeric_limits<uint8_t>::max()));
|
EXPECT_THAT(v8, Eq(std::numeric_limits<uint8_t>::max()));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DataBitsAndBytesOperations, WriteAndReadBits) {
|
TEST(DataBitsAndBytesOperations, WriteAndReadBits)
|
||||||
//setup data
|
{
|
||||||
constexpr IntegralUnsignedTypes data{
|
// setup data
|
||||||
485454,//bits 19
|
constexpr IntegralUnsignedTypes data{
|
||||||
45978,//bits 16
|
485454, // bits 19
|
||||||
0,//bits 1
|
45978, // bits 16
|
||||||
36,//bits 6
|
0, // bits 1
|
||||||
479845648946//bits 39
|
36, // bits 6
|
||||||
};
|
479845648946 // bits 39
|
||||||
|
};
|
||||||
|
|
||||||
constexpr size_t aBITS = getBits(data.a) + 2;
|
constexpr size_t aBITS = getBits(data.a) + 2;
|
||||||
constexpr size_t bBITS = getBits(data.b) + 0;
|
constexpr size_t bBITS = getBits(data.b) + 0;
|
||||||
constexpr size_t cBITS = getBits(data.c) + 2;
|
constexpr size_t cBITS = getBits(data.c) + 2;
|
||||||
constexpr size_t dBITS = getBits(data.d) + 1;
|
constexpr size_t dBITS = getBits(data.d) + 1;
|
||||||
constexpr size_t eBITS = getBits(data.e) + 8;
|
constexpr size_t eBITS = getBits(data.e) + 8;
|
||||||
|
|
||||||
//create and write to buffer
|
// create and write to buffer
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
Writer bw{buf};
|
Writer bw{ buf };
|
||||||
AdapterBitPackingWriter bpw{bw};
|
AdapterBitPackingWriter bpw{ bw };
|
||||||
|
|
||||||
bpw.writeBits(data.a, aBITS);
|
bpw.writeBits(data.a, aBITS);
|
||||||
bpw.writeBits(data.b, bBITS);
|
bpw.writeBits(data.b, bBITS);
|
||||||
bpw.writeBits(data.c, cBITS);
|
bpw.writeBits(data.c, cBITS);
|
||||||
bpw.writeBits(data.d, dBITS);
|
bpw.writeBits(data.d, dBITS);
|
||||||
bpw.writeBits(data.e, eBITS);
|
bpw.writeBits(data.e, eBITS);
|
||||||
bpw.flush();
|
bpw.flush();
|
||||||
auto writtenSize = bpw.writtenBytesCount();
|
auto writtenSize = bpw.writtenBytesCount();
|
||||||
auto bytesCount = ((aBITS + bBITS + cBITS + dBITS + eBITS) / 8) +1 ;
|
auto bytesCount = ((aBITS + bBITS + cBITS + dBITS + eBITS) / 8) + 1;
|
||||||
EXPECT_THAT(writtenSize, Eq(bytesCount));
|
EXPECT_THAT(writtenSize, Eq(bytesCount));
|
||||||
//read from buffer
|
// read from buffer
|
||||||
Reader br{buf.begin(), writtenSize};
|
Reader br{ buf.begin(), writtenSize };
|
||||||
AdapterBitPackingReader bpr{br};
|
AdapterBitPackingReader bpr{ br };
|
||||||
|
|
||||||
IntegralUnsignedTypes res{};
|
IntegralUnsignedTypes res{};
|
||||||
|
|
||||||
bpr.readBits(res.a, aBITS);
|
bpr.readBits(res.a, aBITS);
|
||||||
bpr.readBits(res.b, bBITS);
|
bpr.readBits(res.b, bBITS);
|
||||||
bpr.readBits(res.c, cBITS);
|
bpr.readBits(res.c, cBITS);
|
||||||
bpr.readBits(res.d, dBITS);
|
bpr.readBits(res.d, dBITS);
|
||||||
bpr.readBits(res.e, eBITS);
|
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));
|
|
||||||
|
|
||||||
|
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) {
|
TEST(DataBitsAndBytesOperations, WrittenSizeIsCountedPerByteNotPerBit)
|
||||||
//setup data
|
{
|
||||||
|
// setup data
|
||||||
|
|
||||||
//create and write to buffer
|
// create and write to buffer
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
Writer bw{buf};
|
Writer bw{ buf };
|
||||||
AdapterBitPackingWriter bpw{bw};
|
AdapterBitPackingWriter bpw{ bw };
|
||||||
|
|
||||||
bpw.writeBits(7u,3);
|
bpw.writeBits(7u, 3);
|
||||||
bpw.flush();
|
bpw.flush();
|
||||||
auto writtenSize = bpw.writtenBytesCount();
|
auto writtenSize = bpw.writtenBytesCount();
|
||||||
EXPECT_THAT(writtenSize, Eq(1));
|
EXPECT_THAT(writtenSize, Eq(1));
|
||||||
|
|
||||||
//read from buffer
|
// read from buffer
|
||||||
Reader br{buf.begin(), writtenSize};
|
Reader br{ buf.begin(), writtenSize };
|
||||||
AdapterBitPackingReader bpr{br};
|
AdapterBitPackingReader bpr{ br };
|
||||||
uint16_t tmp;
|
uint16_t tmp;
|
||||||
bpr.readBits(tmp,4);
|
bpr.readBits(tmp, 4);
|
||||||
bpr.readBits(tmp,2);
|
bpr.readBits(tmp, 2);
|
||||||
bpr.readBits(tmp,2);
|
bpr.readBits(tmp, 2);
|
||||||
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
|
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
|
||||||
bpr.readBits(tmp,2);
|
bpr.readBits(tmp, 2);
|
||||||
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::DataOverflow));//false
|
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::DataOverflow)); // false
|
||||||
|
|
||||||
//part of next byte
|
// part of next byte
|
||||||
Reader br1{buf.begin(), writtenSize};
|
Reader br1{ buf.begin(), writtenSize };
|
||||||
AdapterBitPackingReader bpr1{br1};
|
AdapterBitPackingReader bpr1{ br1 };
|
||||||
bpr1.readBits(tmp,2);
|
bpr1.readBits(tmp, 2);
|
||||||
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::NoError));
|
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::NoError));
|
||||||
bpr1.readBits(tmp,7);
|
bpr1.readBits(tmp, 7);
|
||||||
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::DataOverflow));//false
|
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::DataOverflow)); // false
|
||||||
|
|
||||||
//bigger than byte
|
// bigger than byte
|
||||||
Reader br2{buf.begin(), writtenSize};
|
Reader br2{ buf.begin(), writtenSize };
|
||||||
AdapterBitPackingReader bpr2{br2};
|
AdapterBitPackingReader bpr2{ br2 };
|
||||||
bpr2.readBits(tmp,9);
|
bpr2.readBits(tmp, 9);
|
||||||
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::DataOverflow));//false
|
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::DataOverflow)); // false
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DataBitsAndBytesOperations, ConsecutiveCallsToAlignHasNoEffect) {
|
TEST(DataBitsAndBytesOperations, ConsecutiveCallsToAlignHasNoEffect)
|
||||||
Buffer buf;
|
{
|
||||||
Writer bw{buf};
|
Buffer buf;
|
||||||
AdapterBitPackingWriter bpw{bw};
|
Writer bw{ buf };
|
||||||
|
AdapterBitPackingWriter bpw{ bw };
|
||||||
|
|
||||||
bpw.writeBits(3u, 2);
|
bpw.writeBits(3u, 2);
|
||||||
//3 calls to align after 1st data
|
// 3 calls to align after 1st data
|
||||||
bpw.align();
|
bpw.align();
|
||||||
bpw.align();
|
bpw.align();
|
||||||
bpw.align();
|
bpw.align();
|
||||||
bpw.writeBits(7u, 3);
|
bpw.writeBits(7u, 3);
|
||||||
//1 call to align after 2nd data
|
// 1 call to align after 2nd data
|
||||||
bpw.align();
|
bpw.align();
|
||||||
bpw.writeBits(15u, 4);
|
bpw.writeBits(15u, 4);
|
||||||
bpw.flush();
|
bpw.flush();
|
||||||
|
|
||||||
unsigned char tmp;
|
unsigned char tmp;
|
||||||
Reader br{buf.begin(), bpw.writtenBytesCount()};
|
Reader br{ buf.begin(), bpw.writtenBytesCount() };
|
||||||
AdapterBitPackingReader bpr{br};
|
AdapterBitPackingReader bpr{ br };
|
||||||
bpr.readBits(tmp,2);
|
bpr.readBits(tmp, 2);
|
||||||
EXPECT_THAT(tmp, Eq(3u));
|
EXPECT_THAT(tmp, Eq(3u));
|
||||||
bpr.align();
|
bpr.align();
|
||||||
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
|
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
|
||||||
bpr.readBits(tmp,3);
|
bpr.readBits(tmp, 3);
|
||||||
bpr.align();
|
bpr.align();
|
||||||
bpr.align();
|
bpr.align();
|
||||||
bpr.align();
|
bpr.align();
|
||||||
EXPECT_THAT(tmp, Eq(7u));
|
EXPECT_THAT(tmp, Eq(7u));
|
||||||
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
|
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
|
||||||
|
|
||||||
bpr.readBits(tmp,4);
|
bpr.readBits(tmp, 4);
|
||||||
EXPECT_THAT(tmp, Eq(15u));
|
EXPECT_THAT(tmp, Eq(15u));
|
||||||
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
|
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DataBitsAndBytesOperations, AlignWritesZerosBits) {
|
TEST(DataBitsAndBytesOperations, AlignWritesZerosBits)
|
||||||
//setup data
|
{
|
||||||
|
// setup data
|
||||||
|
|
||||||
//create and write to buffer
|
// create and write to buffer
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
Writer bw{buf};
|
Writer bw{ buf };
|
||||||
AdapterBitPackingWriter bpw{bw};
|
AdapterBitPackingWriter bpw{ bw };
|
||||||
|
|
||||||
//write 2 bits and align
|
// write 2 bits and align
|
||||||
bpw.writeBits(3u, 2);
|
bpw.writeBits(3u, 2);
|
||||||
bpw.align();
|
bpw.align();
|
||||||
bpw.flush();
|
bpw.flush();
|
||||||
auto writtenSize = bpw.writtenBytesCount();
|
auto writtenSize = bpw.writtenBytesCount();
|
||||||
EXPECT_THAT(writtenSize, Eq(1));
|
EXPECT_THAT(writtenSize, Eq(1));
|
||||||
unsigned char tmp;
|
unsigned char tmp;
|
||||||
Reader br1{buf.begin(), writtenSize};
|
Reader br1{ buf.begin(), writtenSize };
|
||||||
AdapterBitPackingReader bpr1{br1};
|
AdapterBitPackingReader bpr1{ br1 };
|
||||||
bpr1.readBits(tmp,2);
|
bpr1.readBits(tmp, 2);
|
||||||
//read aligned bits
|
// read aligned bits
|
||||||
bpr1.readBits(tmp,6);
|
bpr1.readBits(tmp, 6);
|
||||||
EXPECT_THAT(tmp, Eq(0));
|
EXPECT_THAT(tmp, Eq(0));
|
||||||
|
|
||||||
Reader br2{buf.begin(), writtenSize};
|
Reader br2{ buf.begin(), writtenSize };
|
||||||
AdapterBitPackingReader bpr2{br2};
|
AdapterBitPackingReader bpr2{ br2 };
|
||||||
//read 2 bits
|
// read 2 bits
|
||||||
bpr2.readBits(tmp,2);
|
bpr2.readBits(tmp, 2);
|
||||||
bpr2.align();
|
bpr2.align();
|
||||||
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::NoError));
|
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::NoError));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// *** bytes operations
|
// *** bytes operations
|
||||||
|
|
||||||
struct IntegralTypes {
|
struct IntegralTypes
|
||||||
int64_t a;
|
{
|
||||||
uint32_t b;
|
int64_t a;
|
||||||
int16_t c;
|
uint32_t b;
|
||||||
uint8_t d;
|
int16_t c;
|
||||||
int8_t e;
|
uint8_t d;
|
||||||
int8_t f[2];
|
int8_t e;
|
||||||
|
int8_t f[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(DataBitsAndBytesOperations, WriteAndReadBytes) {
|
TEST(DataBitsAndBytesOperations, WriteAndReadBytes)
|
||||||
//setup data
|
{
|
||||||
IntegralTypes data;
|
// setup data
|
||||||
data.a = -4894541654564;
|
IntegralTypes data;
|
||||||
data.b = 94545646;
|
data.a = -4894541654564;
|
||||||
data.c = -8778;
|
data.b = 94545646;
|
||||||
data.d = 200;
|
data.c = -8778;
|
||||||
data.e = -98;
|
data.d = 200;
|
||||||
data.f[0] = 43;
|
data.e = -98;
|
||||||
data.f[1] = -45;
|
data.f[0] = 43;
|
||||||
|
data.f[1] = -45;
|
||||||
|
|
||||||
//create and write to buffer
|
// create and write to buffer
|
||||||
Buffer buf{};
|
Buffer buf{};
|
||||||
Writer bw{buf};
|
Writer bw{ buf };
|
||||||
bw.writeBytes<4>(data.b);
|
bw.writeBytes<4>(data.b);
|
||||||
bw.writeBytes<2>(data.c);
|
bw.writeBytes<2>(data.c);
|
||||||
bw.writeBytes<1>(data.d);
|
bw.writeBytes<1>(data.d);
|
||||||
bw.writeBytes<8>(data.a);
|
bw.writeBytes<8>(data.a);
|
||||||
bw.writeBytes<1>(data.e);
|
bw.writeBytes<1>(data.e);
|
||||||
bw.writeBuffer<1>(data.f, 2);
|
bw.writeBuffer<1>(data.f, 2);
|
||||||
bw.flush();
|
bw.flush();
|
||||||
auto writtenSize = bw.writtenBytesCount();
|
auto writtenSize = bw.writtenBytesCount();
|
||||||
|
|
||||||
EXPECT_THAT(writtenSize, Eq(18));
|
EXPECT_THAT(writtenSize, Eq(18));
|
||||||
//read from buffer
|
// read from buffer
|
||||||
Reader br{buf.begin(), writtenSize};
|
Reader br{ buf.begin(), writtenSize };
|
||||||
IntegralTypes res{};
|
IntegralTypes res{};
|
||||||
br.readBytes<4>(res.b);
|
br.readBytes<4>(res.b);
|
||||||
br.readBytes<2>(res.c);
|
br.readBytes<2>(res.c);
|
||||||
br.readBytes<1>(res.d);
|
br.readBytes<1>(res.d);
|
||||||
br.readBytes<8>(res.a);
|
br.readBytes<8>(res.a);
|
||||||
br.readBytes<1>(res.e);
|
br.readBytes<1>(res.e);
|
||||||
br.readBuffer<1>(res.f, 2);
|
br.readBuffer<1>(res.f, 2);
|
||||||
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
|
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
|
||||||
//assert results
|
// 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(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) {
|
TEST(DataBitsAndBytesOperations, WriteAndReadBytesWithBitPackingWrapper)
|
||||||
//setup data
|
{
|
||||||
IntegralTypes data;
|
// setup data
|
||||||
data.a = -4894541654564;
|
IntegralTypes data;
|
||||||
data.b = 94545646;
|
data.a = -4894541654564;
|
||||||
data.c = -8778;
|
data.b = 94545646;
|
||||||
data.d = 200;
|
data.c = -8778;
|
||||||
data.e = -98;
|
data.d = 200;
|
||||||
data.f[0] = 43;
|
data.e = -98;
|
||||||
data.f[1] = -45;
|
data.f[0] = 43;
|
||||||
|
data.f[1] = -45;
|
||||||
|
|
||||||
//create and write to buffer
|
// create and write to buffer
|
||||||
Buffer buf{};
|
Buffer buf{};
|
||||||
Writer bw{buf};
|
Writer bw{ buf };
|
||||||
AdapterBitPackingWriter bpw{bw};
|
AdapterBitPackingWriter bpw{ bw };
|
||||||
bpw.writeBytes<4>(data.b);
|
bpw.writeBytes<4>(data.b);
|
||||||
bpw.writeBytes<2>(data.c);
|
bpw.writeBytes<2>(data.c);
|
||||||
bpw.writeBytes<1>(data.d);
|
bpw.writeBytes<1>(data.d);
|
||||||
bpw.writeBytes<8>(data.a);
|
bpw.writeBytes<8>(data.a);
|
||||||
bpw.writeBytes<1>(data.e);
|
bpw.writeBytes<1>(data.e);
|
||||||
bpw.writeBuffer<1>(data.f, 2);
|
bpw.writeBuffer<1>(data.f, 2);
|
||||||
bpw.flush();
|
bpw.flush();
|
||||||
auto writtenSize = bpw.writtenBytesCount();
|
auto writtenSize = bpw.writtenBytesCount();
|
||||||
|
|
||||||
EXPECT_THAT(writtenSize, Eq(18));
|
EXPECT_THAT(writtenSize, Eq(18));
|
||||||
//read from buffer
|
// read from buffer
|
||||||
Reader br{buf.begin(), writtenSize};
|
Reader br{ buf.begin(), writtenSize };
|
||||||
AdapterBitPackingReader bpr{br};
|
AdapterBitPackingReader bpr{ br };
|
||||||
IntegralTypes res{};
|
IntegralTypes res{};
|
||||||
bpr.readBytes<4>(res.b);
|
bpr.readBytes<4>(res.b);
|
||||||
bpr.readBytes<2>(res.c);
|
bpr.readBytes<2>(res.c);
|
||||||
bpr.readBytes<1>(res.d);
|
bpr.readBytes<1>(res.d);
|
||||||
bpr.readBytes<8>(res.a);
|
bpr.readBytes<8>(res.a);
|
||||||
bpr.readBytes<1>(res.e);
|
bpr.readBytes<1>(res.e);
|
||||||
bpr.readBuffer<1>(res.f, 2);
|
bpr.readBuffer<1>(res.f, 2);
|
||||||
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
|
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
|
||||||
//assert results
|
// 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(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) {
|
TEST(DataBitsAndBytesOperations, ReadWriteFncCanAcceptSignedData)
|
||||||
//setup data
|
{
|
||||||
constexpr size_t DATA_SIZE = 3;
|
// setup data
|
||||||
int16_t src[DATA_SIZE] {54,-4877,30067};
|
constexpr size_t DATA_SIZE = 3;
|
||||||
//create and write to buffer
|
int16_t src[DATA_SIZE]{ 54, -4877, 30067 };
|
||||||
Buffer buf{};
|
// create and write to buffer
|
||||||
Writer bw{buf};
|
Buffer buf{};
|
||||||
bw.writeBuffer<2>(src, DATA_SIZE);
|
Writer bw{ buf };
|
||||||
bw.flush();
|
bw.writeBuffer<2>(src, DATA_SIZE);
|
||||||
//read from buffer
|
bw.flush();
|
||||||
Reader br1{buf.begin(), bw.writtenBytesCount()};
|
// read from buffer
|
||||||
int16_t dst[DATA_SIZE]{};
|
Reader br1{ buf.begin(), bw.writtenBytesCount() };
|
||||||
br1.readBuffer<2>(dst, DATA_SIZE);
|
int16_t dst[DATA_SIZE]{};
|
||||||
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::NoError));
|
br1.readBuffer<2>(dst, DATA_SIZE);
|
||||||
EXPECT_THAT(dst, ContainerEq(src));
|
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::NoError));
|
||||||
|
EXPECT_THAT(dst, ContainerEq(src));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DataBitsAndBytesOperations, ReadWriteCanWorkOnUnalignedData) {
|
TEST(DataBitsAndBytesOperations, ReadWriteCanWorkOnUnalignedData)
|
||||||
//setup data
|
{
|
||||||
constexpr size_t DATA_SIZE = 3;
|
// setup data
|
||||||
int16_t src[DATA_SIZE] {54,-4877,30067};
|
constexpr size_t DATA_SIZE = 3;
|
||||||
//create and write to buffer
|
int16_t src[DATA_SIZE]{ 54, -4877, 30067 };
|
||||||
Buffer buf{};
|
// create and write to buffer
|
||||||
Writer bw{buf};
|
Buffer buf{};
|
||||||
AdapterBitPackingWriter bpw{bw};
|
Writer bw{ buf };
|
||||||
bpw.writeBits(15u, 4);
|
AdapterBitPackingWriter bpw{ bw };
|
||||||
bpw.writeBuffer<2>(src, DATA_SIZE);
|
bpw.writeBits(15u, 4);
|
||||||
bpw.writeBits(12u, 4);
|
bpw.writeBuffer<2>(src, DATA_SIZE);
|
||||||
bpw.flush();
|
bpw.writeBits(12u, 4);
|
||||||
auto writtenSize = bpw.writtenBytesCount();
|
bpw.flush();
|
||||||
EXPECT_THAT(writtenSize, Eq(sizeof(src) + 1));
|
auto writtenSize = bpw.writtenBytesCount();
|
||||||
|
EXPECT_THAT(writtenSize, Eq(sizeof(src) + 1));
|
||||||
|
|
||||||
//read from buffer
|
// read from buffer
|
||||||
Reader br1{buf.begin(), writtenSize};
|
Reader br1{ buf.begin(), writtenSize };
|
||||||
AdapterBitPackingReader bpr1{br1};
|
AdapterBitPackingReader bpr1{ br1 };
|
||||||
int16_t dst[DATA_SIZE]{};
|
int16_t dst[DATA_SIZE]{};
|
||||||
uint8_t tmp{};
|
uint8_t tmp{};
|
||||||
bpr1.readBits(tmp, 4);
|
bpr1.readBits(tmp, 4);
|
||||||
EXPECT_THAT(tmp, Eq(15));
|
EXPECT_THAT(tmp, Eq(15));
|
||||||
bpr1.readBuffer<2>(dst, DATA_SIZE);
|
bpr1.readBuffer<2>(dst, DATA_SIZE);
|
||||||
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::NoError));
|
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::NoError));
|
||||||
EXPECT_THAT(dst, ContainerEq(src));
|
EXPECT_THAT(dst, ContainerEq(src));
|
||||||
bpr1.readBits(tmp, 4);
|
bpr1.readBits(tmp, 4);
|
||||||
EXPECT_THAT(tmp, Eq(12));
|
EXPECT_THAT(tmp, Eq(12));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DataBitsAndBytesOperations, RegressionTestReadBytesAfterReadBitsWithLotsOfZeroBits) {
|
TEST(DataBitsAndBytesOperations,
|
||||||
//setup data
|
RegressionTestReadBytesAfterReadBitsWithLotsOfZeroBits)
|
||||||
int16_t data[2]{0x0000, 0x7FFF};
|
{
|
||||||
int16_t res[2]{};
|
// setup data
|
||||||
//create and write to buffer
|
int16_t data[2]{ 0x0000, 0x7FFF };
|
||||||
Buffer buf{};
|
int16_t res[2]{};
|
||||||
Writer bw{buf};
|
// create and write to buffer
|
||||||
AdapterBitPackingWriter bpw{bw};
|
Buffer buf{};
|
||||||
bpw.writeBits(2u, 2);
|
Writer bw{ buf };
|
||||||
bpw.writeBytes<2>(data[0]);
|
AdapterBitPackingWriter bpw{ bw };
|
||||||
bpw.writeBytes<2>(data[1]);
|
bpw.writeBits(2u, 2);
|
||||||
bpw.align();
|
bpw.writeBytes<2>(data[0]);
|
||||||
bpw.flush();
|
bpw.writeBytes<2>(data[1]);
|
||||||
|
bpw.align();
|
||||||
|
bpw.flush();
|
||||||
|
|
||||||
//read from buffer
|
// read from buffer
|
||||||
Reader br{buf.begin(), bpw.writtenBytesCount()};
|
Reader br{ buf.begin(), bpw.writtenBytesCount() };
|
||||||
AdapterBitPackingReader bpr{br};
|
AdapterBitPackingReader bpr{ br };
|
||||||
uint8_t tmp{};
|
uint8_t tmp{};
|
||||||
bpr.readBits(tmp, 2);
|
bpr.readBits(tmp, 2);
|
||||||
EXPECT_THAT(tmp, Eq(2));
|
EXPECT_THAT(tmp, Eq(2));
|
||||||
bpr.readBytes<2>(res[0]);
|
bpr.readBytes<2>(res[0]);
|
||||||
bpr.readBytes<2>(res[1]);
|
bpr.readBytes<2>(res[1]);
|
||||||
bpr.align();
|
bpr.align();
|
||||||
EXPECT_THAT(res[0], Eq(data[0]));
|
EXPECT_THAT(res[0], Eq(data[0]));
|
||||||
EXPECT_THAT(res[1], Eq(data[1]));
|
EXPECT_THAT(res[1], Eq(data[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#include <bitsery/details/serialization_common.h>
|
#include <bitsery/details/serialization_common.h>
|
||||||
#include <bitsery/traits/array.h>
|
#include <bitsery/traits/array.h>
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
|
||||||
#include "serialization_test_utils.h"
|
#include "serialization_test_utils.h"
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
using testing::Eq;
|
|
||||||
using testing::ContainerEq;
|
|
||||||
using bitsery::EndiannessType;
|
using bitsery::EndiannessType;
|
||||||
|
using testing::ContainerEq;
|
||||||
|
using testing::Eq;
|
||||||
|
|
||||||
template <typename BufType>
|
template<typename BufType>
|
||||||
class DataWriting:public testing::Test {
|
class DataWriting : public testing::Test
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
using TWriter = bitsery::OutputBufferAdapter<BufType>;
|
using TWriter = bitsery::OutputBufferAdapter<BufType>;
|
||||||
using TBuffer = BufType;
|
using TBuffer = BufType;
|
||||||
};
|
};
|
||||||
|
|
||||||
using NonFixedContainer = std::vector<uint8_t>;
|
using NonFixedContainer = std::vector<uint8_t>;
|
||||||
using FixedContainer = std::array<uint8_t, 100>;
|
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;
|
static constexpr size_t DATA_SIZE = 14u;
|
||||||
|
|
||||||
template <typename BW>
|
template<typename BW>
|
||||||
void writeData(BW& bw) {
|
void
|
||||||
uint16_t tmp1{45}, tmp2{6543}, tmp3{46533};
|
writeData(BW& bw)
|
||||||
uint32_t tmp4{8979445}, tmp5{7987564};
|
{
|
||||||
bw.template writeBytes<2>(tmp1);
|
uint16_t tmp1{ 45 }, tmp2{ 6543 }, tmp3{ 46533 };
|
||||||
bw.template writeBytes<2>(tmp2);
|
uint32_t tmp4{ 8979445 }, tmp5{ 7987564 };
|
||||||
bw.template writeBytes<2>(tmp3);
|
bw.template writeBytes<2>(tmp1);
|
||||||
bw.template writeBytes<4>(tmp4);
|
bw.template writeBytes<2>(tmp2);
|
||||||
bw.template writeBytes<4>(tmp5);
|
bw.template writeBytes<2>(tmp3);
|
||||||
|
bw.template writeBytes<4>(tmp4);
|
||||||
|
bw.template writeBytes<4>(tmp5);
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(DataWriting, GetWrittenBytesCountReturnsActualBytesWritten) {
|
TYPED_TEST(DataWriting, GetWrittenBytesCountReturnsActualBytesWritten)
|
||||||
using TWriter = typename TestFixture::TWriter;
|
{
|
||||||
using TBuffer = typename TestFixture::TBuffer;
|
using TWriter = typename TestFixture::TWriter;
|
||||||
TBuffer buf{};
|
using TBuffer = typename TestFixture::TBuffer;
|
||||||
TWriter bw{buf};
|
TBuffer buf{};
|
||||||
writeData(bw);
|
TWriter bw{ buf };
|
||||||
bw.flush();
|
writeData(bw);
|
||||||
auto writtenSize = bw.writtenBytesCount();
|
bw.flush();
|
||||||
EXPECT_THAT(writtenSize, DATA_SIZE);
|
auto writtenSize = bw.writtenBytesCount();
|
||||||
EXPECT_THAT(buf.size(), ::testing::Ge(DATA_SIZE));
|
EXPECT_THAT(writtenSize, DATA_SIZE);
|
||||||
|
EXPECT_THAT(buf.size(), ::testing::Ge(DATA_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(DataWriting, WhenWritingBitsThenMustFlushWriter) {
|
TYPED_TEST(DataWriting, WhenWritingBitsThenMustFlushWriter)
|
||||||
using TWriter = typename TestFixture::TWriter;
|
{
|
||||||
using TBuffer = typename TestFixture::TBuffer;
|
using TWriter = typename TestFixture::TWriter;
|
||||||
TBuffer buf{};
|
using TBuffer = typename TestFixture::TBuffer;
|
||||||
TWriter bw{buf};
|
TBuffer buf{};
|
||||||
bitsery::details::OutputAdapterBitPackingWrapper<TWriter> bpw{bw};
|
TWriter bw{ buf };
|
||||||
bpw.writeBits(3u, 2);
|
bitsery::details::OutputAdapterBitPackingWrapper<TWriter> bpw{ bw };
|
||||||
auto writtenSize1 = bpw.writtenBytesCount();
|
bpw.writeBits(3u, 2);
|
||||||
bpw.flush();
|
auto writtenSize1 = bpw.writtenBytesCount();
|
||||||
auto writtenSize2 = bpw.writtenBytesCount();
|
bpw.flush();
|
||||||
EXPECT_THAT(writtenSize1, Eq(0));
|
auto writtenSize2 = bpw.writtenBytesCount();
|
||||||
EXPECT_THAT(writtenSize2, Eq(1));
|
EXPECT_THAT(writtenSize1, Eq(0));
|
||||||
|
EXPECT_THAT(writtenSize2, Eq(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(DataWriting, WhenDataAlignedThenFlushHasNoEffect) {
|
TYPED_TEST(DataWriting, WhenDataAlignedThenFlushHasNoEffect)
|
||||||
using TWriter = typename TestFixture::TWriter;
|
{
|
||||||
using TBuffer = typename TestFixture::TBuffer;
|
using TWriter = typename TestFixture::TWriter;
|
||||||
TBuffer buf{};
|
using TBuffer = typename TestFixture::TBuffer;
|
||||||
TWriter bw{buf};
|
TBuffer buf{};
|
||||||
bitsery::details::OutputAdapterBitPackingWrapper<TWriter> bpw{bw};
|
TWriter bw{ buf };
|
||||||
bpw.writeBits(3u, 2);
|
bitsery::details::OutputAdapterBitPackingWrapper<TWriter> bpw{ bw };
|
||||||
bpw.align();
|
bpw.writeBits(3u, 2);
|
||||||
auto writtenSize1 = bpw.writtenBytesCount();
|
bpw.align();
|
||||||
bpw.flush();
|
auto writtenSize1 = bpw.writtenBytesCount();
|
||||||
auto writtenSize2 = bpw.writtenBytesCount();
|
bpw.flush();
|
||||||
EXPECT_THAT(writtenSize1, Eq(1));
|
auto writtenSize2 = bpw.writtenBytesCount();
|
||||||
EXPECT_THAT(writtenSize2, Eq(1));
|
EXPECT_THAT(writtenSize1, Eq(1));
|
||||||
|
EXPECT_THAT(writtenSize2, Eq(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DataWritingNonFixedBufferContainer, ContainerIsAlwaysResizedToCapacity) {
|
TEST(DataWritingNonFixedBufferContainer, ContainerIsAlwaysResizedToCapacity)
|
||||||
NonFixedContainer buf{};
|
{
|
||||||
bitsery::OutputBufferAdapter<NonFixedContainer> bw{buf};
|
NonFixedContainer buf{};
|
||||||
for (auto i = 0; i < 5; ++i) {
|
bitsery::OutputBufferAdapter<NonFixedContainer> bw{ buf };
|
||||||
uint32_t tmp{};
|
for (auto i = 0; i < 5; ++i) {
|
||||||
bw.writeBytes<4>(tmp);
|
uint32_t tmp{};
|
||||||
bw.writeBytes<4>(tmp);
|
bw.writeBytes<4>(tmp);
|
||||||
EXPECT_TRUE(buf.size() == buf.capacity());
|
bw.writeBytes<4>(tmp);
|
||||||
}
|
EXPECT_TRUE(buf.size() == buf.capacity());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// 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/pointer.h>
|
||||||
|
#include <bitsery/ext/std_map.h>
|
||||||
|
#include <bitsery/ext/std_set.h>
|
||||||
#include <bitsery/ext/std_smart_ptr.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 "serialization_test_utils.h"
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
using testing::ContainerEq;
|
using testing::ContainerEq;
|
||||||
using testing::Eq;
|
using testing::Eq;
|
||||||
|
|
||||||
//forward declare, for testing with std::unordered_map
|
// forward declare, for testing with std::unordered_map
|
||||||
class HasherForNonDefaultConstructible;
|
class HasherForNonDefaultConstructible;
|
||||||
|
|
||||||
class NonDefaultConstructible {
|
class NonDefaultConstructible
|
||||||
int32_t i{0};
|
{
|
||||||
friend class HasherForNonDefaultConstructible;
|
int32_t i{ 0 };
|
||||||
|
friend class HasherForNonDefaultConstructible;
|
||||||
|
|
||||||
|
friend class bitsery::Access;
|
||||||
|
NonDefaultConstructible() = default;
|
||||||
|
|
||||||
|
template<typename S>
|
||||||
|
void serialize(S& s)
|
||||||
friend class bitsery::Access;
|
{
|
||||||
NonDefaultConstructible() = default;
|
s.value4b(i);
|
||||||
|
}
|
||||||
template <typename S>
|
|
||||||
void serialize(S& s) {
|
|
||||||
s.value4b(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
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 {
|
bool operator<(const NonDefaultConstructible& other) const
|
||||||
return i == other.i;
|
{
|
||||||
}
|
return i < other.i;
|
||||||
|
}
|
||||||
bool operator < (const NonDefaultConstructible& other) const {
|
|
||||||
return i < other.i;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class HasherForNonDefaultConstructible {
|
class HasherForNonDefaultConstructible
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
size_t operator()(const NonDefaultConstructible& o) const {
|
size_t operator()(const NonDefaultConstructible& o) const
|
||||||
return std::hash<int32_t>()(o.i);
|
{
|
||||||
}
|
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{};
|
SerializationContext ctx{};
|
||||||
std::vector<NonDefaultConstructible> data{};
|
std::forward_list<NonDefaultConstructible> data{};
|
||||||
data.emplace_back(1);
|
data.push_front(NonDefaultConstructible{ 1 });
|
||||||
data.emplace_back(2);
|
std::forward_list<NonDefaultConstructible> res{};
|
||||||
data.emplace_back(3);
|
res.push_front(NonDefaultConstructible{ 21 });
|
||||||
std::vector<NonDefaultConstructible> res{};
|
res.push_front(NonDefaultConstructible{ 14 });
|
||||||
|
|
||||||
ctx.createSerializer().container(data, 10);
|
ctx.createSerializer().container(data, 10);
|
||||||
ctx.createDeserializer().container(res, 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) {
|
||||||
//this test is here, because when object is not constructible we cannot simple "resize" container
|
EXPECT_THAT(*resIt, Eq(*it));
|
||||||
TEST(DeserializeNonDefaultConstructible, ResultContainerShouldShrink) {
|
}
|
||||||
|
EXPECT_THAT(resIt, Eq(res.end()));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
// 1) when result should have 0 elements
|
||||||
SerializationContext ctx{};
|
SerializationContext ctx{};
|
||||||
std::vector<NonDefaultConstructible> data{};
|
std::forward_list<NonDefaultConstructible> data{};
|
||||||
data.emplace_back(1);
|
std::forward_list<NonDefaultConstructible> res{};
|
||||||
std::vector<NonDefaultConstructible> res{};
|
res.push_front(NonDefaultConstructible{ 1 });
|
||||||
res.emplace_back(2);
|
res.push_front(NonDefaultConstructible{ 14 });
|
||||||
res.emplace_back(3);
|
|
||||||
res.emplace_back(4);
|
|
||||||
|
|
||||||
ctx.createSerializer().container(data, 10);
|
ctx.createSerializer().container(data, 10);
|
||||||
ctx.createDeserializer().container(res, 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
|
// also check if correctly expands if source is bigger than destination
|
||||||
// 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) {
|
|
||||||
SerializationContext ctx{};
|
SerializationContext ctx{};
|
||||||
std::set<NonDefaultConstructible> data;
|
std::forward_list<NonDefaultConstructible> data{};
|
||||||
data.insert(NonDefaultConstructible{1});
|
data.push_front(NonDefaultConstructible{ 1 });
|
||||||
data.insert(NonDefaultConstructible{2});
|
data.push_front(NonDefaultConstructible{ 14 });
|
||||||
std::set<NonDefaultConstructible> res{};
|
std::forward_list<NonDefaultConstructible> res{};
|
||||||
data.insert(NonDefaultConstructible{3});
|
|
||||||
|
|
||||||
ctx.createSerializer().ext(data, bitsery::ext::StdSet{10});
|
ctx.createSerializer().container(data, 10);
|
||||||
ctx.createDeserializer().ext(res, bitsery::ext::StdSet{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) {
|
TEST(DeserializeNonDefaultConstructible, StdSet)
|
||||||
SerializationContext ctx{};
|
{
|
||||||
std::unordered_map<NonDefaultConstructible, NonDefaultConstructible, HasherForNonDefaultConstructible> data;
|
SerializationContext ctx{};
|
||||||
data.emplace(NonDefaultConstructible{2}, NonDefaultConstructible{3});
|
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{};
|
ctx.createSerializer().ext(data, bitsery::ext::StdSet{ 10 });
|
||||||
data.emplace(NonDefaultConstructible{2}, NonDefaultConstructible{3});
|
ctx.createDeserializer().ext(res, bitsery::ext::StdSet{ 10 });
|
||||||
data.emplace(NonDefaultConstructible{4}, NonDefaultConstructible{4});
|
|
||||||
|
|
||||||
auto& ser = ctx.createSerializer();
|
EXPECT_THAT(res, ContainerEq(data));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(DeserializeNonDefaultConstructible, StdMap)
|
||||||
|
{
|
||||||
|
SerializationContext ctx{};
|
||||||
|
std::unordered_map<NonDefaultConstructible,
|
||||||
|
NonDefaultConstructible,
|
||||||
|
HasherForNonDefaultConstructible>
|
||||||
|
data;
|
||||||
|
data.emplace(NonDefaultConstructible{ 2 }, NonDefaultConstructible{ 3 });
|
||||||
|
|
||||||
struct NonPolymorphicPointers {
|
std::unordered_map<NonDefaultConstructible,
|
||||||
NonDefaultConstructible* pp;
|
NonDefaultConstructible,
|
||||||
std::unique_ptr<NonDefaultConstructible> up;
|
HasherForNonDefaultConstructible>
|
||||||
std::shared_ptr<NonDefaultConstructible> sp;
|
res{};
|
||||||
std::weak_ptr<NonDefaultConstructible> wp;
|
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>
|
template<typename S>
|
||||||
void serialize(S& s, NonPolymorphicPointers& o) {
|
void
|
||||||
s.ext(o.pp, bitsery::ext::PointerOwner{});
|
serialize(S& s, NonPolymorphicPointers& o)
|
||||||
s.ext(o.up, bitsery::ext::StdSmartPtr{});
|
{
|
||||||
s.ext(o.sp, bitsery::ext::StdSmartPtr{});
|
s.ext(o.pp, bitsery::ext::PointerOwner{});
|
||||||
s.ext(o.wp, bitsery::ext::StdSmartPtr{});
|
s.ext(o.up, bitsery::ext::StdSmartPtr{});
|
||||||
|
s.ext(o.sp, bitsery::ext::StdSmartPtr{});
|
||||||
|
s.ext(o.wp, bitsery::ext::StdSmartPtr{});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DeserializeNonDefaultConstructible, NonPolymorphicPointerAndSmartPointer) {
|
TEST(DeserializeNonDefaultConstructible, NonPolymorphicPointerAndSmartPointer)
|
||||||
using SerContext = BasicSerializationContext<bitsery::ext::PointerLinkingContext>;
|
{
|
||||||
SerContext ctx{};
|
using SerContext =
|
||||||
NonPolymorphicPointers data{};
|
BasicSerializationContext<bitsery::ext::PointerLinkingContext>;
|
||||||
data.pp = new NonDefaultConstructible{3};
|
SerContext ctx{};
|
||||||
data.up = std::unique_ptr<NonDefaultConstructible>(new NonDefaultConstructible{54});
|
NonPolymorphicPointers data{};
|
||||||
data.sp = std::shared_ptr<NonDefaultConstructible>(new NonDefaultConstructible{-481});
|
data.pp = new NonDefaultConstructible{ 3 };
|
||||||
data.wp = data.sp;
|
data.up =
|
||||||
|
std::unique_ptr<NonDefaultConstructible>(new NonDefaultConstructible{ 54 });
|
||||||
|
data.sp = std::shared_ptr<NonDefaultConstructible>(
|
||||||
|
new NonDefaultConstructible{ -481 });
|
||||||
|
data.wp = data.sp;
|
||||||
|
|
||||||
NonPolymorphicPointers res{};
|
NonPolymorphicPointers res{};
|
||||||
bitsery::ext::PointerLinkingContext plctx1{};
|
bitsery::ext::PointerLinkingContext plctx1{};
|
||||||
ctx.createSerializer(plctx1).object(data);
|
ctx.createSerializer(plctx1).object(data);
|
||||||
ctx.createDeserializer(plctx1).object(res);
|
ctx.createDeserializer(plctx1).object(res);
|
||||||
|
|
||||||
EXPECT_THAT(*res.pp, Eq(*data.pp));
|
EXPECT_THAT(*res.pp, Eq(*data.pp));
|
||||||
delete res.pp;
|
delete res.pp;
|
||||||
delete data.pp;
|
delete data.pp;
|
||||||
EXPECT_THAT(*res.up, Eq(*data.up));
|
EXPECT_THAT(*res.up, Eq(*data.up));
|
||||||
EXPECT_THAT(*res.sp, Eq(*data.sp));
|
EXPECT_THAT(*res.sp, Eq(*data.sp));
|
||||||
EXPECT_THAT(*(res.wp.lock()), Eq(*(data.wp.lock())));
|
EXPECT_THAT(*(res.wp.lock()), Eq(*(data.wp.lock())));
|
||||||
}
|
}
|
||||||
|
|
||||||
class PolymorphicNDCBase {
|
class PolymorphicNDCBase
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~PolymorphicNDCBase() = 0;
|
virtual ~PolymorphicNDCBase() = 0;
|
||||||
template <typename S>
|
template<typename S>
|
||||||
void serialize(S& ) {}
|
void serialize(S&)
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
PolymorphicNDCBase::~PolymorphicNDCBase() = default;
|
PolymorphicNDCBase::~PolymorphicNDCBase() = default;
|
||||||
|
|
||||||
class PolymorphicNDC1:public PolymorphicNDCBase {
|
class PolymorphicNDC1 : public PolymorphicNDCBase
|
||||||
int8_t i{};
|
{
|
||||||
friend class bitsery::Access;
|
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:
|
public:
|
||||||
PolymorphicNDC1() = default;
|
PolymorphicNDC1() = default;
|
||||||
PolymorphicNDC1(int8_t v):i{v} {}
|
PolymorphicNDC1(int8_t v)
|
||||||
bool operator == (const PolymorphicNDC1& other) const {
|
: i{ v }
|
||||||
return i == other.i;
|
{
|
||||||
}
|
}
|
||||||
|
bool operator==(const PolymorphicNDC1& other) const { return i == other.i; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class PolymorphicNDC2:public PolymorphicNDCBase {
|
class PolymorphicNDC2 : public PolymorphicNDCBase
|
||||||
uint16_t ui{};
|
{
|
||||||
|
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:
|
public:
|
||||||
PolymorphicNDC2() = default;
|
PolymorphicNDC2() = default;
|
||||||
PolymorphicNDC2(uint16_t v):ui{v} {}
|
PolymorphicNDC2(uint16_t v)
|
||||||
bool operator == (const PolymorphicNDC2& other) const {
|
: ui{ v }
|
||||||
return ui == other.ui;
|
{
|
||||||
}
|
}
|
||||||
|
bool operator==(const PolymorphicNDC2& other) const { return ui == other.ui; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
namespace bitsery {
|
namespace bitsery {
|
||||||
namespace ext {
|
namespace ext {
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct PolymorphicBaseClass<PolymorphicNDCBase> : PolymorphicDerivedClasses<PolymorphicNDC1, PolymorphicNDC2> {
|
struct PolymorphicBaseClass<PolymorphicNDCBase>
|
||||||
};
|
: PolymorphicDerivedClasses<PolymorphicNDC1, PolymorphicNDC2>
|
||||||
}
|
{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PolymorphicPointers
|
||||||
struct PolymorphicPointers {
|
{
|
||||||
PolymorphicNDCBase* pp;
|
PolymorphicNDCBase* pp;
|
||||||
std::unique_ptr<PolymorphicNDCBase> up;
|
std::unique_ptr<PolymorphicNDCBase> up;
|
||||||
std::shared_ptr<PolymorphicNDCBase> sp;
|
std::shared_ptr<PolymorphicNDCBase> sp;
|
||||||
std::weak_ptr<PolymorphicNDCBase> wp;
|
std::weak_ptr<PolymorphicNDCBase> wp;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename S>
|
template<typename S>
|
||||||
void serialize(S& s, PolymorphicPointers& o) {
|
void
|
||||||
s.ext(o.pp, bitsery::ext::PointerOwner{});
|
serialize(S& s, PolymorphicPointers& o)
|
||||||
s.ext(o.up, bitsery::ext::StdSmartPtr{});
|
{
|
||||||
s.ext(o.sp, bitsery::ext::StdSmartPtr{});
|
s.ext(o.pp, bitsery::ext::PointerOwner{});
|
||||||
s.ext(o.wp, bitsery::ext::StdSmartPtr{});
|
s.ext(o.up, bitsery::ext::StdSmartPtr{});
|
||||||
|
s.ext(o.sp, bitsery::ext::StdSmartPtr{});
|
||||||
|
s.ext(o.wp, bitsery::ext::StdSmartPtr{});
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(DeserializeNonDefaultConstructible, PolymorphicPointerAndSmartPointer) {
|
TEST(DeserializeNonDefaultConstructible, PolymorphicPointerAndSmartPointer)
|
||||||
using TContext = std::tuple<bitsery::ext::PointerLinkingContext, bitsery::ext::PolymorphicContext<bitsery::ext::StandardRTTI>>;
|
{
|
||||||
using SerContext = BasicSerializationContext<TContext>;
|
using TContext =
|
||||||
SerContext ctx{};
|
std::tuple<bitsery::ext::PointerLinkingContext,
|
||||||
PolymorphicPointers data{};
|
bitsery::ext::PolymorphicContext<bitsery::ext::StandardRTTI>>;
|
||||||
data.pp = new PolymorphicNDC1{-4};
|
using SerContext = BasicSerializationContext<TContext>;
|
||||||
data.up = std::unique_ptr<PolymorphicNDCBase>(new PolymorphicNDC2{54});
|
SerContext ctx{};
|
||||||
data.sp = std::shared_ptr<PolymorphicNDCBase>(new PolymorphicNDC1{15});
|
PolymorphicPointers data{};
|
||||||
data.wp = data.sp;
|
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 serCtx{};
|
||||||
TContext desCtx{};
|
TContext desCtx{};
|
||||||
|
|
||||||
std::get<1>(serCtx).registerBasesList<typename SerContext::TSerializer>(bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
|
std::get<1>(serCtx).registerBasesList<typename SerContext::TSerializer>(
|
||||||
std::get<1>(desCtx).registerBasesList<typename SerContext::TDeserializer>(bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
|
bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
|
||||||
|
std::get<1>(desCtx).registerBasesList<typename SerContext::TDeserializer>(
|
||||||
|
bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
|
||||||
|
|
||||||
ctx.createSerializer(serCtx).object(data);
|
ctx.createSerializer(serCtx).object(data);
|
||||||
ctx.createDeserializer(desCtx).object(res);
|
ctx.createDeserializer(desCtx).object(res);
|
||||||
auto respp = dynamic_cast<PolymorphicNDC1*>(res.pp);
|
auto respp = dynamic_cast<PolymorphicNDC1*>(res.pp);
|
||||||
auto resup = dynamic_cast<PolymorphicNDC2*>(res.up.get());
|
auto resup = dynamic_cast<PolymorphicNDC2*>(res.up.get());
|
||||||
auto ressp = dynamic_cast<PolymorphicNDC1*>(res.sp.get());
|
auto ressp = dynamic_cast<PolymorphicNDC1*>(res.sp.get());
|
||||||
auto reswp = dynamic_cast<PolymorphicNDC1*>(res.wp.lock().get());
|
auto reswp = dynamic_cast<PolymorphicNDC1*>(res.wp.lock().get());
|
||||||
|
|
||||||
auto datapp = dynamic_cast<PolymorphicNDC1*>(data.pp);
|
auto datapp = dynamic_cast<PolymorphicNDC1*>(data.pp);
|
||||||
auto dataup = dynamic_cast<PolymorphicNDC2*>(data.up.get());
|
auto dataup = dynamic_cast<PolymorphicNDC2*>(data.up.get());
|
||||||
auto datasp = dynamic_cast<PolymorphicNDC1*>(data.sp.get());
|
auto datasp = dynamic_cast<PolymorphicNDC1*>(data.sp.get());
|
||||||
auto datawp = dynamic_cast<PolymorphicNDC1*>(data.wp.lock().get());
|
auto datawp = dynamic_cast<PolymorphicNDC1*>(data.wp.lock().get());
|
||||||
|
|
||||||
EXPECT_THAT(respp, ::testing::Ne(nullptr));
|
EXPECT_THAT(respp, ::testing::Ne(nullptr));
|
||||||
EXPECT_THAT(resup, ::testing::Ne(nullptr));
|
EXPECT_THAT(resup, ::testing::Ne(nullptr));
|
||||||
EXPECT_THAT(ressp, ::testing::Ne(nullptr));
|
EXPECT_THAT(ressp, ::testing::Ne(nullptr));
|
||||||
EXPECT_THAT(reswp, ::testing::Ne(nullptr));
|
EXPECT_THAT(reswp, ::testing::Ne(nullptr));
|
||||||
|
|
||||||
EXPECT_THAT(*respp, Eq(*datapp));
|
EXPECT_THAT(*respp, Eq(*datapp));
|
||||||
delete res.pp;
|
delete res.pp;
|
||||||
delete data.pp;
|
delete data.pp;
|
||||||
EXPECT_THAT(*resup, Eq(*dataup));
|
EXPECT_THAT(*resup, Eq(*dataup));
|
||||||
EXPECT_THAT(*ressp, Eq(*datasp));
|
EXPECT_THAT(*ressp, Eq(*datasp));
|
||||||
EXPECT_THAT(*reswp, Eq(*datawp));
|
EXPECT_THAT(*reswp, Eq(*datawp));
|
||||||
std::get<0>(serCtx).clearSharedState();
|
std::get<0>(serCtx).clearSharedState();
|
||||||
std::get<0>(desCtx).clearSharedState();
|
std::get<0>(desCtx).clearSharedState();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
|
||||||
#include "serialization_test_utils.h"
|
#include "serialization_test_utils.h"
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
using testing::Eq;
|
using testing::Eq;
|
||||||
|
|
||||||
TEST(Serialization, AdapterCanBeMovedInAndOut) {
|
TEST(Serialization, AdapterCanBeMovedInAndOut)
|
||||||
Buffer buf{};
|
{
|
||||||
bitsery::Serializer<Writer> ser1{buf};
|
Buffer buf{};
|
||||||
ser1.object(MyStruct1{1, 2});
|
bitsery::Serializer<Writer> ser1{ buf };
|
||||||
auto writeAdapter = std::move(ser1).adapter();
|
ser1.object(MyStruct1{ 1, 2 });
|
||||||
bitsery::Serializer<Writer> ser2(std::move(writeAdapter));
|
auto writeAdapter = std::move(ser1).adapter();
|
||||||
ser2.object(MyStruct1{3, 4});
|
bitsery::Serializer<Writer> ser2(std::move(writeAdapter));
|
||||||
auto writtenBytesCount = ser2.adapter().writtenBytesCount();
|
ser2.object(MyStruct1{ 3, 4 });
|
||||||
EXPECT_THAT(writtenBytesCount, Eq(MyStruct1::SIZE + MyStruct1::SIZE));
|
auto writtenBytesCount = ser2.adapter().writtenBytesCount();
|
||||||
|
EXPECT_THAT(writtenBytesCount, Eq(MyStruct1::SIZE + MyStruct1::SIZE));
|
||||||
|
|
||||||
MyStruct1 res{};
|
MyStruct1 res{};
|
||||||
bitsery::Deserializer<Reader> des1{buf.begin(), writtenBytesCount};
|
bitsery::Deserializer<Reader> des1{ buf.begin(), writtenBytesCount };
|
||||||
des1.object(res);
|
des1.object(res);
|
||||||
EXPECT_THAT(res, Eq(MyStruct1{1, 2}));
|
EXPECT_THAT(res, Eq(MyStruct1{ 1, 2 }));
|
||||||
auto readerAdapter = std::move(des1).adapter();
|
auto readerAdapter = std::move(des1).adapter();
|
||||||
bitsery::Deserializer<Reader> des2(std::move(readerAdapter));
|
bitsery::Deserializer<Reader> des2(std::move(readerAdapter));
|
||||||
des2.object(res);
|
des2.object(res);
|
||||||
EXPECT_THAT(res, Eq(MyStruct1{3, 4}));
|
EXPECT_THAT(res, Eq(MyStruct1{ 3, 4 }));
|
||||||
EXPECT_TRUE(des2.adapter().isCompletedSuccessfully());
|
EXPECT_TRUE(des2.adapter().isCompletedSuccessfully());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
|
||||||
#include "serialization_test_utils.h"
|
#include "serialization_test_utils.h"
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
using testing::Eq;
|
using testing::Eq;
|
||||||
|
|
||||||
|
TEST(SerializeBooleans, BoolAsBit)
|
||||||
|
{
|
||||||
|
|
||||||
TEST(SerializeBooleans, BoolAsBit) {
|
SerializationContext ctx{};
|
||||||
|
bool t1{ true };
|
||||||
SerializationContext ctx{};
|
bool t2{ false };
|
||||||
bool t1{true};
|
bool res1;
|
||||||
bool t2{false};
|
bool res2;
|
||||||
bool res1;
|
auto& ser = ctx.createSerializer();
|
||||||
bool res2;
|
ser.enableBitPacking(
|
||||||
auto& ser = ctx.createSerializer();
|
[&t1, &t2](SerializationContext::TSerializerBPEnabled& sbp) {
|
||||||
ser.enableBitPacking([&t1, &t2](SerializationContext::TSerializerBPEnabled& sbp) {
|
sbp.boolValue(t1);
|
||||||
sbp.boolValue(t1);
|
sbp.boolValue(t2);
|
||||||
sbp.boolValue(t2);
|
|
||||||
});
|
});
|
||||||
auto& des = ctx.createDeserializer();
|
auto& des = ctx.createDeserializer();
|
||||||
des.enableBitPacking([&res1, &res2](SerializationContext::TDeserializerBPEnabled& sbp) {
|
des.enableBitPacking(
|
||||||
sbp.boolValue(res1);
|
[&res1, &res2](SerializationContext::TDeserializerBPEnabled& sbp) {
|
||||||
sbp.boolValue(res2);
|
sbp.boolValue(res1);
|
||||||
|
sbp.boolValue(res2);
|
||||||
});
|
});
|
||||||
|
|
||||||
EXPECT_THAT(res1, Eq(t1));
|
EXPECT_THAT(res1, Eq(t1));
|
||||||
EXPECT_THAT(res2, Eq(t2));
|
EXPECT_THAT(res2, Eq(t2));
|
||||||
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
|
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SerializeBooleans, BoolAsByte) {
|
TEST(SerializeBooleans, BoolAsByte)
|
||||||
SerializationContext ctx;
|
{
|
||||||
bool t1{true};
|
SerializationContext ctx;
|
||||||
bool t2{false};
|
bool t1{ true };
|
||||||
bool res1;
|
bool t2{ false };
|
||||||
bool res2;
|
bool res1;
|
||||||
auto& ser = ctx.createSerializer();
|
bool res2;
|
||||||
ser.boolValue(t1);
|
auto& ser = ctx.createSerializer();
|
||||||
ser.boolValue(t2);
|
ser.boolValue(t1);
|
||||||
auto& des = ctx.createDeserializer();
|
ser.boolValue(t2);
|
||||||
des.boolValue(res1);
|
auto& des = ctx.createDeserializer();
|
||||||
des.boolValue(res2);
|
des.boolValue(res1);
|
||||||
|
des.boolValue(res2);
|
||||||
|
|
||||||
EXPECT_THAT(res1, Eq(t1));
|
EXPECT_THAT(res1, Eq(t1));
|
||||||
EXPECT_THAT(res2, Eq(t2));
|
EXPECT_THAT(res2, Eq(t2));
|
||||||
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
|
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SerializeBooleans, WhenReadingBoolByteReadsMoreThanOneThenInvalidDataErrorAndResultIsFalse) {
|
TEST(SerializeBooleans,
|
||||||
SerializationContext ctx;
|
WhenReadingBoolByteReadsMoreThanOneThenInvalidDataErrorAndResultIsFalse)
|
||||||
auto& ser = ctx.createSerializer();
|
{
|
||||||
ser.value1b(uint8_t{1});
|
SerializationContext ctx;
|
||||||
ser.value1b(uint8_t{2});
|
auto& ser = ctx.createSerializer();
|
||||||
bool res{};
|
ser.value1b(uint8_t{ 1 });
|
||||||
auto& des = ctx.createDeserializer();
|
ser.value1b(uint8_t{ 2 });
|
||||||
des.boolValue(res);
|
bool res{};
|
||||||
EXPECT_THAT(res, Eq(true));
|
auto& des = ctx.createDeserializer();
|
||||||
des.boolValue(res);
|
des.boolValue(res);
|
||||||
EXPECT_THAT(res, Eq(false));
|
EXPECT_THAT(res, Eq(true));
|
||||||
EXPECT_THAT(ctx.des->adapter().error(), Eq(bitsery::ReaderError::InvalidData));
|
des.boolValue(res);
|
||||||
|
EXPECT_THAT(res, Eq(false));
|
||||||
|
EXPECT_THAT(ctx.des->adapter().error(),
|
||||||
|
Eq(bitsery::ReaderError::InvalidData));
|
||||||
}
|
}
|
||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <bitsery/traits/array.h>
|
#include <bitsery/traits/array.h>
|
||||||
#include <bitsery/traits/list.h>
|
|
||||||
#include <bitsery/traits/deque.h>
|
#include <bitsery/traits/deque.h>
|
||||||
#include <bitsery/traits/forward_list.h>
|
#include <bitsery/traits/forward_list.h>
|
||||||
|
#include <bitsery/traits/list.h>
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
|
||||||
#include "serialization_test_utils.h"
|
#include "serialization_test_utils.h"
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
using testing::ContainerEq;
|
using testing::ContainerEq;
|
||||||
using testing::Eq;
|
using testing::Eq;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* overload to get container of types
|
* overload to get container of types
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename Container>
|
template<typename Container>
|
||||||
Container getFilledContainer() {
|
Container
|
||||||
return {1, 2, 3, 4, 5, 78, 456, 8, 54};
|
getFilledContainer()
|
||||||
|
{
|
||||||
|
return { 1, 2, 3, 4, 5, 78, 456, 8, 54 };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
std::vector<MyStruct1> getFilledContainer<std::vector<MyStruct1>>() {
|
std::vector<MyStruct1>
|
||||||
return {
|
getFilledContainer<std::vector<MyStruct1>>()
|
||||||
{0, 1},
|
{
|
||||||
{2, 3},
|
return { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
|
||||||
{4, 5},
|
{ 8, 9 }, { 11, 34 }, { 5134, 1532 } };
|
||||||
{6, 7},
|
|
||||||
{8, 9},
|
|
||||||
{11, 34},
|
|
||||||
{5134, 1532}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
std::list<MyStruct2> getFilledContainer<std::list<MyStruct2>>() {
|
std::list<MyStruct2>
|
||||||
return {
|
getFilledContainer<std::list<MyStruct2>>()
|
||||||
{MyStruct2::V1, {0, 1}},
|
{
|
||||||
{MyStruct2::V3, {-45, 45}}
|
return { { MyStruct2::V1, { 0, 1 } }, { MyStruct2::V3, { -45, 45 } } };
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EmptyFtor {
|
struct EmptyFtor
|
||||||
template <typename S, typename T>
|
{
|
||||||
void operator() (S& , T& ) {
|
template<typename S, typename T>
|
||||||
|
void operator()(S&, T&)
|
||||||
}
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -76,197 +70,227 @@ struct EmptyFtor {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class SerializeContainerDynamicSizeArthmeticTypes : public testing::Test {
|
class SerializeContainerDynamicSizeArthmeticTypes : public testing::Test
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
using TContainer = T;
|
using TContainer = T;
|
||||||
using TValue = typename T::value_type;
|
using TValue = typename T::value_type;
|
||||||
|
|
||||||
const TContainer src = getFilledContainer<TContainer>();
|
const TContainer src = getFilledContainer<TContainer>();
|
||||||
TContainer res{};
|
TContainer res{};
|
||||||
|
|
||||||
size_t getExpectedBufSize(const SerializationContext &ctx) const {
|
size_t getExpectedBufSize(const SerializationContext& ctx) const
|
||||||
auto size = bitsery::traits::ContainerTraits<TContainer>::size(src);
|
{
|
||||||
return ctx.containerSizeSerializedBytesCount(size) + size * sizeof(TValue);
|
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
|
// std::forward_list is not supported, because it doesn't have size() method
|
||||||
using SequenceContainersWithArthmeticTypes = ::testing::Types<
|
using SequenceContainersWithArthmeticTypes =
|
||||||
std::vector<int>,
|
::testing::Types<std::vector<int>,
|
||||||
std::list<float>,
|
std::list<float>,
|
||||||
std::forward_list<int>,
|
std::forward_list<int>,
|
||||||
std::deque<unsigned short>>;
|
std::deque<unsigned short>>;
|
||||||
|
|
||||||
TYPED_TEST_SUITE(SerializeContainerDynamicSizeArthmeticTypes, SequenceContainersWithArthmeticTypes,);
|
TYPED_TEST_SUITE(SerializeContainerDynamicSizeArthmeticTypes,
|
||||||
|
SequenceContainersWithArthmeticTypes, );
|
||||||
|
|
||||||
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, Values) {
|
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, Values)
|
||||||
SerializationContext ctx{};
|
{
|
||||||
using TValue = typename TestFixture::TValue;
|
SerializationContext ctx{};
|
||||||
|
using TValue = typename TestFixture::TValue;
|
||||||
|
|
||||||
ctx.createSerializer().container<sizeof(TValue)>(this->src, 1000);
|
ctx.createSerializer().container<sizeof(TValue)>(this->src, 1000);
|
||||||
ctx.createDeserializer().container<sizeof(TValue)>(this->res, 1000);
|
ctx.createDeserializer().container<sizeof(TValue)>(this->res, 1000);
|
||||||
|
|
||||||
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
|
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
|
||||||
EXPECT_THAT(this->res, ContainerEq(this->src));
|
EXPECT_THAT(this->res, ContainerEq(this->src));
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, CustomFunctionIncrements) {
|
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes,
|
||||||
SerializationContext ctx{};
|
CustomFunctionIncrements)
|
||||||
using TValue = typename TestFixture::TValue;
|
{
|
||||||
|
SerializationContext ctx{};
|
||||||
|
using TValue = typename TestFixture::TValue;
|
||||||
|
|
||||||
auto& ser = ctx.createSerializer();
|
auto& ser = ctx.createSerializer();
|
||||||
ser.container(this->src, 1000, [](decltype(ser)& ser, TValue& v) {
|
ser.container(this->src, 1000, [](decltype(ser)& ser, TValue& v) {
|
||||||
ser.template value<sizeof(v)>(v);
|
ser.template value<sizeof(v)>(v);
|
||||||
});
|
});
|
||||||
auto& des = ctx.createDeserializer();
|
auto& des = ctx.createDeserializer();
|
||||||
des.container(this->res, 1000, [](decltype(des)& des, TValue &v) {
|
des.container(this->res, 1000, [](decltype(des)& des, TValue& v) {
|
||||||
des.template value<sizeof(v)>(v);
|
des.template value<sizeof(v)>(v);
|
||||||
//increment by 1 after reading
|
// increment by 1 after reading
|
||||||
v++;
|
v++;
|
||||||
});
|
});
|
||||||
//decrement result by 1, before comparing for eq
|
// decrement result by 1, before comparing for eq
|
||||||
for (auto &v:this->res)
|
for (auto& v : this->res)
|
||||||
v = static_cast<TValue>(v-1);
|
v = static_cast<TValue>(v - 1);
|
||||||
|
|
||||||
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
|
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
|
||||||
EXPECT_THAT(this->res, ContainerEq(this->src));
|
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())));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class SerializeContainerFixedSizeArithmeticTypes : public testing::Test {
|
class SerializeContainerDynamicSizeCompositeTypes : public testing::Test
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
using TContainer = T;
|
using TContainer = T;
|
||||||
|
using TValue = typename T::value_type;
|
||||||
|
|
||||||
size_t getContainerSize() {
|
const TContainer src = getFilledContainer<TContainer>();
|
||||||
T tmp{};
|
TContainer res{};
|
||||||
return static_cast<size_t>(std::distance(std::begin(tmp), std::end(tmp)));
|
|
||||||
}
|
size_t getExpectedBufSize(const SerializationContext& ctx) const
|
||||||
|
{
|
||||||
|
return ctx.containerSizeSerializedBytesCount(src.size()) +
|
||||||
|
src.size() * TValue::SIZE;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using StaticContainersWithIntegralTypes = ::testing::Types<
|
using SerializeContainerDynamicSizeWithCompositeTypes =
|
||||||
std::array<int16_t, 4>,
|
::testing::Types<std::vector<MyStruct1>, std::list<MyStruct2>>;
|
||||||
int16_t[4]>;
|
|
||||||
|
|
||||||
TYPED_TEST_SUITE(SerializeContainerFixedSizeArithmeticTypes, StaticContainersWithIntegralTypes,);
|
TYPED_TEST_SUITE(SerializeContainerDynamicSizeCompositeTypes,
|
||||||
|
SerializeContainerDynamicSizeWithCompositeTypes, );
|
||||||
|
|
||||||
TYPED_TEST(SerializeContainerFixedSizeArithmeticTypes, ArithmeticValues) {
|
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes,
|
||||||
using Container = typename TestFixture::TContainer;
|
DefaultSerializeFunction)
|
||||||
Container src{5, 9, 15, -459};
|
{
|
||||||
Container res{};
|
SerializationContext ctx{};
|
||||||
|
|
||||||
SerializationContext ctx;
|
ctx.createSerializer().container(this->src, 1000);
|
||||||
ctx.createSerializer().container<2>(src);
|
ctx.createDeserializer().container(this->res, 1000);
|
||||||
ctx.createDeserializer().container<2>(res);
|
|
||||||
|
|
||||||
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * 2));
|
|
||||||
EXPECT_THAT(res, ContainerEq(src));
|
|
||||||
|
|
||||||
|
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>
|
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<
|
using StaticContainersWithIntegralTypes =
|
||||||
std::array<MyStruct1, 4>, MyStruct1[4]>;
|
::testing::Types<std::array<int16_t, 4>, int16_t[4]>;
|
||||||
|
|
||||||
TYPED_TEST_SUITE(SerializeContainerFixedSizeCompositeTypes, StaticContainersWithCompositeTypes,);
|
TYPED_TEST_SUITE(SerializeContainerFixedSizeArithmeticTypes,
|
||||||
|
StaticContainersWithIntegralTypes, );
|
||||||
|
|
||||||
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, DefaultSerializationFunction) {
|
TYPED_TEST(SerializeContainerFixedSizeArithmeticTypes, ArithmeticValues)
|
||||||
using Container = typename TestFixture::TContainer;
|
{
|
||||||
Container src{MyStruct1{0, 1}, MyStruct1{8, 9}, MyStruct1{11, 34}, MyStruct1{5134, 1532}};
|
using Container = typename TestFixture::TContainer;
|
||||||
Container res{};
|
Container src{ 5, 9, 15, -459 };
|
||||||
|
Container res{};
|
||||||
|
|
||||||
SerializationContext ctx{};
|
SerializationContext ctx;
|
||||||
ctx.createSerializer().container(src);
|
ctx.createSerializer().container<2>(src);
|
||||||
ctx.createDeserializer().container(res);
|
ctx.createDeserializer().container<2>(res);
|
||||||
|
|
||||||
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * MyStruct1::SIZE));
|
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * 2));
|
||||||
EXPECT_THAT(res, ContainerEq(src));
|
EXPECT_THAT(res, ContainerEq(src));
|
||||||
}
|
}
|
||||||
|
|
||||||
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, CustomFunctionThatSerializesAnEmptyByteEveryElement) {
|
template<typename T>
|
||||||
using Container = typename TestFixture::TContainer;
|
class SerializeContainerFixedSizeCompositeTypes
|
||||||
Container src{MyStruct1{0, 1}, MyStruct1{2, 3}, MyStruct1{4, 5}, MyStruct1{5134, 1532}};
|
: public SerializeContainerFixedSizeArithmeticTypes<T>
|
||||||
Container res{};
|
{};
|
||||||
|
|
||||||
using TValue = decltype(*std::begin(res));
|
using StaticContainersWithCompositeTypes =
|
||||||
|
::testing::Types<std::array<MyStruct1, 4>, MyStruct1[4]>;
|
||||||
|
|
||||||
SerializationContext ctx{};
|
TYPED_TEST_SUITE(SerializeContainerFixedSizeCompositeTypes,
|
||||||
auto& ser = ctx.createSerializer();
|
StaticContainersWithCompositeTypes, );
|
||||||
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(ctx.getBufferSize(), Eq(this->getContainerSize() * (MyStruct1::SIZE + sizeof(char))));
|
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes,
|
||||||
EXPECT_THAT(res, ContainerEq(src));
|
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) {
|
using TValue = decltype(*std::begin(res));
|
||||||
SerializationContext ctx{};
|
|
||||||
|
|
||||||
std::vector<uint8_t > src(GetParam());
|
SerializationContext ctx{};
|
||||||
std::vector<uint8_t > res{};
|
auto& ser = ctx.createSerializer();
|
||||||
ctx.createSerializer().container(src, std::numeric_limits<size_t>::max(), EmptyFtor{});
|
ser.container(src, [](decltype(ser)& ser, TValue& v) {
|
||||||
ctx.createDeserializer().container(res, std::numeric_limits<size_t>::max(), EmptyFtor{});
|
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(),
|
||||||
EXPECT_THAT(ctx.getBufferSize(), Eq(ctx.containerSizeSerializedBytesCount(src.size())));
|
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));
|
||||||
|
|||||||
@@ -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
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
//of this software and associated documentation files (the "Software"), to deal
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
//in the Software without restriction, including without limitation the rights
|
// in the Software without restriction, including without limitation the rights
|
||||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
//copies of the Software, and to permit persons to whom the Software is
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
//furnished to do so, subject to the following conditions:
|
// furnished to do so, subject to the following conditions:
|
||||||
//
|
//
|
||||||
//The above copyright notice and this permission notice shall be included in all
|
// The above copyright notice and this permission notice shall be included in
|
||||||
//copies or substantial portions of the Software.
|
// all copies or substantial portions of the Software.
|
||||||
//
|
//
|
||||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
// 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
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
//SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
|
||||||
#include "serialization_test_utils.h"
|
#include "serialization_test_utils.h"
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
using testing::Eq;
|
using testing::Eq;
|
||||||
|
|
||||||
@@ -31,78 +30,89 @@ using bitsery::DefaultConfig;
|
|||||||
using SingleTypeContext = int;
|
using SingleTypeContext = int;
|
||||||
using MultipleTypesContext = std::tuple<int, float, char>;
|
using MultipleTypesContext = std::tuple<int, float, char>;
|
||||||
|
|
||||||
TEST(SerializationContext, WhenContextIsNotTupleThenReturnThisContext) {
|
TEST(SerializationContext, WhenContextIsNotTupleThenReturnThisContext)
|
||||||
SingleTypeContext ctx{54};
|
{
|
||||||
BasicSerializationContext<SingleTypeContext> c1;
|
SingleTypeContext ctx{ 54 };
|
||||||
auto& ser1 = c1.createSerializer(ctx);
|
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'};
|
MultipleTypesContext ctx{ 5, 798.654f, 'F' };
|
||||||
BasicSerializationContext<MultipleTypesContext> c1;
|
BasicSerializationContext<MultipleTypesContext> c1;
|
||||||
auto& ser1 = c1.createSerializer(ctx);
|
auto& ser1 = c1.createSerializer(ctx);
|
||||||
|
|
||||||
EXPECT_THAT(ser1.context<int>(), std::get<0>(ctx));
|
EXPECT_THAT(ser1.context<int>(), std::get<0>(ctx));
|
||||||
EXPECT_THAT(ser1.context<float>(), std::get<1>(ctx));
|
EXPECT_THAT(ser1.context<float>(), std::get<1>(ctx));
|
||||||
EXPECT_THAT(ser1.context<char>(), std::get<2>(ctx));
|
EXPECT_THAT(ser1.context<char>(), std::get<2>(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(SerializationContext, WhenContextDoesntExistsThenContextOrNullReturnsNull) {
|
TEST(SerializationContext, WhenContextDoesntExistsThenContextOrNullReturnsNull)
|
||||||
SingleTypeContext ctx1= 32;
|
{
|
||||||
BasicSerializationContext<SingleTypeContext> c1;
|
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);
|
auto& ser = c1.createSerializer(ctx1);
|
||||||
EXPECT_THAT(ser.contextOrNull<char>(), ::testing::IsNull());
|
EXPECT_THAT(ser.context<Derived>().value, Eq(std::get<2>(ctx1).value));
|
||||||
EXPECT_THAT(ser.contextOrNull<int>(), ::testing::NotNull());
|
EXPECT_THAT(ser.context<Base>().value, Eq(std::get<0>(ctx1).value));
|
||||||
*ser.contextOrNull<int>() = 2;
|
}
|
||||||
EXPECT_THAT(ctx1, Eq(2));
|
|
||||||
|
|
||||||
MultipleTypesContext ctx2{5, 798.654f, 'F'};
|
{
|
||||||
BasicSerializationContext<MultipleTypesContext> c2;
|
using CTX2 = std::tuple<float, Derived, Base>;
|
||||||
auto& des = c2.createDeserializer(ctx2);
|
CTX2 ctx2{};
|
||||||
EXPECT_THAT(des.contextOrNull<double>(), ::testing::IsNull());
|
std::get<1>(ctx2).value = 1;
|
||||||
EXPECT_THAT(des.contextOrNull<int>(), ::testing::NotNull());
|
std::get<2>(ctx2).value = 2;
|
||||||
EXPECT_THAT(*des.contextOrNull<char>(), Eq('F'));
|
BasicSerializationContext<CTX2> c2;
|
||||||
EXPECT_THAT(*des.contextOrNull<int>(), Eq(5));
|
auto& des = c2.createSerializer(ctx2);
|
||||||
}
|
|
||||||
|
EXPECT_THAT(des.context<Derived>().value, Eq(std::get<1>(ctx2).value));
|
||||||
struct Base { int value{}; };
|
// Base will not be accessable in this case, because Derived is first valid
|
||||||
struct Derived: Base{};
|
// match
|
||||||
|
EXPECT_THAT(des.context<Base>().value, Eq(std::get<1>(ctx2).value));
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user