mirror of
https://github.com/fraillt/bitsery.git
synced 2026-06-25 08:39:08 +00:00
Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9bebfd4911 | ||
|
|
5e7ecede9b | ||
|
|
ff841d63f6 | ||
|
|
66d16516e2 | ||
|
|
7ea1da0d48 | ||
|
|
8bda82576e | ||
|
|
ee992d8b57 | ||
|
|
4dcdd594da | ||
|
|
b714459a2b | ||
|
|
be2f295310 | ||
|
|
cd73aca2f5 | ||
|
|
94f7adaf6c | ||
|
|
ceeb189c8b | ||
|
|
90243480ec | ||
|
|
d1a47e06e2 | ||
|
|
3e02d0ca44 | ||
|
|
d690908541 | ||
|
|
d3dd64baaf | ||
|
|
d24e0ab1b3 | ||
|
|
c0fc083c9d | ||
|
|
bcd03b4d68 | ||
|
|
4ff80c6426 | ||
|
|
126a6c2971 | ||
|
|
d1830a263b | ||
|
|
47f6f9248a | ||
|
|
9688cb03d2 | ||
|
|
db884a0656 | ||
|
|
8a00183c80 | ||
|
|
8a5e12a125 | ||
|
|
ee7bb2cb93 | ||
|
|
d787680819 | ||
|
|
a519d333e2 | ||
|
|
826b8d4269 | ||
|
|
16f637da0d | ||
|
|
9cade41dbb | ||
|
|
3dc5940c16 | ||
|
|
a544879b22 | ||
|
|
d47ee834e4 | ||
|
|
c556c75100 | ||
|
|
541632fa9e |
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"
|
||||||
46
.github/workflows/on_linux.yml
vendored
Normal file
46
.github/workflows/on_linux.yml
vendored
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
name: On Linux
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ develop, master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ develop, master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: ${{ matrix.config.name }}
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
config:
|
||||||
|
- name: "Ubuntu Latest with GCC 14"
|
||||||
|
compiler: gcc
|
||||||
|
compiler_ver: 14
|
||||||
|
- name: "Ubuntu Latests with Clang 18"
|
||||||
|
compiler: clang
|
||||||
|
compiler_ver: 18
|
||||||
|
steps:
|
||||||
|
- name: Prepare specific Clang version
|
||||||
|
if: ${{ matrix.config.compiler == 'clang' }}
|
||||||
|
run: |
|
||||||
|
sudo apt install clang-${{ matrix.config.compiler_ver}}
|
||||||
|
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++-${{ matrix.config.compiler_ver}} 100
|
||||||
|
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang-${{ matrix.config.compiler_ver}} 100
|
||||||
|
- name: Prepare specific GCC version
|
||||||
|
if: ${{ matrix.config.compiler == 'gcc' }}
|
||||||
|
run: |
|
||||||
|
sudo apt install g++-${{ matrix.config.compiler_ver}}
|
||||||
|
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++-${{ matrix.config.compiler_ver}} 100
|
||||||
|
sudo update-alternatives --install /usr/bin/cc cc /usr/bin/gcc-${{ matrix.config.compiler_ver}} 100
|
||||||
|
- name: Installing GTest
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install libgmock-dev
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Configure
|
||||||
|
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build build
|
||||||
|
- name: Run tests
|
||||||
|
run: ctest --test-dir build
|
||||||
26
.github/workflows/on_mac.yml
vendored
Normal file
26
.github/workflows/on_mac.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
name: On Mac
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ develop, master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ develop, master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: macOS Latest
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- name: Installing GTest
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/google/googletest.git
|
||||||
|
cd googletest
|
||||||
|
git checkout v1.14.0
|
||||||
|
cmake -S . -B build
|
||||||
|
sudo cmake --build build --target install
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Configure
|
||||||
|
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build build
|
||||||
|
- name: Run tests
|
||||||
|
run: ctest --test-dir build
|
||||||
29
.github/workflows/on_windows.yml
vendored
Normal file
29
.github/workflows/on_windows.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
name: On Windows
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ develop, master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ develop, master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
name: Windows MSVC Latest
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- name: Installing GTest
|
||||||
|
run: |
|
||||||
|
git clone https://github.com/google/googletest.git
|
||||||
|
cd googletest
|
||||||
|
git checkout v1.14.0
|
||||||
|
cmake -S . -B build -Dgtest_force_shared_crt=ON
|
||||||
|
cmake --build build --config Release --target install
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Configure
|
||||||
|
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_FLAGS="/Zc:__cplusplus /permissive- /EHsc"
|
||||||
|
env:
|
||||||
|
CMAKE_PREFIX_PATH: "C:/Program Files (x86)/googletest-distribution/"
|
||||||
|
- name: Build
|
||||||
|
run: cmake --build build --config Release
|
||||||
|
- name: Run 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.8.0.tar.gz
|
|
||||||
- tar xf release-1.8.0.tar.gz
|
|
||||||
- cd googletest-release-1.8.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
|
|
||||||
87
CHANGELOG.md
87
CHANGELOG.md
@@ -1,3 +1,90 @@
|
|||||||
|
# [5.2.5](https://github.com/fraillt/bitsery/compare/v5.2.4...v5.2.5) (2025-10-09)
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
* fix security issue during deserialization where a crafted payload could cause a shared pointer to be assigned to a different type. More information is [here](https://gist.github.com/TrebledJ/750abc64a826f19dd2d6774724629b71). (huge thanks to [Johnathan](https://github.com/TrebledJ))
|
||||||
|
* fix serialization of shared polymorphic pointer-like types by correctly identifying same object (e.g. the same object serialized through `Base` or `Derived` would otherwise have different pointer addresses).
|
||||||
|
* fix polymorphic type assignment to "observer" by adjusting pointer address.
|
||||||
|
* fix spelling of C++ "likely" attribute. #121 (thanks to [Jules](https://github.com/jules-ai))
|
||||||
|
|
||||||
|
### Other notes
|
||||||
|
* format code that was left unformatted in the previous version.
|
||||||
|
* remove broken patch for GCC 4.8.2 (CentOS 7).
|
||||||
|
|
||||||
|
# [5.2.4](https://github.com/fraillt/bitsery/compare/v5.2.3...v5.2.4) (2024-07-30)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* implement brief syntax for std::optional and std::bitset. #116 (thanks to [Destroyerrrocket](https://github.com/Destroyerrrocket))
|
||||||
|
* improve performance for buffer adapters. #118 (thanks to [Destroyerrrocket](https://github.com/Destroyerrrocket))
|
||||||
|
* check if should swap by taking into account actual type (in addition to configuration). #105 (thanks to [SoftdriveFelix](https://github.com/SoftdriveFelix))
|
||||||
|
* fix compile errors for latest compilers. #106 (thanks to [NBurley93](https://github.com/NBurley93))
|
||||||
|
|
||||||
|
### Other notes
|
||||||
|
* change cmake_minimum_required to 3.25.
|
||||||
|
* change compilers for ubuntu (gcc 14 and clang 18).
|
||||||
|
|
||||||
|
# [5.2.3](https://github.com/fraillt/bitsery/compare/v5.2.2...v5.2.3) (2022-12-01)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* refactored bit-packing implementation to make sure that `MeasureSize` adapter acts as all other adapters and is not bit-packing enabled by default. #91
|
||||||
|
* `BufferAdapterTraits::increaseBufferSize` now accepts current size and minimum required size in order to better allocate required memory.
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
* fix shadow warning in gcc8 #87 (thanks to [museghost](https://github.com/museghost) and brian.kim)
|
||||||
|
|
||||||
|
### Other notes
|
||||||
|
* format whole code base in Mozilla style.
|
||||||
|
* simplified adapters implementations
|
||||||
|
|
||||||
|
# [5.2.2](https://github.com/fraillt/bitsery/compare/v5.2.1...v5.2.2) (2021-08-31)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* add 16 byte value support #75 (thanks to [Victor Stewart](https://github.com/victorstewart))
|
||||||
|
* avoid reinitializing nontrivial std::variant #77 (thanks to [Robbert van der Helm](https://github.com/robbert-vdh))
|
||||||
|
* avoid reinitializing nontrivial std::optional.
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
* fix missing headers for GCC11, also added test to check includes #82 (thanks to [michael-mueller-git](https://github.com/michael-mueller-git))
|
||||||
|
* fixed **StdBitset** to build on macOS (proxy type, returned by `[]` operator wasn't correctly converted to unsigned integral type).
|
||||||
|
|
||||||
|
### Other notes
|
||||||
|
* migrated to [Github actions](https://docs.github.com/en/actions) for running tests.
|
||||||
|
* fixes few warnings on MSVC compiler.
|
||||||
|
* now tests are also run on macOS and Windows.
|
||||||
|
|
||||||
|
# [5.2.1](https://github.com/fraillt/bitsery/compare/v5.2.0...v5.2.1) (2020-11-14)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* `Input/OutputBufferAdapter` now statically asserts that underlying type is 1byte in size.
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
* fixed serialization in `StdBitset` when it's size is less then `unsigned long long`.
|
||||||
|
|
||||||
|
# [5.2.0](https://github.com/fraillt/bitsery/compare/v5.1.0...v5.2.0) (2020-11-09)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* new extension **StdBitset**.
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* removed unused variable warnings in release build, where `max_size` variable during serialization is ignored.
|
||||||
|
* removed unknown pragmas warnings for GCC/Clang (thanks to [Mmpuskas](https://github.com/Mmpuskas)).
|
||||||
|
|
||||||
|
# [5.1.0](https://github.com/fraillt/bitsery/compare/v5.0.3...v5.1.0) (2020-06-08)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* new extension **StdAtomic** (thanks for [VelocityRa](https://github.com/VelocityRa)).
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
* [examples](examples) no longer include bitsery in global namespace (removed `using namespace bitsery`).
|
||||||
|
* removed multiple warning regarding integer conversions (thanks to [tower120](https://github.com/tower120)).
|
||||||
|
* removed unnecessary `dynamic_cast` from BasicInput/OutputStreamAdapter (thanks to [tower120](https://github.com/tower120)).
|
||||||
|
* fixed some include paths, now you can basically to copy/paste bitsery include directory to your project without cmake support.
|
||||||
|
|
||||||
|
### Other notes
|
||||||
|
* added tutorial of how to write your own extension ([here](doc/tutorial/first_extension.md)).
|
||||||
|
* now gtest 1.10 is required if you want to build tests.
|
||||||
|
|
||||||
# [5.0.3](https://github.com/fraillt/bitsery/compare/v5.0.2...v5.0.3) (2020-01-29)
|
# [5.0.3](https://github.com/fraillt/bitsery/compare/v5.0.2...v5.0.3) (2020-01-29)
|
||||||
|
|
||||||
### 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.0.3)
|
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")
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ However, to make sure the process of accepting patches goes smoothly, you should
|
|||||||
you contribute:
|
you contribute:
|
||||||
|
|
||||||
1. Fork the repository.
|
1. Fork the repository.
|
||||||
2. Create new branch based on the *master* branch (`git checkout -b your_branch master`). If your contribution is a bug fix, you should name your branch `bugfix/xxx`; for a feature, it should be `feature/xxx`. Otherwise, just use your good judgment. Consistent naming of branches is appreciated since it makes the output of `git branch` easier to understand with a single glance.
|
2. Create new branch based on the *develop* branch (`git checkout -b your_branch develop`). If your contribution is a bug fix, you should name your branch `bugfix/xxx`; for a feature, it should be `feature/xxx`. Otherwise, just use your good judgment. Consistent naming of branches is appreciated since it makes the output of `git branch` easier to understand with a single glance.
|
||||||
3. Do your modifications on that branch. Except for special cases, your contribution should include proper unit tests and documentation.
|
3. Do your modifications on that branch. Except for special cases, your contribution should include proper unit tests and documentation.
|
||||||
4. Make sure your modifications did not break anything by building, running tests:
|
4. Make sure your modifications did not break anything by building, running tests:
|
||||||
```shell
|
```shell
|
||||||
@@ -23,7 +23,7 @@ you contribute:
|
|||||||
./show_coverage.sh build
|
./show_coverage.sh build
|
||||||
```
|
```
|
||||||
5. Commit your changes, and push to your fork (`git push origin your_branch`). Commit message should be one line short description. When applicable, please squash adjacent *wip* commits into a single *logical* commit.
|
5. Commit your changes, and push to your fork (`git push origin your_branch`). Commit message should be one line short description. When applicable, please squash adjacent *wip* commits into a single *logical* commit.
|
||||||
6. Open a pull request against Bitsery *master* branch. Currently ongoing development is on *master*. At some point an integration branch will be set-up, and pull-requests should target that, but for now its all against master. You may see feature branches come and go, too.
|
6. Open a pull request against Bitsery *develop* branch.
|
||||||
|
|
||||||
|
|
||||||
If you're working with visual studio, there is how to build and run all tests from command line
|
If you're working with visual studio, there is how to build and run all tests from command line
|
||||||
|
|||||||
51
README.md
51
README.md
@@ -1,6 +1,8 @@
|
|||||||
# Bitsery
|
# Bitsery
|
||||||
|
|
||||||
[](https://travis-ci.org/fraillt/bitsery)
|
[](https://github.com/fraillt/bitsery/actions/workflows/on_windows.yml)
|
||||||
|
[](https://github.com/fraillt/bitsery/actions/workflows/on_mac.yml)
|
||||||
|
[](https://github.com/fraillt/bitsery/actions/workflows/on_linux.yml)
|
||||||
[](https://gitter.im/bitsery/Lobby)
|
[](https://gitter.im/bitsery/Lobby)
|
||||||
|
|
||||||
Header only C++ binary serialization library.
|
Header only C++ binary serialization library.
|
||||||
@@ -30,17 +32,17 @@ All cross-platform requirements are enforced at compile time, so serialized data
|
|||||||
|
|
||||||
Look at the numbers and features list, and decide yourself.
|
Look at the numbers and features list, and decide yourself.
|
||||||
|
|
||||||
| library | data size | serialize | deserialize |
|
| library | data size | ser time | des time |
|
||||||
| ---------------- | --------- | --------- | ----------- |
|
| ----------- | --------- | -------- | -------- |
|
||||||
| bitsery | 6913B | 959ms | 927ms |
|
| bitsery | 6913B | 1119ms | 1166ms |
|
||||||
| bitsery_compress | 4213B | 1282ms | 1115ms |
|
| boost | 11037B | 15391ms | 12912ms |
|
||||||
| boost | 11037B | 9826ms | 8313ms |
|
| cereal | 10413B | 10518ms | 10245ms |
|
||||||
| cereal | 10413B | 6324ms | 5698ms |
|
| flatbuffers | 14924B | 9075ms | 3701ms |
|
||||||
| flatbuffers | 14924B | 5129ms | 2142ms |
|
| msgpack | 8857B | 3340ms | 13842ms |
|
||||||
| protobuf | 10018B | 11966ms | 13919ms |
|
| protobuf | 10018B | 21229ms | 22077ms |
|
||||||
| yas | 10463B | 1908ms | 1217ms |
|
| yas | 10463B | 2107ms | 1554ms |
|
||||||
|
|
||||||
*benchmarked on Ubuntu with GCC 8.3.0, more details can be found [here](https://github.com/fraillt/cpp_serializers_benchmark.git)*
|
*benchmarked on Ubuntu with GCC 10.3.0, more details can be found [here](https://github.com/fraillt/cpp_serializers_benchmark.git)*
|
||||||
|
|
||||||
If still not convinced read more in library [motivation](doc/design/README.md) section.
|
If still not convinced read more in library [motivation](doc/design/README.md) section.
|
||||||
|
|
||||||
@@ -64,11 +66,9 @@ void serialize(S& s, MyStruct& o) {
|
|||||||
s.container4b(o.fs, 10);
|
s.container4b(o.fs, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace bitsery;
|
|
||||||
|
|
||||||
using Buffer = std::vector<uint8_t>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
using OutputAdapter = OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = InputBufferAdapter<Buffer>;
|
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
MyStruct data{8941, MyEnum::V2, {15.0f, -8.5f, 0.045f}};
|
MyStruct data{8941, MyEnum::V2, {15.0f, -8.5f, 0.045f}};
|
||||||
@@ -76,10 +76,10 @@ int main() {
|
|||||||
|
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
auto writtenSize = quickSerialization<OutputAdapter>(buffer, data);
|
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
||||||
auto state = quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
|
auto state = bitsery::quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
|
||||||
|
|
||||||
assert(state.first == 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);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -100,14 +100,15 @@ Works with C++11 compiler, no additional dependencies, include `<bitsery/bitsery
|
|||||||
|
|
||||||
## Platforms
|
## Platforms
|
||||||
|
|
||||||
This library was tested on
|
Library is tested on all major compilers on Windows, Linux and macOS.
|
||||||
* Windows: Visual Studio 2015, MinGW (GCC 5.2)
|
|
||||||
* Linux: GCC 5.4, Clang 3.9
|
|
||||||
* OS X Mavericks: AppleClang 8
|
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
The grand plan for this tutorial is to learn how to serialize/deserialize any object efficiently in time and space, so you could focus on other, more interesting things.
|
The grand plan for this tutorial is to learn how to serialize/deserialize any object efficiently in time and space, so you could focus on other, more interesting things.
|
||||||
|
|
||||||
This tutorial will cover these main topics:
|
This tutorial will cover these main topics:
|
||||||
* `Hello World` write one control flow for both: serialization and deserialization.
|
* [Getting started](hello_world.md) with bitsery, and serialize/deserialize your first object.
|
||||||
* `Composer` efficiently compose complex serialization flows.
|
* [Extend to your needs](first_extension.md) by enabling serialization/deserialization depending on version number.
|
||||||
* `Squeeze Me!` compress your data when you know what it stores.
|
* `Squeeze Me!` compress your data when you know what it stores.
|
||||||
* `Anything is Possible` extend library for custom container, compress geometry and more.
|
* `Anything is Possible` extend library for custom container, compress geometry and more.
|
||||||
* `Little or Big` change endianness if you want best performance on PowerPC.
|
* `Little or Big` change endianness if you want best performance on PowerPC.
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
*document in progress*
|
|
||||||
* explain why *value* and *object* is fundamental functions.
|
|
||||||
* write about *Growable* extension
|
|
||||||
67
doc/tutorial/first_extension.md
Normal file
67
doc/tutorial/first_extension.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
... TODO explain step-by-step what we need and how to get there
|
||||||
|
|
||||||
|
Instead I immediately provide implementation for an extension.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include "../details/adapter_common.h"
|
||||||
|
#include "../traits/core/traits.h"
|
||||||
|
|
||||||
|
namespace bitsery {
|
||||||
|
|
||||||
|
namespace ext {
|
||||||
|
|
||||||
|
template<size_t VERSION>
|
||||||
|
class Version {
|
||||||
|
public:
|
||||||
|
|
||||||
|
template<typename Ser, typename T, typename Fnc>
|
||||||
|
void serialize(Ser &ser, const T &v, Fnc &&fnc) const {
|
||||||
|
details::writeSize(ser.adapter(), VERSION);
|
||||||
|
fnc(ser, const_cast<T&>(v), VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Des, typename T, typename Fnc>
|
||||||
|
void deserialize(Des &des, T &v, Fnc &&fnc) const {
|
||||||
|
size_t version{};
|
||||||
|
details::readSize(des.adapter(), version, 0u, std::false_type{});
|
||||||
|
fnc(des, v, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace traits {
|
||||||
|
template<typename T, size_t V>
|
||||||
|
struct ExtensionTraits<ext::Version<V>, T> {
|
||||||
|
using TValue = T;
|
||||||
|
static constexpr bool SupportValueOverload = false;
|
||||||
|
static constexpr bool SupportObjectOverload = false;
|
||||||
|
static constexpr bool SupportLambdaOverload = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Adding such extension to the bitsery itself is impractical because it is very easy to implement, but at the same time it has a lot of customization options that actual user might require e.g.:
|
||||||
|
* how do you want to handle reading/writing version number? (in this case use compact representation as size, but do not check for errors if version number is too large)
|
||||||
|
* maybe you want to be able to set ReaderError, when version is larger than deserialization implementation handles. (we simply ignore this case and later we'll probably get reading error later anyway)
|
||||||
|
* or maybe you want to wrap object in `Growable` extension? so that you could ignore unknown fields in newer version of object.
|
||||||
|
|
||||||
|
Example of how to use this provided implementation:
|
||||||
|
```cpp
|
||||||
|
|
||||||
|
struct TypeV2 {
|
||||||
|
uint16_t x{};
|
||||||
|
uint16_t y{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
void serialize(S& ser, TypeV2& obj) {
|
||||||
|
ser.ext(obj, bitsery::ext::Version<2u>{}, [](S& s, TypeV2&o, size_t version) {
|
||||||
|
s.value2b(o.x);
|
||||||
|
if (version == 2u) {
|
||||||
|
s.value2b(o.y);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -18,11 +18,9 @@ There's nothing to build or make - **bitsery** is header only.
|
|||||||
#include <bitsery/traits/vector.h>
|
#include <bitsery/traits/vector.h>
|
||||||
#include <bitsery/traits/string.h>
|
#include <bitsery/traits/string.h>
|
||||||
|
|
||||||
using namespace bitsery;
|
|
||||||
|
|
||||||
using Buffer = std::vector<uint8_t>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
using OutputAdapter = OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = InputBufferAdapter<Buffer>;
|
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -62,7 +60,7 @@ void serialize(S& s, MyStruct& o) {
|
|||||||
|
|
||||||
This example we choosed probably unfamiliar verbose syntax, so lets explain core functionality that you'll use all the time:
|
This example we choosed probably unfamiliar verbose syntax, so lets explain core functionality that you'll use all the time:
|
||||||
* **s.value4b(o.i);** serialize fundamental types (ints, floats, enums) value**4b** means, that data type is 4 bytes. If you use same code on different machines, if it compiles it means it is compatible.
|
* **s.value4b(o.i);** serialize fundamental types (ints, floats, enums) value**4b** means, that data type is 4 bytes. If you use same code on different machines, if it compiles it means it is compatible.
|
||||||
* **s.text1b(o.str);** serialize text (null-terminated) of char type, if you use *wchar* then you would write *text2b*.
|
* **s.text1b(o.str);** serialize text (null-terminated) of char type, if you use *wchar* then you would write *text2b* or *text4b* depending on the OS platform.
|
||||||
* **s.container4b(o.fs, 100);** serializes any container of fundamental types of size 4bytes, **100** is max size of container.
|
* **s.container4b(o.fs, 100);** serializes any container of fundamental types of size 4bytes, **100** is max size of container.
|
||||||
**Bitsery** is designed to be save with untrusted (malicious) data from network, so for dynamic containers you always need to provide max possible size available, to avoid buffer-overflow attacks.
|
**Bitsery** is designed to be save with untrusted (malicious) data from network, so for dynamic containers you always need to provide max possible size available, to avoid buffer-overflow attacks.
|
||||||
**text** didn't had this max size specified, because it was serializing fixed size container.
|
**text** didn't had this max size specified, because it was serializing fixed size container.
|
||||||
@@ -76,8 +74,8 @@ Create buffer and use helper functions for serialization and deserialization.
|
|||||||
```cpp
|
```cpp
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
|
|
||||||
auto writtenSize = quickSerialization(OutputAdapter{buffer}, data);
|
auto writtenSize = bitsery::quickSerialization(OutputAdapter{buffer}, data);
|
||||||
auto state = quickDeserialization(InputAdapter{buffer.begin(), writtenSize}, res);
|
auto state = bitsery::quickDeserialization(InputAdapter{buffer.begin(), writtenSize}, res);
|
||||||
```
|
```
|
||||||
|
|
||||||
These helper functions use default configuration *bitsery::DefaultConfig*
|
These helper functions use default configuration *bitsery::DefaultConfig*
|
||||||
@@ -93,11 +91,9 @@ deserialization state has two properties, error code and bool that indicates if
|
|||||||
#include <bitsery/traits/vector.h>
|
#include <bitsery/traits/vector.h>
|
||||||
#include <bitsery/traits/string.h>
|
#include <bitsery/traits/string.h>
|
||||||
|
|
||||||
using namespace bitsery;
|
|
||||||
|
|
||||||
using Buffer = std::vector<uint8_t>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
using OutputAdapter = OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = InputBufferAdapter<Buffer>;
|
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||||
|
|
||||||
struct MyStruct {
|
struct MyStruct {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
@@ -110,17 +106,17 @@ void serialize(S& s, MyStruct& o) {
|
|||||||
s.value4b(o.i);
|
s.value4b(o.i);
|
||||||
s.text1b(o.str);
|
s.text1b(o.str);
|
||||||
s.container4b(o.fs, 100);
|
s.container4b(o.fs, 100);
|
||||||
};
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
MyStruct data{8941, "hello", {15.0f, -8.5f, 0.045f}};
|
MyStruct data{8941, "hello", {15.0f, -8.5f, 0.045f}};
|
||||||
MyStruct res{};
|
MyStruct res{};
|
||||||
|
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
auto writtenSize = quickSerialization(OutputAdapter{buffer}, data);
|
auto writtenSize = bitsery::quickSerialization(OutputAdapter{buffer}, data);
|
||||||
auto state = quickDeserialization(InputAdapter{buffer.begin(), writtenSize}, res);
|
auto state = bitsery::quickDeserialization(InputAdapter{buffer.begin(), writtenSize}, res);
|
||||||
|
|
||||||
assert(state.first == ReaderError::NoError && state.second);
|
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
||||||
assert(data.fs == res.fs && data.i == res.i && std::strcmp(data.str, res.str) == 0);
|
assert(data.fs == res.fs && data.i == res.i && std::strcmp(data.str, res.str) == 0);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -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,50 +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
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace bitsery;
|
// some helper types
|
||||||
|
|
||||||
//some helper types
|
|
||||||
using Buffer = std::vector<uint8_t>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
using OutputAdapter = OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = 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 = 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 = quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
|
// the end.
|
||||||
|
auto state = bitsery::quickDeserialization<InputAdapter>(
|
||||||
|
{ buffer.begin(), writtenSize }, res);
|
||||||
|
|
||||||
assert(state.first == 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,64 +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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace bitsery;
|
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
|
// use fixed-size buffer
|
||||||
using Buffer = std::array<uint8_t, 10000>;
|
using Buffer = std::array<uint8_t, 10000>;
|
||||||
using OutputAdapter = OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = 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 = quickSerialization<OutputAdapter>(buffer, data);
|
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
||||||
|
|
||||||
MyTypes::Monster res{};
|
MyTypes::Monster res{};
|
||||||
auto state = quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
|
auto state = bitsery::quickDeserialization<InputAdapter>(
|
||||||
|
{ buffer.begin(), writtenSize }, res);
|
||||||
|
|
||||||
assert(state.first == ReaderError::NoError && state.second);
|
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +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);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using namespace bitsery;
|
// some helper types
|
||||||
|
|
||||||
//some helper types
|
|
||||||
using Buffer = std::vector<uint8_t>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
using OutputAdapter = OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = 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 = quickSerialization<OutputAdapter>(buffer, data);
|
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
||||||
|
|
||||||
auto state = quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
|
auto state = bitsery::quickDeserialization<InputAdapter>(
|
||||||
|
{ buffer.begin(), writtenSize }, res);
|
||||||
|
|
||||||
assert(state.first == 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,106 +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>;
|
||||||
|
|
||||||
// for convenience
|
// define default serialize function for MyVariant, so that we could use
|
||||||
using namespace bitsery;
|
// 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, 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, 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
|
||||||
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{
|
||||||
ext::OverloadExtValue<int64_t, 8, 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, 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 = OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = 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 data{MyStruct{{-451, 2, 968, 75, 4, 156, 49}, 874.4f}};
|
{ { -451, 2, 968, 75, 4, 156, 49 }, 874.4f } } };
|
||||||
MyVariant res{};
|
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 = 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 = quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
|
// the end.
|
||||||
|
auto state = bitsery::quickDeserialization<InputAdapter>(
|
||||||
|
{ buffer.begin(), writtenSize }, res);
|
||||||
|
|
||||||
assert(state.first == 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("example works only on c++17")
|
#pragma message( \
|
||||||
|
"C++17 and /Zc:__cplusplus option is required to enable this example")
|
||||||
#else
|
#else
|
||||||
#warning "example works only on c++17"
|
#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,92 +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>;
|
||||||
using namespace bitsery;
|
|
||||||
// define adapter types,
|
// define adapter types,
|
||||||
using OutputAdapter = OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = 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 = quickSerialization(ctx, OutputAdapter{buffer}, data);
|
ctx, InputAdapter{ buffer.begin(), writtenSize }, res);
|
||||||
|
|
||||||
MyTypes::GameState res{};
|
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
||||||
auto state = quickDeserialization(ctx, InputAdapter{buffer.begin(), writtenSize}, res);
|
|
||||||
|
|
||||||
assert(state.first == ReaderError::NoError && state.second);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +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);
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace bitsery;
|
int
|
||||||
|
main()
|
||||||
|
{
|
||||||
|
// set some random data
|
||||||
|
MyStruct data{ 8941, MyEnum::V2, 0.045 };
|
||||||
|
MyStruct res{};
|
||||||
|
|
||||||
int main() {
|
// open file stream for writing and reading
|
||||||
//set some random data
|
auto fileName = "test_file.bin";
|
||||||
MyStruct data{8941, MyEnum::V2, 0.045};
|
std::fstream s{ fileName, s.binary | s.trunc | s.out };
|
||||||
MyStruct res{};
|
if (!s.is_open()) {
|
||||||
|
std::cout << "cannot open " << fileName << " for writing\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
//open file stream for writing and reading
|
// we cannot use quick serialization function, because streams cannot use
|
||||||
auto fileName = "test_file.bin";
|
// writtenBytesCount method
|
||||||
std::fstream s{fileName, s.binary | s.trunc | s.out};
|
bitsery::Serializer<bitsery::OutputBufferedStreamAdapter> ser{ s };
|
||||||
if (!s.is_open()) {
|
ser.object(data);
|
||||||
std::cout << "cannot open " << fileName << " for writing\n";
|
// flush to writer
|
||||||
return 0;
|
ser.adapter().flush();
|
||||||
}
|
s.close();
|
||||||
|
// reopen for reading
|
||||||
|
|
||||||
//we cannot use quick serialization function, because streams cannot use writtenBytesCount method
|
s.open(fileName, s.binary | s.in);
|
||||||
Serializer<OutputBufferedStreamAdapter> ser{s};
|
if (!s.is_open()) {
|
||||||
ser.object(data);
|
std::cout << "cannot open " << fileName << " for reading\n";
|
||||||
//flush to writer
|
return 0;
|
||||||
ser.adapter().flush();
|
}
|
||||||
s.close();
|
|
||||||
//reopen for reading
|
|
||||||
|
|
||||||
s.open(fileName, s.binary | s.in);
|
// same as serialization, but returns deserialization state as a pair
|
||||||
if (!s.is_open()) {
|
// first = error code, second = is buffer was successfully read from begin to
|
||||||
std::cout << "cannot open " << fileName << " for reading\n";
|
// the end.
|
||||||
return 0;
|
auto state =
|
||||||
}
|
bitsery::quickDeserialization<bitsery::InputStreamAdapter>(s, res);
|
||||||
|
|
||||||
//same as serialization, but returns deserialization state as a pair
|
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
||||||
//first = error code, second = is buffer was successfully read from begin to the end.
|
assert(data.f == res.f && data.i == res.i && data.e == res.e);
|
||||||
auto state = quickDeserialization<InputStreamAdapter>(s, res);
|
|
||||||
|
|
||||||
assert(state.first == ReaderError::NoError && state.second);
|
|
||||||
assert(data.f == res.f && data.i == res.i && data.e == res.e);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,94 +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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace bitsery;
|
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
|
// use fixed-size buffer
|
||||||
using Buffer = std::array<uint8_t, 10000>;
|
using Buffer = std::array<uint8_t, 10000>;
|
||||||
using OutputAdapter = OutputBufferAdapter<Buffer>;
|
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using InputAdapter = 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 = quickSerialization<OutputAdapter>(buffer, data);
|
|
||||||
|
|
||||||
MyTypes::Monster res{};
|
MyTypes::Monster res{};
|
||||||
//deserialize
|
// deserialize
|
||||||
auto state = quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
|
auto state = bitsery::quickDeserialization<InputAdapter>(
|
||||||
|
{ buffer.begin(), writtenSize }, res);
|
||||||
|
|
||||||
assert(state.first == ReaderError::NoError && state.second);
|
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,107 +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
|
||||||
|
{};
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace bitsery;
|
// some helper types
|
||||||
|
|
||||||
|
|
||||||
//some helper types
|
|
||||||
using Buffer = std::vector<uint8_t>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
using Writer = OutputBufferAdapter<Buffer>;
|
using Writer = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using Reader = 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{};
|
||||||
|
|
||||||
ext::InheritanceContext ctx1;
|
bitsery::ext::InheritanceContext ctx1;
|
||||||
auto writtenSize = 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 };
|
||||||
ext::InheritanceContext ctx2;
|
bitsery::ext::InheritanceContext ctx2;
|
||||||
auto state = quickDeserialization(ctx2, Reader{buf.begin(), writtenSize}, res);
|
auto state = bitsery::quickDeserialization(
|
||||||
assert(state.first == 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,63 +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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using namespace bitsery;
|
// some helper types
|
||||||
|
|
||||||
//some helper types
|
|
||||||
using Buffer = std::vector<uint8_t>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
using Writer = OutputBufferAdapter<Buffer>;
|
using Writer = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using Reader = 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
|
||||||
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
|
||||||
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() == ReaderError::NoError && des.adapter().isCompletedSuccessfully());
|
assert(des.adapter().error() == bitsery::ReaderError::NoError &&
|
||||||
assert(res == data);
|
des.adapter().isCompletedSuccessfully());
|
||||||
|
assert(res == data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,147 +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});
|
}
|
||||||
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using namespace bitsery;
|
// some helper types
|
||||||
|
|
||||||
//some helper types
|
|
||||||
using Buffer = std::vector<uint8_t>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
using Writer = OutputBufferAdapter<Buffer>;
|
using Writer = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using Reader = 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
|
||||||
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{};
|
||||||
{
|
{
|
||||||
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 == 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,271 +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
|
||||||
//use bitsery namespace for convenience
|
|
||||||
using namespace bitsery;
|
|
||||||
|
|
||||||
//some helper types
|
|
||||||
using Buffer = std::vector<uint8_t>;
|
using Buffer = std::vector<uint8_t>;
|
||||||
using Writer = OutputBufferAdapter<Buffer>;
|
using Writer = bitsery::OutputBufferAdapter<Buffer>;
|
||||||
using Reader = 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<ext::PointerLinkingContext, ext::PolymorphicContext<ext::StandardRTTI>>;
|
using TContext =
|
||||||
//NOTE:
|
std::tuple<bitsery::ext::PointerLinkingContext,
|
||||||
// RTTI can be customizable, if you can't use dynamic_cast and typeid, and have 'custom' solution
|
bitsery::ext::PolymorphicContext<bitsery::ext::StandardRTTI>>;
|
||||||
using MySerializer = Serializer<Writer, TContext>;
|
// NOTE:
|
||||||
using MyDeserializer = Deserializer<Reader, TContext>;
|
// RTTI can be customizable, if you can't use dynamic_cast and typeid, and have
|
||||||
|
// 'custom' solution
|
||||||
|
using MySerializer = bitsery::Serializer<Writer, TContext>;
|
||||||
|
using MyDeserializer = bitsery::Deserializer<Reader, TContext>;
|
||||||
|
|
||||||
//checks if deserialized data is equal
|
// 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() == 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,330 +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");
|
|
||||||
|
|
||||||
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, 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; }
|
||||||
|
|
||||||
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 auto newOffset = _currOffset + SIZE;
|
readInternalImpl(
|
||||||
assert(newOffset <= _endReadOffset);
|
data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||||
std::copy_n(_beginIt + _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 auto newOffset = _currOffset + SIZE;
|
const size_t newOffset = _currOffset + size;
|
||||||
if (newOffset <= _endReadOffset) {
|
assert(newOffset <= _endReadOffset);
|
||||||
std::copy_n(_beginIt + _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 auto newOffset = _currOffset + size;
|
{
|
||||||
assert(newOffset <= _endReadOffset);
|
const size_t newOffset = _currOffset + size;
|
||||||
std::copy_n(_beginIt + _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 auto newOffset = _currOffset + size;
|
{
|
||||||
if (newOffset <= _endReadOffset) {
|
if (_bufferSize >= pos && error() == ReaderError::NoError) {
|
||||||
std::copy_n(_beginIt + _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) }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
{
|
||||||
|
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 auto newOffset = _currOffset + SIZE;
|
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(
|
||||||
if (newOffset <= _bufferSize) {
|
*_buffer, _currOffset, newOffset);
|
||||||
std::copy_n(data, SIZE, _beginIt + _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 auto newOffset = _currOffset + size;
|
|
||||||
if (newOffset <= _bufferSize) {
|
|
||||||
std::copy_n(data, size, _beginIt + _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 auto newOffset = _currOffset + SIZE;
|
|
||||||
assert(newOffset <= _bufferSize);
|
|
||||||
std::copy_n(data, SIZE, _beginIt + _currOffset);
|
|
||||||
_currOffset = newOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeInternalBufferImpl(const TValue *data, size_t size, std::false_type) {
|
|
||||||
const auto newOffset = _currOffset + size;
|
|
||||||
assert(newOffset <= _bufferSize);
|
|
||||||
std::copy_n(data, size, _beginIt + _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,95 +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 <type_traits>
|
||||||
|
|
||||||
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,296 +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>
|
||||||
|
|
||||||
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, 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 , 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_ios<TChar, CharTraits>& ostream)
|
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<
|
||||||
:_ios{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
|
||||||
if (auto ostream = dynamic_cast<std::basic_ostream<TChar, CharTraits>*>(_ios))
|
{
|
||||||
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>
|
||||||
_ios->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)
|
||||||
_ios->rdbuf()->sputn( data , size );
|
{
|
||||||
}
|
_ostream->rdbuf()->sputn(data, size);
|
||||||
|
}
|
||||||
|
|
||||||
std::basic_ios<TChar, CharTraits>* _ios;
|
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_ios<TChar, CharTraits>& ostream, size_t bufferSize = 256)
|
BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>;
|
||||||
:_ios(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 atleast 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
|
||||||
: _ios{rhs._ios},
|
// 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)
|
||||||
_ios = rhs._ios;
|
: _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();
|
{
|
||||||
if (auto ostream = dynamic_cast<std::basic_ostream<TChar, CharTraits>*>(_ios))
|
static_assert(std::is_void<TChar>::value,
|
||||||
ostream->flush();
|
"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>;
|
{
|
||||||
|
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 + _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 + _currOffset);
|
writeInternalImpl(data, SIZE);
|
||||||
_currOffset = newOffset;
|
}
|
||||||
} else {
|
|
||||||
writeBufferToStream();
|
|
||||||
// write buffer directly to stream
|
|
||||||
_ios->rdbuf()->sputn(data, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeBufferToStream() {
|
void writeInternalBuffer(const TValue* data, size_t size)
|
||||||
_ios->rdbuf()->sputn(std::addressof(*_beginIt), _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_ios<TChar, CharTraits>* _ios;
|
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>, public BasicOutputStreamAdapter<TChar, Config, CharTraits> {
|
{
|
||||||
public:
|
// resize buffer
|
||||||
using TValue = TChar;
|
_bufferSize = buffSize;
|
||||||
|
_buf.resize(_bufferSize);
|
||||||
|
_beginIt = std::begin(_buf);
|
||||||
|
}
|
||||||
|
void init(size_t, std::false_type)
|
||||||
|
{
|
||||||
|
// ignore buffer size parameter, and instead take actual buffer size
|
||||||
|
_bufferSize = traits::ContainerTraits<Buffer>::size(_buf);
|
||||||
|
}
|
||||||
|
|
||||||
//both bases contain reference to same iostream, so no need to do anything
|
std::basic_ostream<TChar, CharTraits>* _ostream;
|
||||||
BasicIOStreamAdapter(std::basic_ios<TChar, CharTraits>& iostream)
|
TBuffer _buf;
|
||||||
:BasicInputStreamAdapter<TChar, Config, CharTraits>{iostream},
|
BufferIt _beginIt;
|
||||||
BasicOutputStreamAdapter<TChar, Config, CharTraits>{iostream} {
|
size_t _currOffset;
|
||||||
|
size_t _bufferSize{ 0 };
|
||||||
|
};
|
||||||
|
|
||||||
}
|
template<typename TChar, typename Config, typename CharTraits>
|
||||||
};
|
class BasicIOStreamAdapter
|
||||||
|
: public BasicInputStreamAdapter<TChar, Config, CharTraits>
|
||||||
|
, public BasicOutputStreamAdapter<TChar, Config, CharTraits>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using TValue = TChar;
|
||||||
|
|
||||||
//helper types for most common implementations for std streams
|
// both bases contain reference to same iostream, so no need to do anything
|
||||||
using OutputStreamAdapter = BasicOutputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
|
BasicIOStreamAdapter(std::basic_iostream<TChar, CharTraits>& iostream)
|
||||||
using InputStreamAdapter = BasicInputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
|
: BasicInputStreamAdapter<TChar, Config, CharTraits>{ iostream }
|
||||||
using IOStreamAdapter = BasicIOStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
|
, BasicOutputStreamAdapter<TChar, Config, CharTraits>{ iostream }
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
using OutputBufferedStreamAdapter = BasicBufferedOutputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
|
// 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 0
|
#define BITSERY_MINOR_VERSION 2
|
||||||
#define BITSERY_PATCH_VERSION 3
|
#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/brief_syntax_common.h"
|
||||||
#include "details/serialization_common.h"
|
#include "details/serialization_common.h"
|
||||||
#include "bitsery/details/brief_syntax_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 "../details/brief_syntax_common.h"
|
||||||
#include "../traits/array.h"
|
#include "../traits/array.h"
|
||||||
#include "bitsery/details/brief_syntax_common.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
|
||||||
|
|||||||
37
include/bitsery/brief_syntax/atomic.h
Normal file
37
include/bitsery/brief_syntax/atomic.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 Nick Renieris
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// 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_ATOMIC_H
|
||||||
|
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_ATOMIC_H
|
||||||
|
|
||||||
|
#include "../ext/std_atomic.h"
|
||||||
|
|
||||||
|
namespace bitsery {
|
||||||
|
template<typename S, typename T>
|
||||||
|
void
|
||||||
|
serialize(S& s, std::atomic<T>& obj)
|
||||||
|
{
|
||||||
|
s.template ext<sizeof(T)>(obj, ext::StdAtomic{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#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 "../details/brief_syntax_common.h"
|
||||||
#include "../traits/deque.h"
|
#include "../traits/deque.h"
|
||||||
#include "bitsery/details/brief_syntax_common.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 "../details/brief_syntax_common.h"
|
||||||
#include "../traits/forward_list.h"
|
#include "../traits/forward_list.h"
|
||||||
#include "bitsery/details/brief_syntax_common.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 "../details/brief_syntax_common.h"
|
||||||
#include "../traits/list.h"
|
#include "../traits/list.h"
|
||||||
#include "bitsery/details/brief_syntax_common.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,50 +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 "../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,42 +1,50 @@
|
|||||||
//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
|
||||||
|
|
||||||
#include "../ext/std_queue.h"
|
#include "../ext/std_queue.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::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,43 +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 "../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,36 +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 "../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 "../details/brief_syntax_common.h"
|
||||||
#include "../traits/string.h"
|
#include "../traits/string.h"
|
||||||
#include "bitsery/details/brief_syntax_common.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,51 +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 "../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,43 +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 <unordered_set>
|
|
||||||
#include "../ext/std_set.h"
|
#include "../ext/std_set.h"
|
||||||
|
#include <limits>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
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 "../details/brief_syntax_common.h"
|
||||||
#include "../traits/vector.h"
|
#include "../traits/vector.h"
|
||||||
#include "bitsery/details/brief_syntax_common.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,318 +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 Writter>
|
|
||||||
void writeSize(Writter& 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 (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 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
|
|
||||||
struct EndiannessTestData {
|
|
||||||
static constexpr uint32_t _sample4Bytes = 0x01020304;
|
|
||||||
static constexpr uint8_t _sample1stByte = (const uint8_t &) _sample4Bytes;
|
|
||||||
};
|
|
||||||
|
|
||||||
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 = uint16_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) {
|
|
||||||
std::for_each(v, std::next(v, 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,149 +1,200 @@
|
|||||||
//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
|
||||||
|
|
||||||
#include "../traits/core/traits.h"
|
#include "../traits/core/traits.h"
|
||||||
|
#include "serialization_common.h"
|
||||||
#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,465 +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>
|
// 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,186 +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 (v << 1) ^ (v >> (BitsSize<T>::value - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename TResult, typename TUnsigned>
|
|
||||||
TResult zigZagDecode(TUnsigned v, std::true_type) const {
|
|
||||||
return (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 {
|
|
||||||
auto val = 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 {
|
|
||||||
constexpr auto TBITS = sizeof(T)*8;
|
|
||||||
uint8_t b1{0x80u};
|
|
||||||
auto i = 0u;
|
|
||||||
for (;i < TBITS && b1 > 0x7Fu; i +=7u) {
|
|
||||||
r.template readBytes<1>(b1);
|
|
||||||
v += static_cast<T>(b1 & 0x7Fu) << i;
|
|
||||||
}
|
|
||||||
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,76 +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)
|
|
||||||
obj = *std::next(std::begin(_values), 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 "../ext/utils/memory_resource.h"
|
||||||
#include "../traits/core/traits.h"
|
#include "../traits/core/traits.h"
|
||||||
#include "bitsery/ext/utils/memory_resource.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
|
||||||
|
|||||||
67
include/bitsery/ext/std_atomic.h
Normal file
67
include/bitsery/ext/std_atomic.h
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 Nick Renieris
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// 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_EXT_STD_ATOMIC_H
|
||||||
|
#define BITSERY_EXT_STD_ATOMIC_H
|
||||||
|
|
||||||
|
#include "../traits/core/traits.h"
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
namespace bitsery {
|
||||||
|
namespace ext {
|
||||||
|
|
||||||
|
class StdAtomic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename Ser, typename T, typename Fnc>
|
||||||
|
void serialize(Ser& ser, const std::atomic<T>& obj, Fnc&& fnc) const
|
||||||
|
{
|
||||||
|
auto res = obj.load();
|
||||||
|
fnc(ser, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Des, typename T, typename Fnc>
|
||||||
|
void deserialize(Des& des, std::atomic<T>& obj, Fnc&& fnc) const
|
||||||
|
{
|
||||||
|
T res{};
|
||||||
|
fnc(des, res);
|
||||||
|
obj.store(res);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace traits {
|
||||||
|
template<typename T>
|
||||||
|
struct ExtensionTraits<ext::StdAtomic, std::atomic<T>>
|
||||||
|
{
|
||||||
|
using TValue = T;
|
||||||
|
static constexpr bool SupportValueOverload = true;
|
||||||
|
static constexpr bool SupportObjectOverload = false;
|
||||||
|
static constexpr bool SupportLambdaOverload = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BITSERY_EXT_STD_ATOMIC_H
|
||||||
164
include/bitsery/ext/std_bitset.h
Normal file
164
include/bitsery/ext/std_bitset.h
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
// MIT License
|
||||||
|
//
|
||||||
|
// Copyright (c) 2020 Mindaugas Vinkelis
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to deal
|
||||||
|
// in the Software without restriction, including without limitation the rights
|
||||||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
// copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// 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_EXT_STD_BITSET_H
|
||||||
|
#define BITSERY_EXT_STD_BITSET_H
|
||||||
|
|
||||||
|
#include "../traits/core/traits.h"
|
||||||
|
#include <bitset>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace bitsery {
|
||||||
|
namespace ext {
|
||||||
|
|
||||||
|
class StdBitset
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename Ser, typename Fnc, size_t N>
|
||||||
|
void serialize(Ser& ser, const std::bitset<N>& obj, Fnc&&) const
|
||||||
|
{
|
||||||
|
constexpr size_t BYTES = N / 8;
|
||||||
|
constexpr size_t LEFTOVER = N % 8;
|
||||||
|
if (BYTES > sizeof(unsigned long long)) {
|
||||||
|
for (size_t i = 0u; i < BYTES; ++i) {
|
||||||
|
size_t offset = i * 8;
|
||||||
|
auto data = obj[offset + 0] + (obj[offset + 1] << 1) +
|
||||||
|
(obj[offset + 2] << 2) + (obj[offset + 3] << 3) +
|
||||||
|
(obj[offset + 4] << 4) + (obj[offset + 5] << 5) +
|
||||||
|
(obj[offset + 6] << 6) + (obj[offset + 7] << 7);
|
||||||
|
ser.value1b(static_cast<uint8_t>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
} 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) {
|
||||||
|
serializeLeftoverImpl(ser.adapter(),
|
||||||
|
obj,
|
||||||
|
N - LEFTOVER,
|
||||||
|
N,
|
||||||
|
std::is_same<Ser, typename Ser::BPEnabledType>{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Des, typename Fnc, size_t N>
|
||||||
|
void deserialize(Des& des, std::bitset<N>& obj, Fnc&&) const
|
||||||
|
{
|
||||||
|
constexpr size_t BYTES = N / 8;
|
||||||
|
constexpr size_t LEFTOVER = N % 8;
|
||||||
|
for (size_t i = 0u; i < BYTES; ++i) {
|
||||||
|
size_t offset = i * 8;
|
||||||
|
uint8_t data = 0;
|
||||||
|
des.value1b(data);
|
||||||
|
obj[offset + 0] = data & 0x01u;
|
||||||
|
obj[offset + 1] = data & 0x02u;
|
||||||
|
obj[offset + 2] = data & 0x04u;
|
||||||
|
obj[offset + 3] = data & 0x08u;
|
||||||
|
obj[offset + 4] = data & 0x10u;
|
||||||
|
obj[offset + 5] = data & 0x20u;
|
||||||
|
obj[offset + 6] = data & 0x40u;
|
||||||
|
obj[offset + 7] = data & 0x80u;
|
||||||
|
}
|
||||||
|
if (LEFTOVER > 0) {
|
||||||
|
deserializeLeftoverImpl(des.adapter(),
|
||||||
|
obj,
|
||||||
|
N - LEFTOVER,
|
||||||
|
N,
|
||||||
|
std::is_same<Des, typename Des::BPEnabledType>{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename Writer, size_t N>
|
||||||
|
void serializeLeftoverImpl(Writer& w,
|
||||||
|
const std::bitset<N>& obj,
|
||||||
|
size_t from,
|
||||||
|
size_t to,
|
||||||
|
std::integral_constant<bool, false>) const
|
||||||
|
{
|
||||||
|
auto data = 0;
|
||||||
|
for (auto i = from; i < to; ++i) {
|
||||||
|
data += obj[i] << (i - from);
|
||||||
|
}
|
||||||
|
w.template writeBytes<1>(static_cast<uint8_t>(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Writer, size_t N>
|
||||||
|
void serializeLeftoverImpl(Writer& w,
|
||||||
|
const std::bitset<N>& obj,
|
||||||
|
size_t from,
|
||||||
|
size_t to,
|
||||||
|
std::integral_constant<bool, true>) const
|
||||||
|
{
|
||||||
|
for (auto i = from; i < to; ++i) {
|
||||||
|
w.writeBits(obj[i] ? 1u : 0u, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Reader, size_t N>
|
||||||
|
void deserializeLeftoverImpl(Reader& r,
|
||||||
|
std::bitset<N>& obj,
|
||||||
|
size_t from,
|
||||||
|
size_t to,
|
||||||
|
std::integral_constant<bool, false>) const
|
||||||
|
{
|
||||||
|
uint8_t data = 0u;
|
||||||
|
r.template readBytes<1>(data);
|
||||||
|
for (auto i = from; i < to; ++i) {
|
||||||
|
obj[i] = data & (1u << (i - from));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Reader, size_t N>
|
||||||
|
void deserializeLeftoverImpl(Reader& r,
|
||||||
|
std::bitset<N>& obj,
|
||||||
|
size_t from,
|
||||||
|
size_t to,
|
||||||
|
std::integral_constant<bool, true>) const
|
||||||
|
{
|
||||||
|
for (auto i = from; i < to; ++i) {
|
||||||
|
uint8_t res = 0u;
|
||||||
|
r.readBits(res, 1);
|
||||||
|
obj[i] = res == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace traits {
|
||||||
|
template<size_t N>
|
||||||
|
struct ExtensionTraits<ext::StdBitset, std::bitset<N>>
|
||||||
|
{
|
||||||
|
using TValue = void;
|
||||||
|
static constexpr bool SupportValueOverload = false;
|
||||||
|
static constexpr bool SupportObjectOverload = true;
|
||||||
|
static constexpr bool SupportLambdaOverload = false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BITSERY_EXT_STD_BITSET_H
|
||||||
@@ -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,83 +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) {
|
|
||||||
obj = ::bitsery::Access::create<T>();
|
|
||||||
fnc(des, *obj);
|
|
||||||
} else {
|
|
||||||
obj = std::nullopt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
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,91 +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;
|
||||||
TElem item = ::bitsery::Access::create<TElem>();
|
}
|
||||||
this->serializeType(des, item);
|
}
|
||||||
data = std::variant<Ts...>(std::in_place_index_t<Index>{}, std::move(item));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
TElem item = ::bitsery::Access::create<TElem>();
|
||||||
|
this->serializeType(des, item);
|
||||||
|
data =
|
||||||
|
std::variant<Ts...>(std::in_place_index_t<Index>{}, std::move(item));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// deduction guide
|
// deduction guide
|
||||||
template<typename ...Overloads>
|
template<typename... Overloads>
|
||||||
StdVariant(Overloads...) -> StdVariant<Overloads...>;
|
StdVariant(Overloads...) -> StdVariant<Overloads...>;
|
||||||
}
|
}
|
||||||
|
|
||||||
//defines empty fuction, that handles monostate
|
// defines empty fuction, that handles monostate
|
||||||
template <typename S>
|
template<typename S>
|
||||||
void serialize(S& , std::monostate&) {}
|
void
|
||||||
|
serialize(S&, std::monostate&)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
namespace traits {
|
namespace traits {
|
||||||
|
|
||||||
template<typename Variant, typename ... Overloads>
|
template<typename Variant, typename... Overloads>
|
||||||
struct ExtensionTraits<ext::StdVariant<Overloads...>, Variant> {
|
struct ExtensionTraits<ext::StdVariant<Overloads...>, Variant>
|
||||||
static_assert(bitsery::details::IsSpecializationOf<Variant, std::variant>::value,
|
{
|
||||||
"StdVariant only works with std::variant");
|
static_assert(
|
||||||
using TValue = void;
|
bitsery::details::IsSpecializationOf<Variant, std::variant>::value,
|
||||||
static constexpr bool SupportValueOverload = false;
|
"StdVariant only works with std::variant");
|
||||||
static constexpr bool SupportObjectOverload = true;
|
using TValue = void;
|
||||||
static constexpr bool SupportLambdaOverload = false;
|
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 : 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 auto ratio = (v - r.min) / (r.max - r.min);
|
|
||||||
return static_cast<VT>(ratio * 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) / 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,101 +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:
|
|
||||||
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), newSize), std::end(container));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
private:
|
||||||
|
using diff_t = typename T::difference_type;
|
||||||
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>(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,68 +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)
|
||||||
static void resizeImpl(std::forward_list<T, Allocator>& container, size_t size, std::true_type) {
|
{
|
||||||
container.resize(size);
|
resizeImpl(container, size, std::is_default_constructible<TValue>{});
|
||||||
}
|
}
|
||||||
static void resizeImpl(std::forward_list<T, Allocator>& container, size_t newSize, std::false_type) {
|
|
||||||
const auto oldSize = size(container);
|
private:
|
||||||
for (auto it = oldSize; it < newSize; ++it) {
|
using diff_t = typename std::forward_list<T, Allocator>::difference_type;
|
||||||
container.push_front(::bitsery::Access::create<TValue>());
|
static void resizeImpl(std::forward_list<T, Allocator>& container,
|
||||||
}
|
size_t size,
|
||||||
if (oldSize > newSize) {
|
std::true_type)
|
||||||
//erase_after must have atleast one element to work
|
{
|
||||||
if (newSize > 0)
|
container.resize(size);
|
||||||
container.erase_after(std::next(std::begin(container), newSize-1));
|
}
|
||||||
else
|
static void resizeImpl(std::forward_list<T, Allocator>& container,
|
||||||
container.clear();
|
size_t newSize,
|
||||||
}
|
std::false_type)
|
||||||
}
|
{
|
||||||
};
|
const auto oldSize = size(container);
|
||||||
|
for (auto it = oldSize; it < newSize; ++it) {
|
||||||
|
container.push_front(::bitsery::Access::create<TValue>());
|
||||||
}
|
}
|
||||||
|
if (oldSize > newSize) {
|
||||||
|
// erase_after must have atleast one element to work
|
||||||
|
if (newSize > 0)
|
||||||
|
container.erase_after(
|
||||||
|
std::next(std::begin(container), static_cast<diff_t>(newSize - 1)));
|
||||||
|
else
|
||||||
|
container.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // BITSERY_TRAITS_STD_FORWARD_LIST_H
|
||||||
#endif //BITSERY_TRAITS_STD_FORWARD_LIST_H
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -20,10 +20,11 @@
|
|||||||
#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.10)
|
cmake_minimum_required(VERSION 3.25)
|
||||||
project(bitsery_tests CXX)
|
project(bitsery_tests
|
||||||
|
LANGUAGES CXX)
|
||||||
|
|
||||||
find_package(GTest 1.8 REQUIRED)
|
find_package(GTest 1.10 REQUIRED)
|
||||||
|
|
||||||
if (NOT TARGET Bitsery::bitsery)
|
if (NOT TARGET Bitsery::bitsery)
|
||||||
message(FATAL_ERROR "Bitsery::bitsery alias not set. Please generate CMake from bitsery root directory.")
|
message(FATAL_ERROR "Bitsery::bitsery alias not set. Please generate CMake from bitsery root directory.")
|
||||||
@@ -31,15 +32,16 @@ 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})
|
||||||
add_executable(${TestName} ${TestFile})
|
add_executable(${TestName} ${TestFile})
|
||||||
target_link_libraries(${TestName} PRIVATE GTest::Main Bitsery::bitsery)
|
target_link_libraries(${TestName} PRIVATE GTest::Main Bitsery::bitsery)
|
||||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||||
target_compile_options(${TestName} PRIVATE -Wextra -Wno-missing-braces -Wpedantic -Weffc++ -Wno-c++14-extensions)
|
target_compile_options(${TestName} PRIVATE -Wextra -Wconversion -Wno-missing-braces -Wpedantic -Weffc++ -Werror)
|
||||||
|
endif()
|
||||||
|
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
target_compile_options(${TestName} PRIVATE -Wno-c++14-extensions)
|
||||||
endif()
|
endif()
|
||||||
gtest_discover_tests(${TestName})
|
gtest_discover_tests(${TestName})
|
||||||
|
|
||||||
@@ -59,4 +61,40 @@ if (ParentDir)
|
|||||||
# add headers so IDE correctly show them
|
# add headers so IDE correctly show them
|
||||||
target_sources(bitsery.dummy_for_ide PRIVATE ${HeadersForIDE} serialization_test_utils.h)
|
target_sources(bitsery.dummy_for_ide PRIVATE ${HeadersForIDE} serialization_test_utils.h)
|
||||||
target_link_libraries(bitsery.dummy_for_ide PRIVATE GTest::Main Bitsery::bitsery)
|
target_link_libraries(bitsery.dummy_for_ide PRIVATE GTest::Main Bitsery::bitsery)
|
||||||
|
|
||||||
|
# creates a "check_includes" target to verify if all headers has required includes
|
||||||
|
# to simplify things a little bit, it only works with modern compiler (C++17)
|
||||||
|
# as some bitsery extensions require C++17 compliant compiler.
|
||||||
|
if("cxx_std_17" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
|
||||||
|
add_library(check_includes OBJECT)
|
||||||
|
target_compile_features(check_includes PRIVATE cxx_std_17)
|
||||||
|
file(WRITE ${CMAKE_BINARY_DIR}/check_includes.in "
|
||||||
|
// generated by CMake to verify header includes.
|
||||||
|
// we need exactly 201703L, because some compilers with experimental C++17 support
|
||||||
|
// provides bigger number than 201402L (C++14) but doesn't actually has enough
|
||||||
|
// functionality to build these files
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
#include \"@HeaderFile@\"
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#pragma message(\"/Zc:__cplusplus option is required to enable check_includes\")
|
||||||
|
#else
|
||||||
|
#define XSTR(x) STR(x)
|
||||||
|
#define STR(x) #x
|
||||||
|
#pragma message (\"`__cplusplus` macro value should be 201703L or greater, actual value is: \" XSTR(__cplusplus))
|
||||||
|
#endif
|
||||||
|
")
|
||||||
|
|
||||||
|
file(GLOB_RECURSE HeaderFiles "${ParentDir}/include/bitsery/*.h")
|
||||||
|
foreach (HeaderFile ${HeaderFiles})
|
||||||
|
SET(CHK_TARGET_NAME "chk_inc_${HeaderFile}")
|
||||||
|
STRING(REPLACE "${ParentDir}/include/bitsery/" "" CHK_TARGET_NAME ${CHK_TARGET_NAME})
|
||||||
|
STRING(REGEX REPLACE "/" "_" CHK_TARGET_NAME ${CHK_TARGET_NAME})
|
||||||
|
STRING(REGEX REPLACE "\\\\" "_" CHK_TARGET_NAME ${CHK_TARGET_NAME})
|
||||||
|
configure_file(${CMAKE_BINARY_DIR}/check_includes.in "${CHK_TARGET_NAME}.cpp")
|
||||||
|
target_sources(check_includes PRIVATE "${CHK_TARGET_NAME}.cpp")
|
||||||
|
endforeach ()
|
||||||
|
else()
|
||||||
|
message(WARNING "`check_includes` target will be disabled, as it require compiler with C++17 support.")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,33 +1,35 @@
|
|||||||
//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>
|
||||||
|
#include <bitsery/brief_syntax/atomic.h>
|
||||||
#include <bitsery/brief_syntax/chrono.h>
|
#include <bitsery/brief_syntax/chrono.h>
|
||||||
#include <bitsery/brief_syntax/deque.h>
|
#include <bitsery/brief_syntax/deque.h>
|
||||||
#include <bitsery/brief_syntax/forward_list.h>
|
#include <bitsery/brief_syntax/forward_list.h>
|
||||||
#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>
|
||||||
@@ -36,400 +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>
|
||||||
#else
|
#if __cplusplus > 202002L
|
||||||
#if defined(_MSC_VER)
|
#include <bitsery/brief_syntax/bitset.h>
|
||||||
#pragma message("tuple and variant only works with c++17")
|
|
||||||
#else
|
|
||||||
#warning "tuple and variant only works with c++17"
|
|
||||||
#endif
|
#endif
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#pragma message( \
|
||||||
|
"C++17 and /Zc:__cplusplus option is required to enable std::tuple and std::variant brief syntax tests")
|
||||||
|
#else
|
||||||
|
#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 <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 procBriefSyntaxWithMaxSize(const T& testData) {
|
T&&
|
||||||
SerializationContext ctx;
|
procBriefSyntaxRvalue(T&& init_value, const T& testData)
|
||||||
ctx.createSerializer()(bitsery::maxSize(testData, 100));
|
{
|
||||||
T res{};
|
SerializationContext ctx;
|
||||||
ctx.createDeserializer()(bitsery::maxSize(res, 100));
|
ctx.createSerializer()(testData);
|
||||||
return res;
|
ctx.createDeserializer()(init_value);
|
||||||
|
return std::move(init_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, CStyleArrayForValueTypesAsContainer) {
|
template<typename T>
|
||||||
const int t1[3]{8748, -484, 45};
|
T
|
||||||
int r1[3]{0, 0, 0};
|
procBriefSyntaxWithMaxSize(const T& testData)
|
||||||
|
{
|
||||||
SerializationContext ctx;
|
SerializationContext ctx;
|
||||||
ctx.createSerializer()(bitsery::asContainer(t1));
|
ctx.createSerializer()(bitsery::maxSize(testData, 100));
|
||||||
ctx.createDeserializer()(bitsery::asContainer(r1));
|
T res{};
|
||||||
|
ctx.createDeserializer()(bitsery::maxSize(res, 100));
|
||||||
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, CStyleArrayForIntegralTypesAsText) {
|
TEST(BriefSyntax, CStyleArrayForValueTypesAsContainer)
|
||||||
const char t1[3]{"hi"};
|
{
|
||||||
char 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::asText(t1));
|
ctx.createSerializer()(bitsery::asContainer(t1));
|
||||||
ctx.createDeserializer()(bitsery::asText(r1));
|
ctx.createDeserializer()(bitsery::asContainer(r1));
|
||||||
|
|
||||||
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, CStyleArray) {
|
TEST(BriefSyntax, CStyleArrayForIntegralTypesAsText)
|
||||||
const MyEnumClass t1[3]{MyEnumClass::E1, MyEnumClass::E4, MyEnumClass::E2};
|
{
|
||||||
MyEnumClass r1[3]{};
|
const char t1[3]{ "hi" };
|
||||||
|
char r1[3]{ 0, 0, 0 };
|
||||||
|
|
||||||
SerializationContext ctx;
|
SerializationContext ctx;
|
||||||
ctx.createSerializer()(t1);
|
ctx.createSerializer()(bitsery::asText(t1));
|
||||||
ctx.createDeserializer()(r1);
|
ctx.createDeserializer()(bitsery::asText(r1));
|
||||||
|
|
||||||
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdString) {
|
TEST(BriefSyntax, CStyleArray)
|
||||||
std::string t1{"my nice string"};
|
{
|
||||||
std::string t2{};
|
const MyEnumClass t1[3]{ MyEnumClass::E1, MyEnumClass::E4, MyEnumClass::E2 };
|
||||||
|
MyEnumClass r1[3]{};
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
SerializationContext ctx;
|
||||||
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
ctx.createSerializer()(t1);
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
ctx.createDeserializer()(r1);
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
|
||||||
|
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdArray) {
|
TEST(BriefSyntax, StdString)
|
||||||
std::array<int, 3> t1{8748, -484, 45};
|
{
|
||||||
std::array<int, 0> 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(t2), Eq(t2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdVector) {
|
TEST(BriefSyntax, StdArray)
|
||||||
std::vector<int> t1{8748, -484, 45};
|
{
|
||||||
std::vector<float> t2{5.f, 0.198f};
|
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));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdList) {
|
TEST(BriefSyntax, StdVector)
|
||||||
std::list<int> t1{8748, -484, 45};
|
{
|
||||||
std::list<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, StdForwardList) {
|
TEST(BriefSyntax, StdList)
|
||||||
std::forward_list<int> t1{8748, -484, 45};
|
{
|
||||||
std::forward_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, StdDeque) {
|
TEST(BriefSyntax, StdForwardList)
|
||||||
std::deque<int> t1{8748, -484, 45};
|
{
|
||||||
std::deque<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, StdQueue) {
|
TEST(BriefSyntax, StdDeque)
|
||||||
std::queue<std::string> t1;
|
{
|
||||||
t1.push("first");
|
std::deque<int> t1{ 8748, -484, 45 };
|
||||||
t1.push("second string");
|
std::deque<float> t2{ 5.f, 0.198f };
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
||||||
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdPriorityQueue) {
|
TEST(BriefSyntax, StdQueue)
|
||||||
std::priority_queue<std::string> t1;
|
{
|
||||||
t1.push("first");
|
std::queue<std::string> t1;
|
||||||
t1.push("second string");
|
t1.push("first");
|
||||||
t1.push("third");
|
t1.push("second string");
|
||||||
t1.push("fourth");
|
|
||||||
auto r1 = procBriefSyntax(t1);
|
|
||||||
//we cannot compare priority queue directly
|
|
||||||
|
|
||||||
EXPECT_THAT(r1.size(), Eq(t1.size()));
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
for (auto i = 0u; i < r1.size(); ++i) {
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
EXPECT_THAT(r1.top(), Eq(t1.top()));
|
|
||||||
r1.pop();
|
|
||||||
t1.pop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdStack) {
|
TEST(BriefSyntax, StdPriorityQueue)
|
||||||
std::stack<std::string> t1;
|
{
|
||||||
t1.push("first");
|
std::priority_queue<std::string> t1;
|
||||||
t1.push("second string");
|
t1.push("first");
|
||||||
|
t1.push("second string");
|
||||||
|
t1.push("third");
|
||||||
|
t1.push("fourth");
|
||||||
|
auto r1 = procBriefSyntax(t1);
|
||||||
|
// we cannot compare priority queue directly
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
EXPECT_THAT(r1.size(), Eq(t1.size()));
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
for (auto i = 0u; i < r1.size(); ++i) {
|
||||||
|
EXPECT_THAT(r1.top(), Eq(t1.top()));
|
||||||
|
r1.pop();
|
||||||
|
t1.pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdUnorderedMap) {
|
TEST(BriefSyntax, StdStack)
|
||||||
std::unordered_map<int, int> t1;
|
{
|
||||||
t1.emplace(3423, 624);
|
std::stack<std::string> t1;
|
||||||
t1.emplace(-5484, -845);
|
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, StdUnorderedMultiMap) {
|
TEST(BriefSyntax, StdUnorderedMap)
|
||||||
std::unordered_multimap<std::string, int> t1;
|
{
|
||||||
t1.emplace("one", 624);
|
std::unordered_map<int, int> t1;
|
||||||
t1.emplace("two", -845);
|
t1.emplace(3423, 624);
|
||||||
t1.emplace("one", 897);
|
t1.emplace(-5484, -845);
|
||||||
|
|
||||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdMap) {
|
TEST(BriefSyntax, StdUnorderedMultiMap)
|
||||||
std::map<int, int> t1;
|
{
|
||||||
t1.emplace(3423, 624);
|
std::unordered_multimap<std::string, int> t1;
|
||||||
t1.emplace(-5484, -845);
|
t1.emplace("one", 624);
|
||||||
|
t1.emplace("two", -845);
|
||||||
|
t1.emplace("one", 897);
|
||||||
|
|
||||||
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
||||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdMultiMap) {
|
TEST(BriefSyntax, StdMap)
|
||||||
std::multimap<std::string, int> t1;
|
{
|
||||||
t1.emplace("one", 624);
|
std::map<int, int> t1;
|
||||||
t1.emplace("two", -845);
|
t1.emplace(3423, 624);
|
||||||
t1.emplace("one", 897);
|
t1.emplace(-5484, -845);
|
||||||
|
|
||||||
auto res = procBriefSyntax(t1);
|
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
|
||||||
//same key values is not ordered, and operator == compares each element at same position
|
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||||
//so we need to compare our selves
|
|
||||||
EXPECT_THAT(res.size(), Eq(3));
|
|
||||||
for (auto it = t1.begin(); it != t1.end();) {
|
|
||||||
const auto lr = t1.equal_range(it->first);
|
|
||||||
const auto rr = res.equal_range(it->first);
|
|
||||||
EXPECT_TRUE(std::distance(lr.first, lr.second) == std::distance(rr.first, rr.second));
|
|
||||||
EXPECT_TRUE(std::is_permutation(lr.first, lr.second, rr.first));
|
|
||||||
it = lr.second;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdUnorderedSet) {
|
TEST(BriefSyntax, StdMultiMap)
|
||||||
std::unordered_set<std::string> t1;
|
{
|
||||||
t1.emplace("one");
|
std::multimap<std::string, int> t1;
|
||||||
t1.emplace("two");
|
t1.emplace("one", 624);
|
||||||
t1.emplace("three");
|
t1.emplace("two", -845);
|
||||||
|
t1.emplace("one", 897);
|
||||||
|
|
||||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
auto res = procBriefSyntax(t1);
|
||||||
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
// same key values is not ordered, and operator == compares each element at
|
||||||
|
// same position so we need to compare our selves
|
||||||
|
EXPECT_THAT(res.size(), Eq(3));
|
||||||
|
for (auto it = t1.begin(); it != t1.end();) {
|
||||||
|
const auto lr = t1.equal_range(it->first);
|
||||||
|
const auto rr = res.equal_range(it->first);
|
||||||
|
EXPECT_TRUE(std::distance(lr.first, lr.second) ==
|
||||||
|
std::distance(rr.first, rr.second));
|
||||||
|
EXPECT_TRUE(std::is_permutation(lr.first, lr.second, rr.first));
|
||||||
|
it = lr.second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdUnorderedMultiSet) {
|
TEST(BriefSyntax, StdUnorderedSet)
|
||||||
std::unordered_multiset<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("one");
|
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, StdSet) {
|
TEST(BriefSyntax, StdUnorderedMultiSet)
|
||||||
std::set<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("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, StdMultiSet) {
|
TEST(BriefSyntax, StdSet)
|
||||||
std::multiset<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("one");
|
t1.emplace("three");
|
||||||
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, StdMultiSet)
|
||||||
std::shared_ptr<int> dataShared1(new int{4});
|
{
|
||||||
std::weak_ptr<int> dataWeak1(dataShared1);
|
std::multiset<std::string> t1;
|
||||||
std::unique_ptr<std::string> dataUnique1{new std::string{"hello world"}};
|
t1.emplace("one");
|
||||||
|
t1.emplace("two");
|
||||||
|
t1.emplace("three");
|
||||||
|
t1.emplace("one");
|
||||||
|
t1.emplace("two");
|
||||||
|
|
||||||
bitsery::ext::PointerLinkingContext plctx1{};
|
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
||||||
BasicSerializationContext<bitsery::ext::PointerLinkingContext> ctx;
|
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
||||||
ctx.createSerializer(plctx1)(dataShared1, dataWeak1, dataUnique1);
|
|
||||||
|
|
||||||
std::shared_ptr<int> resShared1{};
|
|
||||||
std::weak_ptr<int> resWeak1{};
|
|
||||||
std::unique_ptr<std::string> resUnique1{};
|
|
||||||
ctx.createDeserializer(plctx1)(resShared1, resWeak1, resUnique1);
|
|
||||||
//clear shared state from pointer linking context
|
|
||||||
plctx1.clearSharedState();
|
|
||||||
|
|
||||||
EXPECT_TRUE(plctx1.isValid());
|
|
||||||
EXPECT_THAT(*resShared1, Eq(*dataShared1));
|
|
||||||
EXPECT_THAT(*resWeak1.lock(), Eq(*dataWeak1.lock()));
|
|
||||||
EXPECT_THAT(*resUnique1, Eq(*dataUnique1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdDuration) {
|
TEST(BriefSyntax, StdSmartPtr)
|
||||||
std::chrono::duration<int64_t, std::milli> t1{54654};
|
{
|
||||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
std::shared_ptr<int> dataShared1(new int{ 4 });
|
||||||
|
std::weak_ptr<int> dataWeak1(dataShared1);
|
||||||
|
std::unique_ptr<std::string> dataUnique1{ new std::string{ "hello world" } };
|
||||||
|
|
||||||
|
bitsery::ext::PointerLinkingContext plctx1{};
|
||||||
|
BasicSerializationContext<bitsery::ext::PointerLinkingContext> ctx;
|
||||||
|
ctx.createSerializer(plctx1)(dataShared1, dataWeak1, dataUnique1);
|
||||||
|
|
||||||
|
std::shared_ptr<int> resShared1{};
|
||||||
|
std::weak_ptr<int> resWeak1{};
|
||||||
|
std::unique_ptr<std::string> resUnique1{};
|
||||||
|
ctx.createDeserializer(plctx1)(resShared1, resWeak1, resUnique1);
|
||||||
|
// clear shared state from pointer linking context
|
||||||
|
plctx1.clearSharedState();
|
||||||
|
|
||||||
|
EXPECT_TRUE(plctx1.isValid());
|
||||||
|
EXPECT_THAT(*resShared1, Eq(*dataShared1));
|
||||||
|
EXPECT_THAT(*resWeak1.lock(), Eq(*dataWeak1.lock()));
|
||||||
|
EXPECT_THAT(*resUnique1, Eq(*dataUnique1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BriefSyntax, StdTimePoint) {
|
TEST(BriefSyntax, StdDuration)
|
||||||
using Duration = std::chrono::duration<double, std::milli>;
|
{
|
||||||
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
|
std::chrono::duration<int64_t, std::milli> t1{ 54654 };
|
||||||
|
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
||||||
|
}
|
||||||
|
|
||||||
TP data{Duration{874656.4798}};
|
TEST(BriefSyntax, StdTimePoint)
|
||||||
EXPECT_TRUE(procBriefSyntax(data) == data);
|
{
|
||||||
|
using Duration = std::chrono::duration<double, std::milli>;
|
||||||
|
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
|
||||||
|
|
||||||
|
TP data{ Duration{ 874656.4798 } };
|
||||||
|
EXPECT_TRUE(procBriefSyntax(data) == data);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(BriefSyntax, StdAtomic)
|
||||||
|
{
|
||||||
|
std::atomic<int32_t> atm0{ 54654 };
|
||||||
|
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<int32_t>{}, atm0) == atm0);
|
||||||
|
|
||||||
|
std::atomic<bool> atm1{ false };
|
||||||
|
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm1) == atm1);
|
||||||
|
|
||||||
|
std::atomic<bool> atm2{ true };
|
||||||
|
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm2) == atm2);
|
||||||
|
|
||||||
|
std::atomic<uint16_t> atm3;
|
||||||
|
atm3.store(0x1337);
|
||||||
|
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<uint16_t>{}, atm3).load() ==
|
||||||
|
0x1337);
|
||||||
}
|
}
|
||||||
|
|
||||||
#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_CASE(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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user