5 Commits

Author SHA1 Message Date
Mindaugas Vinkelis
d1a47e06e2 change log update for 5.2.3 2022-12-01 14:25:34 +02:00
Mindaugas Vinkelis
3e02d0ca44 format code base in Mozilla style 2022-12-01 13:50:03 +02:00
Mindaugas Vinkelis
d690908541 reworked bitpacking, to fix measure size (measure size now is not
bit-packing enabled by default)
2022-12-01 13:42:02 +02:00
Mindaugas Vinkelis
d3dd64baaf changed increaseBufferSize signature
simplified adapters implementations
2022-04-21 20:01:58 +03:00
museghost
d24e0ab1b3 fix shadow warning in gcc8 (#1) (#87)
Co-authored-by: brian.kim <brian.kim@beatthemarket.co.kr>
2021-10-22 12:44:38 +03:00
116 changed files with 15122 additions and 12645 deletions

192
.clang-format Normal file
View File

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

View File

@@ -53,10 +53,10 @@ jobs:
sudo add-apt-repository ppa:team-xbmc/ppa
sudo apt-get update
sudo apt-get install libgmock-dev
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Configure
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=${{ matrix.config.cxx_ver }}
- name: Build
run: cmake --build build
- name: Run tests
run: ctest --test-dir build/tests
run: ctest --test-dir build

View File

@@ -17,10 +17,10 @@ jobs:
git checkout release-1.11.0
cmake -S . -B build
cmake --build build --target install
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Configure
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17
- name: Build
run: cmake --build build
- name: Run tests
run: ctest --test-dir build/tests
run: ctest --test-dir build

View File

@@ -18,7 +18,7 @@ jobs:
git checkout release-1.11.0
cmake -S . -B build -Dgtest_force_shared_crt=ON
cmake --build build --config Release --target install
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Configure
run: cmake -S . -B build -DBITSERY_BUILD_TESTS=ON -DBITSERY_BUILD_EXAMPLES=ON -DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_FLAGS="/Zc:__cplusplus /permissive- /EHsc"
env:
@@ -26,4 +26,4 @@ jobs:
- name: Build
run: cmake --build build --config Release
- name: Run tests
run: ctest --test-dir build/tests
run: ctest --test-dir build

1
.gitignore vendored
View File

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

View File

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

View File

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

View File

@@ -51,6 +51,7 @@ endif()
if (BITSERY_BUILD_TESTS)
message("build bitsery tests")
enable_testing()
add_subdirectory(tests)
else()
message("skip bitsery tests")

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

3
format.sh Executable file
View File

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

View File

@@ -1,334 +1,295 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_ADAPTER_BUFFER_H
#define BITSERY_ADAPTER_BUFFER_H
#include "../details/adapter_common.h"
#include "../details/adapter_bit_packing.h"
#include "../traits/core/traits.h"
#include <algorithm>
#include <cassert>
#include <cstring>
namespace bitsery {
template<typename Buffer, typename Config = DefaultConfig>
class InputBufferAdapter: public details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer,Config>> {
public:
friend details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer,Config>>;
using TConfig = Config;
using TIterator = typename traits::BufferAdapterTraits<typename std::remove_const<Buffer>::type>::TConstIterator;
using TValue = typename traits::BufferAdapterTraits<typename std::remove_const<Buffer>::type>::TValue;
static_assert(details::IsDefined<TValue>::value,
"Please define BufferAdapterTraits or include from <bitsery/traits/...>");
static_assert(traits::ContainerTraits<typename std::remove_const<Buffer>::type>::isContiguous,
"BufferAdapter only works with contiguous containers");
static_assert(sizeof(TValue) == 1, "BufferAdapter underlying type must be 1byte.");
template<typename Buffer, typename Config = DefaultConfig>
class InputBufferAdapter
: public details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer, Config>>
{
public:
friend details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer, Config>>;
InputBufferAdapter(TIterator beginIt, size_t size)
: _beginIt{beginIt},
_currOffset{0},
_endReadOffset{size},
_bufferSize{size} {
};
using BitPackingEnabled =
details::InputAdapterBitPackingWrapper<InputBufferAdapter<Buffer, Config>>;
using TConfig = Config;
using TIterator = typename traits::BufferAdapterTraits<
typename std::remove_const<Buffer>::type>::TConstIterator;
using TValue = typename traits::BufferAdapterTraits<
typename std::remove_const<Buffer>::type>::TValue;
static_assert(
details::IsDefined<TValue>::value,
"Please define BufferAdapterTraits or include from <bitsery/traits/...>");
static_assert(traits::ContainerTraits<
typename std::remove_const<Buffer>::type>::isContiguous,
"BufferAdapter only works with contiguous containers");
static_assert(sizeof(TValue) == 1,
"BufferAdapter underlying type must be 1byte.");
InputBufferAdapter(TIterator beginIt, TIterator endIt)
:InputBufferAdapter(beginIt, static_cast<size_t>(std::distance(beginIt, endIt))) {
}
InputBufferAdapter(TIterator beginIt, size_t size)
: _beginIt{ beginIt }
, _currOffset{ 0 }
, _endReadOffset{ size }
, _bufferSize{ size } {};
InputBufferAdapter(const InputBufferAdapter&) = delete;
InputBufferAdapter& operator=(const InputBufferAdapter&) = delete;
InputBufferAdapter(TIterator beginIt, TIterator endIt)
: InputBufferAdapter(beginIt,
static_cast<size_t>(std::distance(beginIt, endIt)))
{
}
InputBufferAdapter(InputBufferAdapter&&) = default;
InputBufferAdapter& operator = (InputBufferAdapter&&) = default;
InputBufferAdapter(const InputBufferAdapter&) = delete;
InputBufferAdapter& operator=(const InputBufferAdapter&) = delete;
void currentReadPos(size_t pos) {
currentReadPosChecked(pos, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
InputBufferAdapter(InputBufferAdapter&&) = default;
InputBufferAdapter& operator=(InputBufferAdapter&&) = default;
size_t currentReadPos() const {
return currentReadPosChecked(std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void currentReadPos(size_t pos)
{
currentReadPosChecked(
pos, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void currentReadEndPos(size_t pos) {
// assert that CheckAdapterErrors is enabled, otherwise it will simply will not work even if data and buffer is not corrupted
static_assert(Config::CheckAdapterErrors, "Please enable CheckAdapterErrors to use this functionality.");
if (_bufferSize >= pos && error() == ReaderError::NoError) {
_overflowOnReadEndPos = pos == 0;
if (pos == 0)
pos = _bufferSize;
_endReadOffset = pos;
} else {
error(ReaderError::DataOverflow);
}
}
size_t currentReadPos() const
{
return currentReadPosChecked(
std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
size_t currentReadEndPos() const {
if (_overflowOnReadEndPos)
return 0;
return _endReadOffset;
}
void currentReadEndPos(size_t pos)
{
// assert that CheckAdapterErrors is enabled, otherwise it will simply will
// not work even if data and buffer is not corrupted
static_assert(
Config::CheckAdapterErrors,
"Please enable CheckAdapterErrors to use this functionality.");
if (_bufferSize >= pos && error() == ReaderError::NoError) {
_overflowOnReadEndPos = pos == 0;
if (pos == 0)
pos = _bufferSize;
_endReadOffset = pos;
} else {
error(ReaderError::DataOverflow);
}
}
ReaderError error() const {
return _currOffset <= _endReadOffset
? ReaderError::NoError
: static_cast<ReaderError>(_currOffset - _endReadOffset);
}
size_t currentReadEndPos() const
{
if (_overflowOnReadEndPos)
return 0;
return _endReadOffset;
}
void error(ReaderError error) {
if (_currOffset <= _endReadOffset) {
_endReadOffset = 0;
_bufferSize = 0;
_currOffset = static_cast<size_t>(error);
}
}
ReaderError error() const
{
return _currOffset <= _endReadOffset
? ReaderError::NoError
: static_cast<ReaderError>(_currOffset - _endReadOffset);
}
bool isCompletedSuccessfully() const {
return _currOffset == _bufferSize;
}
void error(ReaderError error)
{
if (_currOffset <= _endReadOffset) {
_endReadOffset = 0;
_bufferSize = 0;
_currOffset = static_cast<size_t>(error);
}
}
private:
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
bool isCompletedSuccessfully() const { return _currOffset == _bufferSize; }
template <size_t SIZE>
void readInternalValue(TValue *data) {
readInternalValueChecked<SIZE>(data, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
private:
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
void readInternalBuffer(TValue *data, size_t size) {
readInternalBufferChecked(data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
template<size_t SIZE>
void readInternalValue(TValue* data)
{
readInternalImpl(
data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
template <size_t SIZE>
void readInternalValueChecked(TValue *data, std::false_type) {
const size_t newOffset = _currOffset + SIZE;
assert(newOffset <= _endReadOffset);
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), SIZE, data);
_currOffset = newOffset;
}
void readInternalBuffer(TValue* data, size_t size)
{
readInternalImpl(
data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
template <size_t SIZE>
void readInternalValueChecked(TValue *data, std::true_type) {
const size_t newOffset = _currOffset + SIZE;
if (newOffset <= _endReadOffset) {
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), SIZE, data);
_currOffset = newOffset;
} else {
//set everything to zeros
std::memset(data, 0, SIZE);
if (_overflowOnReadEndPos)
error(ReaderError::DataOverflow);
}
}
void readInternalImpl(TValue* data, size_t size, std::false_type)
{
const size_t newOffset = _currOffset + size;
assert(newOffset <= _endReadOffset);
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
_currOffset = newOffset;
}
void readInternalBufferChecked(TValue *data, size_t size, std::false_type) {
const size_t newOffset = _currOffset + size;
assert(newOffset <= _endReadOffset);
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
_currOffset = newOffset;
}
void readInternalImpl(TValue* data, size_t size, std::true_type)
{
const size_t newOffset = _currOffset + size;
if (newOffset <= _endReadOffset) {
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
_currOffset = newOffset;
} else {
// set everything to zeros
std::memset(data, 0, size);
if (_overflowOnReadEndPos)
error(ReaderError::DataOverflow);
}
}
void readInternalBufferChecked(TValue *data, size_t size, std::true_type) {
const size_t newOffset = _currOffset + size;
if (newOffset <= _endReadOffset) {
std::copy_n(_beginIt + static_cast<diff_t>(_currOffset), size, data);
_currOffset = newOffset;
} else {
//set everything to zeros
std::memset(data, 0, size);
if (_overflowOnReadEndPos)
error(ReaderError::DataOverflow);
}
}
void currentReadPosChecked(size_t pos, std::true_type)
{
if (_bufferSize >= pos && error() == ReaderError::NoError) {
_currOffset = pos;
} else {
error(ReaderError::DataOverflow);
}
}
void currentReadPosChecked(size_t pos, std::true_type) {
if (_bufferSize >= pos && error() == ReaderError::NoError) {
_currOffset = pos;
} else {
error(ReaderError::DataOverflow);
}
}
void currentReadPosChecked(size_t pos, std::false_type) { _currOffset = pos; }
void currentReadPosChecked(size_t pos, std::false_type) {
_currOffset = pos;
}
size_t currentReadPosChecked(std::true_type) const
{
return error() == ReaderError::NoError ? _currOffset : 0;
}
size_t currentReadPosChecked(std::true_type) const {
return error() == ReaderError::NoError ? _currOffset : 0;
}
size_t currentReadPosChecked(std::false_type) const { return _currOffset; }
size_t currentReadPosChecked(std::false_type) const {
return _currOffset;
}
TIterator _beginIt;
size_t _currOffset;
size_t _endReadOffset;
size_t _bufferSize;
bool _overflowOnReadEndPos = true;
};
template<typename Buffer, typename Config = DefaultConfig>
class OutputBufferAdapter
: public details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer, Config>>
{
public:
friend details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer, Config>>;
TIterator _beginIt;
size_t _currOffset;
size_t _endReadOffset;
size_t _bufferSize;
bool _overflowOnReadEndPos = true;
};
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<
OutputBufferAdapter<Buffer, Config>>;
using TConfig = Config;
using TIterator = typename traits::BufferAdapterTraits<Buffer>::TIterator;
using TValue = typename traits::BufferAdapterTraits<Buffer>::TValue;
template<typename Buffer, typename Config = DefaultConfig>
class OutputBufferAdapter: public details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer,Config>> {
public:
friend details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer,Config>>;
using TConfig = Config;
using TIterator = typename traits::BufferAdapterTraits<Buffer>::TIterator;
using TValue = typename traits::BufferAdapterTraits<Buffer>::TValue;
static_assert(
details::IsDefined<TValue>::value,
"Please define BufferAdapterTraits or include from <bitsery/traits/...>");
static_assert(traits::ContainerTraits<Buffer>::isContiguous,
"BufferAdapter only works with contiguous containers");
static_assert(sizeof(TValue) == 1,
"BufferAdapter underlying type must be 1byte.");
static_assert(details::IsDefined<TValue>::value,
"Please define BufferAdapterTraits or include from <bitsery/traits/...>");
static_assert(traits::ContainerTraits<Buffer>::isContiguous,
"BufferAdapter only works with contiguous containers");
static_assert(sizeof(TValue) == 1, "BufferAdapter underlying type must be 1byte.");
OutputBufferAdapter(Buffer& buffer)
: _buffer{ std::addressof(buffer) }
, _beginIt{ std::begin(buffer) }
, _bufferSize{ traits::ContainerTraits<Buffer>::size(buffer) }
{
}
OutputBufferAdapter(Buffer &buffer)
: _buffer{std::addressof(buffer)},
_beginIt{std::begin(buffer)} {
init(TResizable{});
}
OutputBufferAdapter(const OutputBufferAdapter&) = delete;
OutputBufferAdapter& operator=(const OutputBufferAdapter&) = delete;
OutputBufferAdapter(OutputBufferAdapter&&) = default;
OutputBufferAdapter& operator=(OutputBufferAdapter&&) = default;
OutputBufferAdapter(const OutputBufferAdapter&) = delete;
OutputBufferAdapter& operator=(const OutputBufferAdapter&) = delete;
OutputBufferAdapter(OutputBufferAdapter&&) = default;
OutputBufferAdapter& operator = (OutputBufferAdapter&&) = default;
void currentWritePos(size_t pos)
{
const auto maxPos = _currOffset > pos ? _currOffset : pos;
if (maxPos > _biggestCurrentPos) {
_biggestCurrentPos = maxPos;
}
maybeResize(pos, TResizable{});
_currOffset = pos;
}
void currentWritePos(size_t pos) {
const auto maxPos = _currOffset > pos ? _currOffset : pos;
if (maxPos > _biggestCurrentPos) {
_biggestCurrentPos = maxPos;
}
setCurrentWritePos(pos, TResizable{});
}
size_t currentWritePos() const { return _currOffset; }
size_t currentWritePos() const {
return _currOffset;
}
void flush()
{
// this function might be useful for stream adapters
}
void flush() {
//this function might be useful for stream adapters
}
size_t writtenBytesCount() const
{
return _currOffset > _biggestCurrentPos ? _currOffset : _biggestCurrentPos;
}
size_t writtenBytesCount() const {
return _currOffset > _biggestCurrentPos ? _currOffset : _biggestCurrentPos;
}
private:
using TResizable =
std::integral_constant<bool, traits::ContainerTraits<Buffer>::isResizable>;
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
private:
using TResizable = std::integral_constant<bool, traits::ContainerTraits<Buffer>::isResizable>;
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
template<size_t SIZE>
void writeInternalValue(const TValue* data)
{
writeInternalImpl(data, SIZE);
}
template <size_t SIZE>
void writeInternalValue(const TValue *data) {
writeInternalValueImpl<SIZE>(data, TResizable{});
}
void writeInternalBuffer(const TValue* data, size_t size)
{
writeInternalImpl(data, size);
}
void writeInternalBuffer(const TValue *data, size_t size) {
writeInternalBufferImpl(data, size, TResizable{});
}
Buffer* _buffer;
TIterator _beginIt;
size_t _currOffset{ 0 };
size_t _bufferSize{ 0 };
size_t _biggestCurrentPos{ 0 };
Buffer* _buffer;
TIterator _beginIt;
size_t _currOffset{0};
size_t _bufferSize{0};
size_t _biggestCurrentPos{0};
void maybeResize(size_t newOffset, std::true_type)
{
if (newOffset > _bufferSize) {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(
*_buffer, _currOffset, newOffset);
_beginIt = std::begin(*_buffer);
_bufferSize = traits::ContainerTraits<Buffer>::size(*_buffer);
}
}
/*
* resizable buffer
*/
void maybeResize(size_t newOffset, std::false_type)
{
assert(newOffset <= _bufferSize);
}
void init(std::true_type) {
//resize buffer immediately, because we need output iterator at valid position
if (traits::ContainerTraits<Buffer>::size(*_buffer) == 0u) {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
}
updateIteratorAndSize();
}
template <size_t SIZE>
void writeInternalValueImpl(const TValue *data, std::true_type) {
const size_t newOffset = _currOffset + SIZE;
if (newOffset <= _bufferSize) {
std::copy_n(data, SIZE, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
} else {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
updateIteratorAndSize();
writeInternalValueImpl<SIZE>(data, std::true_type{});
}
}
void writeInternalBufferImpl(const TValue *data, const size_t size, std::true_type) {
const size_t newOffset = _currOffset + size;
if (newOffset <= _bufferSize) {
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
} else {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
updateIteratorAndSize();
writeInternalBufferImpl(data, size, std::true_type{});
}
}
void setCurrentWritePos(size_t pos, std::true_type) {
if (pos <= _bufferSize) {
_currOffset = pos;
} else {
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer);
updateIteratorAndSize();
setCurrentWritePos(pos, std::true_type{});
}
}
/*
* non resizable buffer
*/
void init(std::false_type) {
updateIteratorAndSize();
}
template <size_t SIZE>
void writeInternalValueImpl(const TValue *data, std::false_type) {
const size_t newOffset = _currOffset + SIZE;
assert(newOffset <= _bufferSize);
std::copy_n(data, SIZE, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
}
void writeInternalBufferImpl(const TValue *data, size_t size, std::false_type) {
const size_t newOffset = _currOffset + size;
assert(newOffset <= _bufferSize);
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
}
void setCurrentWritePos(size_t pos, std::false_type) {
assert(pos <= _bufferSize);
_currOffset = pos;
}
void updateIteratorAndSize() {
_beginIt = std::begin(*_buffer);
_bufferSize = traits::ContainerTraits<Buffer>::size(*_buffer);
}
};
void writeInternalImpl(const TValue* data, size_t size)
{
const size_t newOffset = _currOffset + size;
maybeResize(newOffset, TResizable{});
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
}
};
}
#endif //BITSERY_ADAPTER_BUFFER_H
#endif // BITSERY_ADAPTER_BUFFER_H

View File

@@ -1,99 +1,88 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_ADAPTER_MEASURE_SIZE_H
#define BITSERY_ADAPTER_MEASURE_SIZE_H
#include "../details/adapter_bit_packing.h"
#include <cstddef>
#include <type_traits>
#include "../details/adapter_common.h"
namespace bitsery {
template<typename Config>
class BasicMeasureSize
{
public:
using BitPackingEnabled =
details::BasicMeasureSizeBitPackingWrapper<BasicMeasureSize<Config>>;
using TConfig = Config;
using TValue = void;
template<typename Config>
class BasicMeasureSize {
public:
template<size_t SIZE, typename T>
void writeBytes(const T&)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
_currPos += SIZE;
}
static constexpr bool BitPackingEnabled = true;
using TConfig = Config;
using TValue = void;
template<size_t SIZE, typename T>
void writeBuffer(const T*, size_t count)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
_currPos += SIZE * count;
}
template<size_t SIZE, typename T>
void writeBytes(const T&) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
_currPosBits += details::BitsSize<T>::value;
}
void currentWritePos(size_t pos)
{
const auto maxPos = _currPos > pos ? _currPos : pos;
if (maxPos > _biggestCurrentPos) {
_biggestCurrentPos = maxPos;
}
_currPos = pos;
}
template<size_t SIZE, typename T>
void writeBuffer(const T*, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
_currPosBits += details::BitsSize<T>::value * count;
}
size_t currentWritePos() const { return _currPos; }
template<typename T>
void writeBits(const T&, size_t bitsCount) {
static_assert(std::is_integral<T>() && std::is_unsigned<T>(), "");
assert(bitsCount <= details::BitsSize<T>::value);
_currPosBits += bitsCount;
}
void align() {}
void currentWritePos(size_t pos) {
align();
const auto newPos = pos * 8;
if (_currPosBits > newPos)
_prevLargestPos = _currPosBits;
_currPosBits = newPos;
}
void flush() {}
size_t currentWritePos() const {
return _currPosBits / 8;
}
// get size in bytes
size_t writtenBytesCount() const
{
return _currPos > _biggestCurrentPos ? _currPos : _biggestCurrentPos;
}
void align() {
auto _scratch = (_currPosBits % 8);
_currPosBits += (8 - _scratch) % 8;
}
private:
size_t _biggestCurrentPos{};
size_t _currPos{};
};
void flush() {
align();
}
//get size in bytes
size_t writtenBytesCount() const {
const auto max = _currPosBits > _prevLargestPos ? _currPosBits : _prevLargestPos;
return max / 8;
}
private:
size_t _prevLargestPos{};
size_t _currPosBits{};
};
//helper type for default config
using MeasureSize = BasicMeasureSize<DefaultConfig>;
// helper type for default config
using MeasureSize = BasicMeasureSize<DefaultConfig>;
}
#endif //BITSERY_ADAPTER_MEASURE_SIZE_H
#endif // BITSERY_ADAPTER_MEASURE_SIZE_H

View File

@@ -1,298 +1,376 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_ADAPTER_STREAM_H
#define BITSERY_ADAPTER_STREAM_H
#include "../details/adapter_common.h"
#include "../details/adapter_bit_packing.h"
#include "../traits/array.h"
#include <algorithm>
#include <cassert>
#include <ios>
#include <limits>
namespace bitsery {
template <typename TChar, typename Config, typename CharTraits>
class BasicInputStreamAdapter: public details::InputAdapterBaseCRTP<BasicInputStreamAdapter<TChar, Config, CharTraits>> {
public:
friend details::InputAdapterBaseCRTP<BasicInputStreamAdapter<TChar, Config, CharTraits>>;
using TConfig = Config;
using TValue = TChar;
template<typename TChar, typename Config, typename CharTraits>
class BasicInputStreamAdapter
: public details::InputAdapterBaseCRTP<
BasicInputStreamAdapter<TChar, Config, CharTraits>>
{
public:
friend details::InputAdapterBaseCRTP<
BasicInputStreamAdapter<TChar, Config, CharTraits>>;
BasicInputStreamAdapter(std::basic_ios<TChar, CharTraits>& istream)
:_ios{std::addressof(istream)} {}
using BitPackingEnabled = details::InputAdapterBitPackingWrapper<
BasicInputStreamAdapter<TChar, Config, CharTraits>>;
using TConfig = Config;
using TValue = TChar;
BasicInputStreamAdapter(const BasicInputStreamAdapter&) = delete;
BasicInputStreamAdapter& operator = (const BasicInputStreamAdapter&) = delete;
BasicInputStreamAdapter(std::basic_ios<TChar, CharTraits>& istream)
: _ios{ std::addressof(istream) }
{
}
BasicInputStreamAdapter(BasicInputStreamAdapter&&) = default;
BasicInputStreamAdapter& operator = (BasicInputStreamAdapter&&) = default;
BasicInputStreamAdapter(const BasicInputStreamAdapter&) = delete;
BasicInputStreamAdapter& operator=(const BasicInputStreamAdapter&) = delete;
void currentReadPos(size_t ) {
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
}
BasicInputStreamAdapter(BasicInputStreamAdapter&&) = default;
BasicInputStreamAdapter& operator=(BasicInputStreamAdapter&&) = default;
size_t currentReadPos() const {
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
return {};
}
void currentReadPos(size_t)
{
static_assert(std::is_void<TChar>::value,
"setting read position is not supported with StreamAdapter");
}
void currentReadEndPos(size_t ) {
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
}
size_t currentReadPos() const
{
static_assert(std::is_void<TChar>::value,
"setting read position is not supported with StreamAdapter");
return {};
}
size_t currentReadEndPos() const {
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
return {};
}
void currentReadEndPos(size_t)
{
static_assert(std::is_void<TChar>::value,
"setting read position is not supported with StreamAdapter");
}
ReaderError error() const {
return _err;
}
size_t currentReadEndPos() const
{
static_assert(std::is_void<TChar>::value,
"setting read position is not supported with StreamAdapter");
return {};
}
bool isCompletedSuccessfully() const {
if (error() == ReaderError::NoError) {
return _ios->rdbuf()->sgetc() == CharTraits::eof();
}
return false;
}
ReaderError error() const { return _err; }
void error(ReaderError error) {
if (_err == ReaderError::NoError) {
_err = error;
_zeroIfNoErrors = std::numeric_limits<size_t>::max();
}
}
bool isCompletedSuccessfully() const
{
if (error() == ReaderError::NoError) {
return _ios->rdbuf()->sgetc() == CharTraits::eof();
}
return false;
}
private:
void error(ReaderError error)
{
if (_err == ReaderError::NoError) {
_err = error;
_zeroIfNoErrors = std::numeric_limits<size_t>::max();
}
}
template <size_t SIZE>
void readInternalValue(TValue* data) {
readChecked(data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
private:
template<size_t SIZE>
void readInternalValue(TValue* data)
{
readChecked(
data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void readInternalBuffer(TValue* data, size_t size) {
readChecked(data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void readInternalBuffer(TValue* data, size_t size)
{
readChecked(
data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
}
void readChecked(TValue* data, size_t size, std::true_type) {
if (size - static_cast<size_t>(_ios->rdbuf()->sgetn(data, static_cast<std::streamsize>(size))) != _zeroIfNoErrors) {
*data = {};
if (_zeroIfNoErrors == 0) {
error(_ios->rdstate() == std::ios_base::badbit
? ReaderError::ReadingError
: ReaderError::DataOverflow);
}
}
}
void readChecked(TValue* data, size_t size, std::true_type)
{
if (size - static_cast<size_t>(_ios->rdbuf()->sgetn(
data, static_cast<std::streamsize>(size))) !=
_zeroIfNoErrors) {
*data = {};
if (_zeroIfNoErrors == 0) {
error(_ios->rdstate() == std::ios_base::badbit
? ReaderError::ReadingError
: ReaderError::DataOverflow);
}
}
}
void readChecked(TValue* data, size_t size, std::false_type) {
_ios->rdbuf()->sgetn(data , static_cast<std::streamsize>(size));
}
void readChecked(TValue* data, size_t size, std::false_type)
{
_ios->rdbuf()->sgetn(data, static_cast<std::streamsize>(size));
}
std::basic_ios<TChar, CharTraits>* _ios;
size_t _zeroIfNoErrors{};
ReaderError _err = ReaderError::NoError;
};
std::basic_ios<TChar, CharTraits>* _ios;
size_t _zeroIfNoErrors{};
ReaderError _err = ReaderError::NoError;
};
template <typename TChar, typename Config, typename CharTraits>
class BasicOutputStreamAdapter: public details::OutputAdapterBaseCRTP<BasicOutputStreamAdapter<TChar, Config, CharTraits>> {
public:
friend details::OutputAdapterBaseCRTP<BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
using TConfig = Config;
using TValue = TChar;
template<typename TChar, typename Config, typename CharTraits>
class BasicOutputStreamAdapter
: public details::OutputAdapterBaseCRTP<
BasicOutputStreamAdapter<TChar, Config, CharTraits>>
{
public:
friend details::OutputAdapterBaseCRTP<
BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
BasicOutputStreamAdapter(std::basic_ostream<TChar, CharTraits>& ostream)
:_ostream{std::addressof(ostream)} {}
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<
BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
using TConfig = Config;
using TValue = TChar;
void currentWritePos(size_t ) {
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
}
BasicOutputStreamAdapter(std::basic_ostream<TChar, CharTraits>& ostream)
: _ostream{ std::addressof(ostream) }
{
}
size_t currentWritePos() const {
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
return {};
}
void currentWritePos(size_t)
{
static_assert(std::is_void<TChar>::value,
"setting write position is not supported with StreamAdapter");
}
void flush() {
_ostream->flush();
}
size_t currentWritePos() const
{
static_assert(std::is_void<TChar>::value,
"setting write position is not supported with StreamAdapter");
return {};
}
size_t writtenBytesCount() const {
static_assert(std::is_void<TChar>::value, "`writtenBytesCount` cannot be used with stream adapter");
//streaming doesn't return written bytes
return 0u;
}
void flush() { _ostream->flush(); }
private:
size_t writtenBytesCount() const
{
static_assert(std::is_void<TChar>::value,
"`writtenBytesCount` cannot be used with stream adapter");
// streaming doesn't return written bytes
return 0u;
}
template <size_t SIZE>
void writeInternalValue(const TValue* data) {
_ostream->rdbuf()->sputn( data , SIZE );
}
private:
template<size_t SIZE>
void writeInternalValue(const TValue* data)
{
_ostream->rdbuf()->sputn(data, SIZE);
}
void writeInternalBuffer(const TValue* data, size_t size) {
_ostream->rdbuf()->sputn( data , size );
}
void writeInternalBuffer(const TValue* data, size_t size)
{
_ostream->rdbuf()->sputn(data, size);
}
std::basic_ostream<TChar, CharTraits>* _ostream;
};
std::basic_ostream<TChar, CharTraits>* _ostream;
};
template <typename TChar, typename Config, typename CharTraits, typename TBuffer = std::array<TChar, 256>>
class BasicBufferedOutputStreamAdapter:
public details::OutputAdapterBaseCRTP<BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>> {
public:
friend details::OutputAdapterBaseCRTP<BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>;
using TConfig = Config;
using Buffer = TBuffer;
using BufferIt = typename traits::BufferAdapterTraits<TBuffer>::TIterator;
static_assert(details::IsDefined<BufferIt>::value, "Please define BufferAdapterTraits or include from <bitsery/traits/...> to use as buffer for BasicBufferedOutputStreamAdapter");
static_assert(traits::ContainerTraits<Buffer>::isContiguous, "BasicBufferedOutputStreamAdapter only works with contiguous containers");
using TValue = TChar;
template<typename TChar,
typename Config,
typename CharTraits,
typename TBuffer = std::array<TChar, 256>>
class BasicBufferedOutputStreamAdapter
: public details::OutputAdapterBaseCRTP<
BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>
{
public:
friend details::OutputAdapterBaseCRTP<
BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>;
//bufferSize is used when buffer is dynamically allocated
BasicBufferedOutputStreamAdapter(std::basic_ostream<TChar, CharTraits>& ostream, size_t bufferSize = 256)
:_ostream(std::addressof(ostream)),
_buf{},
_beginIt{std::begin(_buf)},
_currOffset{0}
{
init(bufferSize, TResizable{});
// buffer size must be atleast 16, because writeIntervalValue expect that at least one value fits to buffer.
assert(_bufferSize >= 16);
}
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<
BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>;
using TConfig = Config;
using Buffer = TBuffer;
using BufferIt = typename traits::BufferAdapterTraits<TBuffer>::TIterator;
static_assert(
details::IsDefined<BufferIt>::value,
"Please define BufferAdapterTraits or include from <bitsery/traits/...> to "
"use as buffer for BasicBufferedOutputStreamAdapter");
static_assert(
traits::ContainerTraits<Buffer>::isContiguous,
"BasicBufferedOutputStreamAdapter only works with contiguous containers");
using TValue = TChar;
//we need to explicitly declare move logic, because after move buffer might be invalidated
BasicBufferedOutputStreamAdapter(const BasicBufferedOutputStreamAdapter&) = delete;
BasicBufferedOutputStreamAdapter& operator = (const BasicBufferedOutputStreamAdapter&) = delete;
// bufferSize is used when buffer is dynamically allocated
BasicBufferedOutputStreamAdapter(
std::basic_ostream<TChar, CharTraits>& ostream,
size_t bufferSize = 256)
: _ostream(std::addressof(ostream))
, _buf{}
, _beginIt{ std::begin(_buf) }
, _currOffset{ 0 }
{
init(bufferSize, TResizable{});
// buffer size must be atleast 16, because writeIntervalValue expect that at
// least one value fits to buffer.
assert(_bufferSize >= 16);
}
BasicBufferedOutputStreamAdapter(BasicBufferedOutputStreamAdapter&& rhs)
: _ostream{rhs._ostream},
_buf{std::move(rhs._buf)},
_beginIt{std::begin(_buf)},
_currOffset{rhs._currOffset},
_bufferSize{rhs._bufferSize}
{
};
// we need to explicitly declare move logic, because after move buffer might
// be invalidated
BasicBufferedOutputStreamAdapter(const BasicBufferedOutputStreamAdapter&) =
delete;
BasicBufferedOutputStreamAdapter& operator=(
const BasicBufferedOutputStreamAdapter&) = delete;
BasicBufferedOutputStreamAdapter& operator = (BasicBufferedOutputStreamAdapter&& rhs) {
_ostream = rhs._ostream;
_buf = std::move(rhs._buf);
_beginIt = std::begin(_buf);
_currOffset = rhs._currOffset;
_bufferSize = rhs._bufferSize;
return *this;
};
BasicBufferedOutputStreamAdapter(BasicBufferedOutputStreamAdapter&& rhs)
: _ostream{ rhs._ostream }
, _buf{ std::move(rhs._buf) }
, _beginIt{ std::begin(_buf) }
, _currOffset{ rhs._currOffset }
, _bufferSize{ rhs._bufferSize } {};
void currentWritePos(size_t ) {
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
}
BasicBufferedOutputStreamAdapter& operator=(
BasicBufferedOutputStreamAdapter&& rhs)
{
_ostream = rhs._ostream;
_buf = std::move(rhs._buf);
_beginIt = std::begin(_buf);
_currOffset = rhs._currOffset;
_bufferSize = rhs._bufferSize;
return *this;
};
size_t currentWritePos() const {
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
return {};
}
void currentWritePos(size_t)
{
static_assert(std::is_void<TChar>::value,
"setting write position is not supported with StreamAdapter");
}
void flush() {
writeBufferToStream();
_ostream->flush();
}
size_t currentWritePos() const
{
static_assert(std::is_void<TChar>::value,
"setting write position is not supported with StreamAdapter");
return {};
}
size_t writtenBytesCount() const {
static_assert(std::is_void<TChar>::value, "`writtenBytesCount` cannot be used with stream adapter");
//streaming doesn't return written bytes
return 0u;
}
void flush()
{
writeBufferToStream();
_ostream->flush();
}
private:
using TResizable = std::integral_constant<bool, traits::ContainerTraits<TBuffer>::isResizable>;
using diff_t = typename std::iterator_traits<BufferIt>::difference_type;
size_t writtenBytesCount() const
{
static_assert(std::is_void<TChar>::value,
"`writtenBytesCount` cannot be used with stream adapter");
// streaming doesn't return written bytes
return 0u;
}
template <size_t SIZE>
void writeInternalValue(const TValue* data) {
auto newOffset = _currOffset + SIZE;
if (newOffset > _bufferSize) {
writeBufferToStream();
newOffset = SIZE;
}
std::copy_n(data, SIZE, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
}
private:
using TResizable =
std::integral_constant<bool, traits::ContainerTraits<TBuffer>::isResizable>;
using diff_t = typename std::iterator_traits<BufferIt>::difference_type;
void writeInternalBuffer(const TValue* data, size_t size) {
const auto newOffset = _currOffset + size;
if (newOffset <= _bufferSize) {
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
} else {
writeBufferToStream();
// write buffer directly to stream
_ostream->rdbuf()->sputn(data, size);
}
}
template<size_t SIZE>
void writeInternalValue(const TValue* data)
{
writeInternalImpl(data, SIZE);
}
void writeBufferToStream() {
_ostream->rdbuf()->sputn(std::addressof(*_beginIt), static_cast<std::streamsize>(_currOffset));
_currOffset = 0;
}
void writeInternalBuffer(const TValue* data, size_t size)
{
writeInternalImpl(data, size);
}
void init (size_t buffSize, std::true_type) {
// resize buffer
_bufferSize = buffSize;
_buf.resize(_bufferSize);
_beginIt = std::begin(_buf);
}
void init (size_t , std::false_type) {
// ignore buffer size parameter, and instead take actual buffer size
_bufferSize = traits::ContainerTraits<Buffer>::size(_buf);
}
void writeInternalImpl(const TValue* data, size_t size)
{
const auto newOffset = _currOffset + size;
if (newOffset <= _bufferSize) {
std::copy_n(data, size, _beginIt + static_cast<diff_t>(_currOffset));
_currOffset = newOffset;
} else {
writeBufferToStream();
// write buffer directly to stream
_ostream->rdbuf()->sputn(data, static_cast<std::streamsize>(size));
}
}
std::basic_ostream<TChar, CharTraits>* _ostream;
TBuffer _buf;
BufferIt _beginIt;
size_t _currOffset;
size_t _bufferSize{0};
};
void writeBufferToStream()
{
_ostream->rdbuf()->sputn(std::addressof(*_beginIt),
static_cast<std::streamsize>(_currOffset));
_currOffset = 0;
}
template <typename TChar, typename Config, typename CharTraits>
class BasicIOStreamAdapter
: public BasicInputStreamAdapter<TChar, Config, CharTraits>
, public BasicOutputStreamAdapter<TChar, Config, CharTraits>
{
public:
using TValue = TChar;
void init(size_t buffSize, std::true_type)
{
// resize buffer
_bufferSize = buffSize;
_buf.resize(_bufferSize);
_beginIt = std::begin(_buf);
}
void init(size_t, std::false_type)
{
// ignore buffer size parameter, and instead take actual buffer size
_bufferSize = traits::ContainerTraits<Buffer>::size(_buf);
}
//both bases contain reference to same iostream, so no need to do anything
BasicIOStreamAdapter(std::basic_iostream<TChar, CharTraits>& iostream)
:BasicInputStreamAdapter<TChar, Config, CharTraits>{iostream}
,BasicOutputStreamAdapter<TChar, Config, CharTraits>{iostream}
{}
};
std::basic_ostream<TChar, CharTraits>* _ostream;
TBuffer _buf;
BufferIt _beginIt;
size_t _currOffset;
size_t _bufferSize{ 0 };
};
//helper types for most common implementations for std streams
using OutputStreamAdapter = BasicOutputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
using InputStreamAdapter = BasicInputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
using IOStreamAdapter = BasicIOStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
template<typename TChar, typename Config, typename CharTraits>
class BasicIOStreamAdapter
: public BasicInputStreamAdapter<TChar, Config, CharTraits>
, public BasicOutputStreamAdapter<TChar, Config, CharTraits>
{
public:
using TValue = TChar;
using OutputBufferedStreamAdapter = BasicBufferedOutputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
// both bases contain reference to same iostream, so no need to do anything
BasicIOStreamAdapter(std::basic_iostream<TChar, CharTraits>& iostream)
: BasicInputStreamAdapter<TChar, Config, CharTraits>{ iostream }
, BasicOutputStreamAdapter<TChar, Config, CharTraits>{ iostream }
{
}
};
// helper types for most common implementations for std streams
using OutputStreamAdapter =
BasicOutputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
using InputStreamAdapter =
BasicInputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
using IOStreamAdapter =
BasicIOStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
using OutputBufferedStreamAdapter =
BasicBufferedOutputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
}
#endif //BITSERY_ADAPTER_STREAM_H
#endif // BITSERY_ADAPTER_STREAM_H

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BITSERY_H
#define BITSERY_BITSERY_H
@@ -29,15 +28,15 @@
#define BITSERY_PATCH_VERSION 2
#define BITSERY_QUOTE_MACRO(name) #name
#define BITSERY_BUILD_VERSION_STR(major,minor, patch) \
BITSERY_QUOTE_MACRO(major) "." \
BITSERY_QUOTE_MACRO(minor) "." \
BITSERY_QUOTE_MACRO(patch)
#define BITSERY_BUILD_VERSION_STR(major, minor, patch) \
BITSERY_QUOTE_MACRO(major) \
"." BITSERY_QUOTE_MACRO(minor) "." BITSERY_QUOTE_MACRO(patch)
#define BITSERY_VERSION \
BITSERY_BUILD_VERSION_STR(BITSERY_MAJOR_VERSION, BITSERY_MINOR_VERSION, BITSERY_PATCH_VERSION)
#define BITSERY_VERSION \
BITSERY_BUILD_VERSION_STR( \
BITSERY_MAJOR_VERSION, BITSERY_MINOR_VERSION, BITSERY_PATCH_VERSION)
#include "serializer.h"
#include "deserializer.h"
#include "serializer.h"
#endif //BITSERY_BITSERY_H
#endif // BITSERY_BITSERY_H

View File

@@ -1,94 +1,126 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_H
#define BITSERY_BRIEF_SYNTAX_H
#include "details/serialization_common.h"
#include "details/brief_syntax_common.h"
#include "details/serialization_common.h"
namespace bitsery {
//define function that enables s(....) usage
template<typename S, typename T>
void processBriefSyntax(S& s, T&& head) {
static_assert(std::is_lvalue_reference<T>::value || std::is_base_of<brief_syntax::ModFnc, T>::value,
"Argument must be either lvalue or subclass of brief_syntax::ModFnc");
s.object(head);
}
// define function that enables s(....) usage
template<typename S, typename T>
void
processBriefSyntax(S& s, T&& head)
{
static_assert(
std::is_lvalue_reference<T>::value ||
std::is_base_of<brief_syntax::ModFnc, T>::value,
"Argument must be either lvalue or subclass of brief_syntax::ModFnc");
s.object(head);
}
//wrapper functions that enables to serialize as container or string
template<typename T, size_t N>
brief_syntax::CArray<T, N, true> asText(T (& str)[N]) {
return {str};
}
// wrapper functions that enables to serialize as container or string
template<typename T, size_t N>
brief_syntax::CArray<T, N, true>
asText(T (&str)[N])
{
return { str };
}
template<typename T, size_t N>
brief_syntax::CArray<T, N, false> asContainer(T (& obj)[N]) {
return {obj};
}
template<typename T, size_t N>
brief_syntax::CArray<T, N, false>
asContainer(T (&obj)[N])
{
return { obj };
}
template<typename T>
brief_syntax::MaxSize<T> maxSize(T& obj, size_t max) {
return {obj, max};
}
template<typename T>
brief_syntax::MaxSize<T>
maxSize(T& obj, size_t max)
{
return { obj, max };
}
//define serialize function for fundamental types
template<typename S>
void serialize(S& s, bool& v) {
s.boolValue(v);
}
// define serialize function for fundamental types
template<typename S>
void
serialize(S& s, bool& v)
{
s.boolValue(v);
}
template<typename S, typename T, typename std::enable_if<details::IsFundamentalType<T>::value>::type * = nullptr>
void serialize(S& s, T& v) {
s.template value<sizeof(T)>(v);
}
template<typename S,
typename T,
typename std::enable_if<details::IsFundamentalType<T>::value>::type* =
nullptr>
void
serialize(S& s, T& v)
{
s.template value<sizeof(T)>(v);
}
//define serialization for c-style container
// define serialization for c-style container
//if array is integral type, specify explicitly how to process: as text or container
template<typename S, typename T, size_t N, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
void serialize(S&, T (&)[N]) {
static_assert(N == 0,
"\nPlease use 'asText(obj)' or 'asContainer(obj)' when using c-style array with integral types\n");
}
// if array is integral type, specify explicitly how to process: as text or
// container
template<typename S,
typename T,
size_t N,
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
void
serialize(S&, T (&)[N])
{
static_assert(N == 0,
"\nPlease use 'asText(obj)' or 'asContainer(obj)' when using "
"c-style array with integral types\n");
}
template<typename S, typename T, size_t N, typename std::enable_if<!std::is_integral<T>::value>::type * = nullptr>
void serialize(S& s, T (& obj)[N]) {
brief_syntax::processContainer(s, obj);
}
template<typename S,
typename T,
size_t N,
typename std::enable_if<!std::is_integral<T>::value>::type* = nullptr>
void
serialize(S& s, T (&obj)[N])
{
brief_syntax::processContainer(s, obj);
}
//this is a helper class that enforce fundamental type sizes, when used on multiple platforms
template<size_t TShort, size_t TInt, size_t TLong, size_t TLongLong>
void assertFundamentalTypeSizes() {
//http://en.cppreference.com/w/cpp/language/types
static_assert(sizeof(short) == TShort, "");
static_assert(sizeof(int) == TInt, "");
static_assert(sizeof(long) == TLong, "");
static_assert(sizeof(long long) == TLongLong, "");
//for completion we also need pointer type size, but serializer doesn't support pointer serialization.
}
// this is a helper class that enforce fundamental type sizes, when used on
// multiple platforms
template<size_t TShort, size_t TInt, size_t TLong, size_t TLongLong>
void
assertFundamentalTypeSizes()
{
// http://en.cppreference.com/w/cpp/language/types
static_assert(sizeof(short) == TShort, "");
static_assert(sizeof(int) == TInt, "");
static_assert(sizeof(long) == TLong, "");
static_assert(sizeof(long long) == TLongLong, "");
// for completion we also need pointer type size, but serializer doesn't
// support pointer serialization.
}
}
#endif //BITSERY_BRIEF_SYNTAX_H
#endif // BITSERY_BRIEF_SYNTAX_H

View File

@@ -1,37 +1,38 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_ARRAY_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_ARRAY_H
#include "../traits/array.h"
#include "../details/brief_syntax_common.h"
#include "../traits/array.h"
namespace bitsery {
template<typename S, typename T, size_t N>
void serialize(S &s, std::array<T, N> &obj) {
brief_syntax::processContainer(s, obj);
}
template<typename S, typename T, size_t N>
void
serialize(S& s, std::array<T, N>& obj)
{
brief_syntax::processContainer(s, obj);
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_ARRAY_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_ARRAY_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2020 Nick Renieris
// Copyright (c) 2020 Nick Renieris
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_ATOMIC_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_ATOMIC_H
@@ -26,10 +26,12 @@
#include "../ext/std_atomic.h"
namespace bitsery {
template<typename S, typename T>
void serialize(S &s, std::atomic<T> &obj) {
s.template ext<sizeof(T)>(obj, ext::StdAtomic{});
}
template<typename S, typename T>
void
serialize(S& s, std::atomic<T>& obj)
{
s.template ext<sizeof(T)>(obj, ext::StdAtomic{});
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_ATOMIC_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_ATOMIC_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_CHRONO_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_CHRONO_H
@@ -26,15 +26,19 @@
#include "../ext/std_chrono.h"
namespace bitsery {
template<typename S, typename T, typename P>
void serialize(S &s, std::chrono::duration<T, P> &obj) {
s.template ext<sizeof(T)>(obj, ext::StdDuration{});
}
template<typename S, typename C, typename T, typename P>
void serialize(S &s, std::chrono::time_point<C, std::chrono::duration<T, P>> &obj) {
s.template ext<sizeof(T)>(obj, ext::StdTimePoint{});
}
template<typename S, typename T, typename P>
void
serialize(S& s, std::chrono::duration<T, P>& obj)
{
s.template ext<sizeof(T)>(obj, ext::StdDuration{});
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_CHRONO_H
template<typename S, typename C, typename T, typename P>
void
serialize(S& s, std::chrono::time_point<C, std::chrono::duration<T, P>>& obj)
{
s.template ext<sizeof(T)>(obj, ext::StdTimePoint{});
}
}
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_CHRONO_H

View File

@@ -1,37 +1,38 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_DEQUE_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_DEQUE_H
#include "../traits/deque.h"
#include "../details/brief_syntax_common.h"
#include "../traits/deque.h"
namespace bitsery {
template<typename S, typename T, typename Allocator>
void serialize(S &s, std::deque<T, Allocator> &obj) {
brief_syntax::processContainer(s, obj);
}
template<typename S, typename T, typename Allocator>
void
serialize(S& s, std::deque<T, Allocator>& obj)
{
brief_syntax::processContainer(s, obj);
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_DEQUE_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_DEQUE_H

View File

@@ -1,37 +1,38 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_FORWARD_LIST_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_FORWARD_LIST_H
#include "../traits/forward_list.h"
#include "../details/brief_syntax_common.h"
#include "../traits/forward_list.h"
namespace bitsery {
template<typename S, typename T, typename Allocator>
void serialize(S &s, std::forward_list<T, Allocator> &obj) {
brief_syntax::processContainer(s, obj);
}
template<typename S, typename T, typename Allocator>
void
serialize(S& s, std::forward_list<T, Allocator>& obj)
{
brief_syntax::processContainer(s, obj);
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_FORWARD_LIST_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_FORWARD_LIST_H

View File

@@ -1,37 +1,38 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_LIST_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_LIST_H
#include "../traits/list.h"
#include "../details/brief_syntax_common.h"
#include "../traits/list.h"
namespace bitsery {
template<typename S, typename T, typename Allocator>
void serialize(S &s, std::list<T, Allocator> &obj) {
brief_syntax::processContainer(s, obj);
}
template<typename S, typename T, typename Allocator>
void
serialize(S& s, std::list<T, Allocator>& obj)
{
brief_syntax::processContainer(s, obj);
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_LIST_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_LIST_H

View File

@@ -1,51 +1,64 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_MAP_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_MAP_H
#include <map>
#include <limits>
#include "../ext/std_map.h"
#include <limits>
#include <map>
namespace bitsery {
template<typename S, typename Key, typename T, typename Compare, typename Allocator>
void serialize(S &s, std::map<Key, T, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdMap{maxSize},
[](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
template<typename S, typename Key, typename T, typename Compare, typename Allocator>
void serialize(S &s, std::multimap<Key, T, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdMap{maxSize},
[](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
template<typename S,
typename Key,
typename T,
typename Compare,
typename Allocator>
void
serialize(S& s,
std::map<Key, T, Compare, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdMap{ maxSize }, [](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_MAP_H
template<typename S,
typename Key,
typename T,
typename Compare,
typename Allocator>
void
serialize(S& s,
std::multimap<Key, T, Compare, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdMap{ maxSize }, [](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
}
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_MAP_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2018 Mindaugas Vinkelis
// Copyright (c) 2018 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_MEMORY_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_MEMORY_H
@@ -26,20 +26,26 @@
#include "../ext/std_smart_ptr.h"
namespace bitsery {
template<typename S, typename T, typename D>
void serialize(S &s, std::unique_ptr<T, D> &obj) {
s.ext(obj, ext::StdSmartPtr{});
}
template<typename S, typename T>
void serialize(S &s, std::shared_ptr<T> &obj) {
s.ext(obj, ext::StdSmartPtr{});
}
template<typename S, typename T>
void serialize(S &s, std::weak_ptr<T> &obj) {
s.ext(obj, ext::StdSmartPtr{});
}
template<typename S, typename T, typename D>
void
serialize(S& s, std::unique_ptr<T, D>& obj)
{
s.ext(obj, ext::StdSmartPtr{});
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_MEMORY_H
template<typename S, typename T>
void
serialize(S& s, std::shared_ptr<T>& obj)
{
s.ext(obj, ext::StdSmartPtr{});
}
template<typename S, typename T>
void
serialize(S& s, std::weak_ptr<T>& obj)
{
s.ext(obj, ext::StdSmartPtr{});
}
}
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_MEMORY_H

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_QUEUE_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_QUEUE_H
@@ -28,16 +27,24 @@
#include <limits>
namespace bitsery {
template<typename S, typename T, typename C>
void serialize(S &s, std::queue<T, C> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdQueue{maxSize});
}
template<typename S, typename T, typename C>
void
serialize(S& s,
std::queue<T, C>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdQueue{ maxSize });
}
template<typename S, typename T, typename C, typename Comp>
void serialize(S &s, std::priority_queue<T, C, Comp> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdQueue{maxSize});
}
template<typename S, typename T, typename C, typename Comp>
void
serialize(S& s,
std::priority_queue<T, C, Comp>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdQueue{ maxSize });
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_QUEUE_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_QUEUE_H

View File

@@ -1,44 +1,51 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_SET_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_SET_H
#include <set>
#include <limits>
#include "../ext/std_set.h"
#include <limits>
#include <set>
namespace bitsery {
template<typename S, typename Key, typename Compare, typename Allocator>
void serialize(S &s, std::set<Key, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdSet{maxSize});
}
template<typename S, typename Key, typename Compare, typename Allocator>
void
serialize(S& s,
std::set<Key, Compare, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdSet{ maxSize });
}
template<typename S, typename Key, typename Compare, typename Allocator>
void serialize(S &s, std::multiset<Key, Compare, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdSet{maxSize});
}
template<typename S, typename Key, typename Compare, typename Allocator>
void
serialize(S& s,
std::multiset<Key, Compare, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdSet{ maxSize });
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_SET_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_SET_H

View File

@@ -1,37 +1,40 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_STACK_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_STACK_H
#include <limits>
#include "../ext/std_stack.h"
#include <limits>
namespace bitsery {
template<typename S, typename T, typename C>
void serialize(S &s, std::stack<T, C> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdStack{maxSize});
}
template<typename S, typename T, typename C>
void
serialize(S& s,
std::stack<T, C>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdStack{ maxSize });
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_STACK_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_STACK_H

View File

@@ -1,37 +1,38 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_STRING_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_STRING_H
#include "../traits/string.h"
#include "../details/brief_syntax_common.h"
#include "../traits/string.h"
namespace bitsery {
template<typename S, typename CharT, typename Traits, typename Allocator>
void serialize(S &s, std::basic_string<CharT, Traits, Allocator> &str) {
brief_syntax::processContainer(s, str);
}
template<typename S, typename CharT, typename Traits, typename Allocator>
void
serialize(S& s, std::basic_string<CharT, Traits, Allocator>& str)
{
brief_syntax::processContainer(s, str);
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_STRING_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_STRING_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_TUPLE_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_TUPLE_H
@@ -26,10 +26,12 @@
#include "../ext/std_tuple.h"
namespace bitsery {
template<typename S, typename ...Ts>
void serialize(S &s, std::tuple<Ts...> &obj) {
s.ext(obj, ext::StdTuple{});
}
template<typename S, typename... Ts>
void
serialize(S& s, std::tuple<Ts...>& obj)
{
s.ext(obj, ext::StdTuple{});
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_TUPLE_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_TUPLE_H

View File

@@ -1,52 +1,67 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_MAP_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_MAP_H
#include <unordered_map>
#include <limits>
#include "../ext/std_map.h"
#include <limits>
#include <unordered_map>
namespace bitsery {
template<typename S, typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
void serialize(S &s, std::unordered_map<Key, T, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdMap{maxSize},
[](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
template<typename S,
typename Key,
typename T,
typename Hash,
typename KeyEqual,
typename Allocator>
void
serialize(S& s,
std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdMap{ maxSize }, [](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
template<typename S, typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
void serialize(S &s, std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdMap{maxSize},
[](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
template<typename S,
typename Key,
typename T,
typename Hash,
typename KeyEqual,
typename Allocator>
void
serialize(S& s,
std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdMap{ maxSize }, [](S& s, Key& key, T& value) {
s.object(key);
s.object(value);
});
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_MAP_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_MAP_H

View File

@@ -1,44 +1,59 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_SET_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_SET_H
#include "../ext/std_set.h"
#include <limits>
#include <unordered_set>
#include "../ext/std_set.h"
namespace bitsery {
template<typename S, typename Key, typename Hash, typename KeyEqual, typename Allocator>
void serialize(S &s, std::unordered_set<Key, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdSet{maxSize});
}
template<typename S,
typename Key,
typename Hash,
typename KeyEqual,
typename Allocator>
void
serialize(S& s,
std::unordered_set<Key, Hash, KeyEqual, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdSet{ maxSize });
}
template<typename S, typename Key, typename Hash, typename KeyEqual, typename Allocator>
void serialize(S &s, std::unordered_multiset<Key, Hash, KeyEqual, Allocator> &obj, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.ext(obj, ext::StdSet{maxSize});
}
template<typename S,
typename Key,
typename Hash,
typename KeyEqual,
typename Allocator>
void
serialize(S& s,
std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& obj,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.ext(obj, ext::StdSet{ maxSize });
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_SET_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_UNORDERED_SET_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_VARIANT_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_VARIANT_H
@@ -26,10 +26,12 @@
#include "../ext/std_variant.h"
namespace bitsery {
template<typename S, typename ...Ts>
void serialize(S &s, std::variant<Ts...> &obj) {
s.ext(obj, ext::StdVariant{});
}
template<typename S, typename... Ts>
void
serialize(S& s, std::variant<Ts...>& obj)
{
s.ext(obj, ext::StdVariant{});
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_VARIANT_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_VARIANT_H

View File

@@ -1,37 +1,38 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_BRIEF_SYNTAX_TYPE_STD_VECTOR_H
#define BITSERY_BRIEF_SYNTAX_TYPE_STD_VECTOR_H
#include "../traits/vector.h"
#include "../details/brief_syntax_common.h"
#include "../traits/vector.h"
namespace bitsery {
template<typename S, typename T, typename Allocator>
void serialize(S &s, std::vector<T, Allocator> &obj) {
brief_syntax::processContainer(s, obj);
}
template<typename S, typename T, typename Allocator>
void
serialize(S& s, std::vector<T, Allocator>& obj)
{
brief_syntax::processContainer(s, obj);
}
}
#endif //BITSERY_BRIEF_SYNTAX_TYPE_STD_VECTOR_H
#endif // BITSERY_BRIEF_SYNTAX_TYPE_STD_VECTOR_H

View File

@@ -1,52 +1,54 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_COMMON_H
#define BITSERY_COMMON_H
#include <tuple>
namespace bitsery {
/*
* endianness
*/
enum class EndiannessType {
LittleEndian,
BigEndian
};
enum class EndiannessType
{
LittleEndian,
BigEndian
};
// default configuration for serialization and deserialization
struct DefaultConfig {
// defines endianness of data that is read from input adapter and written to output adapter.
static constexpr EndiannessType Endianness = EndiannessType::LittleEndian;
// these flags allow to improve deserialization performance if data is trusted
// enables/disables checks for buffer end or stream read errors in input adapter
static constexpr bool CheckAdapterErrors = true;
// enables/disables checks for other errors that can significantly affect performance
static constexpr bool CheckDataErrors = true;
};
// default configuration for serialization and deserialization
struct DefaultConfig
{
// defines endianness of data that is read from input adapter and written to
// output adapter.
static constexpr EndiannessType Endianness = EndiannessType::LittleEndian;
// these flags allow to improve deserialization performance if data is trusted
// enables/disables checks for buffer end or stream read errors in input
// adapter
static constexpr bool CheckAdapterErrors = true;
// enables/disables checks for other errors that can significantly affect
// performance
static constexpr bool CheckDataErrors = true;
};
}
#endif //BITSERY_COMMON_H
#endif // BITSERY_COMMON_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,379 @@
// MIT License
//
// Copyright (c) 2022 Mindaugas Vinkelis
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_DETAILS_ADAPTER_BIT_PACKING_H
#define BITSERY_DETAILS_ADAPTER_BIT_PACKING_H
#include "../common.h"
#include "./adapter_common.h"
#include "not_defined_type.h"
#include <limits>
namespace bitsery {
namespace details {
template<typename TAdapter>
class InputAdapterBitPackingWrapper
{
public:
// in order to check if adapter is BP enabled, we use `std::is_same<Adapter,
// typename Adapter::BitPackingEnabled>` so when current implementation is BP
// enabled, we always specify current class as BitPackingEnabled.
using BitPackingEnabled = InputAdapterBitPackingWrapper<TAdapter>;
using TConfig = typename TAdapter::TConfig;
using TValue = typename TAdapter::TValue;
InputAdapterBitPackingWrapper(TAdapter& adapter)
: _wrapped{ adapter }
{
}
~InputAdapterBitPackingWrapper() { align(); }
template<size_t SIZE, typename T>
void readBytes(T& v)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
using UT = typename std::make_unsigned<T>::type;
if (!m_scratchBits)
this->_wrapped.template readBytes<SIZE, T>(v);
else
readBits(reinterpret_cast<UT&>(v), details::BitsSize<T>::value);
}
template<size_t SIZE, typename T>
void readBuffer(T* buf, size_t count)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
if (!m_scratchBits) {
this->_wrapped.template readBuffer<SIZE, T>(buf, count);
} else {
using UT = typename std::make_unsigned<T>::type;
// todo improve implementation
const auto end = buf + count;
for (auto it = buf; it != end; ++it)
readBits(reinterpret_cast<UT&>(*it), details::BitsSize<T>::value);
}
}
template<typename T>
void readBits(T& v, size_t bitsCount)
{
static_assert(std::is_integral<T>() && std::is_unsigned<T>(), "");
readBitsInternal(v, bitsCount);
}
void align()
{
if (m_scratchBits) {
ScratchType tmp{};
readBitsInternal(tmp, m_scratchBits);
handleAlignErrors(
tmp, std::integral_constant<bool, TConfig::CheckDataErrors>{});
}
}
void currentReadPos(size_t pos)
{
align();
this->_wrapped.currentReadPos(pos);
}
size_t currentReadPos() const { return this->_wrapped.currentReadPos(); }
void currentReadEndPos(size_t pos) { this->_wrapped.currentReadEndPos(pos); }
size_t currentReadEndPos() const
{
return this->_wrapped.currentReadEndPos();
}
bool isCompletedSuccessfully() const
{
return this->_wrapped.isCompletedSuccessfully();
}
ReaderError error() const { return this->_wrapped.error(); }
void error(ReaderError error) { this->_wrapped.error(error); }
private:
TAdapter& _wrapped;
using UnsignedValue =
typename std::make_unsigned<typename TAdapter::TValue>::type;
using ScratchType = typename details::ScratchType<UnsignedValue>::type;
ScratchType m_scratch{};
size_t m_scratchBits{};
template<typename T>
void readBitsInternal(T& v, size_t size)
{
auto bitsLeft = size;
using TFast = typename FastType<T>::type;
TFast res{};
while (bitsLeft > 0) {
auto bits = (std::min)(bitsLeft, details::BitsSize<UnsignedValue>::value);
if (m_scratchBits < bits) {
UnsignedValue tmp;
this->_wrapped.template readBytes<sizeof(UnsignedValue), UnsignedValue>(
tmp);
m_scratch |= static_cast<ScratchType>(tmp) << m_scratchBits;
m_scratchBits += details::BitsSize<UnsignedValue>::value;
}
auto shiftedRes =
static_cast<T>(m_scratch & ((static_cast<ScratchType>(1) << bits) - 1))
<< (size - bitsLeft);
res = static_cast<TFast>(res | static_cast<TFast>(shiftedRes));
m_scratch >>= bits;
m_scratchBits -= bits;
bitsLeft -= bits;
}
v = static_cast<T>(res);
}
void handleAlignErrors(ScratchType value, std::true_type)
{
if (value)
error(ReaderError::InvalidData);
}
void handleAlignErrors(ScratchType, std::false_type) {}
};
template<typename TAdapter>
class BasicMeasureSizeBitPackingWrapper
{
public:
using BitPackingEnabled = BasicMeasureSizeBitPackingWrapper<TAdapter>;
using TConfig = typename TAdapter::TConfig;
using TValue = typename TAdapter::TValue;
BasicMeasureSizeBitPackingWrapper(TAdapter& adapter)
: _wrapped{ adapter }
{
}
~BasicMeasureSizeBitPackingWrapper() { align(); }
template<size_t SIZE, typename T>
void writeBytes(const T& value)
{
_wrapped.template writeBytes<SIZE>(value);
}
template<size_t SIZE, typename T>
void writeBuffer(const T* buf, size_t count)
{
_wrapped.template writeBuffer<SIZE>(buf, count);
}
template<typename T>
void writeBits(const T&, size_t bitsCount)
{
_scratchBits += bitsCount;
while (_scratchBits >= 8) {
writeOneByte();
_scratchBits -= 8;
}
}
void align()
{
if (_scratchBits > 0) {
_scratchBits = 0;
writeOneByte();
}
}
void currentWritePos(size_t pos)
{
align();
this->_wrapped.currentWritePos(pos);
}
size_t currentWritePos() const { return this->_wrapped.currentWritePos(); }
void flush()
{
align();
this->_wrapped.flush();
}
size_t writtenBytesCount() const
{
return this->_wrapped.writtenBytesCount();
}
private:
void writeOneByte() { _wrapped.template writeBytes<1>(uint8_t{}); }
TAdapter& _wrapped;
size_t _scratchBits{};
};
template<typename TAdapter>
class OutputAdapterBitPackingWrapper
{
public:
// in order to check if adapter is BP enabled, we use `std::is_same<Adapter,
// typename Adapter::BitPackingEnabled>` so when current implementation is BP
// enabled, we always specify current class as BitPackingEnabled.
using BitPackingEnabled = OutputAdapterBitPackingWrapper<TAdapter>;
using TConfig = typename TAdapter::TConfig;
using TValue = typename TAdapter::TValue;
OutputAdapterBitPackingWrapper(TAdapter& adapter)
: _wrapped{ adapter }
{
}
~OutputAdapterBitPackingWrapper() { align(); }
template<size_t SIZE, typename T>
void writeBytes(const T& v)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
if (!_scratchBits) {
this->_wrapped.template writeBytes<SIZE, T>(v);
} else {
using UT = typename std::make_unsigned<T>::type;
writeBitsInternal(reinterpret_cast<const UT&>(v),
details::BitsSize<T>::value);
}
}
template<size_t SIZE, typename T>
void writeBuffer(const T* buf, size_t count)
{
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
if (!_scratchBits) {
this->_wrapped.template writeBuffer<SIZE, T>(buf, count);
} else {
using UT = typename std::make_unsigned<T>::type;
// todo improve implementation
const auto end = buf + count;
for (auto it = buf; it != end; ++it)
writeBitsInternal(reinterpret_cast<const UT&>(*it),
details::BitsSize<T>::value);
}
}
template<typename T>
void writeBits(const T& v, size_t bitsCount)
{
static_assert(std::is_integral<T>() && std::is_unsigned<T>(), "");
assert(0 < bitsCount && bitsCount <= details::BitsSize<T>::value);
assert(v <= (bitsCount < 64 ? (1ULL << bitsCount) - 1
: (1ULL << (bitsCount - 1)) +
((1ULL << (bitsCount - 1)) - 1)));
writeBitsInternal(v, bitsCount);
}
void align()
{
writeBitsInternal(UnsignedType{},
(details::BitsSize<UnsignedType>::value - _scratchBits) %
8);
}
void currentWritePos(size_t pos)
{
align();
this->_wrapped.currentWritePos(pos);
}
size_t currentWritePos() const { return this->_wrapped.currentWritePos(); }
void flush()
{
align();
this->_wrapped.flush();
}
size_t writtenBytesCount() const
{
return this->_wrapped.writtenBytesCount();
}
private:
TAdapter& _wrapped;
using UnsignedType =
typename std::make_unsigned<typename TAdapter::TValue>::type;
using ScratchType = typename details::ScratchType<UnsignedType>::type;
static_assert(details::IsDefined<ScratchType>::value,
"Underlying adapter value type is not supported");
template<typename T>
void writeBitsInternal(const T& v, size_t size)
{
constexpr size_t valueSize = details::BitsSize<UnsignedType>::value;
T value = v;
size_t bitsLeft = size;
while (bitsLeft > 0) {
auto bits = (std::min)(bitsLeft, valueSize);
_scratch |= static_cast<ScratchType>(value) << _scratchBits;
_scratchBits += bits;
if (_scratchBits >= valueSize) {
auto tmp = static_cast<UnsignedType>(_scratch & _MASK);
this->_wrapped.template writeBytes<sizeof(UnsignedType), UnsignedType>(
tmp);
_scratch >>= valueSize;
_scratchBits -= valueSize;
value = static_cast<T>(value >> valueSize);
}
bitsLeft -= bits;
}
}
// overload for TValue, for better performance
void writeBitsInternal(const UnsignedType& v, size_t size)
{
if (size > 0) {
_scratch |= static_cast<ScratchType>(v) << _scratchBits;
_scratchBits += size;
if (_scratchBits >= details::BitsSize<UnsignedType>::value) {
auto tmp = static_cast<UnsignedType>(_scratch & _MASK);
this->_wrapped.template writeBytes<sizeof(UnsignedType), UnsignedType>(
tmp);
_scratch >>= details::BitsSize<UnsignedType>::value;
_scratchBits -= details::BitsSize<UnsignedType>::value;
}
}
}
const UnsignedType _MASK = (std::numeric_limits<UnsignedType>::max)();
ScratchType _scratch{};
size_t _scratchBits{};
};
}
}
#endif // BITSERY_DETAILS_ADAPTER_BIT_PACKING_H

View File

@@ -1,371 +1,427 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_DETAILS_ADAPTER_COMMON_H
#define BITSERY_DETAILS_ADAPTER_COMMON_H
#include <algorithm>
#include <utility>
#include <cassert>
#include <vector>
#include <stack>
#include <cstring>
#include <climits>
#include "not_defined_type.h"
#include "../common.h"
#include "not_defined_type.h"
#include <algorithm>
#include <cassert>
#include <climits>
namespace bitsery {
enum class ReaderError {
NoError,
ReadingError, // this might be used with stream adapter
DataOverflow,
InvalidData,
InvalidPointer
};
enum class ReaderError
{
NoError,
ReadingError, // this might be used with stream adapter
DataOverflow,
InvalidData,
InvalidPointer
};
namespace details {
namespace details {
/**
* size read/write functions
*/
template <typename Reader, typename TCheckMaxSize>
void readSize(Reader& r, size_t& size, size_t maxSize, TCheckMaxSize) {
uint8_t hb{};
r.template readBytes<1>(hb);
if (hb < 0x80u) {
size = hb;
} else {
uint8_t lb{};
r.template readBytes<1>(lb);
if (hb & 0x40u) {
uint16_t lw{};
r.template readBytes<2>(lw);
size = ((((hb & 0x3Fu) << 8) | lb) << 16) | lw;
} else {
size = ((hb & 0x7Fu) << 8) | lb;
}
}
handleReadMaxSize(r, size, maxSize, TCheckMaxSize{});
}
/**
* size read/write functions
*/
template <typename Reader>
void handleReadMaxSize(Reader& r, size_t& size, size_t maxSize, std::true_type) {
if (size > maxSize) {
r.error(ReaderError::InvalidData);
size = {};
}
}
template <typename Reader>
void handleReadMaxSize(Reader&, size_t&, size_t, std::false_type) {
}
template <typename Writer>
void writeSize(Writer& w, const size_t size) {
if (size < 0x80u) {
w.template writeBytes<1>(static_cast<uint8_t>(size));
} else {
if (size < 0x4000u) {
w.template writeBytes<1>(static_cast<uint8_t>((size >> 8) | 0x80u));
w.template writeBytes<1>(static_cast<uint8_t>(size));
} else {
assert(size < 0x40000000u);
w.template writeBytes<1>(static_cast<uint8_t>((size >> 24) | 0xC0u));
w.template writeBytes<1>(static_cast<uint8_t>(size >> 16));
w.template writeBytes<2>(static_cast<uint16_t>(size));
}
}
}
/**
* swap utils
*/
//add swap functions to class, to avoid compilation warning about unused functions
struct SwapImpl {
static uint64_t exec(uint64_t value) {
#ifdef __GNUC__
return __builtin_bswap64(value);
#else
value = ( value & 0x00000000FFFFFFFF ) << 32 | ( value & 0xFFFFFFFF00000000 ) >> 32;
value = ( value & 0x0000FFFF0000FFFF ) << 16 | ( value & 0xFFFF0000FFFF0000 ) >> 16;
value = ( value & 0x00FF00FF00FF00FF ) << 8 | ( value & 0xFF00FF00FF00FF00 ) >> 8;
return value;
#endif
}
static uint32_t exec(uint32_t value) {
#ifdef __GNUC__
return __builtin_bswap32(value);
#else
return ( value & 0x000000ff ) << 24 | ( value & 0x0000ff00 ) << 8 | ( value & 0x00ff0000 ) >> 8 | ( value & 0xff000000 ) >> 24;
#endif
}
static uint16_t exec(uint16_t value) {
return static_cast<uint16_t>((value & 0x00ff) << 8 | (value & 0xff00) >> 8);
}
static uint8_t exec(uint8_t value) {
return value;
}
};
template<typename TValue>
TValue swap(TValue value) {
constexpr size_t TSize = sizeof(TValue);
using UT = typename std::conditional<TSize == 1, uint8_t,
typename std::conditional<TSize == 2, uint16_t,
typename std::conditional<TSize == 4, uint32_t, uint64_t>::type>::type>::type;
return static_cast<TValue>(SwapImpl::exec(static_cast<UT>(value)));
}
/**
* endianness utils
*/
// add test data in separate struct, because some compilers only support constexpr functions with return-only body
// suppress msvc warnings.
#ifdef _MSC_VER
#pragma warning( disable : 4310 )
#endif
struct EndiannessTestData {
static constexpr uint32_t _sample4Bytes = 0x01020304;
static constexpr uint8_t _sample1stByte = (const uint8_t &) _sample4Bytes;
};
#ifdef _MSC_VER
#pragma warning( default : 4310 )
#endif
constexpr EndiannessType getSystemEndianness() {
static_assert(EndiannessTestData::_sample1stByte == 0x04 || EndiannessTestData::_sample1stByte == 0x01,
"system must be either little or big endian");
return EndiannessTestData::_sample1stByte == 0x04 ? EndiannessType::LittleEndian
: EndiannessType::BigEndian;
}
template <typename Config>
using ShouldSwap = std::integral_constant<bool, Config::Endianness != details::getSystemEndianness()>;
/**
* helper types to work with bits
*/
template<typename T>
struct BitsSize:public std::integral_constant<size_t, sizeof(T) * 8> {
static_assert(CHAR_BIT == 8, "only support systems with byte size of 8 bits");
};
template<typename T>
struct ScratchType {
using type = NotDefinedType;
};
template<>
struct ScratchType<uint8_t> {
using type = uint_fast16_t;
};
template<typename T>
struct FastType {
using type = T;
};
template<>
struct FastType<uint8_t> {
using type = uint_fast8_t;
};
template<>
struct FastType<uint16_t> {
using type = uint_fast16_t;
};
template<>
struct FastType<uint32_t> {
using type = uint_fast32_t;
};
template<>
struct FastType<uint64_t> {
using type = uint_fast64_t;
};
template<>
struct FastType<int8_t> {
using type = int_fast8_t;
};
template<>
struct FastType<int16_t> {
using type = int_fast16_t;
};
template<>
struct FastType<int32_t> {
using type = int_fast32_t;
};
template<>
struct FastType<int64_t> {
using type = int_fast64_t;
};
/**
* output/input adapter base that handles endianness
*/
template<typename Adapter>
struct OutputAdapterBaseCRTP {
static constexpr bool BitPackingEnabled = false;
template<size_t SIZE, typename T>
void writeBytes(const T &v) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
writeSwappedValue(&v, ShouldSwap<typename Adapter::TConfig>{});
}
template<size_t SIZE, typename T>
void writeBuffer(const T *buf, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
writeSwappedBuffer(buf, count, ShouldSwap<typename Adapter::TConfig>{});
}
template<typename T>
void writeBits(const T &, size_t ) {
static_assert(std::is_void<T>::value,
"Bit-packing is not enabled.\nEnable by call to `enableBitPacking`) or create Serializer with bit packing enabled.");
}
void align() {
}
OutputAdapterBaseCRTP() = default;
OutputAdapterBaseCRTP(const OutputAdapterBaseCRTP&) = delete;
OutputAdapterBaseCRTP& operator = (const OutputAdapterBaseCRTP&) = delete;
OutputAdapterBaseCRTP(OutputAdapterBaseCRTP&&) = default;
OutputAdapterBaseCRTP& operator = (OutputAdapterBaseCRTP&&) = default;
private:
template<typename T>
void writeSwappedValue(const T *v, std::true_type) {
const auto res = details::swap(*v);
static_cast<Adapter*>(this)->template writeInternalValue<sizeof(T)>(reinterpret_cast<const typename Adapter::TValue *>(&res));
}
template<typename T>
void writeSwappedValue(const T *v, std::false_type) {
static_cast<Adapter*>(this)->template writeInternalValue<sizeof(T)>(reinterpret_cast<const typename Adapter::TValue *>(v));
}
template<typename T>
void writeSwappedBuffer(const T *v, size_t count, std::true_type) {
std::for_each(v, std::next(v, count), [this](const T &v) {
const auto res = details::swap(v);
static_cast<Adapter*>(this)->template writeInternalValue<sizeof(T)>(reinterpret_cast<const typename Adapter::TValue *>(&res));
});
}
template<typename T>
void writeSwappedBuffer(const T *v, size_t count, std::false_type) {
static_cast<Adapter*>(this)->writeInternalBuffer(reinterpret_cast<const typename Adapter::TValue *>(v), count * sizeof(T));
}
};
template <typename Base>
struct InputAdapterBaseCRTP {
static constexpr bool BitPackingEnabled = false;
template<size_t SIZE, typename T>
void readBytes(T& v) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
static_cast<Base*>(this)->template readInternalValue<sizeof(T)>(reinterpret_cast<typename Base::TValue *>(&v));
swapDataBits(v, ShouldSwap<typename Base::TConfig>{});
}
template<size_t SIZE, typename T>
void readBuffer(T* buf, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
static_cast<Base*>(this)->readInternalBuffer(reinterpret_cast<typename Base::TValue *>(buf), sizeof(T) * count);
swapDataBits(buf, count, ShouldSwap<typename Base::TConfig>{});
}
template<typename T>
void readBits(T&, size_t) {
static_assert(std::is_void<T>::value,
"Bit-packing is not enabled.\nEnable by call to `enableBitPacking`) or create Deserializer with bit packing enabled.");
}
void align() {
}
InputAdapterBaseCRTP() = default;
InputAdapterBaseCRTP(const InputAdapterBaseCRTP&) = delete;
InputAdapterBaseCRTP& operator = (const InputAdapterBaseCRTP&) = delete;
InputAdapterBaseCRTP(InputAdapterBaseCRTP&&) = default;
InputAdapterBaseCRTP& operator = (InputAdapterBaseCRTP&&) = default;
virtual ~InputAdapterBaseCRTP() = default;
private:
template<typename T>
void swapDataBits(T *v, size_t count, std::true_type) {
using diff_t = typename std::iterator_traits<T*>::difference_type;
std::for_each(v, std::next(v, static_cast<diff_t>(count)), [](T &x) { x = details::swap(x); });
}
template<typename T>
void swapDataBits(T *, size_t , std::false_type) {
//empty function because no swap is required
}
template<typename T>
void swapDataBits(T &v, std::true_type) {
v = details::swap(v);
}
template<typename T>
void swapDataBits(T &, std::false_type) {
//empty function because no swap is required
}
};
}
template<typename Reader>
void
handleReadMaxSize(Reader& r, size_t& size, size_t maxSize, std::true_type)
{
if (size > maxSize) {
r.error(ReaderError::InvalidData);
size = {};
}
}
template<typename Reader>
void
handleReadMaxSize(Reader&, size_t&, size_t, std::false_type)
{
}
#endif //BITSERY_DETAILS_ADAPTER_COMMON_H
template<typename Reader, bool CheckMaxSize>
void
readSize(Reader& r,
size_t& size,
size_t maxSize,
std::integral_constant<bool, CheckMaxSize> checkMaxSize)
{
uint8_t hb{};
r.template readBytes<1>(hb);
if (hb < 0x80u) {
size = hb;
} else {
uint8_t lb{};
r.template readBytes<1>(lb);
if (hb & 0x40u) {
uint16_t lw{};
r.template readBytes<2>(lw);
size = ((((hb & 0x3Fu) << 8) | lb) << 16) | lw;
} else {
size = ((hb & 0x7Fu) << 8) | lb;
}
}
handleReadMaxSize(r, size, maxSize, checkMaxSize);
}
template<typename Writer>
void
writeSize(Writer& w, const size_t size)
{
if (size < 0x80u) {
w.template writeBytes<1>(static_cast<uint8_t>(size));
} else {
if (size < 0x4000u) {
w.template writeBytes<1>(static_cast<uint8_t>((size >> 8) | 0x80u));
w.template writeBytes<1>(static_cast<uint8_t>(size));
} else {
assert(size < 0x40000000u);
w.template writeBytes<1>(static_cast<uint8_t>((size >> 24) | 0xC0u));
w.template writeBytes<1>(static_cast<uint8_t>(size >> 16));
w.template writeBytes<2>(static_cast<uint16_t>(size));
}
}
}
/**
* swap utils
*/
// add swap functions to class, to avoid compilation warning about unused
// functions
struct SwapImpl
{
static uint64_t exec(uint64_t value)
{
#ifdef __GNUC__
return __builtin_bswap64(value);
#else
value =
(value & 0x00000000FFFFFFFF) << 32 | (value & 0xFFFFFFFF00000000) >> 32;
value =
(value & 0x0000FFFF0000FFFF) << 16 | (value & 0xFFFF0000FFFF0000) >> 16;
value =
(value & 0x00FF00FF00FF00FF) << 8 | (value & 0xFF00FF00FF00FF00) >> 8;
return value;
#endif
}
static uint32_t exec(uint32_t value)
{
#ifdef __GNUC__
return __builtin_bswap32(value);
#else
return (value & 0x000000ff) << 24 | (value & 0x0000ff00) << 8 |
(value & 0x00ff0000) >> 8 | (value & 0xff000000) >> 24;
#endif
}
static uint16_t exec(uint16_t value)
{
return static_cast<uint16_t>((value & 0x00ff) << 8 | (value & 0xff00) >> 8);
}
static uint8_t exec(uint8_t value)
{
return value;
}
};
template<typename TValue>
TValue
swap(TValue value)
{
constexpr size_t TSize = sizeof(TValue);
using UT = typename std::conditional<
TSize == 1,
uint8_t,
typename std::conditional<
TSize == 2,
uint16_t,
typename std::conditional<TSize == 4, uint32_t, uint64_t>::type>::type>::
type;
return static_cast<TValue>(SwapImpl::exec(static_cast<UT>(value)));
}
/**
* endianness utils
*/
// add test data in separate struct, because some compilers only support
// constexpr functions with return-only body suppress msvc warnings.
#ifdef _MSC_VER
#pragma warning(disable : 4310)
#endif
struct EndiannessTestData
{
static constexpr uint32_t _sample4Bytes = 0x01020304;
static constexpr uint8_t _sample1stByte = (const uint8_t&)_sample4Bytes;
};
#ifdef _MSC_VER
#pragma warning(default : 4310)
#endif
constexpr EndiannessType
getSystemEndianness()
{
static_assert(EndiannessTestData::_sample1stByte == 0x04 ||
EndiannessTestData::_sample1stByte == 0x01,
"system must be either little or big endian");
return EndiannessTestData::_sample1stByte == 0x04
? EndiannessType::LittleEndian
: EndiannessType::BigEndian;
}
template<typename Config>
using ShouldSwap =
std::integral_constant<bool,
Config::Endianness != details::getSystemEndianness()>;
/**
* helper types to work with bits
*/
template<typename T>
struct BitsSize : public std::integral_constant<size_t, sizeof(T) * 8>
{
static_assert(CHAR_BIT == 8, "only support systems with byte size of 8 bits");
};
template<typename T>
struct ScratchType
{
using type = NotDefinedType;
};
template<>
struct ScratchType<uint8_t>
{
using type = uint_fast16_t;
};
template<typename T>
struct FastType
{
using type = T;
};
template<>
struct FastType<uint8_t>
{
using type = uint_fast8_t;
};
template<>
struct FastType<uint16_t>
{
using type = uint_fast16_t;
};
template<>
struct FastType<uint32_t>
{
using type = uint_fast32_t;
};
template<>
struct FastType<uint64_t>
{
using type = uint_fast64_t;
};
template<>
struct FastType<int8_t>
{
using type = int_fast8_t;
};
template<>
struct FastType<int16_t>
{
using type = int_fast16_t;
};
template<>
struct FastType<int32_t>
{
using type = int_fast32_t;
};
template<>
struct FastType<int64_t>
{
using type = int_fast64_t;
};
/**
* output/input adapter base that handles endianness
*/
template<typename Adapter>
struct OutputAdapterBaseCRTP
{
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& 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>{});
}
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>{});
}
template<typename T>
void readBits(T&, size_t)
{
static_assert(
std::is_void<T>::value,
"Bit-packing is not enabled.\nEnable by call to `enableBitPacking`) or "
"create Deserializer with bit packing enabled.");
}
void align() {}
InputAdapterBaseCRTP() = default;
InputAdapterBaseCRTP(const InputAdapterBaseCRTP&) = delete;
InputAdapterBaseCRTP& operator=(const InputAdapterBaseCRTP&) = delete;
InputAdapterBaseCRTP(InputAdapterBaseCRTP&&) = default;
InputAdapterBaseCRTP& operator=(InputAdapterBaseCRTP&&) = default;
virtual ~InputAdapterBaseCRTP() = default;
private:
template<typename T>
void swapDataBits(T* v, size_t count, std::true_type)
{
using diff_t = typename std::iterator_traits<T*>::difference_type;
std::for_each(v, std::next(v, static_cast<diff_t>(count)), [](T& x) {
x = details::swap(x);
});
}
template<typename T>
void swapDataBits(T*, size_t, std::false_type)
{
// empty function because no swap is required
}
template<typename T>
void swapDataBits(T& v, std::true_type)
{
v = details::swap(v);
}
template<typename T>
void swapDataBits(T&, std::false_type)
{
// empty function because no swap is required
}
};
}
}
#endif // BITSERY_DETAILS_ADAPTER_COMMON_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_DETAILS_BRIEF_SYNTAX_COMMON_H
#define BITSERY_DETAILS_BRIEF_SYNTAX_COMMON_H
@@ -28,123 +28,173 @@
#include <limits>
namespace bitsery {
namespace brief_syntax {
namespace brief_syntax {
//these function overloads is required to apply maxSize, and optimize for fundamental types
//for contigous arrays of fundamenal types, memcpy will be applied
// these function overloads is required to apply maxSize, and optimize for
// fundamental types for contigous arrays of fundamenal types, memcpy will be
// applied
template<typename S, typename T, typename std::enable_if<
details::IsFundamentalType<typename traits::ContainerTraits<T>::TValue>::value
&& traits::ContainerTraits<T>::isResizable
>::type * = nullptr>
void processContainer(S &s, T &c, size_t maxSize = std::numeric_limits<size_t>::max()) {
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template container<sizeof(TValue)>(c, maxSize);
}
template<typename S, typename T, typename std::enable_if<
!details::IsFundamentalType<typename traits::ContainerTraits<T>::TValue>::value
&& traits::ContainerTraits<T>::isResizable
>::type * = nullptr>
void processContainer(S &s, T &c, size_t maxSize = std::numeric_limits<size_t>::max()) {
s.container(c, maxSize);
}
template<typename S, typename T, typename std::enable_if<
details::IsFundamentalType<typename traits::ContainerTraits<T>::TValue>::value
&& !traits::ContainerTraits<T>::isResizable
>::type * = nullptr>
void processContainer(S &s, T &c) {
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template container<sizeof(TValue)>(c);
}
template<typename S, typename T, typename std::enable_if<
!details::IsFundamentalType<typename traits::ContainerTraits<T>::TValue>::value
&& !traits::ContainerTraits<T>::isResizable
>::type * = nullptr>
void processContainer(S &s, T &c) {
s.container(c);
}
//overloads for text processing to apply maxSize
template<typename S, typename T, typename std::enable_if<
traits::ContainerTraits<T>::isResizable>::type * = nullptr>
void processText(S &s, T &c, size_t maxSize = std::numeric_limits<size_t>::max()) {
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template text<sizeof(TValue)>(c, maxSize);
}
template<typename S, typename T, typename std::enable_if<
!traits::ContainerTraits<T>::isResizable>::type * = nullptr>
void processText(S &s, T &c) {
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template text<sizeof(TValue)>(c);
}
//all wrapper functions, that modify behaviour, should inherit from this
struct ModFnc {
};
//this type is used to differentiate between container and text behaviour
template<typename T, size_t N, bool isText>
struct CArray : public ModFnc {
CArray(T (&data_)[N]) : data{data_} {};
T (&data)[N];
};
template<typename S, typename T, size_t N>
void serialize(S &s, CArray<T, N, true> &str) {
processText(s, str.data);
}
template<typename S, typename T, size_t N>
void serialize(S &s, CArray<T, N, false> &obj) {
processContainer(s, obj.data);
}
//used to set max container size
template<typename T>
struct MaxSize : public ModFnc {
MaxSize(T &data_, size_t maxSize_) : data{data_}, maxSize{maxSize_} {};
T &data;
size_t maxSize;
};
//if container, then call procesContainer, this memcpy for fundamental types contiguous container
template<typename S, typename T>
void processMaxSize(S &s, T& data, size_t maxSize, std::true_type) {
processContainer(s, data, maxSize);
}
//overload for const T&
template<typename S, typename T>
void processMaxSize(S &s, const T& data, size_t maxSize, std::true_type) {
processContainer(s, const_cast<T&>(data), maxSize);
}
//try to call serialize overload with maxsize, extensions use this technique
template<typename S, typename T>
void processMaxSize(S &s, T& data, size_t maxSize, std::false_type) {
serialize(s, data, maxSize);
}
//overload for const T&
template<typename S, typename T>
void processMaxSize(S &s, const T& data, size_t maxSize, std::false_type) {
serialize(s, const_cast<T&>(data), maxSize);
}
template<typename S, typename T>
void serialize(S &s, const MaxSize<T> &ms) {
processMaxSize(s, ms.data, ms.maxSize, details::IsContainerTraitsDefined<typename std::decay<T>::type>{});
}
}
template<typename S,
typename T,
typename std::enable_if<
details::IsFundamentalType<
typename traits::ContainerTraits<T>::TValue>::value &&
traits::ContainerTraits<T>::isResizable>::type* = nullptr>
void
processContainer(S& s,
T& c,
size_t maxSize = std::numeric_limits<size_t>::max())
{
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template container<sizeof(TValue)>(c, maxSize);
}
#endif //BITSERY_DETAILS_BRIEF_SYNTAX_COMMON_H
template<typename S,
typename T,
typename std::enable_if<
!details::IsFundamentalType<
typename traits::ContainerTraits<T>::TValue>::value &&
traits::ContainerTraits<T>::isResizable>::type* = nullptr>
void
processContainer(S& s,
T& c,
size_t maxSize = std::numeric_limits<size_t>::max())
{
s.container(c, maxSize);
}
template<typename S,
typename T,
typename std::enable_if<
details::IsFundamentalType<
typename traits::ContainerTraits<T>::TValue>::value &&
!traits::ContainerTraits<T>::isResizable>::type* = nullptr>
void
processContainer(S& s, T& c)
{
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template container<sizeof(TValue)>(c);
}
template<typename S,
typename T,
typename std::enable_if<
!details::IsFundamentalType<
typename traits::ContainerTraits<T>::TValue>::value &&
!traits::ContainerTraits<T>::isResizable>::type* = nullptr>
void
processContainer(S& s, T& c)
{
s.container(c);
}
// overloads for text processing to apply maxSize
template<typename S,
typename T,
typename std::enable_if<
traits::ContainerTraits<T>::isResizable>::type* = nullptr>
void
processText(S& s, T& c, size_t maxSize = std::numeric_limits<size_t>::max())
{
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template text<sizeof(TValue)>(c, maxSize);
}
template<typename S,
typename T,
typename std::enable_if<
!traits::ContainerTraits<T>::isResizable>::type* = nullptr>
void
processText(S& s, T& c)
{
using TValue = typename traits::ContainerTraits<T>::TValue;
s.template text<sizeof(TValue)>(c);
}
// all wrapper functions, that modify behaviour, should inherit from this
struct ModFnc
{};
// this type is used to differentiate between container and text behaviour
template<typename T, size_t N, bool isText>
struct CArray : public ModFnc
{
CArray(T (&data_)[N])
: data{ data_ } {};
T (&data)[N];
};
template<typename S, typename T, size_t N>
void
serialize(S& s, CArray<T, N, true>& str)
{
processText(s, str.data);
}
template<typename S, typename T, size_t N>
void
serialize(S& s, CArray<T, N, false>& obj)
{
processContainer(s, obj.data);
}
// used to set max container size
template<typename T>
struct MaxSize : public ModFnc
{
MaxSize(T& data_, size_t maxSize_)
: data{ data_ }
, maxSize{ maxSize_ } {};
T& data;
size_t maxSize;
};
// if container, then call procesContainer, this memcpy for fundamental types
// contiguous container
template<typename S, typename T>
void
processMaxSize(S& s, T& data, size_t maxSize, std::true_type)
{
processContainer(s, data, maxSize);
}
// overload for const T&
template<typename S, typename T>
void
processMaxSize(S& s, const T& data, size_t maxSize, std::true_type)
{
processContainer(s, const_cast<T&>(data), maxSize);
}
// try to call serialize overload with maxsize, extensions use this technique
template<typename S, typename T>
void
processMaxSize(S& s, T& data, size_t maxSize, std::false_type)
{
serialize(s, data, maxSize);
}
// overload for const T&
template<typename S, typename T>
void
processMaxSize(S& s, const T& data, size_t maxSize, std::false_type)
{
serialize(s, const_cast<T&>(data), maxSize);
}
template<typename S, typename T>
void
serialize(S& s, const MaxSize<T>& ms)
{
processMaxSize(
s,
ms.data,
ms.maxSize,
details::IsContainerTraitsDefined<typename std::decay<T>::type>{});
}
}
}
#endif // BITSERY_DETAILS_BRIEF_SYNTAX_COMMON_H

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_DETAILS_NOT_DEFINED_TYPE_H
#define BITSERY_DETAILS_NOT_DEFINED_TYPE_H
@@ -27,53 +26,57 @@
#include <iterator>
namespace bitsery {
namespace details {
//this type is used to show clearer error messages
struct NotDefinedType {
//just swallow anything that is passed during creating
template <typename ... T>
NotDefinedType(T&& ...){}
NotDefinedType() = default;
//define operators so that we also swallow deeper errors, to reduce error stack
//this time will be used as iterator, so define all operators necessary to work with iterators
friend bool operator == (const NotDefinedType&, const NotDefinedType&) {
return true;
}
friend bool operator != (const NotDefinedType&, const NotDefinedType&) {
return false;
}
NotDefinedType& operator += (int) {
return *this;
}
NotDefinedType& operator -= (int) {
return *this;
}
namespace details {
// this type is used to show clearer error messages
struct NotDefinedType
{
// just swallow anything that is passed during creating
template<typename... T>
NotDefinedType(T&&...)
{
}
NotDefinedType() = default;
// define operators so that we also swallow deeper errors, to reduce error
// stack this time will be used as iterator, so define all operators necessary
// to work with iterators
friend bool operator==(const NotDefinedType&, const NotDefinedType&)
{
return true;
}
friend bool operator!=(const NotDefinedType&, const NotDefinedType&)
{
return false;
}
NotDefinedType& operator+=(int) { return *this; }
NotDefinedType& operator-=(int) { return *this; }
friend int operator - (const NotDefinedType&, const NotDefinedType&) {
return 0;
}
friend int operator-(const NotDefinedType&, const NotDefinedType&)
{
return 0;
}
int& operator*() {
return data;
}
int data{};
};
int& operator*() { return data; }
int data{};
};
template <typename T>
struct IsDefined:public std::integral_constant<bool, !std::is_same<NotDefinedType, T>::value> {
};
}
template<typename T>
struct IsDefined
: public std::integral_constant<bool, !std::is_same<NotDefinedType, T>::value>
{
};
}
}
namespace std {
//define iterator traits to work with standart algorithms
template <>
struct iterator_traits<bitsery::details::NotDefinedType> {
using difference_type = int;
using value_type = int;
using pointer = int*;
using reference = int&;
using iterator_category = std::random_access_iterator_tag;
};
// define iterator traits to work with standart algorithms
template<>
struct iterator_traits<bitsery::details::NotDefinedType>
{
using difference_type = int;
using value_type = int;
using pointer = int*;
using reference = int&;
using iterator_category = std::random_access_iterator_tag;
};
}
#endif //BITSERY_DETAILS_NOT_DEFINED_TYPE_H
#endif // BITSERY_DETAILS_NOT_DEFINED_TYPE_H

View File

@@ -1,467 +1,563 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_DETAILS_SERIALIZATION_COMMON_H
#define BITSERY_DETAILS_SERIALIZATION_COMMON_H
#include <type_traits>
#include <utility>
#include <tuple>
#include "adapter_common.h"
#include "../traits/core/traits.h"
#include "adapter_common.h"
#include <tuple>
namespace bitsery {
//this allows to call private serialize method, and construct instance (if no default constructor is provided) for your type
//just make friend it in your class
class Access {
public:
template<typename S, typename T>
static auto serialize(S &s, T &obj) -> decltype(obj.serialize(s)) {
obj.serialize(s);
}
// this allows to call private serialize method, and construct instance (if no
// default constructor is provided) for your type just make friend it in your
// class
class Access
{
public:
template<typename S, typename T>
static auto serialize(S& s, T& obj) -> decltype(obj.serialize(s))
{
obj.serialize(s);
}
template <typename T>
static T create() {
//if you get an error here, please create default constructor
return T{};
}
template <typename T>
static T* create(void* ptr) {
return new(ptr) T{};
}
template<typename T>
static T create()
{
// if you get an error here, please create default constructor
return T{};
}
template<typename T>
static T* create(void* ptr)
{
return new (ptr) T{};
}
};
};
// convenient functors that can be passed as lambda to serializer/deserializer
// instead of writing lambda e.g. instead of writing this: s.container(c, 100,
// [](S& s, float& v) { s.ext4b(v, CompactValue{});}); you can write like this
// s.container(c, 100, FtorExtValue2b<CompactValue>{});
template<size_t N, typename Ext>
struct FtorExtValue : public Ext
{
template<typename S, typename T>
void operator()(S& s, T& v) const
{
s.template ext<N>(v, static_cast<const Ext&>(*this));
}
};
template<typename Ext>
struct FtorExtValue1b : FtorExtValue<1, Ext>
{
};
template<typename Ext>
struct FtorExtValue2b : FtorExtValue<2, Ext>
{
};
template<typename Ext>
struct FtorExtValue4b : FtorExtValue<4, Ext>
{
};
template<typename Ext>
struct FtorExtValue8b : FtorExtValue<8, Ext>
{
};
template<typename Ext>
struct FtorExtValue16b : FtorExtValue<16, Ext>
{
};
// convenient functors that can be passed as lambda to serializer/deserializer instead of writing lambda
// e.g. instead of writing this:
// s.container(c, 100, [](S& s, float& v) { s.ext4b(v, CompactValue{});});
// you can write like this
// s.container(c, 100, FtorExtValue2b<CompactValue>{});
template<size_t N, typename Ext>
struct FtorExtValue : public Ext {
template <typename S, typename T>
void operator()(S& s, T& v) const {
s.template ext<N>(v, static_cast<const Ext&>(*this));
}
};
template<typename Ext>
struct FtorExtObject : public Ext
{
template<typename S, typename T>
void operator()(S& s, T& v) const
{
s.ext(v, static_cast<const Ext&>(*this));
}
};
template <typename Ext>
struct FtorExtValue1b: FtorExtValue<1, Ext> {};
template <typename Ext>
struct FtorExtValue2b: FtorExtValue<2, Ext> {};
template <typename Ext>
struct FtorExtValue4b: FtorExtValue<4, Ext> {};
template <typename Ext>
struct FtorExtValue8b: FtorExtValue<8, Ext> {};
template <typename Ext>
struct FtorExtValue16b: FtorExtValue<16, Ext> {};
// when call to serialize function is ambiguous (member and non-member serialize
// function exists for a type) specialize this class by inheriting from either
// UseNonMemberFnc or UseMemberFnc e.g. template <> struct
// SelectSerializeFnc<MyDerivedClass>:UseMemberFnc {};
template<typename T>
struct SelectSerializeFnc : std::integral_constant<int, 0>
{
};
template<typename Ext>
struct FtorExtObject : public Ext {
template <typename S, typename T>
void operator()(S& s, T& v) const {
s.ext(v, static_cast<const Ext&>(*this));
}
};
// types you need to inherit from when specializing SelectSerializeFnc class
struct UseNonMemberFnc : std::integral_constant<int, 1>
{};
struct UseMemberFnc : std::integral_constant<int, 2>
{};
namespace details {
//when call to serialize function is ambiguous (member and non-member serialize function exists for a type)
//specialize this class by inheriting from either UseNonMemberFnc or UseMemberFnc
//e.g.
//template <> struct SelectSerializeFnc<MyDerivedClass>:UseMemberFnc {};
template<typename T>
struct SelectSerializeFnc : std::integral_constant<int, 0> {
};
// helper types for error handling
template<typename T>
struct IsContainerTraitsDefined
: public IsDefined<typename traits::ContainerTraits<T>::TValue>
{
};
//types you need to inherit from when specializing SelectSerializeFnc class
struct UseNonMemberFnc : std::integral_constant<int, 1> {
};
struct UseMemberFnc : std::integral_constant<int, 2> {
};
template<typename T>
struct IsTextTraitsDefined
: public IsDefined<typename traits::TextTraits<T>::TValue>
{
};
namespace details {
//helper types for error handling
template<typename T>
struct IsContainerTraitsDefined : public IsDefined<typename traits::ContainerTraits<T>::TValue> {
};
template<typename T>
struct IsTextTraitsDefined : public IsDefined<typename traits::TextTraits<T>::TValue> {
};
template<typename Ext, typename T>
struct IsExtensionTraitsDefined : public IsDefined<typename traits::ExtensionTraits<Ext, T>::TValue> {
};
template<typename Ext, typename T>
struct IsExtensionTraitsDefined
: public IsDefined<typename traits::ExtensionTraits<Ext, T>::TValue>
{
};
#ifdef _MSC_VER
//helper types for HasSerializeFunction
template <typename S, typename T>
using TrySerializeFunction = decltype(serialize(std::declval<S &>(), std::declval<T &>()));
// helper types for HasSerializeFunction
template<typename S, typename T>
using TrySerializeFunction =
decltype(serialize(std::declval<S&>(), std::declval<T&>()));
template <typename S, typename T>
struct HasSerializeFunctionHelper {
template <typename Q, typename R, typename = TrySerializeFunction<Q, R>>
static std::true_type tester(Q&&, R&&);
static std::false_type tester(...);
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
};
template <typename S, typename T>
struct HasSerializeFunction :HasSerializeFunctionHelper<S, T>::type {};
template<typename S, typename T>
struct HasSerializeFunctionHelper
{
template<typename Q, typename R, typename = TrySerializeFunction<Q, R>>
static std::true_type tester(Q&&, R&&);
static std::false_type tester(...);
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
};
template<typename S, typename T>
struct HasSerializeFunction : HasSerializeFunctionHelper<S, T>::type
{
};
//helper types for HasSerializeMethod
template <typename S, typename T>
using TrySerializeMethod = decltype(Access::serialize(std::declval<S &>(), std::declval<T &>()));
// helper types for HasSerializeMethod
template<typename S, typename T>
using TrySerializeMethod =
decltype(Access::serialize(std::declval<S&>(), std::declval<T&>()));
template <typename S, typename T>
struct HasSerializeMethodHelper {
template <typename Q, typename R, typename = TrySerializeMethod<Q, R>>
static std::true_type tester(Q&&, R&&);
static std::false_type tester(...);
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
};
template <typename S, typename T>
struct HasSerializeMethod :HasSerializeMethodHelper<S, T>::type {};
template<typename S, typename T>
struct HasSerializeMethodHelper
{
template<typename Q, typename R, typename = TrySerializeMethod<Q, R>>
static std::true_type tester(Q&&, R&&);
static std::false_type tester(...);
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
};
template<typename S, typename T>
struct HasSerializeMethod : HasSerializeMethodHelper<S, T>::type
{
};
//helper types for IsBriefSyntaxIncluded
template <typename S, typename T>
using TryProcessBriefSyntax = decltype(processBriefSyntax(std::declval<S &>(), std::declval<T &&>()));
// helper types for IsBriefSyntaxIncluded
template<typename S, typename T>
using TryProcessBriefSyntax =
decltype(processBriefSyntax(std::declval<S&>(), std::declval<T&&>()));
template <typename S, typename T>
struct IsBriefSyntaxIncludedHelper {
template <typename Q, typename R, typename = TryProcessBriefSyntax<Q, R>>
static std::true_type tester(Q&&, R&&);
static std::false_type tester(...);
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
};
template<typename S, typename T>
struct IsBriefSyntaxIncludedHelper
{
template<typename Q, typename R, typename = TryProcessBriefSyntax<Q, R>>
static std::true_type tester(Q&&, R&&);
static std::false_type tester(...);
using type = decltype(tester(std::declval<S>(), std::declval<T>()));
};
template <typename S, typename T>
struct IsBriefSyntaxIncluded :IsBriefSyntaxIncludedHelper<S, T>::type {};
template<typename S, typename T>
struct IsBriefSyntaxIncluded : IsBriefSyntaxIncludedHelper<S, T>::type
{
};
#else
//helper metafunction, that is added to c++17
template<typename... Ts>
struct make_void {
typedef void type;
};
template<typename... Ts>
using void_t = typename make_void<Ts...>::type;
// helper metafunction, that is added to c++17
template<typename... Ts>
struct make_void
{
typedef void type;
};
template<typename... Ts>
using void_t = typename make_void<Ts...>::type;
template<typename, typename, typename = void>
struct HasSerializeFunction : std::false_type {
};
template<typename, typename, typename = void>
struct HasSerializeFunction : std::false_type
{
};
template<typename S, typename T>
struct HasSerializeFunction<S, T,
void_t<decltype(serialize(std::declval<S &>(), std::declval<T &>()))>
> : std::true_type {
};
template<typename S, typename T>
struct HasSerializeFunction<
S,
T,
void_t<decltype(serialize(std::declval<S&>(), std::declval<T&>()))>>
: std::true_type
{
};
template<typename, typename, typename = void>
struct HasSerializeMethod : std::false_type
{
};
template<typename, typename, typename = void>
struct HasSerializeMethod : std::false_type {
};
template<typename S, typename T>
struct HasSerializeMethod<
S,
T,
void_t<decltype(Access::serialize(std::declval<S&>(), std::declval<T&>()))>>
: std::true_type
{
};
template<typename S, typename T>
struct HasSerializeMethod<S, T,
void_t<decltype(Access::serialize(std::declval<S &>(), std::declval<T &>()))>
> : std::true_type {
};
// this solution doesn't work with visual studio, but is more elegant
template<typename, typename, typename = void>
struct IsBriefSyntaxIncluded : std::false_type
{
};
//this solution doesn't work with visual studio, but is more elegant
template<typename, typename, typename = void>
struct IsBriefSyntaxIncluded : std::false_type {
};
template<typename S, typename T>
struct IsBriefSyntaxIncluded<S, T,
void_t<decltype(processBriefSyntax(std::declval<S &>(), std::declval<T &&>()))>
> : std::true_type {
};
template<typename S, typename T>
struct IsBriefSyntaxIncluded<
S,
T,
void_t<decltype(processBriefSyntax(std::declval<S&>(), std::declval<T&&>()))>>
: std::true_type
{
};
#endif
//used for extensions when extension TValue = void
struct DummyType {
};
// used for extensions when extension TValue = void
struct DummyType
{};
/*
* this includes all integral types, floats and enums(except bool)
*/
template<typename T>
struct IsFundamentalType : std::integral_constant<bool,
std::is_enum<T>::value
|| std::is_floating_point<T>::value
|| std::is_integral<T>::value> {
};
template<typename T>
struct IsFundamentalType
: std::integral_constant<bool,
std::is_enum<T>::value ||
std::is_floating_point<T>::value ||
std::is_integral<T>::value>
{
};
template<typename T, typename Integral = void>
struct IntegralFromFundamental {
using TValue = T;
};
template<typename T, typename Integral = void>
struct IntegralFromFundamental
{
using TValue = T;
};
template<typename T>
struct IntegralFromFundamental<T, typename std::enable_if<std::is_enum<T>::value>::type> {
using TValue = typename std::underlying_type<T>::type;
};
template<typename T>
struct IntegralFromFundamental<
T,
typename std::enable_if<std::is_enum<T>::value>::type>
{
using TValue = typename std::underlying_type<T>::type;
};
template<typename T>
struct IntegralFromFundamental<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
using TValue = typename std::conditional<std::is_same<T, float>::value, uint32_t, uint64_t>::type;
};
template<typename T>
struct IntegralFromFundamental<
T,
typename std::enable_if<std::is_floating_point<T>::value>::type>
{
using TValue = typename std::
conditional<std::is_same<T, float>::value, uint32_t, uint64_t>::type;
};
template<typename T>
struct UnsignedFromFundamental {
using type = typename std::make_unsigned<typename IntegralFromFundamental<T>::TValue>::type;
};
template<typename T>
using SameSizeUnsigned = typename UnsignedFromFundamental<T>::type;
template<typename T>
struct UnsignedFromFundamental
{
using type = typename std::make_unsigned<
typename IntegralFromFundamental<T>::TValue>::type;
};
template<typename T>
using SameSizeUnsigned = typename UnsignedFromFundamental<T>::type;
/*
* functions for object serialization
*/
template<typename S, typename T>
struct SerializeFunction {
template<typename S, typename T>
struct SerializeFunction
{
static void invoke(S &s, T &v) {
static_assert(HasSerializeFunction<S, T>::value || HasSerializeMethod<S, T>::value,
"\nPlease define 'serialize' function for your type (inside or outside of class):\n"
" template<typename S>\n"
" void serialize(S& s)\n"
" {\n"
" ...\n"
" }\n");
using TDecayed = typename std::decay<T>::type;
selectSerializeFnc(s, v, SelectSerializeFnc<TDecayed>{});
}
static void invoke(S& s, T& v)
{
static_assert(HasSerializeFunction<S, T>::value ||
HasSerializeMethod<S, T>::value,
"\nPlease define 'serialize' function for your type (inside "
"or outside of class):\n"
" template<typename S>\n"
" void serialize(S& s)\n"
" {\n"
" ...\n"
" }\n");
using TDecayed = typename std::decay<T>::type;
selectSerializeFnc(s, v, SelectSerializeFnc<TDecayed>{});
}
static constexpr bool isDefined() {
return HasSerializeFunction<S, T>::value || HasSerializeMethod<S, T>::value;
}
static constexpr bool isDefined()
{
return HasSerializeFunction<S, T>::value || HasSerializeMethod<S, T>::value;
}
private:
static void selectSerializeFnc(S &s, T &v, std::integral_constant<int, 0>) {
static_assert(!(HasSerializeFunction<S, T>::value && HasSerializeMethod<S, T>::value),
"\nPlease define only one 'serialize' function (member OR free).\n"
"If serialization function is inherited from base class, then explicitly select correct function for your type e.g.:\n"
" template <>\n"
" struct SelectSerializeFnc<DerivedClass>:UseMemberFnc {};\n");
selectSerializeFnc(s, v, std::integral_constant<int,
HasSerializeFunction<S, T>::value ? 1 : 2>{});
}
private:
static void selectSerializeFnc(S& s, T& v, std::integral_constant<int, 0>)
{
static_assert(
!(HasSerializeFunction<S, T>::value && HasSerializeMethod<S, T>::value),
"\nPlease define only one 'serialize' function (member OR free).\n"
"If serialization function is inherited from base class, then explicitly "
"select correct function for your type e.g.:\n"
" template <>\n"
" struct SelectSerializeFnc<DerivedClass>:UseMemberFnc {};\n");
selectSerializeFnc(s,
v,
std::integral_constant < int,
HasSerializeFunction<S, T>::value ? 1 : 2 > {});
}
static void selectSerializeFnc(S &s, T &v, std::integral_constant<int, 1>) {
serialize(s, v);
}
static void selectSerializeFnc(S& s, T& v, std::integral_constant<int, 1>)
{
serialize(s, v);
}
static void selectSerializeFnc(S &s, T &v, std::integral_constant<int, 2>) {
Access::serialize(s, v);
}
};
static void selectSerializeFnc(S& s, T& v, std::integral_constant<int, 2>)
{
Access::serialize(s, v);
}
};
/*
* functions for object serialization
*/
template<typename S, typename T, typename Enabled = void>
struct BriefSyntaxFunction {
template<typename S, typename T, typename Enabled = void>
struct BriefSyntaxFunction
{
static void invoke(S &s, T &&obj) {
static_assert(IsBriefSyntaxIncluded<S, T>::value,
"\nPlease include '<bitsery/brief_syntax.h>' to use operator():\n");
static void invoke(S& s, T&& obj)
{
static_assert(
IsBriefSyntaxIncluded<S, T>::value,
"\nPlease include '<bitsery/brief_syntax.h>' to use operator():\n");
processBriefSyntax(s, std::forward<T>(obj));
}
};
processBriefSyntax(s, std::forward<T>(obj));
}
};
/*
* helper function for getting context from serializer/deserializer
*/
/*
* helper function for getting context from serializer/deserializer
*/
template<int Index, typename... Conds>
struct FindIndex : std::integral_constant<int, Index> {};
template<int Index, typename... Conds>
struct FindIndex : std::integral_constant<int, Index>
{
};
template<int Index, typename Cond, typename... Conds>
struct FindIndex<Index, Cond, Conds...> :
std::conditional<Cond::value, std::integral_constant<int, Index>, FindIndex<Index+1, Conds...>>::type
{};
template<int Index, typename Cond, typename... Conds>
struct FindIndex<Index, Cond, Conds...>
: std::conditional<Cond::value,
std::integral_constant<int, Index>,
FindIndex<Index + 1, Conds...>>::type
{
};
template <typename T, typename Tuple>
struct GetConvertibleTypeIndexFromTuple;
template<typename T, typename Tuple>
struct GetConvertibleTypeIndexFromTuple;
template <typename T, typename... Us>
struct GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>> : FindIndex<0, std::is_convertible<Us&, T&>...> {};
template<typename T, typename... Us>
struct GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>
: FindIndex<0, std::is_convertible<Us&, T&>...>
{
};
template<typename T, typename Tuple>
struct IsExistsConvertibleTupleType;
template <typename T, typename Tuple>
struct IsExistsConvertibleTupleType;
template<typename T, typename... Us>
struct IsExistsConvertibleTupleType<T, std::tuple<Us...>>
: std::integral_constant<
bool,
GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>::value !=
sizeof...(Us)>
{
};
template <typename T, typename... Us>
struct IsExistsConvertibleTupleType<T, std::tuple<Us...>> :
std::integral_constant<bool, GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>::value != sizeof...(Us)> {};
/*
* get context from internal or external, and check if it's convertible or not
*/
template<bool AssertExists, typename TCast, typename TContext>
TCast*
getDirectlyIfExists(TContext& ctx, std::true_type)
{
return &static_cast<TCast&>(ctx);
}
/*
* get context from internal or external, and check if it's convertible or not
*/
template<bool AssertExists, typename TCast, typename TContext>
TCast*
getDirectlyIfExists(TContext&, std::false_type)
{
// TCast cannot be convertible from provided context
static_assert(
!AssertExists,
"Invalid context cast. Context type doesn't exists.\nSome functionality "
"requires (de)seserializer to have specific context.");
return nullptr;
}
template<bool AssertExists, typename TCast, typename... TArgs>
TCast*
getFromTupleIfExists(std::tuple<TArgs...>& ctx, std::true_type)
{
using TupleIndex =
GetConvertibleTypeIndexFromTuple<TCast, std::tuple<TArgs...>>;
return &static_cast<TCast&>(std::get<TupleIndex::value>(ctx));
}
template<bool AssertExists, typename TCast, typename TContext>
TCast* getDirectlyIfExists(TContext& ctx, std::true_type) {
return &static_cast<TCast&>(ctx);
}
template<bool AssertExists, typename TCast, typename... TArgs>
TCast*
getFromTupleIfExists(std::tuple<TArgs...>&, std::false_type)
{
// TCast cannot be convertible from provided context
static_assert(
!AssertExists,
"Invalid context cast. Context type doesn't exists.\nSome functionality "
"requires (de)seserializer to have specific context.");
return nullptr;
}
template<bool AssertExists, typename TCast, typename TContext>
TCast* getDirectlyIfExists(TContext& , std::false_type) {
// TCast cannot be convertible from provided context
static_assert(!AssertExists,
"Invalid context cast. Context type doesn't exists.\nSome functionality requires (de)seserializer to have specific context.");
return nullptr;
}
// non tuple context
template<bool AssertExists, typename TCast, typename TContext>
TCast*
getContext(TContext& ctx)
{
return getDirectlyIfExists<AssertExists, TCast>(
ctx, std::is_convertible<TContext&, TCast&>{});
}
// tuple context
template<bool AssertExists, typename TCast, typename... TArgs>
TCast*
getContext(std::tuple<TArgs...>& ctx)
{
return getFromTupleIfExists<AssertExists, TCast>(
ctx, IsExistsConvertibleTupleType<TCast, std::tuple<TArgs...>>{});
}
template<bool AssertExists, typename TCast, typename ... TArgs>
TCast* getFromTupleIfExists(std::tuple<TArgs...>& ctx, std::true_type) {
using TupleIndex = GetConvertibleTypeIndexFromTuple<TCast, std::tuple<TArgs...>>;
return &static_cast<TCast&>(std::get<TupleIndex::value>(ctx));
}
template<typename Adapter, typename Context>
class AdapterAndContextRef
{
public:
static constexpr bool HasContext = true;
using Config = typename Adapter::TConfig;
template<bool AssertExists, typename TCast, typename ... TArgs>
TCast* getFromTupleIfExists(std::tuple<TArgs...>& , std::false_type) {
// TCast cannot be convertible from provided context
static_assert(!AssertExists,
"Invalid context cast. Context type doesn't exists.\nSome functionality requires (de)seserializer to have specific context.");
return nullptr;
}
// constructing adapter in place is important,
// because enableBitPacking might create instance with bit write/read enabled
// adapter wrapper, which has non trivial destructor
template<typename... TArgs>
explicit AdapterAndContextRef(Context& ctx, TArgs&&... args)
: _adapter{ std::forward<TArgs>(args)... }
, _context{ ctx }
{
}
//non tuple context
template<bool AssertExists, typename TCast, typename TContext>
TCast* getContext(TContext& ctx) {
return getDirectlyIfExists<AssertExists, TCast>(ctx, std::is_convertible<TContext&, TCast&>{});
}
/*
* get serialization context.
* this is optional, but might be required for some specific serialization
* flows.
*/
//tuple context
template<bool AssertExists, typename TCast, typename ... TArgs>
TCast* getContext(std::tuple<TArgs...>& ctx) {
return getFromTupleIfExists<AssertExists, TCast>(ctx, IsExistsConvertibleTupleType<TCast, std::tuple<TArgs...>>{});
}
template<typename T>
T& context()
{
return *getContext<true, T>(_context);
}
template <typename Adapter, typename Context>
class AdapterAndContextRef {
public:
static constexpr bool HasContext = true;
using Config = typename Adapter::TConfig;
template<typename T>
T* contextOrNull()
{
return getContext<false, T>(_context);
}
// constructing adapter in place is important,
// because enableBitPacking might create instance with bit write/read enabled adapter wrapper,
// which has non trivial destructor
template <typename ... TArgs>
explicit AdapterAndContextRef(Context& ctx, TArgs&& ... args)
: _adapter{std::forward<TArgs>(args)...},
_context{ctx}
{
}
Adapter& adapter() & { return _adapter; }
/*
* get serialization context.
* this is optional, but might be required for some specific serialization flows.
*/
Adapter adapter() && { return std::move(_adapter); }
template <typename T>
T& context() {
return *getContext<true, T>(_context);
}
protected:
Adapter _adapter;
Context& _context;
};
template <typename T>
T* contextOrNull() {
return getContext<false, T>(_context);
}
template<typename Adapter>
class AdapterAndContextRef<Adapter, void>
{
public:
static constexpr bool HasContext = false;
using Config = typename Adapter::TConfig;
Adapter& adapter() & {
return _adapter;
}
template<typename... TArgs>
explicit AdapterAndContextRef(TArgs&&... args)
: _adapter{ std::forward<TArgs>(args)... }
{
}
Adapter adapter() && {
return std::move(_adapter);
}
template<typename T>
T& context()
{
static_assert(std::is_void<T>::value, "Context is not defined (is void).");
}
protected:
Adapter _adapter;
Context& _context;
};
template<typename T>
T* contextOrNull()
{
return nullptr;
}
template <typename Adapter>
class AdapterAndContextRef<Adapter, void> {
public:
static constexpr bool HasContext = false;
using Config = typename Adapter::TConfig;
Adapter& adapter() & { return _adapter; }
template <typename ... TArgs>
explicit AdapterAndContextRef(TArgs&& ... args)
: _adapter{std::forward<TArgs>(args)...}
{
}
Adapter adapter() && { return std::move(_adapter); }
template <typename T>
T& context() {
static_assert(std::is_void<T>::value, "Context is not defined (is void).");
}
template <typename T>
T* contextOrNull() {
return nullptr;
}
Adapter& adapter() & {
return _adapter;
}
Adapter adapter() && {
return std::move(_adapter);
}
protected:
Adapter _adapter;
};
protected:
Adapter _adapter;
};
/**
* other helper meta-functions
*/
template<typename T, template<typename...> class Template>
struct IsSpecializationOf : std::false_type {
};
template<typename T, template<typename...> class Template>
struct IsSpecializationOf : std::false_type
{
};
template<template<typename...> class Template, typename... Args>
struct IsSpecializationOf<Template<Args...>, Template> : std::true_type {
};
template<template<typename...> class Template, typename... Args>
struct IsSpecializationOf<Template<Args...>, Template> : std::true_type
{
};
}
}
}
#endif //BITSERY_DETAILS_SERIALIZATION_COMMON_H
#endif // BITSERY_DETAILS_SERIALIZATION_COMMON_H

View File

@@ -1,190 +1,220 @@
//MIT License
// MIT License
//
//Copyright (c) 2018 Mindaugas Vinkelis
// Copyright (c) 2018 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_COMPACT_VALUE_H
#define BITSERY_EXT_COMPACT_VALUE_H
#include "../details/serialization_common.h"
#include "../details/adapter_common.h"
#include <cassert>
namespace bitsery {
namespace details {
namespace details {
template <bool CheckOverflow>
class CompactValueImpl {
public:
template<bool CheckOverflow>
class CompactValueImpl
{
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& s, const T& v, Fnc&&) const
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
using TValue = typename IntegralFromFundamental<T>::TValue;
serializeImpl(s.adapter(),
reinterpret_cast<const TValue&>(v),
std::integral_constant<bool, sizeof(T) != 1>{});
}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &s, const T &v, Fnc &&) const {
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
using TValue = typename IntegralFromFundamental<T>::TValue;
serializeImpl(s.adapter(), reinterpret_cast<const TValue&>(v), std::integral_constant<bool, sizeof(T) != 1>{});
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& d, T& v, Fnc&&) const
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
using TValue = typename IntegralFromFundamental<T>::TValue;
deserializeImpl(d.adapter(),
reinterpret_cast<TValue&>(v),
std::integral_constant<bool, sizeof(T) != 1>{});
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &d, T &v, Fnc &&) const {
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "");
using TValue = typename IntegralFromFundamental<T>::TValue;
deserializeImpl(d.adapter(), reinterpret_cast<TValue &>(v), std::integral_constant<bool, sizeof(T) != 1>{});
}
private:
// if value is 1byte size, just serialize/ deserialize whole value
template<typename Writer, typename T>
void serializeImpl(Writer& writer, const T& v, std::false_type) const
{
writer.template writeBytes<1>(v);
}
private:
template<typename Reader, typename T>
void deserializeImpl(Reader& reader, T& v, std::false_type) const
{
reader.template readBytes<1>(v);
}
// if value is 1byte size, just serialize/ deserialize whole value
template<typename Writer, typename T>
void serializeImpl(Writer &writer, const T &v, std::false_type) const {
writer.template writeBytes<1>(v);
}
// when value is bigger than 1byte size,
template<typename Writer, typename T>
void serializeImpl(Writer& writer, const T& v, std::true_type) const
{
auto val = zigZagEncode(
v, std::is_signed<typename IntegralFromFundamental<T>::TValue>{});
writeBytes(writer, val);
}
template<typename Reader, typename T>
void deserializeImpl(Reader &reader, T &v, std::false_type) const {
reader.template readBytes<1>(v);
}
template<typename Reader, typename T>
void deserializeImpl(Reader& reader, T& v, std::true_type) const
{
using TUnsigned = SameSizeUnsigned<T>;
TUnsigned res{};
readBytes<Reader::TConfig::CheckDataErrors>(reader, res);
v = zigZagDecode<T>(
res, std::is_signed<typename IntegralFromFundamental<T>::TValue>{});
}
// when value is bigger than 1byte size,
template<typename Writer, typename T>
void serializeImpl(Writer &writer, const T &v, std::true_type) const {
auto val = zigZagEncode(v, std::is_signed<typename IntegralFromFundamental<T>::TValue>{});
writeBytes(writer, val);
}
// zigzag encode signed types
template<typename T>
const SameSizeUnsigned<T>& zigZagEncode(const T& v, std::false_type) const
{
return v;
}
template<typename TResult, typename TUnsigned>
const TResult& zigZagDecode(const TUnsigned& v, std::false_type) const
{
return v;
}
template<typename Reader, typename T>
void deserializeImpl(Reader &reader, T &v, std::true_type) const {
using TUnsigned = SameSizeUnsigned<T>;
TUnsigned res{};
readBytes<Reader::TConfig::CheckDataErrors>(reader, res);
v = zigZagDecode<T>(res, std::is_signed<typename IntegralFromFundamental<T>::TValue>{});
}
template<typename T>
SameSizeUnsigned<T> zigZagEncode(const T& v, std::true_type) const
{
return static_cast<SameSizeUnsigned<T>>((v << 1) ^
(v >> (BitsSize<T>::value - 1)));
}
// zigzag encode signed types
template<typename T>
const SameSizeUnsigned<T> &zigZagEncode(const T &v, std::false_type) const {
return v;
}
template<typename TResult, typename TUnsigned>
const TResult &zigZagDecode(const TUnsigned &v, std::false_type) const{
return v;
}
template<typename T>
SameSizeUnsigned<T> zigZagEncode(const T &v, std::true_type) const {
return static_cast<SameSizeUnsigned<T>>((v << 1) ^ (v >> (BitsSize<T>::value - 1)));
}
template<typename TResult, typename TUnsigned>
TResult zigZagDecode(TUnsigned v, std::true_type) const {
return static_cast<TResult>((v >> 1) ^ (~(v & 1) + 1)); // same as -(v & 1), but no warning on VisualStudio
}
// write/read bytes one by one
template<typename Writer, typename T>
void writeBytes(Writer &w, const T &v) const {
using TFast = typename FastType<T>::type;
auto val= static_cast<TFast>(v);
while(val > 0x7Fu) {
w.template writeBytes<1>(static_cast<uint8_t>(val | 0x80u));
val >>=7u;
}
w.template writeBytes<1>(static_cast<uint8_t>(val));
}
template<bool CheckErrors, typename Reader, typename T>
void readBytes(Reader &r, T &v) const {
using TFast = typename FastType<T>::type;
constexpr auto TBITS = sizeof(T)*8;
uint8_t b1{0x80u};
auto i = 0u;
TFast tmp={};
for (;i < TBITS && b1 > 0x7Fu; i +=7u) {
r.template readBytes<1>(b1);
tmp += static_cast<TFast>(b1 & 0x7Fu) << i;
}
v = static_cast<T>(tmp);
handleReadOverflow<Reader, T>(r, i, b1,
std::integral_constant<bool, CheckOverflow && CheckErrors>{});
}
template <typename Reader, typename T>
void handleReadOverflow(Reader& r, unsigned shiftedBy, uint8_t remainder, std::true_type) const {
constexpr auto TBITS = sizeof(T)*8;
if (shiftedBy > TBITS && remainder >> (TBITS + 7 - shiftedBy)) {
r.error(bitsery::ReaderError::InvalidData);
}
}
template <typename Reader, typename T>
void handleReadOverflow(Reader &, unsigned , uint8_t , std::false_type) const {
}
};
template<typename TResult, typename TUnsigned>
TResult zigZagDecode(TUnsigned v, std::true_type) const
{
return static_cast<TResult>(
(v >> 1) ^
(~(v & 1) + 1)); // same as -(v & 1), but no warning on VisualStudio
}
// write/read bytes one by one
template<typename Writer, typename T>
void writeBytes(Writer& w, const T& v) const
{
using TFast = typename FastType<T>::type;
auto val = static_cast<TFast>(v);
while (val > 0x7Fu) {
w.template writeBytes<1>(static_cast<uint8_t>(val | 0x80u));
val >>= 7u;
}
w.template writeBytes<1>(static_cast<uint8_t>(val));
}
namespace ext {
// this type will use value overload, and do not check if type is sufficiently large during deserialization
class CompactValue: public details::CompactValueImpl<false> {};
// this type will enable object overload, and set DataOverflow if value doesn't fit in type, during deserialization
class CompactValueAsObject: public details::CompactValueImpl<true> {};
template<bool CheckErrors, typename Reader, typename T>
void readBytes(Reader& r, T& v) const
{
using TFast = typename FastType<T>::type;
constexpr auto TBITS = sizeof(T) * 8;
uint8_t b1{ 0x80u };
auto i = 0u;
TFast tmp = {};
for (; i < TBITS && b1 > 0x7Fu; i += 7u) {
r.template readBytes<1>(b1);
tmp += static_cast<TFast>(b1 & 0x7Fu) << i;
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::CompactValue, T> {
using TValue = T;
static constexpr bool SupportValueOverload = true;
// disable object overload, because we don't have implemented serialization function for fundamental types
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
template<typename T>
struct ExtensionTraits<ext::CompactValueAsObject, T> {
// use dummy implemenations for value and object overload
using TValue = void;
// only enable object overload
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
template<typename T, bool Check>
struct ExtensionTraits<details::CompactValueImpl<Check>, T> {
using TValue = T;
static constexpr bool SupportValueOverload = !Check;
static constexpr bool SupportObjectOverload = Check;
static constexpr bool SupportLambdaOverload = false;
};
v = static_cast<T>(tmp);
handleReadOverflow<Reader, T>(r,
i,
b1,
std::integral_constant < bool,
CheckOverflow&& CheckErrors > {});
}
template<typename Reader, typename T>
void handleReadOverflow(Reader& r,
unsigned shiftedBy,
uint8_t remainder,
std::true_type) const
{
constexpr auto TBITS = sizeof(T) * 8;
if (shiftedBy > TBITS && remainder >> (TBITS + 7 - shiftedBy)) {
r.error(bitsery::ReaderError::InvalidData);
}
}
template<typename Reader, typename T>
void handleReadOverflow(Reader&, unsigned, uint8_t, std::false_type) const
{
}
};
}
namespace ext {
#endif //BITSERY_EXT_COMPACT_VALUE_H
// this type will use value overload, and do not check if type is sufficiently
// large during deserialization
class CompactValue : public details::CompactValueImpl<false>
{};
// this type will enable object overload, and set DataOverflow if value doesn't
// fit in type, during deserialization
class CompactValueAsObject : public details::CompactValueImpl<true>
{};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::CompactValue, T>
{
using TValue = T;
static constexpr bool SupportValueOverload = true;
// disable object overload, because we don't have implemented serialization
// function for fundamental types
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
template<typename T>
struct ExtensionTraits<ext::CompactValueAsObject, T>
{
// use dummy implemenations for value and object overload
using TValue = void;
// only enable object overload
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
template<typename T, bool Check>
struct ExtensionTraits<details::CompactValueImpl<Check>, T>
{
using TValue = T;
static constexpr bool SupportValueOverload = !Check;
static constexpr bool SupportObjectOverload = Check;
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif // BITSERY_EXT_COMPACT_VALUE_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_ENTROPY_H
#define BITSERY_EXT_ENTROPY_H
@@ -27,78 +27,88 @@
namespace bitsery {
namespace details {
template<typename TValue, typename TContainer>
size_t findEntropyIndex(const TValue &v, const TContainer &defValues) {
size_t index{1u};
for (auto &d:defValues) {
if (d == v)
return index;
++index;
}
return 0u;
}
}
namespace details {
template<typename TValue, typename TContainer>
size_t
findEntropyIndex(const TValue& v, const TContainer& defValues)
{
size_t index{ 1u };
for (auto& d : defValues) {
if (d == v)
return index;
++index;
}
return 0u;
}
}
namespace ext {
namespace ext {
template<typename TContainer>
class Entropy {
public:
template<typename TContainer>
class Entropy
{
public:
/**
* Allows entropy-encoding technique, by writing few bits for most common
* values
* @param values list of most common values
* @param alignBeforeData only makes sense when bit-packing enabled, by
* default aligns after writing bits for index
*/
constexpr Entropy(TContainer& values, bool alignBeforeData = true)
: _values{ values }
, _alignBeforeData{ alignBeforeData } {};
/**
* Allows entropy-encoding technique, by writing few bits for most common values
* @param values list of most common values
* @param alignBeforeData only makes sense when bit-packing enabled, by default aligns after writing bits for index
*/
constexpr Entropy(TContainer& values, bool alignBeforeData=true)
: _values{values},
_alignBeforeData{alignBeforeData} {
};
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& s, const T& obj, Fnc&& fnc) const
{
assert(traits::ContainerTraits<TContainer>::size(_values) > 0);
auto index = details::findEntropyIndex(obj, _values);
s.ext(index,
ext::ValueRange<size_t>{
0u, traits::ContainerTraits<TContainer>::size(_values) });
if (_alignBeforeData)
s.adapter().align();
if (!index)
fnc(s, const_cast<T&>(obj));
}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &s, const T &obj, Fnc &&fnc) const {
assert(traits::ContainerTraits<TContainer>::size(_values) > 0);
auto index = details::findEntropyIndex(obj, _values);
s.ext(index, ext::ValueRange<size_t>{0u, traits::ContainerTraits<TContainer>::size(_values)});
if (_alignBeforeData)
s.adapter().align();
if (!index)
fnc(s, const_cast<T &>(obj));
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& d, T& obj, Fnc&& fnc) const
{
assert(traits::ContainerTraits<TContainer>::size(_values) > 0);
size_t index{};
d.ext(index,
ext::ValueRange<size_t>{
0u, traits::ContainerTraits<TContainer>::size(_values) });
if (_alignBeforeData)
d.adapter().align();
if (index) {
using TDiff = typename std::iterator_traits<decltype(std::begin(
_values))>::difference_type;
obj = static_cast<T>(
*std::next(std::begin(_values), static_cast<TDiff>(index - 1)));
} else
fnc(d, obj);
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &d, T &obj, Fnc &&fnc) const {
assert(traits::ContainerTraits<TContainer>::size(_values) > 0);
size_t index{};
d.ext(index, ext::ValueRange<size_t>{0u, traits::ContainerTraits<TContainer>::size(_values)});
if (_alignBeforeData)
d.adapter().align();
if (index) {
using TDiff = typename std::iterator_traits<decltype(std::begin(_values))>::difference_type;
obj = static_cast<T>(*std::next(std::begin(_values), static_cast<TDiff>(index-1)));
}
else
fnc(d, obj);
}
private:
TContainer& _values;
bool _alignBeforeData;
};
}
private:
TContainer& _values;
bool _alignBeforeData;
};
}
namespace traits {
template<typename TContainer, typename T>
struct ExtensionTraits<ext::Entropy<TContainer>, T> {
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
namespace traits {
template<typename TContainer, typename T>
struct ExtensionTraits<ext::Entropy<TContainer>, T>
{
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_ENTROPY_H
#endif // BITSERY_EXT_ENTROPY_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_GROWABLE_H
#define BITSERY_EXT_GROWABLE_H
@@ -27,58 +27,62 @@
namespace bitsery {
namespace ext {
namespace ext {
/*
* enables forward and backward compatibility, by allowing to append additional data at the end of serialization
* old deserialization method will ignore additional data by jumping through it at the end of deserialization flow
* new deserialization method will read all 0 for new fields if there is no data for it
*/
class Growable {
public:
/*
* enables forward and backward compatibility, by allowing to append additional
* data at the end of serialization old deserialization method will ignore
* additional data by jumping through it at the end of deserialization flow new
* deserialization method will read all 0 for new fields if there is no data for
* it
*/
class Growable
{
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
{
auto& writer = ser.adapter();
const auto startPos = writer.currentWritePos();
writer.template writeBytes<4>(static_cast<uint32_t>(0));
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
auto& writer = ser.adapter();
const auto startPos = writer.currentWritePos();
writer.template writeBytes<4>(static_cast<uint32_t>(0));
fnc(ser, const_cast<T&>(obj));
fnc(ser, const_cast<T&>(obj));
const auto endPos = writer.currentWritePos();
writer.currentWritePos(startPos);
writer.template writeBytes<4>(static_cast<uint32_t>(endPos - startPos));
writer.currentWritePos(endPos);
}
const auto endPos = writer.currentWritePos();
writer.currentWritePos(startPos);
writer.template writeBytes<4>(static_cast<uint32_t>(endPos - startPos));
writer.currentWritePos(endPos);
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, T& obj, Fnc&& fnc) const
{
auto& reader = des.adapter();
uint32_t size{};
const auto readEndPos = reader.currentReadEndPos();
const auto startPos = reader.currentReadPos();
reader.template readBytes<4>(size);
reader.currentReadEndPos(startPos + size);
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
auto& reader = des.adapter();
uint32_t size{};
const auto readEndPos = reader.currentReadEndPos();
const auto startPos = reader.currentReadPos();
reader.template readBytes<4>(size);
reader.currentReadEndPos(startPos + size);
fnc(des, obj);
fnc(des, obj);
reader.currentReadPos(startPos + size);
reader.currentReadEndPos(readEndPos);
}
};
}
reader.currentReadPos(startPos + size);
reader.currentReadEndPos(readEndPos);
}
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::Growable, T> {
using TValue = T;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::Growable, T>
{
using TValue = T;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_GROWABLE_H
#endif // BITSERY_EXT_GROWABLE_H

View File

@@ -1,162 +1,169 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_INHERITANCE_H
#define BITSERY_EXT_INHERITANCE_H
#include <unordered_set>
#include "../traits/core/traits.h"
#include "../ext/utils/memory_resource.h"
#include "../traits/core/traits.h"
#include <unordered_set>
namespace bitsery {
namespace ext {
namespace ext {
//required when virtual inheritance (ext::VirtualBaseClass) exists in serialization flow.
//for standard inheritance (ext::BaseClass) it is optional.
class InheritanceContext {
public:
explicit InheritanceContext(MemResourceBase* memResource = nullptr)
:_virtualBases{pointer_utils::StdPolyAlloc<const void*>{memResource}}
{}
InheritanceContext(const InheritanceContext&) = delete;
InheritanceContext&operator = (const InheritanceContext&) = delete;
InheritanceContext(InheritanceContext&&) = default;
InheritanceContext& operator = (InheritanceContext&&) = default;
template <typename TDerived, typename TBase>
void beginBase(const TDerived &derived, const TBase &) {
if (_depth == 0) {
const void* ptr = std::addressof(derived);
if ( _parentPtr != ptr)
_virtualBases.clear();
_parentPtr = ptr;
}
++_depth;
}
template <typename TDerived, typename TBase>
bool beginVirtualBase(const TDerived &derived, const TBase &base) {
beginBase(derived, base);
return _virtualBases.emplace(std::addressof(base)).second;
}
void end() {
--_depth;
}
private:
//these members are required to know when we can clear _virtualBases
size_t _depth{};
const void* _parentPtr{};
//add virtual bases to the list, as long as we're on the same parent
std::unordered_set<const void*,
std::hash<const void*>, std::equal_to<const void*>,
pointer_utils::StdPolyAlloc<const void*>
> _virtualBases;
};
template <typename TBase>
class BaseClass {
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
auto& resObj = static_cast<const TBase&>(obj);
if (auto ctx = ser.template contextOrNull<InheritanceContext>()) {
ctx->beginBase(obj, resObj);
fnc(ser, const_cast<TBase&>(resObj));
ctx->end();
} else {
fnc(ser, const_cast<TBase&>(resObj));
}
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
auto& resObj = static_cast<TBase&>(obj);
if (auto ctx = des.template contextOrNull<InheritanceContext>()) {
ctx->beginBase(obj, resObj);
fnc(des, resObj);
ctx->end();
} else {
fnc(des, resObj);
}
}
};
//requires InheritanceContext
template <typename TBase>
class VirtualBaseClass {
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
auto& ctx = ser.template context<InheritanceContext>();
auto& resObj = static_cast<const TBase&>(obj);
if (ctx.beginVirtualBase(obj, resObj))
fnc(ser, const_cast<TBase&>(resObj));
ctx.end();
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
auto& ctx = des.template context<InheritanceContext>();
auto& resObj = static_cast<TBase&>(obj);
if (ctx.beginVirtualBase(obj, resObj))
fnc(des, resObj);
ctx.end();
}
};
// required when virtual inheritance (ext::VirtualBaseClass) exists in
// serialization flow. for standard inheritance (ext::BaseClass) it is optional.
class InheritanceContext
{
public:
explicit InheritanceContext(MemResourceBase* memResource = nullptr)
: _virtualBases{ pointer_utils::StdPolyAlloc<const void*>{ memResource } }
{
}
InheritanceContext(const InheritanceContext&) = delete;
InheritanceContext& operator=(const InheritanceContext&) = delete;
InheritanceContext(InheritanceContext&&) = default;
InheritanceContext& operator=(InheritanceContext&&) = default;
template<typename TDerived, typename TBase>
void beginBase(const TDerived& derived, const TBase&)
{
if (_depth == 0) {
const void* ptr = std::addressof(derived);
if (_parentPtr != ptr)
_virtualBases.clear();
_parentPtr = ptr;
}
++_depth;
}
namespace traits {
template<typename TBase, typename T>
struct ExtensionTraits<ext::BaseClass<TBase>, T> {
static_assert(std::is_base_of<TBase, T>::value, "Invalid base class");
template<typename TDerived, typename TBase>
bool beginVirtualBase(const TDerived& derived, const TBase& base)
{
beginBase(derived, base);
return _virtualBases.emplace(std::addressof(base)).second;
}
using TValue = TBase;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
void end() { --_depth; }
template<typename TBase, typename T>
struct ExtensionTraits<ext::VirtualBaseClass<TBase>, T> {
static_assert(std::is_base_of<TBase, T>::value, "Invalid base class");
private:
// these members are required to know when we can clear _virtualBases
size_t _depth{};
const void* _parentPtr{};
// add virtual bases to the list, as long as we're on the same parent
std::unordered_set<const void*,
std::hash<const void*>,
std::equal_to<const void*>,
pointer_utils::StdPolyAlloc<const void*>>
_virtualBases;
};
using TValue = TBase;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
//disable lambda overload, when serializing virtually inherited base class.
//Only one instance of virtual base will be serialized, when using multiple inheritance
//and it will be undefined behaviour if derived classes would have different virtual base class serialization flow.
static constexpr bool SupportLambdaOverload = false;
};
template<typename TBase>
class BaseClass
{
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
{
auto& resObj = static_cast<const TBase&>(obj);
if (auto ctx = ser.template contextOrNull<InheritanceContext>()) {
ctx->beginBase(obj, resObj);
fnc(ser, const_cast<TBase&>(resObj));
ctx->end();
} else {
fnc(ser, const_cast<TBase&>(resObj));
}
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, T& obj, Fnc&& fnc) const
{
auto& resObj = static_cast<TBase&>(obj);
if (auto ctx = des.template contextOrNull<InheritanceContext>()) {
ctx->beginBase(obj, resObj);
fnc(des, resObj);
ctx->end();
} else {
fnc(des, resObj);
}
}
};
// requires InheritanceContext
template<typename TBase>
class VirtualBaseClass
{
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
{
auto& ctx = ser.template context<InheritanceContext>();
auto& resObj = static_cast<const TBase&>(obj);
if (ctx.beginVirtualBase(obj, resObj))
fnc(ser, const_cast<TBase&>(resObj));
ctx.end();
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, T& obj, Fnc&& fnc) const
{
auto& ctx = des.template context<InheritanceContext>();
auto& resObj = static_cast<TBase&>(obj);
if (ctx.beginVirtualBase(obj, resObj))
fnc(des, resObj);
ctx.end();
}
};
}
namespace traits {
template<typename TBase, typename T>
struct ExtensionTraits<ext::BaseClass<TBase>, T>
{
static_assert(std::is_base_of<TBase, T>::value, "Invalid base class");
#endif //BITSERY_EXT_INHERITANCE_H
using TValue = TBase;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
template<typename TBase, typename T>
struct ExtensionTraits<ext::VirtualBaseClass<TBase>, T>
{
static_assert(std::is_base_of<TBase, T>::value, "Invalid base class");
using TValue = TBase;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
// disable lambda overload, when serializing virtually inherited base class.
// Only one instance of virtual base will be serialized, when using multiple
// inheritance and it will be undefined behaviour if derived classes would
// have different virtual base class serialization flow.
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif // BITSERY_EXT_INHERITANCE_H

View File

@@ -1,220 +1,248 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_POINTER_H
#define BITSERY_EXT_POINTER_H
#include <cassert>
#include "../traits/core/traits.h"
#include "utils/pointer_utils.h"
#include "utils/polymorphism_utils.h"
#include "utils/rtti_utils.h"
#include <cassert>
namespace bitsery {
namespace ext {
namespace ext {
namespace pointer_details {
namespace pointer_details {
template<typename T>
struct PtrOwnerManager {
static_assert(std::is_pointer<T>::value, "");
template<typename T>
struct PtrOwnerManager
{
static_assert(std::is_pointer<T>::value, "");
using TElement = typename std::remove_pointer<T>::type;
using TElement = typename std::remove_pointer<T>::type;
static TElement* getPtr(T& obj) {
return obj;
}
static TElement* getPtr(T& obj) { return obj; }
static constexpr PointerOwnershipType getOwnership() {
return PointerOwnershipType::Owner;
}
static constexpr PointerOwnershipType getOwnership()
{
return PointerOwnershipType::Owner;
}
static void create(T& obj, pointer_utils::PolyAllocWithTypeId alloc, size_t typeId) {
obj = alloc.newObject<TElement>(typeId);
}
static void create(T& obj,
pointer_utils::PolyAllocWithTypeId alloc,
size_t typeId)
{
obj = alloc.newObject<TElement>(typeId);
}
static void createPolymorphic(T& obj, pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
obj = static_cast<TElement*>(handler->create(alloc));
}
static void createPolymorphic(
T& obj,
pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler)
{
obj = static_cast<TElement*>(handler->create(alloc));
}
static void destroy(T& obj, pointer_utils::PolyAllocWithTypeId alloc, size_t typeId) {
alloc.deleteObject(obj, typeId);
obj = nullptr;
}
static void destroy(T& obj,
pointer_utils::PolyAllocWithTypeId alloc,
size_t typeId)
{
alloc.deleteObject(obj, typeId);
obj = nullptr;
}
static void destroyPolymorphic(T& obj, pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
handler->destroy(alloc, obj);
obj = nullptr;
}
static void destroyPolymorphic(
T& obj,
pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler)
{
handler->destroy(alloc, obj);
obj = nullptr;
}
};
};
template<typename T>
struct PtrObserverManager
{
static_assert(std::is_pointer<T>::value, "");
template<typename T>
struct PtrObserverManager {
static_assert(std::is_pointer<T>::value, "");
using TElement = typename std::remove_pointer<T>::type;
using TElement = typename std::remove_pointer<T>::type;
static TElement* getPtr(T& obj) { return obj; }
static TElement* getPtr(T& obj) {
return obj;
}
static constexpr PointerOwnershipType getOwnership()
{
return PointerOwnershipType::Observer;
}
static constexpr PointerOwnershipType getOwnership() {
return PointerOwnershipType::Observer;
}
// pure observer doesn't have create/createPolymorphic methods, but instead
// returns reference to pointer which gets updated later
static TElement*& getPtrRef(T& obj) { return obj; }
//pure observer doesn't have create/createPolymorphic methods, but instead returns reference to pointer
//which gets updated later
static TElement*& getPtrRef(T& obj) {
return obj;
}
static void destroy(T& obj, MemResourceBase*, size_t) { obj = nullptr; }
static void destroy(T& obj, MemResourceBase* , size_t ) {
obj = nullptr;
}
static void destroyPolymorphic(T& obj,
MemResourceBase*,
PolymorphicHandlerBase&)
{
obj = nullptr;
}
};
static void destroyPolymorphic(T& obj, MemResourceBase* , PolymorphicHandlerBase& ) {
obj = nullptr;
}
template<typename T>
struct NonPtrManager
{
};
static_assert(!std::is_pointer<T>::value, "");
template<typename T>
struct NonPtrManager {
using TElement = T;
static_assert(!std::is_pointer<T>::value, "");
static TElement* getPtr(T& obj) { return &obj; }
using TElement = T;
static constexpr PointerOwnershipType getOwnership()
{
return PointerOwnershipType::Owner;
}
static TElement* getPtr(T& obj) {
return &obj;
}
// this code is unreachable for reference type, but is necessary to compile
// LCOV_EXCL_START
static constexpr PointerOwnershipType getOwnership() {
return PointerOwnershipType::Owner;
}
static void create(T&, MemResourceBase*, size_t) {}
// this code is unreachable for reference type, but is necessary to compile
// LCOV_EXCL_START
static void createPolymorphic(T&, MemResourceBase*, PolymorphicHandlerBase&)
{
}
static void create(T& , MemResourceBase* , size_t ) {
static void destroy(T&, MemResourceBase*, size_t) {}
}
static void destroyPolymorphic(T&, MemResourceBase*, PolymorphicHandlerBase&)
{
}
// LCOV_EXCL_STOP
};
static void createPolymorphic(T& , MemResourceBase* , PolymorphicHandlerBase& ) {
// 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;
}
static void destroy(T& , MemResourceBase* , size_t ) {
template<typename TBase, typename TDerived>
static constexpr TDerived* cast(TBase* obj)
{
static_assert(!std::is_pointer<TDerived>::value, "");
return dynamic_cast<TDerived*>(obj);
}
}
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;
};
}
template<typename TBase>
static constexpr bool isPolymorphic()
{
return false;
}
};
}
#endif //BITSERY_EXT_POINTER_H
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

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2020 Nick Renieris
// Copyright (c) 2020 Nick Renieris
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_STD_ATOMIC_H
#define BITSERY_EXT_STD_ATOMIC_H
@@ -27,39 +27,41 @@
#include <atomic>
namespace bitsery {
namespace ext {
namespace ext {
class StdAtomic {
public:
class StdAtomic
{
public:
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const std::atomic<T>& obj, Fnc&& fnc) const
{
auto res = obj.load();
fnc(ser, res);
}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const std::atomic<T>& obj, Fnc&& fnc) const {
auto res = obj.load();
fnc(ser, res);
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, std::atomic<T>& obj, Fnc&& fnc) const {
T res{};
fnc(des, res);
obj.store(res);
}
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdAtomic, std::atomic<T>> {
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, std::atomic<T>& obj, Fnc&& fnc) const
{
T res{};
fnc(des, res);
obj.store(res);
}
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdAtomic, std::atomic<T>>
{
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
#endif //BITSERY_EXT_STD_ATOMIC_H
}
}
#endif // BITSERY_EXT_STD_ATOMIC_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2020 Mindaugas Vinkelis
// Copyright (c) 2020 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_STD_BITSET_H
#define BITSERY_EXT_STD_BITSET_H
@@ -27,122 +27,137 @@
#include <bitset>
namespace bitsery {
namespace ext {
namespace ext {
class StdBitset {
public:
class StdBitset
{
public:
template<typename Ser, typename Fnc, size_t N>
void serialize(Ser& ser, const std::bitset<N>& obj, Fnc&&) const
{
constexpr size_t BYTES = N / 8;
constexpr size_t LEFTOVER = N % 8;
if (BYTES > sizeof(unsigned long long)) {
for (size_t i = 0u; i < BYTES; ++i) {
size_t offset = i * 8;
auto data = obj[offset + 0] + (obj[offset + 1] << 1) +
(obj[offset + 2] << 2) + (obj[offset + 3] << 3) +
(obj[offset + 4] << 4) + (obj[offset + 5] << 5) +
(obj[offset + 6] << 6) + (obj[offset + 7] << 7);
ser.value1b(static_cast<uint8_t>(data));
}
template<typename Ser, typename Fnc, size_t N>
void serialize(Ser &ser, const std::bitset<N> &obj, Fnc &&) const {
constexpr size_t BYTES = N / 8;
constexpr size_t LEFTOVER = N % 8;
if (BYTES > sizeof(unsigned long long)) {
for(size_t i = 0u; i < BYTES; ++i) {
size_t offset = i * 8;
auto data = obj[offset + 0] +
(obj[offset + 1] << 1) +
(obj[offset + 2] << 2) +
(obj[offset + 3] << 3) +
(obj[offset + 4] << 4) +
(obj[offset + 5] << 5) +
(obj[offset + 6] << 6) +
(obj[offset + 7] << 7);
ser.value1b(static_cast<uint8_t>(data));
}
} else {
// more performant way
auto data = obj.to_ullong();
for(size_t i = 0u; i < BYTES; ++i) {
ser.value1b(static_cast<uint8_t>(data & 0xFF));
data >>= 8;
}
}
if (LEFTOVER > 0) {
serializeLeftover(ser.adapter(), obj, N - LEFTOVER, N);
}
}
template<typename Des, typename Fnc, size_t N>
void deserialize(Des &des, std::bitset<N> &obj, Fnc &&) const {
constexpr size_t BYTES = N / 8;
constexpr size_t LEFTOVER = N % 8;
for(size_t i = 0u; i < BYTES; ++i) {
size_t offset = i * 8;
uint8_t data = 0;
des.value1b(data);
obj[offset + 0] = data & 0x01u;
obj[offset + 1] = data & 0x02u;
obj[offset + 2] = data & 0x04u;
obj[offset + 3] = data & 0x08u;
obj[offset + 4] = data & 0x10u;
obj[offset + 5] = data & 0x20u;
obj[offset + 6] = data & 0x40u;
obj[offset + 7] = data & 0x80u;
}
if (LEFTOVER > 0) {
deserializeLeftover(des.adapter(), obj, N - LEFTOVER, N);
}
}
private:
template<typename Writer, size_t N>
void serializeLeftover(Writer& w, const std::bitset<N> &obj, size_t from, size_t to) const {
serializeLeftoverImpl(w, obj, from, to, std::integral_constant<bool, Writer::BitPackingEnabled> {});
}
template<typename Writer, size_t N>
void serializeLeftoverImpl(Writer& w, const std::bitset<N> &obj, size_t from, size_t to, std::integral_constant<bool, false>) const {
auto data = 0;
for (auto i = from; i < to; ++i) {
data += obj[i] << (i - from);
}
w.template writeBytes<1>(static_cast<uint8_t>(data));
}
template<typename Writer, size_t N>
void serializeLeftoverImpl(Writer& w, const std::bitset<N> &obj, size_t from, size_t to, std::integral_constant<bool, true>) const {
for (auto i = from; i < to; ++i) {
w.writeBits(obj[i] ? 1u : 0u, 1);
}
}
template<typename Reader, size_t N>
void deserializeLeftover(Reader& r, std::bitset<N> &obj, size_t from, size_t to) const {
deserializeLeftoverImpl(r, obj, from, to, std::integral_constant<bool, Reader::BitPackingEnabled> {});
}
template<typename Reader, size_t N>
void deserializeLeftoverImpl(Reader& r, std::bitset<N> &obj, size_t from, size_t to, std::integral_constant<bool, false>) const {
uint8_t data = 0u;
r.template readBytes<1>(data);
for (auto i = from; i < to; ++i) {
obj[i] = data & (1u << (i - from));
}
}
template<typename Reader, size_t N>
void deserializeLeftoverImpl(Reader& r, std::bitset<N> &obj, size_t from, size_t to, std::integral_constant<bool, true>) const {
for (auto i = from; i < to; ++i) {
uint8_t res = 0u;
r.readBits(res, 1);
obj[i] = res == 1;
}
}
};
} else {
// more performant way
auto data = obj.to_ullong();
for (size_t i = 0u; i < BYTES; ++i) {
ser.value1b(static_cast<uint8_t>(data & 0xFF));
data >>= 8;
}
}
namespace traits {
template<size_t N>
struct ExtensionTraits<ext::StdBitset, std::bitset<N>> {
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
if (LEFTOVER > 0) {
serializeLeftoverImpl(ser.adapter(),
obj,
N - LEFTOVER,
N,
std::is_same<Ser, typename Ser::BPEnabledType>{});
}
}
template<typename Des, typename Fnc, size_t N>
void deserialize(Des& des, std::bitset<N>& obj, Fnc&&) const
{
constexpr size_t BYTES = N / 8;
constexpr size_t LEFTOVER = N % 8;
for (size_t i = 0u; i < BYTES; ++i) {
size_t offset = i * 8;
uint8_t data = 0;
des.value1b(data);
obj[offset + 0] = data & 0x01u;
obj[offset + 1] = data & 0x02u;
obj[offset + 2] = data & 0x04u;
obj[offset + 3] = data & 0x08u;
obj[offset + 4] = data & 0x10u;
obj[offset + 5] = data & 0x20u;
obj[offset + 6] = data & 0x40u;
obj[offset + 7] = data & 0x80u;
}
if (LEFTOVER > 0) {
deserializeLeftoverImpl(des.adapter(),
obj,
N - LEFTOVER,
N,
std::is_same<Des, typename Des::BPEnabledType>{});
}
}
private:
template<typename Writer, size_t N>
void serializeLeftoverImpl(Writer& w,
const std::bitset<N>& obj,
size_t from,
size_t to,
std::integral_constant<bool, false>) const
{
auto data = 0;
for (auto i = from; i < to; ++i) {
data += obj[i] << (i - from);
}
w.template writeBytes<1>(static_cast<uint8_t>(data));
}
template<typename Writer, size_t N>
void serializeLeftoverImpl(Writer& w,
const std::bitset<N>& obj,
size_t from,
size_t to,
std::integral_constant<bool, true>) const
{
for (auto i = from; i < to; ++i) {
w.writeBits(obj[i] ? 1u : 0u, 1);
}
}
template<typename Reader, size_t N>
void deserializeLeftoverImpl(Reader& r,
std::bitset<N>& obj,
size_t from,
size_t to,
std::integral_constant<bool, false>) const
{
uint8_t data = 0u;
r.template readBytes<1>(data);
for (auto i = from; i < to; ++i) {
obj[i] = data & (1u << (i - from));
}
}
template<typename Reader, size_t N>
void deserializeLeftoverImpl(Reader& r,
std::bitset<N>& obj,
size_t from,
size_t to,
std::integral_constant<bool, true>) const
{
for (auto i = from; i < to; ++i) {
uint8_t res = 0u;
r.readBits(res, 1);
obj[i] = res == 1;
}
}
};
}
namespace traits {
template<size_t N>
struct ExtensionTraits<ext::StdBitset, std::bitset<N>>
{
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif //BITSERY_EXT_STD_BITSET_H
#endif // BITSERY_EXT_STD_BITSET_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_STD_CHRONO_H
#define BITSERY_EXT_STD_CHRONO_H
@@ -27,68 +27,91 @@
#include <chrono>
namespace bitsery {
namespace ext {
namespace ext {
class StdDuration {
public:
class StdDuration
{
public:
template<typename Ser, typename T, typename Period, typename Fnc>
void serialize(Ser& ser,
const std::chrono::duration<T, Period>& obj,
Fnc&& fnc) const
{
auto res = obj.count();
fnc(ser, res);
}
template<typename Ser, typename T, typename Period, typename Fnc>
void serialize(Ser& ser, const std::chrono::duration<T, Period>& obj, Fnc&& fnc) const {
auto res = obj.count();
fnc(ser, res);
}
template<typename Des, typename T, typename Period, typename Fnc>
void deserialize(Des& des,
std::chrono::duration<T, Period>& obj,
Fnc&& fnc) const
{
T res{};
fnc(des, res);
obj = std::chrono::duration<T, Period>{ res };
}
};
template<typename Des, typename T, typename Period, typename Fnc>
void deserialize(Des& des, std::chrono::duration<T, Period>& obj, Fnc&& fnc) const {
T res{};
fnc(des, res);
obj = std::chrono::duration<T, Period>{res};
}
};
class StdTimePoint
{
public:
template<typename Ser,
typename Clock,
typename T,
typename Period,
typename Fnc>
void serialize(
Ser& ser,
const std::chrono::time_point<Clock, std::chrono::duration<T, Period>>& obj,
Fnc&& fnc) const
{
auto res = obj.time_since_epoch().count();
fnc(ser, res);
}
class StdTimePoint {
public:
template<typename Ser, typename Clock, typename T, typename Period, typename Fnc>
void serialize(Ser& ser, const std::chrono::time_point<Clock, std::chrono::duration<T, Period>>& obj,
Fnc&& fnc) const {
auto res = obj.time_since_epoch().count();
fnc(ser, res);
}
template<typename Des, typename Clock, typename T, typename Period, typename Fnc>
void deserialize(Des& des, std::chrono::time_point<Clock, std::chrono::duration<T, Period>>& obj,
Fnc&& fnc) const {
T res{};
fnc(des, res);
auto dur = std::chrono::duration<T, Period>{res};
obj = std::chrono::time_point<Clock, std::chrono::duration<T, Period>>{dur};
}
};
}
namespace traits {
template<typename Rep, typename Period>
struct ExtensionTraits<ext::StdDuration, std::chrono::duration<Rep, Period>> {
using TValue = Rep;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
template<typename Clock, typename Rep, typename Period>
struct ExtensionTraits<ext::StdTimePoint,
std::chrono::time_point<Clock, std::chrono::duration<Rep, Period>>> {
using TValue = Rep;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
}
template<typename Des,
typename Clock,
typename T,
typename Period,
typename Fnc>
void deserialize(
Des& des,
std::chrono::time_point<Clock, std::chrono::duration<T, Period>>& obj,
Fnc&& fnc) const
{
T res{};
fnc(des, res);
auto dur = std::chrono::duration<T, Period>{ res };
obj =
std::chrono::time_point<Clock, std::chrono::duration<T, Period>>{ dur };
}
};
}
namespace traits {
template<typename Rep, typename Period>
struct ExtensionTraits<ext::StdDuration, std::chrono::duration<Rep, Period>>
{
using TValue = Rep;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
#endif //BITSERY_EXT_STD_CHRONO_H
template<typename Clock, typename Rep, typename Period>
struct ExtensionTraits<
ext::StdTimePoint,
std::chrono::time_point<Clock, std::chrono::duration<Rep, Period>>>
{
using TValue = Rep;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif // BITSERY_EXT_STD_CHRONO_H

View File

@@ -1,101 +1,122 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_STD_MAP_H
#define BITSERY_EXT_STD_MAP_H
#include "../traits/core/traits.h"
#include "../details/adapter_common.h"
#include "../details/serialization_common.h"
//we need this, so we could reserve for non ordered map
#include "../traits/core/traits.h"
// we need this, so we could reserve for non ordered map
#include <unordered_map>
namespace bitsery {
namespace ext {
namespace ext {
class StdMap {
public:
class StdMap
{
public:
constexpr explicit StdMap(size_t maxSize)
: _maxSize{ maxSize }
{
}
constexpr explicit StdMap(size_t maxSize):_maxSize{maxSize} {}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
{
using TKey = typename T::key_type;
using TValue = typename T::mapped_type;
auto size = obj.size();
assert(size <= _maxSize);
details::writeSize(ser.adapter(), size);
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
using TKey = typename T::key_type;
using TValue = typename T::mapped_type;
auto size = obj.size();
assert(size <= _maxSize);
details::writeSize(ser.adapter(), size);
for (auto& v : obj)
fnc(ser, const_cast<TKey&>(v.first), const_cast<TValue&>(v.second));
}
for (auto &v:obj)
fnc(ser, const_cast<TKey &>(v.first), const_cast<TValue &>(v.second));
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, T& obj, Fnc&& fnc) const
{
using TKey = typename T::key_type;
using TValue = typename T::mapped_type;
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
using TKey = typename T::key_type;
using TValue = typename T::mapped_type;
size_t size{};
details::readSize(
des.adapter(),
size,
_maxSize,
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
obj.clear();
reserve(obj, size);
size_t size{};
details::readSize(des.adapter(), size, _maxSize,
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
obj.clear();
reserve(obj, size);
auto hint = obj.begin();
for (auto i = 0u; i < size; ++i) {
auto key = bitsery::Access::create<TKey>();
auto value = bitsery::Access::create<TValue>();
fnc(des, key, value);
hint = obj.emplace_hint(hint, std::move(key), std::move(value));
}
}
private:
template <typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& obj, size_t size) const {
obj.reserve(size);
}
template <typename Key, typename T, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& obj, size_t size) const {
obj.reserve(size);
}
template <typename T>
void reserve(T& , size_t ) const {
//for ordered container do nothing
}
size_t _maxSize;
};
auto hint = obj.begin();
for (auto i = 0u; i < size; ++i) {
auto key = bitsery::Access::create<TKey>();
auto value = bitsery::Access::create<TValue>();
fnc(des, key, value);
hint = obj.emplace_hint(hint, std::move(key), std::move(value));
}
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdMap, T> {
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = true;
};
}
private:
template<typename Key,
typename T,
typename Hash,
typename KeyEqual,
typename Allocator>
void reserve(std::unordered_map<Key, T, Hash, KeyEqual, Allocator>& obj,
size_t size) const
{
obj.reserve(size);
}
template<typename Key,
typename T,
typename Hash,
typename KeyEqual,
typename Allocator>
void reserve(std::unordered_multimap<Key, T, Hash, KeyEqual, Allocator>& obj,
size_t size) const
{
obj.reserve(size);
}
template<typename T>
void reserve(T&, size_t) const
{
// for ordered container do nothing
}
size_t _maxSize;
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdMap, T>
{
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = false;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_MAP_H
#endif // BITSERY_EXT_STD_MAP_H

View File

@@ -1,96 +1,109 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_STD_OPTIONAL_H
#define BITSERY_EXT_STD_OPTIONAL_H
#include "../traits/core/traits.h"
#include "../details/serialization_common.h"
#include "../traits/core/traits.h"
#include <optional>
namespace bitsery {
namespace ext {
namespace ext {
class StdOptional {
public:
class StdOptional
{
public:
/**
* Works with std::optional types
* @param alignBeforeData only makes sense when bit-packing enabled, by
* default aligns after writing/reading bool state of optional
*/
explicit StdOptional(bool alignBeforeData = true)
: _alignBeforeData{ alignBeforeData }
{
}
/**
* Works with std::optional types
* @param alignBeforeData only makes sense when bit-packing enabled, by default aligns after writing/reading bool state of optional
*/
explicit StdOptional(bool alignBeforeData=true):_alignBeforeData{alignBeforeData} {}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const std::optional<T>& obj, Fnc&& fnc) const
{
ser.boolValue(static_cast<bool>(obj));
if (_alignBeforeData)
ser.adapter().align();
if (obj)
fnc(ser, const_cast<T&>(*obj));
}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const std::optional<T> &obj, Fnc &&fnc) const {
ser.boolValue(static_cast<bool>(obj));
if (_alignBeforeData)
ser.adapter().align();
if (obj)
fnc(ser, const_cast<T&>(*obj));
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, std::optional<T> &obj, Fnc &&fnc) const {
bool exists{};
des.boolValue(exists);
if (_alignBeforeData)
des.adapter().align();
if (exists) {
deserialize_impl(des, obj, fnc, std::is_trivial<T>{});
} else {
obj = std::nullopt;
}
}
private:
template<typename Des, typename T, typename Fnc>
void deserialize_impl(Des &des, std::optional<T> &obj, Fnc &&fnc, std::true_type) const {
obj = ::bitsery::Access::create<T>();
fnc(des, *obj);
}
template<typename Des, typename T, typename Fnc>
void deserialize_impl(Des &des, std::optional<T> &obj, Fnc &&fnc, std::false_type) const {
if (!obj) {
obj = ::bitsery::Access::create<T>();
}
fnc(des, *obj);
}
bool _alignBeforeData;
};
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, std::optional<T>& obj, Fnc&& fnc) const
{
bool exists{};
des.boolValue(exists);
if (_alignBeforeData)
des.adapter().align();
if (exists) {
deserialize_impl(des, obj, fnc, std::is_trivial<T>{});
} else {
obj = std::nullopt;
}
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdOptional, std::optional<T>> {
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
private:
template<typename Des, typename T, typename Fnc>
void deserialize_impl(Des& des,
std::optional<T>& obj,
Fnc&& fnc,
std::true_type) const
{
obj = ::bitsery::Access::create<T>();
fnc(des, *obj);
}
template<typename Des, typename T, typename Fnc>
void deserialize_impl(Des& des,
std::optional<T>& obj,
Fnc&& fnc,
std::false_type) const
{
if (!obj) {
obj = ::bitsery::Access::create<T>();
}
fnc(des, *obj);
}
bool _alignBeforeData;
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdOptional, std::optional<T>>
{
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_OPTIONAL_H
#endif // BITSERY_EXT_STD_OPTIONAL_H

View File

@@ -1,111 +1,127 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_STD_QUEUE_H
#define BITSERY_EXT_STD_QUEUE_H
#include <type_traits>
#include <queue>
//include type traits for deque and vector, because they are defaults for queue and priority_queue
// include type traits for deque and vector, because they are defaults for queue
// and priority_queue
#include "../traits/deque.h"
#include "../traits/vector.h"
#include <queue>
#include <type_traits>
namespace bitsery {
namespace ext {
namespace ext {
class StdQueue {
private:
//inherit from queue so we could take underlying container
template <typename T, typename C>
struct QueueCnt : public std::queue<T, C>
{
static const C& getContainer(const std::queue<T, C>& s )
{
//get address of underlying container
return s.*(&QueueCnt::c);
}
static C& getContainer(std::queue<T, C>& s )
{
//get address of underlying container
return s.*(&QueueCnt::c);
}
};
//inherit from queue so we could take underlying container
template <typename T, typename Seq, typename Cmp>
struct PriorityQueueCnt : public std::priority_queue<T, Seq, Cmp>
{
static const Seq& getContainer(const std::priority_queue<T, Seq, Cmp>& s )
{
//get address of underlying container
return s.*(&PriorityQueueCnt::c);
}
static Seq& getContainer(std::priority_queue<T, Seq, Cmp>& s )
{
//get address of underlying container
return s.*(&PriorityQueueCnt::c);
}
};
size_t _maxSize;
public:
explicit StdQueue(size_t maxSize):_maxSize{maxSize} {};
//for queue
template<typename Ser, typename T, typename C, typename Fnc>
void serialize(Ser &ser, const std::queue<T,C> &obj, Fnc &&fnc) const {
ser.container(QueueCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename T, typename C, typename Fnc>
void deserialize(Des &des, std::queue<T,C> &obj, Fnc &&fnc) const {
des.container(QueueCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
//for priority_queue
template<typename Ser, typename T, typename C, typename Comp, typename Fnc>
void serialize(Ser &ser, const std::priority_queue<T,C, Comp> &obj, Fnc &&fnc) const {
ser.container(PriorityQueueCnt<T,C, Comp>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename T, typename C, typename Comp, typename Fnc>
void deserialize(Des &des, std::priority_queue<T,C, Comp> &obj, Fnc &&fnc) const {
des.container(PriorityQueueCnt<T,C, Comp>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
};
class StdQueue
{
private:
// inherit from queue so we could take underlying container
template<typename T, typename C>
struct QueueCnt : public std::queue<T, C>
{
static const C& getContainer(const std::queue<T, C>& s)
{
// get address of underlying container
return s.*(&QueueCnt::c);
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdQueue, T> {
using TValue = typename T::value_type;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
static C& getContainer(std::queue<T, C>& s)
{
// get address of underlying container
return s.*(&QueueCnt::c);
}
};
// inherit from queue so we could take underlying container
template<typename T, typename Seq, typename Cmp>
struct PriorityQueueCnt : public std::priority_queue<T, Seq, Cmp>
{
static const Seq& getContainer(const std::priority_queue<T, Seq, Cmp>& s)
{
// get address of underlying container
return s.*(&PriorityQueueCnt::c);
}
static Seq& getContainer(std::priority_queue<T, Seq, Cmp>& s)
{
// get address of underlying container
return s.*(&PriorityQueueCnt::c);
}
};
size_t _maxSize;
public:
explicit StdQueue(size_t maxSize)
: _maxSize{ maxSize } {};
// for queue
template<typename Ser, typename T, typename C, typename Fnc>
void serialize(Ser& ser, const std::queue<T, C>& obj, Fnc&& fnc) const
{
ser.container(
QueueCnt<T, C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename T, typename C, typename Fnc>
void deserialize(Des& des, std::queue<T, C>& obj, Fnc&& fnc) const
{
des.container(
QueueCnt<T, C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
// for priority_queue
template<typename Ser, typename T, typename C, typename Comp, typename Fnc>
void serialize(Ser& ser,
const std::priority_queue<T, C, Comp>& obj,
Fnc&& fnc) const
{
ser.container(PriorityQueueCnt<T, C, Comp>::getContainer(obj),
_maxSize,
std::forward<Fnc>(fnc));
}
template<typename Des, typename T, typename C, typename Comp, typename Fnc>
void deserialize(Des& des,
std::priority_queue<T, C, Comp>& obj,
Fnc&& fnc) const
{
des.container(PriorityQueueCnt<T, C, Comp>::getContainer(obj),
_maxSize,
std::forward<Fnc>(fnc));
}
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdQueue, T>
{
using TValue = typename T::value_type;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_QUEUE_H
#endif // BITSERY_EXT_STD_QUEUE_H

View File

@@ -1,100 +1,109 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_STD_SET_H
#define BITSERY_EXT_STD_SET_H
#include <cassert>
#include "../details/adapter_common.h"
#include "../details/serialization_common.h"
//we need this, so we could reserve for non ordered set
#include <unordered_set>
namespace bitsery {
namespace ext {
namespace ext {
class StdSet {
public:
class StdSet
{
public:
constexpr explicit StdSet(size_t maxSize)
: _maxSize{ maxSize }
{
}
constexpr explicit StdSet(size_t maxSize):_maxSize{maxSize} {}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
{
using TKey = typename T::key_type;
auto size = obj.size();
assert(size <= _maxSize);
details::writeSize(ser.adapter(), size);
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
using TKey = typename T::key_type;
auto size = obj.size();
assert(size <= _maxSize);
details::writeSize(ser.adapter(), size);
for (auto& v : obj)
fnc(ser, const_cast<TKey&>(v));
}
for (auto &v:obj)
fnc(ser, const_cast<TKey &>(v));
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, T& obj, Fnc&& fnc) const
{
using TKey = typename T::key_type;
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
using TKey = typename T::key_type;
size_t size{};
details::readSize(des.adapter(), size, _maxSize, std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
obj.clear();
reserve(obj, size);
auto hint = obj.begin();
for (auto i = 0u; i < size; ++i) {
auto key = bitsery::Access::create<TKey>();
fnc(des, key);
hint = obj.emplace_hint(hint, std::move(key));
}
}
private:
template <typename Key, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_set<Key, Hash, KeyEqual, Allocator>& obj, size_t size) const {
obj.reserve(size);
}
template <typename Key, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& obj, size_t size) const {
obj.reserve(size);
}
template <typename T>
void reserve(T& , size_t ) const {
//for ordered container do nothing
}
size_t _maxSize;
};
size_t size{};
details::readSize(
des.adapter(),
size,
_maxSize,
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
obj.clear();
reserve(obj, size);
auto hint = obj.begin();
for (auto i = 0u; i < size; ++i) {
auto key = bitsery::Access::create<TKey>();
fnc(des, key);
hint = obj.emplace_hint(hint, std::move(key));
}
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdSet, T> {
using TValue = typename T::key_type;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
private:
template<typename Key, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_set<Key, Hash, KeyEqual, Allocator>& obj,
size_t size) const
{
obj.reserve(size);
}
template<typename Key, typename Hash, typename KeyEqual, typename Allocator>
void reserve(std::unordered_multiset<Key, Hash, KeyEqual, Allocator>& obj,
size_t size) const
{
obj.reserve(size);
}
template<typename T>
void reserve(T&, size_t) const
{
// for ordered container do nothing
}
size_t _maxSize;
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdSet, T>
{
using TValue = typename T::key_type;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_SET_H
#endif // BITSERY_EXT_STD_SET_H

View File

@@ -1,29 +1,28 @@
//MIT License
// MIT License
//
//Copyright (c) 2018 Mindaugas Vinkelis
// Copyright (c) 2018 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_STD_SMART_PTR_H
#define BITSERY_EXT_STD_SMART_PTR_H
#include <cassert>
#include "../traits/core/traits.h"
#include "utils/pointer_utils.h"
#include "utils/polymorphism_utils.h"
@@ -31,168 +30,209 @@
#include <memory>
namespace bitsery {
namespace ext {
namespace ext {
namespace smart_ptr_details {
namespace smart_ptr_details {
//further code is for managing shared ownership
//do not nest this type in pointer manager class itself, because it will be different type for different T
struct SharedPtrSharedState : pointer_utils::PointerSharedStateBase {
std::shared_ptr<void> obj{};
};
// further code is for managing shared ownership
// do not nest this type in pointer manager class itself, because it will be
// different type for different T
struct SharedPtrSharedState : pointer_utils::PointerSharedStateBase
{
std::shared_ptr<void> obj{};
};
template<typename T>
struct SmartPtrOwnerManager {
template<typename T>
struct SmartPtrOwnerManager
{
using TElement = typename T::element_type;
using TElement = typename T::element_type;
template<typename TDeleter>
static TElement* getPtr(std::unique_ptr<TElement, TDeleter>& obj) {
return obj.get();
}
template<typename TDeleter>
static TElement* getPtr(std::unique_ptr<TElement, TDeleter>& obj)
{
return obj.get();
}
static TElement* getPtr(std::shared_ptr<TElement>& obj) {
return obj.get();
}
static TElement* getPtr(std::shared_ptr<TElement>& obj) { return obj.get(); }
static TElement* getPtr(std::weak_ptr<TElement>& obj) {
if (auto ptr = obj.lock())
return ptr.get();
return nullptr;
}
static TElement* getPtr(std::weak_ptr<TElement>& obj)
{
if (auto ptr = obj.lock())
return ptr.get();
return nullptr;
}
static constexpr PointerOwnershipType getOwnership() {
return ::bitsery::details::IsSpecializationOf<T, std::unique_ptr>::value
? PointerOwnershipType::Owner
: std::is_same<std::shared_ptr<TElement>, T>::value
? PointerOwnershipType::SharedOwner
: PointerOwnershipType::SharedObserver;
}
static constexpr PointerOwnershipType getOwnership()
{
return ::bitsery::details::IsSpecializationOf<T, std::unique_ptr>::value
? PointerOwnershipType::Owner
: std::is_same<std::shared_ptr<TElement>, T>::value
? PointerOwnershipType::SharedOwner
: PointerOwnershipType::SharedObserver;
}
template<typename TDeleter>
static void create(std::unique_ptr<TElement, TDeleter>& obj, pointer_utils::PolyAllocWithTypeId alloc,
size_t typeId) {
obj.reset(alloc.newObject<TElement>(typeId));
}
template<typename TDeleter>
static void create(std::unique_ptr<TElement, TDeleter>& obj,
pointer_utils::PolyAllocWithTypeId alloc,
size_t typeId)
{
obj.reset(alloc.newObject<TElement>(typeId));
}
template<typename TDeleter>
static void createPolymorphic(std::unique_ptr<TElement, TDeleter>& obj, pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
obj.reset(static_cast<TElement*>(handler->create(alloc)));
}
template<typename TDeleter>
static void createPolymorphic(
std::unique_ptr<TElement, TDeleter>& obj,
pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler)
{
obj.reset(static_cast<TElement*>(handler->create(alloc)));
}
template<typename TDel>
static void destroy(std::unique_ptr<TElement, TDel>& obj, pointer_utils::PolyAllocWithTypeId alloc, size_t typeId) {
auto ptr = obj.release();
alloc.deleteObject(ptr, typeId);
}
template<typename TDel>
static void destroy(std::unique_ptr<TElement, TDel>& obj,
pointer_utils::PolyAllocWithTypeId alloc,
size_t typeId)
{
auto ptr = obj.release();
alloc.deleteObject(ptr, typeId);
}
template<typename TDel>
static void destroyPolymorphic(std::unique_ptr<TElement, TDel>& obj, pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
auto ptr = obj.release();
handler->destroy(alloc, ptr);
}
template<typename TDel>
static void destroyPolymorphic(
std::unique_ptr<TElement, TDel>& obj,
pointer_utils::PolyAllocWithTypeId alloc,
const std::shared_ptr<PolymorphicHandlerBase>& handler)
{
auto ptr = obj.release();
handler->destroy(alloc, ptr);
}
static void destroy(std::shared_ptr<TElement>& obj, MemResourceBase*, size_t) {
obj.reset();
}
static void destroy(std::shared_ptr<TElement>& obj, MemResourceBase*, size_t)
{
obj.reset();
}
static void destroyPolymorphic(std::shared_ptr<TElement>& obj, MemResourceBase*,
const std::shared_ptr<PolymorphicHandlerBase>&) {
obj.reset();
}
static void destroyPolymorphic(std::shared_ptr<TElement>& obj,
MemResourceBase*,
const std::shared_ptr<PolymorphicHandlerBase>&)
{
obj.reset();
}
static void destroy(std::weak_ptr<TElement>& obj, MemResourceBase*, size_t) {
obj.reset();
}
static void destroy(std::weak_ptr<TElement>& obj, MemResourceBase*, size_t)
{
obj.reset();
}
static void destroyPolymorphic(std::weak_ptr<TElement>& obj, MemResourceBase*,
const std::shared_ptr<PolymorphicHandlerBase>&) {
obj.reset();
}
static void destroyPolymorphic(std::weak_ptr<TElement>& obj,
MemResourceBase*,
const std::shared_ptr<PolymorphicHandlerBase>&)
{
obj.reset();
}
// define a type that will store shared state for shared and weak ptrs
using TSharedState = SharedPtrSharedState;
// define a type that will store shared state for shared and weak ptrs
using TSharedState = SharedPtrSharedState;
static void createShared(TSharedState& state,
std::shared_ptr<TElement>& obj, MemResourceBase* memResource, size_t typeId) {
// capture deleter parameters by value
pointer_utils::PolyAllocWithTypeId alloc{memResource};
obj.reset(alloc.newObject<TElement>(typeId), [alloc, typeId](TElement* data) {
alloc.deleteObject(data, typeId);
}, pointer_utils::StdPolyAlloc<TElement>(memResource));
state.obj = obj;
}
static void createShared(TSharedState& state,
std::shared_ptr<TElement>& obj,
MemResourceBase* memResource,
size_t typeId)
{
// capture deleter parameters by value
pointer_utils::PolyAllocWithTypeId alloc{ memResource };
obj.reset(
alloc.newObject<TElement>(typeId),
[alloc, typeId](TElement* data) { alloc.deleteObject(data, typeId); },
pointer_utils::StdPolyAlloc<TElement>(memResource));
state.obj = obj;
}
static void createSharedPolymorphic(TSharedState& state,
std::shared_ptr<TElement>& obj, MemResourceBase* memResource,
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
// capture deleter parameters by value
pointer_utils::PolyAllocWithTypeId alloc{memResource};
obj.reset(static_cast<TElement*>(handler->create(alloc)), [alloc, handler](TElement* data) {
handler->destroy(alloc, data);
}, pointer_utils::StdPolyAlloc<TElement>(memResource));
state.obj = obj;
}
static void createSharedPolymorphic(
TSharedState& state,
std::shared_ptr<TElement>& obj,
MemResourceBase* memResource,
const std::shared_ptr<PolymorphicHandlerBase>& handler)
{
// capture deleter parameters by value
pointer_utils::PolyAllocWithTypeId alloc{ memResource };
obj.reset(
static_cast<TElement*>(handler->create(alloc)),
[alloc, handler](TElement* data) { handler->destroy(alloc, data); },
pointer_utils::StdPolyAlloc<TElement>(memResource));
state.obj = obj;
}
static void createShared(TSharedState& state,
std::weak_ptr<TElement>& obj, MemResourceBase* memResource, size_t typeId) {
pointer_utils::PolyAllocWithTypeId alloc{memResource};
std::shared_ptr<TElement> res(alloc.newObject<TElement>(typeId),[alloc, typeId](TElement* data) {
alloc.deleteObject(data, typeId);
}, pointer_utils::StdPolyAlloc<TElement>(memResource));
obj = res;
state.obj = res;
}
static void createShared(TSharedState& state,
std::weak_ptr<TElement>& obj,
MemResourceBase* memResource,
size_t typeId)
{
pointer_utils::PolyAllocWithTypeId alloc{ memResource };
std::shared_ptr<TElement> res(
alloc.newObject<TElement>(typeId),
[alloc, typeId](TElement* data) { alloc.deleteObject(data, typeId); },
pointer_utils::StdPolyAlloc<TElement>(memResource));
obj = res;
state.obj = res;
}
static void createSharedPolymorphic(TSharedState& state,
std::weak_ptr<TElement>& obj, MemResourceBase* memResource,
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
pointer_utils::PolyAllocWithTypeId alloc{memResource};
std::shared_ptr<TElement> res(static_cast<TElement*>(handler->create(alloc)),
[alloc, handler](TElement* data) {
handler->destroy(alloc, data);
}, pointer_utils::StdPolyAlloc<TElement>(memResource));
obj = res;
state.obj = res;
}
static void createSharedPolymorphic(
TSharedState& state,
std::weak_ptr<TElement>& obj,
MemResourceBase* memResource,
const std::shared_ptr<PolymorphicHandlerBase>& handler)
{
pointer_utils::PolyAllocWithTypeId alloc{ memResource };
std::shared_ptr<TElement> res(
static_cast<TElement*>(handler->create(alloc)),
[alloc, handler](TElement* data) { handler->destroy(alloc, data); },
pointer_utils::StdPolyAlloc<TElement>(memResource));
obj = res;
state.obj = res;
}
static void saveToSharedState(TSharedState& state, T& obj) {
state.obj = std::shared_ptr<TElement>(obj);
}
static void saveToSharedState(TSharedState& state, T& obj)
{
state.obj = std::shared_ptr<TElement>(obj);
}
static void loadFromSharedState(TSharedState& state, T& obj) {
//reinterpret_pointer_cast is only since c++17
auto p = reinterpret_cast<TElement*>(state.obj.get());
obj = std::shared_ptr<TElement>(state.obj, p);
}
static void loadFromSharedState(TSharedState& state, T& obj)
{
// reinterpret_pointer_cast is only since c++17
auto p = reinterpret_cast<TElement*>(state.obj.get());
obj = std::shared_ptr<TElement>(state.obj, p);
}
};
}
};
}
template<typename RTTI>
using StdSmartPtrBase = pointer_utils::PointerObjectExtensionBase<
smart_ptr_details::SmartPtrOwnerManager,
PolymorphicContext,
RTTI>;
template<typename RTTI>
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>();
};
}
// helper type for convienience
using StdSmartPtr = StdSmartPtrBase<StandardRTTI>;
}
#endif //BITSERY_EXT_STD_SMART_PTR_H
namespace traits {
template<typename T, typename RTTI>
struct ExtensionTraits<ext::StdSmartPtrBase<RTTI>, T>
{
using TValue = typename T::element_type;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
// if underlying type is not polymorphic, then we can enable lambda syntax
static constexpr bool SupportLambdaOverload =
!RTTI::template isPolymorphic<TValue>();
};
}
}
#endif // BITSERY_EXT_STD_SMART_PTR_H

View File

@@ -1,82 +1,85 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_STD_STACK_H
#define BITSERY_EXT_STD_STACK_H
#include <type_traits>
#include <stack>
//include type traits for deque, because stack default underlying container is deque
#include "../traits/deque.h"
#include <stack>
namespace bitsery {
namespace ext {
namespace ext {
class StdStack {
private:
//inherit from stack so we could take underlying container
template <typename T, typename C>
struct StackCnt : public std::stack<T, C>
{
static const C& getContainer(const std::stack<T, C>& s )
{
//get address of underlying container
return s.*(&StackCnt::c);
}
static C& getContainer(std::stack<T, C>& s )
{
//get address of underlying container
return s.*(&StackCnt::c);
}
};
size_t _maxSize;
public:
explicit StdStack(size_t maxSize):_maxSize{maxSize} {};
template<typename Ser, typename T, typename C, typename Fnc>
void serialize(Ser &ser, const std::stack<T,C> &obj, Fnc &&fnc) const {
ser.container(StackCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename T, typename C, typename Fnc>
void deserialize(Des &des, std::stack<T,C> &obj, Fnc &&fnc) const {
des.container(StackCnt<T,C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
};
class StdStack
{
private:
// inherit from stack so we could take underlying container
template<typename T, typename C>
struct StackCnt : public std::stack<T, C>
{
static const C& getContainer(const std::stack<T, C>& s)
{
// get address of underlying container
return s.*(&StackCnt::c);
}
namespace traits {
template<typename T, typename Seq>
struct ExtensionTraits<ext::StdStack, std::stack<T, Seq>> {
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
static C& getContainer(std::stack<T, C>& s)
{
// get address of underlying container
return s.*(&StackCnt::c);
}
};
size_t _maxSize;
public:
explicit StdStack(size_t maxSize)
: _maxSize{ maxSize } {};
template<typename Ser, typename T, typename C, typename Fnc>
void serialize(Ser& ser, const std::stack<T, C>& obj, Fnc&& fnc) const
{
ser.container(
StackCnt<T, C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
template<typename Des, typename T, typename C, typename Fnc>
void deserialize(Des& des, std::stack<T, C>& obj, Fnc&& fnc) const
{
des.container(
StackCnt<T, C>::getContainer(obj), _maxSize, std::forward<Fnc>(fnc));
}
};
}
namespace traits {
template<typename T, typename Seq>
struct ExtensionTraits<ext::StdStack, std::stack<T, Seq>>
{
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;
};
}
}
#endif //BITSERY_EXT_STD_STACK_H
#endif // BITSERY_EXT_STD_STACK_H

View File

@@ -1,81 +1,83 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_STD_TUPLE_H
#define BITSERY_EXT_STD_TUPLE_H
#include "utils/composite_type_overloads.h"
#include "../traits/core/traits.h"
#include "utils/composite_type_overloads.h"
#include <tuple>
namespace bitsery {
namespace ext {
namespace ext {
template<typename ...Overloads>
class StdTuple : public details::CompositeTypeOverloadsUtils<std::tuple, Overloads...> {
public:
template<typename... Overloads>
class StdTuple
: public details::CompositeTypeOverloadsUtils<std::tuple, Overloads...>
{
public:
template<typename Ser, typename Fnc, typename... Ts>
void serialize(Ser& ser, const std::tuple<Ts...>& obj, Fnc&&) const
{
serializeAll(ser, const_cast<std::tuple<Ts...>&>(obj));
}
template<typename Ser, typename Fnc, typename ...Ts>
void serialize(Ser& ser, const std::tuple<Ts...>& obj, Fnc&&) const {
serializeAll(ser, const_cast<std::tuple<Ts...>&>(obj));
}
template<typename Des, typename Fnc, typename... Ts>
void deserialize(Des& des, std::tuple<Ts...>& obj, Fnc&&) const
{
serializeAll(des, obj);
}
template<typename Des, typename Fnc, typename ...Ts>
void deserialize(Des& des, std::tuple<Ts...>& obj, Fnc&&) const {
serializeAll(des, obj);
}
private:
template<typename S, typename... Ts>
void serializeAll(S& s, std::tuple<Ts...>& obj) const
{
this->execAll(obj, [this, &s](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
this->serializeType(s, std::get<Index>(data));
});
}
};
private:
template<typename S, typename ...Ts>
void serializeAll(S& s, std::tuple<Ts...>& obj) const {
this->execAll(obj, [this, &s](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
this->serializeType(s, std::get<Index>(data));
});
}
};
// deduction guide
template<typename... Overloads>
StdTuple(Overloads...) -> StdTuple<Overloads...>;
}
// deduction guide
template<typename ...Overloads>
StdTuple(Overloads...) -> StdTuple<Overloads...>;
}
namespace traits {
namespace traits {
template<typename Tuple, typename ... Overloads>
struct ExtensionTraits<ext::StdTuple<Overloads...>, Tuple> {
static_assert(bitsery::details::IsSpecializationOf<Tuple, std::tuple>::value,
"StdTuple only works with std::tuple");
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
template<typename Tuple, typename... Overloads>
struct ExtensionTraits<ext::StdTuple<Overloads...>, Tuple>
{
static_assert(bitsery::details::IsSpecializationOf<Tuple, std::tuple>::value,
"StdTuple only works with std::tuple");
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif //BITSERY_EXT_STD_TUPLE_H
#endif // BITSERY_EXT_STD_TUPLE_H

View File

@@ -1,102 +1,114 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_STD_VARIANT_H
#define BITSERY_EXT_STD_VARIANT_H
#include "utils/composite_type_overloads.h"
#include "../traits/core/traits.h"
#include "utils/composite_type_overloads.h"
#include <variant>
namespace bitsery {
namespace ext {
namespace ext {
template<typename ...Overloads>
class StdVariant : public details::CompositeTypeOverloadsUtils<std::variant, Overloads...> {
public:
template<typename... Overloads>
class StdVariant
: public details::CompositeTypeOverloadsUtils<std::variant, Overloads...>
{
public:
template<typename Ser, typename Fnc, typename... Ts>
void serialize(Ser& ser, const std::variant<Ts...>& obj, Fnc&&) const
{
auto index = obj.index();
assert(index != std::variant_npos);
details::writeSize(ser.adapter(), index);
this->execIndex(index,
const_cast<std::variant<Ts...>&>(obj),
[this, &ser](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
this->serializeType(ser, std::get<Index>(data));
});
}
template<typename Ser, typename Fnc, typename ...Ts>
void serialize(Ser& ser, const std::variant<Ts...>& obj, Fnc&&) const {
auto index = obj.index();
assert(index != std::variant_npos);
details::writeSize(ser.adapter(), index);
this->execIndex(index, const_cast<std::variant<Ts...>&>(obj), [this, &ser](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
this->serializeType(ser, std::get<Index>(data));
});
}
template<typename Des, typename Fnc, typename... Ts>
void deserialize(Des& des, std::variant<Ts...>& obj, Fnc&&) const
{
size_t index{};
details::readSize(
des.adapter(),
index,
sizeof...(Ts),
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
this->execIndex(index, obj, [this, &des](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
using TElem =
typename std::variant_alternative<Index, std::variant<Ts...>>::type;
template<typename Des, typename Fnc, typename ...Ts>
void deserialize(Des& des, std::variant<Ts...>& obj, Fnc&&) const {
size_t index{};
details::readSize(des.adapter(), index, sizeof...(Ts), std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
this->execIndex(index, obj, [this, &des](auto& data, auto index) {
constexpr size_t Index = decltype(index)::value;
using TElem = typename std::variant_alternative<Index, std::variant<Ts...>>::type;
// Reinitializing nontrivial types may be expensive especially when they
// reference heap data, so if `data` is already holding the requested
// variant then we'll deserialize into the existing object
if constexpr (!std::is_trivial_v<TElem>) {
if (auto item = std::get_if<Index>(&data)) {
this->serializeType(des, *item);
return;
}
}
// Reinitializing nontrivial types may be expensive especially when they
// reference heap data, so if `data` is already holding the requested
// variant then we'll deserialize into the existing object
if constexpr (!std::is_trivial_v<TElem>) {
if (auto item = std::get_if<Index>(&data)) {
this->serializeType(des, *item);
return;
}
}
TElem item = ::bitsery::Access::create<TElem>();
this->serializeType(des, item);
data =
std::variant<Ts...>(std::in_place_index_t<Index>{}, std::move(item));
});
}
};
TElem item = ::bitsery::Access::create<TElem>();
this->serializeType(des, item);
data = std::variant<Ts...>(std::in_place_index_t<Index>{}, std::move(item));
});
}
// deduction guide
template<typename... Overloads>
StdVariant(Overloads...) -> StdVariant<Overloads...>;
}
};
// defines empty fuction, that handles monostate
template<typename S>
void
serialize(S&, std::monostate&)
{
}
// deduction guide
template<typename ...Overloads>
StdVariant(Overloads...) -> StdVariant<Overloads...>;
}
namespace traits {
//defines empty fuction, that handles monostate
template <typename S>
void serialize(S& , std::monostate&) {}
namespace traits {
template<typename Variant, typename ... Overloads>
struct ExtensionTraits<ext::StdVariant<Overloads...>, Variant> {
static_assert(bitsery::details::IsSpecializationOf<Variant, std::variant>::value,
"StdVariant only works with std::variant");
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
template<typename Variant, typename... Overloads>
struct ExtensionTraits<ext::StdVariant<Overloads...>, Variant>
{
static_assert(
bitsery::details::IsSpecializationOf<Variant, std::variant>::value,
"StdVariant only works with std::variant");
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif //BITSERY_EXT_STD_VARIANT_H
#endif // BITSERY_EXT_STD_VARIANT_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_COMPOSITE_TYPE_OVERLOADS_H
#define BITSERY_EXT_COMPOSITE_TYPE_OVERLOADS_H
@@ -29,108 +29,131 @@
#if __cplusplus < 201703L
#error these utils requires c++17
// in theory, it could be implemented using C++11
// but without class template argument deduction guides that would be very inconvenient to use
// these are very helpul for sum types (e.g. std::variant),
// but for product types (e.g. std::tuple) you can you can easily do it your self with lambda, without extension
// but without class template argument deduction guides that would be very
// inconvenient to use these are very helpul for sum types (e.g. std::variant),
// but for product types (e.g. std::tuple) you can you can easily do it your
// self with lambda, without extension
#endif
namespace bitsery {
namespace ext {
// might be usable, when you want to have one overload set for different composite types,
// e.g. variant, tuple and pair
template<class... Ts>
struct CompositeTypeOverloads : Ts ... {
using Ts::operator()...;
};
namespace ext {
// might be usable, when you want to have one overload set for different
// composite types, e.g. variant, tuple and pair
template<class... Ts>
struct CompositeTypeOverloads : Ts...
{
using Ts::operator()...;
};
template<typename ...Overloads>
CompositeTypeOverloads(Overloads...) -> CompositeTypeOverloads<Overloads...>;
template<typename... Overloads>
CompositeTypeOverloads(Overloads...) -> CompositeTypeOverloads<Overloads...>;
// convenient way to invoke s.value<N>, shorter than specifying a lambda
template<typename T, size_t N>
struct OverloadValue {
template <typename S>
void operator()(S& s, T& v) const {
s.template value<N>(v);
}
};
// convenient way to invoke s.value<N>, shorter than specifying a lambda
template<typename T, size_t N>
struct OverloadValue
{
template<typename S>
void operator()(S& s, T& v) const
{
s.template value<N>(v);
}
};
// convenient way to invoke other extension using value or object overloads
// there is no reason to write OverloadExtLambda,
// because you'll need to specify lambda type, which is very inconvenient and it will be much
// easier to simple write a lambda with extension inside it,
// in order to implement it in a convenient way, i need a way to deduce only last template parameter (lambda type)
// but this is not possible with deduction guides at the moment
// convenient way to invoke other extension using value or object overloads
// there is no reason to write OverloadExtLambda,
// because you'll need to specify lambda type, which is very inconvenient and it
// will be much easier to simple write a lambda with extension inside it, in
// order to implement it in a convenient way, i need a way to deduce only last
// template parameter (lambda type) but this is not possible with deduction
// guides at the moment
template<typename T, size_t N, typename Ext>
struct OverloadExtValue : public Ext {
template <typename S>
void operator()(S& s, T& v) const {
s.template ext<N>(v, static_cast<const Ext&>(*this));
}
};
template<typename T, size_t N, typename Ext>
struct OverloadExtValue : public Ext
{
template<typename S>
void operator()(S& s, T& v) const
{
s.template ext<N>(v, static_cast<const Ext&>(*this));
}
};
template<typename T, typename Ext>
struct OverloadExtObject : public Ext {
template <typename S>
void operator()(S& s, T& v) const {
s.ext(v, static_cast<const Ext&>(*this));
}
};
}
namespace details {
template<template<typename ...> typename CompositeType, typename ...Overloads>
class CompositeTypeOverloadsUtils : public ext::CompositeTypeOverloads<Overloads...> {
protected:
// converts run-time index to compile-time index,
// by calling lambda with std::integral_constant<size_t, INDEX>
template<typename Fnc, typename ... Ts>
void execIndex(size_t index, CompositeType<Ts...>& obj, Fnc&& fnc) const {
execIndexImpl(index, obj, std::forward<Fnc>(fnc), std::index_sequence_for<Ts...>{});
}
// call lambda for all indexes in composite type
template<typename Fnc, typename ... Ts>
void execAll(CompositeType<Ts...>& obj, Fnc&& fnc) const {
execAllImpl(obj, std::forward<Fnc>(fnc), std::index_sequence_for<Ts...>{});
}
// serialize a type, by using overload first
template<typename S, typename T>
void serializeType(S& s, T& v) const {
// first check if overload exists, otherwise try to call serialize method
if constexpr (hasOverload<S, T>()) {
std::invoke(*this, s, v);
} else {
static_assert(details::SerializeFunction<S, T>::isDefined(),
"Please define overload or 'serialize' function for your type.");
s.object(v);
}
}
private:
template<typename S, typename T>
static constexpr bool hasOverload() {
return std::is_invocable<ext::CompositeTypeOverloads<Overloads...>,
std::add_lvalue_reference_t<S>, std::add_lvalue_reference_t<T>>::value;
}
template<typename Variant, typename Fnc, size_t ...Is>
void execIndexImpl(size_t index, Variant& obj, Fnc&& fnc, std::index_sequence<Is...>) const {
((index == Is ? fnc(obj, std::integral_constant<size_t, Is>{}), 0 : 0), ...);
}
template<typename Variant, typename Fnc, size_t ...Is>
void execAllImpl(Variant& obj, Fnc&& fnc, std::index_sequence<Is...>) const {
(fnc(obj, std::integral_constant<size_t, Is>{}), ...);
}
};
}
template<typename T, typename Ext>
struct OverloadExtObject : public Ext
{
template<typename S>
void operator()(S& s, T& v) const
{
s.ext(v, static_cast<const Ext&>(*this));
}
};
}
#endif //BITSERY_EXT_COMPOSITE_TYPE_OVERLOADS_H
namespace details {
template<template<typename...> typename CompositeType, typename... Overloads>
class CompositeTypeOverloadsUtils
: public ext::CompositeTypeOverloads<Overloads...>
{
protected:
// converts run-time index to compile-time index,
// by calling lambda with std::integral_constant<size_t, INDEX>
template<typename Fnc, typename... Ts>
void execIndex(size_t index, CompositeType<Ts...>& obj, Fnc&& fnc) const
{
execIndexImpl(
index, obj, std::forward<Fnc>(fnc), std::index_sequence_for<Ts...>{});
}
// call lambda for all indexes in composite type
template<typename Fnc, typename... Ts>
void execAll(CompositeType<Ts...>& obj, Fnc&& fnc) const
{
execAllImpl(obj, std::forward<Fnc>(fnc), std::index_sequence_for<Ts...>{});
}
// serialize a type, by using overload first
template<typename S, typename T>
void serializeType(S& s, T& v) const
{
// first check if overload exists, otherwise try to call serialize method
if constexpr (hasOverload<S, T>()) {
std::invoke(*this, s, v);
} else {
static_assert(
details::SerializeFunction<S, T>::isDefined(),
"Please define overload or 'serialize' function for your type.");
s.object(v);
}
}
private:
template<typename S, typename T>
static constexpr bool hasOverload()
{
return std::is_invocable<ext::CompositeTypeOverloads<Overloads...>,
std::add_lvalue_reference_t<S>,
std::add_lvalue_reference_t<T>>::value;
}
template<typename Variant, typename Fnc, size_t... Is>
void execIndexImpl(size_t index,
Variant& obj,
Fnc&& fnc,
std::index_sequence<Is...>) const
{
((index == Is ? fnc(obj, std::integral_constant<size_t, Is>{}), 0 : 0),
...);
}
template<typename Variant, typename Fnc, size_t... Is>
void execAllImpl(Variant& obj, Fnc&& fnc, std::index_sequence<Is...>) const
{
(fnc(obj, std::integral_constant<size_t, Is>{}), ...);
}
};
}
}
#endif // BITSERY_EXT_COMPOSITE_TYPE_OVERLOADS_H

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2018 Mindaugas Vinkelis
// Copyright (c) 2018 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_MEMORY_RESOURCE_H
#define BITSERY_EXT_MEMORY_RESOURCE_H
@@ -27,145 +27,170 @@
#include <new>
namespace bitsery {
namespace ext {
// these are very similar to c++17 polymorphic allocator and memory resource classes
// but i don't want to enforce users to use c++17 if they want to use pointers
// plus this has additional information from RTTI about runtime type information,
// might be useful working with polymorphic types.
// The same memory resource is used to allocate internal data in various contexts,
// (typeId is always 0 for internal data allocation in contexts).
namespace ext {
// these are very similar to c++17 polymorphic allocator and memory resource
// classes but i don't want to enforce users to use c++17 if they want to use
// pointers plus this has additional information from RTTI about runtime type
// information, might be useful working with polymorphic types. The same memory
// resource is used to allocate internal data in various contexts, (typeId is
// always 0 for internal data allocation in contexts).
class MemResourceBase {
public:
virtual void* allocate(size_t bytes, size_t alignment, size_t typeId) = 0;
class MemResourceBase
{
public:
virtual void* allocate(size_t bytes, size_t alignment, size_t typeId) = 0;
virtual void deallocate(void* ptr, size_t bytes, size_t alignment, size_t typeId) noexcept = 0;
virtual void deallocate(void* ptr,
size_t bytes,
size_t alignment,
size_t typeId) noexcept = 0;
virtual ~MemResourceBase() noexcept = default;
};
virtual ~MemResourceBase() noexcept = default;
};
// default implementation for MemResourceBase using new and delete
class MemResourceNewDelete final: public MemResourceBase {
public:
inline void* allocate(size_t bytes, size_t /*alignment*/, size_t /*typeId*/) final {
return (::operator new(bytes));
}
// default implementation for MemResourceBase using new and delete
class MemResourceNewDelete final : public MemResourceBase
{
public:
inline void* allocate(size_t bytes,
size_t /*alignment*/,
size_t /*typeId*/) final
{
return (::operator new(bytes));
}
inline void
deallocate(void* ptr, size_t /*bytes*/, size_t /*alignment*/, size_t /*typeId*/) noexcept final {
(::operator delete(ptr));
}
inline void deallocate(void* ptr,
size_t /*bytes*/,
size_t /*alignment*/,
size_t /*typeId*/) noexcept final
{
(::operator delete(ptr));
}
~MemResourceNewDelete() noexcept final = default;
};
~MemResourceNewDelete() noexcept final = default;
};
// these classes are used internally by bitsery extensions and and pointer utils
namespace pointer_utils {
// this is helper class that stores memory resource and knows how to construct/destroy objects
// capture this by value for custom deleters, because during deserialization mem resource can be changed
class PolyAllocWithTypeId final {
public:
// these classes are used internally by bitsery extensions and and pointer utils
namespace pointer_utils {
// this is helper class that stores memory resource and knows how to
// construct/destroy objects capture this by value for custom deleters, because
// during deserialization mem resource can be changed
class PolyAllocWithTypeId final
{
public:
constexpr PolyAllocWithTypeId(MemResourceBase* memResource = nullptr)
: _resource{ memResource }
{
}
constexpr PolyAllocWithTypeId(MemResourceBase* memResource = nullptr)
:_resource{memResource} {}
template<typename T>
T* allocate(size_t n, size_t typeId) const
{
const auto bytes = sizeof(T) * n;
constexpr auto alignment = std::alignment_of<T>::value;
void* ptr =
_resource
? _resource->allocate(bytes, alignment, typeId)
: ext::MemResourceNewDelete{}.allocate(bytes, alignment, typeId);
return static_cast<T*>(ptr);
}
template<typename T>
T* allocate(size_t n, size_t typeId) const {
const auto bytes = sizeof(T) * n;
constexpr auto alignment = std::alignment_of<T>::value;
void* ptr = _resource
? _resource->allocate(bytes, alignment, typeId)
: ext::MemResourceNewDelete{}.allocate(bytes, alignment, typeId);
return static_cast<T*>(ptr);
}
template<typename T>
void deallocate(T* ptr, size_t n, size_t typeId) const noexcept
{
const auto bytes = sizeof(T) * n;
constexpr auto alignment = std::alignment_of<T>::value;
_resource
? _resource->deallocate(ptr, bytes, alignment, typeId)
: ext::MemResourceNewDelete{}.deallocate(ptr, bytes, alignment, typeId);
}
template<typename T>
void deallocate(T* ptr, size_t n, size_t typeId) const noexcept {
const auto bytes = sizeof(T) * n;
constexpr auto alignment = std::alignment_of<T>::value;
_resource
? _resource->deallocate(ptr, bytes, alignment, typeId)
: ext::MemResourceNewDelete{}.deallocate(ptr, bytes, alignment, typeId);
}
template<typename T>
T* newObject(size_t typeId) const
{
auto ptr = allocate<T>(1, typeId);
return ::bitsery::Access::create<T>(ptr);
}
template<typename T>
T* newObject(size_t typeId) const {
auto ptr = allocate<T>(1, typeId);
return ::bitsery::Access::create<T>(ptr);
}
template<typename T>
void deleteObject(T* obj, size_t typeId) const
{
obj->~T();
deallocate(obj, 1, typeId);
}
template<typename T>
void deleteObject(T* obj, size_t typeId) const {
obj->~T();
deallocate(obj, 1, typeId);
}
void setMemResource(ext::MemResourceBase* resource) { _resource = resource; }
void setMemResource(ext::MemResourceBase* resource) {
_resource = resource;
}
ext::MemResourceBase* getMemResource() const { return _resource; }
ext::MemResourceBase* getMemResource() const {
return _resource;
}
bool operator==(const PolyAllocWithTypeId& rhs) const noexcept
{
return _resource == rhs._resource;
}
bool operator==(const PolyAllocWithTypeId& rhs) const noexcept {
return _resource == rhs._resource;
}
bool operator!=(const PolyAllocWithTypeId& rhs) const noexcept
{
return !(*this == rhs);
}
bool operator!=(const PolyAllocWithTypeId& rhs) const noexcept {
return !(*this == rhs);
}
private:
ext::MemResourceBase* _resource;
};
private:
ext::MemResourceBase* _resource;
};
// this is very similar to c++17 PolymorphicAllocator
// it just wraps our PolyAllocWithTypeId and pass 0 as typeId
// and defines core functions for c++ Allocator concept,
template<class T>
class StdPolyAlloc
{
public:
using value_type = T;
// this is very similar to c++17 PolymorphicAllocator
// it just wraps our PolyAllocWithTypeId and pass 0 as typeId
// and defines core functions for c++ Allocator concept,
template<class T>
class StdPolyAlloc {
public:
using value_type = T;
explicit constexpr StdPolyAlloc(MemResourceBase* memResource)
: _alloc{ memResource }
{
}
explicit constexpr StdPolyAlloc(PolyAllocWithTypeId alloc)
: _alloc{ alloc }
{
}
explicit constexpr StdPolyAlloc(MemResourceBase* memResource)
:_alloc{memResource} {}
explicit constexpr StdPolyAlloc(PolyAllocWithTypeId alloc) : _alloc{alloc} {}
template<typename U>
friend class StdPolyAlloc;
template <typename U>
friend class StdPolyAlloc;
template<class U>
constexpr explicit StdPolyAlloc(const StdPolyAlloc<U>& other) noexcept
: _alloc{ other._alloc }
{
}
template<class U>
constexpr explicit StdPolyAlloc(const StdPolyAlloc<U>& other) noexcept
:_alloc{other._alloc} {
}
T* allocate(std::size_t n) { return _alloc.allocate<T>(n, 0); }
T* allocate(std::size_t n) {
return _alloc.allocate<T>(n, 0);
}
void deallocate(T* p, std::size_t n) noexcept
{
return _alloc.deallocate(p, n, 0);
}
void deallocate(T* p, std::size_t n) noexcept {
return _alloc.deallocate(p, n, 0);
}
template<class U>
friend bool operator==(const StdPolyAlloc<T>& lhs,
const StdPolyAlloc<U>& rhs) noexcept
{
return lhs._alloc == rhs._alloc;
}
template<class U>
friend bool operator==(const StdPolyAlloc<T>& lhs,
const StdPolyAlloc<U>& rhs) noexcept {
return lhs._alloc == rhs._alloc;
}
template<class U>
friend bool operator!=(const StdPolyAlloc<T>& lhs,
const StdPolyAlloc<U>& rhs) noexcept
{
return !(lhs == rhs);
}
template<class U>
friend bool operator!=(const StdPolyAlloc<T>& lhs,
const StdPolyAlloc<U>& rhs) noexcept {
return !(lhs == rhs);
}
private:
PolyAllocWithTypeId _alloc;
};
}
}
private:
PolyAllocWithTypeId _alloc;
};
}
#endif //BITSERY_EXT_MEMORY_RESOURCE_H
}
}
#endif // BITSERY_EXT_MEMORY_RESOURCE_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,287 +1,366 @@
//MIT License
// MIT License
//
//Copyright (c) 2018 Mindaugas Vinkelis
// Copyright (c) 2018 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_POLYMORPHISM_UTILS_H
#define BITSERY_EXT_POLYMORPHISM_UTILS_H
#include <unordered_map>
#include <memory>
#include "memory_resource.h"
#include "../../details/adapter_common.h"
#include "../../details/serialization_common.h"
#include <memory>
#include <unordered_map>
#include <vector>
namespace bitsery {
namespace ext {
namespace ext {
//helper type, that contains list of types
template<typename ...>
struct PolymorphicClassesList {
};
// helper type, that contains list of types
template<typename...>
struct PolymorphicClassesList
{
};
//specialize for your base class by deriving from PolymorphicDerivedClasses with list of derivatives that DIRECTLY inherits from your base class.
//e.g.
// template <> PolymorphicBaseClass<Animal>: PolymorphicDerivedClasses<Dog, Cat>{};
// template <> PolymorphicBaseClass<Dog>: PolymorphicDerivedClasses<Bulldog, GoldenRetriever> {};
// IMPORTANT !!!
// although you can add all derivates to same base like this:
// template <> PolymorphicBaseClass<Animal>:PolymorphicDerivedClasses<Dog, Cat, Bulldog, GoldenRetriever>{};
// it will not work when you try to serialize Dog*, because it will not find Bulldog and GoldenRetriever
template<typename TBase>
struct PolymorphicBaseClass {
using Childs = PolymorphicClassesList<>;
};
// specialize for your base class by deriving from PolymorphicDerivedClasses
// with list of derivatives that DIRECTLY inherits from your base class.
// e.g.
// template <> PolymorphicBaseClass<Animal>: PolymorphicDerivedClasses<Dog,
// Cat>{}; template <> PolymorphicBaseClass<Dog>:
// PolymorphicDerivedClasses<Bulldog, GoldenRetriever> {}; IMPORTANT !!!
// although you can add all derivates to same base like this:
// template <> PolymorphicBaseClass<Animal>:PolymorphicDerivedClasses<Dog, Cat,
// Bulldog, GoldenRetriever>{}; it will not work when you try to serialize
// Dog*, because it will not find Bulldog and GoldenRetriever
template<typename TBase>
struct PolymorphicBaseClass
{
using Childs = PolymorphicClassesList<>;
};
//derive from this class when specifying childs for your base class, atleast one child must exists, hence T1
//e.g.
// template <> PolymorphicBaseClass<Animal>: PolymorphicDerivedClasses<Dog, Cat>{};
template<typename T1, typename ... Tn>
struct PolymorphicDerivedClasses {
using Childs = PolymorphicClassesList<T1, Tn...>;
};
// derive from this class when specifying childs for your base class, atleast
// one child must exists, hence T1 e.g.
// template <> PolymorphicBaseClass<Animal>: PolymorphicDerivedClasses<Dog,
// Cat>{};
template<typename T1, typename... Tn>
struct PolymorphicDerivedClasses
{
using Childs = PolymorphicClassesList<T1, Tn...>;
};
class PolymorphicHandlerBase {
public:
virtual void* create(const pointer_utils::PolyAllocWithTypeId& alloc) const = 0;
class PolymorphicHandlerBase
{
public:
virtual void* create(
const pointer_utils::PolyAllocWithTypeId& alloc) const = 0;
virtual void destroy(const pointer_utils::PolyAllocWithTypeId& alloc, void* ptr) const = 0;
virtual void destroy(const pointer_utils::PolyAllocWithTypeId& alloc,
void* ptr) const = 0;
virtual void process(void* ser, void* obj) const = 0;
virtual void process(void* ser, void* obj) const = 0;
virtual ~PolymorphicHandlerBase() = default;
};
virtual ~PolymorphicHandlerBase() = default;
};
template<typename RTTI, typename TSerializer, typename TBase, typename TDerived>
class PolymorphicHandler : public PolymorphicHandlerBase {
public:
template<typename RTTI, typename TSerializer, 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>()));
}
void* create(const pointer_utils::PolyAllocWithTypeId& alloc) const final {
return toBase(alloc.newObject<TDerived>(RTTI::template get<TDerived>()));
}
void destroy(const pointer_utils::PolyAllocWithTypeId& alloc,
void* ptr) const final
{
alloc.deleteObject<TDerived>(fromBase(ptr), RTTI::template get<TDerived>());
}
void destroy(const pointer_utils::PolyAllocWithTypeId& alloc, void* ptr) const final {
alloc.deleteObject<TDerived>(fromBase(ptr), RTTI::template get<TDerived>());
}
void process(void* ser, void* obj) const final
{
static_cast<TSerializer*>(ser)->object(*fromBase(obj));
}
void process(void* ser, void* obj) const final {
static_cast<TSerializer*>(ser)->object(*fromBase(obj));
}
private:
TDerived* fromBase(void* obj) const
{
return RTTI::template cast<TBase, TDerived>(static_cast<TBase*>(obj));
}
private:
TBase* toBase(void* obj) const
{
return RTTI::template cast<TDerived, TBase>(static_cast<TDerived*>(obj));
}
};
TDerived* fromBase(void* obj) const {
return RTTI::template cast<TBase, TDerived>(static_cast<TBase*>(obj));
}
template<typename RTTI>
class PolymorphicContext
{
private:
struct BaseToDerivedKey
{
TBase* toBase(void* obj) const {
return RTTI::template cast<TDerived, TBase>(static_cast<TDerived*>(obj));
}
};
template<typename RTTI>
class PolymorphicContext {
private:
struct BaseToDerivedKey {
std::size_t baseHash;
std::size_t derivedHash;
bool operator==(const BaseToDerivedKey& other) const {
return baseHash == other.baseHash && derivedHash == other.derivedHash;
}
};
struct BaseToDerivedKeyHashier {
size_t operator()(const BaseToDerivedKey& key) const {
return (key.baseHash + (key.baseHash << 6) + (key.derivedHash >> 2)) ^ key.derivedHash;
}
};
template<typename TSerializer, template<typename> class THierarchy, typename TBase, typename TDerived>
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 addChilds(PolymorphicClassesList<T1, Tn...>) {
static_assert(std::is_base_of<TDerived, T1>::value,
"PolymorphicBaseClass<TBase> must derive a list of derived classes from TBase.");
add<TSerializer, THierarchy, TBase, T1>();
addChilds<TSerializer, THierarchy, TBase, TDerived>(PolymorphicClassesList<Tn...>{});
//iterate through derived class hierarchy as well
add<TSerializer, THierarchy, T1, T1>();
}
template<typename TSerializer, template<typename> class THierarchy, typename TBase, typename TDerived>
void addChilds(PolymorphicClassesList<>) {
}
template<typename TSerializer, typename TBase, typename TDerived>
void addToMap(std::false_type) {
using THandler = PolymorphicHandler<RTTI, TSerializer, TBase, TDerived>;
BaseToDerivedKey key{RTTI::template get<TBase>(), RTTI::template get<TDerived>()};
pointer_utils::StdPolyAlloc<THandler> alloc{_memResource};
auto ptr = alloc.allocate(1);
std::shared_ptr<THandler> handler(new (ptr)THandler{}, [alloc](THandler* data) mutable {
data->~THandler();
alloc.deallocate(data, 1);
}, alloc);
if (_baseToDerivedMap
.emplace(key, std::move(handler))
.second) {
auto it = _baseToDerivedArray.find(key.baseHash);
if (it == _baseToDerivedArray.end()) {
it = _baseToDerivedArray.emplace(
std::piecewise_construct,
std::forward_as_tuple(key.baseHash),
std::forward_as_tuple(pointer_utils::StdPolyAlloc<size_t>{_memResource})).first;
}
it->second.push_back(key.derivedHash);
}
}
template<typename TSerializer, typename TBase, typename TDerived>
void addToMap(std::true_type) {
//cannot add abstract class
}
MemResourceBase* _memResource;
// store shared ptr to polymorphic handler, because it might be copied to "smart pointer" deleter
std::unordered_map<BaseToDerivedKey, std::shared_ptr<PolymorphicHandlerBase>,
BaseToDerivedKeyHashier, std::equal_to<BaseToDerivedKey>,
pointer_utils::StdPolyAlloc<std::pair<const BaseToDerivedKey, std::shared_ptr<PolymorphicHandlerBase>>>
> _baseToDerivedMap;
// this will allow convert from platform specific type information, to platform independent base->derived index
// this only works if all polymorphic relationships (PolymorphicBaseClass<TBase> -> PolymorphicDerivedClasses<TDerived...>)
// is equal between platforms.
std::unordered_map<size_t, std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>,
std::hash<size_t>, std::equal_to<size_t>,
pointer_utils::StdPolyAlloc<std::pair<const size_t, std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>
> _baseToDerivedArray;
public:
explicit PolymorphicContext(MemResourceBase* memResource = nullptr)
:_memResource{memResource},
_baseToDerivedMap{pointer_utils::StdPolyAlloc<std::pair<const BaseToDerivedKey,
std::shared_ptr<PolymorphicHandlerBase>>>{memResource}},
_baseToDerivedArray{pointer_utils::StdPolyAlloc<std::pair<const size_t,
std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>{memResource}}
{}
PolymorphicContext(const PolymorphicContext& ) = delete;
PolymorphicContext& operator = (const PolymorphicContext&) = delete;
PolymorphicContext(PolymorphicContext&& ) = default;
PolymorphicContext& operator = (PolymorphicContext&&) = default;
void clear() {
_baseToDerivedMap.clear();
_baseToDerivedArray.clear();
}
// THierarchy is the name of class, that defines hierarchy
// PolymorphicBaseClass is defined as default parameter, so that at instantiation time
// it will get unique symbol in translation unit for PolymorphicBaseClass (which is defined in anonymous namespace)
// https://github.com/fraillt/bitsery/issues/9
template<typename TSerializer, template<typename> class THierarchy = PolymorphicBaseClass, typename T1, typename ...Tn>
void registerBasesList(PolymorphicClassesList<T1, Tn...>) {
add<TSerializer, THierarchy, T1, T1>();
registerBasesList<TSerializer, THierarchy>(PolymorphicClassesList<Tn...>{});
}
template<typename TSerializer, template<typename> class THierarchy>
void registerBasesList(PolymorphicClassesList<>) {
}
// optional method, in case you want to construct base class hierarchy your self
template<typename TSerializer, typename TBase, typename TDerived>
void registerSingleBaseBranch() {
static_assert(std::is_base_of<TBase, TDerived>::value, "TDerived must be derived from TBase");
static_assert(!std::is_abstract<TDerived>::value, "TDerived cannot be abstract");
addToMap<TSerializer, TBase, TDerived>(std::false_type{});
}
template<typename Serializer, typename TBase>
void serialize(Serializer& ser, TBase& obj) const {
//get derived key
BaseToDerivedKey key{RTTI::template get<TBase>(), RTTI::template get<TBase>(obj)};
auto it = _baseToDerivedMap.find(key);
assert(it != _baseToDerivedMap.end());
//convert derived hash to derived index, to make it work in cross-platform environment
auto& vec = _baseToDerivedArray.find(key.baseHash)->second;
auto derivedIndex = static_cast<size_t>(std::distance(vec.begin(), std::find(vec.begin(), vec.end(),
key.derivedHash)));
details::writeSize(ser.adapter(), derivedIndex);
//serialize
it->second->process(&ser, &obj);
}
template<typename Deserializer, typename TBase, typename TCreateFnc, typename TDestroyFnc>
void deserialize(Deserializer& des, TBase* obj,
TCreateFnc createFnc, TDestroyFnc destroyFnc) const {
size_t derivedIndex{};
details::readSize(des.adapter(), derivedIndex, 0, std::false_type{});
auto baseToDerivedVecIt = _baseToDerivedArray.find(RTTI::template get<TBase>());
//base class is known at compile time, so we can assert on this one
assert(baseToDerivedVecIt != _baseToDerivedArray.end());
if (baseToDerivedVecIt->second.size() > derivedIndex) {
//convert derived index to derived hash, to make it work in cross-platform environment
auto derivedHash = baseToDerivedVecIt->second[derivedIndex];
auto& handler = _baseToDerivedMap.find(
BaseToDerivedKey{RTTI::template get<TBase>(), derivedHash})->second;
//if object is null or different type, create new and assign it
if (obj == nullptr || RTTI::template get<TBase>(*obj) != derivedHash) {
if (obj) {
destroyFnc(getPolymorphicHandler(*obj));
}
obj = createFnc(handler);
}
handler->process(&des, obj);
} else
des.adapter().error(ReaderError::InvalidPointer);
}
template<typename TBase>
const std::shared_ptr<PolymorphicHandlerBase>& getPolymorphicHandler(TBase& obj) const {
auto deleteHandlerIt = _baseToDerivedMap.find(
BaseToDerivedKey{RTTI::template get<TBase>(), RTTI::template get<TBase>(obj)});
assert(deleteHandlerIt != _baseToDerivedMap.end());
return deleteHandlerIt->second;
}
};
std::size_t baseHash;
std::size_t derivedHash;
bool operator==(const BaseToDerivedKey& other) const
{
return baseHash == other.baseHash && derivedHash == other.derivedHash;
}
};
struct BaseToDerivedKeyHashier
{
size_t operator()(const BaseToDerivedKey& key) const
{
return (key.baseHash + (key.baseHash << 6) + (key.derivedHash >> 2)) ^
key.derivedHash;
}
};
template<typename TSerializer,
template<typename>
class THierarchy,
typename TBase,
typename TDerived>
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 addChilds(PolymorphicClassesList<T1, Tn...>)
{
static_assert(std::is_base_of<TDerived, T1>::value,
"PolymorphicBaseClass<TBase> must derive a list of derived "
"classes from TBase.");
add<TSerializer, THierarchy, TBase, T1>();
addChilds<TSerializer, THierarchy, TBase, TDerived>(
PolymorphicClassesList<Tn...>{});
// iterate through derived class hierarchy as well
add<TSerializer, THierarchy, T1, T1>();
}
template<typename TSerializer,
template<typename>
class THierarchy,
typename TBase,
typename TDerived>
void addChilds(PolymorphicClassesList<>)
{
}
template<typename TSerializer, typename TBase, typename TDerived>
void addToMap(std::false_type)
{
using THandler = PolymorphicHandler<RTTI, TSerializer, TBase, TDerived>;
BaseToDerivedKey key{ RTTI::template get<TBase>(),
RTTI::template get<TDerived>() };
pointer_utils::StdPolyAlloc<THandler> alloc{ _memResource };
auto ptr = alloc.allocate(1);
std::shared_ptr<THandler> handler(
new (ptr) THandler{},
[alloc](THandler* data) mutable {
data->~THandler();
alloc.deallocate(data, 1);
},
alloc);
if (_baseToDerivedMap.emplace(key, std::move(handler)).second) {
auto it = _baseToDerivedArray.find(key.baseHash);
if (it == _baseToDerivedArray.end()) {
it = _baseToDerivedArray
.emplace(std::piecewise_construct,
std::forward_as_tuple(key.baseHash),
std::forward_as_tuple(
pointer_utils::StdPolyAlloc<size_t>{ _memResource }))
.first;
}
it->second.push_back(key.derivedHash);
}
}
template<typename TSerializer, typename TBase, typename TDerived>
void addToMap(std::true_type)
{
// cannot add abstract class
}
MemResourceBase* _memResource;
// store shared ptr to polymorphic handler, because it might be copied to
// "smart pointer" deleter
std::unordered_map<BaseToDerivedKey,
std::shared_ptr<PolymorphicHandlerBase>,
BaseToDerivedKeyHashier,
std::equal_to<BaseToDerivedKey>,
pointer_utils::StdPolyAlloc<
std::pair<const BaseToDerivedKey,
std::shared_ptr<PolymorphicHandlerBase>>>>
_baseToDerivedMap;
// this will allow convert from platform specific type information, to
// platform independent base->derived index this only works if all polymorphic
// relationships (PolymorphicBaseClass<TBase> ->
// PolymorphicDerivedClasses<TDerived...>) is equal between platforms.
std::unordered_map<
size_t,
std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>,
std::hash<size_t>,
std::equal_to<size_t>,
pointer_utils::StdPolyAlloc<
std::pair<const size_t,
std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>>
_baseToDerivedArray;
public:
explicit PolymorphicContext(MemResourceBase* memResource = nullptr)
: _memResource{ memResource }
, _baseToDerivedMap{ pointer_utils::StdPolyAlloc<
std::pair<const BaseToDerivedKey,
std::shared_ptr<PolymorphicHandlerBase>>>{ memResource } }
, _baseToDerivedArray{ pointer_utils::StdPolyAlloc<
std::pair<const size_t,
std::vector<size_t, pointer_utils::StdPolyAlloc<size_t>>>>{
memResource } }
{
}
PolymorphicContext(const PolymorphicContext&) = delete;
PolymorphicContext& operator=(const PolymorphicContext&) = delete;
PolymorphicContext(PolymorphicContext&&) = default;
PolymorphicContext& operator=(PolymorphicContext&&) = default;
void clear()
{
_baseToDerivedMap.clear();
_baseToDerivedArray.clear();
}
// THierarchy is the name of class, that defines hierarchy
// PolymorphicBaseClass is defined as default parameter, so that at
// instantiation time it will get unique symbol in translation unit for
// PolymorphicBaseClass (which is defined in anonymous namespace)
// https://github.com/fraillt/bitsery/issues/9
template<typename TSerializer,
template<typename> class THierarchy = PolymorphicBaseClass,
typename T1,
typename... Tn>
void registerBasesList(PolymorphicClassesList<T1, Tn...>)
{
add<TSerializer, THierarchy, T1, T1>();
registerBasesList<TSerializer, THierarchy>(PolymorphicClassesList<Tn...>{});
}
template<typename TSerializer, template<typename> class THierarchy>
void registerBasesList(PolymorphicClassesList<>)
{
}
// optional method, in case you want to construct base class hierarchy your
// self
template<typename TSerializer, typename TBase, typename TDerived>
void registerSingleBaseBranch()
{
static_assert(std::is_base_of<TBase, TDerived>::value,
"TDerived must be derived from TBase");
static_assert(!std::is_abstract<TDerived>::value,
"TDerived cannot be abstract");
addToMap<TSerializer, TBase, TDerived>(std::false_type{});
}
template<typename Serializer, typename TBase>
void serialize(Serializer& ser, TBase& obj) const
{
// get derived key
BaseToDerivedKey key{ RTTI::template get<TBase>(),
RTTI::template get<TBase>(obj) };
auto it = _baseToDerivedMap.find(key);
assert(it != _baseToDerivedMap.end());
// convert derived hash to derived index, to make it work in cross-platform
// environment
auto& vec = _baseToDerivedArray.find(key.baseHash)->second;
auto derivedIndex = static_cast<size_t>(std::distance(
vec.begin(), std::find(vec.begin(), vec.end(), key.derivedHash)));
details::writeSize(ser.adapter(), derivedIndex);
// serialize
it->second->process(&ser, &obj);
}
template<typename Deserializer,
typename TBase,
typename TCreateFnc,
typename TDestroyFnc>
void deserialize(Deserializer& des,
TBase* obj,
TCreateFnc createFnc,
TDestroyFnc destroyFnc) const
{
size_t derivedIndex{};
details::readSize(des.adapter(), derivedIndex, 0, std::false_type{});
auto baseToDerivedVecIt =
_baseToDerivedArray.find(RTTI::template get<TBase>());
// base class is known at compile time, so we can assert on this one
assert(baseToDerivedVecIt != _baseToDerivedArray.end());
if (baseToDerivedVecIt->second.size() > derivedIndex) {
// convert derived index to derived hash, to make it work in
// cross-platform environment
auto derivedHash = baseToDerivedVecIt->second[derivedIndex];
auto& handler =
_baseToDerivedMap
.find(BaseToDerivedKey{ RTTI::template get<TBase>(), derivedHash })
->second;
// if object is null or different type, create new and assign it
if (obj == nullptr || RTTI::template get<TBase>(*obj) != derivedHash) {
if (obj) {
destroyFnc(getPolymorphicHandler(*obj));
}
obj = createFnc(handler);
}
handler->process(&des, obj);
} else
des.adapter().error(ReaderError::InvalidPointer);
}
template<typename TBase>
const std::shared_ptr<PolymorphicHandlerBase>& getPolymorphicHandler(
TBase& obj) const
{
auto deleteHandlerIt = _baseToDerivedMap.find(BaseToDerivedKey{
RTTI::template get<TBase>(), RTTI::template get<TBase>(obj) });
assert(deleteHandlerIt != _baseToDerivedMap.end());
return deleteHandlerIt->second;
}
};
}
#endif //BITSERY_EXT_POLYMORPHISM_UTILS_H
}
#endif // BITSERY_EXT_POLYMORPHISM_UTILS_H

View File

@@ -1,65 +1,65 @@
//MIT License
// MIT License
//
//Copyright (c) 2018 Mindaugas Vinkelis
// Copyright (c) 2018 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_RTTI_UTILS_H
#define BITSERY_RTTI_UTILS_H
#include <typeinfo>
#include <type_traits>
#include <cstddef>
#include <type_traits>
#include <typeinfo>
namespace bitsery {
namespace ext {
namespace ext {
struct StandardRTTI {
struct StandardRTTI
{
// static_assert(!std::is_pointer<TBase>::value &&
// !std::is_const<TBase>::value &&
// !std::is_volatile<TBase>::value, "");
template<typename TBase>
static size_t get(TBase& obj)
{
return typeid(obj).hash_code();
}
template<typename TBase>
static size_t get(TBase& obj) {
return typeid(obj).hash_code();
}
template<typename TBase>
static constexpr size_t get()
{
return typeid(TBase).hash_code();
}
template<typename TBase>
static constexpr size_t get() {
return typeid(TBase).hash_code();
}
template<typename TBase, typename TDerived>
static constexpr TDerived* cast(TBase* obj)
{
static_assert(!std::is_pointer<TDerived>::value, "");
return dynamic_cast<TDerived*>(obj);
}
template<typename TBase, typename TDerived>
static constexpr TDerived* cast(TBase* obj) {
static_assert(!std::is_pointer<TDerived>::value, "");
return dynamic_cast<TDerived*>(obj);
}
template<typename TBase>
static constexpr bool isPolymorphic()
{
return std::is_polymorphic<TBase>::value;
}
};
template<typename TBase>
static constexpr bool isPolymorphic() {
return std::is_polymorphic<TBase>::value;
}
};
}
}
}
#endif //BITSERY_RTTI_UTILS_H
#endif // BITSERY_RTTI_UTILS_H

View File

@@ -1,219 +1,268 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_EXT_VALUE_RANGE_H
#define BITSERY_EXT_VALUE_RANGE_H
#include "../details/serialization_common.h"
#include "../details/adapter_common.h"
#include <cassert>
namespace bitsery {
namespace ext {
//this class is used to make default RangeSpec float specialization always prefer constructor with precision
struct BitsConstraint {
explicit constexpr BitsConstraint(size_t bits) : value{bits} {}
namespace ext {
// this class is used to make default RangeSpec float specialization always
// prefer constructor with precision
struct BitsConstraint
{
explicit constexpr BitsConstraint(size_t bits)
: value{ bits }
{
}
const size_t value;
};
const size_t value;
};
}
// implementation details for range functionality
namespace details {
template<typename T>
constexpr size_t
getSize(T v, size_t s)
{
return v > 0 ? getSize(v / 2, s + 1) : s;
}
template<typename T>
constexpr size_t
calcRequiredBits(T min, T max)
{
// call recursive function, because some compilers only support constexpr
// functions with return-only body
return getSize(max - min, 0);
}
template<typename T, typename Enable = void>
struct RangeSpec
{
constexpr RangeSpec(T minValue, T maxValue)
: min{ minValue }
, max{ maxValue }
, bitsRequired{ calcRequiredBits(min, max) }
{
}
const T min;
const T max;
const size_t bitsRequired;
};
template<typename T>
struct RangeSpec<T, typename std::enable_if<std::is_enum<T>::value>::type>
{
constexpr RangeSpec(T minValue, T maxValue)
: min{ minValue }
, max{ maxValue }
, bitsRequired{ calcRequiredBits(
static_cast<typename std::underlying_type<T>::type>(min),
static_cast<typename std::underlying_type<T>::type>(max)) }
{
}
const T min;
const T max;
const size_t bitsRequired;
};
template<typename T>
struct RangeSpec<
T,
typename std::enable_if<std::is_floating_point<T>::value>::type>
{
constexpr RangeSpec(T minValue, T maxValue, ext::BitsConstraint bits)
: min{ minValue }
, max{ maxValue }
, bitsRequired{ bits.value }
{
}
constexpr RangeSpec(T minValue, T maxValue, T precision)
: min{ minValue }
, max{ maxValue }
, bitsRequired{ calcRequiredBits<details::SameSizeUnsigned<T>>(
{},
static_cast<details::SameSizeUnsigned<T>>((max - min) / precision)) }
{
}
const T min;
const T max;
const size_t bitsRequired;
};
template<typename T,
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
details::SameSizeUnsigned<T>
getRangeValue(const T& v, const RangeSpec<T>& r)
{
return static_cast<details::SameSizeUnsigned<T>>(v - r.min);
}
template<typename T,
typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
details::SameSizeUnsigned<T>
getRangeValue(const T& v, const RangeSpec<T>& r)
{
using VT = details::SameSizeUnsigned<T>;
return static_cast<VT>(static_cast<VT>(v) - static_cast<VT>(r.min));
}
template<
typename T,
typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
details::SameSizeUnsigned<T>
getRangeValue(const T& v, const RangeSpec<T>& r)
{
using VT = details::SameSizeUnsigned<T>;
const VT maxUint = (static_cast<VT>(1) << r.bitsRequired) - 1;
const T ratio = (v - r.min) / (r.max - r.min);
return static_cast<VT>(ratio * static_cast<T>(maxUint));
}
template<typename T,
typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
void
setRangeValue(T& v, const RangeSpec<T>& r)
{
v += r.min;
}
template<typename T,
typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
void
setRangeValue(T& v, const RangeSpec<T>& r)
{
using VT = typename std::underlying_type<T>::type;
reinterpret_cast<VT&>(v) += static_cast<VT>(r.min);
}
template<
typename T,
typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
void
setRangeValue(T& v, const RangeSpec<T>& r)
{
using UIT = details::SameSizeUnsigned<T>;
const auto intRep = reinterpret_cast<UIT&>(v);
const UIT maxUint = (static_cast<UIT>(1) << r.bitsRequired) - 1;
v = r.min +
(static_cast<T>(intRep) / static_cast<T>(maxUint)) * (r.max - r.min);
}
template<typename T,
typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
bool
isRangeValid(const T& v, const RangeSpec<T>& r)
{
return !(r.min > v || v > r.max);
}
template<typename T,
typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
bool
isRangeValid(const T& v, const RangeSpec<T>& r)
{
using VT = typename std::underlying_type<T>::type;
return !(static_cast<VT>(r.min) > static_cast<VT>(v) ||
static_cast<VT>(v) > static_cast<VT>(r.max));
}
}
namespace ext {
template<typename TValue>
class ValueRange
{
public:
template<typename... Args>
constexpr ValueRange(const TValue& min, const TValue& max, Args&&... args)
: _range{ min, max, std::forward<Args>(args)... }
{
}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser& ser, const T& v, Fnc&&) const
{
assert(details::isRangeValid(v, _range));
using BT = decltype(details::getRangeValue(v, _range));
ser.adapter().template writeBits<BT>(details::getRangeValue(v, _range),
_range.bitsRequired);
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des& des, T& v, Fnc&&) const
{
auto& reader = des.adapter();
reader.readBits(reinterpret_cast<details::SameSizeUnsigned<T>&>(v),
_range.bitsRequired);
details::setRangeValue(v, _range);
handleInvalidRange(
reader, v, std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
}
constexpr size_t getRequiredBits() const { return _range.bitsRequired; };
private:
template<typename Reader, typename T>
void handleInvalidRange(Reader& reader, T& v, std::true_type) const
{
if (!details::isRangeValid(v, _range)) {
reader.error(ReaderError::InvalidData);
v = _range.min;
}
}
//implementation details for range functionality
namespace details {
template<typename Reader, typename T>
void handleInvalidRange(Reader&, T&, std::false_type) const
{
}
template<typename T>
constexpr size_t getSize(T v, size_t s) {
return v > 0 ? getSize(v / 2, s + 1) : s;
}
details::RangeSpec<TValue> _range;
};
}
template<typename T>
constexpr size_t calcRequiredBits(T min, T max) {
//call recursive function, because some compilers only support constexpr functions with return-only body
return getSize(max - min, 0);
}
template<typename T, typename Enable = void>
struct RangeSpec {
constexpr RangeSpec(T minValue, T maxValue)
: min{minValue},
max{maxValue},
bitsRequired{calcRequiredBits(min, max)} {
}
const T min;
const T max;
const size_t bitsRequired;
};
template<typename T>
struct RangeSpec<T, typename std::enable_if<std::is_enum<T>::value>::type> {
constexpr RangeSpec(T minValue, T maxValue) :
min{minValue},
max{maxValue},
bitsRequired{calcRequiredBits(
static_cast<typename std::underlying_type<T>::type>(min),
static_cast<typename std::underlying_type<T>::type>(max))} {
}
const T min;
const T max;
const size_t bitsRequired;
};
template<typename T>
struct RangeSpec<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
constexpr RangeSpec(T minValue, T maxValue, ext::BitsConstraint bits) :
min{minValue},
max{maxValue},
bitsRequired{bits.value} {
}
constexpr RangeSpec(T minValue, T maxValue, T precision) :
min{minValue},
max{maxValue},
bitsRequired{calcRequiredBits<details::SameSizeUnsigned<T>>(
{}, static_cast<details::SameSizeUnsigned<T>>((max - min) / precision))} {
}
const T min;
const T max;
const size_t bitsRequired;
};
template<typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
details::SameSizeUnsigned<T> getRangeValue(const T &v, const RangeSpec<T> &r) {
return static_cast<details::SameSizeUnsigned<T>>(v - r.min);
}
template<typename T, typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
details::SameSizeUnsigned<T> getRangeValue(const T &v, const RangeSpec<T> &r) {
using VT = details::SameSizeUnsigned<T>;
return static_cast<VT>(static_cast<VT>(v) - static_cast<VT>(r.min));
}
template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
details::SameSizeUnsigned<T> getRangeValue(const T &v, const RangeSpec<T> &r) {
using VT = details::SameSizeUnsigned<T>;
const VT maxUint = (static_cast<VT>(1) << r.bitsRequired) - 1;
const T ratio = (v - r.min) / (r.max - r.min);
return static_cast<VT>(ratio * static_cast<T>(maxUint));
}
template<typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
void setRangeValue(T &v, const RangeSpec<T> &r) {
v += r.min;
}
template<typename T, typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
void setRangeValue(T &v, const RangeSpec<T> &r) {
using VT = typename std::underlying_type<T>::type;
reinterpret_cast<VT &>(v) += static_cast<VT>(r.min);
}
template<typename T, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
void setRangeValue(T &v, const RangeSpec<T> &r) {
using UIT = details::SameSizeUnsigned<T>;
const auto intRep = reinterpret_cast<UIT &>(v);
const UIT maxUint = (static_cast<UIT>(1) << r.bitsRequired) - 1;
v = r.min + (static_cast<T>(intRep) / static_cast<T>(maxUint)) * (r.max - r.min);
}
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type * = nullptr>
bool isRangeValid(const T &v, const RangeSpec<T> &r) {
return !(r.min > v || v > r.max);
}
template<typename T, typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
bool isRangeValid(const T &v, const RangeSpec<T> &r) {
using VT = typename std::underlying_type<T>::type;
return !(static_cast<VT>(r.min) > static_cast<VT>(v)
|| static_cast<VT>(v) > static_cast<VT>(r.max));
}
}
namespace ext {
template<typename TValue>
class ValueRange {
public:
template<typename ... Args>
constexpr ValueRange(const TValue& min, const TValue& max, Args &&... args)
:_range{min, max, std::forward<Args>(args)...} {}
template<typename Ser, typename T, typename Fnc>
void serialize(Ser &ser, const T &v, Fnc &&) const {
assert(details::isRangeValid(v, _range));
using BT = decltype(details::getRangeValue(v, _range));
ser.adapter().template writeBits<BT>(details::getRangeValue(v, _range), _range.bitsRequired);
}
template<typename Des, typename T, typename Fnc>
void deserialize(Des &des, T &v, Fnc &&) const {
auto& reader = des.adapter();
reader.readBits(reinterpret_cast<details::SameSizeUnsigned<T> &>(v), _range.bitsRequired);
details::setRangeValue(v, _range);
handleInvalidRange(reader, v, std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
}
constexpr size_t getRequiredBits() const {
return _range.bitsRequired;
};
private:
template <typename Reader, typename T>
void handleInvalidRange(Reader& reader, T& v, std::true_type) const {
if (!details::isRangeValid(v, _range)) {
reader.error(ReaderError::InvalidData);
v = _range.min;
}
}
template <typename Reader, typename T>
void handleInvalidRange(Reader&, T&, std::false_type) const {
}
details::RangeSpec<TValue> _range;
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::ValueRange<T>, T> {
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::ValueRange<T>, T>
{
using TValue = void;
static constexpr bool SupportValueOverload = false;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = false;
};
}
}
#endif //BITSERY_EXT_VALUE_RANGE_H
#endif // BITSERY_EXT_VALUE_RANGE_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_TRAITS_STD_ARRAY_H
#define BITSERY_TRAITS_STD_ARRAY_H
@@ -29,16 +28,20 @@
namespace bitsery {
namespace traits {
template<typename T, size_t N>
struct ContainerTraits<std::array<T, N>>
:public StdContainer<std::array<T, N>, false, true> {};
namespace traits {
template<typename T, size_t N>
struct ContainerTraits<std::array<T, N>>
: public StdContainer<std::array<T, N>, false, true>
{
};
template<typename T, size_t N>
struct BufferAdapterTraits<std::array<T, N>>
:public StdContainerForBufferAdapter<std::array<T, N>> {};
}
template<typename T, size_t N>
struct BufferAdapterTraits<std::array<T, N>>
: public StdContainerForBufferAdapter<std::array<T, N>>
{
};
}
}
#endif //BITSERY_TYPE_TRAITS_STD_ARRAY_H
#endif // BITSERY_TYPE_TRAITS_STD_ARRAY_H

View File

@@ -1,103 +1,114 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_TRAITS_CORE_STD_DEFAULTS_H
#define BITSERY_TRAITS_CORE_STD_DEFAULTS_H
#include "traits.h"
#include "../../details/serialization_common.h"
#include "traits.h"
namespace bitsery {
namespace traits {
namespace traits {
/*
* these are helper types, to easier write specializations for std types
*/
/*
* these are helper types, to easier write specializations for std types
*/
template<typename T, bool Resizable, bool Contiguous>
struct StdContainer {
using TValue = typename T::value_type;
static constexpr bool isResizable = Resizable;
static constexpr bool isContiguous = Contiguous;
static size_t size(const T& container) {
return container.size();
}
};
template<typename T, bool Resizable, bool Contiguous>
struct StdContainer
{
using TValue = typename T::value_type;
static constexpr bool isResizable = Resizable;
static constexpr bool isContiguous = Contiguous;
static size_t size(const T& container) { return container.size(); }
};
//specialization for resizable
template<typename T, bool Contiguous>
struct StdContainer<T, true, Contiguous> {
using TValue = typename T::value_type;
static constexpr bool isResizable = true;
static constexpr bool isContiguous = Contiguous;
static size_t size(const T& container) {
return container.size();
}
static void resize(T& container, size_t size) {
resizeImpl(container, size, std::is_default_constructible<TValue>{});
}
private:
using diff_t = typename T::difference_type;
// specialization for resizable
template<typename T, bool Contiguous>
struct StdContainer<T, true, Contiguous>
{
using TValue = typename T::value_type;
static constexpr bool isResizable = true;
static constexpr bool isContiguous = Contiguous;
static size_t size(const T& container) { return container.size(); }
static void resize(T& container, size_t size)
{
resizeImpl(container, size, std::is_default_constructible<TValue>{});
}
static void resizeImpl(T& container, size_t size, std::true_type) {
container.resize(size);
}
static void resizeImpl(T& container, size_t newSize, std::false_type) {
const auto oldSize = size(container);
for (auto it = oldSize; it < newSize; ++it) {
container.push_back(::bitsery::Access::create<TValue>());
}
if (oldSize > newSize) {
container.erase(std::next(std::begin(container), static_cast<diff_t>(newSize)), std::end(container));
}
}
};
template <typename T, bool Resizable = ContainerTraits<T>::isResizable>
struct StdContainerForBufferAdapter {
using TIterator = typename T::iterator;
using TConstIterator = typename T::const_iterator;
using TValue = typename ContainerTraits<T>::TValue;
};
//specialization for resizable buffers
template <typename T>
struct StdContainerForBufferAdapter<T, true> {
static void increaseBufferSize(T& container) {
//since we're writing to buffer use different resize strategy than default implementation
//when small size grow faster, to avoid thouse 2/4/8/16... byte allocations
auto newSize = static_cast<size_t>(static_cast<double>(container.size()) * 1.5) + 128;
//make data cache friendly
newSize -= newSize % 64;//64 is cache line size
container.resize((std::max)(newSize, container.capacity()));
}
using TIterator = typename T::iterator;
using TConstIterator = typename T::const_iterator;
using TValue = typename ContainerTraits<T>::TValue;
};
private:
using diff_t = typename T::difference_type;
static void resizeImpl(T& container, size_t size, std::true_type)
{
container.resize(size);
}
static void resizeImpl(T& container, size_t newSize, std::false_type)
{
const auto oldSize = size(container);
for (auto it = oldSize; it < newSize; ++it) {
container.push_back(::bitsery::Access::create<TValue>());
}
if (oldSize > newSize) {
container.erase(
std::next(std::begin(container), static_cast<diff_t>(newSize)),
std::end(container));
}
}
};
template<typename T, bool Resizable = ContainerTraits<T>::isResizable>
struct StdContainerForBufferAdapter
{
using TIterator = typename T::iterator;
using TConstIterator = typename T::const_iterator;
using TValue = typename ContainerTraits<T>::TValue;
};
// specialization for resizable buffers
template<typename T>
struct StdContainerForBufferAdapter<T, true>
{
using TIterator = typename T::iterator;
using TConstIterator = typename T::const_iterator;
using TValue = typename ContainerTraits<T>::TValue;
static void increaseBufferSize(T& container,
size_t /*currSize*/,
size_t minSize)
{
// since we're writing to buffer use different resize strategy than default
// implementation when small size grow faster, to avoid thouse 2/4/8/16...
// byte allocations
auto newSize =
static_cast<size_t>(static_cast<double>(container.size()) * 1.5) + 128;
// make data cache friendly
newSize -= newSize % 64; // 64 is cache line size
container.resize(
(std::max)(newSize > minSize ? newSize : minSize, container.capacity()));
}
};
}
}
#endif //BITSERY_TRAITS_CORE_STD_DEFAULTS_H
#endif // BITSERY_TRAITS_CORE_STD_DEFAULTS_H

View File

@@ -1,187 +1,208 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_TRAITS_CORE_TRAITS_H
#define BITSERY_TRAITS_CORE_TRAITS_H
#include <type_traits>
#include "../../details/not_defined_type.h"
#include <type_traits>
namespace bitsery {
namespace traits {
namespace traits {
/*
* core library traits, used to extend library for custom types
*/
/*
* core library traits, used to extend library for custom types
*/
//traits for extension
template<typename Extension, typename T>
struct ExtensionTraits {
//this type is used, when using extesion without custom lambda
// eg.: extension4b>(obj, myextension{}) will call s.value4b(obj) for TValue
// or extesion(obj, myextension{}) will call s.object(obj) for TValue
//when this is void, it will compile, but value and object overloads will do nothing.
using TValue = details::NotDefinedType;
// traits for extension
template<typename Extension, typename T>
struct ExtensionTraits
{
// this type is used, when using extesion without custom lambda
// eg.: extension4b>(obj, myextension{}) will call s.value4b(obj) for TValue
// or extesion(obj, myextension{}) will call s.object(obj) for TValue
// when this is void, it will compile, but value and object overloads will do
// nothing.
using TValue = details::NotDefinedType;
//does extension support ext<N>(...) syntax, by calling value<N> with TValue
static constexpr bool SupportValueOverload = false;
//does extension support ext(...) syntax, by calling object with TValue
static constexpr bool SupportObjectOverload = false;
//does extension support ext(..., lambda)
static constexpr bool SupportLambdaOverload = false;
};
// does extension support ext<N>(...) syntax, by calling value<N> with TValue
static constexpr bool SupportValueOverload = false;
// does extension support ext(...) syntax, by calling object with TValue
static constexpr bool SupportObjectOverload = false;
// does extension support ext(..., lambda)
static constexpr bool SupportLambdaOverload = false;
};
//primary traits for containers
template<typename T>
struct ContainerTraits {
// primary traits for containers
template<typename T>
struct ContainerTraits
{
using TValue = details::NotDefinedType;
using TValue = details::NotDefinedType;
static constexpr bool isResizable = false;
//contiguous arrays has oppurtunity to memcpy whole buffer directly when using funtamental types
//contiguous doesn't nesessary equal to random access iterator.
//contiguous hopefully will be available in c++20
static constexpr bool isContiguous = false;
//resize function, called only if container is resizable
static void resize(T& , size_t ) {
static_assert(std::is_void<T>::value,
"Define ContainerTraits or include from <bitsery/traits/...> to use as container");
}
//get container size
static size_t size(const T& ) {
static_assert(std::is_void<T>::value,
"Define ContainerTraits or include from <bitsery/traits/...> to use as container");
return 0u;
}
};
static constexpr bool isResizable = false;
// contiguous arrays has oppurtunity to memcpy whole buffer directly when
// using funtamental types contiguous doesn't nesessary equal to random access
// iterator. contiguous hopefully will be available in c++20
static constexpr bool isContiguous = false;
// resize function, called only if container is resizable
static void resize(T&, size_t)
{
static_assert(std::is_void<T>::value,
"Define ContainerTraits or include from <bitsery/traits/...> "
"to use as container");
}
// get container size
static size_t size(const T&)
{
static_assert(std::is_void<T>::value,
"Define ContainerTraits or include from <bitsery/traits/...> "
"to use as container");
return 0u;
}
};
//specialization for C style array
template<typename T, size_t N>
struct ContainerTraits<T[N]> {
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const T (&)[N]) {
return N;
}
};
// specialization for C style array
template<typename T, size_t N>
struct ContainerTraits<T[N]>
{
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const T (&)[N]) { return N; }
};
//specialization for initializer list.
//only serializer can use it
template<typename T>
struct ContainerTraits<std::initializer_list<T>> {
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const std::initializer_list<T>& container) {
return container.size();
}
};
// specialization for initializer list.
// only serializer can use it
template<typename T>
struct ContainerTraits<std::initializer_list<T>>
{
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const std::initializer_list<T>& container)
{
return container.size();
}
};
//specialization for pointer type buffer
//only deserializer can use it
template <typename T>
struct ContainerTraits<const T*> {
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const T* ) {
static_assert(std::is_void<T>::value, "cannot get size for container of type T*");
return 0u;
}
};
// specialization for pointer type buffer
// only deserializer can use it
template<typename T>
struct ContainerTraits<const T*>
{
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const T*)
{
static_assert(std::is_void<T>::value,
"cannot get size for container of type T*");
return 0u;
}
};
template <typename T>
struct ContainerTraits<T*> {
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const T* ) {
static_assert(std::is_void<T>::value, "cannot get size for container of type T*");
return 0u;
}
};
template<typename T>
struct ContainerTraits<T*>
{
using TValue = T;
static constexpr bool isResizable = false;
static constexpr bool isContiguous = true;
static size_t size(const T*)
{
static_assert(std::is_void<T>::value,
"cannot get size for container of type T*");
return 0u;
}
};
// traits for text, default adds null-terminated character at the end
template<typename T>
struct TextTraits
{
using TValue = details::NotDefinedType;
// if container is not null-terminated by default, add NUL at the end
static constexpr bool addNUL = true;
// get length of null terminated container
static size_t length(const T&)
{
static_assert(
std::is_void<T>::value,
"Define TextTraits or include from <bitsery/traits/...> to use as text");
return 0u;
}
};
//traits for text, default adds null-terminated character at the end
template<typename T>
struct TextTraits {
using TValue = details::NotDefinedType;
//if container is not null-terminated by default, add NUL at the end
static constexpr bool addNUL = true;
// traits only for buffer adapters
template<typename T>
struct BufferAdapterTraits
{
using TIterator = details::NotDefinedType;
using TConstIterator = details::NotDefinedType;
using TValue = typename ContainerTraits<T>::TValue;
//get length of null terminated container
static size_t length(const T& ) {
static_assert(std::is_void<T>::value,
"Define TextTraits or include from <bitsery/traits/...> to use as text");
return 0u;
}
};
// this function is only applies to resizable containers
//traits only for buffer adapters
template <typename T>
struct BufferAdapterTraits {
//this function is only applies to resizable containers
// this function is only used by Writer, when writing data to buffer,
// it is called only current buffer size is not enough to write.
// it is used to dramaticaly improve performance by updating buffer directly
// instead of using back_insert_iterator to append each byte to buffer.
//this function is only used by Writer, when writing data to buffer,
//it is called only current buffer size is not enough to write.
//it is used to dramaticaly improve performance by updating buffer directly
//instead of using back_insert_iterator to append each byte to buffer.
static void increaseBufferSize(T&, size_t, size_t)
{
static_assert(std::is_void<T>::value,
"Define BufferAdapterTraits or include from "
"<bitsery/traits/...> to use as buffer adapter container");
}
};
static void increaseBufferSize(T& ) {
static_assert(std::is_void<T>::value,
"Define BufferAdapterTraits or include from <bitsery/traits/...> to use as buffer adapter container");
}
// specialization for c-style buffer
template<typename T, size_t N>
struct BufferAdapterTraits<T[N]>
{
using TIterator = T*;
using TConstIterator = const T*;
using TValue = T;
};
using TIterator = details::NotDefinedType;
using TConstIterator = details::NotDefinedType;
using TValue = typename ContainerTraits<T>::TValue;
};
// specialization for pointer type buffer
template<typename T>
struct BufferAdapterTraits<const T*>
{
using TIterator = const T*;
using TConstIterator = const T*;
using TValue = T;
};
//specialization for c-style buffer
template <typename T, size_t N>
struct BufferAdapterTraits<T[N]> {
using TIterator = T*;
using TConstIterator = const T*;
using TValue = T;
};
template<typename T>
struct BufferAdapterTraits<T*>
{
using TIterator = T*;
using TConstIterator = const T*;
using TValue = T;
};
//specialization for pointer type buffer
template <typename T>
struct BufferAdapterTraits<const T*> {
using TIterator = const T*;
using TConstIterator = const T*;
using TValue = T;
};
template <typename T>
struct BufferAdapterTraits<T*> {
using TIterator = T*;
using TConstIterator = const T*;
using TValue = T;
};
}
}
}
#endif //BITSERY_TRAITS_CORE_TRAITS_H
#endif // BITSERY_TRAITS_CORE_TRAITS_H

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_TRAITS_STD_DEQUE_H
#define BITSERY_TRAITS_STD_DEQUE_H
@@ -29,14 +28,16 @@
namespace bitsery {
namespace traits {
namespace traits {
template<typename T, typename Allocator>
struct ContainerTraits<std::deque<T, Allocator>>
: public StdContainer<std::deque<T, Allocator>, true, false> {};
}
template<typename T, typename Allocator>
struct ContainerTraits<std::deque<T, Allocator>>
: public StdContainer<std::deque<T, Allocator>, true, false>
{
};
}
#endif //BITSERY_TRAITS_STD_DEQUE_H
}
#endif // BITSERY_TRAITS_STD_DEQUE_H

View File

@@ -1,69 +1,79 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_TRAITS_STD_FORWARD_LIST_H
#define BITSERY_TRAITS_STD_FORWARD_LIST_H
#include "core/traits.h"
#include "../details/serialization_common.h"
#include "core/traits.h"
#include <forward_list>
namespace bitsery {
namespace traits {
namespace traits {
template<typename T, typename Allocator>
struct ContainerTraits<std::forward_list<T, Allocator>> {
using TValue = T;
static constexpr bool isResizable = true;
static constexpr bool isContiguous = false;
static size_t size(const std::forward_list<T, Allocator>& container) {
return static_cast<size_t>(std::distance(container.begin(), container.end()));
}
static void resize(std::forward_list<T, Allocator>& container, size_t size) {
resizeImpl(container, size, std::is_default_constructible<TValue>{});
}
private:
using diff_t = typename std::forward_list<T, Allocator>::difference_type;
static void resizeImpl(std::forward_list<T, Allocator>& container, size_t size, std::true_type) {
container.resize(size);
}
static void resizeImpl(std::forward_list<T, Allocator>& container, size_t newSize, std::false_type) {
const auto oldSize = size(container);
for (auto it = oldSize; it < newSize; ++it) {
container.push_front(::bitsery::Access::create<TValue>());
}
if (oldSize > newSize) {
//erase_after must have atleast one element to work
if (newSize > 0)
container.erase_after(std::next(std::begin(container), static_cast<diff_t>(newSize-1)));
else
container.clear();
}
}
};
template<typename T, typename Allocator>
struct ContainerTraits<std::forward_list<T, Allocator>>
{
using TValue = T;
static constexpr bool isResizable = true;
static constexpr bool isContiguous = false;
static size_t size(const std::forward_list<T, Allocator>& container)
{
return static_cast<size_t>(
std::distance(container.begin(), container.end()));
}
static void resize(std::forward_list<T, Allocator>& container, size_t size)
{
resizeImpl(container, size, std::is_default_constructible<TValue>{});
}
private:
using diff_t = typename std::forward_list<T, Allocator>::difference_type;
static void resizeImpl(std::forward_list<T, Allocator>& container,
size_t size,
std::true_type)
{
container.resize(size);
}
static void resizeImpl(std::forward_list<T, Allocator>& container,
size_t newSize,
std::false_type)
{
const auto oldSize = size(container);
for (auto it = oldSize; it < newSize; ++it) {
container.push_front(::bitsery::Access::create<TValue>());
}
if (oldSize > newSize) {
// erase_after must have atleast one element to work
if (newSize > 0)
container.erase_after(
std::next(std::begin(container), static_cast<diff_t>(newSize - 1)));
else
container.clear();
}
}
};
}
}
#endif //BITSERY_TRAITS_STD_FORWARD_LIST_H
#endif // BITSERY_TRAITS_STD_FORWARD_LIST_H

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_TRAITS_STD_LIST_H
#define BITSERY_TRAITS_STD_LIST_H
@@ -29,14 +28,16 @@
namespace bitsery {
namespace traits {
namespace traits {
template<typename T, typename Allocator>
struct ContainerTraits<std::list<T, Allocator>>
: public StdContainer<std::list<T, Allocator>, true, false> {};
}
template<typename T, typename Allocator>
struct ContainerTraits<std::list<T, Allocator>>
: public StdContainer<std::list<T, Allocator>, true, false>
{
};
}
#endif //BITSERY_TRAITS_STD_LIST_H
}
#endif // BITSERY_TRAITS_STD_LIST_H

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_TRAITS_STD_STRING_H
#define BITSERY_TRAITS_STD_STRING_H
@@ -29,43 +28,55 @@
namespace bitsery {
namespace traits {
namespace traits {
// specialization for string, because string is already included for std::char_traits
// specialization for string, because string is already included for
// std::char_traits
template<typename CharT, typename Traits, typename Allocator>
struct ContainerTraits<std::basic_string<CharT, Traits, Allocator>>
:public StdContainer<std::basic_string<CharT, Traits, Allocator>, true, true> {};
template<typename CharT, typename Traits, typename Allocator>
struct ContainerTraits<std::basic_string<CharT, Traits, Allocator>>
: public StdContainer<std::basic_string<CharT, Traits, Allocator>, true, true>
{
};
template <typename CharT, typename Traits, typename Allocator>
struct TextTraits<std::basic_string<CharT, Traits, Allocator>> {
using TValue = typename ContainerTraits<std::basic_string<CharT, Traits, Allocator>>::TValue;
//string is automatically null-terminated
static constexpr bool addNUL = false;
template<typename CharT, typename Traits, typename Allocator>
struct TextTraits<std::basic_string<CharT, Traits, Allocator>>
{
using TValue = typename ContainerTraits<
std::basic_string<CharT, Traits, Allocator>>::TValue;
// string is automatically null-terminated
static constexpr bool addNUL = false;
//is is not 100% accurate, but for performance reasons assume that string stores text, not binary data
static size_t length(const std::basic_string<CharT, Traits, Allocator>& str) {
return str.size();
}
};
// is is not 100% accurate, but for performance reasons assume that string
// stores text, not binary data
static size_t length(const std::basic_string<CharT, Traits, Allocator>& str)
{
return str.size();
}
};
//specialization for c-array
template <typename T, size_t N>
struct TextTraits<T[N]> {
using TValue = T;
static constexpr bool addNUL = true;
// specialization for c-array
template<typename T, size_t N>
struct TextTraits<T[N]>
{
using TValue = T;
static constexpr bool addNUL = true;
static size_t length(const T (&container)[N]) {
return std::char_traits<T>::length(container);
}
};
static size_t length(const T (&container)[N])
{
return std::char_traits<T>::length(container);
}
};
template<typename CharT, typename Traits, typename Allocator>
struct BufferAdapterTraits<std::basic_string<CharT, Traits, Allocator>>
:public StdContainerForBufferAdapter<std::basic_string<CharT, Traits, Allocator>> {};
}
template<typename CharT, typename Traits, typename Allocator>
struct BufferAdapterTraits<std::basic_string<CharT, Traits, Allocator>>
: public StdContainerForBufferAdapter<
std::basic_string<CharT, Traits, Allocator>>
{
};
}
#endif //BITSERY_TRAITS_VECTOR_H
}
#endif // BITSERY_TRAITS_VECTOR_H

View File

@@ -1,25 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#ifndef BITSERY_TRAITS_STD_VECTOR_H
#define BITSERY_TRAITS_STD_VECTOR_H
@@ -29,22 +28,28 @@
namespace bitsery {
namespace traits {
template<typename T, typename Allocator>
struct ContainerTraits<std::vector<T, Allocator>>
:public StdContainer<std::vector<T, Allocator>, true, true> {};
namespace traits {
template<typename T, typename Allocator>
struct ContainerTraits<std::vector<T, Allocator>>
: public StdContainer<std::vector<T, Allocator>, true, true>
{
};
//bool vector is not contiguous, do not copy it directly to buffer
template<typename Allocator>
struct ContainerTraits<std::vector<bool, Allocator>>
:public StdContainer<std::vector<bool, Allocator>, true, false> {};
// bool vector is not contiguous, do not copy it directly to buffer
template<typename Allocator>
struct ContainerTraits<std::vector<bool, Allocator>>
: public StdContainer<std::vector<bool, Allocator>, true, false>
{
};
template<typename T, typename Allocator>
struct BufferAdapterTraits<std::vector<T, Allocator>>
:public StdContainerForBufferAdapter<std::vector<T, Allocator>> {};
}
template<typename T, typename Allocator>
struct BufferAdapterTraits<std::vector<T, Allocator>>
: public StdContainerForBufferAdapter<std::vector<T, Allocator>>
{
};
}
#endif //BITSERY_TRAITS_STD_VECTOR_H
}
#endif // BITSERY_TRAITS_STD_VECTOR_H

View File

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

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

View File

@@ -32,8 +32,6 @@ endif()
file(GLOB TestSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
enable_testing()
foreach (TestFile ${TestSourceFiles})
get_filename_component(TestName ${TestFile} NAME_WE)
set(TestName bitsery.test.${TestName})

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +1,24 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <bitsery/brief_syntax.h>
#include <bitsery/brief_syntax/array.h>
@@ -40,421 +40,464 @@
#include <bitsery/brief_syntax/tuple.h>
#include <bitsery/brief_syntax/variant.h>
#elif defined(_MSC_VER)
#pragma message("C++17 and /Zc:__cplusplus option is required to enable std::tuple and std::variant brief syntax tests")
#pragma message( \
"C++17 and /Zc:__cplusplus option is required to enable std::tuple and std::variant brief syntax tests")
#else
#pragma message("C++17 is required to enable std::tuple and std::variant brief syntax tests")
#pragma message( \
"C++17 is required to enable std::tuple and std::variant brief syntax tests")
#endif
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
#include <atomic>
#include <utility>
using testing::Eq;
TEST(BriefSyntax, FundamentalTypesAndBool) {
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double td = -454184.48445;
bool tb = true;
SerializationContext ctx{};
ctx.createSerializer()(ti, te, tf, td, tb);
TEST(BriefSyntax, FundamentalTypesAndBool)
{
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double td = -454184.48445;
bool tb = true;
SerializationContext ctx{};
ctx.createSerializer()(ti, te, tf, td, tb);
//result
int ri{};
MyEnumClass re{};
float rf{};
double rd{};
bool rb{};
ctx.createDeserializer()(ri, re, rf, rd, rb);
// result
int ri{};
MyEnumClass re{};
float rf{};
double rd{};
bool rb{};
ctx.createDeserializer()(ri, re, rf, rd, rb);
//test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
// test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
}
TEST(BriefSyntax, UseObjectFncInsteadOfValueN) {
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double td = -454184.48445;
bool tb = true;
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.object(ti);
ser.object(te);
ser.object(tf);
ser.object(td);
ser.object(tb);
TEST(BriefSyntax, UseObjectFncInsteadOfValueN)
{
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double td = -454184.48445;
bool tb = true;
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.object(ti);
ser.object(te);
ser.object(tf);
ser.object(td);
ser.object(tb);
//result
int ri{};
MyEnumClass re{};
float rf{};
double rd{};
bool rb{};
auto& des = ctx.createDeserializer();
des.object(ri);
des.object(re);
des.object(rf);
des.object(rd);
des.object(rb);
// result
int ri{};
MyEnumClass re{};
float rf{};
double rd{};
bool rb{};
auto& des = ctx.createDeserializer();
des.object(ri);
des.object(re);
des.object(rf);
des.object(rd);
des.object(rb);
//test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
// test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
}
TEST(BriefSyntax, MixDifferentSyntax) {
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double td = -454184.48445;
bool tb = true;
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.value<sizeof(ti)>(ti);
ser(te, tf, td);
ser.object(tb);
TEST(BriefSyntax, MixDifferentSyntax)
{
int ti = 8745;
MyEnumClass te = MyEnumClass::E4;
float tf = 485.042f;
double td = -454184.48445;
bool tb = true;
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.value<sizeof(ti)>(ti);
ser(te, tf, td);
ser.object(tb);
//result
int ri{};
MyEnumClass re{};
float rf{};
double rd{};
bool rb{};
auto& des = ctx.createDeserializer();
des(ri, re, rf);
des.value8b(rd);
des.object(rb);
// result
int ri{};
MyEnumClass re{};
float rf{};
double rd{};
bool rb{};
auto& des = ctx.createDeserializer();
des(ri, re, rf);
des.value8b(rd);
des.object(rb);
//test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
// test
EXPECT_THAT(ri, Eq(ti));
EXPECT_THAT(re, Eq(te));
EXPECT_THAT(rf, Eq(tf));
EXPECT_THAT(rd, Eq(td));
EXPECT_THAT(rb, Eq(tb));
}
template<typename T>
T procBriefSyntax(const T& testData) {
SerializationContext ctx;
ctx.createSerializer()(testData);
T res{};
ctx.createDeserializer()(res);
return res;
T
procBriefSyntax(const T& testData)
{
SerializationContext ctx;
ctx.createSerializer()(testData);
T res{};
ctx.createDeserializer()(res);
return res;
}
template<typename T>
T&& procBriefSyntaxRvalue(T&& init_value, const T& testData) {
SerializationContext ctx;
ctx.createSerializer()(testData);
ctx.createDeserializer()(init_value);
return std::move(init_value);
T&&
procBriefSyntaxRvalue(T&& init_value, const T& testData)
{
SerializationContext ctx;
ctx.createSerializer()(testData);
ctx.createDeserializer()(init_value);
return std::move(init_value);
}
template<typename T>
T procBriefSyntaxWithMaxSize(const T& testData) {
SerializationContext ctx;
ctx.createSerializer()(bitsery::maxSize(testData, 100));
T res{};
ctx.createDeserializer()(bitsery::maxSize(res, 100));
return res;
T
procBriefSyntaxWithMaxSize(const T& testData)
{
SerializationContext ctx;
ctx.createSerializer()(bitsery::maxSize(testData, 100));
T res{};
ctx.createDeserializer()(bitsery::maxSize(res, 100));
return res;
}
TEST(BriefSyntax, CStyleArrayForValueTypesAsContainer) {
const int t1[3]{8748, -484, 45};
int r1[3]{0, 0, 0};
TEST(BriefSyntax, CStyleArrayForValueTypesAsContainer)
{
const int t1[3]{ 8748, -484, 45 };
int r1[3]{ 0, 0, 0 };
SerializationContext ctx;
ctx.createSerializer()(bitsery::asContainer(t1));
ctx.createDeserializer()(bitsery::asContainer(r1));
SerializationContext ctx;
ctx.createSerializer()(bitsery::asContainer(t1));
ctx.createDeserializer()(bitsery::asContainer(r1));
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
}
TEST(BriefSyntax, CStyleArrayForIntegralTypesAsText) {
const char t1[3]{"hi"};
char r1[3]{0, 0, 0};
TEST(BriefSyntax, CStyleArrayForIntegralTypesAsText)
{
const char t1[3]{ "hi" };
char r1[3]{ 0, 0, 0 };
SerializationContext ctx;
ctx.createSerializer()(bitsery::asText(t1));
ctx.createDeserializer()(bitsery::asText(r1));
SerializationContext ctx;
ctx.createSerializer()(bitsery::asText(t1));
ctx.createDeserializer()(bitsery::asText(r1));
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
}
TEST(BriefSyntax, CStyleArray) {
const MyEnumClass t1[3]{MyEnumClass::E1, MyEnumClass::E4, MyEnumClass::E2};
MyEnumClass r1[3]{};
TEST(BriefSyntax, CStyleArray)
{
const MyEnumClass t1[3]{ MyEnumClass::E1, MyEnumClass::E4, MyEnumClass::E2 };
MyEnumClass r1[3]{};
SerializationContext ctx;
ctx.createSerializer()(t1);
ctx.createDeserializer()(r1);
SerializationContext ctx;
ctx.createSerializer()(t1);
ctx.createDeserializer()(r1);
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
}
TEST(BriefSyntax, StdString) {
std::string t1{"my nice string"};
std::string t2{};
TEST(BriefSyntax, StdString)
{
std::string t1{ "my nice string" };
std::string t2{};
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
}
TEST(BriefSyntax, StdArray) {
std::array<int, 3> t1{8748, -484, 45};
std::array<int, 0> t2{};
TEST(BriefSyntax, StdArray)
{
std::array<int, 3> t1{ 8748, -484, 45 };
std::array<int, 0> t2{};
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
}
TEST(BriefSyntax, StdVector) {
std::vector<int> t1{8748, -484, 45};
std::vector<float> t2{5.f, 0.198f};
TEST(BriefSyntax, StdVector)
{
std::vector<int> t1{ 8748, -484, 45 };
std::vector<float> t2{ 5.f, 0.198f };
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
}
TEST(BriefSyntax, StdList) {
std::list<int> t1{8748, -484, 45};
std::list<float> t2{5.f, 0.198f};
TEST(BriefSyntax, StdList)
{
std::list<int> t1{ 8748, -484, 45 };
std::list<float> t2{ 5.f, 0.198f };
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
}
TEST(BriefSyntax, StdForwardList) {
std::forward_list<int> t1{8748, -484, 45};
std::forward_list<float> t2{5.f, 0.198f};
TEST(BriefSyntax, StdForwardList)
{
std::forward_list<int> t1{ 8748, -484, 45 };
std::forward_list<float> t2{ 5.f, 0.198f };
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
}
TEST(BriefSyntax, StdDeque) {
std::deque<int> t1{8748, -484, 45};
std::deque<float> t2{5.f, 0.198f};
TEST(BriefSyntax, StdDeque)
{
std::deque<int> t1{ 8748, -484, 45 };
std::deque<float> t2{ 5.f, 0.198f };
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
}
TEST(BriefSyntax, StdQueue) {
std::queue<std::string> t1;
t1.push("first");
t1.push("second string");
TEST(BriefSyntax, StdQueue)
{
std::queue<std::string> t1;
t1.push("first");
t1.push("second string");
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
}
TEST(BriefSyntax, StdPriorityQueue) {
std::priority_queue<std::string> t1;
t1.push("first");
t1.push("second string");
t1.push("third");
t1.push("fourth");
auto r1 = procBriefSyntax(t1);
//we cannot compare priority queue directly
TEST(BriefSyntax, StdPriorityQueue)
{
std::priority_queue<std::string> t1;
t1.push("first");
t1.push("second string");
t1.push("third");
t1.push("fourth");
auto r1 = procBriefSyntax(t1);
// we cannot compare priority queue directly
EXPECT_THAT(r1.size(), Eq(t1.size()));
for (auto i = 0u; i < r1.size(); ++i) {
EXPECT_THAT(r1.top(), Eq(t1.top()));
r1.pop();
t1.pop();
}
EXPECT_THAT(r1.size(), Eq(t1.size()));
for (auto i = 0u; i < r1.size(); ++i) {
EXPECT_THAT(r1.top(), Eq(t1.top()));
r1.pop();
t1.pop();
}
}
TEST(BriefSyntax, StdStack) {
std::stack<std::string> t1;
t1.push("first");
t1.push("second string");
TEST(BriefSyntax, StdStack)
{
std::stack<std::string> t1;
t1.push("first");
t1.push("second string");
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
}
TEST(BriefSyntax, StdUnorderedMap) {
std::unordered_map<int, int> t1;
t1.emplace(3423, 624);
t1.emplace(-5484, -845);
TEST(BriefSyntax, StdUnorderedMap)
{
std::unordered_map<int, int> t1;
t1.emplace(3423, 624);
t1.emplace(-5484, -845);
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
}
TEST(BriefSyntax, StdUnorderedMultiMap) {
std::unordered_multimap<std::string, int> t1;
t1.emplace("one", 624);
t1.emplace("two", -845);
t1.emplace("one", 897);
TEST(BriefSyntax, StdUnorderedMultiMap)
{
std::unordered_multimap<std::string, int> t1;
t1.emplace("one", 624);
t1.emplace("two", -845);
t1.emplace("one", 897);
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
}
TEST(BriefSyntax, StdMap) {
std::map<int, int> t1;
t1.emplace(3423, 624);
t1.emplace(-5484, -845);
TEST(BriefSyntax, StdMap)
{
std::map<int, int> t1;
t1.emplace(3423, 624);
t1.emplace(-5484, -845);
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
}
TEST(BriefSyntax, StdMultiMap) {
std::multimap<std::string, int> t1;
t1.emplace("one", 624);
t1.emplace("two", -845);
t1.emplace("one", 897);
TEST(BriefSyntax, StdMultiMap)
{
std::multimap<std::string, int> t1;
t1.emplace("one", 624);
t1.emplace("two", -845);
t1.emplace("one", 897);
auto res = procBriefSyntax(t1);
//same key values is not ordered, and operator == compares each element at same position
//so we need to compare our selves
EXPECT_THAT(res.size(), Eq(3));
for (auto it = t1.begin(); it != t1.end();) {
const auto lr = t1.equal_range(it->first);
const auto rr = res.equal_range(it->first);
EXPECT_TRUE(std::distance(lr.first, lr.second) == std::distance(rr.first, rr.second));
EXPECT_TRUE(std::is_permutation(lr.first, lr.second, rr.first));
it = lr.second;
}
auto res = procBriefSyntax(t1);
// same key values is not ordered, and operator == compares each element at
// same position so we need to compare our selves
EXPECT_THAT(res.size(), Eq(3));
for (auto it = t1.begin(); it != t1.end();) {
const auto lr = t1.equal_range(it->first);
const auto rr = res.equal_range(it->first);
EXPECT_TRUE(std::distance(lr.first, lr.second) ==
std::distance(rr.first, rr.second));
EXPECT_TRUE(std::is_permutation(lr.first, lr.second, rr.first));
it = lr.second;
}
}
TEST(BriefSyntax, StdUnorderedSet) {
std::unordered_set<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
TEST(BriefSyntax, StdUnorderedSet)
{
std::unordered_set<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
}
TEST(BriefSyntax, StdUnorderedMultiSet) {
std::unordered_multiset<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
t1.emplace("one");
TEST(BriefSyntax, StdUnorderedMultiSet)
{
std::unordered_multiset<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
t1.emplace("one");
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
}
TEST(BriefSyntax, StdSet) {
std::set<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
TEST(BriefSyntax, StdSet)
{
std::set<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
}
TEST(BriefSyntax, StdMultiSet) {
std::multiset<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
t1.emplace("one");
t1.emplace("two");
TEST(BriefSyntax, StdMultiSet)
{
std::multiset<std::string> t1;
t1.emplace("one");
t1.emplace("two");
t1.emplace("three");
t1.emplace("one");
t1.emplace("two");
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
EXPECT_TRUE(procBriefSyntax(t1) == t1);
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
}
TEST(BriefSyntax, StdSmartPtr) {
std::shared_ptr<int> dataShared1(new int{4});
std::weak_ptr<int> dataWeak1(dataShared1);
std::unique_ptr<std::string> dataUnique1{new std::string{"hello world"}};
TEST(BriefSyntax, StdSmartPtr)
{
std::shared_ptr<int> dataShared1(new int{ 4 });
std::weak_ptr<int> dataWeak1(dataShared1);
std::unique_ptr<std::string> dataUnique1{ new std::string{ "hello world" } };
bitsery::ext::PointerLinkingContext plctx1{};
BasicSerializationContext<bitsery::ext::PointerLinkingContext> ctx;
ctx.createSerializer(plctx1)(dataShared1, dataWeak1, dataUnique1);
bitsery::ext::PointerLinkingContext plctx1{};
BasicSerializationContext<bitsery::ext::PointerLinkingContext> ctx;
ctx.createSerializer(plctx1)(dataShared1, dataWeak1, dataUnique1);
std::shared_ptr<int> resShared1{};
std::weak_ptr<int> resWeak1{};
std::unique_ptr<std::string> resUnique1{};
ctx.createDeserializer(plctx1)(resShared1, resWeak1, resUnique1);
//clear shared state from pointer linking context
plctx1.clearSharedState();
std::shared_ptr<int> resShared1{};
std::weak_ptr<int> resWeak1{};
std::unique_ptr<std::string> resUnique1{};
ctx.createDeserializer(plctx1)(resShared1, resWeak1, resUnique1);
// clear shared state from pointer linking context
plctx1.clearSharedState();
EXPECT_TRUE(plctx1.isValid());
EXPECT_THAT(*resShared1, Eq(*dataShared1));
EXPECT_THAT(*resWeak1.lock(), Eq(*dataWeak1.lock()));
EXPECT_THAT(*resUnique1, Eq(*dataUnique1));
EXPECT_TRUE(plctx1.isValid());
EXPECT_THAT(*resShared1, Eq(*dataShared1));
EXPECT_THAT(*resWeak1.lock(), Eq(*dataWeak1.lock()));
EXPECT_THAT(*resUnique1, Eq(*dataUnique1));
}
TEST(BriefSyntax, StdDuration) {
std::chrono::duration<int64_t, std::milli> t1{54654};
EXPECT_TRUE(procBriefSyntax(t1) == t1);
TEST(BriefSyntax, StdDuration)
{
std::chrono::duration<int64_t, std::milli> t1{ 54654 };
EXPECT_TRUE(procBriefSyntax(t1) == t1);
}
TEST(BriefSyntax, StdTimePoint) {
using Duration = std::chrono::duration<double, std::milli>;
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
TEST(BriefSyntax, StdTimePoint)
{
using Duration = std::chrono::duration<double, std::milli>;
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
TP data{Duration{874656.4798}};
EXPECT_TRUE(procBriefSyntax(data) == data);
TP data{ Duration{ 874656.4798 } };
EXPECT_TRUE(procBriefSyntax(data) == data);
}
TEST(BriefSyntax, StdAtomic) {
std::atomic<int32_t> atm0{54654};
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<int32_t>{}, atm0) == atm0);
TEST(BriefSyntax, StdAtomic)
{
std::atomic<int32_t> atm0{ 54654 };
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<int32_t>{}, atm0) == atm0);
std::atomic<bool> atm1{false};
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm1) == atm1);
std::atomic<bool> atm1{ false };
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm1) == atm1);
std::atomic<bool> atm2{true};
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm2) == atm2);
std::atomic<bool> atm2{ true };
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<bool>{}, atm2) == atm2);
std::atomic<uint16_t> atm3;
atm3.store(0x1337);
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<uint16_t>{}, atm3).load() == 0x1337);
std::atomic<uint16_t> atm3;
atm3.store(0x1337);
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<uint16_t>{}, atm3).load() ==
0x1337);
}
#if __cplusplus > 201402L
TEST(BriefSyntax, StdTuple) {
std::tuple<int, std::string, std::vector<char>> t1{5,"hello hello", {'A','B','C'}};
EXPECT_TRUE(procBriefSyntax(t1) == t1);
TEST(BriefSyntax, StdTuple)
{
std::tuple<int, std::string, std::vector<char>> t1{ 5,
"hello hello",
{ 'A', 'B', 'C' } };
EXPECT_TRUE(procBriefSyntax(t1) == t1);
}
TEST(BriefSyntax, StdVariant) {
std::variant<float, std::string, std::chrono::milliseconds> t1{std::string("hello hello")};
EXPECT_TRUE(procBriefSyntax(t1) == t1);
TEST(BriefSyntax, StdVariant)
{
std::variant<float, std::string, std::chrono::milliseconds> t1{ std::string(
"hello hello") };
EXPECT_TRUE(procBriefSyntax(t1) == t1);
}
#endif
TEST(BriefSyntax, NestedTypes) {
std::unordered_map<std::string, std::vector<std::string>> t1;
t1.emplace("my key", std::vector<std::string>{"very", "nice", "string"});
t1.emplace("other key", std::vector<std::string>{"just a string"});
TEST(BriefSyntax, NestedTypes)
{
std::unordered_map<std::string, std::vector<std::string>> t1;
t1.emplace("my key", std::vector<std::string>{ "very", "nice", "string" });
t1.emplace("other key", std::vector<std::string>{ "just a string" });
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
EXPECT_THAT(procBriefSyntax(t1), Eq(t1));
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
}

View File

@@ -1,184 +1,195 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "serialization_test_utils.h"
#include <bitsery/deserializer.h>
#include <bitsery/ext/value_range.h>
#include <bitsery/serializer.h>
#include <bitsery/deserializer.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::Eq;
using testing::ContainerEq;
using bitsery::EndiannessType;
using bitsery::DefaultConfig;
using bitsery::EndiannessType;
using testing::ContainerEq;
using testing::Eq;
constexpr EndiannessType getInverseEndianness(EndiannessType e) {
return e == EndiannessType::LittleEndian
? EndiannessType::BigEndian
: EndiannessType::LittleEndian;
constexpr EndiannessType
getInverseEndianness(EndiannessType e)
{
return e == EndiannessType::LittleEndian ? EndiannessType::BigEndian
: EndiannessType::LittleEndian;
}
struct InverseEndiannessConfig {
static constexpr bitsery::EndiannessType Endianness = getInverseEndianness(DefaultConfig::Endianness);
static constexpr bool CheckDataErrors = true;
static constexpr bool CheckAdapterErrors = true;
struct InverseEndiannessConfig
{
static constexpr bitsery::EndiannessType Endianness =
getInverseEndianness(DefaultConfig::Endianness);
static constexpr bool CheckDataErrors = true;
static constexpr bool CheckAdapterErrors = true;
};
struct IntegralTypes {
int64_t a;
uint32_t b;
int16_t c;
uint8_t d;
int8_t e;
struct IntegralTypes
{
int64_t a;
uint32_t b;
int16_t c;
uint8_t d;
int8_t e;
};
using InverseReader = bitsery::InputBufferAdapter<Buffer, InverseEndiannessConfig>;
using InverseReader =
bitsery::InputBufferAdapter<Buffer, InverseEndiannessConfig>;
TEST(DataEndianness, WhenWriteBytesThenBytesAreSwapped)
{
// fill initial values
IntegralTypes src{};
src.a = static_cast<int64_t>(0x1122334455667788u);
src.b = 0xBBCCDDEEu;
src.c = static_cast<int16_t>(0xCCDDu);
src.d = static_cast<uint8_t>(0xDDu);
src.e = static_cast<int8_t>(0xEEu);
TEST(DataEndianness, WhenWriteBytesThenBytesAreSwapped) {
//fill initial values
IntegralTypes src{};
src.a = static_cast<int64_t>(0x1122334455667788u);
src.b = 0xBBCCDDEEu;
src.c = static_cast<int16_t>(0xCCDDu);
src.d = static_cast<uint8_t>(0xDDu);
src.e = static_cast<int8_t>(0xEEu);
// fill expected result after swap
IntegralTypes resInv{};
resInv.a = static_cast<int64_t>(0x8877665544332211u);
resInv.b = 0xEEDDCCBBu;
resInv.c = static_cast<int16_t>(0xDDCCu);
resInv.d = static_cast<uint8_t>(0xDDu);
resInv.e = static_cast<int8_t>(0xEEu);
//fill expected result after swap
IntegralTypes resInv{};
resInv.a = static_cast<int64_t>(0x8877665544332211u);
resInv.b = 0xEEDDCCBBu;
resInv.c = static_cast<int16_t>(0xDDCCu);
resInv.d = static_cast<uint8_t>(0xDDu);
resInv.e = static_cast<int8_t>(0xEEu);
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBytes<8>(src.a);
bw.writeBytes<4>(src.b);
bw.writeBytes<2>(src.c);
bw.writeBytes<1>(src.d);
bw.writeBytes<1>(src.e);
bw.flush();
//read from buffer using inverse endianness config
InverseReader br{buf.begin(), bw.writtenBytesCount()};
IntegralTypes res{};
br.readBytes<8>(res.a);
br.readBytes<4>(res.b);
br.readBytes<2>(res.c);
br.readBytes<1>(res.d);
br.readBytes<1>(res.e);
//check results
EXPECT_THAT(res.a, Eq(resInv.a));
EXPECT_THAT(res.b, Eq(resInv.b));
EXPECT_THAT(res.c, Eq(resInv.c));
EXPECT_THAT(res.d, Eq(resInv.d));
EXPECT_THAT(res.e, Eq(resInv.e));
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
bw.writeBytes<8>(src.a);
bw.writeBytes<4>(src.b);
bw.writeBytes<2>(src.c);
bw.writeBytes<1>(src.d);
bw.writeBytes<1>(src.e);
bw.flush();
// read from buffer using inverse endianness config
InverseReader br{ buf.begin(), bw.writtenBytesCount() };
IntegralTypes res{};
br.readBytes<8>(res.a);
br.readBytes<4>(res.b);
br.readBytes<2>(res.c);
br.readBytes<1>(res.d);
br.readBytes<1>(res.e);
// check results
EXPECT_THAT(res.a, Eq(resInv.a));
EXPECT_THAT(res.b, Eq(resInv.b));
EXPECT_THAT(res.c, Eq(resInv.c));
EXPECT_THAT(res.d, Eq(resInv.d));
EXPECT_THAT(res.e, Eq(resInv.e));
}
TEST(DataEndianness, WhenWrite1ByteValuesThenEndiannessIsIgnored) {
//fill initial values
constexpr size_t SIZE = 4;
uint8_t src[SIZE] = {0xAA, 0xBB, 0xCC, 0xDD};
uint8_t res[SIZE] = {};
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBuffer<1>(src, SIZE);
bw.flush();
//read from buffer using inverse endianness config
InverseReader br{buf.begin(), bw.writtenBytesCount()};
br.readBuffer<1>(res, SIZE);
//result is identical, because we write separate values, of size 1byte, that requires no swapping
//check results
EXPECT_THAT(res, ContainerEq(src));
TEST(DataEndianness, WhenWrite1ByteValuesThenEndiannessIsIgnored)
{
// fill initial values
constexpr size_t SIZE = 4;
uint8_t src[SIZE] = { 0xAA, 0xBB, 0xCC, 0xDD };
uint8_t res[SIZE] = {};
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
bw.writeBuffer<1>(src, SIZE);
bw.flush();
// read from buffer using inverse endianness config
InverseReader br{ buf.begin(), bw.writtenBytesCount() };
br.readBuffer<1>(res, SIZE);
// result is identical, because we write separate values, of size 1byte, that
// requires no swapping check results
EXPECT_THAT(res, ContainerEq(src));
}
TEST(DataEndianness, WhenWriteMoreThan1ByteValuesThenValuesAreSwapped) {
//fill initial values
constexpr size_t SIZE = 4;
uint16_t src[SIZE] = {0xAA00, 0xBB11, 0xCC22, 0xDD33};
uint16_t resInv[SIZE] = {0x00AA, 0x11BB, 0x22CC, 0x33DD};
uint16_t res[SIZE] = {};
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBuffer<2>(src, SIZE);
bw.flush();
//read from buffer using inverse endianness config
InverseReader br{buf.begin(), bw.writtenBytesCount()};
br.readBuffer<2>(res, SIZE);
//result is identical, because we write separate values, of size 1byte, that requires no swapping
//check results
EXPECT_THAT(res, ContainerEq(resInv));
TEST(DataEndianness, WhenWriteMoreThan1ByteValuesThenValuesAreSwapped)
{
// fill initial values
constexpr size_t SIZE = 4;
uint16_t src[SIZE] = { 0xAA00, 0xBB11, 0xCC22, 0xDD33 };
uint16_t resInv[SIZE] = { 0x00AA, 0x11BB, 0x22CC, 0x33DD };
uint16_t res[SIZE] = {};
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
bw.writeBuffer<2>(src, SIZE);
bw.flush();
// read from buffer using inverse endianness config
InverseReader br{ buf.begin(), bw.writtenBytesCount() };
br.readBuffer<2>(res, SIZE);
// result is identical, because we write separate values, of size 1byte, that
// requires no swapping check results
EXPECT_THAT(res, ContainerEq(resInv));
}
template <typename T>
constexpr size_t getBits(T v) {
return bitsery::details::calcRequiredBits<T>({}, v);
template<typename T>
constexpr size_t
getBits(T v)
{
return bitsery::details::calcRequiredBits<T>({}, v);
}
struct IntegralUnsignedTypes {
uint64_t a;
uint32_t b;
uint16_t c;
uint8_t d;
struct IntegralUnsignedTypes
{
uint64_t a;
uint32_t b;
uint16_t c;
uint8_t d;
};
TEST(DataEndianness, WhenValueTypeIs1ByteThenBitOperationsIsNotAffectedByEndianness) {
//fill initial values
constexpr IntegralUnsignedTypes src {
0x0000334455667788,
0x00CCDDEE,
0x00DD,
0x0F,
};
TEST(DataEndianness,
WhenValueTypeIs1ByteThenBitOperationsIsNotAffectedByEndianness)
{
// fill initial values
constexpr IntegralUnsignedTypes src{
0x0000334455667788,
0x00CCDDEE,
0x00DD,
0x0F,
};
constexpr size_t aBITS = getBits(src.a) + 8;
constexpr size_t bBITS = getBits(src.b) + 0;
constexpr size_t cBITS = getBits(src.c) + 5;
constexpr size_t dBITS = getBits(src.d) + 2;
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bitsery::details::OutputAdapterBitPackingWrapper<Writer> bpw{bw};
bpw.writeBits(src.a, aBITS);
bpw.writeBits(src.b, bBITS);
bpw.writeBits(src.c, cBITS);
bpw.writeBits(src.d, dBITS);
bpw.flush();
//read from buffer using inverse endianness config
InverseReader br{buf.begin(), bpw.writtenBytesCount()};
bitsery::details::InputAdapterBitPackingWrapper<InverseReader> bpr{br};
IntegralUnsignedTypes res{};
bpr.readBits(res.a, aBITS);
bpr.readBits(res.b, bBITS);
bpr.readBits(res.c, cBITS);
bpr.readBits(res.d, dBITS);
//check results
EXPECT_THAT(res.a, Eq(src.a));
EXPECT_THAT(res.b, Eq(src.b));
EXPECT_THAT(res.c, Eq(src.c));
EXPECT_THAT(res.d, Eq(src.d));
constexpr size_t aBITS = getBits(src.a) + 8;
constexpr size_t bBITS = getBits(src.b) + 0;
constexpr size_t cBITS = getBits(src.c) + 5;
constexpr size_t dBITS = getBits(src.d) + 2;
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
bitsery::details::OutputAdapterBitPackingWrapper<Writer> bpw{ bw };
bpw.writeBits(src.a, aBITS);
bpw.writeBits(src.b, bBITS);
bpw.writeBits(src.c, cBITS);
bpw.writeBits(src.d, dBITS);
bpw.flush();
// read from buffer using inverse endianness config
InverseReader br{ buf.begin(), bpw.writtenBytesCount() };
bitsery::details::InputAdapterBitPackingWrapper<InverseReader> bpr{ br };
IntegralUnsignedTypes res{};
bpr.readBits(res.a, aBITS);
bpr.readBits(res.b, bBITS);
bpr.readBits(res.c, cBITS);
bpr.readBits(res.d, dBITS);
// check results
EXPECT_THAT(res.a, Eq(src.a));
EXPECT_THAT(res.b, Eq(src.b));
EXPECT_THAT(res.c, Eq(src.c));
EXPECT_THAT(res.d, Eq(src.d));
}

View File

@@ -1,410 +1,419 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "serialization_test_utils.h"
#include <bitsery/deserializer.h>
#include <bitsery/ext/value_range.h>
#include <bitsery/serializer.h>
#include <bitsery/deserializer.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
using testing::Eq;
using testing::ContainerEq;
using testing::Eq;
using AdapterBitPackingWriter = bitsery::details::OutputAdapterBitPackingWrapper<Writer>;
using AdapterBitPackingReader = bitsery::details::InputAdapterBitPackingWrapper<Reader>;
using AdapterBitPackingWriter =
bitsery::details::OutputAdapterBitPackingWrapper<Writer>;
using AdapterBitPackingReader =
bitsery::details::InputAdapterBitPackingWrapper<Reader>;
struct IntegralUnsignedTypes {
uint32_t a;
uint16_t b;
uint8_t c;
uint8_t d;
uint64_t e;
struct IntegralUnsignedTypes
{
uint32_t a;
uint16_t b;
uint8_t c;
uint8_t d;
uint64_t e;
};
template <typename T>
constexpr size_t getBits(T v) {
return bitsery::details::calcRequiredBits<T>({}, v);
template<typename T>
constexpr size_t
getBits(T v)
{
return bitsery::details::calcRequiredBits<T>({}, v);
}
// *** bits operations
TEST(DataBitsAndBytesOperations, WriteAndReadBitsMaxTypeValues) {
Buffer buf;
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
bpw.writeBits(std::numeric_limits<uint64_t>::max(), 64);
bpw.writeBits(std::numeric_limits<uint32_t>::max(), 32);
bpw.writeBits(std::numeric_limits<uint16_t>::max(), 16);
bpw.writeBits(std::numeric_limits<uint8_t>::max(), 8);
bpw.flush();
TEST(DataBitsAndBytesOperations, WriteAndReadBitsMaxTypeValues)
{
Buffer buf;
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBits(std::numeric_limits<uint64_t>::max(), 64);
bpw.writeBits(std::numeric_limits<uint32_t>::max(), 32);
bpw.writeBits(std::numeric_limits<uint16_t>::max(), 16);
bpw.writeBits(std::numeric_limits<uint8_t>::max(), 8);
bpw.flush();
Reader br{buf.begin(), bpw.writtenBytesCount()};
AdapterBitPackingReader bpr{br};
uint64_t v64{};
uint32_t v32{};
uint16_t v16{};
uint8_t v8{};
bpr.readBits(v64, 64);
bpr.readBits(v32, 32);
bpr.readBits(v16, 16);
bpr.readBits(v8, 8);
Reader br{ buf.begin(), bpw.writtenBytesCount() };
AdapterBitPackingReader bpr{ br };
uint64_t v64{};
uint32_t v32{};
uint16_t v16{};
uint8_t v8{};
bpr.readBits(v64, 64);
bpr.readBits(v32, 32);
bpr.readBits(v16, 16);
bpr.readBits(v8, 8);
EXPECT_THAT(v64, Eq(std::numeric_limits<uint64_t>::max()));
EXPECT_THAT(v32, Eq(std::numeric_limits<uint32_t>::max()));
EXPECT_THAT(v16, Eq(std::numeric_limits<uint16_t>::max()));
EXPECT_THAT(v8, Eq(std::numeric_limits<uint8_t>::max()));
EXPECT_THAT(v64, Eq(std::numeric_limits<uint64_t>::max()));
EXPECT_THAT(v32, Eq(std::numeric_limits<uint32_t>::max()));
EXPECT_THAT(v16, Eq(std::numeric_limits<uint16_t>::max()));
EXPECT_THAT(v8, Eq(std::numeric_limits<uint8_t>::max()));
}
TEST(DataBitsAndBytesOperations, WriteAndReadBits) {
//setup data
constexpr IntegralUnsignedTypes data{
485454,//bits 19
45978,//bits 16
0,//bits 1
36,//bits 6
479845648946//bits 39
};
TEST(DataBitsAndBytesOperations, WriteAndReadBits)
{
// setup data
constexpr IntegralUnsignedTypes data{
485454, // bits 19
45978, // bits 16
0, // bits 1
36, // bits 6
479845648946 // bits 39
};
constexpr size_t aBITS = getBits(data.a) + 2;
constexpr size_t bBITS = getBits(data.b) + 0;
constexpr size_t cBITS = getBits(data.c) + 2;
constexpr size_t dBITS = getBits(data.d) + 1;
constexpr size_t eBITS = getBits(data.e) + 8;
constexpr size_t aBITS = getBits(data.a) + 2;
constexpr size_t bBITS = getBits(data.b) + 0;
constexpr size_t cBITS = getBits(data.c) + 2;
constexpr size_t dBITS = getBits(data.d) + 1;
constexpr size_t eBITS = getBits(data.e) + 8;
//create and write to buffer
Buffer buf;
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
// create and write to buffer
Buffer buf;
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBits(data.a, aBITS);
bpw.writeBits(data.b, bBITS);
bpw.writeBits(data.c, cBITS);
bpw.writeBits(data.d, dBITS);
bpw.writeBits(data.e, eBITS);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
auto bytesCount = ((aBITS + bBITS + cBITS + dBITS + eBITS) / 8) +1 ;
EXPECT_THAT(writtenSize, Eq(bytesCount));
//read from buffer
Reader br{buf.begin(), writtenSize};
AdapterBitPackingReader bpr{br};
bpw.writeBits(data.a, aBITS);
bpw.writeBits(data.b, bBITS);
bpw.writeBits(data.c, cBITS);
bpw.writeBits(data.d, dBITS);
bpw.writeBits(data.e, eBITS);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
auto bytesCount = ((aBITS + bBITS + cBITS + dBITS + eBITS) / 8) + 1;
EXPECT_THAT(writtenSize, Eq(bytesCount));
// read from buffer
Reader br{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr{ br };
IntegralUnsignedTypes res{};
IntegralUnsignedTypes res{};
bpr.readBits(res.a, aBITS);
bpr.readBits(res.b, bBITS);
bpr.readBits(res.c, cBITS);
bpr.readBits(res.d, dBITS);
bpr.readBits(res.e, eBITS);
EXPECT_THAT(res.a, Eq(data.a));
EXPECT_THAT(res.b, Eq(data.b));
EXPECT_THAT(res.c, Eq(data.c));
EXPECT_THAT(res.d, Eq(data.d));
EXPECT_THAT(res.e, Eq(data.e));
bpr.readBits(res.a, aBITS);
bpr.readBits(res.b, bBITS);
bpr.readBits(res.c, cBITS);
bpr.readBits(res.d, dBITS);
bpr.readBits(res.e, eBITS);
EXPECT_THAT(res.a, Eq(data.a));
EXPECT_THAT(res.b, Eq(data.b));
EXPECT_THAT(res.c, Eq(data.c));
EXPECT_THAT(res.d, Eq(data.d));
EXPECT_THAT(res.e, Eq(data.e));
}
TEST(DataBitsAndBytesOperations, WrittenSizeIsCountedPerByteNotPerBit) {
//setup data
TEST(DataBitsAndBytesOperations, WrittenSizeIsCountedPerByteNotPerBit)
{
// setup data
//create and write to buffer
Buffer buf;
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
// create and write to buffer
Buffer buf;
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBits(7u,3);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(1));
bpw.writeBits(7u, 3);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(1));
//read from buffer
Reader br{buf.begin(), writtenSize};
AdapterBitPackingReader bpr{br};
uint16_t tmp;
bpr.readBits(tmp,4);
bpr.readBits(tmp,2);
bpr.readBits(tmp,2);
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
bpr.readBits(tmp,2);
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::DataOverflow));//false
// read from buffer
Reader br{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr{ br };
uint16_t tmp;
bpr.readBits(tmp, 4);
bpr.readBits(tmp, 2);
bpr.readBits(tmp, 2);
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
bpr.readBits(tmp, 2);
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::DataOverflow)); // false
//part of next byte
Reader br1{buf.begin(), writtenSize};
AdapterBitPackingReader bpr1{br1};
bpr1.readBits(tmp,2);
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::NoError));
bpr1.readBits(tmp,7);
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::DataOverflow));//false
// part of next byte
Reader br1{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr1{ br1 };
bpr1.readBits(tmp, 2);
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::NoError));
bpr1.readBits(tmp, 7);
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::DataOverflow)); // false
//bigger than byte
Reader br2{buf.begin(), writtenSize};
AdapterBitPackingReader bpr2{br2};
bpr2.readBits(tmp,9);
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::DataOverflow));//false
// bigger than byte
Reader br2{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr2{ br2 };
bpr2.readBits(tmp, 9);
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::DataOverflow)); // false
}
TEST(DataBitsAndBytesOperations, ConsecutiveCallsToAlignHasNoEffect) {
Buffer buf;
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
TEST(DataBitsAndBytesOperations, ConsecutiveCallsToAlignHasNoEffect)
{
Buffer buf;
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBits(3u, 2);
//3 calls to align after 1st data
bpw.align();
bpw.align();
bpw.align();
bpw.writeBits(7u, 3);
//1 call to align after 2nd data
bpw.align();
bpw.writeBits(15u, 4);
bpw.flush();
bpw.writeBits(3u, 2);
// 3 calls to align after 1st data
bpw.align();
bpw.align();
bpw.align();
bpw.writeBits(7u, 3);
// 1 call to align after 2nd data
bpw.align();
bpw.writeBits(15u, 4);
bpw.flush();
unsigned char tmp;
Reader br{buf.begin(), bpw.writtenBytesCount()};
AdapterBitPackingReader bpr{br};
bpr.readBits(tmp,2);
EXPECT_THAT(tmp, Eq(3u));
bpr.align();
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
bpr.readBits(tmp,3);
bpr.align();
bpr.align();
bpr.align();
EXPECT_THAT(tmp, Eq(7u));
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
unsigned char tmp;
Reader br{ buf.begin(), bpw.writtenBytesCount() };
AdapterBitPackingReader bpr{ br };
bpr.readBits(tmp, 2);
EXPECT_THAT(tmp, Eq(3u));
bpr.align();
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
bpr.readBits(tmp, 3);
bpr.align();
bpr.align();
bpr.align();
EXPECT_THAT(tmp, Eq(7u));
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
bpr.readBits(tmp,4);
EXPECT_THAT(tmp, Eq(15u));
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
bpr.readBits(tmp, 4);
EXPECT_THAT(tmp, Eq(15u));
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
}
TEST(DataBitsAndBytesOperations, AlignWritesZerosBits) {
//setup data
TEST(DataBitsAndBytesOperations, AlignWritesZerosBits)
{
// setup data
//create and write to buffer
Buffer buf;
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
// create and write to buffer
Buffer buf;
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
//write 2 bits and align
bpw.writeBits(3u, 2);
bpw.align();
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(1));
unsigned char tmp;
Reader br1{buf.begin(), writtenSize};
AdapterBitPackingReader bpr1{br1};
bpr1.readBits(tmp,2);
//read aligned bits
bpr1.readBits(tmp,6);
EXPECT_THAT(tmp, Eq(0));
// write 2 bits and align
bpw.writeBits(3u, 2);
bpw.align();
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(1));
unsigned char tmp;
Reader br1{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr1{ br1 };
bpr1.readBits(tmp, 2);
// read aligned bits
bpr1.readBits(tmp, 6);
EXPECT_THAT(tmp, Eq(0));
Reader br2{buf.begin(), writtenSize};
AdapterBitPackingReader bpr2{br2};
//read 2 bits
bpr2.readBits(tmp,2);
bpr2.align();
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::NoError));
Reader br2{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr2{ br2 };
// read 2 bits
bpr2.readBits(tmp, 2);
bpr2.align();
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::NoError));
}
// *** bytes operations
struct IntegralTypes {
int64_t a;
uint32_t b;
int16_t c;
uint8_t d;
int8_t e;
int8_t f[2];
struct IntegralTypes
{
int64_t a;
uint32_t b;
int16_t c;
uint8_t d;
int8_t e;
int8_t f[2];
};
TEST(DataBitsAndBytesOperations, WriteAndReadBytes) {
//setup data
IntegralTypes data;
data.a = -4894541654564;
data.b = 94545646;
data.c = -8778;
data.d = 200;
data.e = -98;
data.f[0] = 43;
data.f[1] = -45;
TEST(DataBitsAndBytesOperations, WriteAndReadBytes)
{
// setup data
IntegralTypes data;
data.a = -4894541654564;
data.b = 94545646;
data.c = -8778;
data.d = 200;
data.e = -98;
data.f[0] = 43;
data.f[1] = -45;
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBytes<4>(data.b);
bw.writeBytes<2>(data.c);
bw.writeBytes<1>(data.d);
bw.writeBytes<8>(data.a);
bw.writeBytes<1>(data.e);
bw.writeBuffer<1>(data.f, 2);
bw.flush();
auto writtenSize = bw.writtenBytesCount();
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
bw.writeBytes<4>(data.b);
bw.writeBytes<2>(data.c);
bw.writeBytes<1>(data.d);
bw.writeBytes<8>(data.a);
bw.writeBytes<1>(data.e);
bw.writeBuffer<1>(data.f, 2);
bw.flush();
auto writtenSize = bw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(18));
//read from buffer
Reader br{buf.begin(), writtenSize};
IntegralTypes res{};
br.readBytes<4>(res.b);
br.readBytes<2>(res.c);
br.readBytes<1>(res.d);
br.readBytes<8>(res.a);
br.readBytes<1>(res.e);
br.readBuffer<1>(res.f, 2);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
//assert results
EXPECT_THAT(data.a, Eq(res.a));
EXPECT_THAT(data.b, Eq(res.b));
EXPECT_THAT(data.c, Eq(res.c));
EXPECT_THAT(data.d, Eq(res.d));
EXPECT_THAT(data.e, Eq(res.e));
EXPECT_THAT(data.f, ContainerEq(res.f));
EXPECT_THAT(writtenSize, Eq(18));
// read from buffer
Reader br{ buf.begin(), writtenSize };
IntegralTypes res{};
br.readBytes<4>(res.b);
br.readBytes<2>(res.c);
br.readBytes<1>(res.d);
br.readBytes<8>(res.a);
br.readBytes<1>(res.e);
br.readBuffer<1>(res.f, 2);
EXPECT_THAT(br.error(), Eq(bitsery::ReaderError::NoError));
// assert results
EXPECT_THAT(data.a, Eq(res.a));
EXPECT_THAT(data.b, Eq(res.b));
EXPECT_THAT(data.c, Eq(res.c));
EXPECT_THAT(data.d, Eq(res.d));
EXPECT_THAT(data.e, Eq(res.e));
EXPECT_THAT(data.f, ContainerEq(res.f));
}
TEST(DataBitsAndBytesOperations, WriteAndReadBytesWithBitPackingWrapper) {
//setup data
IntegralTypes data;
data.a = -4894541654564;
data.b = 94545646;
data.c = -8778;
data.d = 200;
data.e = -98;
data.f[0] = 43;
data.f[1] = -45;
TEST(DataBitsAndBytesOperations, WriteAndReadBytesWithBitPackingWrapper)
{
// setup data
IntegralTypes data;
data.a = -4894541654564;
data.b = 94545646;
data.c = -8778;
data.d = 200;
data.e = -98;
data.f[0] = 43;
data.f[1] = -45;
//create and write to buffer
Buffer buf{};
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
bpw.writeBytes<4>(data.b);
bpw.writeBytes<2>(data.c);
bpw.writeBytes<1>(data.d);
bpw.writeBytes<8>(data.a);
bpw.writeBytes<1>(data.e);
bpw.writeBuffer<1>(data.f, 2);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBytes<4>(data.b);
bpw.writeBytes<2>(data.c);
bpw.writeBytes<1>(data.d);
bpw.writeBytes<8>(data.a);
bpw.writeBytes<1>(data.e);
bpw.writeBuffer<1>(data.f, 2);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(18));
//read from buffer
Reader br{buf.begin(), writtenSize};
AdapterBitPackingReader bpr{br};
IntegralTypes res{};
bpr.readBytes<4>(res.b);
bpr.readBytes<2>(res.c);
bpr.readBytes<1>(res.d);
bpr.readBytes<8>(res.a);
bpr.readBytes<1>(res.e);
bpr.readBuffer<1>(res.f, 2);
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
//assert results
EXPECT_THAT(data.a, Eq(res.a));
EXPECT_THAT(data.b, Eq(res.b));
EXPECT_THAT(data.c, Eq(res.c));
EXPECT_THAT(data.d, Eq(res.d));
EXPECT_THAT(data.e, Eq(res.e));
EXPECT_THAT(data.f, ContainerEq(res.f));
EXPECT_THAT(writtenSize, Eq(18));
// read from buffer
Reader br{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr{ br };
IntegralTypes res{};
bpr.readBytes<4>(res.b);
bpr.readBytes<2>(res.c);
bpr.readBytes<1>(res.d);
bpr.readBytes<8>(res.a);
bpr.readBytes<1>(res.e);
bpr.readBuffer<1>(res.f, 2);
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
// assert results
EXPECT_THAT(data.a, Eq(res.a));
EXPECT_THAT(data.b, Eq(res.b));
EXPECT_THAT(data.c, Eq(res.c));
EXPECT_THAT(data.d, Eq(res.d));
EXPECT_THAT(data.e, Eq(res.e));
EXPECT_THAT(data.f, ContainerEq(res.f));
}
TEST(DataBitsAndBytesOperations, ReadWriteFncCanAcceptSignedData) {
//setup data
constexpr size_t DATA_SIZE = 3;
int16_t src[DATA_SIZE] {54,-4877,30067};
//create and write to buffer
Buffer buf{};
Writer bw{buf};
bw.writeBuffer<2>(src, DATA_SIZE);
bw.flush();
//read from buffer
Reader br1{buf.begin(), bw.writtenBytesCount()};
int16_t dst[DATA_SIZE]{};
br1.readBuffer<2>(dst, DATA_SIZE);
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(dst, ContainerEq(src));
TEST(DataBitsAndBytesOperations, ReadWriteFncCanAcceptSignedData)
{
// setup data
constexpr size_t DATA_SIZE = 3;
int16_t src[DATA_SIZE]{ 54, -4877, 30067 };
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
bw.writeBuffer<2>(src, DATA_SIZE);
bw.flush();
// read from buffer
Reader br1{ buf.begin(), bw.writtenBytesCount() };
int16_t dst[DATA_SIZE]{};
br1.readBuffer<2>(dst, DATA_SIZE);
EXPECT_THAT(br1.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(dst, ContainerEq(src));
}
TEST(DataBitsAndBytesOperations, ReadWriteCanWorkOnUnalignedData) {
//setup data
constexpr size_t DATA_SIZE = 3;
int16_t src[DATA_SIZE] {54,-4877,30067};
//create and write to buffer
Buffer buf{};
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
bpw.writeBits(15u, 4);
bpw.writeBuffer<2>(src, DATA_SIZE);
bpw.writeBits(12u, 4);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(sizeof(src) + 1));
TEST(DataBitsAndBytesOperations, ReadWriteCanWorkOnUnalignedData)
{
// setup data
constexpr size_t DATA_SIZE = 3;
int16_t src[DATA_SIZE]{ 54, -4877, 30067 };
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBits(15u, 4);
bpw.writeBuffer<2>(src, DATA_SIZE);
bpw.writeBits(12u, 4);
bpw.flush();
auto writtenSize = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize, Eq(sizeof(src) + 1));
//read from buffer
Reader br1{buf.begin(), writtenSize};
AdapterBitPackingReader bpr1{br1};
int16_t dst[DATA_SIZE]{};
uint8_t tmp{};
bpr1.readBits(tmp, 4);
EXPECT_THAT(tmp, Eq(15));
bpr1.readBuffer<2>(dst, DATA_SIZE);
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(dst, ContainerEq(src));
bpr1.readBits(tmp, 4);
EXPECT_THAT(tmp, Eq(12));
// read from buffer
Reader br1{ buf.begin(), writtenSize };
AdapterBitPackingReader bpr1{ br1 };
int16_t dst[DATA_SIZE]{};
uint8_t tmp{};
bpr1.readBits(tmp, 4);
EXPECT_THAT(tmp, Eq(15));
bpr1.readBuffer<2>(dst, DATA_SIZE);
EXPECT_THAT(bpr1.error(), Eq(bitsery::ReaderError::NoError));
EXPECT_THAT(dst, ContainerEq(src));
bpr1.readBits(tmp, 4);
EXPECT_THAT(tmp, Eq(12));
}
TEST(DataBitsAndBytesOperations, RegressionTestReadBytesAfterReadBitsWithLotsOfZeroBits) {
//setup data
int16_t data[2]{0x0000, 0x7FFF};
int16_t res[2]{};
//create and write to buffer
Buffer buf{};
Writer bw{buf};
AdapterBitPackingWriter bpw{bw};
bpw.writeBits(2u, 2);
bpw.writeBytes<2>(data[0]);
bpw.writeBytes<2>(data[1]);
bpw.align();
bpw.flush();
TEST(DataBitsAndBytesOperations,
RegressionTestReadBytesAfterReadBitsWithLotsOfZeroBits)
{
// setup data
int16_t data[2]{ 0x0000, 0x7FFF };
int16_t res[2]{};
// create and write to buffer
Buffer buf{};
Writer bw{ buf };
AdapterBitPackingWriter bpw{ bw };
bpw.writeBits(2u, 2);
bpw.writeBytes<2>(data[0]);
bpw.writeBytes<2>(data[1]);
bpw.align();
bpw.flush();
//read from buffer
Reader br{buf.begin(), bpw.writtenBytesCount()};
AdapterBitPackingReader bpr{br};
uint8_t tmp{};
bpr.readBits(tmp, 2);
EXPECT_THAT(tmp, Eq(2));
bpr.readBytes<2>(res[0]);
bpr.readBytes<2>(res[1]);
bpr.align();
EXPECT_THAT(res[0], Eq(data[0]));
EXPECT_THAT(res[1], Eq(data[1]));
// read from buffer
Reader br{ buf.begin(), bpw.writtenBytesCount() };
AdapterBitPackingReader bpr{ br };
uint8_t tmp{};
bpr.readBits(tmp, 2);
EXPECT_THAT(tmp, Eq(2));
bpr.readBytes<2>(res[0]);
bpr.readBytes<2>(res[1]);
bpr.align();
EXPECT_THAT(res[0], Eq(data[0]));
EXPECT_THAT(res[1], Eq(data[1]));
}

View File

@@ -1,111 +1,117 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <bitsery/details/serialization_common.h>
#include <bitsery/traits/array.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::Eq;
using testing::ContainerEq;
using bitsery::EndiannessType;
using testing::ContainerEq;
using testing::Eq;
template <typename BufType>
class DataWriting:public testing::Test {
template<typename BufType>
class DataWriting : public testing::Test
{
public:
using TWriter = bitsery::OutputBufferAdapter<BufType>;
using TBuffer = BufType;
using TWriter = bitsery::OutputBufferAdapter<BufType>;
using TBuffer = BufType;
};
using NonFixedContainer = std::vector<uint8_t>;
using FixedContainer = std::array<uint8_t, 100>;
using ContainerTypes = ::testing::Types<FixedContainer,NonFixedContainer>;
using ContainerTypes = ::testing::Types<FixedContainer, NonFixedContainer>;
TYPED_TEST_SUITE(DataWriting, ContainerTypes,);
TYPED_TEST_SUITE(DataWriting, ContainerTypes, );
static constexpr size_t DATA_SIZE = 14u;
template <typename BW>
void writeData(BW& bw) {
uint16_t tmp1{45}, tmp2{6543}, tmp3{46533};
uint32_t tmp4{8979445}, tmp5{7987564};
bw.template writeBytes<2>(tmp1);
bw.template writeBytes<2>(tmp2);
bw.template writeBytes<2>(tmp3);
bw.template writeBytes<4>(tmp4);
bw.template writeBytes<4>(tmp5);
template<typename BW>
void
writeData(BW& bw)
{
uint16_t tmp1{ 45 }, tmp2{ 6543 }, tmp3{ 46533 };
uint32_t tmp4{ 8979445 }, tmp5{ 7987564 };
bw.template writeBytes<2>(tmp1);
bw.template writeBytes<2>(tmp2);
bw.template writeBytes<2>(tmp3);
bw.template writeBytes<4>(tmp4);
bw.template writeBytes<4>(tmp5);
}
TYPED_TEST(DataWriting, GetWrittenBytesCountReturnsActualBytesWritten) {
using TWriter = typename TestFixture::TWriter;
using TBuffer = typename TestFixture::TBuffer;
TBuffer buf{};
TWriter bw{buf};
writeData(bw);
bw.flush();
auto writtenSize = bw.writtenBytesCount();
EXPECT_THAT(writtenSize, DATA_SIZE);
EXPECT_THAT(buf.size(), ::testing::Ge(DATA_SIZE));
TYPED_TEST(DataWriting, GetWrittenBytesCountReturnsActualBytesWritten)
{
using TWriter = typename TestFixture::TWriter;
using TBuffer = typename TestFixture::TBuffer;
TBuffer buf{};
TWriter bw{ buf };
writeData(bw);
bw.flush();
auto writtenSize = bw.writtenBytesCount();
EXPECT_THAT(writtenSize, DATA_SIZE);
EXPECT_THAT(buf.size(), ::testing::Ge(DATA_SIZE));
}
TYPED_TEST(DataWriting, WhenWritingBitsThenMustFlushWriter) {
using TWriter = typename TestFixture::TWriter;
using TBuffer = typename TestFixture::TBuffer;
TBuffer buf{};
TWriter bw{buf};
bitsery::details::OutputAdapterBitPackingWrapper<TWriter> bpw{bw};
bpw.writeBits(3u, 2);
auto writtenSize1 = bpw.writtenBytesCount();
bpw.flush();
auto writtenSize2 = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize1, Eq(0));
EXPECT_THAT(writtenSize2, Eq(1));
TYPED_TEST(DataWriting, WhenWritingBitsThenMustFlushWriter)
{
using TWriter = typename TestFixture::TWriter;
using TBuffer = typename TestFixture::TBuffer;
TBuffer buf{};
TWriter bw{ buf };
bitsery::details::OutputAdapterBitPackingWrapper<TWriter> bpw{ bw };
bpw.writeBits(3u, 2);
auto writtenSize1 = bpw.writtenBytesCount();
bpw.flush();
auto writtenSize2 = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize1, Eq(0));
EXPECT_THAT(writtenSize2, Eq(1));
}
TYPED_TEST(DataWriting, WhenDataAlignedThenFlushHasNoEffect) {
using TWriter = typename TestFixture::TWriter;
using TBuffer = typename TestFixture::TBuffer;
TBuffer buf{};
TWriter bw{buf};
bitsery::details::OutputAdapterBitPackingWrapper<TWriter> bpw{bw};
bpw.writeBits(3u, 2);
bpw.align();
auto writtenSize1 = bpw.writtenBytesCount();
bpw.flush();
auto writtenSize2 = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize1, Eq(1));
EXPECT_THAT(writtenSize2, Eq(1));
TYPED_TEST(DataWriting, WhenDataAlignedThenFlushHasNoEffect)
{
using TWriter = typename TestFixture::TWriter;
using TBuffer = typename TestFixture::TBuffer;
TBuffer buf{};
TWriter bw{ buf };
bitsery::details::OutputAdapterBitPackingWrapper<TWriter> bpw{ bw };
bpw.writeBits(3u, 2);
bpw.align();
auto writtenSize1 = bpw.writtenBytesCount();
bpw.flush();
auto writtenSize2 = bpw.writtenBytesCount();
EXPECT_THAT(writtenSize1, Eq(1));
EXPECT_THAT(writtenSize2, Eq(1));
}
TEST(DataWritingNonFixedBufferContainer, ContainerIsAlwaysResizedToCapacity) {
NonFixedContainer buf{};
bitsery::OutputBufferAdapter<NonFixedContainer> bw{buf};
for (auto i = 0; i < 5; ++i) {
uint32_t tmp{};
bw.writeBytes<4>(tmp);
bw.writeBytes<4>(tmp);
EXPECT_TRUE(buf.size() == buf.capacity());
}
TEST(DataWritingNonFixedBufferContainer, ContainerIsAlwaysResizedToCapacity)
{
NonFixedContainer buf{};
bitsery::OutputBufferAdapter<NonFixedContainer> bw{ buf };
for (auto i = 0; i < 5; ++i) {
uint32_t tmp{};
bw.writeBytes<4>(tmp);
bw.writeBytes<4>(tmp);
EXPECT_TRUE(buf.size() == buf.capacity());
}
}

View File

@@ -1,351 +1,394 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <forward_list>
#include <bitsery/traits/forward_list.h>
#include <bitsery/ext/std_set.h>
#include <bitsery/ext/std_map.h>
#include <bitsery/ext/pointer.h>
#include <bitsery/ext/std_map.h>
#include <bitsery/ext/std_set.h>
#include <bitsery/ext/std_smart_ptr.h>
#include <bitsery/traits/forward_list.h>
#include <forward_list>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::ContainerEq;
using testing::Eq;
//forward declare, for testing with std::unordered_map
// forward declare, for testing with std::unordered_map
class HasherForNonDefaultConstructible;
class NonDefaultConstructible {
int32_t i{0};
friend class HasherForNonDefaultConstructible;
class NonDefaultConstructible
{
int32_t i{ 0 };
friend class HasherForNonDefaultConstructible;
friend class bitsery::Access;
NonDefaultConstructible() = default;
friend class bitsery::Access;
NonDefaultConstructible() = default;
template <typename S>
void serialize(S& s) {
s.value4b(i);
}
template<typename S>
void serialize(S& s)
{
s.value4b(i);
}
public:
explicit NonDefaultConstructible(int32_t v)
: i{ v }
{
}
explicit NonDefaultConstructible(int32_t v):i{v} {}
bool operator==(const NonDefaultConstructible& other) const
{
return i == other.i;
}
bool operator == (const NonDefaultConstructible& other) const {
return i == other.i;
}
bool operator < (const NonDefaultConstructible& other) const {
return i < other.i;
}
bool operator<(const NonDefaultConstructible& other) const
{
return i < other.i;
}
};
class HasherForNonDefaultConstructible {
class HasherForNonDefaultConstructible
{
public:
size_t operator()(const NonDefaultConstructible& o) const {
return std::hash<int32_t>()(o.i);
}
size_t operator()(const NonDefaultConstructible& o) const
{
return std::hash<int32_t>()(o.i);
}
};
TEST(DeserializeNonDefaultConstructible, Container)
{
SerializationContext ctx{};
std::vector<NonDefaultConstructible> data{};
data.emplace_back(1);
data.emplace_back(2);
data.emplace_back(3);
std::vector<NonDefaultConstructible> res{};
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
EXPECT_THAT(res, ContainerEq(data));
}
// this test is here, because when object is not constructible we cannot simple
// "resize" container
TEST(DeserializeNonDefaultConstructible, ResultContainerShouldShrink)
{
SerializationContext ctx{};
std::vector<NonDefaultConstructible> data{};
data.emplace_back(1);
std::vector<NonDefaultConstructible> res{};
res.emplace_back(2);
res.emplace_back(3);
res.emplace_back(4);
TEST(DeserializeNonDefaultConstructible, Container) {
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
EXPECT_THAT(res, ContainerEq(data));
}
TEST(DeserializeNonDefaultConstructible, ResultStdForwardListShouldShrink)
{
// forward list doesn't have .erase function, bet has erase_after
// in this case, if new size is 0 it must call clear, so we need to check two
// cases
{
// 1) when result should have more than 0 elements
SerializationContext ctx{};
std::vector<NonDefaultConstructible> data{};
data.emplace_back(1);
data.emplace_back(2);
data.emplace_back(3);
std::vector<NonDefaultConstructible> res{};
std::forward_list<NonDefaultConstructible> data{};
data.push_front(NonDefaultConstructible{ 1 });
std::forward_list<NonDefaultConstructible> res{};
res.push_front(NonDefaultConstructible{ 21 });
res.push_front(NonDefaultConstructible{ 14 });
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
EXPECT_THAT(res, ContainerEq(data));
}
//this test is here, because when object is not constructible we cannot simple "resize" container
TEST(DeserializeNonDefaultConstructible, ResultContainerShouldShrink) {
auto resIt = res.begin();
for (auto it = data.begin(); it != data.end(); ++it, ++resIt) {
EXPECT_THAT(*resIt, Eq(*it));
}
EXPECT_THAT(resIt, Eq(res.end()));
}
{
// 1) when result should have 0 elements
SerializationContext ctx{};
std::vector<NonDefaultConstructible> data{};
data.emplace_back(1);
std::vector<NonDefaultConstructible> res{};
res.emplace_back(2);
res.emplace_back(3);
res.emplace_back(4);
std::forward_list<NonDefaultConstructible> data{};
std::forward_list<NonDefaultConstructible> res{};
res.push_front(NonDefaultConstructible{ 1 });
res.push_front(NonDefaultConstructible{ 14 });
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
EXPECT_THAT(res, ContainerEq(data));
}
EXPECT_THAT(res.begin(), Eq(res.end()));
}
TEST(DeserializeNonDefaultConstructible, ResultStdForwardListShouldShrink) {
// forward list doesn't have .erase function, bet has erase_after
// in this case, if new size is 0 it must call clear, so we need to check two cases
{
// 1) when result should have more than 0 elements
SerializationContext ctx{};
std::forward_list<NonDefaultConstructible> data{};
data.push_front(NonDefaultConstructible{1});
std::forward_list<NonDefaultConstructible> res{};
res.push_front(NonDefaultConstructible{21});
res.push_front(NonDefaultConstructible{14});
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
auto resIt = res.begin();
for (auto it = data.begin(); it != data.end(); ++it, ++resIt) {
EXPECT_THAT(*resIt, Eq(*it));
}
EXPECT_THAT(resIt, Eq(res.end()));
}
{
// 1) when result should have 0 elements
SerializationContext ctx{};
std::forward_list<NonDefaultConstructible> data{};
std::forward_list<NonDefaultConstructible> res{};
res.push_front(NonDefaultConstructible{1});
res.push_front(NonDefaultConstructible{14});
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
EXPECT_THAT(res.begin(), Eq(res.end()));
}
{
// also check if correctly expands if source is bigger than destination
SerializationContext ctx{};
std::forward_list<NonDefaultConstructible> data{};
data.push_front(NonDefaultConstructible{1});
data.push_front(NonDefaultConstructible{14});
std::forward_list<NonDefaultConstructible> res{};
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
auto resIt = res.begin();
for (auto it = data.begin(); it != data.end(); ++it, ++resIt) {
EXPECT_THAT(*resIt, Eq(*it));
}
EXPECT_THAT(resIt, Eq(res.end()));
}
}
TEST(DeserializeNonDefaultConstructible, StdSet) {
{
// also check if correctly expands if source is bigger than destination
SerializationContext ctx{};
std::set<NonDefaultConstructible> data;
data.insert(NonDefaultConstructible{1});
data.insert(NonDefaultConstructible{2});
std::set<NonDefaultConstructible> res{};
data.insert(NonDefaultConstructible{3});
std::forward_list<NonDefaultConstructible> data{};
data.push_front(NonDefaultConstructible{ 1 });
data.push_front(NonDefaultConstructible{ 14 });
std::forward_list<NonDefaultConstructible> res{};
ctx.createSerializer().ext(data, bitsery::ext::StdSet{10});
ctx.createDeserializer().ext(res, bitsery::ext::StdSet{10});
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
EXPECT_THAT(res, ContainerEq(data));
auto resIt = res.begin();
for (auto it = data.begin(); it != data.end(); ++it, ++resIt) {
EXPECT_THAT(*resIt, Eq(*it));
}
EXPECT_THAT(resIt, Eq(res.end()));
}
}
TEST(DeserializeNonDefaultConstructible, StdMap) {
SerializationContext ctx{};
std::unordered_map<NonDefaultConstructible, NonDefaultConstructible, HasherForNonDefaultConstructible> data;
data.emplace(NonDefaultConstructible{2}, NonDefaultConstructible{3});
TEST(DeserializeNonDefaultConstructible, StdSet)
{
SerializationContext ctx{};
std::set<NonDefaultConstructible> data;
data.insert(NonDefaultConstructible{ 1 });
data.insert(NonDefaultConstructible{ 2 });
std::set<NonDefaultConstructible> res{};
data.insert(NonDefaultConstructible{ 3 });
std::unordered_map<NonDefaultConstructible, NonDefaultConstructible, HasherForNonDefaultConstructible> res{};
data.emplace(NonDefaultConstructible{2}, NonDefaultConstructible{3});
data.emplace(NonDefaultConstructible{4}, NonDefaultConstructible{4});
ctx.createSerializer().ext(data, bitsery::ext::StdSet{ 10 });
ctx.createDeserializer().ext(res, bitsery::ext::StdSet{ 10 });
auto& ser = ctx.createSerializer();
ser.ext(data, bitsery::ext::StdMap{10},[](decltype(ser)& ser, NonDefaultConstructible& key, NonDefaultConstructible& value) {
ser.object(key);
ser.object(value);
});
auto& des = ctx.createDeserializer();
des.ext(res, bitsery::ext::StdMap{10},[](decltype(des)& des, NonDefaultConstructible& key, NonDefaultConstructible& value) {
des.object(key);
des.object(value);
});
EXPECT_THAT(res, ContainerEq(data));
EXPECT_THAT(res, ContainerEq(data));
}
TEST(DeserializeNonDefaultConstructible, StdMap)
{
SerializationContext ctx{};
std::unordered_map<NonDefaultConstructible,
NonDefaultConstructible,
HasherForNonDefaultConstructible>
data;
data.emplace(NonDefaultConstructible{ 2 }, NonDefaultConstructible{ 3 });
struct NonPolymorphicPointers {
NonDefaultConstructible* pp;
std::unique_ptr<NonDefaultConstructible> up;
std::shared_ptr<NonDefaultConstructible> sp;
std::weak_ptr<NonDefaultConstructible> wp;
std::unordered_map<NonDefaultConstructible,
NonDefaultConstructible,
HasherForNonDefaultConstructible>
res{};
data.emplace(NonDefaultConstructible{ 2 }, NonDefaultConstructible{ 3 });
data.emplace(NonDefaultConstructible{ 4 }, NonDefaultConstructible{ 4 });
auto& ser = ctx.createSerializer();
ser.ext(data,
bitsery::ext::StdMap{ 10 },
[](decltype(ser)& ser,
NonDefaultConstructible& key,
NonDefaultConstructible& value) {
ser.object(key);
ser.object(value);
});
auto& des = ctx.createDeserializer();
des.ext(res,
bitsery::ext::StdMap{ 10 },
[](decltype(des)& des,
NonDefaultConstructible& key,
NonDefaultConstructible& value) {
des.object(key);
des.object(value);
});
EXPECT_THAT(res, ContainerEq(data));
}
struct NonPolymorphicPointers
{
NonDefaultConstructible* pp;
std::unique_ptr<NonDefaultConstructible> up;
std::shared_ptr<NonDefaultConstructible> sp;
std::weak_ptr<NonDefaultConstructible> wp;
};
template <typename S>
void serialize(S& s, NonPolymorphicPointers& o) {
s.ext(o.pp, bitsery::ext::PointerOwner{});
s.ext(o.up, bitsery::ext::StdSmartPtr{});
s.ext(o.sp, bitsery::ext::StdSmartPtr{});
s.ext(o.wp, bitsery::ext::StdSmartPtr{});
template<typename S>
void
serialize(S& s, NonPolymorphicPointers& o)
{
s.ext(o.pp, bitsery::ext::PointerOwner{});
s.ext(o.up, bitsery::ext::StdSmartPtr{});
s.ext(o.sp, bitsery::ext::StdSmartPtr{});
s.ext(o.wp, bitsery::ext::StdSmartPtr{});
}
TEST(DeserializeNonDefaultConstructible, NonPolymorphicPointerAndSmartPointer) {
using SerContext = BasicSerializationContext<bitsery::ext::PointerLinkingContext>;
SerContext ctx{};
NonPolymorphicPointers data{};
data.pp = new NonDefaultConstructible{3};
data.up = std::unique_ptr<NonDefaultConstructible>(new NonDefaultConstructible{54});
data.sp = std::shared_ptr<NonDefaultConstructible>(new NonDefaultConstructible{-481});
data.wp = data.sp;
TEST(DeserializeNonDefaultConstructible, NonPolymorphicPointerAndSmartPointer)
{
using SerContext =
BasicSerializationContext<bitsery::ext::PointerLinkingContext>;
SerContext ctx{};
NonPolymorphicPointers data{};
data.pp = new NonDefaultConstructible{ 3 };
data.up =
std::unique_ptr<NonDefaultConstructible>(new NonDefaultConstructible{ 54 });
data.sp = std::shared_ptr<NonDefaultConstructible>(
new NonDefaultConstructible{ -481 });
data.wp = data.sp;
NonPolymorphicPointers res{};
bitsery::ext::PointerLinkingContext plctx1{};
ctx.createSerializer(plctx1).object(data);
ctx.createDeserializer(plctx1).object(res);
NonPolymorphicPointers res{};
bitsery::ext::PointerLinkingContext plctx1{};
ctx.createSerializer(plctx1).object(data);
ctx.createDeserializer(plctx1).object(res);
EXPECT_THAT(*res.pp, Eq(*data.pp));
delete res.pp;
delete data.pp;
EXPECT_THAT(*res.up, Eq(*data.up));
EXPECT_THAT(*res.sp, Eq(*data.sp));
EXPECT_THAT(*(res.wp.lock()), Eq(*(data.wp.lock())));
EXPECT_THAT(*res.pp, Eq(*data.pp));
delete res.pp;
delete data.pp;
EXPECT_THAT(*res.up, Eq(*data.up));
EXPECT_THAT(*res.sp, Eq(*data.sp));
EXPECT_THAT(*(res.wp.lock()), Eq(*(data.wp.lock())));
}
class PolymorphicNDCBase {
class PolymorphicNDCBase
{
public:
virtual ~PolymorphicNDCBase() = 0;
template <typename S>
void serialize(S& ) {}
virtual ~PolymorphicNDCBase() = 0;
template<typename S>
void serialize(S&)
{
}
};
PolymorphicNDCBase::~PolymorphicNDCBase() = default;
class PolymorphicNDC1:public PolymorphicNDCBase {
int8_t i{};
friend class bitsery::Access;
class PolymorphicNDC1 : public PolymorphicNDCBase
{
int8_t i{};
friend class bitsery::Access;
template<typename S>
void serialize(S& s)
{
s.value1b(i);
}
template <typename S>
void serialize(S& s) {
s.value1b(i);
}
public:
PolymorphicNDC1() = default;
PolymorphicNDC1(int8_t v):i{v} {}
bool operator == (const PolymorphicNDC1& other) const {
return i == other.i;
}
PolymorphicNDC1() = default;
PolymorphicNDC1(int8_t v)
: i{ v }
{
}
bool operator==(const PolymorphicNDC1& other) const { return i == other.i; }
};
class PolymorphicNDC2:public PolymorphicNDCBase {
uint16_t ui{};
class PolymorphicNDC2 : public PolymorphicNDCBase
{
uint16_t ui{};
friend class bitsery::Access;
friend class bitsery::Access;
template<typename S>
void serialize(S& s)
{
s.value2b(ui);
}
template <typename S>
void serialize(S& s) {
s.value2b(ui);
}
public:
PolymorphicNDC2() = default;
PolymorphicNDC2(uint16_t v):ui{v} {}
bool operator == (const PolymorphicNDC2& other) const {
return ui == other.ui;
}
PolymorphicNDC2() = default;
PolymorphicNDC2(uint16_t v)
: ui{ v }
{
}
bool operator==(const PolymorphicNDC2& other) const { return ui == other.ui; }
};
namespace bitsery {
namespace ext {
namespace ext {
template<>
struct PolymorphicBaseClass<PolymorphicNDCBase> : PolymorphicDerivedClasses<PolymorphicNDC1, PolymorphicNDC2> {
};
}
template<>
struct PolymorphicBaseClass<PolymorphicNDCBase>
: PolymorphicDerivedClasses<PolymorphicNDC1, PolymorphicNDC2>
{
};
}
}
struct PolymorphicPointers {
PolymorphicNDCBase* pp;
std::unique_ptr<PolymorphicNDCBase> up;
std::shared_ptr<PolymorphicNDCBase> sp;
std::weak_ptr<PolymorphicNDCBase> wp;
struct PolymorphicPointers
{
PolymorphicNDCBase* pp;
std::unique_ptr<PolymorphicNDCBase> up;
std::shared_ptr<PolymorphicNDCBase> sp;
std::weak_ptr<PolymorphicNDCBase> wp;
};
template <typename S>
void serialize(S& s, PolymorphicPointers& o) {
s.ext(o.pp, bitsery::ext::PointerOwner{});
s.ext(o.up, bitsery::ext::StdSmartPtr{});
s.ext(o.sp, bitsery::ext::StdSmartPtr{});
s.ext(o.wp, bitsery::ext::StdSmartPtr{});
template<typename S>
void
serialize(S& s, PolymorphicPointers& o)
{
s.ext(o.pp, bitsery::ext::PointerOwner{});
s.ext(o.up, bitsery::ext::StdSmartPtr{});
s.ext(o.sp, bitsery::ext::StdSmartPtr{});
s.ext(o.wp, bitsery::ext::StdSmartPtr{});
}
TEST(DeserializeNonDefaultConstructible, PolymorphicPointerAndSmartPointer) {
using TContext = std::tuple<bitsery::ext::PointerLinkingContext, bitsery::ext::PolymorphicContext<bitsery::ext::StandardRTTI>>;
using SerContext = BasicSerializationContext<TContext>;
SerContext ctx{};
PolymorphicPointers data{};
data.pp = new PolymorphicNDC1{-4};
data.up = std::unique_ptr<PolymorphicNDCBase>(new PolymorphicNDC2{54});
data.sp = std::shared_ptr<PolymorphicNDCBase>(new PolymorphicNDC1{15});
data.wp = data.sp;
TEST(DeserializeNonDefaultConstructible, PolymorphicPointerAndSmartPointer)
{
using TContext =
std::tuple<bitsery::ext::PointerLinkingContext,
bitsery::ext::PolymorphicContext<bitsery::ext::StandardRTTI>>;
using SerContext = BasicSerializationContext<TContext>;
SerContext ctx{};
PolymorphicPointers data{};
data.pp = new PolymorphicNDC1{ -4 };
data.up = std::unique_ptr<PolymorphicNDCBase>(new PolymorphicNDC2{ 54 });
data.sp = std::shared_ptr<PolymorphicNDCBase>(new PolymorphicNDC1{ 15 });
data.wp = data.sp;
PolymorphicPointers res{};
PolymorphicPointers res{};
TContext serCtx{};
TContext desCtx{};
TContext serCtx{};
TContext desCtx{};
std::get<1>(serCtx).registerBasesList<typename SerContext::TSerializer>(bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
std::get<1>(desCtx).registerBasesList<typename SerContext::TDeserializer>(bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
std::get<1>(serCtx).registerBasesList<typename SerContext::TSerializer>(
bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
std::get<1>(desCtx).registerBasesList<typename SerContext::TDeserializer>(
bitsery::ext::PolymorphicClassesList<PolymorphicNDCBase>{});
ctx.createSerializer(serCtx).object(data);
ctx.createDeserializer(desCtx).object(res);
auto respp = dynamic_cast<PolymorphicNDC1*>(res.pp);
auto resup = dynamic_cast<PolymorphicNDC2*>(res.up.get());
auto ressp = dynamic_cast<PolymorphicNDC1*>(res.sp.get());
auto reswp = dynamic_cast<PolymorphicNDC1*>(res.wp.lock().get());
ctx.createSerializer(serCtx).object(data);
ctx.createDeserializer(desCtx).object(res);
auto respp = dynamic_cast<PolymorphicNDC1*>(res.pp);
auto resup = dynamic_cast<PolymorphicNDC2*>(res.up.get());
auto ressp = dynamic_cast<PolymorphicNDC1*>(res.sp.get());
auto reswp = dynamic_cast<PolymorphicNDC1*>(res.wp.lock().get());
auto datapp = dynamic_cast<PolymorphicNDC1*>(data.pp);
auto dataup = dynamic_cast<PolymorphicNDC2*>(data.up.get());
auto datasp = dynamic_cast<PolymorphicNDC1*>(data.sp.get());
auto datawp = dynamic_cast<PolymorphicNDC1*>(data.wp.lock().get());
auto datapp = dynamic_cast<PolymorphicNDC1*>(data.pp);
auto dataup = dynamic_cast<PolymorphicNDC2*>(data.up.get());
auto datasp = dynamic_cast<PolymorphicNDC1*>(data.sp.get());
auto datawp = dynamic_cast<PolymorphicNDC1*>(data.wp.lock().get());
EXPECT_THAT(respp, ::testing::Ne(nullptr));
EXPECT_THAT(resup, ::testing::Ne(nullptr));
EXPECT_THAT(ressp, ::testing::Ne(nullptr));
EXPECT_THAT(reswp, ::testing::Ne(nullptr));
EXPECT_THAT(respp, ::testing::Ne(nullptr));
EXPECT_THAT(resup, ::testing::Ne(nullptr));
EXPECT_THAT(ressp, ::testing::Ne(nullptr));
EXPECT_THAT(reswp, ::testing::Ne(nullptr));
EXPECT_THAT(*respp, Eq(*datapp));
delete res.pp;
delete data.pp;
EXPECT_THAT(*resup, Eq(*dataup));
EXPECT_THAT(*ressp, Eq(*datasp));
EXPECT_THAT(*reswp, Eq(*datawp));
std::get<0>(serCtx).clearSharedState();
std::get<0>(desCtx).clearSharedState();
EXPECT_THAT(*respp, Eq(*datapp));
delete res.pp;
delete data.pp;
EXPECT_THAT(*resup, Eq(*dataup));
EXPECT_THAT(*ressp, Eq(*datasp));
EXPECT_THAT(*reswp, Eq(*datawp));
std::get<0>(serCtx).clearSharedState();
std::get<0>(desCtx).clearSharedState();
}

View File

@@ -1,48 +1,48 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::Eq;
TEST(Serialization, AdapterCanBeMovedInAndOut) {
Buffer buf{};
bitsery::Serializer<Writer> ser1{buf};
ser1.object(MyStruct1{1, 2});
auto writeAdapter = std::move(ser1).adapter();
bitsery::Serializer<Writer> ser2(std::move(writeAdapter));
ser2.object(MyStruct1{3, 4});
auto writtenBytesCount = ser2.adapter().writtenBytesCount();
EXPECT_THAT(writtenBytesCount, Eq(MyStruct1::SIZE + MyStruct1::SIZE));
TEST(Serialization, AdapterCanBeMovedInAndOut)
{
Buffer buf{};
bitsery::Serializer<Writer> ser1{ buf };
ser1.object(MyStruct1{ 1, 2 });
auto writeAdapter = std::move(ser1).adapter();
bitsery::Serializer<Writer> ser2(std::move(writeAdapter));
ser2.object(MyStruct1{ 3, 4 });
auto writtenBytesCount = ser2.adapter().writtenBytesCount();
EXPECT_THAT(writtenBytesCount, Eq(MyStruct1::SIZE + MyStruct1::SIZE));
MyStruct1 res{};
bitsery::Deserializer<Reader> des1{buf.begin(), writtenBytesCount};
des1.object(res);
EXPECT_THAT(res, Eq(MyStruct1{1, 2}));
auto readerAdapter = std::move(des1).adapter();
bitsery::Deserializer<Reader> des2(std::move(readerAdapter));
des2.object(res);
EXPECT_THAT(res, Eq(MyStruct1{3, 4}));
EXPECT_TRUE(des2.adapter().isCompletedSuccessfully());
MyStruct1 res{};
bitsery::Deserializer<Reader> des1{ buf.begin(), writtenBytesCount };
des1.object(res);
EXPECT_THAT(res, Eq(MyStruct1{ 1, 2 }));
auto readerAdapter = std::move(des1).adapter();
bitsery::Deserializer<Reader> des2(std::move(readerAdapter));
des2.object(res);
EXPECT_THAT(res, Eq(MyStruct1{ 3, 4 }));
EXPECT_TRUE(des2.adapter().isCompletedSuccessfully());
}

View File

@@ -1,83 +1,88 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::Eq;
TEST(SerializeBooleans, BoolAsBit)
{
TEST(SerializeBooleans, BoolAsBit) {
SerializationContext ctx{};
bool t1{true};
bool t2{false};
bool res1;
bool res2;
auto& ser = ctx.createSerializer();
ser.enableBitPacking([&t1, &t2](SerializationContext::TSerializerBPEnabled& sbp) {
sbp.boolValue(t1);
sbp.boolValue(t2);
SerializationContext ctx{};
bool t1{ true };
bool t2{ false };
bool res1;
bool res2;
auto& ser = ctx.createSerializer();
ser.enableBitPacking(
[&t1, &t2](SerializationContext::TSerializerBPEnabled& sbp) {
sbp.boolValue(t1);
sbp.boolValue(t2);
});
auto& des = ctx.createDeserializer();
des.enableBitPacking([&res1, &res2](SerializationContext::TDeserializerBPEnabled& sbp) {
sbp.boolValue(res1);
sbp.boolValue(res2);
auto& des = ctx.createDeserializer();
des.enableBitPacking(
[&res1, &res2](SerializationContext::TDeserializerBPEnabled& sbp) {
sbp.boolValue(res1);
sbp.boolValue(res2);
});
EXPECT_THAT(res1, Eq(t1));
EXPECT_THAT(res2, Eq(t2));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(res1, Eq(t1));
EXPECT_THAT(res2, Eq(t2));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
}
TEST(SerializeBooleans, BoolAsByte) {
SerializationContext ctx;
bool t1{true};
bool t2{false};
bool res1;
bool res2;
auto& ser = ctx.createSerializer();
ser.boolValue(t1);
ser.boolValue(t2);
auto& des = ctx.createDeserializer();
des.boolValue(res1);
des.boolValue(res2);
TEST(SerializeBooleans, BoolAsByte)
{
SerializationContext ctx;
bool t1{ true };
bool t2{ false };
bool res1;
bool res2;
auto& ser = ctx.createSerializer();
ser.boolValue(t1);
ser.boolValue(t2);
auto& des = ctx.createDeserializer();
des.boolValue(res1);
des.boolValue(res2);
EXPECT_THAT(res1, Eq(t1));
EXPECT_THAT(res2, Eq(t2));
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
EXPECT_THAT(res1, Eq(t1));
EXPECT_THAT(res2, Eq(t2));
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
}
TEST(SerializeBooleans, WhenReadingBoolByteReadsMoreThanOneThenInvalidDataErrorAndResultIsFalse) {
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.value1b(uint8_t{1});
ser.value1b(uint8_t{2});
bool res{};
auto& des = ctx.createDeserializer();
des.boolValue(res);
EXPECT_THAT(res, Eq(true));
des.boolValue(res);
EXPECT_THAT(res, Eq(false));
EXPECT_THAT(ctx.des->adapter().error(), Eq(bitsery::ReaderError::InvalidData));
TEST(SerializeBooleans,
WhenReadingBoolByteReadsMoreThanOneThenInvalidDataErrorAndResultIsFalse)
{
SerializationContext ctx;
auto& ser = ctx.createSerializer();
ser.value1b(uint8_t{ 1 });
ser.value1b(uint8_t{ 2 });
bool res{};
auto& des = ctx.createDeserializer();
des.boolValue(res);
EXPECT_THAT(res, Eq(true));
des.boolValue(res);
EXPECT_THAT(res, Eq(false));
EXPECT_THAT(ctx.des->adapter().error(),
Eq(bitsery::ReaderError::InvalidData));
}

View File

@@ -1,74 +1,68 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <bitsery/traits/array.h>
#include <bitsery/traits/list.h>
#include <bitsery/traits/deque.h>
#include <bitsery/traits/forward_list.h>
#include <bitsery/traits/list.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::ContainerEq;
using testing::Eq;
/*
* overload to get container of types
*/
template<typename Container>
Container getFilledContainer() {
return {1, 2, 3, 4, 5, 78, 456, 8, 54};
Container
getFilledContainer()
{
return { 1, 2, 3, 4, 5, 78, 456, 8, 54 };
}
template<>
std::vector<MyStruct1> getFilledContainer<std::vector<MyStruct1>>() {
return {
{0, 1},
{2, 3},
{4, 5},
{6, 7},
{8, 9},
{11, 34},
{5134, 1532}
};
std::vector<MyStruct1>
getFilledContainer<std::vector<MyStruct1>>()
{
return { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 },
{ 8, 9 }, { 11, 34 }, { 5134, 1532 } };
}
template<>
std::list<MyStruct2> getFilledContainer<std::list<MyStruct2>>() {
return {
{MyStruct2::V1, {0, 1}},
{MyStruct2::V3, {-45, 45}}
};
std::list<MyStruct2>
getFilledContainer<std::list<MyStruct2>>()
{
return { { MyStruct2::V1, { 0, 1 } }, { MyStruct2::V3, { -45, 45 } } };
}
struct EmptyFtor {
template <typename S, typename T>
void operator() (S& , T& ) {
}
struct EmptyFtor
{
template<typename S, typename T>
void operator()(S&, T&)
{
}
};
/*
@@ -76,197 +70,228 @@ struct EmptyFtor {
*/
template<typename T>
class SerializeContainerDynamicSizeArthmeticTypes : public testing::Test {
class SerializeContainerDynamicSizeArthmeticTypes : public testing::Test
{
public:
using TContainer = T;
using TValue = typename T::value_type;
using TContainer = T;
using TValue = typename T::value_type;
const TContainer src = getFilledContainer<TContainer>();
TContainer res{};
const TContainer src = getFilledContainer<TContainer>();
TContainer res{};
size_t getExpectedBufSize(const SerializationContext &ctx) const {
auto size = bitsery::traits::ContainerTraits<TContainer>::size(src);
return ctx.containerSizeSerializedBytesCount(size) + size * sizeof(TValue);
}
size_t getExpectedBufSize(const SerializationContext& ctx) const
{
auto size = bitsery::traits::ContainerTraits<TContainer>::size(src);
return ctx.containerSizeSerializedBytesCount(size) + size * sizeof(TValue);
}
};
//std::forward_list is not supported, because it doesn't have size() method
using SequenceContainersWithArthmeticTypes = ::testing::Types<
std::vector<int>,
std::list<float>,
std::forward_list<int>,
std::deque<unsigned short>>;
// std::forward_list is not supported, because it doesn't have size() method
using SequenceContainersWithArthmeticTypes =
::testing::Types<std::vector<int>,
std::list<float>,
std::forward_list<int>,
std::deque<unsigned short>>;
TYPED_TEST_SUITE(SerializeContainerDynamicSizeArthmeticTypes, SequenceContainersWithArthmeticTypes,);
TYPED_TEST_SUITE(SerializeContainerDynamicSizeArthmeticTypes,
SequenceContainersWithArthmeticTypes, );
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, Values) {
SerializationContext ctx{};
using TValue = typename TestFixture::TValue;
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, Values)
{
SerializationContext ctx{};
using TValue = typename TestFixture::TValue;
ctx.createSerializer().container<sizeof(TValue)>(this->src, 1000);
ctx.createDeserializer().container<sizeof(TValue)>(this->res, 1000);
ctx.createSerializer().container<sizeof(TValue)>(this->src, 1000);
ctx.createDeserializer().container<sizeof(TValue)>(this->res, 1000);
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
}
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, CustomFunctionIncrements) {
SerializationContext ctx{};
using TValue = typename TestFixture::TValue;
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes,
CustomFunctionIncrements)
{
SerializationContext ctx{};
using TValue = typename TestFixture::TValue;
auto& ser = ctx.createSerializer();
ser.container(this->src, 1000, [](decltype(ser)& ser, TValue& v) {
ser.template value<sizeof(v)>(v);
});
auto& des = ctx.createDeserializer();
des.container(this->res, 1000, [](decltype(des)& des, TValue &v) {
des.template value<sizeof(v)>(v);
//increment by 1 after reading
v++;
});
//decrement result by 1, before comparing for eq
for (auto &v:this->res)
v = static_cast<TValue>(v-1);
auto& ser = ctx.createSerializer();
ser.container(this->src, 1000, [](decltype(ser)& ser, TValue& v) {
ser.template value<sizeof(v)>(v);
});
auto& des = ctx.createDeserializer();
des.container(this->res, 1000, [](decltype(des)& des, TValue& v) {
des.template value<sizeof(v)>(v);
// increment by 1 after reading
v++;
});
// decrement result by 1, before comparing for eq
for (auto& v : this->res)
v = static_cast<TValue>(v - 1);
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
}
template<typename T>
class SerializeContainerDynamicSizeCompositeTypes : public testing::Test {
public:
using TContainer = T;
using TValue = typename T::value_type;
const TContainer src = getFilledContainer<TContainer>();
TContainer res{};
size_t getExpectedBufSize(const SerializationContext &ctx) const {
return ctx.containerSizeSerializedBytesCount(src.size()) + src.size() * TValue::SIZE;
}
};
using SerializeContainerDynamicSizeWithCompositeTypes = ::testing::Types<
std::vector<MyStruct1>,
std::list<MyStruct2>>;
TYPED_TEST_SUITE(SerializeContainerDynamicSizeCompositeTypes, SerializeContainerDynamicSizeWithCompositeTypes,);
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes, DefaultSerializeFunction) {
SerializationContext ctx{};
ctx.createSerializer().container(this->src, 1000);
ctx.createDeserializer().container(this->res, 1000);
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
}
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes, CustomFunctionThatDoNothing) {
SerializationContext ctx{};
ctx.createSerializer().container(this->src, 1000, EmptyFtor{});
ctx.createDeserializer().container(this->res, 1000, EmptyFtor{});
EXPECT_THAT(ctx.getBufferSize(), Eq(ctx.containerSizeSerializedBytesCount(this->src.size())));
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
}
template<typename T>
class SerializeContainerFixedSizeArithmeticTypes : public testing::Test {
class SerializeContainerDynamicSizeCompositeTypes : public testing::Test
{
public:
using TContainer = T;
using TContainer = T;
using TValue = typename T::value_type;
size_t getContainerSize() {
T tmp{};
return static_cast<size_t>(std::distance(std::begin(tmp), std::end(tmp)));
}
const TContainer src = getFilledContainer<TContainer>();
TContainer res{};
size_t getExpectedBufSize(const SerializationContext& ctx) const
{
return ctx.containerSizeSerializedBytesCount(src.size()) +
src.size() * TValue::SIZE;
}
};
using StaticContainersWithIntegralTypes = ::testing::Types<
std::array<int16_t, 4>,
int16_t[4]>;
using SerializeContainerDynamicSizeWithCompositeTypes =
::testing::Types<std::vector<MyStruct1>, std::list<MyStruct2>>;
TYPED_TEST_SUITE(SerializeContainerFixedSizeArithmeticTypes, StaticContainersWithIntegralTypes,);
TYPED_TEST_SUITE(SerializeContainerDynamicSizeCompositeTypes,
SerializeContainerDynamicSizeWithCompositeTypes, );
TYPED_TEST(SerializeContainerFixedSizeArithmeticTypes, ArithmeticValues) {
using Container = typename TestFixture::TContainer;
Container src{5, 9, 15, -459};
Container res{};
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes,
DefaultSerializeFunction)
{
SerializationContext ctx{};
SerializationContext ctx;
ctx.createSerializer().container<2>(src);
ctx.createDeserializer().container<2>(res);
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * 2));
EXPECT_THAT(res, ContainerEq(src));
ctx.createSerializer().container(this->src, 1000);
ctx.createDeserializer().container(this->res, 1000);
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx)));
EXPECT_THAT(this->res, ContainerEq(this->src));
}
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes,
CustomFunctionThatDoNothing)
{
SerializationContext ctx{};
ctx.createSerializer().container(this->src, 1000, EmptyFtor{});
ctx.createDeserializer().container(this->res, 1000, EmptyFtor{});
EXPECT_THAT(ctx.getBufferSize(),
Eq(ctx.containerSizeSerializedBytesCount(this->src.size())));
}
template<typename T>
class SerializeContainerFixedSizeCompositeTypes : public SerializeContainerFixedSizeArithmeticTypes<T> {
class SerializeContainerFixedSizeArithmeticTypes : public testing::Test
{
public:
using TContainer = T;
size_t getContainerSize()
{
T tmp{};
return static_cast<size_t>(std::distance(std::begin(tmp), std::end(tmp)));
}
};
using StaticContainersWithCompositeTypes = ::testing::Types<
std::array<MyStruct1, 4>, MyStruct1[4]>;
using StaticContainersWithIntegralTypes =
::testing::Types<std::array<int16_t, 4>, int16_t[4]>;
TYPED_TEST_SUITE(SerializeContainerFixedSizeCompositeTypes, StaticContainersWithCompositeTypes,);
TYPED_TEST_SUITE(SerializeContainerFixedSizeArithmeticTypes,
StaticContainersWithIntegralTypes, );
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, DefaultSerializationFunction) {
using Container = typename TestFixture::TContainer;
Container src{MyStruct1{0, 1}, MyStruct1{8, 9}, MyStruct1{11, 34}, MyStruct1{5134, 1532}};
Container res{};
TYPED_TEST(SerializeContainerFixedSizeArithmeticTypes, ArithmeticValues)
{
using Container = typename TestFixture::TContainer;
Container src{ 5, 9, 15, -459 };
Container res{};
SerializationContext ctx{};
ctx.createSerializer().container(src);
ctx.createDeserializer().container(res);
SerializationContext ctx;
ctx.createSerializer().container<2>(src);
ctx.createDeserializer().container<2>(res);
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * MyStruct1::SIZE));
EXPECT_THAT(res, ContainerEq(src));
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * 2));
EXPECT_THAT(res, ContainerEq(src));
}
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, CustomFunctionThatSerializesAnEmptyByteEveryElement) {
using Container = typename TestFixture::TContainer;
Container src{MyStruct1{0, 1}, MyStruct1{2, 3}, MyStruct1{4, 5}, MyStruct1{5134, 1532}};
Container res{};
using TValue = decltype(*std::begin(res));
SerializationContext ctx{};
auto& ser = ctx.createSerializer();
ser.container(src, [](decltype(ser)& ser, TValue &v) {
char tmp{};
ser.object(v);
ser.value1b(tmp);
});
auto& des = ctx.createDeserializer();
des.container(res, [](decltype(des)& des, TValue &v) {
char tmp{};
des.object(v);
des.value1b(tmp);
});
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * (MyStruct1::SIZE + sizeof(char))));
EXPECT_THAT(res, ContainerEq(src));
}
class SerializeContainer : public ::testing::TestWithParam<size_t> {
template<typename T>
class SerializeContainerFixedSizeCompositeTypes
: public SerializeContainerFixedSizeArithmeticTypes<T>
{
};
TEST_P(SerializeContainer, SizeHasVariableLength) {
SerializationContext ctx{};
using StaticContainersWithCompositeTypes =
::testing::Types<std::array<MyStruct1, 4>, MyStruct1[4]>;
std::vector<uint8_t > src(GetParam());
std::vector<uint8_t > res{};
ctx.createSerializer().container(src, std::numeric_limits<size_t>::max(), EmptyFtor{});
ctx.createDeserializer().container(res, std::numeric_limits<size_t>::max(), EmptyFtor{});
TYPED_TEST_SUITE(SerializeContainerFixedSizeCompositeTypes,
StaticContainersWithCompositeTypes, );
EXPECT_THAT(res.size(), Eq(src.size()));
EXPECT_THAT(ctx.getBufferSize(), Eq(ctx.containerSizeSerializedBytesCount(src.size())));
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes,
DefaultSerializationFunction)
{
using Container = typename TestFixture::TContainer;
Container src{ MyStruct1{ 0, 1 },
MyStruct1{ 8, 9 },
MyStruct1{ 11, 34 },
MyStruct1{ 5134, 1532 } };
Container res{};
SerializationContext ctx{};
ctx.createSerializer().container(src);
ctx.createDeserializer().container(res);
EXPECT_THAT(ctx.getBufferSize(),
Eq(this->getContainerSize() * MyStruct1::SIZE));
EXPECT_THAT(res, ContainerEq(src));
}
INSTANTIATE_TEST_SUITE_P(LargeContainerSize, SerializeContainer, ::testing::Values(0x01, 0x80, 0x4000));
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes,
CustomFunctionThatSerializesAnEmptyByteEveryElement)
{
using Container = typename TestFixture::TContainer;
Container src{ MyStruct1{ 0, 1 },
MyStruct1{ 2, 3 },
MyStruct1{ 4, 5 },
MyStruct1{ 5134, 1532 } };
Container res{};
using TValue = decltype(*std::begin(res));
SerializationContext ctx{};
auto& ser = ctx.createSerializer();
ser.container(src, [](decltype(ser)& ser, TValue& v) {
char tmp{};
ser.object(v);
ser.value1b(tmp);
});
auto& des = ctx.createDeserializer();
des.container(res, [](decltype(des)& des, TValue& v) {
char tmp{};
des.object(v);
des.value1b(tmp);
});
EXPECT_THAT(ctx.getBufferSize(),
Eq(this->getContainerSize() * (MyStruct1::SIZE + sizeof(char))));
EXPECT_THAT(res, ContainerEq(src));
}
class SerializeContainer : public ::testing::TestWithParam<size_t>
{};
TEST_P(SerializeContainer, SizeHasVariableLength)
{
SerializationContext ctx{};
std::vector<uint8_t> src(GetParam());
std::vector<uint8_t> res{};
ctx.createSerializer().container(
src, std::numeric_limits<size_t>::max(), EmptyFtor{});
ctx.createDeserializer().container(
res, std::numeric_limits<size_t>::max(), EmptyFtor{});
EXPECT_THAT(res.size(), Eq(src.size()));
EXPECT_THAT(ctx.getBufferSize(),
Eq(ctx.containerSizeSerializedBytesCount(src.size())));
}
INSTANTIATE_TEST_SUITE_P(LargeContainerSize,
SerializeContainer,
::testing::Values(0x01, 0x80, 0x4000));

View File

@@ -1,28 +1,27 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using testing::Eq;
@@ -31,78 +30,89 @@ using bitsery::DefaultConfig;
using SingleTypeContext = int;
using MultipleTypesContext = std::tuple<int, float, char>;
TEST(SerializationContext, WhenContextIsNotTupleThenReturnThisContext) {
SingleTypeContext ctx{54};
BasicSerializationContext<SingleTypeContext> c1;
auto& ser1 = c1.createSerializer(ctx);
TEST(SerializationContext, WhenContextIsNotTupleThenReturnThisContext)
{
SingleTypeContext ctx{ 54 };
BasicSerializationContext<SingleTypeContext> c1;
auto& ser1 = c1.createSerializer(ctx);
EXPECT_THAT(ser1.context<SingleTypeContext>(), Eq(ctx));
EXPECT_THAT(ser1.context<SingleTypeContext>(), Eq(ctx));
}
TEST(SerializationContext, WhenContextIsTupleThenReturnsTupleElements) {
TEST(SerializationContext, WhenContextIsTupleThenReturnsTupleElements)
{
MultipleTypesContext ctx{5, 798.654f, 'F'};
BasicSerializationContext<MultipleTypesContext> c1;
auto& ser1 = c1.createSerializer(ctx);
MultipleTypesContext ctx{ 5, 798.654f, 'F' };
BasicSerializationContext<MultipleTypesContext> c1;
auto& ser1 = c1.createSerializer(ctx);
EXPECT_THAT(ser1.context<int>(), std::get<0>(ctx));
EXPECT_THAT(ser1.context<float>(), std::get<1>(ctx));
EXPECT_THAT(ser1.context<char>(), std::get<2>(ctx));
EXPECT_THAT(ser1.context<int>(), std::get<0>(ctx));
EXPECT_THAT(ser1.context<float>(), std::get<1>(ctx));
EXPECT_THAT(ser1.context<char>(), std::get<2>(ctx));
}
TEST(SerializationContext, WhenContextDoesntExistsThenContextOrNullReturnsNull) {
SingleTypeContext ctx1= 32;
BasicSerializationContext<SingleTypeContext> c1;
TEST(SerializationContext, WhenContextDoesntExistsThenContextOrNullReturnsNull)
{
SingleTypeContext ctx1 = 32;
BasicSerializationContext<SingleTypeContext> c1;
auto& ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.contextOrNull<char>(), ::testing::IsNull());
EXPECT_THAT(ser.contextOrNull<int>(), ::testing::NotNull());
*ser.contextOrNull<int>() = 2;
EXPECT_THAT(ctx1, Eq(2));
MultipleTypesContext ctx2{ 5, 798.654f, 'F' };
BasicSerializationContext<MultipleTypesContext> c2;
auto& des = c2.createDeserializer(ctx2);
EXPECT_THAT(des.contextOrNull<double>(), ::testing::IsNull());
EXPECT_THAT(des.contextOrNull<int>(), ::testing::NotNull());
EXPECT_THAT(*des.contextOrNull<char>(), Eq('F'));
EXPECT_THAT(*des.contextOrNull<int>(), Eq(5));
}
struct Base
{
int value{};
};
struct Derived : Base
{};
TEST(SerializationContext, ContextWillTryToConvertIfTypeIsConvertible)
{
Derived ctx1{};
BasicSerializationContext<Derived> c1;
auto& ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.contextOrNull<Derived>(), ::testing::NotNull());
EXPECT_THAT(ser.contextOrNull<Base>(), ::testing::NotNull());
ser.context<Derived>();
ser.context<Base>();
}
TEST(SerializationContext,
WhenMultipleConvertibleTypesExistsThenFirstMatchIsTaken)
{
{
using CTX1 = std::tuple<Base, int, Derived>;
CTX1 ctx1{};
std::get<0>(ctx1).value = 1;
std::get<2>(ctx1).value = 2;
BasicSerializationContext<CTX1> c1;
auto& ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.contextOrNull<char>(), ::testing::IsNull());
EXPECT_THAT(ser.contextOrNull<int>(), ::testing::NotNull());
*ser.contextOrNull<int>() = 2;
EXPECT_THAT(ctx1, Eq(2));
EXPECT_THAT(ser.context<Derived>().value, Eq(std::get<2>(ctx1).value));
EXPECT_THAT(ser.context<Base>().value, Eq(std::get<0>(ctx1).value));
}
MultipleTypesContext ctx2{5, 798.654f, 'F'};
BasicSerializationContext<MultipleTypesContext> c2;
auto& des = c2.createDeserializer(ctx2);
EXPECT_THAT(des.contextOrNull<double>(), ::testing::IsNull());
EXPECT_THAT(des.contextOrNull<int>(), ::testing::NotNull());
EXPECT_THAT(*des.contextOrNull<char>(), Eq('F'));
EXPECT_THAT(*des.contextOrNull<int>(), Eq(5));
}
struct Base { int value{}; };
struct Derived: Base{};
TEST(SerializationContext, ContextWillTryToConvertIfTypeIsConvertible) {
Derived ctx1{};
BasicSerializationContext<Derived> c1;
auto& ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.contextOrNull<Derived>(), ::testing::NotNull());
EXPECT_THAT(ser.contextOrNull<Base>(), ::testing::NotNull());
ser.context<Derived>();
ser.context<Base>();
}
TEST(SerializationContext, WhenMultipleConvertibleTypesExistsThenFirstMatchIsTaken) {
{
using CTX1 = std::tuple<Base, int, Derived>;
CTX1 ctx1{};
std::get<0>(ctx1).value = 1;
std::get<2>(ctx1).value = 2;
BasicSerializationContext<CTX1> c1;
auto& ser = c1.createSerializer(ctx1);
EXPECT_THAT(ser.context<Derived>().value, Eq(std::get<2>(ctx1).value));
EXPECT_THAT(ser.context<Base>().value, Eq(std::get<0>(ctx1).value));
}
{
using CTX2 = std::tuple<float, Derived, Base>;
CTX2 ctx2{};
std::get<1>(ctx2).value = 1;
std::get<2>(ctx2).value = 2;
BasicSerializationContext<CTX2> c2;
auto& des = c2.createSerializer(ctx2);
EXPECT_THAT(des.context<Derived>().value, Eq(std::get<1>(ctx2).value));
//Base will not be accessable in this case, because Derived is first valid match
EXPECT_THAT(des.context<Base>().value, Eq(std::get<1>(ctx2).value));
}
{
using CTX2 = std::tuple<float, Derived, Base>;
CTX2 ctx2{};
std::get<1>(ctx2).value = 1;
std::get<2>(ctx2).value = 2;
BasicSerializationContext<CTX2> c2;
auto& des = c2.createSerializer(ctx2);
EXPECT_THAT(des.context<Derived>().value, Eq(std::get<1>(ctx2).value));
// Base will not be accessable in this case, because Derived is first valid
// match
EXPECT_THAT(des.context<Base>().value, Eq(std::get<1>(ctx2).value));
}
}

View File

@@ -1,244 +1,276 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "serialization_test_utils.h"
#include <bitsery/ext/compact_value.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <bitsery/traits/array.h>
#include <bitset>
#include <chrono>
using testing::Eq;
using bitsery::EndiannessType;
using bitsery::ext::CompactValue;
using bitsery::ext::CompactValueAsObject;
using bitsery::EndiannessType;
using testing::Eq;
// helper function, that gets value filled with specified number of bits
template <typename TValue>
TValue getValue(bool isPositive, size_t significantBits) {
TValue v = isPositive ? 0 : static_cast<TValue>(-1);
if (significantBits == 0)
return v;
template<typename TValue>
TValue
getValue(bool isPositive, size_t significantBits)
{
TValue v = isPositive ? 0 : static_cast<TValue>(-1);
if (significantBits == 0)
return v;
using TUnsigned = typename std::make_unsigned<TValue>::type;
TUnsigned mask = {};
mask = static_cast<TUnsigned>(~mask); // invert shiftByBits
auto shiftBy = bitsery::details::BitsSize<TValue>::value - significantBits;
mask = static_cast<TUnsigned>(mask >> shiftBy);
//cast to unsigned when applying mask
return v ^ static_cast<TValue>(mask);
using TUnsigned = typename std::make_unsigned<TValue>::type;
TUnsigned mask = {};
mask = static_cast<TUnsigned>(~mask); // invert shiftByBits
auto shiftBy = bitsery::details::BitsSize<TValue>::value - significantBits;
mask = static_cast<TUnsigned>(mask >> shiftBy);
// cast to unsigned when applying mask
return v ^ static_cast<TValue>(mask);
}
// helper function, that serialize and return deserialized value
template <typename TConfig, typename TValue>
std::pair<TValue, size_t> serializeAndGetDeserialized(TValue data) {
Buffer buf{};
bitsery::Serializer<bitsery::OutputBufferAdapter<Buffer, TConfig>> ser{buf};
ser.template ext<sizeof(TValue)>(data, CompactValue{});
template<typename TConfig, typename TValue>
std::pair<TValue, size_t>
serializeAndGetDeserialized(TValue data)
{
Buffer buf{};
bitsery::Serializer<bitsery::OutputBufferAdapter<Buffer, TConfig>> ser{ buf };
ser.template ext<sizeof(TValue)>(data, CompactValue{});
bitsery::Deserializer<bitsery::InputBufferAdapter<Buffer, TConfig>> des{buf.begin(), ser.adapter().writtenBytesCount()};
TValue res;
des.template ext<sizeof(TValue)>(res, CompactValue{});
return {res, ser.adapter().writtenBytesCount()};
bitsery::Deserializer<bitsery::InputBufferAdapter<Buffer, TConfig>> des{
buf.begin(), ser.adapter().writtenBytesCount()
};
TValue res;
des.template ext<sizeof(TValue)>(res, CompactValue{});
return { res, ser.adapter().writtenBytesCount() };
}
struct LittleEndianConfig {
static constexpr EndiannessType Endianness = EndiannessType::LittleEndian;
static constexpr bool CheckDataErrors = true;
static constexpr bool CheckAdapterErrors = true;
struct LittleEndianConfig
{
static constexpr EndiannessType Endianness = EndiannessType::LittleEndian;
static constexpr bool CheckDataErrors = true;
static constexpr bool CheckAdapterErrors = true;
};
struct BigEndianConfig {
static constexpr EndiannessType Endianness = EndiannessType::BigEndian;
static constexpr bool CheckDataErrors = true;
static constexpr bool CheckAdapterErrors = true;
struct BigEndianConfig
{
static constexpr EndiannessType Endianness = EndiannessType::BigEndian;
static constexpr bool CheckDataErrors = true;
static constexpr bool CheckAdapterErrors = true;
};
template <typename TValue, bool isPositiveNr, typename TConfig>
struct TC {
static_assert(isPositiveNr || std::is_signed<TValue>::value, "");
template<typename TValue, bool isPositiveNr, typename TConfig>
struct TC
{
static_assert(isPositiveNr || std::is_signed<TValue>::value, "");
using Value = TValue;
using Config = TConfig;
bool isPositive = isPositiveNr;
using Value = TValue;
using Config = TConfig;
bool isPositive = isPositiveNr;
};
template<typename T>
class SerializeExtensionCompactValueCorrectness : public testing::Test {
class SerializeExtensionCompactValueCorrectness : public testing::Test
{
public:
using TestCase = T;
using TestCase = T;
};
using AllValueSizesTestCases =
::testing::Types<TC<uint8_t, true, LittleEndianConfig>,
TC<uint16_t, true, LittleEndianConfig>,
TC<uint32_t, true, LittleEndianConfig>,
TC<uint64_t, true, LittleEndianConfig>,
TC<int8_t, true, LittleEndianConfig>,
TC<int16_t, true, LittleEndianConfig>,
TC<int32_t, true, LittleEndianConfig>,
TC<int64_t, true, LittleEndianConfig>,
TC<int8_t, false, LittleEndianConfig>,
TC<int16_t, false, LittleEndianConfig>,
TC<int32_t, false, LittleEndianConfig>,
TC<int64_t, false, LittleEndianConfig>,
TC<uint8_t, true, BigEndianConfig>,
TC<uint16_t, true, BigEndianConfig>,
TC<uint32_t, true, BigEndianConfig>,
TC<uint64_t, true, BigEndianConfig>,
TC<int8_t, true, BigEndianConfig>,
TC<int16_t, true, BigEndianConfig>,
TC<int32_t, true, BigEndianConfig>,
TC<int64_t, true, BigEndianConfig>,
TC<int8_t, false, BigEndianConfig>,
TC<int16_t, false, BigEndianConfig>,
TC<int32_t, false, BigEndianConfig>,
TC<int64_t, false, BigEndianConfig>>;
using AllValueSizesTestCases = ::testing::Types<
TC<uint8_t, true, LittleEndianConfig>,
TC<uint16_t, true, LittleEndianConfig>,
TC<uint32_t, true, LittleEndianConfig>,
TC<uint64_t, true, LittleEndianConfig>,
TC<int8_t, true, LittleEndianConfig>,
TC<int16_t, true, LittleEndianConfig>,
TC<int32_t, true, LittleEndianConfig>,
TC<int64_t, true, LittleEndianConfig>,
TC<int8_t, false, LittleEndianConfig>,
TC<int16_t, false, LittleEndianConfig>,
TC<int32_t, false, LittleEndianConfig>,
TC<int64_t, false, LittleEndianConfig>,
TC<uint8_t, true, BigEndianConfig>,
TC<uint16_t, true, BigEndianConfig>,
TC<uint32_t, true, BigEndianConfig>,
TC<uint64_t, true, BigEndianConfig>,
TC<int8_t, true, BigEndianConfig>,
TC<int16_t, true, BigEndianConfig>,
TC<int32_t, true, BigEndianConfig>,
TC<int64_t, true, BigEndianConfig>,
TC<int8_t, false, BigEndianConfig>,
TC<int16_t, false, BigEndianConfig>,
TC<int32_t, false, BigEndianConfig>,
TC<int64_t, false, BigEndianConfig>
>;
TYPED_TEST_SUITE(SerializeExtensionCompactValueCorrectness,
AllValueSizesTestCases, );
TYPED_TEST_SUITE(SerializeExtensionCompactValueCorrectness, AllValueSizesTestCases,);
TYPED_TEST(SerializeExtensionCompactValueCorrectness, TestDifferentSizeValues)
{
using TCase = typename TestFixture::TestCase;
using TValue = typename TCase::Value;
TCase tc{};
TYPED_TEST(SerializeExtensionCompactValueCorrectness, TestDifferentSizeValues) {
using TCase = typename TestFixture::TestCase;
using TValue = typename TCase::Value;
TCase tc{};
for (auto i = 0u; i < bitsery::details::BitsSize<TValue>::value + 1; ++i) {
auto data = getValue<TValue>(tc.isPositive, i);
auto res = serializeAndGetDeserialized<typename TCase::Config>(data);
EXPECT_THAT(res.first, Eq(data));
}
for (auto i = 0u; i < bitsery::details::BitsSize<TValue>::value + 1; ++i) {
auto data = getValue<TValue>(tc.isPositive, i);
auto res = serializeAndGetDeserialized<typename TCase::Config>(data);
EXPECT_THAT(res.first, Eq(data));
}
}
// this stucture will contain test data and result, as type paramters
template <typename TValue, bool isPositiveNr, size_t significantBits, size_t resultBytes>
struct SizeTC {
static_assert(isPositiveNr || std::is_signed<TValue>::value, "");
static_assert(bitsery::details::BitsSize<TValue>::value >= significantBits, "");
template<typename TValue,
bool isPositiveNr,
size_t significantBits,
size_t resultBytes>
struct SizeTC
{
static_assert(isPositiveNr || std::is_signed<TValue>::value, "");
static_assert(bitsery::details::BitsSize<TValue>::value >= significantBits,
"");
using Value = TValue;
bool isPositive = isPositiveNr;
size_t fillBits = significantBits;
size_t bytesCount = resultBytes;
using Value = TValue;
bool isPositive = isPositiveNr;
size_t fillBits = significantBits;
size_t bytesCount = resultBytes;
};
template<typename T>
class SerializeExtensionCompactValueRequiredBytes : public testing::Test {
class SerializeExtensionCompactValueRequiredBytes : public testing::Test
{
public:
using TestCase = T;
using TestCase = T;
};
using RequiredBytesTestCases = ::testing::Types<
//1 byte always writes to 1 byte
SizeTC<uint8_t, true, 0,1>,
SizeTC<uint8_t, true, 8,1>,
SizeTC<int8_t, false, 0,1>,
SizeTC<int8_t, true, 8,1>,
// 1 byte always writes to 1 byte
SizeTC<uint8_t, true, 0, 1>,
SizeTC<uint8_t, true, 8, 1>,
SizeTC<int8_t, false, 0, 1>,
SizeTC<int8_t, true, 8, 1>,
//2 byte, +1 byte after 15 significant bits
SizeTC<uint16_t, true, 7,1>,
SizeTC<uint16_t, true, 8,2>,
SizeTC<uint16_t, true, 14,2>,
SizeTC<uint16_t, true, 15,3>,
//2 byte, +1 byte after 15-1 significant bits (1 bit for sign)
SizeTC<int16_t, true, 6,1>,
SizeTC<int16_t, false, 7,2>,
SizeTC<int16_t, true, 13,2>,
SizeTC<int16_t, false, 14,3>,
// 2 byte, +1 byte after 15 significant bits
SizeTC<uint16_t, true, 7, 1>,
SizeTC<uint16_t, true, 8, 2>,
SizeTC<uint16_t, true, 14, 2>,
SizeTC<uint16_t, true, 15, 3>,
// 2 byte, +1 byte after 15-1 significant bits (1 bit for sign)
SizeTC<int16_t, true, 6, 1>,
SizeTC<int16_t, false, 7, 2>,
SizeTC<int16_t, true, 13, 2>,
SizeTC<int16_t, false, 14, 3>,
//4 byte, +1 byte after 29 significant bits
SizeTC<uint32_t, true, 14,2>,
SizeTC<uint32_t, true, 21,3>,
SizeTC<uint32_t, true, 28,4>,
SizeTC<uint32_t, true, 29,5>,
SizeTC<uint32_t, true, 32,5>,
//4 byte
SizeTC<int32_t, true, 13,2>,
SizeTC<int32_t, false, 20,3>,
SizeTC<int32_t, true, 27,4>,
SizeTC<int32_t, false, 28,5>,
SizeTC<int32_t, true, 31,5>,
// 4 byte, +1 byte after 29 significant bits
SizeTC<uint32_t, true, 14, 2>,
SizeTC<uint32_t, true, 21, 3>,
SizeTC<uint32_t, true, 28, 4>,
SizeTC<uint32_t, true, 29, 5>,
SizeTC<uint32_t, true, 32, 5>,
// 4 byte
SizeTC<int32_t, true, 13, 2>,
SizeTC<int32_t, false, 20, 3>,
SizeTC<int32_t, true, 27, 4>,
SizeTC<int32_t, false, 28, 5>,
SizeTC<int32_t, true, 31, 5>,
//8 byte, +1 byte after 57 significant bits, or +2 byte when all bits are significant
SizeTC<uint64_t, true, 28,4>,
SizeTC<uint64_t, true, 35,5>,
SizeTC<uint64_t, true, 42,6>,
SizeTC<uint64_t, true, 49,7>,
SizeTC<uint64_t, true, 56,8>,
SizeTC<uint64_t, true, 57,9>,
SizeTC<uint64_t, true, 63,9>,
SizeTC<uint64_t, true, 64,10>,
//8 byte,
SizeTC<int64_t, true, 27,4>,
SizeTC<int64_t, false, 34,5>,
SizeTC<int64_t, true, 41,6>,
SizeTC<int64_t, false, 48,7>,
SizeTC<int64_t, true, 55,8>,
SizeTC<int64_t, false, 56,9>,
SizeTC<int64_t, true, 62,9>,
SizeTC<int64_t, false, 63,10>
>;
// 8 byte, +1 byte after 57 significant bits, or +2 byte when all bits are
// significant
SizeTC<uint64_t, true, 28, 4>,
SizeTC<uint64_t, true, 35, 5>,
SizeTC<uint64_t, true, 42, 6>,
SizeTC<uint64_t, true, 49, 7>,
SizeTC<uint64_t, true, 56, 8>,
SizeTC<uint64_t, true, 57, 9>,
SizeTC<uint64_t, true, 63, 9>,
SizeTC<uint64_t, true, 64, 10>,
// 8 byte,
SizeTC<int64_t, true, 27, 4>,
SizeTC<int64_t, false, 34, 5>,
SizeTC<int64_t, true, 41, 6>,
SizeTC<int64_t, false, 48, 7>,
SizeTC<int64_t, true, 55, 8>,
SizeTC<int64_t, false, 56, 9>,
SizeTC<int64_t, true, 62, 9>,
SizeTC<int64_t, false, 63, 10>>;
TYPED_TEST_SUITE(SerializeExtensionCompactValueRequiredBytes, RequiredBytesTestCases,);
TYPED_TEST_SUITE(SerializeExtensionCompactValueRequiredBytes,
RequiredBytesTestCases, );
TYPED_TEST(SerializeExtensionCompactValueRequiredBytes, Test) {
using TCase = typename TestFixture::TestCase;
using TValue = typename TCase::Value;
TCase tc{};
TValue data = getValue<TValue>(tc.isPositive, tc.fillBits);
auto res = serializeAndGetDeserialized<bitsery::DefaultConfig>(data);
EXPECT_THAT(res.first, Eq(data));
EXPECT_THAT(res.second, tc.bytesCount);
TYPED_TEST(SerializeExtensionCompactValueRequiredBytes, Test)
{
using TCase = typename TestFixture::TestCase;
using TValue = typename TCase::Value;
TCase tc{};
TValue data = getValue<TValue>(tc.isPositive, tc.fillBits);
auto res = serializeAndGetDeserialized<bitsery::DefaultConfig>(data);
EXPECT_THAT(res.first, Eq(data));
EXPECT_THAT(res.second, tc.bytesCount);
}
enum b1En: uint8_t {
A,B,C,D=54,E
enum b1En : uint8_t
{
A,
B,
C,
D = 54,
E
};
enum class b8En: int64_t {
A=-874987489,B,C=0,D,E=489748978, F,G
enum class b8En : int64_t
{
A = -874987489,
B,
C = 0,
D,
E = 489748978,
F,
G
};
TEST(SerializeExtensionCompactValueEnum, TestEnums) {
auto d1 = b1En::E;
auto d2 = b8En::B;
auto d3 = b8En::F;
EXPECT_THAT(serializeAndGetDeserialized<bitsery::DefaultConfig>(d1).first, Eq(d1));
EXPECT_THAT(serializeAndGetDeserialized<bitsery::DefaultConfig>(d2).first, Eq(d2));
EXPECT_THAT(serializeAndGetDeserialized<bitsery::DefaultConfig>(d3).first, Eq(d3));
TEST(SerializeExtensionCompactValueEnum, TestEnums)
{
auto d1 = b1En::E;
auto d2 = b8En::B;
auto d3 = b8En::F;
EXPECT_THAT(serializeAndGetDeserialized<bitsery::DefaultConfig>(d1).first,
Eq(d1));
EXPECT_THAT(serializeAndGetDeserialized<bitsery::DefaultConfig>(d2).first,
Eq(d2));
EXPECT_THAT(serializeAndGetDeserialized<bitsery::DefaultConfig>(d3).first,
Eq(d3));
}
TEST(SerializeExtensionCompactValueAsObjectDeserializeOverflow, TestEnums) {
SerializationContext ctx;
auto data = getValue<uint32_t >(true, 17);
uint16_t res{};
ctx.createSerializer().ext(data, CompactValueAsObject{});
ctx.createDeserializer().ext(res, CompactValueAsObject{});
EXPECT_THAT(data, ::testing::Ne(res));
EXPECT_THAT(ctx.des->adapter().error(), Eq(bitsery::ReaderError::InvalidData));
TEST(SerializeExtensionCompactValueAsObjectDeserializeOverflow, TestEnums)
{
SerializationContext ctx;
auto data = getValue<uint32_t>(true, 17);
uint16_t res{};
ctx.createSerializer().ext(data, CompactValueAsObject{});
ctx.createDeserializer().ext(res, CompactValueAsObject{});
EXPECT_THAT(data, ::testing::Ne(res));
EXPECT_THAT(ctx.des->adapter().error(),
Eq(bitsery::ReaderError::InvalidData));
}

View File

@@ -1,31 +1,30 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <bitsery/ext/entropy.h>
#include <bitsery/traits/list.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using namespace testing;
@@ -34,167 +33,195 @@ using bitsery::ext::Entropy;
using BPSer = SerializationContext::TSerializerBPEnabled;
using BPDes = SerializationContext::TDeserializerBPEnabled;
TEST(SerializeExtensionEntropy,
WhenEntropyEncodedThenOnlyWriteIndexUsingMinRequiredBits)
{
int32_t v = 4849;
int32_t res;
int32_t values[3] = { 485, 4849, 89 };
SerializationContext ctx{};
ctx.createSerializer().enableBitPacking(
[&v, &values](BPSer& ser) { ser.ext4b(v, Entropy<int32_t[3]>{ values }); });
ctx.createDeserializer().enableBitPacking([&res, &values](BPDes& des) {
des.ext4b(res, Entropy<int32_t[3]>{ values });
});
TEST(SerializeExtensionEntropy, WhenEntropyEncodedThenOnlyWriteIndexUsingMinRequiredBits) {
int32_t v = 4849;
int32_t res;
int32_t values[3] = {485,4849,89};
SerializationContext ctx{};
ctx.createSerializer().enableBitPacking([&v, &values](BPSer& ser) {
ser.ext4b(v, Entropy<int32_t[3]>{values});
});
ctx.createDeserializer().enableBitPacking([&res, &values](BPDes& des) {
des.ext4b(res, Entropy<int32_t[3]>{values});
});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
SerializationContext ctx1{};
ctx1.createSerializer().enableBitPacking([&v, &values](BPSer& ser) {
ser.ext4b(v, Entropy<int32_t[3]>{values});
});
ctx1.createDeserializer().enableBitPacking([&res](BPDes& des) {
des.ext(res, bitsery::ext::ValueRange<int32_t>{0, static_cast<int32_t>(3 + 1)});
});
EXPECT_THAT(res, Eq(2));
SerializationContext ctx1{};
ctx1.createSerializer().enableBitPacking(
[&v, &values](BPSer& ser) { ser.ext4b(v, Entropy<int32_t[3]>{ values }); });
ctx1.createDeserializer().enableBitPacking([&res](BPDes& des) {
des.ext(
res, bitsery::ext::ValueRange<int32_t>{ 0, static_cast<int32_t>(3 + 1) });
});
EXPECT_THAT(res, Eq(2));
}
TEST(SerializeExtensionEntropy, WhenNoEntropyEncodedThenWriteZeroBitsAndValueOrObject) {
int16_t v = 8945;
int16_t res;
std::initializer_list<int> values{485,4849,89};
SerializationContext ctx{};
ctx.createSerializer().enableBitPacking([&v, &values](BPSer& ser) {
ser.ext2b(v, Entropy<std::initializer_list<int>>{values});
});
ctx.createDeserializer().enableBitPacking([&res, &values](BPDes& des) {
des.ext2b(res, Entropy<std::initializer_list<int>>{values});
});
TEST(SerializeExtensionEntropy,
WhenNoEntropyEncodedThenWriteZeroBitsAndValueOrObject)
{
int16_t v = 8945;
int16_t res;
std::initializer_list<int> values{ 485, 4849, 89 };
SerializationContext ctx{};
ctx.createSerializer().enableBitPacking([&v, &values](BPSer& ser) {
ser.ext2b(v, Entropy<std::initializer_list<int>>{ values });
});
ctx.createDeserializer().enableBitPacking([&res, &values](BPDes& des) {
des.ext2b(res, Entropy<std::initializer_list<int>>{ values });
});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(sizeof(int16_t)+1));
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(sizeof(int16_t) + 1));
}
TEST(SerializeExtensionEntropy, CustomTypeEntropyEncoded) {
MyStruct1 v = {12,10};
MyStruct1 res;
constexpr size_t N = 4;
TEST(SerializeExtensionEntropy, CustomTypeEntropyEncoded)
{
MyStruct1 v = { 12, 10 };
MyStruct1 res;
constexpr size_t N = 4;
MyStruct1 values[N]{
MyStruct1{12, 10}, MyStruct1{485, 454},
MyStruct1{4849, 89}, MyStruct1{0, 1}};
SerializationContext ctx{};
ctx.createSerializer().enableBitPacking([&v, &values](BPSer& ser) {
ser.ext(v, Entropy<MyStruct1[4]>{values});
});
ctx.createDeserializer().enableBitPacking([&res, &values](BPDes& des) {
des.ext(res, Entropy<MyStruct1[4]>{values});
});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
MyStruct1 values[N]{ MyStruct1{ 12, 10 },
MyStruct1{ 485, 454 },
MyStruct1{ 4849, 89 },
MyStruct1{ 0, 1 } };
SerializationContext ctx{};
ctx.createSerializer().enableBitPacking(
[&v, &values](BPSer& ser) { ser.ext(v, Entropy<MyStruct1[4]>{ values }); });
ctx.createDeserializer().enableBitPacking([&res, &values](BPDes& des) {
des.ext(res, Entropy<MyStruct1[4]>{ values });
});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
}
TEST(SerializeExtensionEntropy, CustomTypeNotEntropyEncoded) {
MyStruct1 v = {8945,4456};
MyStruct1 res;
TEST(SerializeExtensionEntropy, CustomTypeNotEntropyEncoded)
{
MyStruct1 v = { 8945, 4456 };
MyStruct1 res;
std::initializer_list<MyStruct1> values {
MyStruct1{12,10}, MyStruct1{485, 454},
MyStruct1{4849,89}, MyStruct1{0,1}};
SerializationContext ctx{};
ctx.createSerializer().enableBitPacking([&v, &values](BPSer& ser) {
ser.ext(v, Entropy<std::initializer_list<MyStruct1>>{values});
});
ctx.createDeserializer().enableBitPacking([&res, &values](BPDes& des) {
des.ext(res, Entropy<std::initializer_list<MyStruct1>>{values});
});
std::initializer_list<MyStruct1> values{ MyStruct1{ 12, 10 },
MyStruct1{ 485, 454 },
MyStruct1{ 4849, 89 },
MyStruct1{ 0, 1 } };
SerializationContext ctx{};
ctx.createSerializer().enableBitPacking([&v, &values](BPSer& ser) {
ser.ext(v, Entropy<std::initializer_list<MyStruct1>>{ values });
});
ctx.createDeserializer().enableBitPacking([&res, &values](BPDes& des) {
des.ext(res, Entropy<std::initializer_list<MyStruct1>>{ values });
});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(MyStruct1::SIZE + 1));
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(MyStruct1::SIZE + 1));
}
TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncodedWithNoAlignBeforeData) {
MyStruct1 v = {8945,4456};
MyStruct1 res;
constexpr size_t N = 4;
TEST(SerializeExtensionEntropy,
CustomFunctionNotEntropyEncodedWithNoAlignBeforeData)
{
MyStruct1 v = { 8945, 4456 };
MyStruct1 res;
constexpr size_t N = 4;
std::vector<MyStruct1> values{
MyStruct1{12,10}, MyStruct1{485, 454},
MyStruct1{4849,89}, MyStruct1{0,1}};
std::vector<MyStruct1> values{ MyStruct1{ 12, 10 },
MyStruct1{ 485, 454 },
MyStruct1{ 4849, 89 },
MyStruct1{ 0, 1 } };
auto rangeForValue = bitsery::ext::ValueRange<int>{0, 10000};
auto rangeForValue = bitsery::ext::ValueRange<int>{ 0, 10000 };
SerializationContext ctx;
ctx.createSerializer().enableBitPacking([&v, &values, &rangeForValue](BPSer& ser){
//lambdas differ only in capture clauses, it would make sense to use std::bind, but debugger crashes when it sees std::bind...
auto serLambda = [&rangeForValue](BPSer& ser, MyStruct1& data) {
ser.ext(data.i1, rangeForValue);
ser.ext(data.i2, rangeForValue);
};
ser.ext(v, Entropy<std::vector<MyStruct1>>(values, false), serLambda);
SerializationContext ctx;
ctx.createSerializer().enableBitPacking(
[&v, &values, &rangeForValue](BPSer& ser) {
// lambdas differ only in capture clauses, it would make sense to use
// std::bind, but debugger crashes when it sees std::bind...
auto serLambda = [&rangeForValue](BPSer& ser, MyStruct1& data) {
ser.ext(data.i1, rangeForValue);
ser.ext(data.i2, rangeForValue);
};
ser.ext(v, Entropy<std::vector<MyStruct1>>(values, false), serLambda);
});
ctx.createDeserializer().enableBitPacking([&res, &values, &rangeForValue](BPDes& des) {
auto desLambda = [&rangeForValue](BPDes& des, MyStruct1& data) {
des.ext(data.i1, rangeForValue);
des.ext(data.i2, rangeForValue);
};
des.ext(res, Entropy<std::vector<MyStruct1>>(values, false), desLambda);
ctx.createDeserializer().enableBitPacking(
[&res, &values, &rangeForValue](BPDes& des) {
auto desLambda = [&rangeForValue](BPDes& des, MyStruct1& data) {
des.ext(data.i1, rangeForValue);
des.ext(data.i2, rangeForValue);
};
des.ext(res, Entropy<std::vector<MyStruct1>>(values, false), desLambda);
});
EXPECT_THAT(res, Eq(v));
auto rangeForIndex = bitsery::ext::ValueRange<size_t>{0u, N+1};
EXPECT_THAT(ctx.getBufferSize(), Eq((rangeForIndex.getRequiredBits() + rangeForValue.getRequiredBits() * 2 - 1) / 8 + 1 ));
EXPECT_THAT(res, Eq(v));
auto rangeForIndex = bitsery::ext::ValueRange<size_t>{ 0u, N + 1 };
EXPECT_THAT(ctx.getBufferSize(),
Eq((rangeForIndex.getRequiredBits() +
rangeForValue.getRequiredBits() * 2 - 1) /
8 +
1));
}
TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncodedWithAlignBeforeData) {
MyStruct1 v = {8945,4456};
MyStruct1 res;
TEST(SerializeExtensionEntropy,
CustomFunctionNotEntropyEncodedWithAlignBeforeData)
{
MyStruct1 v = { 8945, 4456 };
MyStruct1 res;
std::vector<MyStruct1> values{
MyStruct1{12,10}, MyStruct1{485, 454},
MyStruct1{4849,89}, MyStruct1{0,1}};
std::vector<MyStruct1> values{ MyStruct1{ 12, 10 },
MyStruct1{ 485, 454 },
MyStruct1{ 4849, 89 },
MyStruct1{ 0, 1 } };
auto rangeForValue = bitsery::ext::ValueRange<int>{0, 10000};
auto rangeForValue = bitsery::ext::ValueRange<int>{ 0, 10000 };
SerializationContext ctx;
ctx.createSerializer().enableBitPacking([&v, &values, &rangeForValue](BPSer& ser){
//lambdas differ only in capture clauses, it would make sense to use std::bind, but debugger crashes when it sees std::bind...
auto serLambda = [&rangeForValue](BPSer& ser, MyStruct1& data) {
ser.ext(data.i1, rangeForValue);
ser.ext(data.i2, rangeForValue);
};
ser.ext(v, Entropy<std::vector<MyStruct1>>(values, true), serLambda);
SerializationContext ctx;
ctx.createSerializer().enableBitPacking(
[&v, &values, &rangeForValue](BPSer& ser) {
// lambdas differ only in capture clauses, it would make sense to use
// std::bind, but debugger crashes when it sees std::bind...
auto serLambda = [&rangeForValue](BPSer& ser, MyStruct1& data) {
ser.ext(data.i1, rangeForValue);
ser.ext(data.i2, rangeForValue);
};
ser.ext(v, Entropy<std::vector<MyStruct1>>(values, true), serLambda);
});
ctx.createDeserializer().enableBitPacking([&res, &values, &rangeForValue](BPDes& des) {
auto desLambda = [&rangeForValue](BPDes& des, MyStruct1& data) {
des.ext(data.i1, rangeForValue);
des.ext(data.i2, rangeForValue);
};
des.ext(res, Entropy<std::vector<MyStruct1>>(values, true), desLambda);
ctx.createDeserializer().enableBitPacking(
[&res, &values, &rangeForValue](BPDes& des) {
auto desLambda = [&rangeForValue](BPDes& des, MyStruct1& data) {
des.ext(data.i1, rangeForValue);
des.ext(data.i2, rangeForValue);
};
des.ext(res, Entropy<std::vector<MyStruct1>>(values, true), desLambda);
});
EXPECT_THAT(res, Eq(v));
auto bitsForIndex = 8u; //because aligned
EXPECT_THAT(ctx.getBufferSize(), Eq((bitsForIndex + rangeForValue.getRequiredBits() * 2 - 1) / 8 + 1 ));
EXPECT_THAT(res, Eq(v));
auto bitsForIndex = 8u; // because aligned
EXPECT_THAT(
ctx.getBufferSize(),
Eq((bitsForIndex + rangeForValue.getRequiredBits() * 2 - 1) / 8 + 1));
}
TEST(SerializeExtensionEntropy, WhenEntropyEncodedThenCustomFunctionNotInvoked) {
MyStruct1 v = {4849,89};
MyStruct1 res;
TEST(SerializeExtensionEntropy, WhenEntropyEncodedThenCustomFunctionNotInvoked)
{
MyStruct1 v = { 4849, 89 };
MyStruct1 res;
std::list<MyStruct1> values {MyStruct1{12,10}, MyStruct1{485, 454},
MyStruct1{4849,89}, MyStruct1{0,1}};
std::list<MyStruct1> values{ MyStruct1{ 12, 10 },
MyStruct1{ 485, 454 },
MyStruct1{ 4849, 89 },
MyStruct1{ 0, 1 } };
SerializationContext ctx;
ctx.createSerializer().enableBitPacking([&v, &values](BPSer& ser) {
ser.ext(v, Entropy<std::list<MyStruct1>>{values}, [](BPSer& ,MyStruct1& ) {});
});
ctx.createDeserializer().enableBitPacking([&res, &values](BPDes& des) {
des.ext(res, Entropy<std::list<MyStruct1>>{values}, [](BPDes& , MyStruct1& ) {});
});
SerializationContext ctx;
ctx.createSerializer().enableBitPacking([&v, &values](BPSer& ser) {
ser.ext(
v, Entropy<std::list<MyStruct1>>{ values }, [](BPSer&, MyStruct1&) {});
});
ctx.createDeserializer().enableBitPacking([&res, &values](BPDes& des) {
des.ext(
res, Entropy<std::list<MyStruct1>>{ values }, [](BPDes&, MyStruct1&) {});
});
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
EXPECT_THAT(res, Eq(v));
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
}

View File

@@ -1,238 +1,253 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "serialization_test_utils.h"
#include <bitsery/ext/growable.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
using namespace testing;
using bitsery::ext::Growable;
struct DataV1 {
int32_t v1;
struct DataV1
{
int32_t v1;
};
template <typename S>
void serialize(S& s, DataV1& o) {
s.value4b(o.v1);
template<typename S>
void
serialize(S& s, DataV1& o)
{
s.value4b(o.v1);
}
struct DataV2 {
int32_t v1;
int32_t v2;
struct DataV2
{
int32_t v1;
int32_t v2;
};
template <typename S>
void serialize(S& s, DataV2& o) {
s.value4b(o.v1);
s.value4b(o.v2);
template<typename S>
void
serialize(S& s, DataV2& o)
{
s.value4b(o.v1);
s.value4b(o.v2);
}
struct DataV3 {
int32_t v1;
int32_t v2;
int32_t v3;
template <typename S>
void serialize(S& s) {
s.value4b(v1);
s.value4b(v2);
s.value4b(v3);
}
struct DataV3
{
int32_t v1;
int32_t v2;
int32_t v3;
template<typename S>
void serialize(S& s)
{
s.value4b(v1);
s.value4b(v2);
s.value4b(v3);
}
};
TEST(SerializeExtensionGrowable, SessionsLengthIsStoredWith4BytesBeforeSessionDataStarts) {
SerializationContext ctx;
auto& ser = ctx.createSerializer();
//session cannot be empty
ser.value2b(int16_t{1});
ser.ext(int8_t{2}, Growable{}, [] (decltype(ser)& ser, int8_t& v) {
ser.value1b(v);
TEST(SerializeExtensionGrowable,
SessionsLengthIsStoredWith4BytesBeforeSessionDataStarts)
{
SerializationContext ctx;
auto& ser = ctx.createSerializer();
// session cannot be empty
ser.value2b(int16_t{ 1 });
ser.ext(int8_t{ 2 }, Growable{}, [](decltype(ser)& ser, int8_t& v) {
ser.value1b(v);
});
ser.value1b(int8_t{ 3 });
auto& des = ctx.createDeserializer();
uint8_t res1b{};
uint16_t res2b{};
uint32_t res4b{};
des.value2b(res2b);
EXPECT_THAT(res2b, Eq(1));
des.value4b(res4b);
EXPECT_THAT(res4b, Eq(1 + 4)); // size + 4bytes
des.value1b(res1b);
EXPECT_THAT(res1b, Eq(2));
des.value1b(res1b);
EXPECT_THAT(res1b, Eq(3));
EXPECT_THAT(ctx.ser->adapter().writtenBytesCount(), Eq(8));
}
TEST(SerializeExtensionGrowable, MultipleSessionsReadSameVersionData)
{
SerializationContext ctx;
DataV2 data{ 8454, 987451 };
auto& ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{});
}
ctx.createDeserializer();
DataV2 res{};
auto& des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{});
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
}
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleSessionsReadNewerVersionData)
{
SerializationContext ctx;
DataV3 data{ 8454, 987451, 45612 };
auto& ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{});
}
ctx.createDeserializer();
DataV2 res{};
auto& des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{});
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
}
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleSessionsReadOlderVersionData)
{
SerializationContext ctx;
DataV2 data{ 8454, 987451 };
auto& ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{});
}
ctx.createDeserializer();
DataV3 res{};
auto& des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{});
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
EXPECT_THAT(res.v3, Eq(0));
}
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadSameVersionData)
{
SerializationContext ctx;
DataV2 data{ 8454, 987451 };
auto& ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{}, [](decltype(ser)& ser, DataV2& o) {
ser.value4b(o.v1);
ser.value4b(o.v2);
ser.ext(o, Growable{});
});
ser.value1b(int8_t{3});
auto& des = ctx.createDeserializer();
uint8_t res1b{};
uint16_t res2b{};
uint32_t res4b{};
des.value2b(res2b);
EXPECT_THAT(res2b, Eq(1));
des.value4b(res4b);
EXPECT_THAT(res4b, Eq(1+4));//size + 4bytes
des.value1b(res1b);
EXPECT_THAT(res1b, Eq(2));
des.value1b(res1b);
EXPECT_THAT(res1b, Eq(3));
EXPECT_THAT(ctx.ser->adapter().writtenBytesCount(), Eq(8));
}
ctx.createDeserializer();
DataV2 res{};
auto& des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{}, [&res, &data](decltype(des)& des, DataV2& o) {
des.value4b(o.v1);
des.value4b(o.v2);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
des.ext(o, Growable{});
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
});
}
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleSessionsReadSameVersionData) {
SerializationContext ctx;
DataV2 data{8454,987451};
auto& ser = ctx.createSerializer();
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadNewerVersionData)
{
SerializationContext ctx;
DataV3 data{ 8454, 987451, 54124 };
auto& ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{});
}
ctx.createDeserializer();
DataV2 res{};
auto& des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{});
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
}
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{}, [](decltype(ser)& ser, DataV3& o) {
ser.value4b(o.v1);
ser.value4b(o.v2);
ser.ext(o, Growable{});
// new fields can only be added at the end
ser.value4b(o.v3);
});
}
ctx.createDeserializer();
DataV2 res{};
auto& des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{}, [&res, &data](decltype(des)& des, DataV2& o) {
des.value4b(o.v1);
des.value4b(o.v2);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
des.ext(o, Growable{});
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
});
}
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleSessionsReadNewerVersionData) {
SerializationContext ctx;
DataV3 data{8454,987451, 45612};
auto& ser = ctx.createSerializer();
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadOlderVersionData)
{
SerializationContext ctx;
DataV2 data{ 8454, 987451 };
auto& ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{});
}
ctx.createDeserializer();
DataV2 res{};
auto& des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{});
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
}
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleSessionsReadOlderVersionData) {
SerializationContext ctx;
DataV2 data{8454,987451};
auto& ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{});
}
ctx.createDeserializer();
DataV3 res{};
auto& des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{});
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
EXPECT_THAT(res.v3, Eq(0));
}
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadSameVersionData) {
SerializationContext ctx;
DataV2 data{8454,987451};
auto& ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{}, [](decltype(ser)& ser, DataV2& o) {
ser.value4b(o.v1);
ser.value4b(o.v2);
ser.ext(o, Growable{});
});
}
ctx.createDeserializer();
DataV2 res{};
auto& des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{}, [&res, &data](decltype(des)& des, DataV2& o) {
des.value4b(o.v1);
des.value4b(o.v2);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
des.ext(o, Growable{});
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
});
}
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadNewerVersionData) {
SerializationContext ctx;
DataV3 data{8454,987451, 54124};
auto& ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{}, [](decltype(ser)& ser, DataV3& o) {
ser.value4b(o.v1);
ser.value4b(o.v2);
ser.ext(o, Growable{});
//new fields can only be added at the end
ser.value4b(o.v3);
});
}
ctx.createDeserializer();
DataV2 res{};
auto& des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{}, [&res, &data](decltype(des)& des, DataV2& o) {
des.value4b(o.v1);
des.value4b(o.v2);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
des.ext(o, Growable{});
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
});
}
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
}
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadOlderVersionData) {
SerializationContext ctx;
DataV2 data{8454,987451};
auto& ser = ctx.createSerializer();
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{}, [](decltype(ser)& ser, DataV2& o) {
ser.value4b(o.v1);
ser.value4b(o.v2);
ser.ext(o, Growable{});
});
}
ctx.createDeserializer();
DataV3 res{};
auto& des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{}, [&res, &data](decltype(des)& des, DataV3& o) {
des.value4b(o.v1);
des.value4b(o.v2);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
des.ext(o, Growable{});
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
EXPECT_THAT(res.v3, Eq(0));
//new fields can only be added at the end
des.value4b(o.v3);
EXPECT_THAT(res.v3, Eq(0));
});
}
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
for (auto i = 0; i < 10; ++i) {
ser.ext(data, Growable{}, [](decltype(ser)& ser, DataV2& o) {
ser.value4b(o.v1);
ser.value4b(o.v2);
ser.ext(o, Growable{});
});
}
ctx.createDeserializer();
DataV3 res{};
auto& des = ctx.createDeserializer();
for (auto i = 0; i < 10; ++i) {
des.ext(res, Growable{}, [&res, &data](decltype(des)& des, DataV3& o) {
des.value4b(o.v1);
des.value4b(o.v2);
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
des.ext(o, Growable{});
EXPECT_THAT(res.v1, Eq(data.v1));
EXPECT_THAT(res.v2, Eq(data.v2));
EXPECT_THAT(res.v3, Eq(0));
// new fields can only be added at the end
des.value4b(o.v3);
EXPECT_THAT(res.v3, Eq(0));
});
}
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
}

View File

@@ -1,28 +1,28 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include "serialization_test_utils.h"
#include <bitsery/ext/inheritance.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
using bitsery::ext::BaseClass;
using bitsery::ext::VirtualBaseClass;
@@ -34,332 +34,400 @@ using testing::Eq;
/*
* base class
*/
struct Base {
uint8_t x{};
virtual ~Base() = default;
struct Base
{
uint8_t x{};
virtual ~Base() = default;
};
template <typename S>
void serialize(S& s, Base& o) {
s.value1b(o.x);
template<typename S>
void
serialize(S& s, Base& o)
{
s.value1b(o.x);
}
/*
* non virtual inheritance from base
*/
struct Derive1NonVirtually:Base {
uint8_t y1{};
struct Derive1NonVirtually : Base
{
uint8_t y1{};
};
template <typename S>
void serialize(S& s, Derive1NonVirtually& o) {
s.ext(o, BaseClass<Base>{});
s.value1b(o.y1);
template<typename S>
void
serialize(S& s, Derive1NonVirtually& o)
{
s.ext(o, BaseClass<Base>{});
s.value1b(o.y1);
}
struct Derive2NonVirtually:Base {
uint8_t y2{};
struct Derive2NonVirtually : Base
{
uint8_t y2{};
};
template <typename S>
void serialize(S& s, Derive2NonVirtually& o) {
//use lambda to serialize base
s.ext(o, BaseClass<Base>{}, [](S& s, Base& b) {
s.object(b);
});
s.value1b(o.y2);
template<typename S>
void
serialize(S& s, Derive2NonVirtually& o)
{
// use lambda to serialize base
s.ext(o, BaseClass<Base>{}, [](S& s, Base& b) { s.object(b); });
s.value1b(o.y2);
}
struct MultipleInheritanceNonVirtualBase: Derive1NonVirtually, Derive2NonVirtually {
uint8_t z{};
struct MultipleInheritanceNonVirtualBase
: Derive1NonVirtually
, Derive2NonVirtually
{
uint8_t z{};
};
template <typename S>
void serialize(S& s, MultipleInheritanceNonVirtualBase& o) {
s.ext(o, BaseClass<Derive1NonVirtually>{});
s.ext(o, BaseClass<Derive2NonVirtually>{});
s.value1b(o.z);
template<typename S>
void
serialize(S& s, MultipleInheritanceNonVirtualBase& o)
{
s.ext(o, BaseClass<Derive1NonVirtually>{});
s.ext(o, BaseClass<Derive2NonVirtually>{});
s.value1b(o.z);
}
/*
* virtual inheritance from base
*/
struct Derive1Virtually:virtual Base {
uint8_t y1{};
struct Derive1Virtually : virtual Base
{
uint8_t y1{};
};
template <typename S>
void serialize(S& s, Derive1Virtually& o) {
s.ext(o, VirtualBaseClass<Base>{});
s.value1b(o.y1);
template<typename S>
void
serialize(S& s, Derive1Virtually& o)
{
s.ext(o, VirtualBaseClass<Base>{});
s.value1b(o.y1);
}
struct Derive2Virtually:virtual Base {
uint8_t y2{};
struct Derive2Virtually : virtual Base
{
uint8_t y2{};
};
template <typename S>
void serialize(S& s, Derive2Virtually& o) {
s.ext(o, VirtualBaseClass<Base>{});
s.value1b(o.y2);
template<typename S>
void
serialize(S& s, Derive2Virtually& o)
{
s.ext(o, VirtualBaseClass<Base>{});
s.value1b(o.y2);
}
struct MultipleInheritanceVirtualBase: Derive1Virtually, Derive2Virtually {
uint8_t z{};
MultipleInheritanceVirtualBase() = default;
struct MultipleInheritanceVirtualBase
: Derive1Virtually
, Derive2Virtually
{
uint8_t z{};
MultipleInheritanceVirtualBase() = default;
MultipleInheritanceVirtualBase(uint8_t x_, uint8_t y1_, uint8_t y2_, uint8_t z_) {
x = x_;
y1 = y1_;
y2 = y2_;
z = z_;
}
template <typename S>
void serialize(S& s) {
s.ext(*this, BaseClass<Derive1Virtually>{});
s.ext(*this, BaseClass<Derive2Virtually>{});
s.value1b(z);
}
MultipleInheritanceVirtualBase(uint8_t x_,
uint8_t y1_,
uint8_t y2_,
uint8_t z_)
{
x = x_;
y1 = y1_;
y2 = y2_;
z = z_;
}
template<typename S>
void serialize(S& s)
{
s.ext(*this, BaseClass<Derive1Virtually>{});
s.ext(*this, BaseClass<Derive2Virtually>{});
s.value1b(z);
}
};
bool operator == (const MultipleInheritanceVirtualBase& lhs, const MultipleInheritanceVirtualBase& rhs) {
return std::tie(lhs.x, lhs.y1, lhs.y2, lhs.z) == std::tie(rhs.x, rhs.y1, rhs.y2, rhs.z);
bool
operator==(const MultipleInheritanceVirtualBase& lhs,
const MultipleInheritanceVirtualBase& rhs)
{
return std::tie(lhs.x, lhs.y1, lhs.y2, lhs.z) ==
std::tie(rhs.x, rhs.y1, rhs.y2, rhs.z);
}
TEST(SerializeExtensionInheritance, BaseClass) {
TEST(SerializeExtensionInheritance, BaseClass)
{
Derive1NonVirtually d1{};
d1.x = 187;
d1.y1 = 74;
Derive1NonVirtually rd1{};
Derive1NonVirtually d1{};
d1.x = 187;
d1.y1 = 74;
Derive1NonVirtually rd1{};
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(d1);
ctx.createDeserializer(inherCtxDes).object(rd1);
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(d1);
ctx.createDeserializer(inherCtxDes).object(rd1);
EXPECT_THAT(rd1.x, Eq(d1.x));
EXPECT_THAT(rd1.y1, Eq(d1.y1));
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
EXPECT_THAT(rd1.x, Eq(d1.x));
EXPECT_THAT(rd1.y1, Eq(d1.y1));
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
}
TEST(SerializeExtensionInheritance, VirtualBaseClass) {
Derive1Virtually d1{};
d1.x = 15;
d1.y1 = 87;
Derive1Virtually rd1{};
TEST(SerializeExtensionInheritance, VirtualBaseClass)
{
Derive1Virtually d1{};
d1.x = 15;
d1.y1 = 87;
Derive1Virtually rd1{};
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(d1);
ctx.createDeserializer(inherCtxDes).object(rd1);
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(d1);
ctx.createDeserializer(inherCtxDes).object(rd1);
EXPECT_THAT(rd1.x, Eq(d1.x));
EXPECT_THAT(rd1.y1, Eq(d1.y1));
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
EXPECT_THAT(rd1.x, Eq(d1.x));
EXPECT_THAT(rd1.y1, Eq(d1.y1));
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
}
TEST(SerializeExtensionInheritance, MultipleBasesWithoutVirtualInheritance) {
MultipleInheritanceNonVirtualBase md{};
//x is ambiguous because we don't derive virtually
static_cast<Derive1NonVirtually&>(md).x = 1;
static_cast<Derive2NonVirtually&>(md).x = 2;
md.y1 = 4;
md.z = 5;
md.y2 = 6;
MultipleInheritanceNonVirtualBase res{};
TEST(SerializeExtensionInheritance, MultipleBasesWithoutVirtualInheritance)
{
MultipleInheritanceNonVirtualBase md{};
// x is ambiguous because we don't derive virtually
static_cast<Derive1NonVirtually&>(md).x = 1;
static_cast<Derive2NonVirtually&>(md).x = 2;
md.y1 = 4;
md.z = 5;
md.y2 = 6;
MultipleInheritanceNonVirtualBase res{};
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(md);
ctx.createDeserializer(inherCtxDes).object(res);
EXPECT_THAT(static_cast<Derive1NonVirtually&>(res).x, Eq(static_cast<Derive1NonVirtually&>(md).x));
EXPECT_THAT(static_cast<Derive2NonVirtually&>(res).x, Eq(static_cast<Derive2NonVirtually&>(md).x));
EXPECT_THAT(res.y1, Eq(md.y1));
EXPECT_THAT(res.y2, Eq(md.y2));
EXPECT_THAT(res.z, Eq(md.z));
EXPECT_THAT(ctx.getBufferSize(), Eq(5)); //5 because two bases
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(md);
ctx.createDeserializer(inherCtxDes).object(res);
EXPECT_THAT(static_cast<Derive1NonVirtually&>(res).x,
Eq(static_cast<Derive1NonVirtually&>(md).x));
EXPECT_THAT(static_cast<Derive2NonVirtually&>(res).x,
Eq(static_cast<Derive2NonVirtually&>(md).x));
EXPECT_THAT(res.y1, Eq(md.y1));
EXPECT_THAT(res.y2, Eq(md.y2));
EXPECT_THAT(res.z, Eq(md.z));
EXPECT_THAT(ctx.getBufferSize(), Eq(5)); // 5 because two bases
}
TEST(SerializeExtensionInheritance, WhenNoVirtualInheritanceExistsThenInheritanceContextIsNotRequired) {
MultipleInheritanceNonVirtualBase md{};
//x is ambiguous because we don't derive virtually
static_cast<Derive1NonVirtually&>(md).x = 1;
static_cast<Derive2NonVirtually&>(md).x = 2;
md.y1 = 4;
md.z = 5;
md.y2 = 6;
MultipleInheritanceNonVirtualBase res{};
TEST(SerializeExtensionInheritance,
WhenNoVirtualInheritanceExistsThenInheritanceContextIsNotRequired)
{
MultipleInheritanceNonVirtualBase md{};
// x is ambiguous because we don't derive virtually
static_cast<Derive1NonVirtually&>(md).x = 1;
static_cast<Derive2NonVirtually&>(md).x = 2;
md.y1 = 4;
md.z = 5;
md.y2 = 6;
MultipleInheritanceNonVirtualBase res{};
//without InheritanceContext
SerializationContext ctx{};
ctx.createSerializer().object(md);
ctx.createDeserializer().object(res);
EXPECT_THAT(static_cast<Derive1NonVirtually&>(res).x, Eq(static_cast<Derive1NonVirtually&>(md).x));
EXPECT_THAT(static_cast<Derive2NonVirtually&>(res).x, Eq(static_cast<Derive2NonVirtually&>(md).x));
EXPECT_THAT(res.y1, Eq(md.y1));
EXPECT_THAT(res.y2, Eq(md.y2));
EXPECT_THAT(res.z, Eq(md.z));
EXPECT_THAT(ctx.getBufferSize(), Eq(5)); //5 because two bases
// without InheritanceContext
SerializationContext ctx{};
ctx.createSerializer().object(md);
ctx.createDeserializer().object(res);
EXPECT_THAT(static_cast<Derive1NonVirtually&>(res).x,
Eq(static_cast<Derive1NonVirtually&>(md).x));
EXPECT_THAT(static_cast<Derive2NonVirtually&>(res).x,
Eq(static_cast<Derive2NonVirtually&>(md).x));
EXPECT_THAT(res.y1, Eq(md.y1));
EXPECT_THAT(res.y2, Eq(md.y2));
EXPECT_THAT(res.z, Eq(md.z));
EXPECT_THAT(ctx.getBufferSize(), Eq(5)); // 5 because two bases
}
TEST(SerializeExtensionInheritance, MultipleBasesWithVirtualInheritance)
{
MultipleInheritanceVirtualBase md{ 3, 7, 5, 15 };
MultipleInheritanceVirtualBase res{};
TEST(SerializeExtensionInheritance, MultipleBasesWithVirtualInheritance) {
MultipleInheritanceVirtualBase md{3,7,5,15};
MultipleInheritanceVirtualBase res{};
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(md);
ctx.createDeserializer(inherCtxDes).object(res);
EXPECT_THAT(res, Eq(md));
EXPECT_THAT(ctx.getBufferSize(), Eq(4)); //4 because virtual base
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(md);
ctx.createDeserializer(inherCtxDes).object(res);
EXPECT_THAT(res, Eq(md));
EXPECT_THAT(ctx.getBufferSize(), Eq(4)); // 4 because virtual base
}
TEST(SerializeExtensionInheritance, MultipleBasesWithVirtualInheritanceMultipleObjects) {
std::vector<MultipleInheritanceVirtualBase> data;
data.emplace_back(4,8,7,9);
data.emplace_back(1,2,3,4);
data.emplace_back(8,7,15,97);
data.emplace_back(54,132,45,84);
data.emplace_back(27,85,41,2);
std::vector<MultipleInheritanceVirtualBase> res{};
TEST(SerializeExtensionInheritance,
MultipleBasesWithVirtualInheritanceMultipleObjects)
{
std::vector<MultipleInheritanceVirtualBase> data;
data.emplace_back(4, 8, 7, 9);
data.emplace_back(1, 2, 3, 4);
data.emplace_back(8, 7, 15, 97);
data.emplace_back(54, 132, 45, 84);
data.emplace_back(27, 85, 41, 2);
std::vector<MultipleInheritanceVirtualBase> res{};
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).container(data, 10);
ctx.createDeserializer(inherCtxDes).container(res, 10);
EXPECT_THAT(res, ::testing::ContainerEq(data));
EXPECT_THAT(ctx.getBufferSize(), Eq(1 + 4 * data.size())); //1 container size + 4 because virtual base * elements
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).container(data, 10);
ctx.createDeserializer(inherCtxDes).container(res, 10);
EXPECT_THAT(res, ::testing::ContainerEq(data));
EXPECT_THAT(
ctx.getBufferSize(),
Eq(1 +
4 *
data.size())); // 1 container size + 4 because virtual base * elements
}
//
class BasePrivateSerialize {
class BasePrivateSerialize
{
public:
explicit BasePrivateSerialize(uint8_t v):_v{v} {}
uint8_t getX() const { return _v; }
explicit BasePrivateSerialize(uint8_t v)
: _v{ v }
{
}
uint8_t getX() const { return _v; }
private:
uint8_t _v;
friend bitsery::Access;
template <typename S>
void serialize(S& s) {
s.value1b(_v);
}
uint8_t _v;
friend bitsery::Access;
template<typename S>
void serialize(S& s)
{
s.value1b(_v);
}
};
class DerivedPrivateBase: public BasePrivateSerialize {
class DerivedPrivateBase : public BasePrivateSerialize
{
public:
explicit DerivedPrivateBase(uint8_t v) : BasePrivateSerialize(v) {}
uint8_t z{};
explicit DerivedPrivateBase(uint8_t v)
: BasePrivateSerialize(v)
{
}
uint8_t z{};
};
template <typename S>
void serialize(S& s, DerivedPrivateBase& o) {
//use lambda for base serialization
s.ext(o, BaseClass<BasePrivateSerialize>{}, [](S& s, BasePrivateSerialize& b) {
s.object(b);
});
s.value1b(o.z);
template<typename S>
void
serialize(S& s, DerivedPrivateBase& o)
{
// use lambda for base serialization
s.ext(o,
BaseClass<BasePrivateSerialize>{},
[](S& s, BasePrivateSerialize& b) { s.object(b); });
s.value1b(o.z);
}
struct BaseNonMemberSerialize {
uint8_t x{};
struct BaseNonMemberSerialize
{
uint8_t x{};
};
template <typename S>
void serialize(S& s, BaseNonMemberSerialize& o) {
s.value1b(o.x);
template<typename S>
void
serialize(S& s, BaseNonMemberSerialize& o)
{
s.value1b(o.x);
}
struct DerivedMemberSerialize: public BaseNonMemberSerialize {
uint8_t z{};
template <typename S>
void serialize(S& s) {
s.ext(*this, BaseClass<BaseNonMemberSerialize>{});
s.value1b(z);
}
struct DerivedMemberSerialize : public BaseNonMemberSerialize
{
uint8_t z{};
template<typename S>
void serialize(S& s)
{
s.ext(*this, BaseClass<BaseNonMemberSerialize>{});
s.value1b(z);
}
};
//explicitly select serialize functions, for types that has ambiguous serialize functions
// explicitly select serialize functions, for types that has ambiguous serialize
// functions
namespace bitsery {
template <>
struct SelectSerializeFnc<DerivedPrivateBase>:UseNonMemberFnc {};
template <>
struct SelectSerializeFnc<DerivedMemberSerialize>:UseMemberFnc {};
}
TEST(SerializeExtensionInheritance, WhenDerivedClassHasAmbiguousSerializeFunctionThenExplicitlySelectSpecialization) {
DerivedPrivateBase data1{43};
data1.z = 87;
DerivedMemberSerialize data2{};
data2.x = 71;
data2.z = 22;
DerivedPrivateBase res1{0};
DerivedMemberSerialize res2{};
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(data1);
ctx.createSerializer(inherCtxSer).object(data2);
ctx.createDeserializer(inherCtxDes).object(res1);
ctx.createDeserializer(inherCtxDes).object(res2);
EXPECT_THAT(res1.getX(), Eq(data1.getX()));
EXPECT_THAT(res1.z, Eq(data1.z));
EXPECT_THAT(res2.x, Eq(data2.x));
EXPECT_THAT(res2.z, Eq(data2.z));
}
struct AbstractBase {
uint8_t x{};
virtual void exec() = 0;
virtual ~AbstractBase() = default;
template <typename S>
void serialize(S& s) {
s.value1b(x);
}
template<>
struct SelectSerializeFnc<DerivedPrivateBase> : UseNonMemberFnc
{
};
struct ImplementedBase:AbstractBase {
uint8_t y{};
void exec() override {}
template<>
struct SelectSerializeFnc<DerivedMemberSerialize> : UseMemberFnc
{
};
}
template <typename S>
void serialize(S& s) {
s.ext(*this, BaseClass<AbstractBase>{});
s.value1b(y);
}
TEST(
SerializeExtensionInheritance,
WhenDerivedClassHasAmbiguousSerializeFunctionThenExplicitlySelectSpecialization)
{
DerivedPrivateBase data1{ 43 };
data1.z = 87;
DerivedMemberSerialize data2{};
data2.x = 71;
data2.z = 22;
DerivedPrivateBase res1{ 0 };
DerivedMemberSerialize res2{};
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(data1);
ctx.createSerializer(inherCtxSer).object(data2);
ctx.createDeserializer(inherCtxDes).object(res1);
ctx.createDeserializer(inherCtxDes).object(res2);
EXPECT_THAT(res1.getX(), Eq(data1.getX()));
EXPECT_THAT(res1.z, Eq(data1.z));
EXPECT_THAT(res2.x, Eq(data2.x));
EXPECT_THAT(res2.z, Eq(data2.z));
}
struct AbstractBase
{
uint8_t x{};
virtual void exec() = 0;
virtual ~AbstractBase() = default;
template<typename S>
void serialize(S& s)
{
s.value1b(x);
}
};
TEST(SerializeExtensionInheritance, CanSerializeAbstractClass) {
ImplementedBase data{};
data.x = 4;
data.y = 2;
data.exec();
ImplementedBase res{};
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(data);
ctx.createDeserializer(inherCtxDes).object(res);
EXPECT_THAT(res.x, Eq(data.x));
EXPECT_THAT(res.y, Eq(data.y));
struct ImplementedBase : AbstractBase
{
uint8_t y{};
void exec() override {}
template<typename S>
void serialize(S& s)
{
s.ext(*this, BaseClass<AbstractBase>{});
s.value1b(y);
}
};
TEST(SerializeExtensionInheritance, CanSerializeAbstractClass)
{
ImplementedBase data{};
data.x = 4;
data.y = 2;
data.exec();
ImplementedBase res{};
SerContext ctx{};
bitsery::ext::InheritanceContext inherCtxSer{};
bitsery::ext::InheritanceContext inherCtxDes{};
ctx.createSerializer(inherCtxSer).object(data);
ctx.createDeserializer(inherCtxDes).object(res);
EXPECT_THAT(res.x, Eq(data.x));
EXPECT_THAT(res.y, Eq(data.y));
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +1,30 @@
//MIT License
// MIT License
//
//Copyright (c) 2017 Mindaugas Vinkelis
// Copyright (c) 2017 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <bitsery/ext/inheritance.h>
#include <bitsery/ext/pointer.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using bitsery::ext::BaseClass;
using bitsery::ext::VirtualBaseClass;
@@ -35,294 +34,342 @@ using bitsery::ext::PointerLinkingContext;
using bitsery::ext::PolymorphicContext;
using bitsery::ext::StandardRTTI;
using bitsery::ext::PointerOwner;
using bitsery::ext::PointerObserver;
using bitsery::ext::PointerOwner;
using bitsery::ext::ReferencedByPointer;
using testing::Eq;
using TContext = std::tuple<PointerLinkingContext, InheritanceContext, PolymorphicContext<StandardRTTI>>;
using TContext = std::tuple<PointerLinkingContext,
InheritanceContext,
PolymorphicContext<StandardRTTI>>;
using SerContext = BasicSerializationContext<TContext>;
//this is useful for PolymorphicContext to bind classes to serializer/deserializer
// this is useful for PolymorphicContext to bind classes to
// serializer/deserializer
using TSerializer = typename SerContext::TSerializer;
using TDeserializer = typename SerContext::TDeserializer;
/*
* base class
*/
struct Base {
uint8_t x{};
struct Base
{
uint8_t x{};
virtual ~Base() = default;
virtual ~Base() = default;
};
template<typename S>
void serialize(S &s, Base &o) {
s.value1b(o.x);
void
serialize(S& s, Base& o)
{
s.value1b(o.x);
}
struct Derived1 : virtual Base {
uint8_t y1{};
struct Derived1 : virtual Base
{
uint8_t y1{};
};
template<typename S>
void serialize(S &s, Derived1 &o) {
s.ext(o, VirtualBaseClass<Base>{});
s.value1b(o.y1);
void
serialize(S& s, Derived1& o)
{
s.ext(o, VirtualBaseClass<Base>{});
s.value1b(o.y1);
}
struct Derived2 : virtual Base {
uint8_t y2{};
struct Derived2 : virtual Base
{
uint8_t y2{};
};
template<typename S>
void serialize(S &s, Derived2 &o) {
s.ext(o, VirtualBaseClass<Base>{});
s.value1b(o.y2);
void
serialize(S& s, Derived2& o)
{
s.ext(o, VirtualBaseClass<Base>{});
s.value1b(o.y2);
}
struct MultipleVirtualInheritance : Derived1, Derived2 {
int8_t z{};
struct MultipleVirtualInheritance
: Derived1
, Derived2
{
int8_t z{};
MultipleVirtualInheritance() = default;
MultipleVirtualInheritance() = default;
MultipleVirtualInheritance(uint8_t x_, uint8_t y1_, uint8_t y2_, int8_t z_) {
x = x_;
y1 = y1_;
y2 = y2_;
z = z_;
}
template<typename S>
void serialize(S &s) {
s.ext(*this, BaseClass<Derived1>{});
s.ext(*this, BaseClass<Derived2>{});
s.value1b(z);
}
MultipleVirtualInheritance(uint8_t x_, uint8_t y1_, uint8_t y2_, int8_t z_)
{
x = x_;
y1 = y1_;
y2 = y2_;
z = z_;
}
template<typename S>
void serialize(S& s)
{
s.ext(*this, BaseClass<Derived1>{});
s.ext(*this, BaseClass<Derived2>{});
s.value1b(z);
}
};
//this class has no relationships specified via PolymorphicBaseClass
struct NoRelationshipSpecifiedDerived : Base {
};
// this class has no relationships specified via PolymorphicBaseClass
struct NoRelationshipSpecifiedDerived : Base
{};
//these classes will be used to "cheat" a little bit when testing deserialization flows
struct BaseClone {
uint8_t x{};
// these classes will be used to "cheat" a little bit when testing
// deserialization flows
struct BaseClone
{
uint8_t x{};
virtual ~BaseClone() = default;
virtual ~BaseClone() = default;
};
template<typename S>
void serialize(S &s, BaseClone &o) {
s.value1b(o.x);
void
serialize(S& s, BaseClone& o)
{
s.value1b(o.x);
}
//define relationships between base class and derived classes for runtime polymorphism
// define relationships between base class and derived classes for runtime
// polymorphism
namespace bitsery {
namespace ext {
namespace ext {
template<>
struct PolymorphicBaseClass<Base> : PolymorphicDerivedClasses<Derived1, Derived2> {
};
// this is commented on purpose, to test scenario when base class is registered (Base)
// but using instance of Derived1 which is not registered as base
// template<>
// struct PolymorphicBaseClass<Derived1> : PolymorphicDerivedClasses<MultipleVirtualInheritance> {
// };
template<>
struct PolymorphicBaseClass<Derived2> : PolymorphicDerivedClasses<MultipleVirtualInheritance> {
};
}
}
class SerializeExtensionPointerPolymorphicTypes : public testing::Test {
public:
TContext plctx{};
SerContext sctx{};
typename SerContext::TSerializer& createSerializer() {
auto& res = sctx.createSerializer(plctx);
std::get<2>(plctx).clear();
//bind serializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TSerializer>(bitsery::ext::PolymorphicClassesList<Base>{});
return res;
}
typename SerContext::TDeserializer& createDeserializer() {
auto& res = sctx.createDeserializer(plctx);
std::get<2>(plctx).clear();
//bind deserializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TDeserializer>(bitsery::ext::PolymorphicClassesList<Base>{});
return res;
}
bool isPointerContextValid() {
return std::get<0>(plctx).isValid();
}
virtual void TearDown() override {
EXPECT_TRUE(isPointerContextValid());
}
template<>
struct PolymorphicBaseClass<Base>
: PolymorphicDerivedClasses<Derived1, Derived2>
{
};
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data0Result0) {
Base *baseData = nullptr;
createSerializer().ext(baseData, PointerOwner{});
Base *baseRes = nullptr;
createDeserializer().ext(baseRes, PointerOwner{});
// this is commented on purpose, to test scenario when base class is registered
// (Base) but using instance of Derived1 which is not registered as base
// template<>
// struct PolymorphicBaseClass<Derived1> :
// PolymorphicDerivedClasses<MultipleVirtualInheritance> {
// };
EXPECT_THAT(baseRes, ::testing::IsNull());
EXPECT_THAT(baseData, ::testing::IsNull());
template<>
struct PolymorphicBaseClass<Derived2>
: PolymorphicDerivedClasses<MultipleVirtualInheritance>
{
};
}
}
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data0Result1) {
Base *baseData = nullptr;
createSerializer().ext(baseData, PointerOwner{});
class SerializeExtensionPointerPolymorphicTypes : public testing::Test
{
public:
TContext plctx{};
SerContext sctx{};
Base *baseRes = new Derived1{};
createDeserializer().ext(baseRes, PointerOwner{});
typename SerContext::TSerializer& createSerializer()
{
auto& res = sctx.createSerializer(plctx);
std::get<2>(plctx).clear();
// bind serializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TSerializer>(
bitsery::ext::PolymorphicClassesList<Base>{});
return res;
}
EXPECT_THAT(baseRes, ::testing::IsNull());
EXPECT_THAT(baseData, ::testing::IsNull());
typename SerContext::TDeserializer& createDeserializer()
{
auto& res = sctx.createDeserializer(plctx);
std::get<2>(plctx).clear();
// bind deserializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TDeserializer>(
bitsery::ext::PolymorphicClassesList<Base>{});
return res;
}
bool isPointerContextValid() { return std::get<0>(plctx).isValid(); }
virtual void TearDown() override { EXPECT_TRUE(isPointerContextValid()); }
};
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data0Result0)
{
Base* baseData = nullptr;
createSerializer().ext(baseData, PointerOwner{});
Base* baseRes = nullptr;
createDeserializer().ext(baseRes, PointerOwner{});
EXPECT_THAT(baseRes, ::testing::IsNull());
EXPECT_THAT(baseData, ::testing::IsNull());
}
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data1Result0) {
Derived1 d1{};
d1.x = 3;
d1.y1 = 78;
Base *baseData = &d1;
createSerializer().ext(baseData, PointerOwner{});
Base *baseRes = nullptr;
createDeserializer().ext(baseRes, PointerOwner{});
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data0Result1)
{
Base* baseData = nullptr;
createSerializer().ext(baseData, PointerOwner{});
auto *data = dynamic_cast<Derived1 *>(baseData);
auto *res = dynamic_cast<Derived1 *>(baseRes);
Base* baseRes = new Derived1{};
createDeserializer().ext(baseRes, PointerOwner{});
EXPECT_THAT(baseRes, ::testing::NotNull());
EXPECT_THAT(data, ::testing::NotNull());
EXPECT_THAT(res, ::testing::NotNull());
EXPECT_THAT(res->x, Eq(data->x));
EXPECT_THAT(res->y1, Eq(data->y1));
delete baseRes;
EXPECT_THAT(baseRes, ::testing::IsNull());
EXPECT_THAT(baseData, ::testing::IsNull());
}
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data1Result1) {
Derived1 d1{};
d1.x = 3;
d1.y1 = 78;
Base *baseData = &d1;
createSerializer().ext(baseData, PointerOwner{});
Base *baseRes = &d1;
createDeserializer().ext(baseRes, PointerOwner{});
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data1Result0)
{
Derived1 d1{};
d1.x = 3;
d1.y1 = 78;
Base* baseData = &d1;
createSerializer().ext(baseData, PointerOwner{});
Base* baseRes = nullptr;
createDeserializer().ext(baseRes, PointerOwner{});
auto *data = dynamic_cast<Derived1 *>(baseData);
auto *res = dynamic_cast<Derived1 *>(baseRes);
auto* data = dynamic_cast<Derived1*>(baseData);
auto* res = dynamic_cast<Derived1*>(baseRes);
EXPECT_THAT(baseRes, ::testing::NotNull());
EXPECT_THAT(data, ::testing::NotNull());
EXPECT_THAT(res, ::testing::NotNull());
EXPECT_THAT(res->x, Eq(data->x));
EXPECT_THAT(res->y1, Eq(data->y1));
EXPECT_THAT(baseRes, ::testing::NotNull());
EXPECT_THAT(data, ::testing::NotNull());
EXPECT_THAT(res, ::testing::NotNull());
EXPECT_THAT(res->x, Eq(data->x));
EXPECT_THAT(res->y1, Eq(data->y1));
delete baseRes;
}
TEST_F(SerializeExtensionPointerPolymorphicTypes, ComplexTypeWithVirtualInheritanceData1Result0) {
MultipleVirtualInheritance md1{};
md1.x = 3;
md1.y1 = 78;
md1.y2 = 14;
md1.z = -33;
Base *baseData = &md1;
createSerializer().ext(baseData, PointerOwner{});
Base *baseRes = nullptr;
createDeserializer().ext(baseRes, PointerOwner{});
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data1Result1)
{
Derived1 d1{};
d1.x = 3;
d1.y1 = 78;
Base* baseData = &d1;
createSerializer().ext(baseData, PointerOwner{});
Base* baseRes = &d1;
createDeserializer().ext(baseRes, PointerOwner{});
auto *data = dynamic_cast<MultipleVirtualInheritance *>(baseData);
auto *res = dynamic_cast<MultipleVirtualInheritance *>(baseRes);
auto* data = dynamic_cast<Derived1*>(baseData);
auto* res = dynamic_cast<Derived1*>(baseRes);
EXPECT_THAT(baseRes, ::testing::NotNull());
EXPECT_THAT(data, ::testing::NotNull());
EXPECT_THAT(res, ::testing::NotNull());
EXPECT_THAT(res->x, Eq(data->x));
EXPECT_THAT(res->y1, Eq(data->y1));
EXPECT_THAT(res->y2, Eq(data->y2));
EXPECT_THAT(res->z, Eq(data->z));
delete baseRes;
EXPECT_THAT(baseRes, ::testing::NotNull());
EXPECT_THAT(data, ::testing::NotNull());
EXPECT_THAT(res, ::testing::NotNull());
EXPECT_THAT(res->x, Eq(data->x));
EXPECT_THAT(res->y1, Eq(data->y1));
}
TEST_F(SerializeExtensionPointerPolymorphicTypes, WhenResultIsDifferentTypeThenRecreate) {
MultipleVirtualInheritance md1{};
md1.x = 3;
md1.y1 = 78;
md1.y2 = 14;
md1.z = -33;
Base *baseData = &md1;
createSerializer().ext(baseData, PointerOwner{});
Base *baseRes = new Derived1{};
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance *>(baseRes), ::testing::IsNull());
createDeserializer().ext(baseRes, PointerOwner{});
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance *>(baseRes), ::testing::NotNull());
delete baseRes;
TEST_F(SerializeExtensionPointerPolymorphicTypes,
ComplexTypeWithVirtualInheritanceData1Result0)
{
MultipleVirtualInheritance md1{};
md1.x = 3;
md1.y1 = 78;
md1.y2 = 14;
md1.z = -33;
Base* baseData = &md1;
createSerializer().ext(baseData, PointerOwner{});
Base* baseRes = nullptr;
createDeserializer().ext(baseRes, PointerOwner{});
auto* data = dynamic_cast<MultipleVirtualInheritance*>(baseData);
auto* res = dynamic_cast<MultipleVirtualInheritance*>(baseRes);
EXPECT_THAT(baseRes, ::testing::NotNull());
EXPECT_THAT(data, ::testing::NotNull());
EXPECT_THAT(res, ::testing::NotNull());
EXPECT_THAT(res->x, Eq(data->x));
EXPECT_THAT(res->y1, Eq(data->y1));
EXPECT_THAT(res->y2, Eq(data->y2));
EXPECT_THAT(res->z, Eq(data->z));
delete baseRes;
}
TEST_F(SerializeExtensionPointerPolymorphicTypes,
WhenResultIsDifferentTypeThenRecreate)
{
MultipleVirtualInheritance md1{};
md1.x = 3;
md1.y1 = 78;
md1.y2 = 14;
md1.z = -33;
Base* baseData = &md1;
createSerializer().ext(baseData, PointerOwner{});
Base* baseRes = new Derived1{};
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance*>(baseRes),
::testing::IsNull());
createDeserializer().ext(baseRes, PointerOwner{});
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance*>(baseRes),
::testing::NotNull());
delete baseRes;
}
#ifndef NDEBUG
TEST_F(SerializeExtensionPointerPolymorphicTypes,
WhenSerializingDerivedTypeWithoutSpecifiedRelationshipsWithBaseThenAssert) {
TEST_F(
SerializeExtensionPointerPolymorphicTypes,
WhenSerializingDerivedTypeWithoutSpecifiedRelationshipsWithBaseThenAssert)
{
NoRelationshipSpecifiedDerived md1;//this class has no relationships specified via PolymorphicBaseClass
Base *baseData = &md1;
EXPECT_DEATH(createSerializer().ext(baseData, PointerOwner{}), "");
NoRelationshipSpecifiedDerived
md1; // this class has no relationships specified via PolymorphicBaseClass
Base* baseData = &md1;
EXPECT_DEATH(createSerializer().ext(baseData, PointerOwner{}), "");
}
TEST_F(SerializeExtensionPointerPolymorphicTypes,
WhenDeserializingDerivedTypeNotRegisteredWithPolymorphicContextThenAssert) {
TEST_F(
SerializeExtensionPointerPolymorphicTypes,
WhenDeserializingDerivedTypeNotRegisteredWithPolymorphicContextThenAssert)
{
Derived1 d1{};
Base *baseData = &d1;
createSerializer().ext(baseData, PointerOwner{});
Derived1 d1{};
Base* baseData = &d1;
createSerializer().ext(baseData, PointerOwner{});
BaseClone *baseRes = nullptr; //this class is not registered
EXPECT_DEATH(createDeserializer().ext(baseRes, PointerOwner{}), "");
BaseClone* baseRes = nullptr; // this class is not registered
EXPECT_DEATH(createDeserializer().ext(baseRes, PointerOwner{}), "");
}
#endif
TEST_F(SerializeExtensionPointerPolymorphicTypes,
CompileTimeTypeIsDerivedAndReachableFromBaseRegisteredWithPolymorphicContext) {
TEST_F(
SerializeExtensionPointerPolymorphicTypes,
CompileTimeTypeIsDerivedAndReachableFromBaseRegisteredWithPolymorphicContext)
{
MultipleVirtualInheritance md;
Derived2 *derivedData = &md;//this class is not registered via PolymorphicContext
createSerializer().ext(derivedData, PointerOwner{});
Derived2 *derivedRes = new Derived2{};
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance *>(derivedRes), ::testing::IsNull());
createDeserializer().ext(derivedRes, PointerOwner{});
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance *>(derivedRes), ::testing::NotNull());
delete derivedRes;
MultipleVirtualInheritance md;
Derived2* derivedData =
&md; // this class is not registered via PolymorphicContext
createSerializer().ext(derivedData, PointerOwner{});
Derived2* derivedRes = new Derived2{};
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance*>(derivedRes),
::testing::IsNull());
createDeserializer().ext(derivedRes, PointerOwner{});
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance*>(derivedRes),
::testing::NotNull());
delete derivedRes;
}
TEST_F(SerializeExtensionPointerPolymorphicTypes,
WhenPolymorphicTypeNotFoundDuringDeserializionThenInvalidPointerError) {
WhenPolymorphicTypeNotFoundDuringDeserializionThenInvalidPointerError)
{
Derived1 d1{};
Base *baseData = &d1;
createSerializer().ext(baseData, PointerOwner{});
Derived1 d1{};
Base* baseData = &d1;
createSerializer().ext(baseData, PointerOwner{});
BaseClone *baseRes = nullptr; //this class will be registered, but it doesn't have relationships specified via PolymorphicBaseClass
auto& des = sctx.createDeserializer(plctx);
auto &pc = std::get<2>(plctx);
pc.clear();
pc.registerBasesList<SerContext::TDeserializer>(bitsery::ext::PolymorphicClassesList<BaseClone>{});
des.ext(baseRes, PointerOwner{});
EXPECT_THAT(sctx.des->adapter().error(), Eq(bitsery::ReaderError::InvalidPointer));
BaseClone* baseRes =
nullptr; // this class will be registered, but it doesn't have relationships
// specified via PolymorphicBaseClass
auto& des = sctx.createDeserializer(plctx);
auto& pc = std::get<2>(plctx);
pc.clear();
pc.registerBasesList<SerContext::TDeserializer>(
bitsery::ext::PolymorphicClassesList<BaseClone>{});
des.ext(baseRes, PointerOwner{});
EXPECT_THAT(sctx.des->adapter().error(),
Eq(bitsery::ReaderError::InvalidPointer));
}

View File

@@ -1,32 +1,31 @@
//MIT License
// MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
// Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <bitsery/ext/inheritance.h>
#include <bitsery/ext/pointer.h>
#include <bitsery/ext/std_smart_ptr.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#include <gmock/gmock.h>
using bitsery::ext::BaseClass;
using bitsery::ext::VirtualBaseClass;
@@ -36,332 +35,396 @@ using bitsery::ext::PointerLinkingContext;
using bitsery::ext::PolymorphicContext;
using bitsery::ext::StandardRTTI;
using bitsery::ext::PointerOwner;
using bitsery::ext::PointerObserver;
using bitsery::ext::PointerOwner;
using bitsery::ext::ReferencedByPointer;
using bitsery::ext::StdSmartPtr;
using testing::Eq;
using TContext = std::tuple<PointerLinkingContext, InheritanceContext, PolymorphicContext<StandardRTTI>>;
using TContext = std::tuple<PointerLinkingContext,
InheritanceContext,
PolymorphicContext<StandardRTTI>>;
using SerContext = BasicSerializationContext<TContext>;
//this is useful for PolymorphicContext to bind classes to serializer/deserializer
// this is useful for PolymorphicContext to bind classes to
// serializer/deserializer
using TSerializer = typename SerContext::TSerializer;
using TDeserializer = typename SerContext::TDeserializer;
/*
* base class
*/
struct Base {
Base() = default;
struct Base
{
Base() = default;
explicit Base(uint64_t v) : x{v} {}
explicit Base(uint64_t v)
: x{ v }
{
}
uint64_t x{};
uint64_t x{};
virtual ~Base() = default;
virtual ~Base() = default;
};
template<typename S>
void serialize(S& s, Base& o) {
s.value8b(o.x);
void
serialize(S& s, Base& o)
{
s.value8b(o.x);
}
struct Derived1 : Base {
Derived1() = default;
struct Derived1 : Base
{
Derived1() = default;
Derived1(uint64_t x_, uint64_t y_) : Base{x_}, y1{y_} {}
Derived1(uint64_t x_, uint64_t y_)
: Base{ x_ }
, y1{ y_ }
{
}
friend bool operator==(const Derived1& lhs, const Derived1& rhs) {
return lhs.x == rhs.x && lhs.y1 == rhs.y1;
}
friend bool operator==(const Derived1& lhs, const Derived1& rhs)
{
return lhs.x == rhs.x && lhs.y1 == rhs.y1;
}
uint64_t y1{};
uint64_t y1{};
};
template<typename S>
void serialize(S& s, Derived1& o) {
s.ext(o, BaseClass<Base>{});
s.value8b(o.y1);
void
serialize(S& s, Derived1& o)
{
s.ext(o, BaseClass<Base>{});
s.value8b(o.y1);
}
struct Derived2 : Base {
uint64_t y1{};
uint64_t y2{};
struct Derived2 : Base
{
uint64_t y1{};
uint64_t y2{};
};
template<typename S>
void serialize(S& s, Derived2& o) {
s.ext(o, BaseClass<Base>{});
s.value8b(o.y1);
s.value8b(o.y2);
void
serialize(S& s, Derived2& o)
{
s.ext(o, BaseClass<Base>{});
s.value8b(o.y1);
s.value8b(o.y2);
}
// polymorphic structure that contains polymorphic pointer, to test memory resource propagation
struct PolyPtrWithPolyPtrBase {
std::unique_ptr<Base> ptr{};
// polymorphic structure that contains polymorphic pointer, to test memory
// resource propagation
struct PolyPtrWithPolyPtrBase
{
std::unique_ptr<Base> ptr{};
virtual ~PolyPtrWithPolyPtrBase() = default;
virtual ~PolyPtrWithPolyPtrBase() = default;
};
template<typename S>
void serialize(S& s, PolyPtrWithPolyPtrBase& o) {
s.ext(o.ptr, StdSmartPtr{});
void
serialize(S& s, PolyPtrWithPolyPtrBase& o)
{
s.ext(o.ptr, StdSmartPtr{});
}
struct DerivedPolyPtrWithPolyPtr : PolyPtrWithPolyPtrBase {
};
struct DerivedPolyPtrWithPolyPtr : PolyPtrWithPolyPtrBase
{};
template<typename S>
void serialize(S& s, DerivedPolyPtrWithPolyPtr& o) {
s.ext(o.ptr, StdSmartPtr{});
void
serialize(S& s, DerivedPolyPtrWithPolyPtr& o)
{
s.ext(o.ptr, StdSmartPtr{});
}
//define relationships between base class and derived classes for runtime polymorphism
// define relationships between base class and derived classes for runtime
// polymorphism
namespace bitsery {
namespace ext {
namespace ext {
template<>
struct PolymorphicBaseClass<Base> : PolymorphicDerivedClasses<Derived1, Derived2> {
};
template<>
struct PolymorphicBaseClass<Base>
: PolymorphicDerivedClasses<Derived1, Derived2>
{
};
template<>
struct PolymorphicBaseClass<PolyPtrWithPolyPtrBase> : PolymorphicDerivedClasses<DerivedPolyPtrWithPolyPtr> {
};
template<>
struct PolymorphicBaseClass<PolyPtrWithPolyPtrBase>
: PolymorphicDerivedClasses<DerivedPolyPtrWithPolyPtr>
{
};
}
}
}
// this class is for testing
struct TestAllocInfo {
void* ptr;
size_t bytes;
size_t alignment;
size_t typeId;
struct TestAllocInfo
{
void* ptr;
size_t bytes;
size_t alignment;
size_t typeId;
friend bool operator==(const TestAllocInfo& lhs, const TestAllocInfo& rhs) {
return std::tie(lhs.ptr, lhs.bytes, lhs.alignment, lhs.typeId) ==
std::tie(rhs.ptr, rhs.bytes, rhs.alignment, rhs.typeId);
}
friend bool operator==(const TestAllocInfo& lhs, const TestAllocInfo& rhs)
{
return std::tie(lhs.ptr, lhs.bytes, lhs.alignment, lhs.typeId) ==
std::tie(rhs.ptr, rhs.bytes, rhs.alignment, rhs.typeId);
}
};
struct MemResourceForTest : public bitsery::ext::MemResourceBase {
struct MemResourceForTest : public bitsery::ext::MemResourceBase
{
void* allocate(size_t bytes, size_t alignment, size_t typeId) override {
const auto res = bitsery::ext::MemResourceNewDelete{}.allocate(bytes, alignment, typeId);
allocs.push_back({res, bytes, alignment, typeId});
return res;
}
void* allocate(size_t bytes, size_t alignment, size_t typeId) override
{
const auto res =
bitsery::ext::MemResourceNewDelete{}.allocate(bytes, alignment, typeId);
allocs.push_back({ res, bytes, alignment, typeId });
return res;
}
void deallocate(void* ptr, size_t bytes, size_t alignment, size_t typeId) noexcept override {
deallocs.push_back({ptr, bytes, alignment, typeId});
bitsery::ext::MemResourceNewDelete{}.deallocate(ptr, bytes, alignment, typeId);
}
void deallocate(void* ptr,
size_t bytes,
size_t alignment,
size_t typeId) noexcept override
{
deallocs.push_back({ ptr, bytes, alignment, typeId });
bitsery::ext::MemResourceNewDelete{}.deallocate(
ptr, bytes, alignment, typeId);
}
std::vector<TestAllocInfo> allocs{};
std::vector<TestAllocInfo> deallocs{};
std::vector<TestAllocInfo> allocs{};
std::vector<TestAllocInfo> deallocs{};
};
class SerializeExtensionPointerWithAllocator : public testing::Test {
class SerializeExtensionPointerWithAllocator : public testing::Test
{
public:
TContext plctx{};
SerContext sctx{};
TContext plctx{};
SerContext sctx{};
typename SerContext::TSerializer& createSerializer()
{
auto& res = sctx.createSerializer(plctx);
std::get<2>(plctx).clear();
// bind serializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TSerializer>(
bitsery::ext::PolymorphicClassesList<Base, PolyPtrWithPolyPtrBase>{});
return res;
}
typename SerContext::TSerializer& createSerializer() {
auto& res = sctx.createSerializer(plctx);
std::get<2>(plctx).clear();
//bind serializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TSerializer>(
bitsery::ext::PolymorphicClassesList<Base, PolyPtrWithPolyPtrBase>{});
return res;
}
typename SerContext::TDeserializer& createDeserializer()
{
auto& res = sctx.createDeserializer(plctx);
std::get<2>(plctx).clear();
// bind deserializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TDeserializer>(
bitsery::ext::PolymorphicClassesList<Base, PolyPtrWithPolyPtrBase>{});
return res;
}
typename SerContext::TDeserializer& createDeserializer() {
auto& res = sctx.createDeserializer(plctx);
std::get<2>(plctx).clear();
//bind deserializer with classes
std::get<2>(plctx).registerBasesList<SerContext::TDeserializer>(
bitsery::ext::PolymorphicClassesList<Base, PolyPtrWithPolyPtrBase>{});
return res;
}
bool isPointerContextValid() { return std::get<0>(plctx).isValid(); }
bool isPointerContextValid() {
return std::get<0>(plctx).isValid();
}
virtual void TearDown() override {
EXPECT_TRUE(isPointerContextValid());
}
virtual void TearDown() override { EXPECT_TRUE(isPointerContextValid()); }
};
TEST_F(SerializeExtensionPointerWithAllocator, CanSetDefaultMemoryResourceInPointerLinkingContext) {
TEST_F(SerializeExtensionPointerWithAllocator,
CanSetDefaultMemoryResourceInPointerLinkingContext)
{
MemResourceForTest memRes{};
std::get<0>(plctx).setMemResource(&memRes);
MemResourceForTest memRes{};
std::get<0>(plctx).setMemResource(&memRes);
Base* baseData = new Derived1{2, 1};
createSerializer().ext(baseData, PointerOwner{});
Base* baseRes = nullptr;
createDeserializer().ext(baseRes, PointerOwner{});
Base* baseData = new Derived1{ 2, 1 };
createSerializer().ext(baseData, PointerOwner{});
Base* baseRes = nullptr;
createDeserializer().ext(baseRes, PointerOwner{});
auto dData = dynamic_cast<Derived1*>(baseData);
auto dRes = dynamic_cast<Derived1*>(baseRes);
auto dData = dynamic_cast<Derived1*>(baseData);
auto dRes = dynamic_cast<Derived1*>(baseRes);
EXPECT_THAT(dRes, ::testing::NotNull());
EXPECT_THAT(*dData, *dRes);
EXPECT_THAT(memRes.allocs.size(), Eq(1u));
EXPECT_THAT(memRes.allocs[0].bytes, Eq(sizeof(Derived1)));
EXPECT_THAT(memRes.allocs[0].alignment, Eq(alignof(Derived1)));
EXPECT_THAT(memRes.allocs[0].typeId, Eq(bitsery::ext::StandardRTTI::get<Derived1>()));
EXPECT_THAT(memRes.deallocs.size(), Eq(0u));
delete dData;
delete dRes;
EXPECT_THAT(dRes, ::testing::NotNull());
EXPECT_THAT(*dData, *dRes);
EXPECT_THAT(memRes.allocs.size(), Eq(1u));
EXPECT_THAT(memRes.allocs[0].bytes, Eq(sizeof(Derived1)));
EXPECT_THAT(memRes.allocs[0].alignment, Eq(alignof(Derived1)));
EXPECT_THAT(memRes.allocs[0].typeId,
Eq(bitsery::ext::StandardRTTI::get<Derived1>()));
EXPECT_THAT(memRes.deallocs.size(), Eq(0u));
delete dData;
delete dRes;
}
TEST_F(SerializeExtensionPointerWithAllocator, CorrectlyDeallocatesPreviousInstance) {
MemResourceForTest memRes{};
std::get<0>(plctx).setMemResource(&memRes);
TEST_F(SerializeExtensionPointerWithAllocator,
CorrectlyDeallocatesPreviousInstance)
{
MemResourceForTest memRes{};
std::get<0>(plctx).setMemResource(&memRes);
Base* baseData = new Derived1{2, 1};
createSerializer().ext(baseData, PointerOwner{});
Base* baseRes = new Derived2;
createDeserializer().ext(baseRes, PointerOwner{});
Base* baseData = new Derived1{ 2, 1 };
createSerializer().ext(baseData, PointerOwner{});
Base* baseRes = new Derived2;
createDeserializer().ext(baseRes, PointerOwner{});
auto dData = dynamic_cast<Derived1*>(baseData);
auto dRes = dynamic_cast<Derived1*>(baseRes);
auto dData = dynamic_cast<Derived1*>(baseData);
auto dRes = dynamic_cast<Derived1*>(baseRes);
EXPECT_THAT(dRes, ::testing::NotNull());
EXPECT_THAT(*dData, *dRes);
EXPECT_THAT(memRes.allocs.size(), Eq(1u));
EXPECT_THAT(memRes.allocs[0].bytes, Eq(sizeof(Derived1)));
EXPECT_THAT(memRes.allocs[0].alignment, Eq(alignof(Derived1)));
EXPECT_THAT(memRes.allocs[0].typeId, Eq(bitsery::ext::StandardRTTI::get<Derived1>()));
EXPECT_THAT(memRes.deallocs.size(), Eq(1u));
EXPECT_THAT(memRes.deallocs[0].bytes, Eq(sizeof(Derived2)));
EXPECT_THAT(memRes.deallocs[0].alignment, Eq(alignof(Derived2)));
EXPECT_THAT(memRes.deallocs[0].typeId, Eq(bitsery::ext::StandardRTTI::get<Derived2>()));
EXPECT_THAT(dRes, ::testing::NotNull());
EXPECT_THAT(*dData, *dRes);
EXPECT_THAT(memRes.allocs.size(), Eq(1u));
EXPECT_THAT(memRes.allocs[0].bytes, Eq(sizeof(Derived1)));
EXPECT_THAT(memRes.allocs[0].alignment, Eq(alignof(Derived1)));
EXPECT_THAT(memRes.allocs[0].typeId,
Eq(bitsery::ext::StandardRTTI::get<Derived1>()));
EXPECT_THAT(memRes.deallocs.size(), Eq(1u));
EXPECT_THAT(memRes.deallocs[0].bytes, Eq(sizeof(Derived2)));
EXPECT_THAT(memRes.deallocs[0].alignment, Eq(alignof(Derived2)));
EXPECT_THAT(memRes.deallocs[0].typeId,
Eq(bitsery::ext::StandardRTTI::get<Derived2>()));
delete dData;
delete dRes;
delete dData;
delete dRes;
}
TEST_F(SerializeExtensionPointerWithAllocator, DefaultDeleterIsNotUsedForStdUniquePtr) {
MemResourceForTest memRes{};
std::get<0>(plctx).setMemResource(&memRes);
TEST_F(SerializeExtensionPointerWithAllocator,
DefaultDeleterIsNotUsedForStdUniquePtr)
{
MemResourceForTest memRes{};
std::get<0>(plctx).setMemResource(&memRes);
std::unique_ptr<Base> baseData{};
createSerializer().ext(baseData, StdSmartPtr{});
auto baseRes = std::unique_ptr<Base>(new Derived1{45, 64});
createDeserializer().ext(baseRes, StdSmartPtr{});
std::unique_ptr<Base> baseData{};
createSerializer().ext(baseData, StdSmartPtr{});
auto baseRes = std::unique_ptr<Base>(new Derived1{ 45, 64 });
createDeserializer().ext(baseRes, StdSmartPtr{});
EXPECT_THAT(memRes.allocs.size(), Eq(0u));
EXPECT_THAT(memRes.deallocs.size(), Eq(1u));
EXPECT_THAT(memRes.deallocs[0].bytes, Eq(sizeof(Derived1)));
EXPECT_THAT(memRes.deallocs[0].alignment, Eq(alignof(Derived1)));
EXPECT_THAT(memRes.deallocs[0].typeId, Eq(bitsery::ext::StandardRTTI::get<Derived1>()));
EXPECT_THAT(memRes.allocs.size(), Eq(0u));
EXPECT_THAT(memRes.deallocs.size(), Eq(1u));
EXPECT_THAT(memRes.deallocs[0].bytes, Eq(sizeof(Derived1)));
EXPECT_THAT(memRes.deallocs[0].alignment, Eq(alignof(Derived1)));
EXPECT_THAT(memRes.deallocs[0].typeId,
Eq(bitsery::ext::StandardRTTI::get<Derived1>()));
}
struct CustomBaseDeleter {
void operator()(Base* obj) {
delete obj;
}
struct CustomBaseDeleter
{
void operator()(Base* obj) { delete obj; }
};
TEST_F(SerializeExtensionPointerWithAllocator, CustomDeleterIsNotUsedForStdUniquePtr) {
MemResourceForTest memRes{};
std::get<0>(plctx).setMemResource(&memRes);
TEST_F(SerializeExtensionPointerWithAllocator,
CustomDeleterIsNotUsedForStdUniquePtr)
{
MemResourceForTest memRes{};
std::get<0>(plctx).setMemResource(&memRes);
std::unique_ptr<Base, CustomBaseDeleter> baseData{};
createSerializer().ext(baseData, StdSmartPtr{});
auto baseRes = std::unique_ptr<Base, CustomBaseDeleter>(new Derived1{45, 64});
createDeserializer().ext(baseRes, StdSmartPtr{});
std::unique_ptr<Base, CustomBaseDeleter> baseData{};
createSerializer().ext(baseData, StdSmartPtr{});
auto baseRes =
std::unique_ptr<Base, CustomBaseDeleter>(new Derived1{ 45, 64 });
createDeserializer().ext(baseRes, StdSmartPtr{});
EXPECT_THAT(memRes.allocs.size(), Eq(0u));
EXPECT_THAT(memRes.deallocs.size(), Eq(1u));
EXPECT_THAT(memRes.deallocs[0].bytes, Eq(sizeof(Derived1)));
EXPECT_THAT(memRes.deallocs[0].alignment, Eq(alignof(Derived1)));
EXPECT_THAT(memRes.deallocs[0].typeId, Eq(bitsery::ext::StandardRTTI::get<Derived1>()));
EXPECT_THAT(memRes.allocs.size(), Eq(0u));
EXPECT_THAT(memRes.deallocs.size(), Eq(1u));
EXPECT_THAT(memRes.deallocs[0].bytes, Eq(sizeof(Derived1)));
EXPECT_THAT(memRes.deallocs[0].alignment, Eq(alignof(Derived1)));
EXPECT_THAT(memRes.deallocs[0].typeId,
Eq(bitsery::ext::StandardRTTI::get<Derived1>()));
}
TEST_F(SerializeExtensionPointerWithAllocator, CanSetMemResourcePerPointer)
{
MemResourceForTest memRes1{};
MemResourceForTest memRes2{};
std::get<0>(plctx).setMemResource(&memRes1);
TEST_F(SerializeExtensionPointerWithAllocator, CanSetMemResourcePerPointer) {
MemResourceForTest memRes1{};
MemResourceForTest memRes2{};
std::get<0>(plctx).setMemResource(&memRes1);
Base* baseData = new Derived1{ 2, 1 };
createSerializer().ext(
baseData, PointerOwner{ bitsery::ext::PointerType::Nullable, &memRes2 });
Base* baseRes = new Derived2;
createDeserializer().ext(
baseRes, PointerOwner{ bitsery::ext::PointerType::Nullable, &memRes2 });
Base* baseData = new Derived1{2, 1};
createSerializer().ext(baseData, PointerOwner{bitsery::ext::PointerType::Nullable, &memRes2});
Base* baseRes = new Derived2;
createDeserializer().ext(baseRes, PointerOwner{bitsery::ext::PointerType::Nullable, &memRes2});
auto dData = dynamic_cast<Derived1*>(baseData);
auto dRes = dynamic_cast<Derived1*>(baseRes);
auto dData = dynamic_cast<Derived1*>(baseData);
auto dRes = dynamic_cast<Derived1*>(baseRes);
EXPECT_THAT(dRes, ::testing::NotNull());
EXPECT_THAT(*dData, *dRes);
EXPECT_THAT(memRes1.allocs.size(), Eq(0u));
EXPECT_THAT(memRes1.deallocs.size(), Eq(0u));
EXPECT_THAT(memRes2.allocs.size(), Eq(1u));
EXPECT_THAT(memRes2.allocs[0].bytes, Eq(sizeof(Derived1)));
EXPECT_THAT(memRes2.allocs[0].alignment, Eq(alignof(Derived1)));
EXPECT_THAT(memRes2.allocs[0].typeId,
Eq(bitsery::ext::StandardRTTI::get<Derived1>()));
EXPECT_THAT(memRes2.deallocs.size(), Eq(1u));
EXPECT_THAT(memRes2.deallocs[0].bytes, Eq(sizeof(Derived2)));
EXPECT_THAT(memRes2.deallocs[0].alignment, Eq(alignof(Derived2)));
EXPECT_THAT(memRes2.deallocs[0].typeId,
Eq(bitsery::ext::StandardRTTI::get<Derived2>()));
EXPECT_THAT(dRes, ::testing::NotNull());
EXPECT_THAT(*dData, *dRes);
EXPECT_THAT(memRes1.allocs.size(), Eq(0u));
EXPECT_THAT(memRes1.deallocs.size(), Eq(0u));
EXPECT_THAT(memRes2.allocs.size(), Eq(1u));
EXPECT_THAT(memRes2.allocs[0].bytes, Eq(sizeof(Derived1)));
EXPECT_THAT(memRes2.allocs[0].alignment, Eq(alignof(Derived1)));
EXPECT_THAT(memRes2.allocs[0].typeId, Eq(bitsery::ext::StandardRTTI::get<Derived1>()));
EXPECT_THAT(memRes2.deallocs.size(), Eq(1u));
EXPECT_THAT(memRes2.deallocs[0].bytes, Eq(sizeof(Derived2)));
EXPECT_THAT(memRes2.deallocs[0].alignment, Eq(alignof(Derived2)));
EXPECT_THAT(memRes2.deallocs[0].typeId, Eq(bitsery::ext::StandardRTTI::get<Derived2>()));
delete dData;
delete dRes;
delete dData;
delete dRes;
}
TEST_F(SerializeExtensionPointerWithAllocator,
MemResourceSetPerPointerByDefaultDoNotPropagate)
{
MemResourceForTest memRes1{};
MemResourceForTest memRes2{};
std::get<0>(plctx).setMemResource(&memRes1);
TEST_F(SerializeExtensionPointerWithAllocator, MemResourceSetPerPointerByDefaultDoNotPropagate) {
MemResourceForTest memRes1{};
MemResourceForTest memRes2{};
std::get<0>(plctx).setMemResource(&memRes1);
auto data =
std::unique_ptr<PolyPtrWithPolyPtrBase>(new PolyPtrWithPolyPtrBase{});
data->ptr = std::unique_ptr<Base>(new Derived1{ 5, 6 });
createSerializer().ext(
data, StdSmartPtr{ bitsery::ext::PointerType::Nullable, &memRes2 });
auto data = std::unique_ptr<PolyPtrWithPolyPtrBase>(new PolyPtrWithPolyPtrBase{});
data->ptr = std::unique_ptr<Base>(new Derived1{5, 6});
createSerializer().ext(data, StdSmartPtr{bitsery::ext::PointerType::Nullable, &memRes2});
auto res =
std::unique_ptr<PolyPtrWithPolyPtrBase>(new DerivedPolyPtrWithPolyPtr{});
res->ptr = std::unique_ptr<Base>(new Derived2{});
createDeserializer().ext(
res, StdSmartPtr{ bitsery::ext::PointerType::Nullable, &memRes2 });
auto res = std::unique_ptr<PolyPtrWithPolyPtrBase>(new DerivedPolyPtrWithPolyPtr{});
res->ptr = std::unique_ptr<Base>(new Derived2{});
createDeserializer().ext(res, StdSmartPtr{bitsery::ext::PointerType::Nullable, &memRes2});
EXPECT_THAT(memRes1.allocs.size(), Eq(1u));
// Base* was destroyed by unique_ptr on PolyPtrWithPolyPtrBase destructor, hence == 0
EXPECT_THAT(memRes1.deallocs.size(), Eq(0u));
EXPECT_THAT(memRes2.allocs.size(), Eq(1u));
EXPECT_THAT(memRes2.deallocs.size(), Eq(1u));
EXPECT_THAT(memRes1.allocs.size(), Eq(1u));
// Base* was destroyed by unique_ptr on PolyPtrWithPolyPtrBase destructor,
// hence == 0
EXPECT_THAT(memRes1.deallocs.size(), Eq(0u));
EXPECT_THAT(memRes2.allocs.size(), Eq(1u));
EXPECT_THAT(memRes2.deallocs.size(), Eq(1u));
}
TEST_F(SerializeExtensionPointerWithAllocator, MemResourceSetPerPointerCanPropagate) {
MemResourceForTest memRes1{};
MemResourceForTest memRes2{};
std::get<0>(plctx).setMemResource(&memRes1);
TEST_F(SerializeExtensionPointerWithAllocator,
MemResourceSetPerPointerCanPropagate)
{
MemResourceForTest memRes1{};
MemResourceForTest memRes2{};
std::get<0>(plctx).setMemResource(&memRes1);
auto data = std::unique_ptr<PolyPtrWithPolyPtrBase>(new PolyPtrWithPolyPtrBase{});
data->ptr = std::unique_ptr<Base>(new Derived1{5, 6});
createSerializer().ext(data, StdSmartPtr{bitsery::ext::PointerType::Nullable, &memRes2, true});
auto data =
std::unique_ptr<PolyPtrWithPolyPtrBase>(new PolyPtrWithPolyPtrBase{});
data->ptr = std::unique_ptr<Base>(new Derived1{ 5, 6 });
createSerializer().ext(
data, StdSmartPtr{ bitsery::ext::PointerType::Nullable, &memRes2, true });
auto res = std::unique_ptr<PolyPtrWithPolyPtrBase>(new DerivedPolyPtrWithPolyPtr{});
res->ptr = std::unique_ptr<Base>(new Derived2{});
createDeserializer().ext(res, StdSmartPtr{bitsery::ext::PointerType::Nullable, &memRes2, true});
EXPECT_THAT(memRes1.allocs.size(), Eq(0u));
EXPECT_THAT(memRes1.deallocs.size(), Eq(0u));
EXPECT_THAT(memRes2.allocs.size(), Eq(2u));
// deallocates are actually == 1, because when we destroy PolyPtrWithPolyPtrBase
// it also destroys Base because it is managed by unique_ptr.
// in order to do it correctly we should always use custom deleter for structures with nested pointers
EXPECT_THAT(memRes2.deallocs.size(), Eq(1u));
auto res =
std::unique_ptr<PolyPtrWithPolyPtrBase>(new DerivedPolyPtrWithPolyPtr{});
res->ptr = std::unique_ptr<Base>(new Derived2{});
createDeserializer().ext(
res, StdSmartPtr{ bitsery::ext::PointerType::Nullable, &memRes2, true });
EXPECT_THAT(memRes1.allocs.size(), Eq(0u));
EXPECT_THAT(memRes1.deallocs.size(), Eq(0u));
EXPECT_THAT(memRes2.allocs.size(), Eq(2u));
// deallocates are actually == 1, because when we destroy
// PolyPtrWithPolyPtrBase it also destroys Base because it is managed by
// unique_ptr. in order to do it correctly we should always use custom deleter
// for structures with nested pointers
EXPECT_THAT(memRes2.deallocs.size(), Eq(1u));
}

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