mirror of
https://github.com/fraillt/bitsery.git
synced 2026-06-08 00:03:54 +00:00
format code base in Mozilla style
This commit is contained in:
192
.clang-format
Normal file
192
.clang-format
Normal file
@@ -0,0 +1,192 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: Mozilla
|
||||
AccessModifierOffset: -2
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveMacros: None
|
||||
AlignConsecutiveAssignments: None
|
||||
AlignConsecutiveBitFields: None
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||
AlwaysBreakAfterReturnType: TopLevel
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: true
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: true
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: true
|
||||
BreakBeforeBraces: Mozilla
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeComma
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
QualifierAlignment: Leave
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerIndentWidth: 2
|
||||
ContinuationIndentWidth: 2
|
||||
Cpp11BracedListStyle: false
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
PackConstructorInitializers: BinPack
|
||||
BasedOnStyle: ''
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: true
|
||||
IndentCaseBlocks: false
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentExternBlock: AfterExternBlock
|
||||
IndentRequires: false
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
LambdaBodyIndentation: Signature
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: false
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakOpenParenthesis: 0
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Left
|
||||
PPIndentWidth: -1
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
RemoveBracesLLVM: false
|
||||
SeparateDefinitionBlocks: Leave
|
||||
ShortNamespaceLines: 1
|
||||
SortIncludes: CaseSensitive
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
AfterForeachMacros: true
|
||||
AfterFunctionDefinitionName: false
|
||||
AfterFunctionDeclarationName: false
|
||||
AfterIfMacros: true
|
||||
AfterOverloadedOperator: false
|
||||
BeforeNonEmptyParentheses: false
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
...
|
||||
|
||||
@@ -2,13 +2,20 @@
|
||||
#include <bitsery/bitsery.h>
|
||||
// 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 {
|
||||
enum class MyEnum : uint16_t
|
||||
{
|
||||
V1,
|
||||
V2,
|
||||
V3
|
||||
};
|
||||
struct MyStruct
|
||||
{
|
||||
uint32_t i;
|
||||
MyEnum e;
|
||||
std::vector<float> fs;
|
||||
@@ -16,10 +23,13 @@ struct MyStruct {
|
||||
|
||||
// define how object should be serialized/deserialized
|
||||
template<typename S>
|
||||
void serialize(S& s, MyStruct& o) {
|
||||
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
|
||||
s.container4b(o.fs, 10); // resizable containers also requires maxSize, to
|
||||
// make it safe from buffer-overflow attacks
|
||||
}
|
||||
|
||||
// some helper types
|
||||
@@ -27,7 +37,9 @@ using Buffer = std::vector<uint8_t>;
|
||||
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||
|
||||
int main() {
|
||||
int
|
||||
main()
|
||||
{
|
||||
// set some random data
|
||||
MyStruct data{ 8941, MyEnum::V2, { 15.0f, -8.5f, 0.045f } };
|
||||
MyStruct res{};
|
||||
@@ -40,8 +52,10 @@ int main() {
|
||||
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);
|
||||
// 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);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#include <bitsery/bitsery.h>
|
||||
#include <bitsery/adapter/buffer.h>
|
||||
#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>
|
||||
@@ -9,27 +9,36 @@
|
||||
|
||||
namespace MyTypes {
|
||||
|
||||
struct Vec3 { float x, y, z; };
|
||||
struct Vec3
|
||||
{
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
struct Monster {
|
||||
struct Monster
|
||||
{
|
||||
Vec3 pos;
|
||||
std::vector<Vec3> path;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, MyTypes::Vec3 &o) {
|
||||
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) {
|
||||
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
|
||||
// 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 };
|
||||
@@ -46,7 +55,9 @@ using Buffer = std::array<uint8_t, 10000>;
|
||||
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||
|
||||
int main() {
|
||||
int
|
||||
main()
|
||||
{
|
||||
// set some random data
|
||||
MyTypes::Monster data{};
|
||||
data.name = "lew";
|
||||
@@ -56,7 +67,8 @@ int main() {
|
||||
auto writtenSize = bitsery::quickSerialization<OutputAdapter>(buffer, data);
|
||||
|
||||
MyTypes::Monster res{};
|
||||
auto state = bitsery::quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
|
||||
auto state = bitsery::quickDeserialization<InputAdapter>(
|
||||
{ buffer.begin(), writtenSize }, res);
|
||||
|
||||
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,33 @@
|
||||
#include <bitsery/bitsery.h>
|
||||
#include <bitsery/adapter/buffer.h>
|
||||
#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.
|
||||
// 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 {
|
||||
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) {
|
||||
void serialize(S& s)
|
||||
{
|
||||
// now we can use brief syntax with
|
||||
s(i, e, fs);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// some helper types
|
||||
@@ -28,7 +35,9 @@ using Buffer = std::vector<uint8_t>;
|
||||
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||
|
||||
int main() {
|
||||
int
|
||||
main()
|
||||
{
|
||||
// set some random data
|
||||
MyStruct data{ 8941, MyEnum::V2, { 15.0f, -8.5f, 0.045f } };
|
||||
MyStruct res{};
|
||||
@@ -37,7 +46,8 @@ int main() {
|
||||
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);
|
||||
|
||||
@@ -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,17 +10,21 @@
|
||||
// let's include this extension to make it more interesting :)
|
||||
#include <bitsery/ext/compact_value.h>
|
||||
|
||||
struct MyStruct {
|
||||
struct MyStruct
|
||||
{
|
||||
std::vector<int32_t> v{};
|
||||
float f{};
|
||||
|
||||
bool operator==(const MyStruct& rhs) const {
|
||||
bool operator==(const MyStruct& rhs) const
|
||||
{
|
||||
return v == rhs.v && f == rhs.f;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, MyStruct& o) {
|
||||
void
|
||||
serialize(S& s, MyStruct& o)
|
||||
{
|
||||
s.container4b(o.v, 1000);
|
||||
s.value4b(o.f);
|
||||
}
|
||||
@@ -29,30 +33,43 @@ void serialize(S& s, MyStruct& o) {
|
||||
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{
|
||||
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{
|
||||
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);}
|
||||
// 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
|
||||
// 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
|
||||
// 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>>>{},
|
||||
// ext::OverloadExtObject<MyTuple, ext::StdTuple<ext::OverloadValue<float,
|
||||
// 4>>>{},
|
||||
|
||||
// we can also override default 'serialize' function by creating an overloading for that type
|
||||
// we can also override default 'serialize' function by creating an
|
||||
// overloading for that type
|
||||
[](S& s, MyStruct& o) {
|
||||
s.value4b(o.f);
|
||||
s.container(o.v, 1000, [](S& s, int32_t& v) {
|
||||
@@ -62,26 +79,29 @@ void serialize(S& s, MyVariant& o) {
|
||||
// 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);
|
||||
// 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
|
||||
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 data{ MyTuple{ -7549,
|
||||
{ { -451, 2, 968, 75, 4, 156, 49 }, 874.4f } } };
|
||||
MyVariant res{};
|
||||
|
||||
// create buffer to store data
|
||||
@@ -92,19 +112,24 @@ int main() {
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
#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() {
|
||||
int
|
||||
main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -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,10 +8,15 @@
|
||||
|
||||
namespace MyTypes {
|
||||
|
||||
struct Monster {
|
||||
struct Monster
|
||||
{
|
||||
Monster() = default;
|
||||
Monster(std::string _name, uint32_t minDmg, uint32_t maxDmg)
|
||||
:name{_name}, minDamage{minDmg}, maxDamage{maxDmg} {}
|
||||
: name{ _name }
|
||||
, minDamage{ minDmg }
|
||||
, maxDamage{ maxDmg }
|
||||
{
|
||||
}
|
||||
|
||||
std::string name{};
|
||||
uint32_t minDamage{};
|
||||
@@ -19,29 +24,36 @@ namespace MyTypes {
|
||||
//...
|
||||
};
|
||||
|
||||
struct GameState {
|
||||
struct GameState
|
||||
{
|
||||
std::vector<Monster> monsters;
|
||||
};
|
||||
|
||||
// default flow for monster
|
||||
template<typename S>
|
||||
void serialize (S& s, Monster& o) {
|
||||
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) {
|
||||
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
|
||||
// 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
|
||||
// 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) {
|
||||
@@ -71,7 +83,9 @@ using Buffer = std::vector<uint8_t>;
|
||||
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||
|
||||
int main() {
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
||||
MyTypes::GameState data{};
|
||||
data.monsters.push_back({ "weaksy", 100, 200 });
|
||||
@@ -86,13 +100,14 @@ int main() {
|
||||
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);
|
||||
auto writtenSize =
|
||||
bitsery::quickSerialization(ctx, OutputAdapter{ buffer }, data);
|
||||
|
||||
MyTypes::GameState res{};
|
||||
auto state = bitsery::quickDeserialization(ctx, InputAdapter{buffer.begin(), writtenSize}, res);
|
||||
auto state = bitsery::quickDeserialization(
|
||||
ctx, InputAdapter{ buffer.begin(), writtenSize }, res);
|
||||
|
||||
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,14 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
enum class MyEnum:uint16_t { V1,V2,V3 };
|
||||
struct MyStruct {
|
||||
enum class MyEnum : uint16_t
|
||||
{
|
||||
V1,
|
||||
V2,
|
||||
V3
|
||||
};
|
||||
struct MyStruct
|
||||
{
|
||||
uint32_t i;
|
||||
MyEnum e;
|
||||
double f;
|
||||
@@ -13,13 +19,17 @@ struct MyStruct {
|
||||
|
||||
// define how object should be serialized/deserialized
|
||||
template<typename S>
|
||||
void serialize(S& s, MyStruct& o) {
|
||||
void
|
||||
serialize(S& s, MyStruct& o)
|
||||
{
|
||||
s.value4b(o.i);
|
||||
s.value2b(o.e);
|
||||
s.value8b(o.f);
|
||||
}
|
||||
|
||||
int main() {
|
||||
int
|
||||
main()
|
||||
{
|
||||
// set some random data
|
||||
MyStruct data{ 8941, MyEnum::V2, 0.045 };
|
||||
MyStruct res{};
|
||||
@@ -32,7 +42,8 @@ int main() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
//we cannot use quick serialization function, because streams cannot use writtenBytesCount method
|
||||
// we cannot use quick serialization function, because streams cannot use
|
||||
// writtenBytesCount method
|
||||
bitsery::Serializer<bitsery::OutputBufferedStreamAdapter> ser{ s };
|
||||
ser.object(data);
|
||||
// flush to writer
|
||||
@@ -47,8 +58,10 @@ int main() {
|
||||
}
|
||||
|
||||
// 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);
|
||||
// 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);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#include <bitsery/bitsery.h>
|
||||
#include <bitsery/adapter/buffer.h>
|
||||
#include <bitsery/bitsery.h>
|
||||
// include traits for types, that we'll be using
|
||||
#include <bitsery/traits/string.h>
|
||||
#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 <bitsery/ext/growable.h>
|
||||
@@ -10,20 +10,35 @@
|
||||
namespace MyTypes {
|
||||
|
||||
// define data
|
||||
enum Color:uint8_t { Red, Green, Blue };
|
||||
enum Color : uint8_t
|
||||
{
|
||||
Red,
|
||||
Green,
|
||||
Blue
|
||||
};
|
||||
|
||||
struct Vec3 { float x, y, z; };
|
||||
struct Vec3
|
||||
{
|
||||
float x, y, z;
|
||||
};
|
||||
|
||||
struct Weapon {
|
||||
struct Weapon
|
||||
{
|
||||
std::string name{};
|
||||
int16_t damage{};
|
||||
Weapon() = default;
|
||||
Weapon(const std::string& _name, int16_t dmg):name{_name}, damage{dmg} {}
|
||||
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) {
|
||||
void serialize(S& s)
|
||||
{
|
||||
// forward/backward compatibility for monsters
|
||||
s.ext(*this, bitsery::ext::Growable{}, [](S& s, Weapon& o1) {
|
||||
s.text1b(o1.name, 20);
|
||||
@@ -32,7 +47,8 @@ namespace MyTypes {
|
||||
}
|
||||
};
|
||||
|
||||
struct Monster {
|
||||
struct Monster
|
||||
{
|
||||
Vec3 pos;
|
||||
int16_t mana;
|
||||
int16_t hp;
|
||||
@@ -45,14 +61,18 @@ namespace MyTypes {
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, Vec3& o) {
|
||||
void
|
||||
serialize(S& s, Vec3& o)
|
||||
{
|
||||
s.value4b(o.x);
|
||||
s.value4b(o.y);
|
||||
s.value4b(o.z);
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
void serialize (S& s, Monster& o) {
|
||||
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);
|
||||
@@ -73,7 +93,9 @@ using Buffer = std::array<uint8_t, 10000>;
|
||||
using OutputAdapter = bitsery::OutputBufferAdapter<Buffer>;
|
||||
using InputAdapter = bitsery::InputBufferAdapter<Buffer>;
|
||||
|
||||
int main() {
|
||||
int
|
||||
main()
|
||||
{
|
||||
// set some random data
|
||||
MyTypes::Monster data{};
|
||||
data.name = "lew";
|
||||
@@ -81,12 +103,14 @@ int main() {
|
||||
|
||||
// create buffer to store data to
|
||||
Buffer buffer{};
|
||||
//since we're using different configuration, we cannot use quickSerialization function.
|
||||
// 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);
|
||||
auto state = bitsery::quickDeserialization<InputAdapter>(
|
||||
{ buffer.begin(), writtenSize }, res);
|
||||
|
||||
assert(state.first == bitsery::ReaderError::NoError && state.second);
|
||||
}
|
||||
|
||||
@@ -1,65 +1,88 @@
|
||||
//
|
||||
// this example covers all the corner cases that can happen using inheritance
|
||||
//in reality virtual inherintance is usually avoided, so your code would look much simpler.
|
||||
// in reality virtual inherintance is usually avoided, so your code would look
|
||||
// much simpler.
|
||||
//
|
||||
|
||||
#include <bitsery/bitsery.h>
|
||||
#include <bitsery/adapter/buffer.h>
|
||||
#include <bitsery/bitsery.h>
|
||||
#include <bitsery/traits/vector.h>
|
||||
|
||||
// include inheritance extension
|
||||
//this header contains two extensions, that specifies inheritance type of base class
|
||||
// this header contains two extensions, that specifies inheritance type of base
|
||||
// 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
|
||||
// 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 {
|
||||
struct Base
|
||||
{
|
||||
uint8_t x{};
|
||||
//Base doesn't have to be polymorphic class, inheritance works at compile-time.
|
||||
// Base doesn't have to be polymorphic class, inheritance works at
|
||||
// compile-time.
|
||||
};
|
||||
template<typename S>
|
||||
void serialize(S& s, Base& o) {
|
||||
void
|
||||
serialize(S& s, Base& o)
|
||||
{
|
||||
s.value1b(o.x);
|
||||
}
|
||||
|
||||
struct Derive1:virtual Base {// virtually inherits from base
|
||||
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
|
||||
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} {}
|
||||
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) {
|
||||
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} {}
|
||||
struct MultipleInheritance
|
||||
: Derive1
|
||||
, Derived2
|
||||
{
|
||||
explicit MultipleInheritance(uint8_t y2)
|
||||
: Derived2{ y2 }
|
||||
{
|
||||
}
|
||||
uint8_t z{};
|
||||
};
|
||||
template<typename S>
|
||||
void serialize(S& s, MultipleInheritance& o) {
|
||||
void
|
||||
serialize(S& s, MultipleInheritance& o)
|
||||
{
|
||||
// has two bases, serialize them separately
|
||||
s.ext(o, BaseClass<Derive1>{});
|
||||
s.ext(o, BaseClass<Derived2>{});
|
||||
@@ -67,15 +90,19 @@ void serialize(S& s, MultipleInheritance& o) {
|
||||
}
|
||||
|
||||
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
|
||||
// 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 {};
|
||||
struct SelectSerializeFnc<Derived2> : UseMemberFnc
|
||||
{
|
||||
};
|
||||
|
||||
// multiple inheritance has non-member serialize function defined
|
||||
template<>
|
||||
struct SelectSerializeFnc<MultipleInheritance>:UseNonMemberFnc {};
|
||||
struct SelectSerializeFnc<MultipleInheritance> : UseNonMemberFnc
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
// some helper types
|
||||
@@ -83,7 +110,9 @@ 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;
|
||||
@@ -94,11 +123,14 @@ int main() {
|
||||
|
||||
bitsery::ext::InheritanceContext ctx1;
|
||||
auto writtenSize = bitsery::quickSerialization(ctx1, Writer{ buf }, data);
|
||||
assert(writtenSize == 4);//base is serialized once, because it is inherited virtually
|
||||
assert(writtenSize ==
|
||||
4); // base is serialized once, because it is inherited virtually
|
||||
|
||||
MultipleInheritance res{ 0 };
|
||||
bitsery::ext::InheritanceContext ctx2;
|
||||
auto state = bitsery::quickDeserialization(ctx2, Reader{buf.begin(), writtenSize}, res);
|
||||
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);
|
||||
assert(data.x == res.x && data.y1 == res.y1 && data.getY2() == res.getY2() &&
|
||||
data.z == res.z);
|
||||
}
|
||||
|
||||
@@ -2,30 +2,39 @@
|
||||
// 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 {
|
||||
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
|
||||
// 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) {
|
||||
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} {}
|
||||
MyData(float x, float y)
|
||||
: _x{ x }
|
||||
, _y{ y }
|
||||
{
|
||||
}
|
||||
// this is for convenience
|
||||
bool operator ==(const MyData&rhs) const {
|
||||
bool operator==(const MyData& rhs) const
|
||||
{
|
||||
return _x == rhs._x && _y == rhs._y;
|
||||
}
|
||||
};
|
||||
@@ -35,7 +44,9 @@ 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{};
|
||||
@@ -45,18 +56,19 @@ int main() {
|
||||
// create buffer
|
||||
Buffer buffer{};
|
||||
|
||||
//we cant use quick (de)serialization helper methods, because we ant to serialize container directly
|
||||
//create writer and serialize container
|
||||
// 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()};
|
||||
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(des.adapter().error() == bitsery::ReaderError::NoError &&
|
||||
des.adapter().isCompletedSuccessfully());
|
||||
assert(res == data);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,39 +1,55 @@
|
||||
#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.
|
||||
// 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::ReferencedByPointer;
|
||||
|
||||
enum class MyEnum:uint16_t { V1,V2,V3 };
|
||||
struct MyStruct {
|
||||
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, {}} {}
|
||||
: 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) {
|
||||
void
|
||||
serialize(S& s, MyStruct& o)
|
||||
{
|
||||
s.value4b(o.i);
|
||||
s.value2b(o.e);
|
||||
s.container4b(o.fs, 10);
|
||||
}
|
||||
|
||||
// our test data
|
||||
struct Test1Data {
|
||||
struct Test1Data
|
||||
{
|
||||
// regular data, nothing fancy here
|
||||
MyStruct o1;
|
||||
int32_t i1;
|
||||
@@ -50,31 +66,30 @@ private:
|
||||
friend bitsery::Access;
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& 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{});
|
||||
});
|
||||
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{});
|
||||
});
|
||||
// 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 });
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -84,12 +99,15 @@ 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:
|
||||
// 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() {
|
||||
int
|
||||
main()
|
||||
{
|
||||
// set some random data
|
||||
Test1Data data{};
|
||||
data.vdata.emplace_back(8941, MyEnum::V1, std::vector<float>{ 4.4f });
|
||||
@@ -110,21 +128,24 @@ int main() {
|
||||
// create buffer to store data
|
||||
Buffer buffer{};
|
||||
size_t writtenSize{};
|
||||
//in order to use pointers, we need to pass pointer linking context serializer/deserializer
|
||||
// in order to use pointers, we need to pass pointer linking context
|
||||
// serializer/deserializer
|
||||
{
|
||||
bitsery::ext::PointerLinkingContext ctx{};
|
||||
writtenSize = quickSerialization(ctx, Writer{ buffer }, data);
|
||||
|
||||
// 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
|
||||
// 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);
|
||||
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
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
//
|
||||
// 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.
|
||||
// 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;
|
||||
|
||||
@@ -23,43 +24,47 @@ using bitsery::ext::PointerObserver;
|
||||
using bitsery::ext::StdSmartPtr;
|
||||
|
||||
// define our data structures
|
||||
struct Color {
|
||||
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);
|
||||
bool operator==(const Color& o) const
|
||||
{
|
||||
return std::tie(r, g, b) == std::tie(o.r, o.g, o.b);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Shape {
|
||||
struct Shape
|
||||
{
|
||||
Color clr{};
|
||||
virtual ~Shape() = 0;
|
||||
};
|
||||
|
||||
Shape::~Shape() = default;
|
||||
|
||||
struct Circle : Shape {
|
||||
struct Circle : Shape
|
||||
{
|
||||
int32_t radius{};
|
||||
bool operator == (const Circle& o) const {
|
||||
return std::tie(radius, clr) ==
|
||||
std::tie(o.radius, o.clr);
|
||||
bool operator==(const Circle& o) const
|
||||
{
|
||||
return std::tie(radius, clr) == std::tie(o.radius, o.clr);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct Rectangle : Shape {
|
||||
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);
|
||||
bool operator==(const Rectangle& o) const
|
||||
{
|
||||
return std::tie(width, height, clr) == std::tie(o.width, o.height, o.clr);
|
||||
}
|
||||
};
|
||||
|
||||
struct RoundedRectangle : Rectangle {
|
||||
struct RoundedRectangle : Rectangle
|
||||
{
|
||||
int32_t radius{};
|
||||
bool operator == (const RoundedRectangle& o) const {
|
||||
bool operator==(const RoundedRectangle& o) const
|
||||
{
|
||||
return std::tie(radius, static_cast<const Rectangle&>(*this)) ==
|
||||
std::tie(o.radius, static_cast<const Rectangle&>(o));
|
||||
}
|
||||
@@ -67,40 +72,52 @@ struct RoundedRectangle : Rectangle {
|
||||
|
||||
// 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
|
||||
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) {
|
||||
void
|
||||
serialize(S& s, Shape& o)
|
||||
{
|
||||
s.object(o.clr);
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
void serialize(S &s, Circle &o) {
|
||||
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) {
|
||||
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) {
|
||||
void
|
||||
serialize(S& s, RoundedRectangle& o)
|
||||
{
|
||||
s.ext(o, bitsery::ext::BaseClass<Rectangle>{});
|
||||
s.value4b(o.radius);
|
||||
}
|
||||
|
||||
// define our test structure
|
||||
struct SomeShapes {
|
||||
struct SomeShapes
|
||||
{
|
||||
std::vector<std::shared_ptr<Shape>> sharedList;
|
||||
std::unique_ptr<Shape> uniquePtr;
|
||||
// weak ptr and refPtr will point to sharedList
|
||||
@@ -109,7 +126,9 @@ struct SomeShapes {
|
||||
};
|
||||
|
||||
// creates object, and populates some data
|
||||
SomeShapes createData() {
|
||||
SomeShapes
|
||||
createData()
|
||||
{
|
||||
SomeShapes data{};
|
||||
{
|
||||
auto tmp = new RoundedRectangle{};
|
||||
@@ -144,9 +163,10 @@ SomeShapes createData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
template<typename S>
|
||||
void serialize(S &s, SomeShapes &o) {
|
||||
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,
|
||||
@@ -165,21 +185,28 @@ namespace bitsery {
|
||||
namespace ext {
|
||||
|
||||
// for each base class define DIRECTLY derived classes
|
||||
//e.g. PolymorphicBaseClass<Shape> : PolymorphicDerivedClasses<Circle, Rectangle, RoundedRectangle>
|
||||
// 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> {
|
||||
struct PolymorphicBaseClass<Shape>
|
||||
: PolymorphicDerivedClasses<Circle, Rectangle>
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct PolymorphicBaseClass<Rectangle> : PolymorphicDerivedClasses<RoundedRectangle> {
|
||||
struct PolymorphicBaseClass<Rectangle>
|
||||
: PolymorphicDerivedClasses<RoundedRectangle>
|
||||
{
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// convenient type that stores all our types, so that we could easily register and
|
||||
// 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
|
||||
using Buffer = std::vector<uint8_t>;
|
||||
@@ -189,16 +216,19 @@ 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,
|
||||
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
|
||||
// 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) {
|
||||
void
|
||||
assertSameShapes(const SomeShapes& data, const SomeShapes& res)
|
||||
{
|
||||
{
|
||||
auto d = dynamic_cast<RoundedRectangle*>(data.uniquePtr.get());
|
||||
auto r = dynamic_cast<RoundedRectangle*>(res.uniquePtr.get());
|
||||
@@ -221,22 +251,27 @@ void assertSameShapes(const SomeShapes &data, const SomeShapes &res) {
|
||||
assert(res.refPtr == res.sharedList[1].get());
|
||||
}
|
||||
|
||||
int main() {
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
||||
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
|
||||
// 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
|
||||
// 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{});
|
||||
std::get<1>(ctx).registerBasesList<MySerializer>(
|
||||
MyPolymorphicClassesForRegistering{});
|
||||
// create writer and serialize
|
||||
MySerializer ser{ ctx, buffer };
|
||||
ser.object(data);
|
||||
@@ -244,23 +279,28 @@ int main() {
|
||||
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
|
||||
// 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{});
|
||||
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());
|
||||
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
|
||||
// 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);
|
||||
}
|
||||
|
||||
3
format.sh
Executable file
3
format.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
find . -regex '.*\.\(cpp\|hpp\|cu\|c\|h\)' -exec clang-format -style=file -i {} \;
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -32,29 +32,38 @@
|
||||
namespace bitsery {
|
||||
|
||||
template<typename Buffer, typename Config = DefaultConfig>
|
||||
class InputBufferAdapter: public details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer,Config>> {
|
||||
class InputBufferAdapter
|
||||
: public details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer, Config>>
|
||||
{
|
||||
public:
|
||||
friend details::InputAdapterBaseCRTP<InputBufferAdapter<Buffer, Config>>;
|
||||
|
||||
using BitPackingEnabled = details::InputAdapterBitPackingWrapper<InputBufferAdapter<Buffer, Config>>;
|
||||
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,
|
||||
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,
|
||||
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.");
|
||||
static_assert(sizeof(TValue) == 1,
|
||||
"BufferAdapter underlying type must be 1byte.");
|
||||
|
||||
InputBufferAdapter(TIterator beginIt, size_t size)
|
||||
: _beginIt{beginIt},
|
||||
_currOffset{0},
|
||||
_endReadOffset{size},
|
||||
_bufferSize{size} {
|
||||
};
|
||||
: _beginIt{ beginIt }
|
||||
, _currOffset{ 0 }
|
||||
, _endReadOffset{ size }
|
||||
, _bufferSize{ size } {};
|
||||
|
||||
InputBufferAdapter(TIterator beginIt, TIterator endIt)
|
||||
:InputBufferAdapter(beginIt, static_cast<size_t>(std::distance(beginIt, endIt))) {
|
||||
: InputBufferAdapter(beginIt,
|
||||
static_cast<size_t>(std::distance(beginIt, endIt)))
|
||||
{
|
||||
}
|
||||
|
||||
InputBufferAdapter(const InputBufferAdapter&) = delete;
|
||||
@@ -63,17 +72,25 @@ namespace bitsery {
|
||||
InputBufferAdapter(InputBufferAdapter&&) = default;
|
||||
InputBufferAdapter& operator=(InputBufferAdapter&&) = default;
|
||||
|
||||
void currentReadPos(size_t pos) {
|
||||
currentReadPosChecked(pos, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||
void currentReadPos(size_t pos)
|
||||
{
|
||||
currentReadPosChecked(
|
||||
pos, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||
}
|
||||
|
||||
size_t currentReadPos() const {
|
||||
return currentReadPosChecked(std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||
size_t currentReadPos() const
|
||||
{
|
||||
return currentReadPosChecked(
|
||||
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.");
|
||||
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)
|
||||
@@ -84,19 +101,22 @@ namespace bitsery {
|
||||
}
|
||||
}
|
||||
|
||||
size_t currentReadEndPos() const {
|
||||
size_t currentReadEndPos() const
|
||||
{
|
||||
if (_overflowOnReadEndPos)
|
||||
return 0;
|
||||
return _endReadOffset;
|
||||
}
|
||||
|
||||
ReaderError error() const {
|
||||
ReaderError error() const
|
||||
{
|
||||
return _currOffset <= _endReadOffset
|
||||
? ReaderError::NoError
|
||||
: static_cast<ReaderError>(_currOffset - _endReadOffset);
|
||||
}
|
||||
|
||||
void error(ReaderError error) {
|
||||
void error(ReaderError error)
|
||||
{
|
||||
if (_currOffset <= _endReadOffset) {
|
||||
_endReadOffset = 0;
|
||||
_bufferSize = 0;
|
||||
@@ -104,30 +124,34 @@ namespace bitsery {
|
||||
}
|
||||
}
|
||||
|
||||
bool isCompletedSuccessfully() const {
|
||||
return _currOffset == _bufferSize;
|
||||
}
|
||||
bool isCompletedSuccessfully() const { return _currOffset == _bufferSize; }
|
||||
|
||||
private:
|
||||
using diff_t = typename std::iterator_traits<TIterator>::difference_type;
|
||||
|
||||
template<size_t SIZE>
|
||||
void readInternalValue(TValue *data) {
|
||||
readInternalImpl(data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||
void readInternalValue(TValue* data)
|
||||
{
|
||||
readInternalImpl(
|
||||
data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||
}
|
||||
|
||||
void readInternalBuffer(TValue *data, size_t size) {
|
||||
readInternalImpl(data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||
void readInternalBuffer(TValue* data, size_t size)
|
||||
{
|
||||
readInternalImpl(
|
||||
data, size, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||
}
|
||||
|
||||
void readInternalImpl(TValue * data, size_t size, std::false_type) {
|
||||
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 readInternalImpl(TValue *data, size_t size, std::true_type) {
|
||||
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);
|
||||
@@ -140,7 +164,8 @@ namespace bitsery {
|
||||
}
|
||||
}
|
||||
|
||||
void currentReadPosChecked(size_t pos, std::true_type) {
|
||||
void currentReadPosChecked(size_t pos, std::true_type)
|
||||
{
|
||||
if (_bufferSize >= pos && error() == ReaderError::NoError) {
|
||||
_currOffset = pos;
|
||||
} else {
|
||||
@@ -148,18 +173,14 @@ namespace bitsery {
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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;
|
||||
@@ -169,25 +190,31 @@ namespace bitsery {
|
||||
};
|
||||
|
||||
template<typename Buffer, typename Config = DefaultConfig>
|
||||
class OutputBufferAdapter: public details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer,Config>> {
|
||||
class OutputBufferAdapter
|
||||
: public details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer, Config>>
|
||||
{
|
||||
public:
|
||||
friend details::OutputAdapterBaseCRTP<OutputBufferAdapter<Buffer, Config>>;
|
||||
|
||||
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<OutputBufferAdapter<Buffer, Config>>;
|
||||
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<
|
||||
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,
|
||||
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(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)} {
|
||||
: _buffer{ std::addressof(buffer) }
|
||||
, _beginIt{ std::begin(buffer) }
|
||||
, _bufferSize{ traits::ContainerTraits<Buffer>::size(buffer) }
|
||||
{
|
||||
}
|
||||
|
||||
OutputBufferAdapter(const OutputBufferAdapter&) = delete;
|
||||
@@ -195,7 +222,8 @@ namespace bitsery {
|
||||
OutputBufferAdapter(OutputBufferAdapter&&) = default;
|
||||
OutputBufferAdapter& operator=(OutputBufferAdapter&&) = default;
|
||||
|
||||
void currentWritePos(size_t pos) {
|
||||
void currentWritePos(size_t pos)
|
||||
{
|
||||
const auto maxPos = _currOffset > pos ? _currOffset : pos;
|
||||
if (maxPos > _biggestCurrentPos) {
|
||||
_biggestCurrentPos = maxPos;
|
||||
@@ -204,28 +232,31 @@ namespace bitsery {
|
||||
_currOffset = pos;
|
||||
}
|
||||
|
||||
size_t currentWritePos() const {
|
||||
return _currOffset;
|
||||
}
|
||||
size_t currentWritePos() const { return _currOffset; }
|
||||
|
||||
void flush() {
|
||||
void flush()
|
||||
{
|
||||
// this function might be useful for stream adapters
|
||||
}
|
||||
|
||||
size_t writtenBytesCount() const {
|
||||
size_t writtenBytesCount() const
|
||||
{
|
||||
return _currOffset > _biggestCurrentPos ? _currOffset : _biggestCurrentPos;
|
||||
}
|
||||
|
||||
private:
|
||||
using TResizable = std::integral_constant<bool, traits::ContainerTraits<Buffer>::isResizable>;
|
||||
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) {
|
||||
void writeInternalValue(const TValue* data)
|
||||
{
|
||||
writeInternalImpl(data, SIZE);
|
||||
}
|
||||
|
||||
void writeInternalBuffer(const TValue *data, size_t size) {
|
||||
void writeInternalBuffer(const TValue* data, size_t size)
|
||||
{
|
||||
writeInternalImpl(data, size);
|
||||
}
|
||||
|
||||
@@ -235,25 +266,28 @@ namespace bitsery {
|
||||
size_t _bufferSize{ 0 };
|
||||
size_t _biggestCurrentPos{ 0 };
|
||||
|
||||
void maybeResize(size_t newOffset, std::true_type) {
|
||||
void maybeResize(size_t newOffset, std::true_type)
|
||||
{
|
||||
if (newOffset > _bufferSize) {
|
||||
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(*_buffer, _currOffset, newOffset);
|
||||
traits::BufferAdapterTraits<Buffer>::increaseBufferSize(
|
||||
*_buffer, _currOffset, newOffset);
|
||||
_beginIt = std::begin(*_buffer);
|
||||
_bufferSize = traits::ContainerTraits<Buffer>::size(*_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void maybeResize(size_t newOffset, std::false_type) {
|
||||
void maybeResize(size_t newOffset, std::false_type)
|
||||
{
|
||||
assert(newOffset <= _bufferSize);
|
||||
}
|
||||
|
||||
void writeInternalImpl(const TValue *data, size_t size) {
|
||||
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;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -29,30 +29,33 @@
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
|
||||
template<typename Config>
|
||||
class BasicMeasureSize {
|
||||
class BasicMeasureSize
|
||||
{
|
||||
public:
|
||||
|
||||
using BitPackingEnabled = details::BasicMeasureSizeBitPackingWrapper<BasicMeasureSize<Config>>;
|
||||
using BitPackingEnabled =
|
||||
details::BasicMeasureSizeBitPackingWrapper<BasicMeasureSize<Config>>;
|
||||
using TConfig = Config;
|
||||
using TValue = void;
|
||||
|
||||
template<size_t SIZE, typename T>
|
||||
void writeBytes(const T&) {
|
||||
void writeBytes(const T&)
|
||||
{
|
||||
static_assert(std::is_integral<T>(), "");
|
||||
static_assert(sizeof(T) == SIZE, "");
|
||||
_currPos += SIZE;
|
||||
}
|
||||
|
||||
template<size_t SIZE, typename T>
|
||||
void writeBuffer(const T*, size_t count) {
|
||||
void writeBuffer(const T*, size_t count)
|
||||
{
|
||||
static_assert(std::is_integral<T>(), "");
|
||||
static_assert(sizeof(T) == SIZE, "");
|
||||
_currPos += SIZE * count;
|
||||
}
|
||||
|
||||
void currentWritePos(size_t pos) {
|
||||
void currentWritePos(size_t pos)
|
||||
{
|
||||
const auto maxPos = _currPos > pos ? _currPos : pos;
|
||||
if (maxPos > _biggestCurrentPos) {
|
||||
_biggestCurrentPos = maxPos;
|
||||
@@ -60,18 +63,15 @@ namespace bitsery {
|
||||
_currPos = pos;
|
||||
}
|
||||
|
||||
size_t currentWritePos() const {
|
||||
return _currPos;
|
||||
}
|
||||
size_t currentWritePos() const { return _currPos; }
|
||||
|
||||
void align() {
|
||||
}
|
||||
void align() {}
|
||||
|
||||
void flush() {
|
||||
}
|
||||
void flush() {}
|
||||
|
||||
// get size in bytes
|
||||
size_t writtenBytesCount() const {
|
||||
size_t writtenBytesCount() const
|
||||
{
|
||||
return _currPos > _biggestCurrentPos ? _currPos : _biggestCurrentPos;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -33,16 +33,23 @@
|
||||
namespace bitsery {
|
||||
|
||||
template<typename TChar, typename Config, typename CharTraits>
|
||||
class BasicInputStreamAdapter: public details::InputAdapterBaseCRTP<BasicInputStreamAdapter<TChar, Config, CharTraits>> {
|
||||
class BasicInputStreamAdapter
|
||||
: public details::InputAdapterBaseCRTP<
|
||||
BasicInputStreamAdapter<TChar, Config, CharTraits>>
|
||||
{
|
||||
public:
|
||||
friend details::InputAdapterBaseCRTP<BasicInputStreamAdapter<TChar, Config, CharTraits>>;
|
||||
friend details::InputAdapterBaseCRTP<
|
||||
BasicInputStreamAdapter<TChar, Config, CharTraits>>;
|
||||
|
||||
using BitPackingEnabled = details::InputAdapterBitPackingWrapper<BasicInputStreamAdapter<TChar, Config, CharTraits>>;
|
||||
using BitPackingEnabled = details::InputAdapterBitPackingWrapper<
|
||||
BasicInputStreamAdapter<TChar, Config, CharTraits>>;
|
||||
using TConfig = Config;
|
||||
using TValue = TChar;
|
||||
|
||||
BasicInputStreamAdapter(std::basic_ios<TChar, CharTraits>& istream)
|
||||
:_ios{std::addressof(istream)} {}
|
||||
: _ios{ std::addressof(istream) }
|
||||
{
|
||||
}
|
||||
|
||||
BasicInputStreamAdapter(const BasicInputStreamAdapter&) = delete;
|
||||
BasicInputStreamAdapter& operator=(const BasicInputStreamAdapter&) = delete;
|
||||
@@ -50,36 +57,44 @@ namespace bitsery {
|
||||
BasicInputStreamAdapter(BasicInputStreamAdapter&&) = default;
|
||||
BasicInputStreamAdapter& operator=(BasicInputStreamAdapter&&) = default;
|
||||
|
||||
void currentReadPos(size_t ) {
|
||||
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
|
||||
void currentReadPos(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");
|
||||
size_t currentReadPos() 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");
|
||||
void currentReadEndPos(size_t)
|
||||
{
|
||||
static_assert(std::is_void<TChar>::value,
|
||||
"setting read position is not supported with StreamAdapter");
|
||||
}
|
||||
|
||||
size_t currentReadEndPos() const {
|
||||
static_assert(std::is_void<TChar>::value, "setting read position is not supported with StreamAdapter");
|
||||
size_t currentReadEndPos() const
|
||||
{
|
||||
static_assert(std::is_void<TChar>::value,
|
||||
"setting read position is not supported with StreamAdapter");
|
||||
return {};
|
||||
}
|
||||
|
||||
ReaderError error() const {
|
||||
return _err;
|
||||
}
|
||||
ReaderError error() const { return _err; }
|
||||
|
||||
bool isCompletedSuccessfully() const {
|
||||
bool isCompletedSuccessfully() const
|
||||
{
|
||||
if (error() == ReaderError::NoError) {
|
||||
return _ios->rdbuf()->sgetc() == CharTraits::eof();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void error(ReaderError error) {
|
||||
void error(ReaderError error)
|
||||
{
|
||||
if (_err == ReaderError::NoError) {
|
||||
_err = error;
|
||||
_zeroIfNoErrors = std::numeric_limits<size_t>::max();
|
||||
@@ -87,18 +102,24 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template<size_t SIZE>
|
||||
void readInternalValue(TValue* data) {
|
||||
readChecked(data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||
void readInternalValue(TValue* data)
|
||||
{
|
||||
readChecked(
|
||||
data, SIZE, std::integral_constant<bool, Config::CheckAdapterErrors>{});
|
||||
}
|
||||
|
||||
void readInternalBuffer(TValue* data, size_t size) {
|
||||
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) {
|
||||
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
|
||||
@@ -108,7 +129,8 @@ namespace bitsery {
|
||||
}
|
||||
}
|
||||
|
||||
void readChecked(TValue* data, size_t size, std::false_type) {
|
||||
void readChecked(TValue* data, size_t size, std::false_type)
|
||||
{
|
||||
_ios->rdbuf()->sgetn(data, static_cast<std::streamsize>(size));
|
||||
}
|
||||
|
||||
@@ -118,90 +140,120 @@ namespace bitsery {
|
||||
};
|
||||
|
||||
template<typename TChar, typename Config, typename CharTraits>
|
||||
class BasicOutputStreamAdapter: public details::OutputAdapterBaseCRTP<BasicOutputStreamAdapter<TChar, Config, CharTraits>> {
|
||||
class BasicOutputStreamAdapter
|
||||
: public details::OutputAdapterBaseCRTP<
|
||||
BasicOutputStreamAdapter<TChar, Config, CharTraits>>
|
||||
{
|
||||
public:
|
||||
friend details::OutputAdapterBaseCRTP<BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
|
||||
friend details::OutputAdapterBaseCRTP<
|
||||
BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
|
||||
|
||||
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
|
||||
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<
|
||||
BasicOutputStreamAdapter<TChar, Config, CharTraits>>;
|
||||
using TConfig = Config;
|
||||
using TValue = TChar;
|
||||
|
||||
BasicOutputStreamAdapter(std::basic_ostream<TChar, CharTraits>& ostream)
|
||||
:_ostream{std::addressof(ostream)} {}
|
||||
|
||||
void currentWritePos(size_t ) {
|
||||
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
|
||||
: _ostream{ std::addressof(ostream) }
|
||||
{
|
||||
}
|
||||
|
||||
size_t currentWritePos() const {
|
||||
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
|
||||
void currentWritePos(size_t)
|
||||
{
|
||||
static_assert(std::is_void<TChar>::value,
|
||||
"setting write position is not supported with StreamAdapter");
|
||||
}
|
||||
|
||||
size_t currentWritePos() const
|
||||
{
|
||||
static_assert(std::is_void<TChar>::value,
|
||||
"setting write position is not supported with StreamAdapter");
|
||||
return {};
|
||||
}
|
||||
|
||||
void flush() {
|
||||
_ostream->flush();
|
||||
}
|
||||
void flush() { _ostream->flush(); }
|
||||
|
||||
size_t writtenBytesCount() const {
|
||||
static_assert(std::is_void<TChar>::value, "`writtenBytesCount` cannot be used with stream adapter");
|
||||
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;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template<size_t SIZE>
|
||||
void writeInternalValue(const TValue* data) {
|
||||
void writeInternalValue(const TValue* data)
|
||||
{
|
||||
_ostream->rdbuf()->sputn(data, SIZE);
|
||||
}
|
||||
|
||||
void writeInternalBuffer(const TValue* data, size_t size) {
|
||||
void writeInternalBuffer(const TValue* data, size_t size)
|
||||
{
|
||||
_ostream->rdbuf()->sputn(data, size);
|
||||
}
|
||||
|
||||
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>> {
|
||||
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>>;
|
||||
friend details::OutputAdapterBaseCRTP<
|
||||
BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>;
|
||||
|
||||
using BitPackingEnabled = details::OutputAdapterBitPackingWrapper<BasicBufferedOutputStreamAdapter<TChar, Config, CharTraits, TBuffer>>;
|
||||
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");
|
||||
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;
|
||||
|
||||
// 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}
|
||||
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.
|
||||
// buffer size must be atleast 16, because writeIntervalValue expect that at
|
||||
// least one value fits to buffer.
|
||||
assert(_bufferSize >= 16);
|
||||
}
|
||||
|
||||
//we need to explicitly declare move logic, because after move buffer might be invalidated
|
||||
BasicBufferedOutputStreamAdapter(const BasicBufferedOutputStreamAdapter&) = delete;
|
||||
BasicBufferedOutputStreamAdapter& operator = (const BasicBufferedOutputStreamAdapter&) = delete;
|
||||
// we need to explicitly declare move logic, because after move buffer might
|
||||
// be invalidated
|
||||
BasicBufferedOutputStreamAdapter(const BasicBufferedOutputStreamAdapter&) =
|
||||
delete;
|
||||
BasicBufferedOutputStreamAdapter& operator=(
|
||||
const BasicBufferedOutputStreamAdapter&) = delete;
|
||||
|
||||
BasicBufferedOutputStreamAdapter(BasicBufferedOutputStreamAdapter&& rhs)
|
||||
: _ostream{rhs._ostream},
|
||||
_buf{std::move(rhs._buf)},
|
||||
_beginIt{std::begin(_buf)},
|
||||
_currOffset{rhs._currOffset},
|
||||
_bufferSize{rhs._bufferSize}
|
||||
{
|
||||
};
|
||||
: _ostream{ rhs._ostream }
|
||||
, _buf{ std::move(rhs._buf) }
|
||||
, _beginIt{ std::begin(_buf) }
|
||||
, _currOffset{ rhs._currOffset }
|
||||
, _bufferSize{ rhs._bufferSize } {};
|
||||
|
||||
BasicBufferedOutputStreamAdapter& operator = (BasicBufferedOutputStreamAdapter&& rhs) {
|
||||
BasicBufferedOutputStreamAdapter& operator=(
|
||||
BasicBufferedOutputStreamAdapter&& rhs)
|
||||
{
|
||||
_ostream = rhs._ostream;
|
||||
_buf = std::move(rhs._buf);
|
||||
_beginIt = std::begin(_buf);
|
||||
@@ -210,40 +262,51 @@ namespace bitsery {
|
||||
return *this;
|
||||
};
|
||||
|
||||
void currentWritePos(size_t ) {
|
||||
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
|
||||
void currentWritePos(size_t)
|
||||
{
|
||||
static_assert(std::is_void<TChar>::value,
|
||||
"setting write position is not supported with StreamAdapter");
|
||||
}
|
||||
|
||||
size_t currentWritePos() const {
|
||||
static_assert(std::is_void<TChar>::value, "setting write position is not supported with StreamAdapter");
|
||||
size_t currentWritePos() const
|
||||
{
|
||||
static_assert(std::is_void<TChar>::value,
|
||||
"setting write position is not supported with StreamAdapter");
|
||||
return {};
|
||||
}
|
||||
|
||||
void flush() {
|
||||
void flush()
|
||||
{
|
||||
writeBufferToStream();
|
||||
_ostream->flush();
|
||||
}
|
||||
|
||||
size_t writtenBytesCount() const {
|
||||
static_assert(std::is_void<TChar>::value, "`writtenBytesCount` cannot be used with stream adapter");
|
||||
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;
|
||||
}
|
||||
|
||||
private:
|
||||
using TResizable = std::integral_constant<bool, traits::ContainerTraits<TBuffer>::isResizable>;
|
||||
using TResizable =
|
||||
std::integral_constant<bool, traits::ContainerTraits<TBuffer>::isResizable>;
|
||||
using diff_t = typename std::iterator_traits<BufferIt>::difference_type;
|
||||
|
||||
template<size_t SIZE>
|
||||
void writeInternalValue(const TValue* data) {
|
||||
void writeInternalValue(const TValue* data)
|
||||
{
|
||||
writeInternalImpl(data, SIZE);
|
||||
}
|
||||
|
||||
void writeInternalBuffer(const TValue* data, size_t size) {
|
||||
void writeInternalBuffer(const TValue* data, size_t size)
|
||||
{
|
||||
writeInternalImpl(data, size);
|
||||
}
|
||||
|
||||
void writeInternalImpl(const TValue* data, size_t size) {
|
||||
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));
|
||||
@@ -255,18 +318,22 @@ namespace bitsery {
|
||||
}
|
||||
}
|
||||
|
||||
void writeBufferToStream() {
|
||||
_ostream->rdbuf()->sputn(std::addressof(*_beginIt), static_cast<std::streamsize>(_currOffset));
|
||||
void writeBufferToStream()
|
||||
{
|
||||
_ostream->rdbuf()->sputn(std::addressof(*_beginIt),
|
||||
static_cast<std::streamsize>(_currOffset));
|
||||
_currOffset = 0;
|
||||
}
|
||||
|
||||
void init (size_t buffSize, std::true_type) {
|
||||
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) {
|
||||
void init(size_t, std::false_type)
|
||||
{
|
||||
// ignore buffer size parameter, and instead take actual buffer size
|
||||
_bufferSize = traits::ContainerTraits<Buffer>::size(_buf);
|
||||
}
|
||||
@@ -290,15 +357,20 @@ namespace bitsery {
|
||||
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 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>>;
|
||||
using OutputBufferedStreamAdapter =
|
||||
BasicBufferedOutputStreamAdapter<char, DefaultConfig, std::char_traits<char>>;
|
||||
}
|
||||
|
||||
#endif // BITSERY_ADAPTER_STREAM_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// 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
|
||||
|
||||
@@ -30,14 +29,14 @@
|
||||
|
||||
#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)
|
||||
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)
|
||||
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
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,73 +20,105 @@
|
||||
// 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,
|
||||
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]) {
|
||||
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]) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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
|
||||
|
||||
//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]) {
|
||||
// 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");
|
||||
"\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]) {
|
||||
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
|
||||
// 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() {
|
||||
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.
|
||||
// for completion we also need pointer type size, but serializer doesn't
|
||||
// support pointer serialization.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,16 +20,17 @@
|
||||
// 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) {
|
||||
void
|
||||
serialize(S& s, std::array<T, N>& obj)
|
||||
{
|
||||
brief_syntax::processContainer(s, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -27,7 +27,9 @@
|
||||
|
||||
namespace bitsery {
|
||||
template<typename S, typename T>
|
||||
void serialize(S &s, std::atomic<T> &obj) {
|
||||
void
|
||||
serialize(S& s, std::atomic<T>& obj)
|
||||
{
|
||||
s.template ext<sizeof(T)>(obj, ext::StdAtomic{});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -27,12 +27,16 @@
|
||||
|
||||
namespace bitsery {
|
||||
template<typename S, typename T, typename P>
|
||||
void serialize(S &s, std::chrono::duration<T, P> &obj) {
|
||||
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) {
|
||||
void
|
||||
serialize(S& s, std::chrono::time_point<C, std::chrono::duration<T, P>>& obj)
|
||||
{
|
||||
s.template ext<sizeof(T)>(obj, ext::StdTimePoint{});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,16 +20,17 @@
|
||||
// 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) {
|
||||
void
|
||||
serialize(S& s, std::deque<T, Allocator>& obj)
|
||||
{
|
||||
brief_syntax::processContainer(s, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,16 +20,17 @@
|
||||
// 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) {
|
||||
void
|
||||
serialize(S& s, std::forward_list<T, Allocator>& obj)
|
||||
{
|
||||
brief_syntax::processContainer(s, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,16 +20,17 @@
|
||||
// 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) {
|
||||
void
|
||||
serialize(S& s, std::list<T, Allocator>& obj)
|
||||
{
|
||||
brief_syntax::processContainer(s, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,28 +20,41 @@
|
||||
// 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 "../ext/std_map.h"
|
||||
#include <map>
|
||||
#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) {
|
||||
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) {
|
||||
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);
|
||||
});
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -27,17 +27,23 @@
|
||||
|
||||
namespace bitsery {
|
||||
template<typename S, typename T, typename D>
|
||||
void serialize(S &s, std::unique_ptr<T, D> &obj) {
|
||||
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) {
|
||||
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) {
|
||||
void
|
||||
serialize(S& s, std::weak_ptr<T>& obj)
|
||||
{
|
||||
s.ext(obj, ext::StdSmartPtr{});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// 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
|
||||
|
||||
@@ -29,12 +28,20 @@
|
||||
|
||||
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()) {
|
||||
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()) {
|
||||
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 });
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,22 +20,29 @@
|
||||
// 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 "../ext/std_set.h"
|
||||
#include <set>
|
||||
#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()) {
|
||||
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()) {
|
||||
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 });
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// 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
|
||||
|
||||
@@ -29,7 +28,11 @@
|
||||
|
||||
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()) {
|
||||
void
|
||||
serialize(S& s,
|
||||
std::stack<T, C>& obj,
|
||||
size_t maxSize = std::numeric_limits<size_t>::max())
|
||||
{
|
||||
s.ext(obj, ext::StdStack{ maxSize });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,16 +20,17 @@
|
||||
// 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) {
|
||||
void
|
||||
serialize(S& s, std::basic_string<CharT, Traits, Allocator>& str)
|
||||
{
|
||||
brief_syntax::processContainer(s, str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -27,7 +27,9 @@
|
||||
|
||||
namespace bitsery {
|
||||
template<typename S, typename... Ts>
|
||||
void serialize(S &s, std::tuple<Ts...> &obj) {
|
||||
void
|
||||
serialize(S& s, std::tuple<Ts...>& obj)
|
||||
{
|
||||
s.ext(obj, ext::StdTuple{});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,28 +20,43 @@
|
||||
// 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 "../ext/std_map.h"
|
||||
#include <unordered_map>
|
||||
#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) {
|
||||
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) {
|
||||
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);
|
||||
});
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// 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
|
||||
|
||||
@@ -29,13 +28,29 @@
|
||||
#include <unordered_set>
|
||||
|
||||
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()) {
|
||||
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()) {
|
||||
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 });
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -27,7 +27,9 @@
|
||||
|
||||
namespace bitsery {
|
||||
template<typename S, typename... Ts>
|
||||
void serialize(S &s, std::variant<Ts...> &obj) {
|
||||
void
|
||||
serialize(S& s, std::variant<Ts...>& obj)
|
||||
{
|
||||
s.ext(obj, ext::StdVariant{});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,16 +20,17 @@
|
||||
// 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) {
|
||||
void
|
||||
serialize(S& s, std::vector<T, Allocator>& obj)
|
||||
{
|
||||
brief_syntax::processContainer(s, obj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// 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
|
||||
|
||||
@@ -29,19 +28,24 @@ namespace bitsery {
|
||||
/*
|
||||
* endianness
|
||||
*/
|
||||
enum class EndiannessType {
|
||||
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.
|
||||
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
|
||||
// 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
|
||||
// enables/disables checks for other errors that can significantly affect
|
||||
// performance
|
||||
static constexpr bool CheckDataErrors = true;
|
||||
};
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
|
||||
#ifndef BITSERY_DESERIALIZER_H
|
||||
#define BITSERY_DESERIALIZER_H
|
||||
|
||||
@@ -29,34 +28,44 @@
|
||||
namespace bitsery {
|
||||
|
||||
template<typename TInputAdapter, typename TContext = void>
|
||||
class Deserializer: public details::AdapterAndContextRef<TInputAdapter, TContext> {
|
||||
class Deserializer
|
||||
: public details::AdapterAndContextRef<TInputAdapter, TContext>
|
||||
{
|
||||
public:
|
||||
//helper type, that always returns bit-packing enabled type, useful inside deserialize function when enabling bitpacking
|
||||
using BPEnabledType = Deserializer<typename TInputAdapter::BitPackingEnabled, TContext>;
|
||||
// helper type, that always returns bit-packing enabled type, useful inside
|
||||
// deserialize function when enabling bitpacking
|
||||
using BPEnabledType =
|
||||
Deserializer<typename TInputAdapter::BitPackingEnabled, TContext>;
|
||||
using TConfig = typename TInputAdapter::TConfig;
|
||||
|
||||
using details::AdapterAndContextRef<TInputAdapter, TContext>::AdapterAndContextRef;
|
||||
using details::AdapterAndContextRef<TInputAdapter,
|
||||
TContext>::AdapterAndContextRef;
|
||||
|
||||
/*
|
||||
* object function
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
void object(T &&obj) {
|
||||
details::SerializeFunction<Deserializer, T>::invoke(*this, std::forward<T>(obj));
|
||||
void object(T&& obj)
|
||||
{
|
||||
details::SerializeFunction<Deserializer, T>::invoke(*this,
|
||||
std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename T, typename Fnc>
|
||||
void object(T &&obj, Fnc &&fnc) {
|
||||
void object(T&& obj, Fnc&& fnc)
|
||||
{
|
||||
fnc(*this, std::forward<T>(obj));
|
||||
}
|
||||
|
||||
/*
|
||||
* functionality, that enables simpler serialization syntax, by including additional header
|
||||
* functionality, that enables simpler serialization syntax, by including
|
||||
* additional header
|
||||
*/
|
||||
|
||||
template<typename... TArgs>
|
||||
Deserializer &operator()(TArgs &&... args) {
|
||||
Deserializer& operator()(TArgs&&... args)
|
||||
{
|
||||
archive(std::forward<TArgs>(args)...);
|
||||
return *this;
|
||||
}
|
||||
@@ -66,8 +75,10 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void value(T &v) {
|
||||
static_assert(details::IsFundamentalType<T>::value, "Value must be integral, float or enum type.");
|
||||
void value(T& v)
|
||||
{
|
||||
static_assert(details::IsFundamentalType<T>::value,
|
||||
"Value must be integral, float or enum type.");
|
||||
using TValue = typename details::IntegralFromFundamental<T>::TValue;
|
||||
this->_adapter.template readBytes<VSIZE>(reinterpret_cast<TValue&>(v));
|
||||
}
|
||||
@@ -76,8 +87,11 @@ namespace bitsery {
|
||||
* enable bit-packing
|
||||
*/
|
||||
template<typename Fnc>
|
||||
void enableBitPacking(Fnc&& fnc) {
|
||||
procEnableBitPacking(std::forward<Fnc>(fnc), std::is_same<TInputAdapter, typename TInputAdapter::BitPackingEnabled>{});
|
||||
void enableBitPacking(Fnc&& fnc)
|
||||
{
|
||||
procEnableBitPacking(
|
||||
std::forward<Fnc>(fnc),
|
||||
std::is_same<TInputAdapter, typename TInputAdapter::BitPackingEnabled>{});
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -85,38 +99,52 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T, typename Ext, typename Fnc>
|
||||
void ext(T &obj, const Ext &extension, Fnc &&fnc) {
|
||||
static_assert(details::IsExtensionTraitsDefined<Ext, T>::value, "Please define ExtensionTraits");
|
||||
void ext(T& obj, const Ext& extension, Fnc&& fnc)
|
||||
{
|
||||
static_assert(details::IsExtensionTraitsDefined<Ext, T>::value,
|
||||
"Please define ExtensionTraits");
|
||||
static_assert(traits::ExtensionTraits<Ext, T>::SupportLambdaOverload,
|
||||
"extension doesn't support overload with lambda");
|
||||
extension.deserialize(*this, obj, std::forward<Fnc>(fnc));
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T, typename Ext>
|
||||
void ext(T &obj, const Ext &extension) {
|
||||
static_assert(details::IsExtensionTraitsDefined<Ext, T>::value, "Please define ExtensionTraits");
|
||||
void ext(T& obj, const Ext& extension)
|
||||
{
|
||||
static_assert(details::IsExtensionTraitsDefined<Ext, T>::value,
|
||||
"Please define ExtensionTraits");
|
||||
static_assert(traits::ExtensionTraits<Ext, T>::SupportValueOverload,
|
||||
"extension doesn't support overload with `value<N>`");
|
||||
using ExtVType = typename traits::ExtensionTraits<Ext, T>::TValue;
|
||||
using VType = typename std::conditional<std::is_void<ExtVType>::value, details::DummyType, ExtVType>::type;
|
||||
extension.deserialize(*this, obj, [](Deserializer& s, VType &v) { s.value<VSIZE>(v);});
|
||||
using VType = typename std::conditional<std::is_void<ExtVType>::value,
|
||||
details::DummyType,
|
||||
ExtVType>::type;
|
||||
extension.deserialize(
|
||||
*this, obj, [](Deserializer& s, VType& v) { s.value<VSIZE>(v); });
|
||||
}
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext(T &obj, const Ext &extension) {
|
||||
static_assert(details::IsExtensionTraitsDefined<Ext, T>::value, "Please define ExtensionTraits");
|
||||
void ext(T& obj, const Ext& extension)
|
||||
{
|
||||
static_assert(details::IsExtensionTraitsDefined<Ext, T>::value,
|
||||
"Please define ExtensionTraits");
|
||||
static_assert(traits::ExtensionTraits<Ext, T>::SupportObjectOverload,
|
||||
"extension doesn't support overload with `object`");
|
||||
using ExtVType = typename traits::ExtensionTraits<Ext, T>::TValue;
|
||||
using VType = typename std::conditional<std::is_void<ExtVType>::value, details::DummyType, ExtVType>::type;
|
||||
extension.deserialize(*this, obj, [](Deserializer& s, VType &v) { s.object(v); });
|
||||
using VType = typename std::conditional<std::is_void<ExtVType>::value,
|
||||
details::DummyType,
|
||||
ExtVType>::type;
|
||||
extension.deserialize(
|
||||
*this, obj, [](Deserializer& s, VType& v) { s.object(v); });
|
||||
}
|
||||
|
||||
/*
|
||||
* boolValue
|
||||
*/
|
||||
void boolValue(bool &v) {
|
||||
procBoolValue(v,
|
||||
void boolValue(bool& v)
|
||||
{
|
||||
procBoolValue(
|
||||
v,
|
||||
std::is_same<TInputAdapter, typename TInputAdapter::BitPackingEnabled>{},
|
||||
std::integral_constant<bool, TInputAdapter::TConfig::CheckDataErrors>{});
|
||||
}
|
||||
@@ -126,22 +154,29 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void text(T &str, size_t maxSize) {
|
||||
static_assert(details::IsTextTraitsDefined<T>::value,
|
||||
void text(T& str, size_t maxSize)
|
||||
{
|
||||
static_assert(
|
||||
details::IsTextTraitsDefined<T>::value,
|
||||
"Please define TextTraits or include from <bitsery/traits/...>");
|
||||
static_assert(traits::ContainerTraits<T>::isResizable,
|
||||
static_assert(
|
||||
traits::ContainerTraits<T>::isResizable,
|
||||
"use text(T&) overload without `maxSize` for static containers");
|
||||
size_t length;
|
||||
readSize(length, maxSize);
|
||||
traits::ContainerTraits<T>::resize(str, length + (traits::TextTraits<T>::addNUL ? 1u : 0u));
|
||||
traits::ContainerTraits<T>::resize(
|
||||
str, length + (traits::TextTraits<T>::addNUL ? 1u : 0u));
|
||||
procText<VSIZE>(str, length);
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void text(T &str) {
|
||||
static_assert(details::IsTextTraitsDefined<T>::value,
|
||||
void text(T& str)
|
||||
{
|
||||
static_assert(
|
||||
details::IsTextTraitsDefined<T>::value,
|
||||
"Please define TextTraits or include from <bitsery/traits/...>");
|
||||
static_assert(!traits::ContainerTraits<T>::isResizable,
|
||||
static_assert(
|
||||
!traits::ContainerTraits<T>::isResizable,
|
||||
"use text(T&, size_t) overload with `maxSize` for dynamic containers");
|
||||
size_t length;
|
||||
readSize(length, traits::ContainerTraits<T>::size(str));
|
||||
@@ -155,10 +190,13 @@ namespace bitsery {
|
||||
// dynamic size containers
|
||||
|
||||
template<typename T, typename Fnc>
|
||||
void container(T &obj, size_t maxSize, Fnc &&fnc) {
|
||||
static_assert(details::IsContainerTraitsDefined<T>::value,
|
||||
void container(T& obj, size_t maxSize, Fnc&& fnc)
|
||||
{
|
||||
static_assert(
|
||||
details::IsContainerTraitsDefined<T>::value,
|
||||
"Please define ContainerTraits or include from <bitsery/traits/...>");
|
||||
static_assert(traits::ContainerTraits<T>::isResizable,
|
||||
static_assert(
|
||||
traits::ContainerTraits<T>::isResizable,
|
||||
"use container(T&) overload without `maxSize` for static containers");
|
||||
size_t size{};
|
||||
readSize(size, maxSize);
|
||||
@@ -167,22 +205,31 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void container(T &obj, size_t maxSize) {
|
||||
static_assert(details::IsContainerTraitsDefined<T>::value,
|
||||
void container(T& obj, size_t maxSize)
|
||||
{
|
||||
static_assert(
|
||||
details::IsContainerTraitsDefined<T>::value,
|
||||
"Please define ContainerTraits or include from <bitsery/traits/...>");
|
||||
static_assert(traits::ContainerTraits<T>::isResizable,
|
||||
static_assert(
|
||||
traits::ContainerTraits<T>::isResizable,
|
||||
"use container(T&) overload without `maxSize` for static containers");
|
||||
size_t size{};
|
||||
readSize(size, maxSize);
|
||||
traits::ContainerTraits<T>::resize(obj, size);
|
||||
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::integral_constant<bool, traits::ContainerTraits<T>::isContiguous>{});
|
||||
procContainer<VSIZE>(
|
||||
std::begin(obj),
|
||||
std::end(obj),
|
||||
std::integral_constant<bool, traits::ContainerTraits<T>::isContiguous>{});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container(T &obj, size_t maxSize) {
|
||||
static_assert(details::IsContainerTraitsDefined<T>::value,
|
||||
void container(T& obj, size_t maxSize)
|
||||
{
|
||||
static_assert(
|
||||
details::IsContainerTraitsDefined<T>::value,
|
||||
"Please define ContainerTraits or include from <bitsery/traits/...>");
|
||||
static_assert(traits::ContainerTraits<T>::isResizable,
|
||||
static_assert(
|
||||
traits::ContainerTraits<T>::isResizable,
|
||||
"use container(T&) overload without `maxSize` for static containers");
|
||||
size_t size{};
|
||||
readSize(size, maxSize);
|
||||
@@ -191,125 +238,222 @@ namespace bitsery {
|
||||
}
|
||||
// fixed size containers
|
||||
|
||||
template<typename T, typename Fnc, typename std::enable_if<!std::is_integral<Fnc>::value>::type * = nullptr>
|
||||
void container(T &obj, Fnc &&fnc) {
|
||||
static_assert(details::IsContainerTraitsDefined<T>::value,
|
||||
template<
|
||||
typename T,
|
||||
typename Fnc,
|
||||
typename std::enable_if<!std::is_integral<Fnc>::value>::type* = nullptr>
|
||||
void container(T& obj, Fnc&& fnc)
|
||||
{
|
||||
static_assert(
|
||||
details::IsContainerTraitsDefined<T>::value,
|
||||
"Please define ContainerTraits or include from <bitsery/traits/...>");
|
||||
static_assert(!traits::ContainerTraits<T>::isResizable,
|
||||
"use container(T&, size_t, Fnc) overload with `maxSize` for dynamic containers");
|
||||
"use container(T&, size_t, Fnc) overload with `maxSize` for "
|
||||
"dynamic containers");
|
||||
procContainer(std::begin(obj), std::end(obj), std::forward<Fnc>(fnc));
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void container(T &obj) {
|
||||
static_assert(details::IsContainerTraitsDefined<T>::value,
|
||||
void container(T& obj)
|
||||
{
|
||||
static_assert(
|
||||
details::IsContainerTraitsDefined<T>::value,
|
||||
"Please define ContainerTraits or include from <bitsery/traits/...>");
|
||||
static_assert(!traits::ContainerTraits<T>::isResizable,
|
||||
"use container(T&, size_t) overload with `maxSize` for dynamic containers");
|
||||
"use container(T&, size_t) overload with `maxSize` for "
|
||||
"dynamic containers");
|
||||
static_assert(VSIZE > 0, "");
|
||||
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::integral_constant<bool, traits::ContainerTraits<T>::isContiguous>{});
|
||||
procContainer<VSIZE>(
|
||||
std::begin(obj),
|
||||
std::end(obj),
|
||||
std::integral_constant<bool, traits::ContainerTraits<T>::isContiguous>{});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container(T &obj) {
|
||||
static_assert(details::IsContainerTraitsDefined<T>::value,
|
||||
void container(T& obj)
|
||||
{
|
||||
static_assert(
|
||||
details::IsContainerTraitsDefined<T>::value,
|
||||
"Please define ContainerTraits or include from <bitsery/traits/...>");
|
||||
static_assert(!traits::ContainerTraits<T>::isResizable,
|
||||
"use container(T&, size_t) overload with `maxSize` for dynamic containers");
|
||||
"use container(T&, size_t) overload with `maxSize` for "
|
||||
"dynamic containers");
|
||||
procContainer(std::begin(obj), std::end(obj));
|
||||
}
|
||||
|
||||
// overloads for functions with explicit type size
|
||||
|
||||
template<typename T>
|
||||
void value1b(T &&v) { value<1>(std::forward<T>(v)); }
|
||||
void value1b(T&& v)
|
||||
{
|
||||
value<1>(std::forward<T>(v));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void value2b(T &&v) { value<2>(std::forward<T>(v)); }
|
||||
void value2b(T&& v)
|
||||
{
|
||||
value<2>(std::forward<T>(v));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void value4b(T &&v) { value<4>(std::forward<T>(v)); }
|
||||
void value4b(T&& v)
|
||||
{
|
||||
value<4>(std::forward<T>(v));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void value8b(T &&v) { value<8>(std::forward<T>(v)); }
|
||||
void value8b(T&& v)
|
||||
{
|
||||
value<8>(std::forward<T>(v));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void value16b(T &&v) { value<16>(std::forward<T>(v)); }
|
||||
void value16b(T&& v)
|
||||
{
|
||||
value<16>(std::forward<T>(v));
|
||||
}
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext1b(T &v, Ext &&extension) { ext<1, T, Ext>(v, std::forward<Ext>(extension)); }
|
||||
void ext1b(T& v, Ext&& extension)
|
||||
{
|
||||
ext<1, T, Ext>(v, std::forward<Ext>(extension));
|
||||
}
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext2b(T &v, Ext &&extension) { ext<2, T, Ext>(v, std::forward<Ext>(extension)); }
|
||||
void ext2b(T& v, Ext&& extension)
|
||||
{
|
||||
ext<2, T, Ext>(v, std::forward<Ext>(extension));
|
||||
}
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext4b(T &v, Ext &&extension) { ext<4, T, Ext>(v, std::forward<Ext>(extension)); }
|
||||
void ext4b(T& v, Ext&& extension)
|
||||
{
|
||||
ext<4, T, Ext>(v, std::forward<Ext>(extension));
|
||||
}
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext8b(T &v, Ext &&extension) { ext<8, T, Ext>(v, std::forward<Ext>(extension)); }
|
||||
void ext8b(T& v, Ext&& extension)
|
||||
{
|
||||
ext<8, T, Ext>(v, std::forward<Ext>(extension));
|
||||
}
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext16b(T &v, Ext &&extension) { ext<16, T, Ext>(v, std::forward<Ext>(extension)); }
|
||||
void ext16b(T& v, Ext&& extension)
|
||||
{
|
||||
ext<16, T, Ext>(v, std::forward<Ext>(extension));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void text1b(T &str, size_t maxSize) { text<1>(str, maxSize); }
|
||||
void text1b(T& str, size_t maxSize)
|
||||
{
|
||||
text<1>(str, maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void text2b(T &str, size_t maxSize) { text<2>(str, maxSize); }
|
||||
void text2b(T& str, size_t maxSize)
|
||||
{
|
||||
text<2>(str, maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void text4b(T &str, size_t maxSize) { text<4>(str, maxSize); }
|
||||
void text4b(T& str, size_t maxSize)
|
||||
{
|
||||
text<4>(str, maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void text1b(T &str) { text<1>(str); }
|
||||
void text1b(T& str)
|
||||
{
|
||||
text<1>(str);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void text2b(T &str) { text<2>(str); }
|
||||
void text2b(T& str)
|
||||
{
|
||||
text<2>(str);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void text4b(T &str) { text<4>(str); }
|
||||
void text4b(T& str)
|
||||
{
|
||||
text<4>(str);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container1b(T &&obj, size_t maxSize) { container<1>(std::forward<T>(obj), maxSize); }
|
||||
void container1b(T&& obj, size_t maxSize)
|
||||
{
|
||||
container<1>(std::forward<T>(obj), maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container2b(T &&obj, size_t maxSize) { container<2>(std::forward<T>(obj), maxSize); }
|
||||
void container2b(T&& obj, size_t maxSize)
|
||||
{
|
||||
container<2>(std::forward<T>(obj), maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container4b(T &&obj, size_t maxSize) { container<4>(std::forward<T>(obj), maxSize); }
|
||||
void container4b(T&& obj, size_t maxSize)
|
||||
{
|
||||
container<4>(std::forward<T>(obj), maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container8b(T &&obj, size_t maxSize) { container<8>(std::forward<T>(obj), maxSize); }
|
||||
void container8b(T&& obj, size_t maxSize)
|
||||
{
|
||||
container<8>(std::forward<T>(obj), maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container16b(T &&obj, size_t maxSize) { container<16>(std::forward<T>(obj), maxSize); }
|
||||
void container16b(T&& obj, size_t maxSize)
|
||||
{
|
||||
container<16>(std::forward<T>(obj), maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container1b(T &&obj) { container<1>(std::forward<T>(obj)); }
|
||||
void container1b(T&& obj)
|
||||
{
|
||||
container<1>(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container2b(T &&obj) { container<2>(std::forward<T>(obj)); }
|
||||
void container2b(T&& obj)
|
||||
{
|
||||
container<2>(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container4b(T &&obj) { container<4>(std::forward<T>(obj)); }
|
||||
void container4b(T&& obj)
|
||||
{
|
||||
container<4>(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container8b(T &&obj) { container<8>(std::forward<T>(obj)); }
|
||||
void container8b(T&& obj)
|
||||
{
|
||||
container<8>(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container16b(T &&obj) { container<16>(std::forward<T>(obj)); }
|
||||
void container16b(T&& obj)
|
||||
{
|
||||
container<16>(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void readSize(size_t& size, size_t maxSize) {
|
||||
details::readSize(this->_adapter, size, maxSize,
|
||||
void readSize(size_t& size, size_t maxSize)
|
||||
{
|
||||
details::readSize(
|
||||
this->_adapter,
|
||||
size,
|
||||
maxSize,
|
||||
std::integral_constant<bool, TInputAdapter::TConfig::CheckDataErrors>{});
|
||||
}
|
||||
|
||||
// process value types
|
||||
// false_type means that we must process all elements individually
|
||||
template<size_t VSIZE, typename It>
|
||||
void procContainer(It first, It last, std::false_type) {
|
||||
void procContainer(It first, It last, std::false_type)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
value<VSIZE>(*first);
|
||||
}
|
||||
@@ -317,36 +461,45 @@ namespace bitsery {
|
||||
// process value types
|
||||
// true_type means, that we can copy whole buffer
|
||||
template<size_t VSIZE, typename It>
|
||||
void procContainer(It first, It last, std::true_type) {
|
||||
void procContainer(It first, It last, std::true_type)
|
||||
{
|
||||
using TValue = typename std::decay<decltype(*first)>::type;
|
||||
using TIntegral = typename details::IntegralFromFundamental<TValue>::TValue;
|
||||
if (first != last) {
|
||||
const auto distance = std::distance(first, last);
|
||||
this->_adapter.template readBuffer<VSIZE>(reinterpret_cast<TIntegral*>(&(*first)), static_cast<size_t>(distance));
|
||||
this->_adapter.template readBuffer<VSIZE>(
|
||||
reinterpret_cast<TIntegral*>(&(*first)), static_cast<size_t>(distance));
|
||||
}
|
||||
}
|
||||
|
||||
// process by calling functions
|
||||
template<typename It, typename Fnc>
|
||||
void procContainer(It first, It last, Fnc fnc) {
|
||||
void procContainer(It first, It last, Fnc fnc)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
fnc(*this, *first);
|
||||
}
|
||||
|
||||
// process object types
|
||||
template<typename It>
|
||||
void procContainer(It first, It last) {
|
||||
void procContainer(It first, It last)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
object(*first);
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void procText(T& str, size_t length) {
|
||||
void procText(T& str, size_t length)
|
||||
{
|
||||
auto begin = std::begin(str);
|
||||
// end of string, not end of container
|
||||
using diff_t = typename std::iterator_traits<decltype(begin)>::difference_type;
|
||||
using diff_t =
|
||||
typename std::iterator_traits<decltype(begin)>::difference_type;
|
||||
auto end = std::next(begin, static_cast<diff_t>(length));
|
||||
procContainer<VSIZE>(begin, end, std::integral_constant<bool, traits::ContainerTraits<T>::isContiguous>{});
|
||||
procContainer<VSIZE>(
|
||||
begin,
|
||||
end,
|
||||
std::integral_constant<bool, traits::ContainerTraits<T>::isContiguous>{});
|
||||
// null terminated character at the end
|
||||
if (traits::TextTraits<T>::addNUL)
|
||||
*end = {};
|
||||
@@ -354,13 +507,15 @@ namespace bitsery {
|
||||
|
||||
// proc bool writing bit or byte, depending on if BitPackingEnabled or not
|
||||
template<typename HandleDataErrors>
|
||||
void procBoolValue(bool &v, std::true_type, HandleDataErrors) {
|
||||
void procBoolValue(bool& v, std::true_type, HandleDataErrors)
|
||||
{
|
||||
uint8_t tmp{};
|
||||
this->_adapter.readBits(tmp, 1);
|
||||
v = tmp == 1;
|
||||
}
|
||||
|
||||
void procBoolValue(bool &v, std::false_type, std::true_type) {
|
||||
void procBoolValue(bool& v, std::false_type, std::true_type)
|
||||
{
|
||||
uint8_t tmp{};
|
||||
this->_adapter.template readBytes<1>(tmp);
|
||||
if (tmp > 1)
|
||||
@@ -368,7 +523,8 @@ namespace bitsery {
|
||||
v = tmp == 1;
|
||||
}
|
||||
|
||||
void procBoolValue(bool &v, std::false_type, std::false_type) {
|
||||
void procBoolValue(bool& v, std::false_type, std::false_type)
|
||||
{
|
||||
uint8_t tmp{};
|
||||
this->_adapter.template readBytes<1>(tmp);
|
||||
v = tmp > 0;
|
||||
@@ -376,61 +532,68 @@ namespace bitsery {
|
||||
|
||||
// enable bit-packing or do nothing if it is already enabled
|
||||
template<typename Fnc>
|
||||
void procEnableBitPacking(const Fnc& fnc, std::true_type) {
|
||||
void procEnableBitPacking(const Fnc& fnc, std::true_type)
|
||||
{
|
||||
fnc(*this);
|
||||
}
|
||||
|
||||
template<typename Fnc>
|
||||
void procEnableBitPacking(const Fnc& fnc, std::false_type) {
|
||||
auto des = createWithContext(std::integral_constant<bool, Deserializer::HasContext>{});
|
||||
void procEnableBitPacking(const Fnc& fnc, std::false_type)
|
||||
{
|
||||
auto des = createWithContext(
|
||||
std::integral_constant<bool, Deserializer::HasContext>{});
|
||||
fnc(des);
|
||||
}
|
||||
|
||||
BPEnabledType createWithContext(std::true_type) {
|
||||
BPEnabledType createWithContext(std::true_type)
|
||||
{
|
||||
return BPEnabledType{ this->_context, this->_adapter };
|
||||
}
|
||||
|
||||
BPEnabledType createWithContext(std::false_type) {
|
||||
BPEnabledType createWithContext(std::false_type)
|
||||
{
|
||||
return BPEnabledType{ this->_adapter };
|
||||
}
|
||||
|
||||
|
||||
// these are dummy functions for extensions that have TValue = void
|
||||
void object(details::DummyType&) {
|
||||
|
||||
}
|
||||
void object(details::DummyType&) {}
|
||||
|
||||
template<size_t VSIZE>
|
||||
void value(details::DummyType&) {
|
||||
|
||||
void value(details::DummyType&)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, typename... TArgs>
|
||||
void archive(T &&head, TArgs &&... tail) {
|
||||
void archive(T&& head, TArgs&&... tail)
|
||||
{
|
||||
// serialize object
|
||||
details::BriefSyntaxFunction<Deserializer, T>::invoke(*this, std::forward<T>(head));
|
||||
details::BriefSyntaxFunction<Deserializer, T>::invoke(
|
||||
*this, std::forward<T>(head));
|
||||
// expand other elements
|
||||
archive(std::forward<TArgs>(tail)...);
|
||||
}
|
||||
|
||||
// dummy function, that stops archive variadic arguments expansion
|
||||
void archive() {
|
||||
}
|
||||
|
||||
void archive() {}
|
||||
};
|
||||
|
||||
// helper type
|
||||
|
||||
//helper function that set ups all the basic steps and after deserialziation returns status
|
||||
// helper function that set ups all the basic steps and after deserialziation
|
||||
// returns status
|
||||
template<typename InputAdapter, typename T>
|
||||
std::pair<ReaderError, bool> quickDeserialization(InputAdapter adapter, T& value) {
|
||||
std::pair<ReaderError, bool>
|
||||
quickDeserialization(InputAdapter adapter, T& value)
|
||||
{
|
||||
Deserializer<InputAdapter> des{ std::move(adapter) };
|
||||
des.object(value);
|
||||
return { des.adapter().error(), des.adapter().isCompletedSuccessfully() };
|
||||
}
|
||||
|
||||
template<typename Context, typename InputAdapter, typename T>
|
||||
std::pair<ReaderError, bool> quickDeserialization(Context& ctx, InputAdapter adapter, T& value) {
|
||||
std::pair<ReaderError, bool>
|
||||
quickDeserialization(Context& ctx, InputAdapter adapter, T& value)
|
||||
{
|
||||
Deserializer<InputAdapter, Context> des{ ctx, std::move(adapter) };
|
||||
des.object(value);
|
||||
return { des.adapter().error(), des.adapter().isCompletedSuccessfully() };
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -23,21 +23,22 @@
|
||||
#ifndef BITSERY_DETAILS_ADAPTER_BIT_PACKING_H
|
||||
#define BITSERY_DETAILS_ADAPTER_BIT_PACKING_H
|
||||
|
||||
#include "not_defined_type.h"
|
||||
#include "./adapter_common.h"
|
||||
#include "../common.h"
|
||||
#include "./adapter_common.h"
|
||||
#include "not_defined_type.h"
|
||||
#include <limits>
|
||||
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
namespace details {
|
||||
|
||||
template<typename TAdapter>
|
||||
class InputAdapterBitPackingWrapper {
|
||||
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.
|
||||
// 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;
|
||||
@@ -47,12 +48,11 @@ namespace bitsery {
|
||||
{
|
||||
}
|
||||
|
||||
~InputAdapterBitPackingWrapper() {
|
||||
align();
|
||||
}
|
||||
~InputAdapterBitPackingWrapper() { align(); }
|
||||
|
||||
template<size_t SIZE, typename T>
|
||||
void readBytes(T &v) {
|
||||
void readBytes(T& v)
|
||||
{
|
||||
static_assert(std::is_integral<T>(), "");
|
||||
static_assert(sizeof(T) == SIZE, "");
|
||||
using UT = typename std::make_unsigned<T>::type;
|
||||
@@ -63,7 +63,8 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<size_t SIZE, typename T>
|
||||
void readBuffer(T *buf, size_t count) {
|
||||
void readBuffer(T* buf, size_t count)
|
||||
{
|
||||
static_assert(std::is_integral<T>(), "");
|
||||
static_assert(sizeof(T) == SIZE, "");
|
||||
|
||||
@@ -79,58 +80,58 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void readBits(T &v, size_t bitsCount) {
|
||||
void readBits(T& v, size_t bitsCount)
|
||||
{
|
||||
static_assert(std::is_integral<T>() && std::is_unsigned<T>(), "");
|
||||
readBitsInternal(v, bitsCount);
|
||||
}
|
||||
|
||||
void align() {
|
||||
void align()
|
||||
{
|
||||
if (m_scratchBits) {
|
||||
ScratchType tmp{};
|
||||
readBitsInternal(tmp, m_scratchBits);
|
||||
handleAlignErrors(tmp, std::integral_constant<bool, TConfig::CheckDataErrors>{});
|
||||
handleAlignErrors(
|
||||
tmp, std::integral_constant<bool, TConfig::CheckDataErrors>{});
|
||||
}
|
||||
}
|
||||
|
||||
void currentReadPos(size_t pos) {
|
||||
void currentReadPos(size_t pos)
|
||||
{
|
||||
align();
|
||||
this->_wrapped.currentReadPos(pos);
|
||||
}
|
||||
|
||||
size_t currentReadPos() const {
|
||||
return this->_wrapped.currentReadPos();
|
||||
}
|
||||
size_t currentReadPos() const { return this->_wrapped.currentReadPos(); }
|
||||
|
||||
void currentReadEndPos(size_t pos) {
|
||||
this->_wrapped.currentReadEndPos(pos);
|
||||
}
|
||||
void currentReadEndPos(size_t pos) { this->_wrapped.currentReadEndPos(pos); }
|
||||
|
||||
size_t currentReadEndPos() const {
|
||||
size_t currentReadEndPos() const
|
||||
{
|
||||
return this->_wrapped.currentReadEndPos();
|
||||
}
|
||||
|
||||
bool isCompletedSuccessfully() const {
|
||||
bool isCompletedSuccessfully() const
|
||||
{
|
||||
return this->_wrapped.isCompletedSuccessfully();
|
||||
}
|
||||
|
||||
ReaderError error() const {
|
||||
return this->_wrapped.error();
|
||||
}
|
||||
ReaderError error() const { return this->_wrapped.error(); }
|
||||
|
||||
void error(ReaderError error) {
|
||||
this->_wrapped.error(error);
|
||||
}
|
||||
void error(ReaderError error) { this->_wrapped.error(error); }
|
||||
|
||||
private:
|
||||
TAdapter& _wrapped;
|
||||
using UnsignedValue = typename std::make_unsigned<typename TAdapter::TValue>::type;
|
||||
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) {
|
||||
void readBitsInternal(T& v, size_t size)
|
||||
{
|
||||
auto bitsLeft = size;
|
||||
using TFast = typename FastType<T>::type;
|
||||
TFast res{};
|
||||
@@ -138,12 +139,14 @@ namespace bitsery {
|
||||
auto bits = (std::min)(bitsLeft, details::BitsSize<UnsignedValue>::value);
|
||||
if (m_scratchBits < bits) {
|
||||
UnsignedValue tmp;
|
||||
this->_wrapped.template readBytes<sizeof(UnsignedValue), 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);
|
||||
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;
|
||||
@@ -152,19 +155,18 @@ namespace bitsery {
|
||||
v = static_cast<T>(res);
|
||||
}
|
||||
|
||||
void handleAlignErrors(ScratchType value, std::true_type) {
|
||||
void handleAlignErrors(ScratchType value, std::true_type)
|
||||
{
|
||||
if (value)
|
||||
error(ReaderError::InvalidData);
|
||||
}
|
||||
|
||||
void handleAlignErrors(ScratchType, std::false_type) {
|
||||
}
|
||||
|
||||
void handleAlignErrors(ScratchType, std::false_type) {}
|
||||
};
|
||||
|
||||
|
||||
template<typename TAdapter>
|
||||
class BasicMeasureSizeBitPackingWrapper {
|
||||
class BasicMeasureSizeBitPackingWrapper
|
||||
{
|
||||
public:
|
||||
using BitPackingEnabled = BasicMeasureSizeBitPackingWrapper<TAdapter>;
|
||||
using TConfig = typename TAdapter::TConfig;
|
||||
@@ -175,22 +177,23 @@ namespace bitsery {
|
||||
{
|
||||
}
|
||||
|
||||
~BasicMeasureSizeBitPackingWrapper() {
|
||||
align();
|
||||
}
|
||||
~BasicMeasureSizeBitPackingWrapper() { align(); }
|
||||
|
||||
template<size_t SIZE, typename T>
|
||||
void writeBytes(const T& value) {
|
||||
void writeBytes(const T& value)
|
||||
{
|
||||
_wrapped.template writeBytes<SIZE>(value);
|
||||
}
|
||||
|
||||
template<size_t SIZE, typename T>
|
||||
void writeBuffer(const T* buf, size_t count) {
|
||||
void writeBuffer(const T* buf, size_t count)
|
||||
{
|
||||
_wrapped.template writeBuffer<SIZE>(buf, count);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void writeBits(const T& , size_t bitsCount) {
|
||||
void writeBits(const T&, size_t bitsCount)
|
||||
{
|
||||
_scratchBits += bitsCount;
|
||||
while (_scratchBits >= 8) {
|
||||
writeOneByte();
|
||||
@@ -198,45 +201,46 @@ namespace bitsery {
|
||||
}
|
||||
}
|
||||
|
||||
void align() {
|
||||
void align()
|
||||
{
|
||||
if (_scratchBits > 0) {
|
||||
_scratchBits = 0;
|
||||
writeOneByte();
|
||||
}
|
||||
}
|
||||
|
||||
void currentWritePos(size_t pos) {
|
||||
void currentWritePos(size_t pos)
|
||||
{
|
||||
align();
|
||||
this->_wrapped.currentWritePos(pos);
|
||||
}
|
||||
|
||||
size_t currentWritePos() const {
|
||||
return this->_wrapped.currentWritePos();
|
||||
}
|
||||
size_t currentWritePos() const { return this->_wrapped.currentWritePos(); }
|
||||
|
||||
void flush() {
|
||||
void flush()
|
||||
{
|
||||
align();
|
||||
this->_wrapped.flush();
|
||||
}
|
||||
|
||||
size_t writtenBytesCount() const {
|
||||
size_t writtenBytesCount() const
|
||||
{
|
||||
return this->_wrapped.writtenBytesCount();
|
||||
}
|
||||
|
||||
private:
|
||||
void writeOneByte() {
|
||||
_wrapped.template writeBytes<1>(uint8_t{});
|
||||
}
|
||||
void writeOneByte() { _wrapped.template writeBytes<1>(uint8_t{}); }
|
||||
TAdapter& _wrapped;
|
||||
size_t _scratchBits{};
|
||||
};
|
||||
|
||||
|
||||
template<typename TAdapter>
|
||||
class OutputAdapterBitPackingWrapper {
|
||||
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.
|
||||
// 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;
|
||||
@@ -246,12 +250,11 @@ namespace bitsery {
|
||||
{
|
||||
}
|
||||
|
||||
~OutputAdapterBitPackingWrapper() {
|
||||
align();
|
||||
}
|
||||
~OutputAdapterBitPackingWrapper() { align(); }
|
||||
|
||||
template<size_t SIZE, typename T>
|
||||
void writeBytes(const T &v) {
|
||||
void writeBytes(const T& v)
|
||||
{
|
||||
static_assert(std::is_integral<T>(), "");
|
||||
static_assert(sizeof(T) == SIZE, "");
|
||||
|
||||
@@ -259,12 +262,14 @@ namespace bitsery {
|
||||
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);
|
||||
writeBitsInternal(reinterpret_cast<const UT&>(v),
|
||||
details::BitsSize<T>::value);
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t SIZE, typename T>
|
||||
void writeBuffer(const T *buf, size_t count) {
|
||||
void writeBuffer(const T* buf, size_t count)
|
||||
{
|
||||
static_assert(std::is_integral<T>(), "");
|
||||
static_assert(sizeof(T) == SIZE, "");
|
||||
if (!_scratchBits) {
|
||||
@@ -274,52 +279,60 @@ namespace bitsery {
|
||||
// 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);
|
||||
writeBitsInternal(reinterpret_cast<const UT&>(*it),
|
||||
details::BitsSize<T>::value);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void writeBits(const T &v, size_t bitsCount) {
|
||||
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)));
|
||||
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 align()
|
||||
{
|
||||
writeBitsInternal(UnsignedType{},
|
||||
(details::BitsSize<UnsignedType>::value - _scratchBits) %
|
||||
8);
|
||||
}
|
||||
|
||||
void currentWritePos(size_t pos) {
|
||||
void currentWritePos(size_t pos)
|
||||
{
|
||||
align();
|
||||
this->_wrapped.currentWritePos(pos);
|
||||
}
|
||||
|
||||
size_t currentWritePos() const {
|
||||
return this->_wrapped.currentWritePos();
|
||||
}
|
||||
size_t currentWritePos() const { return this->_wrapped.currentWritePos(); }
|
||||
|
||||
void flush() {
|
||||
void flush()
|
||||
{
|
||||
align();
|
||||
this->_wrapped.flush();
|
||||
}
|
||||
|
||||
size_t writtenBytesCount() const {
|
||||
size_t writtenBytesCount() const
|
||||
{
|
||||
return this->_wrapped.writtenBytesCount();
|
||||
}
|
||||
|
||||
private:
|
||||
TAdapter& _wrapped;
|
||||
|
||||
using UnsignedType = typename std::make_unsigned<typename TAdapter::TValue>::type;
|
||||
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");
|
||||
|
||||
static_assert(details::IsDefined<ScratchType>::value,
|
||||
"Underlying adapter value type is not supported");
|
||||
|
||||
template<typename T>
|
||||
void writeBitsInternal(const T &v, size_t size) {
|
||||
void writeBitsInternal(const T& v, size_t size)
|
||||
{
|
||||
constexpr size_t valueSize = details::BitsSize<UnsignedType>::value;
|
||||
T value = v;
|
||||
size_t bitsLeft = size;
|
||||
@@ -329,7 +342,8 @@ namespace bitsery {
|
||||
_scratchBits += bits;
|
||||
if (_scratchBits >= valueSize) {
|
||||
auto tmp = static_cast<UnsignedType>(_scratch & _MASK);
|
||||
this->_wrapped.template writeBytes<sizeof(UnsignedType), UnsignedType >(tmp);
|
||||
this->_wrapped.template writeBytes<sizeof(UnsignedType), UnsignedType>(
|
||||
tmp);
|
||||
_scratch >>= valueSize;
|
||||
_scratchBits -= valueSize;
|
||||
|
||||
@@ -340,13 +354,15 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
// overload for TValue, for better performance
|
||||
void writeBitsInternal(const UnsignedType &v, size_t size) {
|
||||
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);
|
||||
this->_wrapped.template writeBytes<sizeof(UnsignedType), UnsignedType>(
|
||||
tmp);
|
||||
_scratch >>= details::BitsSize<UnsignedType>::value;
|
||||
_scratchBits -= details::BitsSize<UnsignedType>::value;
|
||||
}
|
||||
@@ -360,5 +376,4 @@ namespace bitsery {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_DETAILS_ADAPTER_BIT_PACKING_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -23,15 +23,16 @@
|
||||
#ifndef BITSERY_DETAILS_ADAPTER_COMMON_H
|
||||
#define BITSERY_DETAILS_ADAPTER_COMMON_H
|
||||
|
||||
#include "not_defined_type.h"
|
||||
#include "../common.h"
|
||||
#include "not_defined_type.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
enum class ReaderError {
|
||||
enum class ReaderError
|
||||
{
|
||||
NoError,
|
||||
ReadingError, // this might be used with stream adapter
|
||||
DataOverflow,
|
||||
@@ -46,7 +47,9 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename Reader>
|
||||
void handleReadMaxSize(Reader& r, size_t& size, size_t maxSize, std::true_type) {
|
||||
void
|
||||
handleReadMaxSize(Reader& r, size_t& size, size_t maxSize, std::true_type)
|
||||
{
|
||||
if (size > maxSize) {
|
||||
r.error(ReaderError::InvalidData);
|
||||
size = {};
|
||||
@@ -54,11 +57,18 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Reader>
|
||||
void handleReadMaxSize(Reader&, size_t&, size_t, std::false_type) {
|
||||
void
|
||||
handleReadMaxSize(Reader&, size_t&, size_t, std::false_type)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Reader, bool CheckMaxSize>
|
||||
void readSize(Reader& r, size_t& size, size_t maxSize, std::integral_constant<bool, CheckMaxSize> 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) {
|
||||
@@ -78,7 +88,9 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Writer>
|
||||
void writeSize(Writer& w, const size_t size) {
|
||||
void
|
||||
writeSize(Writer& w, const size_t size)
|
||||
{
|
||||
if (size < 0x80u) {
|
||||
w.template writeBytes<1>(static_cast<uint8_t>(size));
|
||||
} else {
|
||||
@@ -98,54 +110,72 @@ namespace bitsery {
|
||||
* swap utils
|
||||
*/
|
||||
|
||||
//add swap functions to class, to avoid compilation warning about unused functions
|
||||
struct SwapImpl {
|
||||
static uint64_t exec(uint64_t value) {
|
||||
// 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;
|
||||
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) {
|
||||
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;
|
||||
return (value & 0x000000ff) << 24 | (value & 0x0000ff00) << 8 |
|
||||
(value & 0x00ff0000) >> 8 | (value & 0xff000000) >> 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint16_t exec(uint16_t value) {
|
||||
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) {
|
||||
static uint8_t exec(uint8_t value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename TValue>
|
||||
TValue swap(TValue value) {
|
||||
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;
|
||||
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.
|
||||
// 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 {
|
||||
struct EndiannessTestData
|
||||
{
|
||||
static constexpr uint32_t _sample4Bytes = 0x01020304;
|
||||
static constexpr uint8_t _sample1stByte = (const uint8_t&)_sample4Bytes;
|
||||
};
|
||||
@@ -153,76 +183,94 @@ namespace bitsery {
|
||||
#pragma warning(default : 4310)
|
||||
#endif
|
||||
|
||||
constexpr EndiannessType getSystemEndianness() {
|
||||
static_assert(EndiannessTestData::_sample1stByte == 0x04 || EndiannessTestData::_sample1stByte == 0x01,
|
||||
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
|
||||
return EndiannessTestData::_sample1stByte == 0x04
|
||||
? EndiannessType::LittleEndian
|
||||
: EndiannessType::BigEndian;
|
||||
}
|
||||
|
||||
template<typename Config>
|
||||
using ShouldSwap = std::integral_constant<bool, Config::Endianness != details::getSystemEndianness()>;
|
||||
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> {
|
||||
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 {
|
||||
struct ScratchType
|
||||
{
|
||||
using type = NotDefinedType;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct ScratchType<uint8_t> {
|
||||
struct ScratchType<uint8_t>
|
||||
{
|
||||
using type = uint_fast16_t;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct FastType {
|
||||
struct FastType
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct FastType<uint8_t> {
|
||||
struct FastType<uint8_t>
|
||||
{
|
||||
using type = uint_fast8_t;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct FastType<uint16_t> {
|
||||
struct FastType<uint16_t>
|
||||
{
|
||||
using type = uint_fast16_t;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct FastType<uint32_t> {
|
||||
struct FastType<uint32_t>
|
||||
{
|
||||
using type = uint_fast32_t;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct FastType<uint64_t> {
|
||||
struct FastType<uint64_t>
|
||||
{
|
||||
using type = uint_fast64_t;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct FastType<int8_t> {
|
||||
struct FastType<int8_t>
|
||||
{
|
||||
using type = int_fast8_t;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct FastType<int16_t> {
|
||||
struct FastType<int16_t>
|
||||
{
|
||||
using type = int_fast16_t;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct FastType<int32_t> {
|
||||
struct FastType<int32_t>
|
||||
{
|
||||
using type = int_fast32_t;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct FastType<int64_t> {
|
||||
struct FastType<int64_t>
|
||||
{
|
||||
using type = int_fast64_t;
|
||||
};
|
||||
|
||||
@@ -231,31 +279,35 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename Adapter>
|
||||
struct OutputAdapterBaseCRTP {
|
||||
struct OutputAdapterBaseCRTP
|
||||
{
|
||||
|
||||
template<size_t SIZE, typename T>
|
||||
void writeBytes(const T &v) {
|
||||
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) {
|
||||
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 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() {
|
||||
|
||||
}
|
||||
void align() {}
|
||||
|
||||
OutputAdapterBaseCRTP() = default;
|
||||
OutputAdapterBaseCRTP(const OutputAdapterBaseCRTP&) = delete;
|
||||
@@ -264,62 +316,73 @@ namespace bitsery {
|
||||
OutputAdapterBaseCRTP& operator=(OutputAdapterBaseCRTP&&) = default;
|
||||
|
||||
private:
|
||||
|
||||
template<typename T>
|
||||
void writeSwappedValue(const T *v, std::true_type) {
|
||||
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));
|
||||
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));
|
||||
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) {
|
||||
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));
|
||||
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));
|
||||
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 {
|
||||
struct InputAdapterBaseCRTP
|
||||
{
|
||||
|
||||
template<size_t SIZE, typename T>
|
||||
void readBytes(T& v) {
|
||||
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));
|
||||
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) {
|
||||
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);
|
||||
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 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() {
|
||||
|
||||
}
|
||||
void align() {}
|
||||
|
||||
InputAdapterBaseCRTP() = default;
|
||||
InputAdapterBaseCRTP(const InputAdapterBaseCRTP&) = delete;
|
||||
@@ -331,30 +394,34 @@ namespace bitsery {
|
||||
virtual ~InputAdapterBaseCRTP() = default;
|
||||
|
||||
private:
|
||||
|
||||
template<typename T>
|
||||
void swapDataBits(T *v, size_t count, std::true_type) {
|
||||
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); });
|
||||
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) {
|
||||
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) {
|
||||
void swapDataBits(T& v, std::true_type)
|
||||
{
|
||||
v = details::swap(v);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void swapDataBits(T &, std::false_type) {
|
||||
void swapDataBits(T&, std::false_type)
|
||||
{
|
||||
// empty function because no swap is required
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_DETAILS_ADAPTER_COMMON_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -30,118 +30,168 @@
|
||||
namespace bitsery {
|
||||
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()) {
|
||||
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()) {
|
||||
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) {
|
||||
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) {
|
||||
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<
|
||||
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()) {
|
||||
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<
|
||||
template<typename S,
|
||||
typename T,
|
||||
typename std::enable_if<
|
||||
!traits::ContainerTraits<T>::isResizable>::type* = nullptr>
|
||||
void processText(S &s, T &c) {
|
||||
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 {
|
||||
|
||||
};
|
||||
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_} {};
|
||||
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) {
|
||||
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) {
|
||||
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_} {};
|
||||
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
|
||||
// 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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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>{});
|
||||
void
|
||||
serialize(S& s, const MaxSize<T>& ms)
|
||||
{
|
||||
processMaxSize(
|
||||
s,
|
||||
ms.data,
|
||||
ms.maxSize,
|
||||
details::IsContainerTraitsDefined<typename std::decay<T>::type>{});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// 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
|
||||
|
||||
@@ -29,38 +28,41 @@
|
||||
namespace bitsery {
|
||||
namespace details {
|
||||
// this type is used to show clearer error messages
|
||||
struct NotDefinedType {
|
||||
struct NotDefinedType
|
||||
{
|
||||
// just swallow anything that is passed during creating
|
||||
template<typename... T>
|
||||
NotDefinedType(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&) {
|
||||
// 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&) {
|
||||
friend bool operator!=(const NotDefinedType&, const NotDefinedType&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
NotDefinedType& operator += (int) {
|
||||
return *this;
|
||||
}
|
||||
NotDefinedType& operator -= (int) {
|
||||
return *this;
|
||||
}
|
||||
NotDefinedType& operator+=(int) { return *this; }
|
||||
NotDefinedType& operator-=(int) { return *this; }
|
||||
|
||||
friend int operator - (const NotDefinedType&, const NotDefinedType&) {
|
||||
friend int operator-(const NotDefinedType&, const NotDefinedType&)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int& operator*() {
|
||||
return data;
|
||||
}
|
||||
int& operator*() { return data; }
|
||||
int data{};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct IsDefined:public std::integral_constant<bool, !std::is_same<NotDefinedType, T>::value> {
|
||||
struct IsDefined
|
||||
: public std::integral_constant<bool, !std::is_same<NotDefinedType, T>::value>
|
||||
{
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -68,7 +70,8 @@ namespace bitsery {
|
||||
namespace std {
|
||||
// define iterator traits to work with standart algorithms
|
||||
template<>
|
||||
struct iterator_traits<bitsery::details::NotDefinedType> {
|
||||
struct iterator_traits<bitsery::details::NotDefinedType>
|
||||
{
|
||||
using difference_type = int;
|
||||
using value_type = int;
|
||||
using pointer = int*;
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -23,131 +23,163 @@
|
||||
#ifndef BITSERY_DETAILS_SERIALIZATION_COMMON_H
|
||||
#define BITSERY_DETAILS_SERIALIZATION_COMMON_H
|
||||
|
||||
#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 {
|
||||
// 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)) {
|
||||
static auto serialize(S& s, T& obj) -> decltype(obj.serialize(s))
|
||||
{
|
||||
obj.serialize(s);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T create() {
|
||||
static T create()
|
||||
{
|
||||
// if you get an error here, please create default constructor
|
||||
return T{};
|
||||
}
|
||||
template<typename T>
|
||||
static T* create(void* ptr) {
|
||||
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
|
||||
// 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 {
|
||||
struct FtorExtValue : public Ext
|
||||
{
|
||||
template<typename S, typename T>
|
||||
void operator()(S& s, T& v) const {
|
||||
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> {};
|
||||
struct FtorExtValue1b : FtorExtValue<1, Ext>
|
||||
{
|
||||
};
|
||||
template<typename Ext>
|
||||
struct FtorExtValue2b: FtorExtValue<2, Ext> {};
|
||||
struct FtorExtValue2b : FtorExtValue<2, Ext>
|
||||
{
|
||||
};
|
||||
template<typename Ext>
|
||||
struct FtorExtValue4b: FtorExtValue<4, Ext> {};
|
||||
struct FtorExtValue4b : FtorExtValue<4, Ext>
|
||||
{
|
||||
};
|
||||
template<typename Ext>
|
||||
struct FtorExtValue8b: FtorExtValue<8, Ext> {};
|
||||
struct FtorExtValue8b : FtorExtValue<8, Ext>
|
||||
{
|
||||
};
|
||||
template<typename Ext>
|
||||
struct FtorExtValue16b: FtorExtValue<16, Ext> {};
|
||||
struct FtorExtValue16b : FtorExtValue<16, Ext>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ext>
|
||||
struct FtorExtObject : public Ext {
|
||||
struct FtorExtObject : public Ext
|
||||
{
|
||||
template<typename S, typename T>
|
||||
void operator()(S& s, T& v) const {
|
||||
void operator()(S& s, T& v) const
|
||||
{
|
||||
s.ext(v, static_cast<const Ext&>(*this));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//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 {};
|
||||
// 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> {
|
||||
struct SelectSerializeFnc : std::integral_constant<int, 0>
|
||||
{
|
||||
};
|
||||
|
||||
// types you need to inherit from when specializing SelectSerializeFnc class
|
||||
struct UseNonMemberFnc : std::integral_constant<int, 1> {
|
||||
};
|
||||
struct UseMemberFnc : std::integral_constant<int, 2> {
|
||||
};
|
||||
struct UseNonMemberFnc : std::integral_constant<int, 1>
|
||||
{};
|
||||
struct UseMemberFnc : std::integral_constant<int, 2>
|
||||
{};
|
||||
|
||||
namespace details {
|
||||
|
||||
// helper types for error handling
|
||||
template<typename T>
|
||||
struct IsContainerTraitsDefined : public IsDefined<typename traits::ContainerTraits<T>::TValue> {
|
||||
struct IsContainerTraitsDefined
|
||||
: public IsDefined<typename traits::ContainerTraits<T>::TValue>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct IsTextTraitsDefined : public IsDefined<typename traits::TextTraits<T>::TValue> {
|
||||
struct IsTextTraitsDefined
|
||||
: public IsDefined<typename traits::TextTraits<T>::TValue>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename Ext, typename T>
|
||||
struct IsExtensionTraitsDefined : public IsDefined<typename traits::ExtensionTraits<Ext, T>::TValue> {
|
||||
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 &>()));
|
||||
using TrySerializeFunction =
|
||||
decltype(serialize(std::declval<S&>(), std::declval<T&>()));
|
||||
|
||||
template<typename S, typename T>
|
||||
struct HasSerializeFunctionHelper {
|
||||
struct HasSerializeFunctionHelper
|
||||
{
|
||||
template<typename Q, typename R, typename = TrySerializeFunction<Q, R>>
|
||||
static std::true_type tester(Q&&, R&&);
|
||||
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 {};
|
||||
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 &>()));
|
||||
using TrySerializeMethod =
|
||||
decltype(Access::serialize(std::declval<S&>(), std::declval<T&>()));
|
||||
|
||||
template<typename S, typename T>
|
||||
struct HasSerializeMethodHelper {
|
||||
struct HasSerializeMethodHelper
|
||||
{
|
||||
template<typename Q, typename R, typename = TrySerializeMethod<Q, R>>
|
||||
static std::true_type tester(Q&&, R&&);
|
||||
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 {};
|
||||
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 &&>()));
|
||||
using TryProcessBriefSyntax =
|
||||
decltype(processBriefSyntax(std::declval<S&>(), std::declval<T&&>()));
|
||||
|
||||
template<typename S, typename T>
|
||||
struct IsBriefSyntaxIncludedHelper {
|
||||
struct IsBriefSyntaxIncludedHelper
|
||||
{
|
||||
template<typename Q, typename R, typename = TryProcessBriefSyntax<Q, R>>
|
||||
static std::true_type tester(Q&&, R&&);
|
||||
static std::false_type tester(...);
|
||||
@@ -155,98 +187,126 @@ namespace bitsery {
|
||||
};
|
||||
|
||||
template<typename S, typename T>
|
||||
struct IsBriefSyntaxIncluded :IsBriefSyntaxIncludedHelper<S, T>::type {};
|
||||
struct IsBriefSyntaxIncluded : IsBriefSyntaxIncludedHelper<S, T>::type
|
||||
{
|
||||
};
|
||||
#else
|
||||
// helper metafunction, that is added to c++17
|
||||
template<typename... Ts>
|
||||
struct make_void {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
};
|
||||
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> {
|
||||
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 {
|
||||
struct IntegralFromFundamental
|
||||
{
|
||||
using TValue = T;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct IntegralFromFundamental<T, typename std::enable_if<std::is_enum<T>::value>::type> {
|
||||
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;
|
||||
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;
|
||||
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 {
|
||||
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"
|
||||
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"
|
||||
@@ -256,26 +316,34 @@ namespace bitsery {
|
||||
selectSerializeFnc(s, v, SelectSerializeFnc<TDecayed>{});
|
||||
}
|
||||
|
||||
static constexpr bool isDefined() {
|
||||
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),
|
||||
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"
|
||||
"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,
|
||||
selectSerializeFnc(s,
|
||||
v,
|
||||
std::integral_constant < int,
|
||||
HasSerializeFunction<S, T>::value ? 1 : 2 > {});
|
||||
}
|
||||
|
||||
static void selectSerializeFnc(S &s, T &v, std::integral_constant<int, 1>) {
|
||||
static void selectSerializeFnc(S& s, T& v, std::integral_constant<int, 1>)
|
||||
{
|
||||
serialize(s, v);
|
||||
}
|
||||
|
||||
static void selectSerializeFnc(S &s, T &v, std::integral_constant<int, 2>) {
|
||||
static void selectSerializeFnc(S& s, T& v, std::integral_constant<int, 2>)
|
||||
{
|
||||
Access::serialize(s, v);
|
||||
}
|
||||
};
|
||||
@@ -285,10 +353,13 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename S, typename T, typename Enabled = void>
|
||||
struct BriefSyntaxFunction {
|
||||
struct BriefSyntaxFunction
|
||||
{
|
||||
|
||||
static void invoke(S &s, T &&obj) {
|
||||
static_assert(IsBriefSyntaxIncluded<S, T>::value,
|
||||
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));
|
||||
@@ -300,111 +371,139 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<int Index, typename... Conds>
|
||||
struct FindIndex : std::integral_constant<int, Index> {};
|
||||
struct FindIndex : std::integral_constant<int, Index>
|
||||
{
|
||||
};
|
||||
|
||||
template<int Index, typename Cond, typename... Conds>
|
||||
struct FindIndex<Index, Cond, Conds...> :
|
||||
std::conditional<Cond::value, std::integral_constant<int, Index>, FindIndex<Index+1, Conds...>>::type
|
||||
{};
|
||||
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... Us>
|
||||
struct GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>> : FindIndex<0, std::is_convertible<Us&, T&>...> {};
|
||||
|
||||
struct GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>
|
||||
: FindIndex<0, std::is_convertible<Us&, T&>...>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T, typename Tuple>
|
||||
struct IsExistsConvertibleTupleType;
|
||||
|
||||
template<typename T, typename... Us>
|
||||
struct IsExistsConvertibleTupleType<T, std::tuple<Us...>> :
|
||||
std::integral_constant<bool, GetConvertibleTypeIndexFromTuple<T, std::tuple<Us...>>::value != sizeof...(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) {
|
||||
TCast*
|
||||
getDirectlyIfExists(TContext& ctx, std::true_type)
|
||||
{
|
||||
return &static_cast<TCast&>(ctx);
|
||||
}
|
||||
|
||||
template<bool AssertExists, typename TCast, typename TContext>
|
||||
TCast* getDirectlyIfExists(TContext& , std::false_type) {
|
||||
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.");
|
||||
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...>>;
|
||||
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... TArgs>
|
||||
TCast* getFromTupleIfExists(std::tuple<TArgs...>& , std::false_type) {
|
||||
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.");
|
||||
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&>{});
|
||||
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...>>{});
|
||||
TCast*
|
||||
getContext(std::tuple<TArgs...>& ctx)
|
||||
{
|
||||
return getFromTupleIfExists<AssertExists, TCast>(
|
||||
ctx, IsExistsConvertibleTupleType<TCast, std::tuple<TArgs...>>{});
|
||||
}
|
||||
|
||||
template<typename Adapter, typename Context>
|
||||
class AdapterAndContextRef {
|
||||
class AdapterAndContextRef
|
||||
{
|
||||
public:
|
||||
static constexpr bool HasContext = true;
|
||||
using Config = typename Adapter::TConfig;
|
||||
|
||||
// constructing adapter in place is important,
|
||||
// because enableBitPacking might create instance with bit write/read enabled adapter wrapper,
|
||||
// which has non trivial destructor
|
||||
// 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{ std::forward<TArgs>(args)... }
|
||||
, _context{ ctx }
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* get serialization context.
|
||||
* this is optional, but might be required for some specific serialization flows.
|
||||
* this is optional, but might be required for some specific serialization
|
||||
* flows.
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
T& context() {
|
||||
T& context()
|
||||
{
|
||||
return *getContext<true, T>(_context);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* contextOrNull() {
|
||||
T* contextOrNull()
|
||||
{
|
||||
return getContext<false, T>(_context);
|
||||
}
|
||||
|
||||
Adapter& adapter() & {
|
||||
return _adapter;
|
||||
}
|
||||
Adapter& adapter() & { return _adapter; }
|
||||
|
||||
Adapter adapter() && {
|
||||
return std::move(_adapter);
|
||||
}
|
||||
Adapter adapter() && { return std::move(_adapter); }
|
||||
|
||||
protected:
|
||||
Adapter _adapter;
|
||||
@@ -412,7 +511,8 @@ namespace bitsery {
|
||||
};
|
||||
|
||||
template<typename Adapter>
|
||||
class AdapterAndContextRef<Adapter, void> {
|
||||
class AdapterAndContextRef<Adapter, void>
|
||||
{
|
||||
public:
|
||||
static constexpr bool HasContext = false;
|
||||
using Config = typename Adapter::TConfig;
|
||||
@@ -424,22 +524,20 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T& context() {
|
||||
T& context()
|
||||
{
|
||||
static_assert(std::is_void<T>::value, "Context is not defined (is void).");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* contextOrNull() {
|
||||
T* contextOrNull()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Adapter& adapter() & {
|
||||
return _adapter;
|
||||
}
|
||||
Adapter& adapter() & { return _adapter; }
|
||||
|
||||
Adapter adapter() && {
|
||||
return std::move(_adapter);
|
||||
}
|
||||
Adapter adapter() && { return std::move(_adapter); }
|
||||
|
||||
protected:
|
||||
Adapter _adapter;
|
||||
@@ -450,15 +548,16 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T, template<typename...> class Template>
|
||||
struct IsSpecializationOf : std::false_type {
|
||||
struct IsSpecializationOf : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template<template<typename...> class Template, typename... Args>
|
||||
struct IsSpecializationOf<Template<Args...>, Template> : std::true_type {
|
||||
struct IsSpecializationOf<Template<Args...>, Template> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BITSERY_DETAILS_SERIALIZATION_COMMON_H
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -30,76 +30,94 @@ namespace bitsery {
|
||||
namespace details {
|
||||
|
||||
template<bool CheckOverflow>
|
||||
class CompactValueImpl {
|
||||
class CompactValueImpl
|
||||
{
|
||||
public:
|
||||
|
||||
template<typename Ser, typename T, typename Fnc>
|
||||
void serialize(Ser &s, const T &v, Fnc &&) const {
|
||||
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>{});
|
||||
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 {
|
||||
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>{});
|
||||
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 {
|
||||
void serializeImpl(Writer& writer, const T& v, std::false_type) const
|
||||
{
|
||||
writer.template writeBytes<1>(v);
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
void deserializeImpl(Reader &reader, T &v, std::false_type) const {
|
||||
void deserializeImpl(Reader& reader, T& v, std::false_type) const
|
||||
{
|
||||
reader.template readBytes<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>{});
|
||||
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::true_type) const {
|
||||
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>{});
|
||||
v = zigZagDecode<T>(
|
||||
res, std::is_signed<typename IntegralFromFundamental<T>::TValue>{});
|
||||
}
|
||||
|
||||
// zigzag encode signed types
|
||||
template<typename T>
|
||||
const SameSizeUnsigned<T> &zigZagEncode(const T &v, std::false_type) const {
|
||||
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{
|
||||
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)));
|
||||
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
|
||||
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 {
|
||||
void writeBytes(Writer& w, const T& v) const
|
||||
{
|
||||
using TFast = typename FastType<T>::type;
|
||||
auto val = static_cast<TFast>(v);
|
||||
while (val > 0x7Fu) {
|
||||
@@ -110,7 +128,8 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<bool CheckErrors, typename Reader, typename T>
|
||||
void readBytes(Reader &r, T &v) const {
|
||||
void readBytes(Reader& r, T& v) const
|
||||
{
|
||||
using TFast = typename FastType<T>::type;
|
||||
constexpr auto TBITS = sizeof(T) * 8;
|
||||
uint8_t b1{ 0x80u };
|
||||
@@ -121,11 +140,18 @@ namespace bitsery {
|
||||
tmp += static_cast<TFast>(b1 & 0x7Fu) << i;
|
||||
}
|
||||
v = static_cast<T>(tmp);
|
||||
handleReadOverflow<Reader, T>(r, i, b1,
|
||||
std::integral_constant<bool, CheckOverflow && CheckErrors>{});
|
||||
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 {
|
||||
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);
|
||||
@@ -133,37 +159,43 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
void handleReadOverflow(Reader &, unsigned , uint8_t , std::false_type) const {
|
||||
|
||||
void handleReadOverflow(Reader&, unsigned, uint8_t, std::false_type) const
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
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 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> {};
|
||||
// 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> {
|
||||
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
|
||||
// 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> {
|
||||
struct ExtensionTraits<ext::CompactValueAsObject, T>
|
||||
{
|
||||
// use dummy implemenations for value and object overload
|
||||
using TValue = void;
|
||||
// only enable object overload
|
||||
@@ -173,7 +205,8 @@ namespace bitsery {
|
||||
};
|
||||
|
||||
template<typename T, bool Check>
|
||||
struct ExtensionTraits<details::CompactValueImpl<Check>, T> {
|
||||
struct ExtensionTraits<details::CompactValueImpl<Check>, T>
|
||||
{
|
||||
using TValue = T;
|
||||
static constexpr bool SupportValueOverload = !Check;
|
||||
static constexpr bool SupportObjectOverload = Check;
|
||||
@@ -184,5 +217,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_COMPACT_VALUE_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -29,7 +29,9 @@ namespace bitsery {
|
||||
|
||||
namespace details {
|
||||
template<typename TValue, typename TContainer>
|
||||
size_t findEntropyIndex(const TValue &v, const TContainer &defValues) {
|
||||
size_t
|
||||
findEntropyIndex(const TValue& v, const TContainer& defValues)
|
||||
{
|
||||
size_t index{ 1u };
|
||||
for (auto& d : defValues) {
|
||||
if (d == v)
|
||||
@@ -43,24 +45,28 @@ namespace bitsery {
|
||||
namespace ext {
|
||||
|
||||
template<typename TContainer>
|
||||
class Entropy {
|
||||
class Entropy
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Allows entropy-encoding technique, by writing few bits for most common values
|
||||
* 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
|
||||
* @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} {
|
||||
};
|
||||
: _values{ values }
|
||||
, _alignBeforeData{ alignBeforeData } {};
|
||||
|
||||
template<typename Ser, typename T, typename Fnc>
|
||||
void serialize(Ser &s, const T &obj, Fnc &&fnc) const {
|
||||
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)});
|
||||
s.ext(index,
|
||||
ext::ValueRange<size_t>{
|
||||
0u, traits::ContainerTraits<TContainer>::size(_values) });
|
||||
if (_alignBeforeData)
|
||||
s.adapter().align();
|
||||
if (!index)
|
||||
@@ -68,17 +74,21 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserialize(Des &d, T &obj, Fnc &&fnc) const {
|
||||
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)});
|
||||
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
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -90,7 +100,8 @@ namespace bitsery {
|
||||
|
||||
namespace traits {
|
||||
template<typename TContainer, typename T>
|
||||
struct ExtensionTraits<ext::Entropy<TContainer>, T> {
|
||||
struct ExtensionTraits<ext::Entropy<TContainer>, T>
|
||||
{
|
||||
using TValue = T;
|
||||
static constexpr bool SupportValueOverload = true;
|
||||
static constexpr bool SupportObjectOverload = true;
|
||||
@@ -100,5 +111,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_ENTROPY_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -30,15 +30,18 @@ namespace bitsery {
|
||||
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
|
||||
* 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 {
|
||||
class Growable
|
||||
{
|
||||
public:
|
||||
|
||||
template<typename Ser, typename T, typename Fnc>
|
||||
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
|
||||
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));
|
||||
@@ -52,7 +55,8 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
|
||||
void deserialize(Des& des, T& obj, Fnc&& fnc) const
|
||||
{
|
||||
auto& reader = des.adapter();
|
||||
uint32_t size{};
|
||||
const auto readEndPos = reader.currentReadEndPos();
|
||||
@@ -70,7 +74,8 @@ namespace bitsery {
|
||||
|
||||
namespace traits {
|
||||
template<typename T>
|
||||
struct ExtensionTraits<ext::Growable, T> {
|
||||
struct ExtensionTraits<ext::Growable, T>
|
||||
{
|
||||
using TValue = T;
|
||||
static constexpr bool SupportValueOverload = false;
|
||||
static constexpr bool SupportObjectOverload = true;
|
||||
@@ -80,5 +85,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_GROWABLE_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -23,28 +23,31 @@
|
||||
#ifndef BITSERY_EXT_INHERITANCE_H
|
||||
#define BITSERY_EXT_INHERITANCE_H
|
||||
|
||||
#include "../traits/core/traits.h"
|
||||
#include "../ext/utils/memory_resource.h"
|
||||
#include "../traits/core/traits.h"
|
||||
#include <unordered_set>
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
namespace ext {
|
||||
|
||||
//required when virtual inheritance (ext::VirtualBaseClass) exists in serialization flow.
|
||||
//for standard inheritance (ext::BaseClass) it is optional.
|
||||
class InheritanceContext {
|
||||
// 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 &) {
|
||||
void beginBase(const TDerived& derived, const TBase&)
|
||||
{
|
||||
if (_depth == 0) {
|
||||
const void* ptr = std::addressof(derived);
|
||||
if (_parentPtr != ptr)
|
||||
@@ -55,14 +58,13 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename TDerived, typename TBase>
|
||||
bool beginVirtualBase(const TDerived &derived, const TBase &base) {
|
||||
bool beginVirtualBase(const TDerived& derived, const TBase& base)
|
||||
{
|
||||
beginBase(derived, base);
|
||||
return _virtualBases.emplace(std::addressof(base)).second;
|
||||
}
|
||||
|
||||
void end() {
|
||||
--_depth;
|
||||
}
|
||||
void end() { --_depth; }
|
||||
|
||||
private:
|
||||
// these members are required to know when we can clear _virtualBases
|
||||
@@ -70,17 +72,19 @@ namespace bitsery {
|
||||
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;
|
||||
std::hash<const void*>,
|
||||
std::equal_to<const void*>,
|
||||
pointer_utils::StdPolyAlloc<const void*>>
|
||||
_virtualBases;
|
||||
};
|
||||
|
||||
template<typename TBase>
|
||||
class BaseClass {
|
||||
class BaseClass
|
||||
{
|
||||
public:
|
||||
|
||||
template<typename Ser, typename T, typename Fnc>
|
||||
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
|
||||
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);
|
||||
@@ -92,7 +96,8 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
|
||||
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);
|
||||
@@ -102,16 +107,16 @@ namespace bitsery {
|
||||
fnc(des, resObj);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// requires InheritanceContext
|
||||
template<typename TBase>
|
||||
class VirtualBaseClass {
|
||||
class VirtualBaseClass
|
||||
{
|
||||
public:
|
||||
|
||||
template<typename Ser, typename T, typename Fnc>
|
||||
void serialize(Ser &ser, const T &obj, Fnc &&fnc) const {
|
||||
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))
|
||||
@@ -120,21 +125,22 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
|
||||
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> {
|
||||
struct ExtensionTraits<ext::BaseClass<TBase>, T>
|
||||
{
|
||||
static_assert(std::is_base_of<TBase, T>::value, "Invalid base class");
|
||||
|
||||
using TValue = TBase;
|
||||
@@ -144,19 +150,20 @@ namespace bitsery {
|
||||
};
|
||||
|
||||
template<typename TBase, typename T>
|
||||
struct ExtensionTraits<ext::VirtualBaseClass<TBase>, 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.
|
||||
// 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
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -36,128 +36,137 @@ namespace bitsery {
|
||||
namespace pointer_details {
|
||||
|
||||
template<typename T>
|
||||
struct PtrOwnerManager {
|
||||
struct PtrOwnerManager
|
||||
{
|
||||
static_assert(std::is_pointer<T>::value, "");
|
||||
|
||||
using TElement = typename std::remove_pointer<T>::type;
|
||||
|
||||
static TElement* getPtr(T& obj) {
|
||||
return obj;
|
||||
}
|
||||
static TElement* getPtr(T& obj) { return obj; }
|
||||
|
||||
static constexpr PointerOwnershipType getOwnership() {
|
||||
static constexpr PointerOwnershipType getOwnership()
|
||||
{
|
||||
return PointerOwnershipType::Owner;
|
||||
}
|
||||
|
||||
static void create(T& obj, pointer_utils::PolyAllocWithTypeId alloc, size_t 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) {
|
||||
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) {
|
||||
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) {
|
||||
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 {
|
||||
struct PtrObserverManager
|
||||
{
|
||||
static_assert(std::is_pointer<T>::value, "");
|
||||
|
||||
using TElement = typename std::remove_pointer<T>::type;
|
||||
|
||||
static TElement* getPtr(T& obj) {
|
||||
return obj;
|
||||
}
|
||||
static TElement* getPtr(T& obj) { return obj; }
|
||||
|
||||
static constexpr PointerOwnershipType getOwnership() {
|
||||
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 ) {
|
||||
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 {
|
||||
struct NonPtrManager
|
||||
{
|
||||
|
||||
static_assert(!std::is_pointer<T>::value, "");
|
||||
|
||||
using TElement = T;
|
||||
|
||||
static TElement* getPtr(T& obj) {
|
||||
return &obj;
|
||||
}
|
||||
static TElement* getPtr(T& obj) { return &obj; }
|
||||
|
||||
static constexpr PointerOwnershipType getOwnership() {
|
||||
static constexpr PointerOwnershipType getOwnership()
|
||||
{
|
||||
return PointerOwnershipType::Owner;
|
||||
}
|
||||
|
||||
// this code is unreachable for reference type, but is necessary to compile
|
||||
// LCOV_EXCL_START
|
||||
|
||||
static void create(T& , MemResourceBase* , size_t ) {
|
||||
static void create(T&, MemResourceBase*, size_t) {}
|
||||
|
||||
static void createPolymorphic(T&, MemResourceBase*, PolymorphicHandlerBase&)
|
||||
{
|
||||
}
|
||||
|
||||
static void createPolymorphic(T& , MemResourceBase* , PolymorphicHandlerBase& ) {
|
||||
|
||||
}
|
||||
|
||||
static void destroy(T& , MemResourceBase* , size_t ) {
|
||||
|
||||
}
|
||||
|
||||
static void destroyPolymorphic(T& , MemResourceBase* , PolymorphicHandlerBase& ) {
|
||||
static void destroy(T&, MemResourceBase*, size_t) {}
|
||||
|
||||
static void destroyPolymorphic(T&, MemResourceBase*, PolymorphicHandlerBase&)
|
||||
{
|
||||
}
|
||||
// LCOV_EXCL_STOP
|
||||
|
||||
};
|
||||
|
||||
// this class is used by NonPtrManager
|
||||
struct NoRTTI {
|
||||
struct NoRTTI
|
||||
{
|
||||
template<typename TBase>
|
||||
static size_t get(TBase&) {
|
||||
static size_t get(TBase&)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename TBase>
|
||||
static constexpr size_t get() {
|
||||
static constexpr size_t get()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename TBase, typename TDerived>
|
||||
static constexpr TDerived* cast(TBase* obj) {
|
||||
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() {
|
||||
static constexpr bool isPolymorphic()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -165,21 +174,34 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename RTTI>
|
||||
using PointerOwnerBase = pointer_utils::PointerObjectExtensionBase<
|
||||
pointer_details::PtrOwnerManager, PolymorphicContext, 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>;
|
||||
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> {
|
||||
// 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) {}
|
||||
ReferencedByPointer()
|
||||
: pointer_utils::PointerObjectExtensionBase<pointer_details::NonPtrManager,
|
||||
PolymorphicContext,
|
||||
pointer_details::NoRTTI>(
|
||||
PointerType::NotNull)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -187,18 +209,22 @@ namespace bitsery {
|
||||
namespace traits {
|
||||
|
||||
template<typename T, typename RTTI>
|
||||
struct ExtensionTraits<ext::PointerOwnerBase<RTTI>, T*> {
|
||||
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>();
|
||||
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
|
||||
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;
|
||||
@@ -206,8 +232,10 @@ namespace bitsery {
|
||||
};
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -29,17 +29,19 @@
|
||||
namespace bitsery {
|
||||
namespace ext {
|
||||
|
||||
class StdAtomic {
|
||||
class StdAtomic
|
||||
{
|
||||
public:
|
||||
|
||||
template<typename Ser, typename T, typename Fnc>
|
||||
void serialize(Ser& ser, const std::atomic<T>& obj, Fnc&& fnc) const {
|
||||
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 {
|
||||
void deserialize(Des& des, std::atomic<T>& obj, Fnc&& fnc) const
|
||||
{
|
||||
T res{};
|
||||
fnc(des, res);
|
||||
obj.store(res);
|
||||
@@ -50,7 +52,8 @@ namespace bitsery {
|
||||
|
||||
namespace traits {
|
||||
template<typename T>
|
||||
struct ExtensionTraits<ext::StdAtomic, std::atomic<T>> {
|
||||
struct ExtensionTraits<ext::StdAtomic, std::atomic<T>>
|
||||
{
|
||||
using TValue = T;
|
||||
static constexpr bool SupportValueOverload = true;
|
||||
static constexpr bool SupportObjectOverload = false;
|
||||
@@ -61,5 +64,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_STD_ATOMIC_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -29,24 +29,21 @@
|
||||
namespace bitsery {
|
||||
namespace ext {
|
||||
|
||||
class StdBitset {
|
||||
class StdBitset
|
||||
{
|
||||
public:
|
||||
|
||||
template<typename Ser, typename Fnc, size_t N>
|
||||
void serialize(Ser &ser, const std::bitset<N> &obj, Fnc &&) const {
|
||||
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);
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -59,12 +56,17 @@ namespace bitsery {
|
||||
}
|
||||
}
|
||||
if (LEFTOVER > 0) {
|
||||
serializeLeftoverImpl(ser.adapter(), obj, N - LEFTOVER, N, std::is_same<Ser, typename Ser::BPEnabledType>{});
|
||||
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 {
|
||||
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) {
|
||||
@@ -81,14 +83,22 @@ namespace bitsery {
|
||||
obj[offset + 7] = data & 0x80u;
|
||||
}
|
||||
if (LEFTOVER > 0) {
|
||||
deserializeLeftoverImpl(des.adapter(), obj, N - LEFTOVER, N, std::is_same<Des, typename Des::BPEnabledType>{});
|
||||
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 {
|
||||
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);
|
||||
@@ -97,14 +107,24 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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) {
|
||||
@@ -113,20 +133,25 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
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 {
|
||||
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>> {
|
||||
struct ExtensionTraits<ext::StdBitset, std::bitset<N>>
|
||||
{
|
||||
using TValue = void;
|
||||
static constexpr bool SupportValueOverload = false;
|
||||
static constexpr bool SupportObjectOverload = true;
|
||||
@@ -135,5 +160,4 @@ namespace bitsery {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_STD_BITSET_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -29,40 +29,61 @@
|
||||
namespace bitsery {
|
||||
namespace ext {
|
||||
|
||||
class StdDuration {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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};
|
||||
obj =
|
||||
std::chrono::time_point<Clock, std::chrono::duration<T, Period>>{ dur };
|
||||
}
|
||||
};
|
||||
|
||||
@@ -70,7 +91,8 @@ namespace bitsery {
|
||||
|
||||
namespace traits {
|
||||
template<typename Rep, typename Period>
|
||||
struct ExtensionTraits<ext::StdDuration, std::chrono::duration<Rep, Period>> {
|
||||
struct ExtensionTraits<ext::StdDuration, std::chrono::duration<Rep, Period>>
|
||||
{
|
||||
using TValue = Rep;
|
||||
static constexpr bool SupportValueOverload = true;
|
||||
static constexpr bool SupportObjectOverload = false;
|
||||
@@ -78,8 +100,10 @@ namespace bitsery {
|
||||
};
|
||||
|
||||
template<typename Clock, typename Rep, typename Period>
|
||||
struct ExtensionTraits<ext::StdTimePoint,
|
||||
std::chrono::time_point<Clock, std::chrono::duration<Rep, 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;
|
||||
@@ -90,5 +114,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_STD_CHRONO_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -23,21 +23,25 @@
|
||||
#ifndef BITSERY_EXT_STD_MAP_H
|
||||
#define BITSERY_EXT_STD_MAP_H
|
||||
|
||||
#include "../traits/core/traits.h"
|
||||
#include "../details/serialization_common.h"
|
||||
#include "../traits/core/traits.h"
|
||||
// we need this, so we could reserve for non ordered map
|
||||
#include <unordered_map>
|
||||
|
||||
namespace bitsery {
|
||||
namespace ext {
|
||||
|
||||
class StdMap {
|
||||
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 {
|
||||
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();
|
||||
@@ -49,12 +53,16 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
|
||||
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,
|
||||
details::readSize(
|
||||
des.adapter(),
|
||||
size,
|
||||
_maxSize,
|
||||
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
|
||||
obj.clear();
|
||||
reserve(obj, size);
|
||||
@@ -67,17 +75,31 @@ namespace bitsery {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
void reserve(T&, size_t) const
|
||||
{
|
||||
// for ordered container do nothing
|
||||
}
|
||||
size_t _maxSize;
|
||||
@@ -86,7 +108,8 @@ namespace bitsery {
|
||||
|
||||
namespace traits {
|
||||
template<typename T>
|
||||
struct ExtensionTraits<ext::StdMap, T> {
|
||||
struct ExtensionTraits<ext::StdMap, T>
|
||||
{
|
||||
using TValue = void;
|
||||
static constexpr bool SupportValueOverload = false;
|
||||
static constexpr bool SupportObjectOverload = false;
|
||||
@@ -96,5 +119,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_STD_MAP_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,28 +20,32 @@
|
||||
// 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 {
|
||||
|
||||
class StdOptional {
|
||||
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
|
||||
* @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} {}
|
||||
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 {
|
||||
void serialize(Ser& ser, const std::optional<T>& obj, Fnc&& fnc) const
|
||||
{
|
||||
ser.boolValue(static_cast<bool>(obj));
|
||||
if (_alignBeforeData)
|
||||
ser.adapter().align();
|
||||
@@ -50,7 +54,8 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserialize(Des &des, std::optional<T> &obj, Fnc &&fnc) const {
|
||||
void deserialize(Des& des, std::optional<T>& obj, Fnc&& fnc) const
|
||||
{
|
||||
bool exists{};
|
||||
des.boolValue(exists);
|
||||
if (_alignBeforeData)
|
||||
@@ -61,16 +66,24 @@ namespace bitsery {
|
||||
obj = std::nullopt;
|
||||
}
|
||||
}
|
||||
private:
|
||||
|
||||
private:
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserialize_impl(Des &des, std::optional<T> &obj, Fnc &&fnc, std::true_type) const {
|
||||
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 {
|
||||
void deserialize_impl(Des& des,
|
||||
std::optional<T>& obj,
|
||||
Fnc&& fnc,
|
||||
std::false_type) const
|
||||
{
|
||||
if (!obj) {
|
||||
obj = ::bitsery::Access::create<T>();
|
||||
}
|
||||
@@ -82,7 +95,8 @@ namespace bitsery {
|
||||
|
||||
namespace traits {
|
||||
template<typename T>
|
||||
struct ExtensionTraits<ext::StdOptional, std::optional<T>> {
|
||||
struct ExtensionTraits<ext::StdOptional, std::optional<T>>
|
||||
{
|
||||
using TValue = T;
|
||||
static constexpr bool SupportValueOverload = true;
|
||||
static constexpr bool SupportObjectOverload = true;
|
||||
@@ -92,5 +106,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_STD_OPTIONAL_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,20 +20,21 @@
|
||||
// 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 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 <type_traits>
|
||||
#include <queue>
|
||||
#include <type_traits>
|
||||
|
||||
namespace bitsery {
|
||||
namespace ext {
|
||||
|
||||
class StdQueue {
|
||||
class StdQueue
|
||||
{
|
||||
private:
|
||||
// inherit from queue so we could take underlying container
|
||||
template<typename T, typename C>
|
||||
@@ -67,37 +68,53 @@ namespace bitsery {
|
||||
};
|
||||
|
||||
size_t _maxSize;
|
||||
|
||||
public:
|
||||
explicit StdQueue(size_t maxSize):_maxSize{maxSize} {};
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
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> {
|
||||
struct ExtensionTraits<ext::StdQueue, T>
|
||||
{
|
||||
using TValue = typename T::value_type;
|
||||
static constexpr bool SupportValueOverload = true;
|
||||
static constexpr bool SupportObjectOverload = true;
|
||||
@@ -107,5 +124,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_STD_QUEUE_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -29,13 +29,17 @@
|
||||
namespace bitsery {
|
||||
namespace ext {
|
||||
|
||||
class StdSet {
|
||||
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 {
|
||||
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
|
||||
{
|
||||
using TKey = typename T::key_type;
|
||||
auto size = obj.size();
|
||||
assert(size <= _maxSize);
|
||||
@@ -46,11 +50,16 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserialize(Des &des, T &obj, Fnc &&fnc) const {
|
||||
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>{});
|
||||
details::readSize(
|
||||
des.adapter(),
|
||||
size,
|
||||
_maxSize,
|
||||
std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
|
||||
obj.clear();
|
||||
reserve(obj, size);
|
||||
auto hint = obj.begin();
|
||||
@@ -60,21 +69,24 @@ namespace bitsery {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
void reserve(T&, size_t) const
|
||||
{
|
||||
// for ordered container do nothing
|
||||
}
|
||||
size_t _maxSize;
|
||||
@@ -83,7 +95,8 @@ namespace bitsery {
|
||||
|
||||
namespace traits {
|
||||
template<typename T>
|
||||
struct ExtensionTraits<ext::StdSet, T> {
|
||||
struct ExtensionTraits<ext::StdSet, T>
|
||||
{
|
||||
using TValue = typename T::key_type;
|
||||
static constexpr bool SupportValueOverload = true;
|
||||
static constexpr bool SupportObjectOverload = true;
|
||||
@@ -93,5 +106,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_STD_SET_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -35,32 +35,36 @@ namespace bitsery {
|
||||
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 {
|
||||
// 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 {
|
||||
struct SmartPtrOwnerManager
|
||||
{
|
||||
|
||||
using TElement = typename T::element_type;
|
||||
|
||||
template<typename TDeleter>
|
||||
static TElement* getPtr(std::unique_ptr<TElement, TDeleter>& obj) {
|
||||
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) {
|
||||
static TElement* getPtr(std::weak_ptr<TElement>& obj)
|
||||
{
|
||||
if (auto ptr = obj.lock())
|
||||
return ptr.get();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static constexpr PointerOwnershipType getOwnership() {
|
||||
static constexpr PointerOwnershipType getOwnership()
|
||||
{
|
||||
return ::bitsery::details::IsSpecializationOf<T, std::unique_ptr>::value
|
||||
? PointerOwnershipType::Owner
|
||||
: std::is_same<std::shared_ptr<TElement>, T>::value
|
||||
@@ -69,45 +73,62 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename TDeleter>
|
||||
static void create(std::unique_ptr<TElement, TDeleter>& obj, pointer_utils::PolyAllocWithTypeId alloc,
|
||||
size_t typeId) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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>&) {
|
||||
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) {
|
||||
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>&) {
|
||||
static void destroyPolymorphic(std::weak_ptr<TElement>& obj,
|
||||
MemResourceBase*,
|
||||
const std::shared_ptr<PolymorphicHandlerBase>&)
|
||||
{
|
||||
obj.reset();
|
||||
}
|
||||
|
||||
@@ -115,64 +136,82 @@ namespace bitsery {
|
||||
using TSharedState = SharedPtrSharedState;
|
||||
|
||||
static void createShared(TSharedState& state,
|
||||
std::shared_ptr<TElement>& obj, MemResourceBase* memResource, size_t typeId) {
|
||||
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));
|
||||
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) {
|
||||
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));
|
||||
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) {
|
||||
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));
|
||||
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) {
|
||||
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));
|
||||
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) {
|
||||
static void saveToSharedState(TSharedState& state, T& obj)
|
||||
{
|
||||
state.obj = std::shared_ptr<TElement>(obj);
|
||||
}
|
||||
|
||||
static void loadFromSharedState(TSharedState& state, T& obj) {
|
||||
static void loadFromSharedState(TSharedState& state, T& obj)
|
||||
{
|
||||
// reinterpret_pointer_cast is only since c++17
|
||||
auto 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>;
|
||||
smart_ptr_details::SmartPtrOwnerManager,
|
||||
PolymorphicContext,
|
||||
RTTI>;
|
||||
|
||||
// helper type for convienience
|
||||
using StdSmartPtr = StdSmartPtrBase<StandardRTTI>;
|
||||
@@ -182,12 +221,14 @@ namespace bitsery {
|
||||
namespace traits {
|
||||
|
||||
template<typename T, typename RTTI>
|
||||
struct ExtensionTraits<ext::StdSmartPtrBase<RTTI>, T> {
|
||||
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>();
|
||||
static constexpr bool SupportLambdaOverload =
|
||||
!RTTI::template isPolymorphic<TValue>();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// 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
|
||||
|
||||
@@ -30,7 +29,8 @@
|
||||
namespace bitsery {
|
||||
namespace ext {
|
||||
|
||||
class StdStack {
|
||||
class StdStack
|
||||
{
|
||||
private:
|
||||
// inherit from stack so we could take underlying container
|
||||
template<typename T, typename C>
|
||||
@@ -48,25 +48,31 @@ namespace bitsery {
|
||||
}
|
||||
};
|
||||
size_t _maxSize;
|
||||
|
||||
public:
|
||||
explicit StdStack(size_t maxSize):_maxSize{maxSize} {};
|
||||
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));
|
||||
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));
|
||||
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>> {
|
||||
struct ExtensionTraits<ext::StdStack, std::stack<T, Seq>>
|
||||
{
|
||||
using TValue = T;
|
||||
static constexpr bool SupportValueOverload = true;
|
||||
static constexpr bool SupportObjectOverload = true;
|
||||
@@ -76,5 +82,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_STD_STACK_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,35 +20,37 @@
|
||||
// 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 {
|
||||
|
||||
template<typename... Overloads>
|
||||
class StdTuple : public details::CompositeTypeOverloadsUtils<std::tuple, 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 {
|
||||
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 {
|
||||
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 {
|
||||
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));
|
||||
@@ -64,7 +66,8 @@ namespace bitsery {
|
||||
namespace traits {
|
||||
|
||||
template<typename Tuple, typename... Overloads>
|
||||
struct ExtensionTraits<ext::StdTuple<Overloads...>, Tuple> {
|
||||
struct ExtensionTraits<ext::StdTuple<Overloads...>, Tuple>
|
||||
{
|
||||
static_assert(bitsery::details::IsSpecializationOf<Tuple, std::tuple>::value,
|
||||
"StdTuple only works with std::tuple");
|
||||
using TValue = void;
|
||||
@@ -77,5 +80,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_STD_TUPLE_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,40 +20,48 @@
|
||||
// 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 {
|
||||
|
||||
template<typename... Overloads>
|
||||
class StdVariant : public details::CompositeTypeOverloadsUtils<std::variant, 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 {
|
||||
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) {
|
||||
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 {
|
||||
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>{});
|
||||
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;
|
||||
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
|
||||
@@ -67,10 +75,10 @@ namespace bitsery {
|
||||
|
||||
TElem item = ::bitsery::Access::create<TElem>();
|
||||
this->serializeType(des, item);
|
||||
data = std::variant<Ts...>(std::in_place_index_t<Index>{}, std::move(item));
|
||||
data =
|
||||
std::variant<Ts...>(std::in_place_index_t<Index>{}, std::move(item));
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// deduction guide
|
||||
@@ -80,13 +88,18 @@ namespace bitsery {
|
||||
|
||||
// defines empty fuction, that handles monostate
|
||||
template<typename S>
|
||||
void serialize(S& , std::monostate&) {}
|
||||
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,
|
||||
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;
|
||||
@@ -98,5 +111,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_STD_VARIANT_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -29,18 +29,20 @@
|
||||
#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
|
||||
// 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 ... {
|
||||
struct CompositeTypeOverloads : Ts...
|
||||
{
|
||||
using Ts::operator()...;
|
||||
};
|
||||
|
||||
@@ -49,32 +51,39 @@ namespace bitsery {
|
||||
|
||||
// convenient way to invoke s.value<N>, shorter than specifying a lambda
|
||||
template<typename T, size_t N>
|
||||
struct OverloadValue {
|
||||
struct OverloadValue
|
||||
{
|
||||
template<typename S>
|
||||
void operator()(S& s, T& v) const {
|
||||
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
|
||||
// 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 {
|
||||
struct OverloadExtValue : public Ext
|
||||
{
|
||||
template<typename S>
|
||||
void operator()(S& s, T& v) const {
|
||||
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 {
|
||||
struct OverloadExtObject : public Ext
|
||||
{
|
||||
template<typename S>
|
||||
void operator()(S& s, T& v) const {
|
||||
void operator()(S& s, T& v) const
|
||||
{
|
||||
s.ext(v, static_cast<const Ext&>(*this));
|
||||
}
|
||||
};
|
||||
@@ -83,49 +92,63 @@ namespace bitsery {
|
||||
namespace details {
|
||||
|
||||
template<template<typename...> typename CompositeType, typename... Overloads>
|
||||
class CompositeTypeOverloadsUtils : public ext::CompositeTypeOverloads<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...>{});
|
||||
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 {
|
||||
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 {
|
||||
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(),
|
||||
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() {
|
||||
static constexpr bool hasOverload()
|
||||
{
|
||||
return std::is_invocable<ext::CompositeTypeOverloads<Overloads...>,
|
||||
std::add_lvalue_reference_t<S>, std::add_lvalue_reference_t<T>>::value;
|
||||
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), ...);
|
||||
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 {
|
||||
void execAllImpl(Variant& obj, Fnc&& fnc, std::index_sequence<Is...>) const
|
||||
{
|
||||
(fnc(obj, std::integral_constant<size_t, Is>{}), ...);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -28,31 +28,42 @@
|
||||
|
||||
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).
|
||||
// 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 {
|
||||
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;
|
||||
};
|
||||
|
||||
// default implementation for MemResourceBase using new and delete
|
||||
class MemResourceNewDelete final: public MemResourceBase {
|
||||
class MemResourceNewDelete final : public MemResourceBase
|
||||
{
|
||||
public:
|
||||
inline void* allocate(size_t bytes, size_t /*alignment*/, size_t /*typeId*/) final {
|
||||
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 {
|
||||
inline void deallocate(void* ptr,
|
||||
size_t /*bytes*/,
|
||||
size_t /*alignment*/,
|
||||
size_t /*typeId*/) noexcept final
|
||||
{
|
||||
(::operator delete(ptr));
|
||||
}
|
||||
|
||||
@@ -61,26 +72,32 @@ namespace bitsery {
|
||||
|
||||
// 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 {
|
||||
// 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} {}
|
||||
: _resource{ memResource }
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* allocate(size_t n, size_t typeId) const {
|
||||
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
|
||||
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 {
|
||||
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
|
||||
@@ -89,30 +106,30 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T* newObject(size_t typeId) const {
|
||||
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 {
|
||||
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 {
|
||||
bool operator==(const PolyAllocWithTypeId& rhs) const noexcept
|
||||
{
|
||||
return _resource == rhs._resource;
|
||||
}
|
||||
|
||||
bool operator!=(const PolyAllocWithTypeId& rhs) const noexcept {
|
||||
bool operator!=(const PolyAllocWithTypeId& rhs) const noexcept
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
@@ -124,39 +141,47 @@ namespace bitsery {
|
||||
// it just wraps our PolyAllocWithTypeId and pass 0 as typeId
|
||||
// and defines core functions for c++ Allocator concept,
|
||||
template<class T>
|
||||
class StdPolyAlloc {
|
||||
class StdPolyAlloc
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
explicit constexpr StdPolyAlloc(MemResourceBase* memResource)
|
||||
:_alloc{memResource} {}
|
||||
explicit constexpr StdPolyAlloc(PolyAllocWithTypeId alloc) : _alloc{alloc} {}
|
||||
: _alloc{ memResource }
|
||||
{
|
||||
}
|
||||
explicit constexpr StdPolyAlloc(PolyAllocWithTypeId alloc)
|
||||
: _alloc{ alloc }
|
||||
{
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
friend class StdPolyAlloc;
|
||||
|
||||
template<class U>
|
||||
constexpr explicit StdPolyAlloc(const StdPolyAlloc<U>& other) noexcept
|
||||
:_alloc{other._alloc} {
|
||||
: _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 {
|
||||
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 {
|
||||
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 {
|
||||
const StdPolyAlloc<U>& rhs) noexcept
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -29,19 +29,22 @@ namespace bitsery {
|
||||
namespace ext {
|
||||
|
||||
// change name
|
||||
enum class PointerType : uint8_t {
|
||||
enum class PointerType : uint8_t
|
||||
{
|
||||
Nullable,
|
||||
NotNull
|
||||
};
|
||||
|
||||
// Observer - not responsible for pointer lifetime management.
|
||||
// Owner - only ONE owner is responsible for this pointers creation/destruction
|
||||
// SharedOwner, SharedObserver - MANY shared owners is responsible for pointer creation/destruction
|
||||
// requires additional context to manage shared owners themselves.
|
||||
// SharedOwner actually manages life time e.g. std::shared_ptr
|
||||
// SharedObserver do not manage life time of the pointer, but can observe shared state .e.. std::weak_ptr
|
||||
// and differently from Observer, creates new object if necessary and saves to shared state
|
||||
enum class PointerOwnershipType : uint8_t {
|
||||
// SharedOwner, SharedObserver - MANY shared owners is responsible for pointer
|
||||
// creation/destruction requires additional context to manage shared owners
|
||||
// themselves. SharedOwner actually manages life time e.g. std::shared_ptr
|
||||
// SharedObserver do not manage life time of the pointer, but can observe shared
|
||||
// state .e.. std::weak_ptr and differently from Observer, creates new object if
|
||||
// necessary and saves to shared state
|
||||
enum class PointerOwnershipType : uint8_t
|
||||
{
|
||||
Observer,
|
||||
Owner,
|
||||
SharedOwner,
|
||||
@@ -51,15 +54,20 @@ namespace bitsery {
|
||||
namespace pointer_utils {
|
||||
|
||||
// this class is used to store context for shared ptr owners
|
||||
struct PointerSharedStateBase {
|
||||
struct PointerSharedStateBase
|
||||
{
|
||||
virtual ~PointerSharedStateBase() = default;
|
||||
};
|
||||
|
||||
struct PointerSharedStateDeleter {
|
||||
struct PointerSharedStateDeleter
|
||||
{
|
||||
PointerSharedStateDeleter() = default;
|
||||
explicit PointerSharedStateDeleter(MemResourceBase* memResource)
|
||||
:_memResource{memResource} {}
|
||||
void operator()(PointerSharedStateBase* data) const {
|
||||
: _memResource{ memResource }
|
||||
{
|
||||
}
|
||||
void operator()(PointerSharedStateBase* data) const
|
||||
{
|
||||
data->~PointerSharedStateBase();
|
||||
StdPolyAlloc<PointerSharedStateBase> alloc{ _memResource };
|
||||
alloc.deallocate(data, 1);
|
||||
@@ -68,14 +76,16 @@ namespace bitsery {
|
||||
};
|
||||
|
||||
// PLC info is internal classes for serializer, and deserializer
|
||||
struct PLCInfo {
|
||||
struct PLCInfo
|
||||
{
|
||||
explicit PLCInfo(PointerOwnershipType ownershipType_)
|
||||
: ownershipType{ownershipType_},
|
||||
isSharedProcessed{false} {};
|
||||
: ownershipType{ ownershipType_ }
|
||||
, isSharedProcessed{ false } {};
|
||||
PointerOwnershipType ownershipType;
|
||||
bool isSharedProcessed;
|
||||
|
||||
void update(PointerOwnershipType ptrType) {
|
||||
void update(PointerOwnershipType ptrType)
|
||||
{
|
||||
// do nothing for observer
|
||||
if (ptrType == PointerOwnershipType::Observer)
|
||||
return;
|
||||
@@ -90,24 +100,33 @@ namespace bitsery {
|
||||
// check if need to update to SharedOwner
|
||||
if (ptrType == PointerOwnershipType::SharedOwner)
|
||||
ownershipType = ptrType;
|
||||
//mark that object already processed, so we do not serialize/deserialize duplicate objects
|
||||
// mark that object already processed, so we do not serialize/deserialize
|
||||
// duplicate objects
|
||||
isSharedProcessed = true;
|
||||
}
|
||||
};
|
||||
|
||||
struct PLCInfoSerializer : PLCInfo {
|
||||
struct PLCInfoSerializer : PLCInfo
|
||||
{
|
||||
PLCInfoSerializer(size_t id_, PointerOwnershipType ownershipType_)
|
||||
: PLCInfo(ownershipType_), id{id_} {}
|
||||
: PLCInfo(ownershipType_)
|
||||
, id{ id_ }
|
||||
{
|
||||
}
|
||||
|
||||
size_t id;
|
||||
};
|
||||
|
||||
struct PLCInfoDeserializer : PLCInfo {
|
||||
PLCInfoDeserializer(void* ptr, PointerOwnershipType ownershipType_, MemResourceBase* memResource_)
|
||||
: PLCInfo(ownershipType_),
|
||||
ownerPtr{ptr},
|
||||
memResource{memResource_},
|
||||
observersList{StdPolyAlloc<std::reference_wrapper<void*>>{memResource_}} {};
|
||||
struct PLCInfoDeserializer : PLCInfo
|
||||
{
|
||||
PLCInfoDeserializer(void* ptr,
|
||||
PointerOwnershipType ownershipType_,
|
||||
MemResourceBase* memResource_)
|
||||
: PLCInfo(ownershipType_)
|
||||
, ownerPtr{ ptr }
|
||||
, memResource{ memResource_ }
|
||||
, observersList{ StdPolyAlloc<std::reference_wrapper<void*>>{
|
||||
memResource_ } } {};
|
||||
|
||||
// need to override these explicitly because we have pointer member
|
||||
PLCInfoDeserializer(const PLCInfoDeserializer&) = delete;
|
||||
@@ -118,7 +137,8 @@ namespace bitsery {
|
||||
|
||||
PLCInfoDeserializer& operator=(PLCInfoDeserializer&&) = default;
|
||||
|
||||
void processOwner(void* ptr) {
|
||||
void processOwner(void* ptr)
|
||||
{
|
||||
ownerPtr = ptr;
|
||||
assert(ownershipType != PointerOwnershipType::Observer);
|
||||
for (auto& o : observersList)
|
||||
@@ -127,7 +147,8 @@ namespace bitsery {
|
||||
observersList.shrink_to_fit();
|
||||
}
|
||||
|
||||
void processObserver(void* (& ptr)) {
|
||||
void processObserver(void*(&ptr))
|
||||
{
|
||||
if (ownerPtr) {
|
||||
ptr = ownerPtr;
|
||||
} else {
|
||||
@@ -138,27 +159,40 @@ namespace bitsery {
|
||||
void* ownerPtr;
|
||||
MemResourceBase* memResource;
|
||||
std::vector<std::reference_wrapper<void*>,
|
||||
StdPolyAlloc<std::reference_wrapper<void*>>> observersList;
|
||||
std::unique_ptr<PointerSharedStateBase, PointerSharedStateDeleter> sharedState{};
|
||||
StdPolyAlloc<std::reference_wrapper<void*>>>
|
||||
observersList;
|
||||
std::unique_ptr<PointerSharedStateBase, PointerSharedStateDeleter>
|
||||
sharedState{};
|
||||
};
|
||||
|
||||
class PointerLinkingContextSerialization {
|
||||
class PointerLinkingContextSerialization
|
||||
{
|
||||
public:
|
||||
explicit PointerLinkingContextSerialization(MemResourceBase* memResource = nullptr)
|
||||
: _currId{0},
|
||||
_ptrMap{StdPolyAlloc<std::pair<const void* const, PLCInfoSerializer>>{memResource}} {}
|
||||
explicit PointerLinkingContextSerialization(
|
||||
MemResourceBase* memResource = nullptr)
|
||||
: _currId{ 0 }
|
||||
, _ptrMap{ StdPolyAlloc<std::pair<const void* const, PLCInfoSerializer>>{
|
||||
memResource } }
|
||||
{
|
||||
}
|
||||
|
||||
PointerLinkingContextSerialization(const PointerLinkingContextSerialization&) = delete;
|
||||
PointerLinkingContextSerialization(
|
||||
const PointerLinkingContextSerialization&) = delete;
|
||||
|
||||
PointerLinkingContextSerialization& operator=(const PointerLinkingContextSerialization&) = delete;
|
||||
PointerLinkingContextSerialization& operator=(
|
||||
const PointerLinkingContextSerialization&) = delete;
|
||||
|
||||
PointerLinkingContextSerialization(PointerLinkingContextSerialization&&) = default;
|
||||
PointerLinkingContextSerialization(PointerLinkingContextSerialization&&) =
|
||||
default;
|
||||
|
||||
PointerLinkingContextSerialization& operator=(PointerLinkingContextSerialization&&) = default;
|
||||
PointerLinkingContextSerialization& operator=(
|
||||
PointerLinkingContextSerialization&&) = default;
|
||||
|
||||
~PointerLinkingContextSerialization() = default;
|
||||
|
||||
const PLCInfoSerializer& getInfoByPtr(const void* ptr, PointerOwnershipType ptrType) {
|
||||
const PLCInfoSerializer& getInfoByPtr(const void* ptr,
|
||||
PointerOwnershipType ptrType)
|
||||
{
|
||||
auto res = _ptrMap.emplace(ptr, PLCInfoSerializer{ _currId + 1u, ptrType });
|
||||
auto& ptrInfo = res.first->second;
|
||||
if (res.second) {
|
||||
@@ -171,8 +205,11 @@ namespace bitsery {
|
||||
|
||||
// valid, when all pointers have owners.
|
||||
// we cannot serialize pointers, if we haven't serialized objects themselves
|
||||
bool isPointerSerializationValid() const {
|
||||
return std::all_of(_ptrMap.begin(), _ptrMap.end(),
|
||||
bool isPointerSerializationValid() const
|
||||
{
|
||||
return std::all_of(
|
||||
_ptrMap.begin(),
|
||||
_ptrMap.end(),
|
||||
[](const std::pair<const void*, PLCInfoSerializer>& p) {
|
||||
return p.second.ownershipType == PointerOwnershipType::SharedOwner ||
|
||||
p.second.ownershipType == PointerOwnershipType::Owner;
|
||||
@@ -181,76 +218,98 @@ namespace bitsery {
|
||||
|
||||
private:
|
||||
size_t _currId;
|
||||
std::unordered_map<const void*, PLCInfoSerializer,
|
||||
std::hash<const void*>, std::equal_to<const void*>,
|
||||
StdPolyAlloc<std::pair<const void* const, PLCInfoSerializer>>
|
||||
> _ptrMap;
|
||||
std::unordered_map<
|
||||
const void*,
|
||||
PLCInfoSerializer,
|
||||
std::hash<const void*>,
|
||||
std::equal_to<const void*>,
|
||||
StdPolyAlloc<std::pair<const void* const, PLCInfoSerializer>>>
|
||||
_ptrMap;
|
||||
};
|
||||
|
||||
class PointerLinkingContextDeserialization {
|
||||
class PointerLinkingContextDeserialization
|
||||
{
|
||||
public:
|
||||
explicit PointerLinkingContextDeserialization(MemResourceBase* memResource = nullptr)
|
||||
: _memResource{memResource},
|
||||
_idMap{StdPolyAlloc<std::pair<const size_t, PLCInfoDeserializer>>{memResource}} {}
|
||||
explicit PointerLinkingContextDeserialization(
|
||||
MemResourceBase* memResource = nullptr)
|
||||
: _memResource{ memResource }
|
||||
, _idMap{ StdPolyAlloc<std::pair<const size_t, PLCInfoDeserializer>>{
|
||||
memResource } }
|
||||
{
|
||||
}
|
||||
|
||||
PointerLinkingContextDeserialization(const PointerLinkingContextDeserialization&) = delete;
|
||||
PointerLinkingContextDeserialization(
|
||||
const PointerLinkingContextDeserialization&) = delete;
|
||||
|
||||
PointerLinkingContextDeserialization& operator=(const PointerLinkingContextDeserialization&) = delete;
|
||||
PointerLinkingContextDeserialization& operator=(
|
||||
const PointerLinkingContextDeserialization&) = delete;
|
||||
|
||||
PointerLinkingContextDeserialization(PointerLinkingContextDeserialization&&) = default;
|
||||
PointerLinkingContextDeserialization(PointerLinkingContextDeserialization&&) =
|
||||
default;
|
||||
|
||||
PointerLinkingContextDeserialization& operator=(PointerLinkingContextDeserialization&&) = default;
|
||||
PointerLinkingContextDeserialization& operator=(
|
||||
PointerLinkingContextDeserialization&&) = default;
|
||||
|
||||
~PointerLinkingContextDeserialization() = default;
|
||||
|
||||
PLCInfoDeserializer& getInfoById(size_t id, PointerOwnershipType ptrType) {
|
||||
auto res = _idMap.emplace(id, PLCInfoDeserializer{nullptr, ptrType, _memResource});
|
||||
PLCInfoDeserializer& getInfoById(size_t id, PointerOwnershipType ptrType)
|
||||
{
|
||||
auto res =
|
||||
_idMap.emplace(id, PLCInfoDeserializer{ nullptr, ptrType, _memResource });
|
||||
auto& ptrInfo = res.first->second;
|
||||
if (!res.second)
|
||||
ptrInfo.update(ptrType);
|
||||
return ptrInfo;
|
||||
}
|
||||
|
||||
void clearSharedState() {
|
||||
void clearSharedState()
|
||||
{
|
||||
for (auto& item : _idMap)
|
||||
item.second.sharedState.reset();
|
||||
}
|
||||
|
||||
// valid, when all pointers has owners
|
||||
bool isPointerDeserializationValid() const {
|
||||
return std::all_of(_idMap.begin(), _idMap.end(),
|
||||
bool isPointerDeserializationValid() const
|
||||
{
|
||||
return std::all_of(
|
||||
_idMap.begin(),
|
||||
_idMap.end(),
|
||||
[](const std::pair<const size_t, PLCInfoDeserializer>& p) {
|
||||
return p.second.ownershipType == PointerOwnershipType::SharedOwner ||
|
||||
p.second.ownershipType == PointerOwnershipType::Owner;
|
||||
});
|
||||
}
|
||||
|
||||
MemResourceBase* getMemResource() noexcept {
|
||||
return _memResource;
|
||||
}
|
||||
MemResourceBase* getMemResource() noexcept { return _memResource; }
|
||||
|
||||
void setMemResource(MemResourceBase* resource) noexcept {
|
||||
void setMemResource(MemResourceBase* resource) noexcept
|
||||
{
|
||||
_memResource = resource;
|
||||
}
|
||||
|
||||
private:
|
||||
MemResourceBase* _memResource;
|
||||
std::unordered_map<size_t, PLCInfoDeserializer,
|
||||
std::hash<size_t>, std::equal_to<size_t>,
|
||||
StdPolyAlloc<std::pair<const size_t, PLCInfoDeserializer>>> _idMap;
|
||||
std::unordered_map<size_t,
|
||||
PLCInfoDeserializer,
|
||||
std::hash<size_t>,
|
||||
std::equal_to<size_t>,
|
||||
StdPolyAlloc<std::pair<const size_t, PLCInfoDeserializer>>>
|
||||
_idMap;
|
||||
};
|
||||
}
|
||||
|
||||
// this class is for convenience
|
||||
class PointerLinkingContext :
|
||||
public pointer_utils::PointerLinkingContextSerialization,
|
||||
public pointer_utils::PointerLinkingContextDeserialization {
|
||||
class PointerLinkingContext
|
||||
: public pointer_utils::PointerLinkingContextSerialization
|
||||
, public pointer_utils::PointerLinkingContextDeserialization
|
||||
{
|
||||
public:
|
||||
explicit PointerLinkingContext(MemResourceBase* memResource = nullptr)
|
||||
:pointer_utils::PointerLinkingContextSerialization(memResource),
|
||||
pointer_utils::PointerLinkingContextDeserialization(memResource) {};
|
||||
: pointer_utils::PointerLinkingContextSerialization(memResource)
|
||||
, pointer_utils::PointerLinkingContextDeserialization(memResource){};
|
||||
|
||||
bool isValid() const {
|
||||
bool isValid() const
|
||||
{
|
||||
return isPointerSerializationValid() && isPointerDeserializationValid();
|
||||
}
|
||||
};
|
||||
@@ -258,35 +317,44 @@ namespace bitsery {
|
||||
namespace pointer_utils {
|
||||
|
||||
template<template<typename> class TPtrManager,
|
||||
template<typename> class TPolymorphicContext, typename RTTI>
|
||||
class PointerObjectExtensionBase {
|
||||
template<typename>
|
||||
class TPolymorphicContext,
|
||||
typename RTTI>
|
||||
class PointerObjectExtensionBase
|
||||
{
|
||||
public:
|
||||
|
||||
// helper types
|
||||
template<typename T>
|
||||
struct IsPolymorphic : std::integral_constant<bool,
|
||||
RTTI::template isPolymorphic<typename TPtrManager<T>::TElement>()> {
|
||||
struct IsPolymorphic
|
||||
: std::integral_constant<
|
||||
bool,
|
||||
RTTI::template isPolymorphic<typename TPtrManager<T>::TElement>()>
|
||||
{
|
||||
};
|
||||
|
||||
template<PointerOwnershipType Value>
|
||||
using OwnershipType = std::integral_constant<PointerOwnershipType, Value>;
|
||||
|
||||
|
||||
explicit PointerObjectExtensionBase(PointerType ptrType = PointerType::Nullable,
|
||||
explicit PointerObjectExtensionBase(
|
||||
PointerType ptrType = PointerType::Nullable,
|
||||
MemResourceBase* resource = nullptr,
|
||||
bool resourcePropagate = false) :
|
||||
_ptrType{ptrType},
|
||||
_resourcePropagate{resourcePropagate},
|
||||
_resource{resource} {
|
||||
bool resourcePropagate = false)
|
||||
: _ptrType{ ptrType }
|
||||
, _resourcePropagate{ resourcePropagate }
|
||||
, _resource{ resource }
|
||||
{
|
||||
}
|
||||
|
||||
template<typename Ser, typename T, typename Fnc>
|
||||
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const {
|
||||
void serialize(Ser& ser, const T& obj, Fnc&& fnc) const
|
||||
{
|
||||
|
||||
auto ptr = TPtrManager<T>::getPtr(const_cast<T&>(obj));
|
||||
if (ptr) {
|
||||
auto& ctx = ser.template context<pointer_utils::PointerLinkingContextSerialization>();
|
||||
auto& ptrInfo = ctx.getInfoByPtr(getBasePtr(ptr), TPtrManager<T>::getOwnership());
|
||||
auto& ctx = ser.template context<
|
||||
pointer_utils::PointerLinkingContextSerialization>();
|
||||
auto& ptrInfo =
|
||||
ctx.getInfoByPtr(getBasePtr(ptr), TPtrManager<T>::getOwnership());
|
||||
details::writeSize(ser.adapter(), ptrInfo.id);
|
||||
if (TPtrManager<T>::getOwnership() != PointerOwnershipType::Observer) {
|
||||
if (!ptrInfo.isSharedProcessed)
|
||||
@@ -296,14 +364,15 @@ namespace bitsery {
|
||||
assert(_ptrType == PointerType::Nullable);
|
||||
details::writeSize(ser.adapter(), 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserialize(Des& des, T& obj, Fnc&& fnc) const {
|
||||
void deserialize(Des& des, T& obj, Fnc&& fnc) const
|
||||
{
|
||||
size_t id{};
|
||||
details::readSize(des.adapter(), id, 0, std::false_type{});
|
||||
auto& ctx = des.template context<pointer_utils::PointerLinkingContextDeserialization>();
|
||||
auto& ctx = des.template context<
|
||||
pointer_utils::PointerLinkingContextDeserialization>();
|
||||
auto prevResource = ctx.getMemResource();
|
||||
auto memResource = _resource ? _resource : prevResource;
|
||||
// if we have resource and propagate is true, then change current resource
|
||||
@@ -313,7 +382,12 @@ namespace bitsery {
|
||||
}
|
||||
if (id) {
|
||||
auto& ptrInfo = ctx.getInfoById(id, TPtrManager<T>::getOwnership());
|
||||
deserializeImpl(memResource, ptrInfo, des, obj, std::forward<Fnc>(fnc), IsPolymorphic<T>{},
|
||||
deserializeImpl(memResource,
|
||||
ptrInfo,
|
||||
des,
|
||||
obj,
|
||||
std::forward<Fnc>(fnc),
|
||||
IsPolymorphic<T>{},
|
||||
OwnershipType<TPtrManager<T>::getOwnership()>{});
|
||||
} else {
|
||||
if (_ptrType == PointerType::Nullable) {
|
||||
@@ -329,65 +403,95 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
template<typename Des, typename TObj>
|
||||
void destroyPtr(MemResourceBase* memResource, Des& des, TObj& obj,
|
||||
std::true_type /*polymorphic*/) const {
|
||||
void destroyPtr(MemResourceBase* memResource,
|
||||
Des& des,
|
||||
TObj& obj,
|
||||
std::true_type /*polymorphic*/) const
|
||||
{
|
||||
const auto& ctx = des.template context<TPolymorphicContext<RTTI>>();
|
||||
auto ptr = TPtrManager<TObj>::getPtr(obj);
|
||||
TPtrManager<TObj>::destroyPolymorphic(obj, memResource, ctx.getPolymorphicHandler(*ptr));
|
||||
TPtrManager<TObj>::destroyPolymorphic(
|
||||
obj, memResource, ctx.getPolymorphicHandler(*ptr));
|
||||
}
|
||||
|
||||
template<typename Des, typename TObj>
|
||||
void destroyPtr(MemResourceBase* memResource, Des&, TObj& obj,
|
||||
std::false_type /*polymorphic*/) const {
|
||||
TPtrManager<TObj>::destroy(obj, memResource, RTTI::template get<typename TPtrManager<TObj>::TElement>());
|
||||
void destroyPtr(MemResourceBase* memResource,
|
||||
Des&,
|
||||
TObj& obj,
|
||||
std::false_type /*polymorphic*/) const
|
||||
{
|
||||
TPtrManager<TObj>::destroy(
|
||||
obj,
|
||||
memResource,
|
||||
RTTI::template get<typename TPtrManager<TObj>::TElement>());
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
const void* getBasePtr(const T* ptr) const {
|
||||
const void* getBasePtr(const T* ptr) const
|
||||
{
|
||||
// todo implement handling of types with virtual inheritance
|
||||
// this is required to correctly track same object, when one object is derived and other is base class
|
||||
// e.g. shared_ptr<Base> and weak_ptr<Derived> or pointer observer Base*
|
||||
// this is required to correctly track same object, when one object is
|
||||
// derived and other is base class e.g. shared_ptr<Base> and
|
||||
// weak_ptr<Derived> or pointer observer Base*
|
||||
return ptr;
|
||||
}
|
||||
|
||||
template<typename Ser, typename TPtr, typename Fnc>
|
||||
void serializeImpl(Ser& ser, TPtr& ptr, Fnc&&, std::true_type) const {
|
||||
void serializeImpl(Ser& ser, TPtr& ptr, Fnc&&, std::true_type) const
|
||||
{
|
||||
const auto& ctx = ser.template context<TPolymorphicContext<RTTI>>();
|
||||
ctx.serialize(ser, *ptr);
|
||||
}
|
||||
|
||||
template<typename Ser, typename TPtr, typename Fnc>
|
||||
void serializeImpl(Ser& ser, TPtr& ptr, Fnc&& fnc, std::false_type) const {
|
||||
void serializeImpl(Ser& ser, TPtr& ptr, Fnc&& fnc, std::false_type) const
|
||||
{
|
||||
fnc(ser, *ptr);
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserializeImpl(MemResourceBase* memResource, PLCInfoDeserializer& ptrInfo, Des& des, T& obj, Fnc&&,
|
||||
std::true_type, OwnershipType<PointerOwnershipType::Owner>) const {
|
||||
void deserializeImpl(MemResourceBase* memResource,
|
||||
PLCInfoDeserializer& ptrInfo,
|
||||
Des& des,
|
||||
T& obj,
|
||||
Fnc&&,
|
||||
std::true_type,
|
||||
OwnershipType<PointerOwnershipType::Owner>) const
|
||||
{
|
||||
const auto& ctx = des.template context<TPolymorphicContext<RTTI>>();
|
||||
ctx.deserialize(des, TPtrManager<T>::getPtr(obj),
|
||||
[&obj, memResource](
|
||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
ctx.deserialize(
|
||||
des,
|
||||
TPtrManager<T>::getPtr(obj),
|
||||
[&obj,
|
||||
memResource](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
TPtrManager<T>::createPolymorphic(obj, memResource, handler);
|
||||
return TPtrManager<T>::getPtr(obj);
|
||||
},
|
||||
[&obj, memResource](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
[&obj,
|
||||
memResource](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
TPtrManager<T>::destroyPolymorphic(obj, memResource, handler);
|
||||
});
|
||||
ptrInfo.processOwner(TPtrManager<T>::getPtr(obj));
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserializeImpl(MemResourceBase* memResource, PLCInfoDeserializer& ptrInfo, Des& des, T& obj, Fnc&& fnc,
|
||||
std::false_type, OwnershipType<PointerOwnershipType::Owner>) const {
|
||||
void deserializeImpl(MemResourceBase* memResource,
|
||||
PLCInfoDeserializer& ptrInfo,
|
||||
Des& des,
|
||||
T& obj,
|
||||
Fnc&& fnc,
|
||||
std::false_type,
|
||||
OwnershipType<PointerOwnershipType::Owner>) const
|
||||
{
|
||||
auto ptr = TPtrManager<T>::getPtr(obj);
|
||||
if (ptr) {
|
||||
fnc(des, *ptr);
|
||||
} else {
|
||||
TPtrManager<T>::create(obj, memResource, RTTI::template get<typename TPtrManager<T>::TElement>());
|
||||
TPtrManager<T>::create(
|
||||
obj,
|
||||
memResource,
|
||||
RTTI::template get<typename TPtrManager<T>::TElement>());
|
||||
ptr = TPtrManager<T>::getPtr(obj);
|
||||
fnc(des, *ptr);
|
||||
}
|
||||
@@ -395,39 +499,57 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserializeImpl(MemResourceBase* memResource, PLCInfoDeserializer& ptrInfo, Des& des, T& obj, Fnc&&,
|
||||
std::true_type, OwnershipType<PointerOwnershipType::SharedOwner>) const {
|
||||
void deserializeImpl(MemResourceBase* memResource,
|
||||
PLCInfoDeserializer& ptrInfo,
|
||||
Des& des,
|
||||
T& obj,
|
||||
Fnc&&,
|
||||
std::true_type,
|
||||
OwnershipType<PointerOwnershipType::SharedOwner>) const
|
||||
{
|
||||
if (!ptrInfo.sharedState) {
|
||||
const auto& ctx = des.template context<TPolymorphicContext<RTTI>>();
|
||||
ctx.deserialize(des, TPtrManager<T>::getPtr(obj),
|
||||
ctx.deserialize(
|
||||
des,
|
||||
TPtrManager<T>::getPtr(obj),
|
||||
[&obj, &ptrInfo, memResource, this](
|
||||
const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
TPtrManager<T>::createSharedPolymorphic(
|
||||
createAndGetSharedStateObj<T>(ptrInfo),
|
||||
obj, memResource, handler);
|
||||
createAndGetSharedStateObj<T>(ptrInfo), obj, memResource, handler);
|
||||
return TPtrManager<T>::getPtr(obj);
|
||||
},
|
||||
[&obj, memResource](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
[&obj,
|
||||
memResource](const std::shared_ptr<PolymorphicHandlerBase>& handler) {
|
||||
TPtrManager<T>::destroyPolymorphic(obj, memResource, handler);
|
||||
});
|
||||
if (!ptrInfo.sharedState)
|
||||
TPtrManager<T>::saveToSharedState(createAndGetSharedStateObj<T>(ptrInfo), obj);
|
||||
TPtrManager<T>::saveToSharedState(
|
||||
createAndGetSharedStateObj<T>(ptrInfo), obj);
|
||||
}
|
||||
TPtrManager<T>::loadFromSharedState(getSharedStateObj<T>(ptrInfo), obj);
|
||||
ptrInfo.processOwner(TPtrManager<T>::getPtr(obj));
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc>
|
||||
void deserializeImpl(MemResourceBase* memResource, PLCInfoDeserializer& ptrInfo, Des& des, T& obj, Fnc&& fnc,
|
||||
std::false_type, OwnershipType<PointerOwnershipType::SharedOwner>) const {
|
||||
void deserializeImpl(MemResourceBase* memResource,
|
||||
PLCInfoDeserializer& ptrInfo,
|
||||
Des& des,
|
||||
T& obj,
|
||||
Fnc&& fnc,
|
||||
std::false_type,
|
||||
OwnershipType<PointerOwnershipType::SharedOwner>) const
|
||||
{
|
||||
if (!ptrInfo.sharedState) {
|
||||
auto ptr = TPtrManager<T>::getPtr(obj);
|
||||
if (ptr) {
|
||||
TPtrManager<T>::saveToSharedState(createAndGetSharedStateObj<T>(ptrInfo), obj);
|
||||
TPtrManager<T>::saveToSharedState(
|
||||
createAndGetSharedStateObj<T>(ptrInfo), obj);
|
||||
} else {
|
||||
TPtrManager<T>::createShared(
|
||||
createAndGetSharedStateObj<T>(ptrInfo),
|
||||
obj, memResource, RTTI::template get<typename TPtrManager<T>::TElement>());
|
||||
obj,
|
||||
memResource,
|
||||
RTTI::template get<typename TPtrManager<T>::TElement>());
|
||||
ptr = TPtrManager<T>::getPtr(obj);
|
||||
}
|
||||
fnc(des, *ptr);
|
||||
@@ -437,36 +559,59 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc, typename isPolymorph>
|
||||
void deserializeImpl(MemResourceBase* memResource, PLCInfoDeserializer& ptrInfo, Des& des, T& obj,
|
||||
Fnc&& fnc, isPolymorph polymorph,
|
||||
OwnershipType<PointerOwnershipType::SharedObserver>) const {
|
||||
deserializeImpl(memResource, ptrInfo, des, obj, fnc, polymorph,
|
||||
void deserializeImpl(
|
||||
MemResourceBase* memResource,
|
||||
PLCInfoDeserializer& ptrInfo,
|
||||
Des& des,
|
||||
T& obj,
|
||||
Fnc&& fnc,
|
||||
isPolymorph polymorph,
|
||||
OwnershipType<PointerOwnershipType::SharedObserver>) const
|
||||
{
|
||||
deserializeImpl(memResource,
|
||||
ptrInfo,
|
||||
des,
|
||||
obj,
|
||||
fnc,
|
||||
polymorph,
|
||||
OwnershipType<PointerOwnershipType::SharedOwner>{});
|
||||
}
|
||||
|
||||
template<typename Des, typename T, typename Fnc, typename isPolymorphic>
|
||||
void deserializeImpl(MemResourceBase* , PLCInfoDeserializer& ptrInfo, Des&, T& obj, Fnc&&,
|
||||
isPolymorphic, OwnershipType<PointerOwnershipType::Observer>) const {
|
||||
ptrInfo.processObserver(reinterpret_cast<void*&>(TPtrManager<T>::getPtrRef(obj)));
|
||||
void deserializeImpl(MemResourceBase*,
|
||||
PLCInfoDeserializer& ptrInfo,
|
||||
Des&,
|
||||
T& obj,
|
||||
Fnc&&,
|
||||
isPolymorphic,
|
||||
OwnershipType<PointerOwnershipType::Observer>) const
|
||||
{
|
||||
ptrInfo.processObserver(
|
||||
reinterpret_cast<void*&>(TPtrManager<T>::getPtrRef(obj)));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename TPtrManager<T>::TSharedState& createAndGetSharedStateObj(PLCInfoDeserializer& info) const {
|
||||
typename TPtrManager<T>::TSharedState& createAndGetSharedStateObj(
|
||||
PLCInfoDeserializer& info) const
|
||||
{
|
||||
using TSharedState = typename TPtrManager<T>::TSharedState;
|
||||
StdPolyAlloc<TSharedState> alloc{ info.memResource };
|
||||
auto* ptr = alloc.allocate(1);
|
||||
auto* obj = new (ptr) TSharedState{};
|
||||
info.sharedState = std::unique_ptr<PointerSharedStateBase, PointerSharedStateDeleter>(
|
||||
info.sharedState =
|
||||
std::unique_ptr<PointerSharedStateBase, PointerSharedStateDeleter>(
|
||||
obj, PointerSharedStateDeleter{ info.memResource });
|
||||
return *obj;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
typename TPtrManager<T>::TSharedState& getSharedStateObj(PLCInfoDeserializer& info) const {
|
||||
return static_cast<typename TPtrManager<T>::TSharedState&>(*info.sharedState);
|
||||
typename TPtrManager<T>::TSharedState& getSharedStateObj(
|
||||
PLCInfoDeserializer& info) const
|
||||
{
|
||||
return static_cast<typename TPtrManager<T>::TSharedState&>(
|
||||
*info.sharedState);
|
||||
}
|
||||
|
||||
|
||||
PointerType _ptrType;
|
||||
bool _resourcePropagate;
|
||||
MemResourceBase* _resource;
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
#include "memory_resource.h"
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
@@ -34,35 +34,44 @@ namespace bitsery {
|
||||
|
||||
// helper type, that contains list of types
|
||||
template<typename...>
|
||||
struct PolymorphicClassesList {
|
||||
struct PolymorphicClassesList
|
||||
{
|
||||
};
|
||||
|
||||
//specialize for your base class by deriving from PolymorphicDerivedClasses with list of derivatives that DIRECTLY inherits from your base class.
|
||||
// specialize for your base class by deriving from PolymorphicDerivedClasses
|
||||
// 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 !!!
|
||||
// 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 <> 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 {
|
||||
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>{};
|
||||
// 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 {
|
||||
struct PolymorphicDerivedClasses
|
||||
{
|
||||
using Childs = PolymorphicClassesList<T1, Tn...>;
|
||||
};
|
||||
|
||||
class PolymorphicHandlerBase {
|
||||
class PolymorphicHandlerBase
|
||||
{
|
||||
public:
|
||||
virtual void* create(const pointer_utils::PolyAllocWithTypeId& alloc) const = 0;
|
||||
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;
|
||||
|
||||
@@ -70,192 +79,263 @@ namespace bitsery {
|
||||
};
|
||||
|
||||
template<typename RTTI, typename TSerializer, typename TBase, typename TDerived>
|
||||
class PolymorphicHandler : public PolymorphicHandlerBase {
|
||||
class PolymorphicHandler : public PolymorphicHandlerBase
|
||||
{
|
||||
public:
|
||||
|
||||
void* create(const pointer_utils::PolyAllocWithTypeId& alloc) const final {
|
||||
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 {
|
||||
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 {
|
||||
void process(void* ser, void* obj) const final
|
||||
{
|
||||
static_cast<TSerializer*>(ser)->object(*fromBase(obj));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
TDerived* fromBase(void* obj) const {
|
||||
TDerived* fromBase(void* obj) const
|
||||
{
|
||||
return RTTI::template cast<TBase, TDerived>(static_cast<TBase*>(obj));
|
||||
}
|
||||
|
||||
TBase* toBase(void* obj) const {
|
||||
TBase* toBase(void* obj) const
|
||||
{
|
||||
return RTTI::template cast<TDerived, TBase>(static_cast<TDerived*>(obj));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename RTTI>
|
||||
class PolymorphicContext {
|
||||
class PolymorphicContext
|
||||
{
|
||||
private:
|
||||
|
||||
struct BaseToDerivedKey {
|
||||
struct BaseToDerivedKey
|
||||
{
|
||||
|
||||
std::size_t baseHash;
|
||||
std::size_t derivedHash;
|
||||
|
||||
bool operator==(const BaseToDerivedKey& other) const {
|
||||
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;
|
||||
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() {
|
||||
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{});
|
||||
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...>) {
|
||||
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.");
|
||||
"PolymorphicBaseClass<TBase> must derive a list of derived "
|
||||
"classes from TBase.");
|
||||
add<TSerializer, THierarchy, TBase, T1>();
|
||||
addChilds<TSerializer, THierarchy, TBase, TDerived>(PolymorphicClassesList<Tn...>{});
|
||||
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,
|
||||
template<typename>
|
||||
class THierarchy,
|
||||
typename TBase,
|
||||
typename TDerived>
|
||||
void addChilds(PolymorphicClassesList<>)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename TSerializer, typename TBase, typename TDerived>
|
||||
void addToMap(std::false_type) {
|
||||
void addToMap(std::false_type)
|
||||
{
|
||||
using THandler = PolymorphicHandler<RTTI, TSerializer, TBase, TDerived>;
|
||||
BaseToDerivedKey key{RTTI::template get<TBase>(), RTTI::template get<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 {
|
||||
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) {
|
||||
},
|
||||
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,
|
||||
it = _baseToDerivedArray
|
||||
.emplace(std::piecewise_construct,
|
||||
std::forward_as_tuple(key.baseHash),
|
||||
std::forward_as_tuple(pointer_utils::StdPolyAlloc<size_t>{_memResource})).first;
|
||||
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) {
|
||||
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;
|
||||
// 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}}
|
||||
{}
|
||||
: _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() {
|
||||
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)
|
||||
// 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...>) {
|
||||
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<>) {
|
||||
void registerBasesList(PolymorphicClassesList<>)
|
||||
{
|
||||
}
|
||||
|
||||
// optional method, in case you want to construct base class hierarchy your self
|
||||
// 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");
|
||||
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 {
|
||||
void serialize(Serializer& ser, TBase& obj) const
|
||||
{
|
||||
// get derived key
|
||||
BaseToDerivedKey key{RTTI::template get<TBase>(), RTTI::template get<TBase>(obj)};
|
||||
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
|
||||
// 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)));
|
||||
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 {
|
||||
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>());
|
||||
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
|
||||
// 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;
|
||||
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) {
|
||||
@@ -269,14 +349,14 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
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)});
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -23,36 +23,40 @@
|
||||
#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 {
|
||||
|
||||
struct StandardRTTI {
|
||||
struct StandardRTTI
|
||||
{
|
||||
|
||||
template<typename TBase>
|
||||
static size_t get(TBase& obj) {
|
||||
static size_t get(TBase& obj)
|
||||
{
|
||||
return typeid(obj).hash_code();
|
||||
}
|
||||
|
||||
template<typename TBase>
|
||||
static constexpr size_t get() {
|
||||
static constexpr size_t get()
|
||||
{
|
||||
return typeid(TBase).hash_code();
|
||||
}
|
||||
|
||||
template<typename TBase, typename TDerived>
|
||||
static constexpr TDerived* cast(TBase* obj) {
|
||||
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() {
|
||||
static constexpr bool isPolymorphic()
|
||||
{
|
||||
return std::is_polymorphic<TBase>::value;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -28,9 +28,14 @@
|
||||
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} {}
|
||||
// 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;
|
||||
};
|
||||
@@ -40,23 +45,30 @@ namespace bitsery {
|
||||
namespace details {
|
||||
|
||||
template<typename T>
|
||||
constexpr size_t getSize(T v, size_t s) {
|
||||
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
|
||||
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 {
|
||||
struct RangeSpec
|
||||
{
|
||||
|
||||
constexpr RangeSpec(T minValue, T maxValue)
|
||||
: min{minValue},
|
||||
max{maxValue},
|
||||
bitsRequired{calcRequiredBits(min, max)} {
|
||||
: min{ minValue }
|
||||
, max{ maxValue }
|
||||
, bitsRequired{ calcRequiredBits(min, max) }
|
||||
{
|
||||
}
|
||||
|
||||
const T min;
|
||||
@@ -64,16 +76,17 @@ namespace bitsery {
|
||||
const size_t bitsRequired;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct RangeSpec<T, typename std::enable_if<std::is_enum<T>::value>::type> {
|
||||
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(
|
||||
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))} {
|
||||
static_cast<typename std::underlying_type<T>::type>(max)) }
|
||||
{
|
||||
}
|
||||
|
||||
const T min;
|
||||
@@ -81,22 +94,26 @@ namespace bitsery {
|
||||
const size_t bitsRequired;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct RangeSpec<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
|
||||
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, 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))} {
|
||||
|
||||
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;
|
||||
@@ -104,89 +121,122 @@ namespace bitsery {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
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) {
|
||||
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) {
|
||||
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));
|
||||
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 {
|
||||
class ValueRange
|
||||
{
|
||||
public:
|
||||
|
||||
template<typename... Args>
|
||||
constexpr ValueRange(const TValue& min, const TValue& max, Args&&... args)
|
||||
:_range{min, max, std::forward<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 {
|
||||
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);
|
||||
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 {
|
||||
void deserialize(Des& des, T& v, Fnc&&) const
|
||||
{
|
||||
auto& reader = des.adapter();
|
||||
reader.readBits(reinterpret_cast<details::SameSizeUnsigned<T> &>(v), _range.bitsRequired);
|
||||
reader.readBits(reinterpret_cast<details::SameSizeUnsigned<T>&>(v),
|
||||
_range.bitsRequired);
|
||||
details::setRangeValue(v, _range);
|
||||
handleInvalidRange(reader, v, std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
|
||||
handleInvalidRange(
|
||||
reader, v, std::integral_constant<bool, Des::TConfig::CheckDataErrors>{});
|
||||
}
|
||||
|
||||
constexpr size_t getRequiredBits() const {
|
||||
return _range.bitsRequired;
|
||||
};
|
||||
private:
|
||||
constexpr size_t getRequiredBits() const { return _range.bitsRequired; };
|
||||
|
||||
private:
|
||||
template<typename Reader, typename T>
|
||||
void handleInvalidRange(Reader& reader, T& v, std::true_type) const {
|
||||
void handleInvalidRange(Reader& reader, T& v, std::true_type) const
|
||||
{
|
||||
if (!details::isRangeValid(v, _range)) {
|
||||
reader.error(ReaderError::InvalidData);
|
||||
v = _range.min;
|
||||
@@ -194,7 +244,8 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Reader, typename T>
|
||||
void handleInvalidRange(Reader&, T&, std::false_type) const {
|
||||
void handleInvalidRange(Reader&, T&, std::false_type) const
|
||||
{
|
||||
}
|
||||
|
||||
details::RangeSpec<TValue> _range;
|
||||
@@ -203,7 +254,8 @@ namespace bitsery {
|
||||
|
||||
namespace traits {
|
||||
template<typename T>
|
||||
struct ExtensionTraits<ext::ValueRange<T>, T> {
|
||||
struct ExtensionTraits<ext::ValueRange<T>, T>
|
||||
{
|
||||
using TValue = void;
|
||||
static constexpr bool SupportValueOverload = false;
|
||||
static constexpr bool SupportObjectOverload = true;
|
||||
@@ -213,5 +265,4 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_EXT_VALUE_RANGE_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
|
||||
#ifndef BITSERY_SERIALIZER_H
|
||||
#define BITSERY_SERIALIZER_H
|
||||
|
||||
@@ -30,33 +29,43 @@
|
||||
namespace bitsery {
|
||||
|
||||
template<typename TOutputAdapter, typename TContext = void>
|
||||
class Serializer: public details::AdapterAndContextRef<TOutputAdapter, TContext> {
|
||||
class Serializer
|
||||
: public details::AdapterAndContextRef<TOutputAdapter, TContext>
|
||||
{
|
||||
public:
|
||||
//helper type, that always returns bit-packing enabled type, useful inside serialize function when enabling bitpacking
|
||||
using BPEnabledType = Serializer<typename TOutputAdapter::BitPackingEnabled, TContext>;
|
||||
// helper type, that always returns bit-packing enabled type, useful inside
|
||||
// serialize function when enabling bitpacking
|
||||
using BPEnabledType =
|
||||
Serializer<typename TOutputAdapter::BitPackingEnabled, TContext>;
|
||||
using TConfig = typename TOutputAdapter::TConfig;
|
||||
|
||||
using details::AdapterAndContextRef<TOutputAdapter, TContext>::AdapterAndContextRef;
|
||||
using details::AdapterAndContextRef<TOutputAdapter,
|
||||
TContext>::AdapterAndContextRef;
|
||||
|
||||
/*
|
||||
* object function
|
||||
*/
|
||||
template<typename T>
|
||||
void object(const T &obj) {
|
||||
details::SerializeFunction<Serializer, T>::invoke(*this, const_cast<T& >(obj));
|
||||
void object(const T& obj)
|
||||
{
|
||||
details::SerializeFunction<Serializer, T>::invoke(*this,
|
||||
const_cast<T&>(obj));
|
||||
}
|
||||
|
||||
template<typename T, typename Fnc>
|
||||
void object(const T &obj, Fnc &&fnc) {
|
||||
void object(const T& obj, Fnc&& fnc)
|
||||
{
|
||||
fnc(*this, const_cast<T&>(obj));
|
||||
}
|
||||
|
||||
/*
|
||||
* functionality, that enables simpler serialization syntax, by including additional header
|
||||
* functionality, that enables simpler serialization syntax, by including
|
||||
* additional header
|
||||
*/
|
||||
|
||||
template<typename... TArgs>
|
||||
Serializer &operator()(TArgs &&... args) {
|
||||
Serializer& operator()(TArgs&&... args)
|
||||
{
|
||||
archive(std::forward<TArgs>(args)...);
|
||||
return *this;
|
||||
}
|
||||
@@ -66,19 +75,25 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void value(const T &v) {
|
||||
static_assert(details::IsFundamentalType<T>::value, "Value must be integral, float or enum type.");
|
||||
void value(const T& v)
|
||||
{
|
||||
static_assert(details::IsFundamentalType<T>::value,
|
||||
"Value must be integral, float or enum type.");
|
||||
using TValue = typename details::IntegralFromFundamental<T>::TValue;
|
||||
this->_adapter.template writeBytes<VSIZE>(reinterpret_cast<const TValue &>(v));
|
||||
this->_adapter.template writeBytes<VSIZE>(
|
||||
reinterpret_cast<const TValue&>(v));
|
||||
}
|
||||
|
||||
/*
|
||||
* enable bit-packing
|
||||
*/
|
||||
template<typename Fnc>
|
||||
void enableBitPacking(Fnc&& fnc) {
|
||||
procEnableBitPacking(std::forward<Fnc>(fnc),
|
||||
std::is_same<TOutputAdapter, typename TOutputAdapter::BitPackingEnabled>{},
|
||||
void enableBitPacking(Fnc&& fnc)
|
||||
{
|
||||
procEnableBitPacking(
|
||||
std::forward<Fnc>(fnc),
|
||||
std::is_same<TOutputAdapter,
|
||||
typename TOutputAdapter::BitPackingEnabled>{},
|
||||
std::integral_constant<bool, Serializer::HasContext>{});
|
||||
}
|
||||
|
||||
@@ -87,39 +102,54 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T, typename Ext, typename Fnc>
|
||||
void ext(const T &obj, const Ext &extension, Fnc &&fnc) {
|
||||
static_assert(details::IsExtensionTraitsDefined<Ext, T>::value, "Please define ExtensionTraits");
|
||||
void ext(const T& obj, const Ext& extension, Fnc&& fnc)
|
||||
{
|
||||
static_assert(details::IsExtensionTraitsDefined<Ext, T>::value,
|
||||
"Please define ExtensionTraits");
|
||||
static_assert(traits::ExtensionTraits<Ext, T>::SupportLambdaOverload,
|
||||
"extension doesn't support overload with lambda");
|
||||
extension.serialize(*this, obj, std::forward<Fnc>(fnc));
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T, typename Ext>
|
||||
void ext(const T &obj, const Ext &extension) {
|
||||
static_assert(details::IsExtensionTraitsDefined<Ext, T>::value, "Please define ExtensionTraits");
|
||||
void ext(const T& obj, const Ext& extension)
|
||||
{
|
||||
static_assert(details::IsExtensionTraitsDefined<Ext, T>::value,
|
||||
"Please define ExtensionTraits");
|
||||
static_assert(traits::ExtensionTraits<Ext, T>::SupportValueOverload,
|
||||
"extension doesn't support overload with `value<N>`");
|
||||
using ExtVType = typename traits::ExtensionTraits<Ext, T>::TValue;
|
||||
using VType = typename std::conditional<std::is_void<ExtVType>::value, details::DummyType, ExtVType>::type;
|
||||
extension.serialize(*this, obj, [](Serializer& s, VType &v) { s.value<VSIZE>(v); });
|
||||
using VType = typename std::conditional<std::is_void<ExtVType>::value,
|
||||
details::DummyType,
|
||||
ExtVType>::type;
|
||||
extension.serialize(
|
||||
*this, obj, [](Serializer& s, VType& v) { s.value<VSIZE>(v); });
|
||||
}
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext(const T &obj, const Ext &extension) {
|
||||
static_assert(details::IsExtensionTraitsDefined<Ext, T>::value, "Please define ExtensionTraits");
|
||||
void ext(const T& obj, const Ext& extension)
|
||||
{
|
||||
static_assert(details::IsExtensionTraitsDefined<Ext, T>::value,
|
||||
"Please define ExtensionTraits");
|
||||
static_assert(traits::ExtensionTraits<Ext, T>::SupportObjectOverload,
|
||||
"extension doesn't support overload with `object`");
|
||||
using ExtVType = typename traits::ExtensionTraits<Ext, T>::TValue;
|
||||
using VType = typename std::conditional<std::is_void<ExtVType>::value, details::DummyType, ExtVType>::type;
|
||||
extension.serialize(*this, obj, [](Serializer& s, VType &v) { s.object(v); });
|
||||
using VType = typename std::conditional<std::is_void<ExtVType>::value,
|
||||
details::DummyType,
|
||||
ExtVType>::type;
|
||||
extension.serialize(
|
||||
*this, obj, [](Serializer& s, VType& v) { s.object(v); });
|
||||
}
|
||||
|
||||
/*
|
||||
* boolValue
|
||||
*/
|
||||
|
||||
void boolValue(bool v) {
|
||||
procBoolValue(v, std::is_same<TOutputAdapter, typename TOutputAdapter::BitPackingEnabled>{});
|
||||
void boolValue(bool v)
|
||||
{
|
||||
procBoolValue(v,
|
||||
std::is_same<TOutputAdapter,
|
||||
typename TOutputAdapter::BitPackingEnabled>{});
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -127,20 +157,26 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void text(const T &str, size_t maxSize) {
|
||||
static_assert(details::IsTextTraitsDefined<T>::value,
|
||||
void text(const T& str, size_t maxSize)
|
||||
{
|
||||
static_assert(
|
||||
details::IsTextTraitsDefined<T>::value,
|
||||
"Please define TextTraits or include from <bitsery/traits/...>");
|
||||
static_assert(traits::ContainerTraits<T>::isResizable,
|
||||
static_assert(
|
||||
traits::ContainerTraits<T>::isResizable,
|
||||
"use text(const T&) overload without `maxSize` for static container");
|
||||
procText<VSIZE>(str, maxSize);
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void text(const T &str) {
|
||||
static_assert(details::IsTextTraitsDefined<T>::value,
|
||||
void text(const T& str)
|
||||
{
|
||||
static_assert(
|
||||
details::IsTextTraitsDefined<T>::value,
|
||||
"Please define TextTraits or include from <bitsery/traits/...>");
|
||||
static_assert(!traits::ContainerTraits<T>::isResizable,
|
||||
"use text(const T&, size_t) overload with `maxSize` for dynamic containers");
|
||||
"use text(const T&, size_t) overload with `maxSize` for "
|
||||
"dynamic containers");
|
||||
procText<VSIZE>(str, traits::ContainerTraits<T>::size(str));
|
||||
}
|
||||
|
||||
@@ -151,11 +187,14 @@ namespace bitsery {
|
||||
// dynamic size containers
|
||||
|
||||
template<typename T, typename Fnc>
|
||||
void container(const T &obj, size_t maxSize, Fnc &&fnc) {
|
||||
static_assert(details::IsContainerTraitsDefined<T>::value,
|
||||
void container(const T& obj, size_t maxSize, Fnc&& fnc)
|
||||
{
|
||||
static_assert(
|
||||
details::IsContainerTraitsDefined<T>::value,
|
||||
"Please define ContainerTraits or include from <bitsery/traits/...>");
|
||||
static_assert(traits::ContainerTraits<T>::isResizable,
|
||||
"use container(const T&, Fnc) overload without `maxSize` for static containers");
|
||||
"use container(const T&, Fnc) overload without `maxSize` for "
|
||||
"static containers");
|
||||
auto size = traits::ContainerTraits<T>::size(obj);
|
||||
(void)maxSize; // unused in release
|
||||
assert(size <= maxSize);
|
||||
@@ -164,26 +203,35 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void container(const T &obj, size_t maxSize) {
|
||||
static_assert(details::IsContainerTraitsDefined<T>::value,
|
||||
void container(const T& obj, size_t maxSize)
|
||||
{
|
||||
static_assert(
|
||||
details::IsContainerTraitsDefined<T>::value,
|
||||
"Please define ContainerTraits or include from <bitsery/traits/...>");
|
||||
static_assert(traits::ContainerTraits<T>::isResizable,
|
||||
"use container(const T&) overload without `maxSize` for static containers");
|
||||
"use container(const T&) overload without `maxSize` for "
|
||||
"static containers");
|
||||
static_assert(VSIZE > 0, "");
|
||||
auto size = traits::ContainerTraits<T>::size(obj);
|
||||
(void)maxSize; // unused in release
|
||||
assert(size <= maxSize);
|
||||
details::writeSize(this->_adapter, size);
|
||||
|
||||
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::integral_constant<bool, traits::ContainerTraits<T>::isContiguous>{});
|
||||
procContainer<VSIZE>(
|
||||
std::begin(obj),
|
||||
std::end(obj),
|
||||
std::integral_constant<bool, traits::ContainerTraits<T>::isContiguous>{});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container(const T &obj, size_t maxSize) {
|
||||
static_assert(details::IsContainerTraitsDefined<T>::value,
|
||||
void container(const T& obj, size_t maxSize)
|
||||
{
|
||||
static_assert(
|
||||
details::IsContainerTraitsDefined<T>::value,
|
||||
"Please define ContainerTraits or include from <bitsery/traits/...>");
|
||||
static_assert(traits::ContainerTraits<T>::isResizable,
|
||||
"use container(const T&) overload without `maxSize` for static containers");
|
||||
"use container(const T&) overload without `maxSize` for "
|
||||
"static containers");
|
||||
auto size = traits::ContainerTraits<T>::size(obj);
|
||||
(void)maxSize; // unused in release
|
||||
assert(size <= maxSize);
|
||||
@@ -193,121 +241,213 @@ namespace bitsery {
|
||||
|
||||
// fixed size containers
|
||||
|
||||
template<typename T, typename Fnc, typename std::enable_if<!std::is_integral<Fnc>::value>::type * = nullptr>
|
||||
void container(const T &obj, Fnc &&fnc) {
|
||||
static_assert(details::IsContainerTraitsDefined<T>::value,
|
||||
template<
|
||||
typename T,
|
||||
typename Fnc,
|
||||
typename std::enable_if<!std::is_integral<Fnc>::value>::type* = nullptr>
|
||||
void container(const T& obj, Fnc&& fnc)
|
||||
{
|
||||
static_assert(
|
||||
details::IsContainerTraitsDefined<T>::value,
|
||||
"Please define ContainerTraits or include from <bitsery/traits/...>");
|
||||
static_assert(!traits::ContainerTraits<T>::isResizable,
|
||||
"use container(const T&, size_t, Fnc) overload with `maxSize` for dynamic containers");
|
||||
"use container(const T&, size_t, Fnc) overload with "
|
||||
"`maxSize` for dynamic containers");
|
||||
procContainer(std::begin(obj), std::end(obj), std::forward<Fnc>(fnc));
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void container(const T &obj) {
|
||||
static_assert(details::IsContainerTraitsDefined<T>::value,
|
||||
void container(const T& obj)
|
||||
{
|
||||
static_assert(
|
||||
details::IsContainerTraitsDefined<T>::value,
|
||||
"Please define ContainerTraits or include from <bitsery/traits/...>");
|
||||
static_assert(!traits::ContainerTraits<T>::isResizable,
|
||||
"use container(const T&, size_t) overload with `maxSize` for dynamic containers");
|
||||
"use container(const T&, size_t) overload with `maxSize` for "
|
||||
"dynamic containers");
|
||||
static_assert(VSIZE > 0, "");
|
||||
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::integral_constant<bool, traits::ContainerTraits<T>::isContiguous>{});
|
||||
procContainer<VSIZE>(
|
||||
std::begin(obj),
|
||||
std::end(obj),
|
||||
std::integral_constant<bool, traits::ContainerTraits<T>::isContiguous>{});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container(const T &obj) {
|
||||
static_assert(details::IsContainerTraitsDefined<T>::value,
|
||||
void container(const T& obj)
|
||||
{
|
||||
static_assert(
|
||||
details::IsContainerTraitsDefined<T>::value,
|
||||
"Please define ContainerTraits or include from <bitsery/traits/...>");
|
||||
static_assert(!traits::ContainerTraits<T>::isResizable,
|
||||
"use container(const T&, size_t) overload with `maxSize` for dynamic containers");
|
||||
"use container(const T&, size_t) overload with `maxSize` for "
|
||||
"dynamic containers");
|
||||
procContainer(std::begin(obj), std::end(obj));
|
||||
}
|
||||
|
||||
// overloads for functions with explicit type size
|
||||
|
||||
template<typename T>
|
||||
void value1b(T &&v) { value<1>(std::forward<T>(v)); }
|
||||
void value1b(T&& v)
|
||||
{
|
||||
value<1>(std::forward<T>(v));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void value2b(T &&v) { value<2>(std::forward<T>(v)); }
|
||||
void value2b(T&& v)
|
||||
{
|
||||
value<2>(std::forward<T>(v));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void value4b(T &&v) { value<4>(std::forward<T>(v)); }
|
||||
void value4b(T&& v)
|
||||
{
|
||||
value<4>(std::forward<T>(v));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void value8b(T &&v) { value<8>(std::forward<T>(v)); }
|
||||
void value8b(T&& v)
|
||||
{
|
||||
value<8>(std::forward<T>(v));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void value16b(T &&v) { value<16>(std::forward<T>(v)); }
|
||||
void value16b(T&& v)
|
||||
{
|
||||
value<16>(std::forward<T>(v));
|
||||
}
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext1b(const T &v, Ext &&extension) { ext<1, T, Ext>(v, std::forward<Ext>(extension)); }
|
||||
void ext1b(const T& v, Ext&& extension)
|
||||
{
|
||||
ext<1, T, Ext>(v, std::forward<Ext>(extension));
|
||||
}
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext2b(const T &v, Ext &&extension) { ext<2, T, Ext>(v, std::forward<Ext>(extension)); }
|
||||
void ext2b(const T& v, Ext&& extension)
|
||||
{
|
||||
ext<2, T, Ext>(v, std::forward<Ext>(extension));
|
||||
}
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext4b(const T &v, Ext &&extension) { ext<4, T, Ext>(v, std::forward<Ext>(extension)); }
|
||||
void ext4b(const T& v, Ext&& extension)
|
||||
{
|
||||
ext<4, T, Ext>(v, std::forward<Ext>(extension));
|
||||
}
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext8b(const T &v, Ext &&extension) { ext<8, T, Ext>(v, std::forward<Ext>(extension)); }
|
||||
void ext8b(const T& v, Ext&& extension)
|
||||
{
|
||||
ext<8, T, Ext>(v, std::forward<Ext>(extension));
|
||||
}
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext16b(const T &v, Ext &&extension) { ext<16, T, Ext>(v, std::forward<Ext>(extension)); }
|
||||
void ext16b(const T& v, Ext&& extension)
|
||||
{
|
||||
ext<16, T, Ext>(v, std::forward<Ext>(extension));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void text1b(const T &str, size_t maxSize) { text<1>(str, maxSize); }
|
||||
void text1b(const T& str, size_t maxSize)
|
||||
{
|
||||
text<1>(str, maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void text2b(const T &str, size_t maxSize) { text<2>(str, maxSize); }
|
||||
void text2b(const T& str, size_t maxSize)
|
||||
{
|
||||
text<2>(str, maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void text4b(const T &str, size_t maxSize) { text<4>(str, maxSize); }
|
||||
void text4b(const T& str, size_t maxSize)
|
||||
{
|
||||
text<4>(str, maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void text1b(const T &str) { text<1>(str); }
|
||||
void text1b(const T& str)
|
||||
{
|
||||
text<1>(str);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void text2b(const T &str) { text<2>(str); }
|
||||
void text2b(const T& str)
|
||||
{
|
||||
text<2>(str);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void text4b(const T &str) { text<4>(str); }
|
||||
void text4b(const T& str)
|
||||
{
|
||||
text<4>(str);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container1b(T &&obj, size_t maxSize) { container<1>(std::forward<T>(obj), maxSize); }
|
||||
void container1b(T&& obj, size_t maxSize)
|
||||
{
|
||||
container<1>(std::forward<T>(obj), maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container2b(T &&obj, size_t maxSize) { container<2>(std::forward<T>(obj), maxSize); }
|
||||
void container2b(T&& obj, size_t maxSize)
|
||||
{
|
||||
container<2>(std::forward<T>(obj), maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container4b(T &&obj, size_t maxSize) { container<4>(std::forward<T>(obj), maxSize); }
|
||||
void container4b(T&& obj, size_t maxSize)
|
||||
{
|
||||
container<4>(std::forward<T>(obj), maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container8b(T &&obj, size_t maxSize) { container<8>(std::forward<T>(obj), maxSize); }
|
||||
void container8b(T&& obj, size_t maxSize)
|
||||
{
|
||||
container<8>(std::forward<T>(obj), maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container16b(T &&obj, size_t maxSize) { container<16>(std::forward<T>(obj), maxSize); }
|
||||
void container16b(T&& obj, size_t maxSize)
|
||||
{
|
||||
container<16>(std::forward<T>(obj), maxSize);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container1b(T &&obj) { container<1>(std::forward<T>(obj)); }
|
||||
void container1b(T&& obj)
|
||||
{
|
||||
container<1>(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container2b(T &&obj) { container<2>(std::forward<T>(obj)); }
|
||||
void container2b(T&& obj)
|
||||
{
|
||||
container<2>(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container4b(T &&obj) { container<4>(std::forward<T>(obj)); }
|
||||
void container4b(T&& obj)
|
||||
{
|
||||
container<4>(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container8b(T &&obj) { container<8>(std::forward<T>(obj)); }
|
||||
void container8b(T&& obj)
|
||||
{
|
||||
container<8>(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void container16b(T &&obj) { container<16>(std::forward<T>(obj)); }
|
||||
|
||||
void container16b(T&& obj)
|
||||
{
|
||||
container<16>(std::forward<T>(obj));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// process value types
|
||||
// false_type means that we must process all elements individually
|
||||
template<size_t VSIZE, typename It>
|
||||
void procContainer(It first, It last, std::false_type) {
|
||||
void procContainer(It first, It last, std::false_type)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
value<VSIZE>(*first);
|
||||
}
|
||||
@@ -315,17 +455,20 @@ namespace bitsery {
|
||||
// process value types
|
||||
// true_type means, that we can copy whole buffer
|
||||
template<size_t VSIZE, typename It>
|
||||
void procContainer(It first, It last, std::true_type) {
|
||||
void procContainer(It first, It last, std::true_type)
|
||||
{
|
||||
using TValue = typename std::decay<decltype(*first)>::type;
|
||||
using TIntegral = typename details::IntegralFromFundamental<TValue>::TValue;
|
||||
if (first != last)
|
||||
this->_adapter.template writeBuffer<VSIZE>(reinterpret_cast<const TIntegral*>(&(*first)),
|
||||
this->_adapter.template writeBuffer<VSIZE>(
|
||||
reinterpret_cast<const TIntegral*>(&(*first)),
|
||||
static_cast<size_t>(std::distance(first, last)));
|
||||
}
|
||||
|
||||
// process by calling functions
|
||||
template<typename It, typename Fnc>
|
||||
void procContainer(It first, It last, Fnc fnc) {
|
||||
void procContainer(It first, It last, Fnc fnc)
|
||||
{
|
||||
using TValue = typename std::decay<decltype(*first)>::type;
|
||||
for (; first != last; ++first) {
|
||||
fnc(*this, const_cast<TValue&>(*first));
|
||||
@@ -334,76 +477,89 @@ namespace bitsery {
|
||||
|
||||
// process text,
|
||||
template<size_t VSIZE, typename T>
|
||||
void procText(const T& str, size_t maxSize) {
|
||||
void procText(const T& str, size_t maxSize)
|
||||
{
|
||||
const size_t length = traits::TextTraits<T>::length(str);
|
||||
(void)maxSize; // unused in release
|
||||
assert((length + (traits::TextTraits<T>::addNUL ? 1u : 0u)) <= maxSize);
|
||||
details::writeSize(this->_adapter, length);
|
||||
auto begin = std::begin(str);
|
||||
using diff_t = typename std::iterator_traits<decltype(begin)>::difference_type;
|
||||
procContainer<VSIZE>(begin, std::next(begin, static_cast<diff_t>(length)), std::integral_constant<bool, traits::ContainerTraits<T>::isContiguous>{});
|
||||
using diff_t =
|
||||
typename std::iterator_traits<decltype(begin)>::difference_type;
|
||||
procContainer<VSIZE>(
|
||||
begin,
|
||||
std::next(begin, static_cast<diff_t>(length)),
|
||||
std::integral_constant<bool, traits::ContainerTraits<T>::isContiguous>{});
|
||||
}
|
||||
|
||||
// process object types
|
||||
template<typename It>
|
||||
void procContainer(It first, It last) {
|
||||
void procContainer(It first, It last)
|
||||
{
|
||||
for (; first != last; ++first)
|
||||
object(*first);
|
||||
}
|
||||
|
||||
// proc bool writing bit or byte, depending on if BitPackingEnabled or not
|
||||
void procBoolValue(bool v, std::true_type) {
|
||||
void procBoolValue(bool v, std::true_type)
|
||||
{
|
||||
this->_adapter.writeBits(static_cast<unsigned char>(v ? 1 : 0), 1);
|
||||
}
|
||||
|
||||
void procBoolValue(bool v, std::false_type) {
|
||||
this->_adapter.template writeBytes<1>(static_cast<unsigned char>(v ? 1 : 0));
|
||||
void procBoolValue(bool v, std::false_type)
|
||||
{
|
||||
this->_adapter.template writeBytes<1>(
|
||||
static_cast<unsigned char>(v ? 1 : 0));
|
||||
}
|
||||
|
||||
// enable bit-packing or do nothing if it is already enabled
|
||||
template<typename Fnc, typename HasContext>
|
||||
void procEnableBitPacking(const Fnc& fnc, std::true_type, HasContext) {
|
||||
void procEnableBitPacking(const Fnc& fnc, std::true_type, HasContext)
|
||||
{
|
||||
fnc(*this);
|
||||
}
|
||||
|
||||
template<typename Fnc>
|
||||
void procEnableBitPacking(const Fnc& fnc, std::false_type, std::true_type) {
|
||||
void procEnableBitPacking(const Fnc& fnc, std::false_type, std::true_type)
|
||||
{
|
||||
BPEnabledType ser{ this->_context, this->_adapter };
|
||||
fnc(ser);
|
||||
}
|
||||
|
||||
template<typename Fnc>
|
||||
void procEnableBitPacking(const Fnc& fnc, std::false_type, std::false_type) {
|
||||
void procEnableBitPacking(const Fnc& fnc, std::false_type, std::false_type)
|
||||
{
|
||||
BPEnabledType ser{ this->_adapter };
|
||||
fnc(ser);
|
||||
}
|
||||
|
||||
// these are dummy functions for extensions that have TValue = void
|
||||
void object(const details::DummyType&) {
|
||||
|
||||
}
|
||||
void object(const details::DummyType&) {}
|
||||
|
||||
template<size_t VSIZE>
|
||||
void value(const details::DummyType&) {
|
||||
|
||||
void value(const details::DummyType&)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename T, typename... TArgs>
|
||||
void archive(T &&head, TArgs &&... tail) {
|
||||
void archive(T&& head, TArgs&&... tail)
|
||||
{
|
||||
// serialize object
|
||||
details::BriefSyntaxFunction<Serializer, T>::invoke(*this, std::forward<T>(head));
|
||||
details::BriefSyntaxFunction<Serializer, T>::invoke(*this,
|
||||
std::forward<T>(head));
|
||||
// expand other elements
|
||||
archive(std::forward<TArgs>(tail)...);
|
||||
}
|
||||
// dummy function, that stops archive variadic arguments expansion
|
||||
void archive() {
|
||||
}
|
||||
|
||||
void archive() {}
|
||||
};
|
||||
|
||||
//helper function that set ups all the basic steps and after serialziation returns serialized bytes count
|
||||
// helper function that set ups all the basic steps and after serialziation
|
||||
// returns serialized bytes count
|
||||
template<typename OutputAdapter, typename T>
|
||||
size_t quickSerialization(OutputAdapter adapter, const T& value) {
|
||||
size_t
|
||||
quickSerialization(OutputAdapter adapter, const T& value)
|
||||
{
|
||||
Serializer<OutputAdapter> ser{ std::move(adapter) };
|
||||
ser.object(value);
|
||||
ser.adapter().flush();
|
||||
@@ -411,7 +567,9 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename Context, typename OutputAdapter, typename T>
|
||||
size_t quickSerialization(Context& ctx, OutputAdapter adapter, const T& value) {
|
||||
size_t
|
||||
quickSerialization(Context& ctx, OutputAdapter adapter, const T& value)
|
||||
{
|
||||
Serializer<OutputAdapter, Context> ser{ ctx, std::move(adapter) };
|
||||
ser.object(value);
|
||||
ser.adapter().flush();
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// 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
|
||||
|
||||
@@ -32,11 +31,15 @@ namespace bitsery {
|
||||
namespace traits {
|
||||
template<typename T, size_t N>
|
||||
struct ContainerTraits<std::array<T, N>>
|
||||
:public StdContainer<std::array<T, N>, false, true> {};
|
||||
: public StdContainer<std::array<T, N>, false, true>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
struct BufferAdapterTraits<std::array<T, N>>
|
||||
:public StdContainerForBufferAdapter<std::array<T, N>> {};
|
||||
: public StdContainerForBufferAdapter<std::array<T, N>>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -23,8 +23,8 @@
|
||||
#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 {
|
||||
@@ -34,47 +34,51 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T, bool Resizable, bool Contiguous>
|
||||
struct StdContainer {
|
||||
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();
|
||||
}
|
||||
static size_t size(const T& container) { return container.size(); }
|
||||
};
|
||||
|
||||
// specialization for resizable
|
||||
template<typename T, bool Contiguous>
|
||||
struct StdContainer<T, true, Contiguous> {
|
||||
struct StdContainer<T, true, Contiguous>
|
||||
{
|
||||
using TValue = typename T::value_type;
|
||||
static constexpr bool isResizable = true;
|
||||
static constexpr bool isContiguous = Contiguous;
|
||||
static size_t size(const T& container) {
|
||||
return container.size();
|
||||
}
|
||||
static void resize(T& container, size_t size) {
|
||||
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;
|
||||
|
||||
static void resizeImpl(T& container, size_t size, std::true_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) {
|
||||
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));
|
||||
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 {
|
||||
struct StdContainerForBufferAdapter
|
||||
{
|
||||
using TIterator = typename T::iterator;
|
||||
using TConstIterator = typename T::const_iterator;
|
||||
using TValue = typename ContainerTraits<T>::TValue;
|
||||
@@ -82,19 +86,25 @@ namespace bitsery {
|
||||
|
||||
// specialization for resizable buffers
|
||||
template<typename T>
|
||||
struct StdContainerForBufferAdapter<T, true> {
|
||||
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;
|
||||
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()));
|
||||
container.resize(
|
||||
(std::max)(newSize > minSize ? newSize : minSize, container.capacity()));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -23,8 +23,8 @@
|
||||
#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 {
|
||||
@@ -35,11 +35,13 @@ namespace bitsery {
|
||||
|
||||
// traits for extension
|
||||
template<typename Extension, typename T>
|
||||
struct ExtensionTraits {
|
||||
struct ExtensionTraits
|
||||
{
|
||||
// this type is used, when using extesion without custom lambda
|
||||
// eg.: extension4b>(obj, myextension{}) will call s.value4b(obj) for TValue
|
||||
// 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.
|
||||
// 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
|
||||
@@ -52,47 +54,53 @@ namespace bitsery {
|
||||
|
||||
// primary traits for containers
|
||||
template<typename T>
|
||||
struct ContainerTraits {
|
||||
struct ContainerTraits
|
||||
{
|
||||
|
||||
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
|
||||
// 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 void resize(T&, size_t)
|
||||
{
|
||||
static_assert(std::is_void<T>::value,
|
||||
"Define ContainerTraits or include from <bitsery/traits/...> to use as container");
|
||||
"Define ContainerTraits or include from <bitsery/traits/...> "
|
||||
"to use as container");
|
||||
}
|
||||
// get container size
|
||||
static size_t size(const T& ) {
|
||||
static size_t size(const T&)
|
||||
{
|
||||
static_assert(std::is_void<T>::value,
|
||||
"Define ContainerTraits or include from <bitsery/traits/...> to use as container");
|
||||
"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]> {
|
||||
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;
|
||||
}
|
||||
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>> {
|
||||
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) {
|
||||
static size_t size(const std::initializer_list<T>& container)
|
||||
{
|
||||
return container.size();
|
||||
}
|
||||
};
|
||||
@@ -100,39 +108,46 @@ namespace bitsery {
|
||||
// specialization for pointer type buffer
|
||||
// only deserializer can use it
|
||||
template<typename T>
|
||||
struct ContainerTraits<const 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*");
|
||||
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*> {
|
||||
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*");
|
||||
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 {
|
||||
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,
|
||||
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;
|
||||
}
|
||||
@@ -140,7 +155,8 @@ namespace bitsery {
|
||||
|
||||
// traits only for buffer adapters
|
||||
template<typename T>
|
||||
struct BufferAdapterTraits {
|
||||
struct BufferAdapterTraits
|
||||
{
|
||||
using TIterator = details::NotDefinedType;
|
||||
using TConstIterator = details::NotDefinedType;
|
||||
using TValue = typename ContainerTraits<T>::TValue;
|
||||
@@ -152,16 +168,18 @@ namespace bitsery {
|
||||
// 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 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");
|
||||
"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]> {
|
||||
struct BufferAdapterTraits<T[N]>
|
||||
{
|
||||
using TIterator = T*;
|
||||
using TConstIterator = const T*;
|
||||
using TValue = T;
|
||||
@@ -169,14 +187,16 @@ namespace bitsery {
|
||||
|
||||
// specialization for pointer type buffer
|
||||
template<typename T>
|
||||
struct BufferAdapterTraits<const T*> {
|
||||
struct BufferAdapterTraits<const T*>
|
||||
{
|
||||
using TIterator = const T*;
|
||||
using TConstIterator = const T*;
|
||||
using TValue = T;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct BufferAdapterTraits<T*> {
|
||||
struct BufferAdapterTraits<T*>
|
||||
{
|
||||
using TIterator = T*;
|
||||
using TConstIterator = const T*;
|
||||
using TValue = T;
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// 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
|
||||
|
||||
@@ -33,7 +32,9 @@ namespace bitsery {
|
||||
|
||||
template<typename T, typename Allocator>
|
||||
struct ContainerTraits<std::deque<T, Allocator>>
|
||||
: public StdContainer<std::deque<T, Allocator>, true, false> {};
|
||||
: public StdContainer<std::deque<T, Allocator>, true, false>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,12 +20,11 @@
|
||||
// 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 {
|
||||
@@ -33,22 +32,33 @@ namespace bitsery {
|
||||
namespace traits {
|
||||
|
||||
template<typename T, typename Allocator>
|
||||
struct ContainerTraits<std::forward_list<T, Allocator>> {
|
||||
struct ContainerTraits<std::forward_list<T, Allocator>>
|
||||
{
|
||||
using TValue = T;
|
||||
static constexpr bool isResizable = true;
|
||||
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 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) {
|
||||
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) {
|
||||
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) {
|
||||
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>());
|
||||
@@ -56,7 +66,8 @@ namespace bitsery {
|
||||
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)));
|
||||
container.erase_after(
|
||||
std::next(std::begin(container), static_cast<diff_t>(newSize - 1)));
|
||||
else
|
||||
container.clear();
|
||||
}
|
||||
@@ -65,5 +76,4 @@ namespace bitsery {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // BITSERY_TRAITS_STD_FORWARD_LIST_H
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// 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
|
||||
|
||||
@@ -33,7 +32,9 @@ namespace bitsery {
|
||||
|
||||
template<typename T, typename Allocator>
|
||||
struct ContainerTraits<std::list<T, Allocator>>
|
||||
: public StdContainer<std::list<T, Allocator>, true, false> {};
|
||||
: public StdContainer<std::list<T, Allocator>, true, false>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// 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
|
||||
|
||||
@@ -31,38 +30,50 @@ namespace bitsery {
|
||||
|
||||
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> {};
|
||||
: 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;
|
||||
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) {
|
||||
// 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]> {
|
||||
struct TextTraits<T[N]>
|
||||
{
|
||||
using TValue = T;
|
||||
static constexpr bool addNUL = true;
|
||||
|
||||
static size_t length(const T (&container)[N]) {
|
||||
static size_t length(const T (&container)[N])
|
||||
{
|
||||
return std::char_traits<T>::length(container);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename CharT, typename Traits, typename Allocator>
|
||||
struct BufferAdapterTraits<std::basic_string<CharT, Traits, Allocator>>
|
||||
:public StdContainerForBufferAdapter<std::basic_string<CharT, Traits, Allocator>> {};
|
||||
: public StdContainerForBufferAdapter<
|
||||
std::basic_string<CharT, Traits, Allocator>>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,7 +20,6 @@
|
||||
// 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
|
||||
|
||||
@@ -32,16 +31,22 @@ namespace bitsery {
|
||||
namespace traits {
|
||||
template<typename T, typename Allocator>
|
||||
struct ContainerTraits<std::vector<T, Allocator>>
|
||||
:public StdContainer<std::vector<T, Allocator>, true, true> {};
|
||||
: public StdContainer<std::vector<T, Allocator>, true, true>
|
||||
{
|
||||
};
|
||||
|
||||
// bool vector is not contiguous, do not copy it directly to buffer
|
||||
template<typename Allocator>
|
||||
struct ContainerTraits<std::vector<bool, Allocator>>
|
||||
:public StdContainer<std::vector<bool, Allocator>, true, false> {};
|
||||
: public StdContainer<std::vector<bool, Allocator>, true, false>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename T, typename Allocator>
|
||||
struct BufferAdapterTraits<std::vector<T, Allocator>>
|
||||
:public StdContainerForBufferAdapter<std::vector<T, Allocator>> {};
|
||||
: public StdContainerForBufferAdapter<std::vector<T, Allocator>>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,16 +20,15 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
|
||||
#include <bitsery/adapter/buffer.h>
|
||||
#include <bitsery/adapter/stream.h>
|
||||
#include <bitsery/adapter/measure_size.h>
|
||||
#include <bitsery/adapter/stream.h>
|
||||
#include <bitsery/deserializer.h>
|
||||
#include <bitsery/traits/vector.h>
|
||||
#include <bitsery/traits/array.h>
|
||||
#include <bitsery/traits/string.h>
|
||||
#include <bitsery/ext/value_range.h>
|
||||
#include <bitsery/serializer.h>
|
||||
#include <bitsery/traits/array.h>
|
||||
#include <bitsery/traits/string.h>
|
||||
#include <bitsery/traits/vector.h>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
@@ -43,13 +42,16 @@ using bitsery::ReaderError;
|
||||
using testing::Eq;
|
||||
using testing::Ge;
|
||||
|
||||
struct DisableAdapterErrorsConfig {
|
||||
static constexpr bitsery::EndiannessType Endianness = bitsery::DefaultConfig::Endianness;
|
||||
struct DisableAdapterErrorsConfig
|
||||
{
|
||||
static constexpr bitsery::EndiannessType Endianness =
|
||||
bitsery::DefaultConfig::Endianness;
|
||||
static constexpr bool CheckAdapterErrors = false;
|
||||
static constexpr bool CheckDataErrors = true;
|
||||
};
|
||||
|
||||
TEST(OutputBuffer, WhenSetWritePositionThenResizeUnderlyingBufferIfRequired) {
|
||||
TEST(OutputBuffer, WhenSetWritePositionThenResizeUnderlyingBufferIfRequired)
|
||||
{
|
||||
// setup data
|
||||
Buffer buf{};
|
||||
OutputAdapter w{ buf };
|
||||
@@ -61,7 +63,10 @@ TEST(OutputBuffer, WhenSetWritePositionThenResizeUnderlyingBufferIfRequired) {
|
||||
EXPECT_THAT(buf.size(), Ge(initialSize + 10));
|
||||
}
|
||||
|
||||
TEST(OutputBuffer, WhenSettingCurrentPositionBeforeBufferEndThenWrittenBytesCountIsNotAffected) {
|
||||
TEST(
|
||||
OutputBuffer,
|
||||
WhenSettingCurrentPositionBeforeBufferEndThenWrittenBytesCountIsNotAffected)
|
||||
{
|
||||
// setup data
|
||||
Buffer buf{};
|
||||
OutputAdapter w{ buf };
|
||||
@@ -75,7 +80,8 @@ TEST(OutputBuffer, WhenSettingCurrentPositionBeforeBufferEndThenWrittenBytesCoun
|
||||
EXPECT_THAT(w.writtenBytesCount(), Eq(initialSize + 10 + 8));
|
||||
}
|
||||
|
||||
TEST(OutputBuffer, CanWorkWithFixedSizeBuffer) {
|
||||
TEST(OutputBuffer, CanWorkWithFixedSizeBuffer)
|
||||
{
|
||||
// setup data
|
||||
std::array<uint8_t, 10> buf{};
|
||||
bitsery::OutputBufferAdapter<std::array<uint8_t, 10>> w{ buf };
|
||||
@@ -86,7 +92,8 @@ TEST(OutputBuffer, CanWorkWithFixedSizeBuffer) {
|
||||
EXPECT_THAT(w.currentWritePos(), Eq(5));
|
||||
}
|
||||
|
||||
TEST(InputBuffer, CorrectlySetsAndGetsCurrentReadPosition) {
|
||||
TEST(InputBuffer, CorrectlySetsAndGetsCurrentReadPosition)
|
||||
{
|
||||
|
||||
Buffer buf{};
|
||||
buf.resize(100);
|
||||
@@ -100,8 +107,8 @@ TEST(InputBuffer, CorrectlySetsAndGetsCurrentReadPosition) {
|
||||
EXPECT_THAT(r.currentReadPos(), Eq(1));
|
||||
}
|
||||
|
||||
|
||||
TEST(InputBuffer, WhenSetReadPositionOutOfRangeThenDataOverflow) {
|
||||
TEST(InputBuffer, WhenSetReadPositionOutOfRangeThenDataOverflow)
|
||||
{
|
||||
|
||||
Buffer buf{};
|
||||
buf.resize(100);
|
||||
@@ -112,7 +119,8 @@ TEST(InputBuffer, WhenSetReadPositionOutOfRangeThenDataOverflow) {
|
||||
EXPECT_THAT(r.error(), Eq(ReaderError::DataOverflow));
|
||||
}
|
||||
|
||||
TEST(InputBuffer, WhenSetReadEndPositionOutOfRangeThenDataOverflow) {
|
||||
TEST(InputBuffer, WhenSetReadEndPositionOutOfRangeThenDataOverflow)
|
||||
{
|
||||
Buffer buf{};
|
||||
buf.resize(100);
|
||||
InputAdapter r{ buf.begin(), 10 };
|
||||
@@ -120,7 +128,8 @@ TEST(InputBuffer, WhenSetReadEndPositionOutOfRangeThenDataOverflow) {
|
||||
EXPECT_THAT(r.error(), Eq(ReaderError::DataOverflow));
|
||||
}
|
||||
|
||||
TEST(InputBuffer, WhenReadEndPositionIsNotSetThenReturnZeroAsBufferEndPosition) {
|
||||
TEST(InputBuffer, WhenReadEndPositionIsNotSetThenReturnZeroAsBufferEndPosition)
|
||||
{
|
||||
Buffer buf{};
|
||||
buf.resize(100);
|
||||
InputAdapter r{ buf.begin(), 10 };
|
||||
@@ -130,8 +139,9 @@ TEST(InputBuffer, WhenReadEndPositionIsNotSetThenReturnZeroAsBufferEndPosition)
|
||||
EXPECT_THAT(r.error(), Eq(ReaderError::NoError));
|
||||
}
|
||||
|
||||
|
||||
TEST(InputBuffer, WhenReadEndPositionIsNotZeroThenDataOverflowErrorWillBeIgnored) {
|
||||
TEST(InputBuffer,
|
||||
WhenReadEndPositionIsNotZeroThenDataOverflowErrorWillBeIgnored)
|
||||
{
|
||||
Buffer buf{};
|
||||
buf.resize(100);
|
||||
InputAdapter r{ buf.begin(), 1 };
|
||||
@@ -146,8 +156,9 @@ TEST(InputBuffer, WhenReadEndPositionIsNotZeroThenDataOverflowErrorWillBeIgnored
|
||||
EXPECT_THAT(r.error(), Eq(ReaderError::DataOverflow));
|
||||
}
|
||||
|
||||
|
||||
TEST(InputBuffer, WhenReadingPastReadEndPositionOrBufferEndThenReadPositionDoesntChange) {
|
||||
TEST(InputBuffer,
|
||||
WhenReadingPastReadEndPositionOrBufferEndThenReadPositionDoesntChange)
|
||||
{
|
||||
Buffer buf{};
|
||||
buf.resize(10);
|
||||
InputAdapter r{ buf.begin(), 3 };
|
||||
@@ -164,7 +175,10 @@ TEST(InputBuffer, WhenReadingPastReadEndPositionOrBufferEndThenReadPositionDoesn
|
||||
EXPECT_THAT(tmp, Eq(0));
|
||||
}
|
||||
|
||||
TEST(InputBuffer, WhenReaderHasErrorsThenSettingReadPosAndReadEndPosIsIgnoredAndGettingAlwaysReturnsZero) {
|
||||
TEST(
|
||||
InputBuffer,
|
||||
WhenReaderHasErrorsThenSettingReadPosAndReadEndPosIsIgnoredAndGettingAlwaysReturnsZero)
|
||||
{
|
||||
Buffer buf{};
|
||||
buf.resize(10);
|
||||
InputAdapter r{ buf.begin(), 10 };
|
||||
@@ -184,7 +198,8 @@ TEST(InputBuffer, WhenReaderHasErrorsThenSettingReadPosAndReadEndPosIsIgnoredAnd
|
||||
EXPECT_THAT(r.currentReadEndPos(), Eq(0));
|
||||
}
|
||||
|
||||
TEST(InputBuffer, ConstDataForBufferAllAdapters) {
|
||||
TEST(InputBuffer, ConstDataForBufferAllAdapters)
|
||||
{
|
||||
// create and write to buffer
|
||||
uint16_t data = 7549;
|
||||
Buffer bufWrite{};
|
||||
@@ -203,7 +218,9 @@ TEST(InputBuffer, ConstDataForBufferAllAdapters) {
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
TEST(InputBuffer, WhenAdapterErrorsIsDisabledThenCanChangeAnyReadPositionAndReadsAsserts) {
|
||||
TEST(InputBuffer,
|
||||
WhenAdapterErrorsIsDisabledThenCanChangeAnyReadPositionAndReadsAsserts)
|
||||
{
|
||||
// create and write to buffer
|
||||
uint64_t data = 0x1122334455667788;
|
||||
Buffer buf{};
|
||||
@@ -211,7 +228,9 @@ TEST(InputBuffer, WhenAdapterErrorsIsDisabledThenCanChangeAnyReadPositionAndRead
|
||||
bw.writeBytes<8>(data);
|
||||
bw.flush();
|
||||
|
||||
bitsery::InputBufferAdapter<Buffer, DisableAdapterErrorsConfig> r1{buf.begin(), 2};
|
||||
bitsery::InputBufferAdapter<Buffer, DisableAdapterErrorsConfig> r1{
|
||||
buf.begin(), 2
|
||||
};
|
||||
uint16_t res1{};
|
||||
r1.readBytes<2>(res1);
|
||||
EXPECT_THAT(res1, Eq(0x7788)); // default config is little endian
|
||||
@@ -222,7 +241,10 @@ TEST(InputBuffer, WhenAdapterErrorsIsDisabledThenCanChangeAnyReadPositionAndRead
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(InputStream, WhenAdapterErrorsIsDisabledThenReadingPastEndDoesntSetErrorAndDoesntReturnZero) {
|
||||
TEST(
|
||||
InputStream,
|
||||
WhenAdapterErrorsIsDisabledThenReadingPastEndDoesntSetErrorAndDoesntReturnZero)
|
||||
{
|
||||
// create and write to buffer
|
||||
std::stringstream ss{};
|
||||
bitsery::OutputStreamAdapter bw{ ss };
|
||||
@@ -230,7 +252,10 @@ TEST(InputStream, WhenAdapterErrorsIsDisabledThenReadingPastEndDoesntSetErrorAnd
|
||||
bw.writeBytes<4>(data);
|
||||
bw.flush();
|
||||
|
||||
bitsery::BasicInputStreamAdapter<char, DisableAdapterErrorsConfig, std::char_traits<char>> br{ss};
|
||||
bitsery::BasicInputStreamAdapter<char,
|
||||
DisableAdapterErrorsConfig,
|
||||
std::char_traits<char>>
|
||||
br{ ss };
|
||||
uint32_t res{};
|
||||
br.readBytes<4>(res);
|
||||
EXPECT_THAT(res, Eq(data));
|
||||
@@ -240,24 +265,28 @@ TEST(InputStream, WhenAdapterErrorsIsDisabledThenReadingPastEndDoesntSetErrorAnd
|
||||
}
|
||||
|
||||
template<template<typename...> class TAdapter>
|
||||
struct InBufferConfig {
|
||||
struct InBufferConfig
|
||||
{
|
||||
using Data = std::vector<char>;
|
||||
using Adapter = TAdapter<Data>;
|
||||
|
||||
Data data{};
|
||||
Adapter createReader(const std::vector<char>& buffer) {
|
||||
Adapter createReader(const std::vector<char>& buffer)
|
||||
{
|
||||
data = buffer;
|
||||
return Adapter{ data.begin(), data.size() };
|
||||
}
|
||||
};
|
||||
|
||||
template<typename TAdapter>
|
||||
struct InStreamConfig {
|
||||
struct InStreamConfig
|
||||
{
|
||||
using Data = std::stringstream;
|
||||
using Adapter = TAdapter;
|
||||
|
||||
Data data{};
|
||||
Adapter createReader(const std::vector<char>& buffer) {
|
||||
Adapter createReader(const std::vector<char>& buffer)
|
||||
{
|
||||
std::string str(buffer.begin(), buffer.end());
|
||||
data = std::stringstream{ str };
|
||||
return Adapter{ data };
|
||||
@@ -265,25 +294,25 @@ struct InStreamConfig {
|
||||
};
|
||||
|
||||
template<typename TAdapterWithData>
|
||||
class AdapterConfig : public testing::Test {
|
||||
class AdapterConfig : public testing::Test
|
||||
{
|
||||
public:
|
||||
|
||||
TAdapterWithData config{};
|
||||
};
|
||||
|
||||
using AdapterInputTypes = ::testing::Types<
|
||||
InBufferConfig<bitsery::InputBufferAdapter>,
|
||||
InStreamConfig<bitsery::InputStreamAdapter>
|
||||
>;
|
||||
using AdapterInputTypes =
|
||||
::testing::Types<InBufferConfig<bitsery::InputBufferAdapter>,
|
||||
InStreamConfig<bitsery::InputStreamAdapter>>;
|
||||
|
||||
template<typename TConfig>
|
||||
class InputAll: public AdapterConfig<TConfig> {
|
||||
class InputAll : public AdapterConfig<TConfig>
|
||||
{
|
||||
};
|
||||
|
||||
TYPED_TEST_SUITE(InputAll, AdapterInputTypes, );
|
||||
|
||||
|
||||
TYPED_TEST(InputAll, SettingMultipleErrorsAlwaysReturnsFirstError) {
|
||||
TYPED_TEST(InputAll, SettingMultipleErrorsAlwaysReturnsFirstError)
|
||||
{
|
||||
auto r = this->config.createReader({ 0, 0, 0, 0 });
|
||||
EXPECT_THAT(r.error(), Eq(ReaderError::NoError));
|
||||
r.error(ReaderError::InvalidPointer);
|
||||
@@ -294,7 +323,8 @@ TYPED_TEST(InputAll, SettingMultipleErrorsAlwaysReturnsFirstError) {
|
||||
EXPECT_THAT(r.error(), Eq(ReaderError::InvalidPointer));
|
||||
}
|
||||
|
||||
TYPED_TEST(InputAll, CanBeMoveConstructedAndMoveAssigned) {
|
||||
TYPED_TEST(InputAll, CanBeMoveConstructedAndMoveAssigned)
|
||||
{
|
||||
auto r = this->config.createReader({ 1, 2, 3 });
|
||||
uint8_t res{};
|
||||
r.template readBytes<1>(res);
|
||||
@@ -309,8 +339,8 @@ TYPED_TEST(InputAll, CanBeMoveConstructedAndMoveAssigned) {
|
||||
EXPECT_THAT(res, Eq(3));
|
||||
}
|
||||
|
||||
|
||||
TYPED_TEST(InputAll, WhenAlignHasNonZerosThenInvalidDataError) {
|
||||
TYPED_TEST(InputAll, WhenAlignHasNonZerosThenInvalidDataError)
|
||||
{
|
||||
|
||||
auto r = this->config.createReader({ 0x7F });
|
||||
bitsery::details::InputAdapterBitPackingWrapper<decltype(r)> bpr{ r };
|
||||
@@ -321,8 +351,9 @@ TYPED_TEST(InputAll, WhenAlignHasNonZerosThenInvalidDataError) {
|
||||
EXPECT_THAT(bpr.error(), Eq(ReaderError::InvalidData));
|
||||
}
|
||||
|
||||
|
||||
TYPED_TEST(InputAll, WhenAllBytesAreReadWithoutErrorsThenIsCompletedSuccessfully) {
|
||||
TYPED_TEST(InputAll,
|
||||
WhenAllBytesAreReadWithoutErrorsThenIsCompletedSuccessfully)
|
||||
{
|
||||
// setup data
|
||||
|
||||
uint32_t tb = 94545646;
|
||||
@@ -359,8 +390,8 @@ TYPED_TEST(InputAll, WhenAllBytesAreReadWithoutErrorsThenIsCompletedSuccessfully
|
||||
EXPECT_THAT(rd, Eq(td));
|
||||
}
|
||||
|
||||
|
||||
TYPED_TEST(InputAll, WhenReadingMoreThanAvailableThenDataOverflow) {
|
||||
TYPED_TEST(InputAll, WhenReadingMoreThanAvailableThenDataOverflow)
|
||||
{
|
||||
// setup data
|
||||
uint8_t t1 = 111;
|
||||
|
||||
@@ -384,10 +415,10 @@ TYPED_TEST(InputAll, WhenReadingMoreThanAvailableThenDataOverflow) {
|
||||
EXPECT_THAT(r1, Eq(0));
|
||||
EXPECT_THAT(r.isCompletedSuccessfully(), Eq(false));
|
||||
EXPECT_THAT(r.error(), Eq(ReaderError::DataOverflow));
|
||||
|
||||
}
|
||||
|
||||
TYPED_TEST(InputAll, WhenReaderHasErrorsAllThenReadsReturnZero) {
|
||||
TYPED_TEST(InputAll, WhenReaderHasErrorsAllThenReadsReturnZero)
|
||||
{
|
||||
// setup data
|
||||
uint8_t t1 = 111;
|
||||
|
||||
@@ -408,50 +439,50 @@ TYPED_TEST(InputAll, WhenReaderHasErrorsAllThenReadsReturnZero) {
|
||||
EXPECT_THAT(r1, Eq(0));
|
||||
}
|
||||
|
||||
|
||||
template<template<typename...> class TAdapter>
|
||||
struct OutBufferConfig {
|
||||
struct OutBufferConfig
|
||||
{
|
||||
using Data = std::vector<char>;
|
||||
using Adapter = TAdapter<Data>;
|
||||
|
||||
Data data{};
|
||||
Adapter createWriter() {
|
||||
return Adapter{data};
|
||||
}
|
||||
Adapter createWriter() { return Adapter{ data }; }
|
||||
|
||||
bitsery::InputBufferAdapter<Data> getReader() {
|
||||
bitsery::InputBufferAdapter<Data> getReader()
|
||||
{
|
||||
return bitsery::InputBufferAdapter<Data>{ data.begin(), data.end() };
|
||||
}
|
||||
};
|
||||
|
||||
template<typename TAdapter>
|
||||
struct OutStreamConfig {
|
||||
struct OutStreamConfig
|
||||
{
|
||||
using Data = std::stringstream;
|
||||
using Adapter = TAdapter;
|
||||
|
||||
Data data{};
|
||||
Adapter createWriter() {
|
||||
return Adapter{data};
|
||||
}
|
||||
Adapter createWriter() { return Adapter{ data }; }
|
||||
|
||||
bitsery::InputStreamAdapter getReader() {
|
||||
bitsery::InputStreamAdapter getReader()
|
||||
{
|
||||
return bitsery::InputStreamAdapter{ data };
|
||||
}
|
||||
};
|
||||
|
||||
using AdapterOutputTypes = ::testing::Types<
|
||||
OutBufferConfig<bitsery::OutputBufferAdapter>,
|
||||
using AdapterOutputTypes =
|
||||
::testing::Types<OutBufferConfig<bitsery::OutputBufferAdapter>,
|
||||
OutStreamConfig<bitsery::OutputStreamAdapter>,
|
||||
OutStreamConfig<bitsery::OutputBufferedStreamAdapter>
|
||||
>;
|
||||
OutStreamConfig<bitsery::OutputBufferedStreamAdapter>>;
|
||||
|
||||
template<typename TConfig>
|
||||
class OutputAll: public AdapterConfig<TConfig> {
|
||||
class OutputAll : public AdapterConfig<TConfig>
|
||||
{
|
||||
};
|
||||
|
||||
TYPED_TEST_SUITE(OutputAll, AdapterOutputTypes, );
|
||||
|
||||
TYPED_TEST(OutputAll, CanBeMoveConstructedAndMoveAssigned) {
|
||||
TYPED_TEST(OutputAll, CanBeMoveConstructedAndMoveAssigned)
|
||||
{
|
||||
auto w = this->config.createWriter();
|
||||
uint8_t data{ 1 };
|
||||
w.template writeBytes<1>(data);
|
||||
@@ -474,12 +505,16 @@ TYPED_TEST(OutputAll, CanBeMoveConstructedAndMoveAssigned) {
|
||||
EXPECT_THAT(data, Eq(3));
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
class OutputStreamBuffered : public testing::Test {
|
||||
class OutputStreamBuffered : public testing::Test
|
||||
{
|
||||
public:
|
||||
using Buffer = T;
|
||||
using Adapter = bitsery::BasicBufferedOutputStreamAdapter<char, bitsery::DefaultConfig, std::char_traits<char>, Buffer>;
|
||||
using Adapter =
|
||||
bitsery::BasicBufferedOutputStreamAdapter<char,
|
||||
bitsery::DefaultConfig,
|
||||
std::char_traits<char>,
|
||||
Buffer>;
|
||||
|
||||
static constexpr size_t InternalBufferSize = 128;
|
||||
|
||||
@@ -488,24 +523,25 @@ public:
|
||||
Adapter writer{ stream, 128 };
|
||||
};
|
||||
|
||||
using BufferedAdapterInternalBufferTypes = ::testing::Types<
|
||||
std::vector<char>,
|
||||
std::array<char, 128>,
|
||||
std::string
|
||||
>;
|
||||
using BufferedAdapterInternalBufferTypes =
|
||||
::testing::Types<std::vector<char>, std::array<char, 128>, std::string>;
|
||||
|
||||
TYPED_TEST_SUITE(OutputStreamBuffered, BufferedAdapterInternalBufferTypes, );
|
||||
|
||||
TYPED_TEST(OutputStreamBuffered, WhenInternalBufferIsFullThenWriteBufferAndValueToStream) {
|
||||
TYPED_TEST(OutputStreamBuffered,
|
||||
WhenInternalBufferIsFullThenWriteBufferAndValueToStream)
|
||||
{
|
||||
uint8_t x{};
|
||||
for (auto i = 0u; i < TestFixture::InternalBufferSize; ++i)
|
||||
this->writer.template writeBytes<1>(x);
|
||||
EXPECT_TRUE(this->stream.str().empty());
|
||||
this->writer.template writeBytes<1>(x);
|
||||
EXPECT_THAT(this->stream.str().size(), Eq(TestFixture::InternalBufferSize + 1));
|
||||
EXPECT_THAT(this->stream.str().size(),
|
||||
Eq(TestFixture::InternalBufferSize + 1));
|
||||
}
|
||||
|
||||
TYPED_TEST(OutputStreamBuffered, WhenFlushThenWriteImmediately) {
|
||||
TYPED_TEST(OutputStreamBuffered, WhenFlushThenWriteImmediately)
|
||||
{
|
||||
uint8_t x{};
|
||||
this->writer.template writeBytes<1>(x);
|
||||
EXPECT_THAT(this->stream.str().size(), Eq(0));
|
||||
@@ -515,16 +551,21 @@ TYPED_TEST(OutputStreamBuffered, WhenFlushThenWriteImmediately) {
|
||||
EXPECT_THAT(this->stream.str().size(), Eq(1));
|
||||
}
|
||||
|
||||
TYPED_TEST(OutputStreamBuffered, WhenBufferIsStackAllocatedThenBufferSizeViaCtorHasNoEffect) {
|
||||
TYPED_TEST(OutputStreamBuffered,
|
||||
WhenBufferIsStackAllocatedThenBufferSizeViaCtorHasNoEffect)
|
||||
{
|
||||
|
||||
// create writer with half the internal buffer size
|
||||
//for std::vector it should overflow, and for std::array it should have no effect
|
||||
typename TestFixture::Adapter w{this->stream, TestFixture::InternalBufferSize / 2};
|
||||
// for std::vector it should overflow, and for std::array it should have no
|
||||
// effect
|
||||
typename TestFixture::Adapter w{ this->stream,
|
||||
TestFixture::InternalBufferSize / 2 };
|
||||
|
||||
uint8_t x{};
|
||||
for (auto i = 0u; i < TestFixture::InternalBufferSize; ++i)
|
||||
w.template writeBytes<1>(x);
|
||||
static constexpr bool ShouldWriteToStream = bitsery::traits::ContainerTraits<typename TestFixture::Buffer>::isResizable;
|
||||
static constexpr bool ShouldWriteToStream =
|
||||
bitsery::traits::ContainerTraits<typename TestFixture::Buffer>::isResizable;
|
||||
EXPECT_THAT(this->stream.str().empty(), ::testing::Ne(ShouldWriteToStream));
|
||||
}
|
||||
|
||||
@@ -535,20 +576,21 @@ struct TestData
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S &s, TestData &o)
|
||||
void
|
||||
serialize(S& s, TestData& o)
|
||||
{
|
||||
s.value4b(o.b4);
|
||||
s.enableBitPacking([&o](typename S::BPEnabledType& sbp) {
|
||||
sbp.ext(o.b4, bitsery::ext::ValueRange<uint32_t>{ 0, 1023 }); // 10 bits
|
||||
sbp.value4b(o.b4);
|
||||
sbp.container(o.vb2, 10, [](typename S::BPEnabledType& sbp, uint16_t& data) {
|
||||
sbp.container(
|
||||
o.vb2, 10, [](typename S::BPEnabledType& sbp, uint16_t& data) {
|
||||
sbp.ext(data, bitsery::ext::ValueRange<uint16_t>{ 0, 200 }); // 7 bits
|
||||
});
|
||||
});
|
||||
s.container2b(o.vb2, 10);
|
||||
}
|
||||
|
||||
|
||||
TEST(AdapterWriterMeasureSize, CorrectlyMeasuresBytesAndBitsSize)
|
||||
{
|
||||
TestData data{ 456, { 45, 98, 189, 4 } };
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -40,20 +40,23 @@
|
||||
#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) {
|
||||
TEST(BriefSyntax, FundamentalTypesAndBool)
|
||||
{
|
||||
int ti = 8745;
|
||||
MyEnumClass te = MyEnumClass::E4;
|
||||
float tf = 485.042f;
|
||||
@@ -78,7 +81,8 @@ TEST(BriefSyntax, FundamentalTypesAndBool) {
|
||||
EXPECT_THAT(rb, Eq(tb));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, UseObjectFncInsteadOfValueN) {
|
||||
TEST(BriefSyntax, UseObjectFncInsteadOfValueN)
|
||||
{
|
||||
int ti = 8745;
|
||||
MyEnumClass te = MyEnumClass::E4;
|
||||
float tf = 485.042f;
|
||||
@@ -113,7 +117,8 @@ TEST(BriefSyntax, UseObjectFncInsteadOfValueN) {
|
||||
EXPECT_THAT(rb, Eq(tb));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, MixDifferentSyntax) {
|
||||
TEST(BriefSyntax, MixDifferentSyntax)
|
||||
{
|
||||
int ti = 8745;
|
||||
MyEnumClass te = MyEnumClass::E4;
|
||||
float tf = 485.042f;
|
||||
@@ -145,7 +150,9 @@ TEST(BriefSyntax, MixDifferentSyntax) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T procBriefSyntax(const T& testData) {
|
||||
T
|
||||
procBriefSyntax(const T& testData)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
ctx.createSerializer()(testData);
|
||||
T res{};
|
||||
@@ -154,7 +161,9 @@ T procBriefSyntax(const T& testData) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T&& procBriefSyntaxRvalue(T&& init_value, const T& testData) {
|
||||
T&&
|
||||
procBriefSyntaxRvalue(T&& init_value, const T& testData)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
ctx.createSerializer()(testData);
|
||||
ctx.createDeserializer()(init_value);
|
||||
@@ -162,7 +171,9 @@ T&& procBriefSyntaxRvalue(T&& init_value, const T& testData) {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T procBriefSyntaxWithMaxSize(const T& testData) {
|
||||
T
|
||||
procBriefSyntaxWithMaxSize(const T& testData)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
ctx.createSerializer()(bitsery::maxSize(testData, 100));
|
||||
T res{};
|
||||
@@ -170,7 +181,8 @@ T procBriefSyntaxWithMaxSize(const T& testData) {
|
||||
return res;
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, CStyleArrayForValueTypesAsContainer) {
|
||||
TEST(BriefSyntax, CStyleArrayForValueTypesAsContainer)
|
||||
{
|
||||
const int t1[3]{ 8748, -484, 45 };
|
||||
int r1[3]{ 0, 0, 0 };
|
||||
|
||||
@@ -181,7 +193,8 @@ TEST(BriefSyntax, CStyleArrayForValueTypesAsContainer) {
|
||||
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, CStyleArrayForIntegralTypesAsText) {
|
||||
TEST(BriefSyntax, CStyleArrayForIntegralTypesAsText)
|
||||
{
|
||||
const char t1[3]{ "hi" };
|
||||
char r1[3]{ 0, 0, 0 };
|
||||
|
||||
@@ -192,7 +205,8 @@ TEST(BriefSyntax, CStyleArrayForIntegralTypesAsText) {
|
||||
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, CStyleArray) {
|
||||
TEST(BriefSyntax, CStyleArray)
|
||||
{
|
||||
const MyEnumClass t1[3]{ MyEnumClass::E1, MyEnumClass::E4, MyEnumClass::E2 };
|
||||
MyEnumClass r1[3]{};
|
||||
|
||||
@@ -203,7 +217,8 @@ TEST(BriefSyntax, CStyleArray) {
|
||||
EXPECT_THAT(r1, ::testing::ContainerEq(t1));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdString) {
|
||||
TEST(BriefSyntax, StdString)
|
||||
{
|
||||
std::string t1{ "my nice string" };
|
||||
std::string t2{};
|
||||
|
||||
@@ -213,7 +228,8 @@ TEST(BriefSyntax, StdString) {
|
||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdArray) {
|
||||
TEST(BriefSyntax, StdArray)
|
||||
{
|
||||
std::array<int, 3> t1{ 8748, -484, 45 };
|
||||
std::array<int, 0> t2{};
|
||||
|
||||
@@ -221,7 +237,8 @@ TEST(BriefSyntax, StdArray) {
|
||||
EXPECT_THAT(procBriefSyntax(t2), Eq(t2));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdVector) {
|
||||
TEST(BriefSyntax, StdVector)
|
||||
{
|
||||
std::vector<int> t1{ 8748, -484, 45 };
|
||||
std::vector<float> t2{ 5.f, 0.198f };
|
||||
|
||||
@@ -231,7 +248,8 @@ TEST(BriefSyntax, StdVector) {
|
||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdList) {
|
||||
TEST(BriefSyntax, StdList)
|
||||
{
|
||||
std::list<int> t1{ 8748, -484, 45 };
|
||||
std::list<float> t2{ 5.f, 0.198f };
|
||||
|
||||
@@ -241,7 +259,8 @@ TEST(BriefSyntax, StdList) {
|
||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdForwardList) {
|
||||
TEST(BriefSyntax, StdForwardList)
|
||||
{
|
||||
std::forward_list<int> t1{ 8748, -484, 45 };
|
||||
std::forward_list<float> t2{ 5.f, 0.198f };
|
||||
|
||||
@@ -251,7 +270,8 @@ TEST(BriefSyntax, StdForwardList) {
|
||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdDeque) {
|
||||
TEST(BriefSyntax, StdDeque)
|
||||
{
|
||||
std::deque<int> t1{ 8748, -484, 45 };
|
||||
std::deque<float> t2{ 5.f, 0.198f };
|
||||
|
||||
@@ -261,7 +281,8 @@ TEST(BriefSyntax, StdDeque) {
|
||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t2), Eq(t2));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdQueue) {
|
||||
TEST(BriefSyntax, StdQueue)
|
||||
{
|
||||
std::queue<std::string> t1;
|
||||
t1.push("first");
|
||||
t1.push("second string");
|
||||
@@ -270,7 +291,8 @@ TEST(BriefSyntax, StdQueue) {
|
||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdPriorityQueue) {
|
||||
TEST(BriefSyntax, StdPriorityQueue)
|
||||
{
|
||||
std::priority_queue<std::string> t1;
|
||||
t1.push("first");
|
||||
t1.push("second string");
|
||||
@@ -287,7 +309,8 @@ TEST(BriefSyntax, StdPriorityQueue) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdStack) {
|
||||
TEST(BriefSyntax, StdStack)
|
||||
{
|
||||
std::stack<std::string> t1;
|
||||
t1.push("first");
|
||||
t1.push("second string");
|
||||
@@ -296,7 +319,8 @@ TEST(BriefSyntax, StdStack) {
|
||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdUnorderedMap) {
|
||||
TEST(BriefSyntax, StdUnorderedMap)
|
||||
{
|
||||
std::unordered_map<int, int> t1;
|
||||
t1.emplace(3423, 624);
|
||||
t1.emplace(-5484, -845);
|
||||
@@ -305,7 +329,8 @@ TEST(BriefSyntax, StdUnorderedMap) {
|
||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdUnorderedMultiMap) {
|
||||
TEST(BriefSyntax, StdUnorderedMultiMap)
|
||||
{
|
||||
std::unordered_multimap<std::string, int> t1;
|
||||
t1.emplace("one", 624);
|
||||
t1.emplace("two", -845);
|
||||
@@ -315,7 +340,8 @@ TEST(BriefSyntax, StdUnorderedMultiMap) {
|
||||
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdMap) {
|
||||
TEST(BriefSyntax, StdMap)
|
||||
{
|
||||
std::map<int, int> t1;
|
||||
t1.emplace(3423, 624);
|
||||
t1.emplace(-5484, -845);
|
||||
@@ -324,26 +350,29 @@ TEST(BriefSyntax, StdMap) {
|
||||
EXPECT_THAT(procBriefSyntaxWithMaxSize(t1), Eq(t1));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdMultiMap) {
|
||||
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
|
||||
// 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::distance(lr.first, lr.second) ==
|
||||
std::distance(rr.first, rr.second));
|
||||
EXPECT_TRUE(std::is_permutation(lr.first, lr.second, rr.first));
|
||||
it = lr.second;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdUnorderedSet) {
|
||||
TEST(BriefSyntax, StdUnorderedSet)
|
||||
{
|
||||
std::unordered_set<std::string> t1;
|
||||
t1.emplace("one");
|
||||
t1.emplace("two");
|
||||
@@ -353,7 +382,8 @@ TEST(BriefSyntax, StdUnorderedSet) {
|
||||
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdUnorderedMultiSet) {
|
||||
TEST(BriefSyntax, StdUnorderedMultiSet)
|
||||
{
|
||||
std::unordered_multiset<std::string> t1;
|
||||
t1.emplace("one");
|
||||
t1.emplace("two");
|
||||
@@ -364,7 +394,8 @@ TEST(BriefSyntax, StdUnorderedMultiSet) {
|
||||
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdSet) {
|
||||
TEST(BriefSyntax, StdSet)
|
||||
{
|
||||
std::set<std::string> t1;
|
||||
t1.emplace("one");
|
||||
t1.emplace("two");
|
||||
@@ -374,7 +405,8 @@ TEST(BriefSyntax, StdSet) {
|
||||
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdMultiSet) {
|
||||
TEST(BriefSyntax, StdMultiSet)
|
||||
{
|
||||
std::multiset<std::string> t1;
|
||||
t1.emplace("one");
|
||||
t1.emplace("two");
|
||||
@@ -386,7 +418,8 @@ TEST(BriefSyntax, StdMultiSet) {
|
||||
EXPECT_TRUE(procBriefSyntaxWithMaxSize(t1) == t1);
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdSmartPtr) {
|
||||
TEST(BriefSyntax, StdSmartPtr)
|
||||
{
|
||||
std::shared_ptr<int> dataShared1(new int{ 4 });
|
||||
std::weak_ptr<int> dataWeak1(dataShared1);
|
||||
std::unique_ptr<std::string> dataUnique1{ new std::string{ "hello world" } };
|
||||
@@ -408,12 +441,14 @@ TEST(BriefSyntax, StdSmartPtr) {
|
||||
EXPECT_THAT(*resUnique1, Eq(*dataUnique1));
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdDuration) {
|
||||
TEST(BriefSyntax, StdDuration)
|
||||
{
|
||||
std::chrono::duration<int64_t, std::milli> t1{ 54654 };
|
||||
EXPECT_TRUE(procBriefSyntax(t1) == t1);
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdTimePoint) {
|
||||
TEST(BriefSyntax, StdTimePoint)
|
||||
{
|
||||
using Duration = std::chrono::duration<double, std::milli>;
|
||||
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
|
||||
|
||||
@@ -421,7 +456,8 @@ TEST(BriefSyntax, StdTimePoint) {
|
||||
EXPECT_TRUE(procBriefSyntax(data) == data);
|
||||
}
|
||||
|
||||
TEST(BriefSyntax, StdAtomic) {
|
||||
TEST(BriefSyntax, StdAtomic)
|
||||
{
|
||||
std::atomic<int32_t> atm0{ 54654 };
|
||||
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<int32_t>{}, atm0) == atm0);
|
||||
|
||||
@@ -433,24 +469,31 @@ TEST(BriefSyntax, StdAtomic) {
|
||||
|
||||
std::atomic<uint16_t> atm3;
|
||||
atm3.store(0x1337);
|
||||
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<uint16_t>{}, atm3).load() == 0x1337);
|
||||
EXPECT_TRUE(procBriefSyntaxRvalue(std::atomic<uint16_t>{}, atm3).load() ==
|
||||
0x1337);
|
||||
}
|
||||
|
||||
#if __cplusplus > 201402L
|
||||
|
||||
TEST(BriefSyntax, StdTuple) {
|
||||
std::tuple<int, std::string, std::vector<char>> t1{5,"hello hello", {'A','B','C'}};
|
||||
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")};
|
||||
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) {
|
||||
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" });
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,30 +20,34 @@
|
||||
// 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
|
||||
constexpr EndiannessType
|
||||
getInverseEndianness(EndiannessType e)
|
||||
{
|
||||
return e == EndiannessType::LittleEndian ? EndiannessType::BigEndian
|
||||
: EndiannessType::LittleEndian;
|
||||
}
|
||||
|
||||
struct InverseEndiannessConfig {
|
||||
static constexpr bitsery::EndiannessType Endianness = getInverseEndianness(DefaultConfig::Endianness);
|
||||
struct InverseEndiannessConfig
|
||||
{
|
||||
static constexpr bitsery::EndiannessType Endianness =
|
||||
getInverseEndianness(DefaultConfig::Endianness);
|
||||
static constexpr bool CheckDataErrors = true;
|
||||
static constexpr bool CheckAdapterErrors = true;
|
||||
};
|
||||
|
||||
struct IntegralTypes {
|
||||
struct IntegralTypes
|
||||
{
|
||||
int64_t a;
|
||||
uint32_t b;
|
||||
int16_t c;
|
||||
@@ -51,10 +55,11 @@ struct IntegralTypes {
|
||||
int8_t e;
|
||||
};
|
||||
|
||||
using InverseReader = bitsery::InputBufferAdapter<Buffer, InverseEndiannessConfig>;
|
||||
using InverseReader =
|
||||
bitsery::InputBufferAdapter<Buffer, InverseEndiannessConfig>;
|
||||
|
||||
|
||||
TEST(DataEndianness, WhenWriteBytesThenBytesAreSwapped) {
|
||||
TEST(DataEndianness, WhenWriteBytesThenBytesAreSwapped)
|
||||
{
|
||||
// fill initial values
|
||||
IntegralTypes src{};
|
||||
src.a = static_cast<int64_t>(0x1122334455667788u);
|
||||
@@ -96,7 +101,8 @@ TEST(DataEndianness, WhenWriteBytesThenBytesAreSwapped) {
|
||||
EXPECT_THAT(res.e, Eq(resInv.e));
|
||||
}
|
||||
|
||||
TEST(DataEndianness, WhenWrite1ByteValuesThenEndiannessIsIgnored) {
|
||||
TEST(DataEndianness, WhenWrite1ByteValuesThenEndiannessIsIgnored)
|
||||
{
|
||||
// fill initial values
|
||||
constexpr size_t SIZE = 4;
|
||||
uint8_t src[SIZE] = { 0xAA, 0xBB, 0xCC, 0xDD };
|
||||
@@ -109,12 +115,13 @@ TEST(DataEndianness, WhenWrite1ByteValuesThenEndiannessIsIgnored) {
|
||||
// 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
|
||||
// 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) {
|
||||
TEST(DataEndianness, WhenWriteMoreThan1ByteValuesThenValuesAreSwapped)
|
||||
{
|
||||
// fill initial values
|
||||
constexpr size_t SIZE = 4;
|
||||
uint16_t src[SIZE] = { 0xAA00, 0xBB11, 0xCC22, 0xDD33 };
|
||||
@@ -128,25 +135,29 @@ TEST(DataEndianness, WhenWriteMoreThan1ByteValuesThenValuesAreSwapped) {
|
||||
// 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
|
||||
// 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) {
|
||||
constexpr size_t
|
||||
getBits(T v)
|
||||
{
|
||||
return bitsery::details::calcRequiredBits<T>({}, v);
|
||||
}
|
||||
|
||||
struct IntegralUnsignedTypes {
|
||||
struct IntegralUnsignedTypes
|
||||
{
|
||||
uint64_t a;
|
||||
uint32_t b;
|
||||
uint16_t c;
|
||||
uint8_t d;
|
||||
};
|
||||
|
||||
TEST(DataEndianness, WhenValueTypeIs1ByteThenBitOperationsIsNotAffectedByEndianness) {
|
||||
TEST(DataEndianness,
|
||||
WhenValueTypeIs1ByteThenBitOperationsIsNotAffectedByEndianness)
|
||||
{
|
||||
// fill initial values
|
||||
constexpr IntegralUnsignedTypes src{
|
||||
0x0000334455667788,
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,22 +20,22 @@
|
||||
// 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 {
|
||||
struct IntegralUnsignedTypes
|
||||
{
|
||||
uint32_t a;
|
||||
uint16_t b;
|
||||
uint8_t c;
|
||||
@@ -44,13 +44,16 @@ struct IntegralUnsignedTypes {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
constexpr size_t getBits(T v) {
|
||||
constexpr size_t
|
||||
getBits(T v)
|
||||
{
|
||||
return bitsery::details::calcRequiredBits<T>({}, v);
|
||||
}
|
||||
|
||||
// *** bits operations
|
||||
|
||||
TEST(DataBitsAndBytesOperations, WriteAndReadBitsMaxTypeValues) {
|
||||
TEST(DataBitsAndBytesOperations, WriteAndReadBitsMaxTypeValues)
|
||||
{
|
||||
Buffer buf;
|
||||
Writer bw{ buf };
|
||||
AdapterBitPackingWriter bpw{ bw };
|
||||
@@ -77,7 +80,8 @@ TEST(DataBitsAndBytesOperations, WriteAndReadBitsMaxTypeValues) {
|
||||
EXPECT_THAT(v8, Eq(std::numeric_limits<uint8_t>::max()));
|
||||
}
|
||||
|
||||
TEST(DataBitsAndBytesOperations, WriteAndReadBits) {
|
||||
TEST(DataBitsAndBytesOperations, WriteAndReadBits)
|
||||
{
|
||||
// setup data
|
||||
constexpr IntegralUnsignedTypes data{
|
||||
485454, // bits 19
|
||||
@@ -124,10 +128,10 @@ TEST(DataBitsAndBytesOperations, WriteAndReadBits) {
|
||||
EXPECT_THAT(res.c, Eq(data.c));
|
||||
EXPECT_THAT(res.d, Eq(data.d));
|
||||
EXPECT_THAT(res.e, Eq(data.e));
|
||||
|
||||
}
|
||||
|
||||
TEST(DataBitsAndBytesOperations, WrittenSizeIsCountedPerByteNotPerBit) {
|
||||
TEST(DataBitsAndBytesOperations, WrittenSizeIsCountedPerByteNotPerBit)
|
||||
{
|
||||
// setup data
|
||||
|
||||
// create and write to buffer
|
||||
@@ -166,7 +170,8 @@ TEST(DataBitsAndBytesOperations, WrittenSizeIsCountedPerByteNotPerBit) {
|
||||
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::DataOverflow)); // false
|
||||
}
|
||||
|
||||
TEST(DataBitsAndBytesOperations, ConsecutiveCallsToAlignHasNoEffect) {
|
||||
TEST(DataBitsAndBytesOperations, ConsecutiveCallsToAlignHasNoEffect)
|
||||
{
|
||||
Buffer buf;
|
||||
Writer bw{ buf };
|
||||
AdapterBitPackingWriter bpw{ bw };
|
||||
@@ -201,7 +206,8 @@ TEST(DataBitsAndBytesOperations, ConsecutiveCallsToAlignHasNoEffect) {
|
||||
EXPECT_THAT(bpr.error(), Eq(bitsery::ReaderError::NoError));
|
||||
}
|
||||
|
||||
TEST(DataBitsAndBytesOperations, AlignWritesZerosBits) {
|
||||
TEST(DataBitsAndBytesOperations, AlignWritesZerosBits)
|
||||
{
|
||||
// setup data
|
||||
|
||||
// create and write to buffer
|
||||
@@ -231,10 +237,10 @@ TEST(DataBitsAndBytesOperations, AlignWritesZerosBits) {
|
||||
EXPECT_THAT(bpr2.error(), Eq(bitsery::ReaderError::NoError));
|
||||
}
|
||||
|
||||
|
||||
// *** bytes operations
|
||||
|
||||
struct IntegralTypes {
|
||||
struct IntegralTypes
|
||||
{
|
||||
int64_t a;
|
||||
uint32_t b;
|
||||
int16_t c;
|
||||
@@ -243,7 +249,8 @@ struct IntegralTypes {
|
||||
int8_t f[2];
|
||||
};
|
||||
|
||||
TEST(DataBitsAndBytesOperations, WriteAndReadBytes) {
|
||||
TEST(DataBitsAndBytesOperations, WriteAndReadBytes)
|
||||
{
|
||||
// setup data
|
||||
IntegralTypes data;
|
||||
data.a = -4894541654564;
|
||||
@@ -285,10 +292,10 @@ TEST(DataBitsAndBytesOperations, WriteAndReadBytes) {
|
||||
EXPECT_THAT(data.d, Eq(res.d));
|
||||
EXPECT_THAT(data.e, Eq(res.e));
|
||||
EXPECT_THAT(data.f, ContainerEq(res.f));
|
||||
|
||||
}
|
||||
|
||||
TEST(DataBitsAndBytesOperations, WriteAndReadBytesWithBitPackingWrapper) {
|
||||
TEST(DataBitsAndBytesOperations, WriteAndReadBytesWithBitPackingWrapper)
|
||||
{
|
||||
// setup data
|
||||
IntegralTypes data;
|
||||
data.a = -4894541654564;
|
||||
@@ -332,10 +339,10 @@ TEST(DataBitsAndBytesOperations, WriteAndReadBytesWithBitPackingWrapper) {
|
||||
EXPECT_THAT(data.d, Eq(res.d));
|
||||
EXPECT_THAT(data.e, Eq(res.e));
|
||||
EXPECT_THAT(data.f, ContainerEq(res.f));
|
||||
|
||||
}
|
||||
|
||||
TEST(DataBitsAndBytesOperations, ReadWriteFncCanAcceptSignedData) {
|
||||
TEST(DataBitsAndBytesOperations, ReadWriteFncCanAcceptSignedData)
|
||||
{
|
||||
// setup data
|
||||
constexpr size_t DATA_SIZE = 3;
|
||||
int16_t src[DATA_SIZE]{ 54, -4877, 30067 };
|
||||
@@ -352,7 +359,8 @@ TEST(DataBitsAndBytesOperations, ReadWriteFncCanAcceptSignedData) {
|
||||
EXPECT_THAT(dst, ContainerEq(src));
|
||||
}
|
||||
|
||||
TEST(DataBitsAndBytesOperations, ReadWriteCanWorkOnUnalignedData) {
|
||||
TEST(DataBitsAndBytesOperations, ReadWriteCanWorkOnUnalignedData)
|
||||
{
|
||||
// setup data
|
||||
constexpr size_t DATA_SIZE = 3;
|
||||
int16_t src[DATA_SIZE]{ 54, -4877, 30067 };
|
||||
@@ -381,7 +389,9 @@ TEST(DataBitsAndBytesOperations, ReadWriteCanWorkOnUnalignedData) {
|
||||
EXPECT_THAT(tmp, Eq(12));
|
||||
}
|
||||
|
||||
TEST(DataBitsAndBytesOperations, RegressionTestReadBytesAfterReadBitsWithLotsOfZeroBits) {
|
||||
TEST(DataBitsAndBytesOperations,
|
||||
RegressionTestReadBytesAfterReadBitsWithLotsOfZeroBits)
|
||||
{
|
||||
// setup data
|
||||
int16_t data[2]{ 0x0000, 0x7FFF };
|
||||
int16_t res[2]{};
|
||||
@@ -407,4 +417,3 @@ TEST(DataBitsAndBytesOperations, RegressionTestReadBytesAfterReadBitsWithLotsOfZ
|
||||
EXPECT_THAT(res[0], Eq(data[0]));
|
||||
EXPECT_THAT(res[1], Eq(data[1]));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -23,15 +23,16 @@
|
||||
#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 {
|
||||
class DataWriting : public testing::Test
|
||||
{
|
||||
public:
|
||||
using TWriter = bitsery::OutputBufferAdapter<BufType>;
|
||||
using TBuffer = BufType;
|
||||
@@ -47,7 +48,9 @@ TYPED_TEST_SUITE(DataWriting, ContainerTypes,);
|
||||
static constexpr size_t DATA_SIZE = 14u;
|
||||
|
||||
template<typename BW>
|
||||
void writeData(BW& bw) {
|
||||
void
|
||||
writeData(BW& bw)
|
||||
{
|
||||
uint16_t tmp1{ 45 }, tmp2{ 6543 }, tmp3{ 46533 };
|
||||
uint32_t tmp4{ 8979445 }, tmp5{ 7987564 };
|
||||
bw.template writeBytes<2>(tmp1);
|
||||
@@ -57,7 +60,8 @@ void writeData(BW& bw) {
|
||||
bw.template writeBytes<4>(tmp5);
|
||||
}
|
||||
|
||||
TYPED_TEST(DataWriting, GetWrittenBytesCountReturnsActualBytesWritten) {
|
||||
TYPED_TEST(DataWriting, GetWrittenBytesCountReturnsActualBytesWritten)
|
||||
{
|
||||
using TWriter = typename TestFixture::TWriter;
|
||||
using TBuffer = typename TestFixture::TBuffer;
|
||||
TBuffer buf{};
|
||||
@@ -69,7 +73,8 @@ TYPED_TEST(DataWriting, GetWrittenBytesCountReturnsActualBytesWritten) {
|
||||
EXPECT_THAT(buf.size(), ::testing::Ge(DATA_SIZE));
|
||||
}
|
||||
|
||||
TYPED_TEST(DataWriting, WhenWritingBitsThenMustFlushWriter) {
|
||||
TYPED_TEST(DataWriting, WhenWritingBitsThenMustFlushWriter)
|
||||
{
|
||||
using TWriter = typename TestFixture::TWriter;
|
||||
using TBuffer = typename TestFixture::TBuffer;
|
||||
TBuffer buf{};
|
||||
@@ -83,7 +88,8 @@ TYPED_TEST(DataWriting, WhenWritingBitsThenMustFlushWriter) {
|
||||
EXPECT_THAT(writtenSize2, Eq(1));
|
||||
}
|
||||
|
||||
TYPED_TEST(DataWriting, WhenDataAlignedThenFlushHasNoEffect) {
|
||||
TYPED_TEST(DataWriting, WhenDataAlignedThenFlushHasNoEffect)
|
||||
{
|
||||
using TWriter = typename TestFixture::TWriter;
|
||||
using TBuffer = typename TestFixture::TBuffer;
|
||||
TBuffer buf{};
|
||||
@@ -96,10 +102,10 @@ TYPED_TEST(DataWriting, WhenDataAlignedThenFlushHasNoEffect) {
|
||||
auto writtenSize2 = bpw.writtenBytesCount();
|
||||
EXPECT_THAT(writtenSize1, Eq(1));
|
||||
EXPECT_THAT(writtenSize2, Eq(1));
|
||||
|
||||
}
|
||||
|
||||
TEST(DataWritingNonFixedBufferContainer, ContainerIsAlwaysResizedToCapacity) {
|
||||
TEST(DataWritingNonFixedBufferContainer, ContainerIsAlwaysResizedToCapacity)
|
||||
{
|
||||
NonFixedContainer buf{};
|
||||
bitsery::OutputBufferAdapter<NonFixedContainer> bw{ buf };
|
||||
for (auto i = 0; i < 5; ++i) {
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,16 +20,15 @@
|
||||
// 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;
|
||||
@@ -37,45 +36,48 @@ using testing::Eq;
|
||||
// forward declare, for testing with std::unordered_map
|
||||
class HasherForNonDefaultConstructible;
|
||||
|
||||
class NonDefaultConstructible {
|
||||
class NonDefaultConstructible
|
||||
{
|
||||
int32_t i{ 0 };
|
||||
friend class HasherForNonDefaultConstructible;
|
||||
|
||||
|
||||
|
||||
|
||||
friend class bitsery::Access;
|
||||
NonDefaultConstructible() = default;
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& 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 {
|
||||
bool operator==(const NonDefaultConstructible& other) const
|
||||
{
|
||||
return i == other.i;
|
||||
}
|
||||
|
||||
bool operator < (const NonDefaultConstructible& other) const {
|
||||
bool operator<(const NonDefaultConstructible& other) const
|
||||
{
|
||||
return i < other.i;
|
||||
}
|
||||
};
|
||||
|
||||
class HasherForNonDefaultConstructible {
|
||||
class HasherForNonDefaultConstructible
|
||||
{
|
||||
public:
|
||||
size_t operator()(const NonDefaultConstructible& o) const {
|
||||
size_t operator()(const NonDefaultConstructible& o) const
|
||||
{
|
||||
return std::hash<int32_t>()(o.i);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
TEST(DeserializeNonDefaultConstructible, Container) {
|
||||
TEST(DeserializeNonDefaultConstructible, Container)
|
||||
{
|
||||
SerializationContext ctx{};
|
||||
std::vector<NonDefaultConstructible> data{};
|
||||
data.emplace_back(1);
|
||||
@@ -88,8 +90,10 @@ TEST(DeserializeNonDefaultConstructible, Container) {
|
||||
|
||||
EXPECT_THAT(res, ContainerEq(data));
|
||||
}
|
||||
//this test is here, because when object is not constructible we cannot simple "resize" container
|
||||
TEST(DeserializeNonDefaultConstructible, ResultContainerShouldShrink) {
|
||||
// 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);
|
||||
@@ -104,9 +108,11 @@ TEST(DeserializeNonDefaultConstructible, ResultContainerShouldShrink) {
|
||||
EXPECT_THAT(res, ContainerEq(data));
|
||||
}
|
||||
|
||||
TEST(DeserializeNonDefaultConstructible, ResultStdForwardListShouldShrink) {
|
||||
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
|
||||
// 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{};
|
||||
@@ -124,7 +130,6 @@ TEST(DeserializeNonDefaultConstructible, ResultStdForwardListShouldShrink) {
|
||||
EXPECT_THAT(*resIt, Eq(*it));
|
||||
}
|
||||
EXPECT_THAT(resIt, Eq(res.end()));
|
||||
|
||||
}
|
||||
{
|
||||
// 1) when result should have 0 elements
|
||||
@@ -138,7 +143,6 @@ TEST(DeserializeNonDefaultConstructible, ResultStdForwardListShouldShrink) {
|
||||
ctx.createDeserializer().container(res, 10);
|
||||
|
||||
EXPECT_THAT(res.begin(), Eq(res.end()));
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
@@ -160,7 +164,8 @@ TEST(DeserializeNonDefaultConstructible, ResultStdForwardListShouldShrink) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DeserializeNonDefaultConstructible, StdSet) {
|
||||
TEST(DeserializeNonDefaultConstructible, StdSet)
|
||||
{
|
||||
SerializationContext ctx{};
|
||||
std::set<NonDefaultConstructible> data;
|
||||
data.insert(NonDefaultConstructible{ 1 });
|
||||
@@ -174,22 +179,37 @@ TEST(DeserializeNonDefaultConstructible, StdSet) {
|
||||
EXPECT_THAT(res, ContainerEq(data));
|
||||
}
|
||||
|
||||
TEST(DeserializeNonDefaultConstructible, StdMap) {
|
||||
TEST(DeserializeNonDefaultConstructible, StdMap)
|
||||
{
|
||||
SerializationContext ctx{};
|
||||
std::unordered_map<NonDefaultConstructible, NonDefaultConstructible, HasherForNonDefaultConstructible> data;
|
||||
std::unordered_map<NonDefaultConstructible,
|
||||
NonDefaultConstructible,
|
||||
HasherForNonDefaultConstructible>
|
||||
data;
|
||||
data.emplace(NonDefaultConstructible{ 2 }, NonDefaultConstructible{ 3 });
|
||||
|
||||
std::unordered_map<NonDefaultConstructible, NonDefaultConstructible, HasherForNonDefaultConstructible> res{};
|
||||
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.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.ext(res,
|
||||
bitsery::ext::StdMap{ 10 },
|
||||
[](decltype(des)& des,
|
||||
NonDefaultConstructible& key,
|
||||
NonDefaultConstructible& value) {
|
||||
des.object(key);
|
||||
des.object(value);
|
||||
});
|
||||
@@ -197,8 +217,8 @@ TEST(DeserializeNonDefaultConstructible, StdMap) {
|
||||
EXPECT_THAT(res, ContainerEq(data));
|
||||
}
|
||||
|
||||
|
||||
struct NonPolymorphicPointers {
|
||||
struct NonPolymorphicPointers
|
||||
{
|
||||
NonDefaultConstructible* pp;
|
||||
std::unique_ptr<NonDefaultConstructible> up;
|
||||
std::shared_ptr<NonDefaultConstructible> sp;
|
||||
@@ -206,20 +226,26 @@ struct NonPolymorphicPointers {
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, NonPolymorphicPointers& o) {
|
||||
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>;
|
||||
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.up =
|
||||
std::unique_ptr<NonDefaultConstructible>(new NonDefaultConstructible{ 54 });
|
||||
data.sp = std::shared_ptr<NonDefaultConstructible>(
|
||||
new NonDefaultConstructible{ -481 });
|
||||
data.wp = data.sp;
|
||||
|
||||
NonPolymorphicPointers res{};
|
||||
@@ -235,62 +261,72 @@ TEST(DeserializeNonDefaultConstructible, NonPolymorphicPointerAndSmartPointer) {
|
||||
EXPECT_THAT(*(res.wp.lock()), Eq(*(data.wp.lock())));
|
||||
}
|
||||
|
||||
class PolymorphicNDCBase {
|
||||
class PolymorphicNDCBase
|
||||
{
|
||||
public:
|
||||
virtual ~PolymorphicNDCBase() = 0;
|
||||
template<typename S>
|
||||
void serialize(S& ) {}
|
||||
void serialize(S&)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
PolymorphicNDCBase::~PolymorphicNDCBase() = default;
|
||||
|
||||
class PolymorphicNDC1:public PolymorphicNDCBase {
|
||||
class PolymorphicNDC1 : public PolymorphicNDCBase
|
||||
{
|
||||
int8_t i{};
|
||||
friend class bitsery::Access;
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& 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(int8_t v)
|
||||
: i{ v }
|
||||
{
|
||||
}
|
||||
bool operator==(const PolymorphicNDC1& other) const { return i == other.i; }
|
||||
};
|
||||
|
||||
class PolymorphicNDC2:public PolymorphicNDCBase {
|
||||
class PolymorphicNDC2 : public PolymorphicNDCBase
|
||||
{
|
||||
uint16_t ui{};
|
||||
|
||||
friend class bitsery::Access;
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& 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(uint16_t v)
|
||||
: ui{ v }
|
||||
{
|
||||
}
|
||||
|
||||
bool operator==(const PolymorphicNDC2& other) const { return ui == other.ui; }
|
||||
};
|
||||
|
||||
|
||||
namespace bitsery {
|
||||
namespace ext {
|
||||
|
||||
template<>
|
||||
struct PolymorphicBaseClass<PolymorphicNDCBase> : PolymorphicDerivedClasses<PolymorphicNDC1, PolymorphicNDC2> {
|
||||
struct PolymorphicBaseClass<PolymorphicNDCBase>
|
||||
: PolymorphicDerivedClasses<PolymorphicNDC1, PolymorphicNDC2>
|
||||
{
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct PolymorphicPointers {
|
||||
struct PolymorphicPointers
|
||||
{
|
||||
PolymorphicNDCBase* pp;
|
||||
std::unique_ptr<PolymorphicNDCBase> up;
|
||||
std::shared_ptr<PolymorphicNDCBase> sp;
|
||||
@@ -298,15 +334,20 @@ struct PolymorphicPointers {
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, PolymorphicPointers& o) {
|
||||
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>>;
|
||||
TEST(DeserializeNonDefaultConstructible, PolymorphicPointerAndSmartPointer)
|
||||
{
|
||||
using TContext =
|
||||
std::tuple<bitsery::ext::PointerLinkingContext,
|
||||
bitsery::ext::PolymorphicContext<bitsery::ext::StandardRTTI>>;
|
||||
using SerContext = BasicSerializationContext<TContext>;
|
||||
SerContext ctx{};
|
||||
PolymorphicPointers data{};
|
||||
@@ -320,8 +361,10 @@ TEST(DeserializeNonDefaultConstructible, PolymorphicPointerAndSmartPointer) {
|
||||
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);
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,13 +20,13 @@
|
||||
// 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) {
|
||||
TEST(Serialization, AdapterCanBeMovedInAndOut)
|
||||
{
|
||||
Buffer buf{};
|
||||
bitsery::Serializer<Writer> ser1{ buf };
|
||||
ser1.object(MyStruct1{ 1, 2 });
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,14 +20,13 @@
|
||||
// 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 };
|
||||
@@ -35,12 +34,14 @@ TEST(SerializeBooleans, BoolAsBit) {
|
||||
bool res1;
|
||||
bool res2;
|
||||
auto& ser = ctx.createSerializer();
|
||||
ser.enableBitPacking([&t1, &t2](SerializationContext::TSerializerBPEnabled& sbp) {
|
||||
ser.enableBitPacking(
|
||||
[&t1, &t2](SerializationContext::TSerializerBPEnabled& sbp) {
|
||||
sbp.boolValue(t1);
|
||||
sbp.boolValue(t2);
|
||||
});
|
||||
auto& des = ctx.createDeserializer();
|
||||
des.enableBitPacking([&res1, &res2](SerializationContext::TDeserializerBPEnabled& sbp) {
|
||||
des.enableBitPacking(
|
||||
[&res1, &res2](SerializationContext::TDeserializerBPEnabled& sbp) {
|
||||
sbp.boolValue(res1);
|
||||
sbp.boolValue(res2);
|
||||
});
|
||||
@@ -50,7 +51,8 @@ TEST(SerializeBooleans, BoolAsBit) {
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
|
||||
}
|
||||
|
||||
TEST(SerializeBooleans, BoolAsByte) {
|
||||
TEST(SerializeBooleans, BoolAsByte)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
bool t1{ true };
|
||||
bool t2{ false };
|
||||
@@ -68,7 +70,9 @@ TEST(SerializeBooleans, BoolAsByte) {
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
|
||||
}
|
||||
|
||||
TEST(SerializeBooleans, WhenReadingBoolByteReadsMoreThanOneThenInvalidDataErrorAndResultIsFalse) {
|
||||
TEST(SerializeBooleans,
|
||||
WhenReadingBoolByteReadsMoreThanOneThenInvalidDataErrorAndResultIsFalse)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
auto& ser = ctx.createSerializer();
|
||||
ser.value1b(uint8_t{ 1 });
|
||||
@@ -79,5 +83,6 @@ TEST(SerializeBooleans, WhenReadingBoolByteReadsMoreThanOneThenInvalidDataErrorA
|
||||
EXPECT_THAT(res, Eq(true));
|
||||
des.boolValue(res);
|
||||
EXPECT_THAT(res, Eq(false));
|
||||
EXPECT_THAT(ctx.des->adapter().error(), Eq(bitsery::ReaderError::InvalidData));
|
||||
EXPECT_THAT(ctx.des->adapter().error(),
|
||||
Eq(bitsery::ReaderError::InvalidData));
|
||||
}
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,54 +20,48 @@
|
||||
// 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() {
|
||||
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 {
|
||||
struct EmptyFtor
|
||||
{
|
||||
template<typename S, typename T>
|
||||
void operator() (S& , T& ) {
|
||||
|
||||
void operator()(S&, T&)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -76,7 +70,8 @@ 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;
|
||||
@@ -84,21 +79,24 @@ public:
|
||||
const TContainer src = getFilledContainer<TContainer>();
|
||||
TContainer res{};
|
||||
|
||||
size_t getExpectedBufSize(const SerializationContext &ctx) const {
|
||||
size_t getExpectedBufSize(const SerializationContext& ctx) const
|
||||
{
|
||||
auto size = bitsery::traits::ContainerTraits<TContainer>::size(src);
|
||||
return ctx.containerSizeSerializedBytesCount(size) + size * sizeof(TValue);
|
||||
}
|
||||
};
|
||||
// std::forward_list is not supported, because it doesn't have size() method
|
||||
using SequenceContainersWithArthmeticTypes = ::testing::Types<
|
||||
std::vector<int>,
|
||||
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) {
|
||||
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, Values)
|
||||
{
|
||||
SerializationContext ctx{};
|
||||
using TValue = typename TestFixture::TValue;
|
||||
|
||||
@@ -109,7 +107,9 @@ TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, Values) {
|
||||
EXPECT_THAT(this->res, ContainerEq(this->src));
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, CustomFunctionIncrements) {
|
||||
TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes,
|
||||
CustomFunctionIncrements)
|
||||
{
|
||||
SerializationContext ctx{};
|
||||
using TValue = typename TestFixture::TValue;
|
||||
|
||||
@@ -131,9 +131,9 @@ TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, CustomFunctionIncrements
|
||||
EXPECT_THAT(this->res, ContainerEq(this->src));
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
class SerializeContainerDynamicSizeCompositeTypes : public testing::Test {
|
||||
class SerializeContainerDynamicSizeCompositeTypes : public testing::Test
|
||||
{
|
||||
public:
|
||||
using TContainer = T;
|
||||
using TValue = typename T::value_type;
|
||||
@@ -141,19 +141,22 @@ public:
|
||||
const TContainer src = getFilledContainer<TContainer>();
|
||||
TContainer res{};
|
||||
|
||||
size_t getExpectedBufSize(const SerializationContext &ctx) const {
|
||||
return ctx.containerSizeSerializedBytesCount(src.size()) + src.size() * TValue::SIZE;
|
||||
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>>;
|
||||
|
||||
using SerializeContainerDynamicSizeWithCompositeTypes = ::testing::Types<
|
||||
std::vector<MyStruct1>,
|
||||
std::list<MyStruct2>>;
|
||||
TYPED_TEST_SUITE(SerializeContainerDynamicSizeCompositeTypes,
|
||||
SerializeContainerDynamicSizeWithCompositeTypes, );
|
||||
|
||||
TYPED_TEST_SUITE(SerializeContainerDynamicSizeCompositeTypes, SerializeContainerDynamicSizeWithCompositeTypes,);
|
||||
|
||||
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes, DefaultSerializeFunction) {
|
||||
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes,
|
||||
DefaultSerializeFunction)
|
||||
{
|
||||
SerializationContext ctx{};
|
||||
|
||||
ctx.createSerializer().container(this->src, 1000);
|
||||
@@ -163,34 +166,39 @@ TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes, DefaultSerializeFunction
|
||||
EXPECT_THAT(this->res, ContainerEq(this->src));
|
||||
}
|
||||
|
||||
|
||||
TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes, CustomFunctionThatDoNothing) {
|
||||
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(ctx.containerSizeSerializedBytesCount(this->src.size())));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class SerializeContainerFixedSizeArithmeticTypes : public testing::Test {
|
||||
class SerializeContainerFixedSizeArithmeticTypes : public testing::Test
|
||||
{
|
||||
public:
|
||||
using TContainer = T;
|
||||
|
||||
size_t getContainerSize() {
|
||||
size_t getContainerSize()
|
||||
{
|
||||
T tmp{};
|
||||
return static_cast<size_t>(std::distance(std::begin(tmp), std::end(tmp)));
|
||||
}
|
||||
};
|
||||
|
||||
using StaticContainersWithIntegralTypes = ::testing::Types<
|
||||
std::array<int16_t, 4>,
|
||||
int16_t[4]>;
|
||||
using StaticContainersWithIntegralTypes =
|
||||
::testing::Types<std::array<int16_t, 4>, int16_t[4]>;
|
||||
|
||||
TYPED_TEST_SUITE(SerializeContainerFixedSizeArithmeticTypes, StaticContainersWithIntegralTypes,);
|
||||
TYPED_TEST_SUITE(SerializeContainerFixedSizeArithmeticTypes,
|
||||
StaticContainersWithIntegralTypes, );
|
||||
|
||||
TYPED_TEST(SerializeContainerFixedSizeArithmeticTypes, ArithmeticValues) {
|
||||
TYPED_TEST(SerializeContainerFixedSizeArithmeticTypes, ArithmeticValues)
|
||||
{
|
||||
using Container = typename TestFixture::TContainer;
|
||||
Container src{ 5, 9, 15, -459 };
|
||||
Container res{};
|
||||
@@ -201,36 +209,47 @@ TYPED_TEST(SerializeContainerFixedSizeArithmeticTypes, ArithmeticValues) {
|
||||
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * 2));
|
||||
EXPECT_THAT(res, ContainerEq(src));
|
||||
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
class SerializeContainerFixedSizeCompositeTypes : public SerializeContainerFixedSizeArithmeticTypes<T> {
|
||||
|
||||
class SerializeContainerFixedSizeCompositeTypes
|
||||
: public SerializeContainerFixedSizeArithmeticTypes<T>
|
||||
{
|
||||
};
|
||||
|
||||
using StaticContainersWithCompositeTypes = ::testing::Types<
|
||||
std::array<MyStruct1, 4>, MyStruct1[4]>;
|
||||
using StaticContainersWithCompositeTypes =
|
||||
::testing::Types<std::array<MyStruct1, 4>, MyStruct1[4]>;
|
||||
|
||||
TYPED_TEST_SUITE(SerializeContainerFixedSizeCompositeTypes, StaticContainersWithCompositeTypes,);
|
||||
TYPED_TEST_SUITE(SerializeContainerFixedSizeCompositeTypes,
|
||||
StaticContainersWithCompositeTypes, );
|
||||
|
||||
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, DefaultSerializationFunction) {
|
||||
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes,
|
||||
DefaultSerializationFunction)
|
||||
{
|
||||
using Container = typename TestFixture::TContainer;
|
||||
Container src{MyStruct1{0, 1}, MyStruct1{8, 9}, MyStruct1{11, 34}, MyStruct1{5134, 1532}};
|
||||
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(ctx.getBufferSize(),
|
||||
Eq(this->getContainerSize() * MyStruct1::SIZE));
|
||||
EXPECT_THAT(res, ContainerEq(src));
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, CustomFunctionThatSerializesAnEmptyByteEveryElement) {
|
||||
TYPED_TEST(SerializeContainerFixedSizeCompositeTypes,
|
||||
CustomFunctionThatSerializesAnEmptyByteEveryElement)
|
||||
{
|
||||
using Container = typename TestFixture::TContainer;
|
||||
Container src{MyStruct1{0, 1}, MyStruct1{2, 3}, MyStruct1{4, 5}, MyStruct1{5134, 1532}};
|
||||
Container src{ MyStruct1{ 0, 1 },
|
||||
MyStruct1{ 2, 3 },
|
||||
MyStruct1{ 4, 5 },
|
||||
MyStruct1{ 5134, 1532 } };
|
||||
Container res{};
|
||||
|
||||
using TValue = decltype(*std::begin(res));
|
||||
@@ -249,24 +268,30 @@ TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, CustomFunctionThatSerializ
|
||||
des.value1b(tmp);
|
||||
});
|
||||
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * (MyStruct1::SIZE + sizeof(char))));
|
||||
EXPECT_THAT(ctx.getBufferSize(),
|
||||
Eq(this->getContainerSize() * (MyStruct1::SIZE + sizeof(char))));
|
||||
EXPECT_THAT(res, ContainerEq(src));
|
||||
}
|
||||
|
||||
class SerializeContainer : public ::testing::TestWithParam<size_t> {
|
||||
};
|
||||
class SerializeContainer : public ::testing::TestWithParam<size_t>
|
||||
{};
|
||||
|
||||
TEST_P(SerializeContainer, SizeHasVariableLength) {
|
||||
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{});
|
||||
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())));
|
||||
EXPECT_THAT(ctx.getBufferSize(),
|
||||
Eq(ctx.containerSizeSerializedBytesCount(src.size())));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(LargeContainerSize, SerializeContainer, ::testing::Values(0x01, 0x80, 0x4000));
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(LargeContainerSize,
|
||||
SerializeContainer,
|
||||
::testing::Values(0x01, 0x80, 0x4000));
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,9 +20,8 @@
|
||||
// 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,7 +30,8 @@ using bitsery::DefaultConfig;
|
||||
using SingleTypeContext = int;
|
||||
using MultipleTypesContext = std::tuple<int, float, char>;
|
||||
|
||||
TEST(SerializationContext, WhenContextIsNotTupleThenReturnThisContext) {
|
||||
TEST(SerializationContext, WhenContextIsNotTupleThenReturnThisContext)
|
||||
{
|
||||
SingleTypeContext ctx{ 54 };
|
||||
BasicSerializationContext<SingleTypeContext> c1;
|
||||
auto& ser1 = c1.createSerializer(ctx);
|
||||
@@ -39,7 +39,8 @@ TEST(SerializationContext, WhenContextIsNotTupleThenReturnThisContext) {
|
||||
EXPECT_THAT(ser1.context<SingleTypeContext>(), Eq(ctx));
|
||||
}
|
||||
|
||||
TEST(SerializationContext, WhenContextIsTupleThenReturnsTupleElements) {
|
||||
TEST(SerializationContext, WhenContextIsTupleThenReturnsTupleElements)
|
||||
{
|
||||
|
||||
MultipleTypesContext ctx{ 5, 798.654f, 'F' };
|
||||
BasicSerializationContext<MultipleTypesContext> c1;
|
||||
@@ -50,7 +51,8 @@ TEST(SerializationContext, WhenContextIsTupleThenReturnsTupleElements) {
|
||||
EXPECT_THAT(ser1.context<char>(), std::get<2>(ctx));
|
||||
}
|
||||
|
||||
TEST(SerializationContext, WhenContextDoesntExistsThenContextOrNullReturnsNull) {
|
||||
TEST(SerializationContext, WhenContextDoesntExistsThenContextOrNullReturnsNull)
|
||||
{
|
||||
SingleTypeContext ctx1 = 32;
|
||||
BasicSerializationContext<SingleTypeContext> c1;
|
||||
auto& ser = c1.createSerializer(ctx1);
|
||||
@@ -68,10 +70,15 @@ TEST(SerializationContext, WhenContextDoesntExistsThenContextOrNullReturnsNull)
|
||||
EXPECT_THAT(*des.contextOrNull<int>(), Eq(5));
|
||||
}
|
||||
|
||||
struct Base { int value{}; };
|
||||
struct Derived: Base{};
|
||||
struct Base
|
||||
{
|
||||
int value{};
|
||||
};
|
||||
struct Derived : Base
|
||||
{};
|
||||
|
||||
TEST(SerializationContext, ContextWillTryToConvertIfTypeIsConvertible) {
|
||||
TEST(SerializationContext, ContextWillTryToConvertIfTypeIsConvertible)
|
||||
{
|
||||
Derived ctx1{};
|
||||
BasicSerializationContext<Derived> c1;
|
||||
auto& ser = c1.createSerializer(ctx1);
|
||||
@@ -81,7 +88,9 @@ TEST(SerializationContext, ContextWillTryToConvertIfTypeIsConvertible) {
|
||||
ser.context<Base>();
|
||||
}
|
||||
|
||||
TEST(SerializationContext, WhenMultipleConvertibleTypesExistsThenFirstMatchIsTaken) {
|
||||
TEST(SerializationContext,
|
||||
WhenMultipleConvertibleTypesExistsThenFirstMatchIsTaken)
|
||||
{
|
||||
{
|
||||
using CTX1 = std::tuple<Base, int, Derived>;
|
||||
CTX1 ctx1{};
|
||||
@@ -102,7 +111,8 @@ TEST(SerializationContext, WhenMultipleConvertibleTypesExistsThenFirstMatchIsTak
|
||||
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
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,23 +20,24 @@
|
||||
// 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
|
||||
getValue(bool isPositive, size_t significantBits)
|
||||
{
|
||||
TValue v = isPositive ? 0 : static_cast<TValue>(-1);
|
||||
if (significantBits == 0)
|
||||
return v;
|
||||
@@ -52,31 +53,38 @@ TValue getValue(bool isPositive, size_t significantBits) {
|
||||
|
||||
// helper function, that serialize and return deserialized value
|
||||
template<typename TConfig, typename TValue>
|
||||
std::pair<TValue, size_t> serializeAndGetDeserialized(TValue data) {
|
||||
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()};
|
||||
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 {
|
||||
struct LittleEndianConfig
|
||||
{
|
||||
static constexpr EndiannessType Endianness = EndiannessType::LittleEndian;
|
||||
static constexpr bool CheckDataErrors = true;
|
||||
static constexpr bool CheckAdapterErrors = true;
|
||||
};
|
||||
|
||||
struct BigEndianConfig {
|
||||
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 {
|
||||
struct TC
|
||||
{
|
||||
static_assert(isPositiveNr || std::is_signed<TValue>::value, "");
|
||||
|
||||
using Value = TValue;
|
||||
@@ -85,14 +93,14 @@ struct TC {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class SerializeExtensionCompactValueCorrectness : public testing::Test {
|
||||
class SerializeExtensionCompactValueCorrectness : public testing::Test
|
||||
{
|
||||
public:
|
||||
using TestCase = T;
|
||||
};
|
||||
|
||||
|
||||
using AllValueSizesTestCases = ::testing::Types<
|
||||
TC<uint8_t, true, LittleEndianConfig>,
|
||||
using AllValueSizesTestCases =
|
||||
::testing::Types<TC<uint8_t, true, LittleEndianConfig>,
|
||||
TC<uint16_t, true, LittleEndianConfig>,
|
||||
TC<uint32_t, true, LittleEndianConfig>,
|
||||
TC<uint64_t, true, LittleEndianConfig>,
|
||||
@@ -115,12 +123,13 @@ using AllValueSizesTestCases = ::testing::Types<
|
||||
TC<int8_t, false, BigEndianConfig>,
|
||||
TC<int16_t, false, BigEndianConfig>,
|
||||
TC<int32_t, false, BigEndianConfig>,
|
||||
TC<int64_t, false, BigEndianConfig>
|
||||
>;
|
||||
TC<int64_t, false, BigEndianConfig>>;
|
||||
|
||||
TYPED_TEST_SUITE(SerializeExtensionCompactValueCorrectness, AllValueSizesTestCases,);
|
||||
TYPED_TEST_SUITE(SerializeExtensionCompactValueCorrectness,
|
||||
AllValueSizesTestCases, );
|
||||
|
||||
TYPED_TEST(SerializeExtensionCompactValueCorrectness, TestDifferentSizeValues) {
|
||||
TYPED_TEST(SerializeExtensionCompactValueCorrectness, TestDifferentSizeValues)
|
||||
{
|
||||
using TCase = typename TestFixture::TestCase;
|
||||
using TValue = typename TCase::Value;
|
||||
TCase tc{};
|
||||
@@ -132,12 +141,16 @@ TYPED_TEST(SerializeExtensionCompactValueCorrectness, TestDifferentSizeValues) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// this stucture will contain test data and result, as type paramters
|
||||
template <typename TValue, bool isPositiveNr, size_t significantBits, size_t resultBytes>
|
||||
struct SizeTC {
|
||||
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, "");
|
||||
static_assert(bitsery::details::BitsSize<TValue>::value >= significantBits,
|
||||
"");
|
||||
|
||||
using Value = TValue;
|
||||
bool isPositive = isPositiveNr;
|
||||
@@ -146,7 +159,8 @@ struct SizeTC {
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class SerializeExtensionCompactValueRequiredBytes : public testing::Test {
|
||||
class SerializeExtensionCompactValueRequiredBytes : public testing::Test
|
||||
{
|
||||
public:
|
||||
using TestCase = T;
|
||||
};
|
||||
@@ -182,7 +196,8 @@ using RequiredBytesTestCases = ::testing::Types<
|
||||
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
|
||||
// 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>,
|
||||
@@ -199,12 +214,13 @@ using RequiredBytesTestCases = ::testing::Types<
|
||||
SizeTC<int64_t, true, 55, 8>,
|
||||
SizeTC<int64_t, false, 56, 9>,
|
||||
SizeTC<int64_t, true, 62, 9>,
|
||||
SizeTC<int64_t, false, 63,10>
|
||||
>;
|
||||
SizeTC<int64_t, false, 63, 10>>;
|
||||
|
||||
TYPED_TEST_SUITE(SerializeExtensionCompactValueRequiredBytes, RequiredBytesTestCases,);
|
||||
TYPED_TEST_SUITE(SerializeExtensionCompactValueRequiredBytes,
|
||||
RequiredBytesTestCases, );
|
||||
|
||||
TYPED_TEST(SerializeExtensionCompactValueRequiredBytes, Test) {
|
||||
TYPED_TEST(SerializeExtensionCompactValueRequiredBytes, Test)
|
||||
{
|
||||
using TCase = typename TestFixture::TestCase;
|
||||
using TValue = typename TCase::Value;
|
||||
TCase tc{};
|
||||
@@ -214,31 +230,47 @@ TYPED_TEST(SerializeExtensionCompactValueRequiredBytes, Test) {
|
||||
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) {
|
||||
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));
|
||||
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) {
|
||||
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));
|
||||
EXPECT_THAT(ctx.des->adapter().error(),
|
||||
Eq(bitsery::ReaderError::InvalidData));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,12 +20,11 @@
|
||||
// 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,15 +33,15 @@ using bitsery::ext::Entropy;
|
||||
using BPSer = SerializationContext::TSerializerBPEnabled;
|
||||
using BPDes = SerializationContext::TDeserializerBPEnabled;
|
||||
|
||||
|
||||
TEST(SerializeExtensionEntropy, WhenEntropyEncodedThenOnlyWriteIndexUsingMinRequiredBits) {
|
||||
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.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 });
|
||||
});
|
||||
@@ -51,16 +50,18 @@ TEST(SerializeExtensionEntropy, WhenEntropyEncodedThenOnlyWriteIndexUsingMinRequ
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
|
||||
|
||||
SerializationContext ctx1{};
|
||||
ctx1.createSerializer().enableBitPacking([&v, &values](BPSer& ser) {
|
||||
ser.ext4b(v, Entropy<int32_t[3]>{values});
|
||||
});
|
||||
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)});
|
||||
des.ext(
|
||||
res, bitsery::ext::ValueRange<int32_t>{ 0, static_cast<int32_t>(3 + 1) });
|
||||
});
|
||||
EXPECT_THAT(res, Eq(2));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionEntropy, WhenNoEntropyEncodedThenWriteZeroBitsAndValueOrObject) {
|
||||
TEST(SerializeExtensionEntropy,
|
||||
WhenNoEntropyEncodedThenWriteZeroBitsAndValueOrObject)
|
||||
{
|
||||
int16_t v = 8945;
|
||||
int16_t res;
|
||||
std::initializer_list<int> values{ 485, 4849, 89 };
|
||||
@@ -76,18 +77,19 @@ TEST(SerializeExtensionEntropy, WhenNoEntropyEncodedThenWriteZeroBitsAndValueOrO
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(sizeof(int16_t) + 1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionEntropy, CustomTypeEntropyEncoded) {
|
||||
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}};
|
||||
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.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 });
|
||||
});
|
||||
@@ -95,13 +97,15 @@ TEST(SerializeExtensionEntropy, CustomTypeEntropyEncoded) {
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionEntropy, CustomTypeNotEntropyEncoded) {
|
||||
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}};
|
||||
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 });
|
||||
@@ -114,20 +118,25 @@ TEST(SerializeExtensionEntropy, CustomTypeNotEntropyEncoded) {
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(MyStruct1::SIZE + 1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncodedWithNoAlignBeforeData) {
|
||||
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 };
|
||||
|
||||
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...
|
||||
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);
|
||||
@@ -135,7 +144,8 @@ TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncodedWithNoAlignBefore
|
||||
ser.ext(v, Entropy<std::vector<MyStruct1>>(values, false), serLambda);
|
||||
});
|
||||
|
||||
ctx.createDeserializer().enableBitPacking([&res, &values, &rangeForValue](BPDes& des) {
|
||||
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);
|
||||
@@ -145,29 +155,39 @@ TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncodedWithNoAlignBefore
|
||||
|
||||
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(ctx.getBufferSize(),
|
||||
Eq((rangeForIndex.getRequiredBits() +
|
||||
rangeForValue.getRequiredBits() * 2 - 1) /
|
||||
8 +
|
||||
1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncodedWithAlignBeforeData) {
|
||||
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 };
|
||||
|
||||
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...
|
||||
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) {
|
||||
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);
|
||||
@@ -177,22 +197,29 @@ TEST(SerializeExtensionEntropy, CustomFunctionNotEntropyEncodedWithAlignBeforeDa
|
||||
|
||||
EXPECT_THAT(res, Eq(v));
|
||||
auto bitsForIndex = 8u; // because aligned
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq((bitsForIndex + rangeForValue.getRequiredBits() * 2 - 1) / 8 + 1 ));
|
||||
EXPECT_THAT(
|
||||
ctx.getBufferSize(),
|
||||
Eq((bitsForIndex + rangeForValue.getRequiredBits() * 2 - 1) / 8 + 1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionEntropy, WhenEntropyEncodedThenCustomFunctionNotInvoked) {
|
||||
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& ) {});
|
||||
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& ) {});
|
||||
des.ext(
|
||||
res, Entropy<std::list<MyStruct1>>{ values }, [](BPDes&, MyStruct1&) {});
|
||||
});
|
||||
|
||||
EXPECT_THAT(res, Eq(v));
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,48 +20,57 @@
|
||||
// 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 {
|
||||
struct DataV1
|
||||
{
|
||||
int32_t v1;
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, DataV1& o) {
|
||||
void
|
||||
serialize(S& s, DataV1& o)
|
||||
{
|
||||
s.value4b(o.v1);
|
||||
}
|
||||
|
||||
struct DataV2 {
|
||||
struct DataV2
|
||||
{
|
||||
int32_t v1;
|
||||
int32_t v2;
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, DataV2& o) {
|
||||
void
|
||||
serialize(S& s, DataV2& o)
|
||||
{
|
||||
s.value4b(o.v1);
|
||||
s.value4b(o.v2);
|
||||
}
|
||||
|
||||
struct DataV3 {
|
||||
struct DataV3
|
||||
{
|
||||
int32_t v1;
|
||||
int32_t v2;
|
||||
int32_t v3;
|
||||
template<typename S>
|
||||
void serialize(S& s) {
|
||||
void serialize(S& s)
|
||||
{
|
||||
s.value4b(v1);
|
||||
s.value4b(v2);
|
||||
s.value4b(v3);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
TEST(SerializeExtensionGrowable, SessionsLengthIsStoredWith4BytesBeforeSessionDataStarts) {
|
||||
TEST(SerializeExtensionGrowable,
|
||||
SessionsLengthIsStoredWith4BytesBeforeSessionDataStarts)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
auto& ser = ctx.createSerializer();
|
||||
// session cannot be empty
|
||||
@@ -86,7 +95,8 @@ TEST(SerializeExtensionGrowable, SessionsLengthIsStoredWith4BytesBeforeSessionDa
|
||||
EXPECT_THAT(ctx.ser->adapter().writtenBytesCount(), Eq(8));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionGrowable, MultipleSessionsReadSameVersionData) {
|
||||
TEST(SerializeExtensionGrowable, MultipleSessionsReadSameVersionData)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
DataV2 data{ 8454, 987451 };
|
||||
auto& ser = ctx.createSerializer();
|
||||
@@ -105,7 +115,8 @@ TEST(SerializeExtensionGrowable, MultipleSessionsReadSameVersionData) {
|
||||
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionGrowable, MultipleSessionsReadNewerVersionData) {
|
||||
TEST(SerializeExtensionGrowable, MultipleSessionsReadNewerVersionData)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
DataV3 data{ 8454, 987451, 45612 };
|
||||
auto& ser = ctx.createSerializer();
|
||||
@@ -124,7 +135,8 @@ TEST(SerializeExtensionGrowable, MultipleSessionsReadNewerVersionData) {
|
||||
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionGrowable, MultipleSessionsReadOlderVersionData) {
|
||||
TEST(SerializeExtensionGrowable, MultipleSessionsReadOlderVersionData)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
DataV2 data{ 8454, 987451 };
|
||||
auto& ser = ctx.createSerializer();
|
||||
@@ -144,7 +156,8 @@ TEST(SerializeExtensionGrowable, MultipleSessionsReadOlderVersionData) {
|
||||
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadSameVersionData) {
|
||||
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadSameVersionData)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
DataV2 data{ 8454, 987451 };
|
||||
auto& ser = ctx.createSerializer();
|
||||
@@ -173,7 +186,8 @@ TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadSameVersionData) {
|
||||
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadNewerVersionData) {
|
||||
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadNewerVersionData)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
DataV3 data{ 8454, 987451, 54124 };
|
||||
auto& ser = ctx.createSerializer();
|
||||
@@ -204,7 +218,8 @@ TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadNewerVersionData) {
|
||||
EXPECT_THAT(ctx.des->adapter().isCompletedSuccessfully(), Eq(true));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadOlderVersionData) {
|
||||
TEST(SerializeExtensionGrowable, MultipleNestedSessionsReadOlderVersionData)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
DataV2 data{ 8454, 987451 };
|
||||
auto& ser = ctx.createSerializer();
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,9 +20,9 @@
|
||||
// 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,48 +34,60 @@ using testing::Eq;
|
||||
/*
|
||||
* base class
|
||||
*/
|
||||
struct Base {
|
||||
struct Base
|
||||
{
|
||||
uint8_t x{};
|
||||
virtual ~Base() = default;
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, Base& o) {
|
||||
void
|
||||
serialize(S& s, Base& o)
|
||||
{
|
||||
s.value1b(o.x);
|
||||
}
|
||||
|
||||
/*
|
||||
* non virtual inheritance from base
|
||||
*/
|
||||
struct Derive1NonVirtually:Base {
|
||||
struct Derive1NonVirtually : Base
|
||||
{
|
||||
uint8_t y1{};
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, Derive1NonVirtually& o) {
|
||||
void
|
||||
serialize(S& s, Derive1NonVirtually& o)
|
||||
{
|
||||
s.ext(o, BaseClass<Base>{});
|
||||
s.value1b(o.y1);
|
||||
}
|
||||
|
||||
struct Derive2NonVirtually:Base {
|
||||
struct Derive2NonVirtually : Base
|
||||
{
|
||||
uint8_t y2{};
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, Derive2NonVirtually& o) {
|
||||
void
|
||||
serialize(S& s, Derive2NonVirtually& o)
|
||||
{
|
||||
// use lambda to serialize base
|
||||
s.ext(o, BaseClass<Base>{}, [](S& s, Base& b) {
|
||||
s.object(b);
|
||||
});
|
||||
s.ext(o, BaseClass<Base>{}, [](S& s, Base& b) { s.object(b); });
|
||||
s.value1b(o.y2);
|
||||
}
|
||||
|
||||
struct MultipleInheritanceNonVirtualBase: Derive1NonVirtually, Derive2NonVirtually {
|
||||
struct MultipleInheritanceNonVirtualBase
|
||||
: Derive1NonVirtually
|
||||
, Derive2NonVirtually
|
||||
{
|
||||
uint8_t z{};
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, MultipleInheritanceNonVirtualBase& o) {
|
||||
void
|
||||
serialize(S& s, MultipleInheritanceNonVirtualBase& o)
|
||||
{
|
||||
s.ext(o, BaseClass<Derive1NonVirtually>{});
|
||||
s.ext(o, BaseClass<Derive2NonVirtually>{});
|
||||
s.value1b(o.z);
|
||||
@@ -84,31 +96,44 @@ void serialize(S& s, MultipleInheritanceNonVirtualBase& o) {
|
||||
/*
|
||||
* virtual inheritance from base
|
||||
*/
|
||||
struct Derive1Virtually:virtual Base {
|
||||
struct Derive1Virtually : virtual Base
|
||||
{
|
||||
uint8_t y1{};
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, Derive1Virtually& o) {
|
||||
void
|
||||
serialize(S& s, Derive1Virtually& o)
|
||||
{
|
||||
s.ext(o, VirtualBaseClass<Base>{});
|
||||
s.value1b(o.y1);
|
||||
}
|
||||
|
||||
struct Derive2Virtually:virtual Base {
|
||||
struct Derive2Virtually : virtual Base
|
||||
{
|
||||
uint8_t y2{};
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, Derive2Virtually& o) {
|
||||
void
|
||||
serialize(S& s, Derive2Virtually& o)
|
||||
{
|
||||
s.ext(o, VirtualBaseClass<Base>{});
|
||||
s.value1b(o.y2);
|
||||
}
|
||||
|
||||
struct MultipleInheritanceVirtualBase: Derive1Virtually, Derive2Virtually {
|
||||
struct MultipleInheritanceVirtualBase
|
||||
: Derive1Virtually
|
||||
, Derive2Virtually
|
||||
{
|
||||
uint8_t z{};
|
||||
MultipleInheritanceVirtualBase() = default;
|
||||
|
||||
MultipleInheritanceVirtualBase(uint8_t x_, uint8_t y1_, uint8_t y2_, uint8_t z_) {
|
||||
MultipleInheritanceVirtualBase(uint8_t x_,
|
||||
uint8_t y1_,
|
||||
uint8_t y2_,
|
||||
uint8_t z_)
|
||||
{
|
||||
x = x_;
|
||||
y1 = y1_;
|
||||
y2 = y2_;
|
||||
@@ -116,19 +141,24 @@ struct MultipleInheritanceVirtualBase: Derive1Virtually, Derive2Virtually {
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& 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;
|
||||
@@ -146,7 +176,8 @@ TEST(SerializeExtensionInheritance, BaseClass) {
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionInheritance, VirtualBaseClass) {
|
||||
TEST(SerializeExtensionInheritance, VirtualBaseClass)
|
||||
{
|
||||
Derive1Virtually d1{};
|
||||
d1.x = 15;
|
||||
d1.y1 = 87;
|
||||
@@ -163,7 +194,8 @@ TEST(SerializeExtensionInheritance, VirtualBaseClass) {
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionInheritance, MultipleBasesWithoutVirtualInheritance) {
|
||||
TEST(SerializeExtensionInheritance, MultipleBasesWithoutVirtualInheritance)
|
||||
{
|
||||
MultipleInheritanceNonVirtualBase md{};
|
||||
// x is ambiguous because we don't derive virtually
|
||||
static_cast<Derive1NonVirtually&>(md).x = 1;
|
||||
@@ -179,16 +211,19 @@ TEST(SerializeExtensionInheritance, MultipleBasesWithoutVirtualInheritance) {
|
||||
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(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) {
|
||||
TEST(SerializeExtensionInheritance,
|
||||
WhenNoVirtualInheritanceExistsThenInheritanceContextIsNotRequired)
|
||||
{
|
||||
MultipleInheritanceNonVirtualBase md{};
|
||||
// x is ambiguous because we don't derive virtually
|
||||
static_cast<Derive1NonVirtually&>(md).x = 1;
|
||||
@@ -203,18 +238,18 @@ TEST(SerializeExtensionInheritance, WhenNoVirtualInheritanceExistsThenInheritanc
|
||||
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(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) {
|
||||
TEST(SerializeExtensionInheritance, MultipleBasesWithVirtualInheritance)
|
||||
{
|
||||
MultipleInheritanceVirtualBase md{ 3, 7, 5, 15 };
|
||||
MultipleInheritanceVirtualBase res{};
|
||||
|
||||
@@ -227,7 +262,9 @@ TEST(SerializeExtensionInheritance, MultipleBasesWithVirtualInheritance) {
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(4)); // 4 because virtual base
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionInheritance, MultipleBasesWithVirtualInheritanceMultipleObjects) {
|
||||
TEST(SerializeExtensionInheritance,
|
||||
MultipleBasesWithVirtualInheritanceMultipleObjects)
|
||||
{
|
||||
std::vector<MultipleInheritanceVirtualBase> data;
|
||||
data.emplace_back(4, 8, 7, 9);
|
||||
data.emplace_back(1, 2, 3, 4);
|
||||
@@ -242,70 +279,96 @@ TEST(SerializeExtensionInheritance, MultipleBasesWithVirtualInheritanceMultipleO
|
||||
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
|
||||
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} {}
|
||||
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) {
|
||||
void serialize(S& s)
|
||||
{
|
||||
s.value1b(_v);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class DerivedPrivateBase: public BasePrivateSerialize {
|
||||
class DerivedPrivateBase : public BasePrivateSerialize
|
||||
{
|
||||
public:
|
||||
explicit DerivedPrivateBase(uint8_t v) : BasePrivateSerialize(v) {}
|
||||
explicit DerivedPrivateBase(uint8_t v)
|
||||
: BasePrivateSerialize(v)
|
||||
{
|
||||
}
|
||||
uint8_t z{};
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, DerivedPrivateBase& o) {
|
||||
void
|
||||
serialize(S& s, DerivedPrivateBase& o)
|
||||
{
|
||||
// use lambda for base serialization
|
||||
s.ext(o, BaseClass<BasePrivateSerialize>{}, [](S& s, BasePrivateSerialize& b) {
|
||||
s.object(b);
|
||||
});
|
||||
s.ext(o,
|
||||
BaseClass<BasePrivateSerialize>{},
|
||||
[](S& s, BasePrivateSerialize& b) { s.object(b); });
|
||||
s.value1b(o.z);
|
||||
}
|
||||
|
||||
struct BaseNonMemberSerialize {
|
||||
struct BaseNonMemberSerialize
|
||||
{
|
||||
uint8_t x{};
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, BaseNonMemberSerialize& o) {
|
||||
void
|
||||
serialize(S& s, BaseNonMemberSerialize& o)
|
||||
{
|
||||
s.value1b(o.x);
|
||||
}
|
||||
|
||||
|
||||
struct DerivedMemberSerialize: public BaseNonMemberSerialize {
|
||||
struct DerivedMemberSerialize : public BaseNonMemberSerialize
|
||||
{
|
||||
uint8_t z{};
|
||||
template<typename S>
|
||||
void serialize(S& 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 {};
|
||||
struct SelectSerializeFnc<DerivedPrivateBase> : UseNonMemberFnc
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SelectSerializeFnc<DerivedMemberSerialize>:UseMemberFnc {};
|
||||
struct SelectSerializeFnc<DerivedMemberSerialize> : UseMemberFnc
|
||||
{
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
TEST(SerializeExtensionInheritance, WhenDerivedClassHasAmbiguousSerializeFunctionThenExplicitlySelectSpecialization) {
|
||||
TEST(
|
||||
SerializeExtensionInheritance,
|
||||
WhenDerivedClassHasAmbiguousSerializeFunctionThenExplicitlySelectSpecialization)
|
||||
{
|
||||
DerivedPrivateBase data1{ 43 };
|
||||
data1.z = 87;
|
||||
DerivedMemberSerialize data2{};
|
||||
@@ -327,29 +390,34 @@ TEST(SerializeExtensionInheritance, WhenDerivedClassHasAmbiguousSerializeFunctio
|
||||
EXPECT_THAT(res2.z, Eq(data2.z));
|
||||
}
|
||||
|
||||
struct AbstractBase {
|
||||
struct AbstractBase
|
||||
{
|
||||
uint8_t x{};
|
||||
virtual void exec() = 0;
|
||||
virtual ~AbstractBase() = default;
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s) {
|
||||
void serialize(S& s)
|
||||
{
|
||||
s.value1b(x);
|
||||
}
|
||||
};
|
||||
|
||||
struct ImplementedBase:AbstractBase {
|
||||
struct ImplementedBase : AbstractBase
|
||||
{
|
||||
uint8_t y{};
|
||||
void exec() override {}
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s) {
|
||||
void serialize(S& s)
|
||||
{
|
||||
s.ext(*this, BaseClass<AbstractBase>{});
|
||||
s.value1b(y);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(SerializeExtensionInheritance, CanSerializeAbstractClass) {
|
||||
TEST(SerializeExtensionInheritance, CanSerializeAbstractClass)
|
||||
{
|
||||
ImplementedBase data{};
|
||||
data.x = 4;
|
||||
data.y = 2;
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,21 +20,22 @@
|
||||
// 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/pointer.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include "serialization_test_utils.h"
|
||||
|
||||
using bitsery::ext::PointerOwner;
|
||||
using bitsery::ext::PointerObserver;
|
||||
using bitsery::ext::ReferencedByPointer;
|
||||
using bitsery::ext::PointerLinkingContext;
|
||||
using bitsery::ext::PointerObserver;
|
||||
using bitsery::ext::PointerOwner;
|
||||
using bitsery::ext::PointerType;
|
||||
using bitsery::ext::ReferencedByPointer;
|
||||
|
||||
using testing::Eq;
|
||||
|
||||
using SerContext = BasicSerializationContext<PointerLinkingContext>;
|
||||
|
||||
class SerializeExtensionPointerSerialization : public testing::Test {
|
||||
class SerializeExtensionPointerSerialization : public testing::Test
|
||||
{
|
||||
public:
|
||||
// data used for serialization
|
||||
int16_t d1{ 1597 };
|
||||
@@ -60,22 +61,21 @@ public:
|
||||
PointerLinkingContext plctx1{};
|
||||
SerContext sctx1{};
|
||||
|
||||
|
||||
typename SerContext::TSerializer& createSerializer() {
|
||||
typename SerContext::TSerializer& createSerializer()
|
||||
{
|
||||
return sctx1.createSerializer(plctx1);
|
||||
}
|
||||
|
||||
typename SerContext::TDeserializer& createDeserializer() {
|
||||
typename SerContext::TDeserializer& createDeserializer()
|
||||
{
|
||||
return sctx1.createDeserializer(plctx1);
|
||||
}
|
||||
|
||||
bool isPointerContextValid() {
|
||||
return plctx1.isValid();
|
||||
}
|
||||
|
||||
bool isPointerContextValid() { return plctx1.isValid(); }
|
||||
};
|
||||
|
||||
TEST(SerializeExtensionPointer, RequiresPointerLinkingContext) {
|
||||
TEST(SerializeExtensionPointer, RequiresPointerLinkingContext)
|
||||
{
|
||||
MyStruct1* data = nullptr;
|
||||
// linking context
|
||||
PointerLinkingContext plctx1{};
|
||||
@@ -91,18 +91,34 @@ TEST(SerializeExtensionPointer, RequiresPointerLinkingContext) {
|
||||
sctx2.createDeserializer(plctx2).ext(data, PointerObserver{});
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionPointer, PointerLinkingContextAcceptsMultipleSharedOwnersAndReturnSameId) {
|
||||
TEST(SerializeExtensionPointer,
|
||||
PointerLinkingContextAcceptsMultipleSharedOwnersAndReturnSameId)
|
||||
{
|
||||
MyStruct1 data{};
|
||||
// pretend that this is shared ptr
|
||||
MyStruct1* sharedPtr = &data;
|
||||
// linking context
|
||||
PointerLinkingContext plctx1{};
|
||||
EXPECT_THAT(plctx1.getInfoByPtr(sharedPtr, bitsery::ext::PointerOwnershipType::SharedOwner).id, Eq(1));
|
||||
EXPECT_THAT(plctx1.getInfoByPtr(sharedPtr, bitsery::ext::PointerOwnershipType::SharedObserver).id, Eq(1));
|
||||
EXPECT_THAT(plctx1.getInfoByPtr(sharedPtr, bitsery::ext::PointerOwnershipType::SharedOwner).id, Eq(1));
|
||||
EXPECT_THAT(
|
||||
plctx1
|
||||
.getInfoByPtr(sharedPtr, bitsery::ext::PointerOwnershipType::SharedOwner)
|
||||
.id,
|
||||
Eq(1));
|
||||
EXPECT_THAT(plctx1
|
||||
.getInfoByPtr(
|
||||
sharedPtr, bitsery::ext::PointerOwnershipType::SharedObserver)
|
||||
.id,
|
||||
Eq(1));
|
||||
EXPECT_THAT(
|
||||
plctx1
|
||||
.getInfoByPtr(sharedPtr, bitsery::ext::PointerOwnershipType::SharedOwner)
|
||||
.id,
|
||||
Eq(1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionPointer, WhenOnlySharedObserverThenPointerLinkingContextIsInvalid) {
|
||||
TEST(SerializeExtensionPointer,
|
||||
WhenOnlySharedObserverThenPointerLinkingContextIsInvalid)
|
||||
{
|
||||
MyStruct1 data1{};
|
||||
MyStruct1 data2{};
|
||||
// pretend that this is shared ptr
|
||||
@@ -110,16 +126,40 @@ TEST(SerializeExtensionPointer, WhenOnlySharedObserverThenPointerLinkingContextI
|
||||
MyStruct1* sharedPtr2 = &data2;
|
||||
// linking context
|
||||
PointerLinkingContext plctx1{};
|
||||
EXPECT_THAT(plctx1.getInfoByPtr(sharedPtr1, bitsery::ext::PointerOwnershipType::SharedObserver).id, Eq(1));
|
||||
EXPECT_THAT(plctx1.getInfoByPtr(sharedPtr2, bitsery::ext::PointerOwnershipType::SharedObserver).id, Eq(2));
|
||||
EXPECT_THAT(plctx1.getInfoByPtr(sharedPtr1, bitsery::ext::PointerOwnershipType::SharedObserver).id, Eq(1));
|
||||
EXPECT_THAT(
|
||||
plctx1
|
||||
.getInfoByPtr(sharedPtr1,
|
||||
bitsery::ext::PointerOwnershipType::SharedObserver)
|
||||
.id,
|
||||
Eq(1));
|
||||
EXPECT_THAT(
|
||||
plctx1
|
||||
.getInfoByPtr(sharedPtr2,
|
||||
bitsery::ext::PointerOwnershipType::SharedObserver)
|
||||
.id,
|
||||
Eq(2));
|
||||
EXPECT_THAT(
|
||||
plctx1
|
||||
.getInfoByPtr(sharedPtr1,
|
||||
bitsery::ext::PointerOwnershipType::SharedObserver)
|
||||
.id,
|
||||
Eq(1));
|
||||
EXPECT_FALSE(plctx1.isValid());
|
||||
EXPECT_THAT(plctx1.getInfoByPtr(sharedPtr1, bitsery::ext::PointerOwnershipType::SharedOwner).id, Eq(1));
|
||||
EXPECT_THAT(plctx1.getInfoByPtr(sharedPtr2, bitsery::ext::PointerOwnershipType::SharedOwner).id, Eq(2));
|
||||
EXPECT_THAT(
|
||||
plctx1
|
||||
.getInfoByPtr(sharedPtr1, bitsery::ext::PointerOwnershipType::SharedOwner)
|
||||
.id,
|
||||
Eq(1));
|
||||
EXPECT_THAT(
|
||||
plctx1
|
||||
.getInfoByPtr(sharedPtr2, bitsery::ext::PointerOwnershipType::SharedOwner)
|
||||
.id,
|
||||
Eq(2));
|
||||
EXPECT_TRUE(plctx1.isValid());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerSerialization, WhenPointersAreNullThenIsValid) {
|
||||
TEST_F(SerializeExtensionPointerSerialization, WhenPointersAreNullThenIsValid)
|
||||
{
|
||||
|
||||
auto& ser = createSerializer();
|
||||
ser.ext2b(p1null, PointerOwner{});
|
||||
@@ -134,7 +174,9 @@ TEST_F(SerializeExtensionPointerSerialization, WhenPointersAreNullThenIsValid) {
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
||||
TEST_F(SerializeExtensionPointerSerialization, WhenPointerOwnerIsNotUniqueThenAssert) {
|
||||
TEST_F(SerializeExtensionPointerSerialization,
|
||||
WhenPointerOwnerIsNotUniqueThenAssert)
|
||||
{
|
||||
|
||||
auto& ser = createSerializer();
|
||||
ser.ext2b(p1null, PointerOwner{});
|
||||
@@ -145,7 +187,9 @@ TEST_F(SerializeExtensionPointerSerialization, WhenPointerOwnerIsNotUniqueThenAs
|
||||
EXPECT_DEATH(ser.ext2b(pd1, PointerOwner{}), "");
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerSerialization, WhenRererencedByPointerIsSameAsPointerOwnerThenAssert1) {
|
||||
TEST_F(SerializeExtensionPointerSerialization,
|
||||
WhenRererencedByPointerIsSameAsPointerOwnerThenAssert1)
|
||||
{
|
||||
auto& ser1 = createSerializer();
|
||||
ser1.ext4b(pd2, PointerOwner{});
|
||||
ser1.ext(d3, ReferencedByPointer{});
|
||||
@@ -153,14 +197,18 @@ TEST_F(SerializeExtensionPointerSerialization, WhenRererencedByPointerIsSameAsPo
|
||||
EXPECT_DEATH(ser1.ext(pd3, PointerOwner{}), "");
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerSerialization, WhenRererencedByPointerIsSameAsPointerOwnerThenAssert2) {
|
||||
TEST_F(SerializeExtensionPointerSerialization,
|
||||
WhenRererencedByPointerIsSameAsPointerOwnerThenAssert2)
|
||||
{
|
||||
auto& ser1 = createSerializer();
|
||||
ser1.ext2b(pd1, PointerOwner{});
|
||||
ser1.ext4b(d2, ReferencedByPointer{});
|
||||
EXPECT_DEATH(ser1.ext2b(d1, ReferencedByPointer{}), "");
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerSerialization, WhenNonNullPointerIsNullThenAssert) {
|
||||
TEST_F(SerializeExtensionPointerSerialization,
|
||||
WhenNonNullPointerIsNullThenAssert)
|
||||
{
|
||||
auto& ser1 = createSerializer();
|
||||
EXPECT_DEATH(ser1.ext2b(p1null, PointerOwner{ PointerType::NotNull }), "");
|
||||
EXPECT_DEATH(ser1.ext2b(p1null, PointerObserver{ PointerType::NotNull }), "");
|
||||
@@ -168,32 +216,45 @@ TEST_F(SerializeExtensionPointerSerialization, WhenNonNullPointerIsNullThenAsser
|
||||
|
||||
#endif
|
||||
|
||||
TEST_F(SerializeExtensionPointerSerialization, WhenPointerObserverPointsToOwnerThenIsValid) {
|
||||
TEST_F(SerializeExtensionPointerSerialization,
|
||||
WhenPointerObserverPointsToOwnerThenIsValid)
|
||||
{
|
||||
auto& ser1 = createSerializer();
|
||||
ser1.ext2b(pd1, PointerOwner{});
|
||||
ser1.ext2b(p1null, PointerObserver{});
|
||||
EXPECT_THAT(plctx1.isValid(), Eq(true));
|
||||
ser1.ext4b(pd2, PointerObserver{});//points to d2, and d2 is not still marked as owner
|
||||
ser1.ext4b(
|
||||
pd2,
|
||||
PointerObserver{}); // points to d2, and d2 is not still marked as owner
|
||||
EXPECT_THAT(plctx1.isValid(), Eq(false));
|
||||
ser1.ext4b(pd2, PointerOwner{}); // now d2 is owning pointer
|
||||
ser1.ext4b(pd2, PointerObserver{});//points to d2, but this time d2 has owner
|
||||
ser1.ext4b(pd2, PointerObserver{}); // points to d2, but this time d2 has
|
||||
// owner
|
||||
ser1.ext2b(p1null, PointerObserver{});
|
||||
EXPECT_THAT(plctx1.isValid(), Eq(true));
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerSerialization, ReferenceTypeCanAlsoBeReferencedByPointerObservers) {
|
||||
TEST_F(SerializeExtensionPointerSerialization,
|
||||
ReferenceTypeCanAlsoBeReferencedByPointerObservers)
|
||||
{
|
||||
auto& ser1 = createSerializer();
|
||||
ser1.ext2b(p1null, PointerObserver{});
|
||||
EXPECT_THAT(plctx1.isValid(), Eq(true));
|
||||
ser1.ext4b(pd2, PointerObserver{});//points to d2, and d2 is not still marked as owner
|
||||
ser1.ext4b(
|
||||
pd2,
|
||||
PointerObserver{}); // points to d2, and d2 is not still marked as owner
|
||||
EXPECT_THAT(plctx1.isValid(), Eq(false));
|
||||
ser1.ext4b(d2, ReferencedByPointer{});//now d2 is marked by marked as owning pointer
|
||||
ser1.ext4b(pd2, PointerObserver{});//points to d2, but this time d2 has owner
|
||||
ser1.ext4b(
|
||||
d2, ReferencedByPointer{}); // now d2 is marked by marked as owning pointer
|
||||
ser1.ext4b(pd2, PointerObserver{}); // points to d2, but this time d2 has
|
||||
// owner
|
||||
ser1.ext(p3null, PointerObserver{});
|
||||
EXPECT_THAT(plctx1.isValid(), Eq(true));
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerSerialization, WhenPointerIsNullThenPointerIdIsZero) {
|
||||
TEST_F(SerializeExtensionPointerSerialization,
|
||||
WhenPointerIsNullThenPointerIdIsZero)
|
||||
{
|
||||
auto& ser1 = createSerializer();
|
||||
ser1.ext(p3null, PointerOwner{});
|
||||
ser1.ext2b(p1null, PointerObserver{});
|
||||
@@ -206,7 +267,8 @@ TEST_F(SerializeExtensionPointerSerialization, WhenPointerIsNullThenPointerIdIsZ
|
||||
EXPECT_THAT(res, Eq(0));
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerSerialization, PointerIdsStartsFromOne) {
|
||||
TEST_F(SerializeExtensionPointerSerialization, PointerIdsStartsFromOne)
|
||||
{
|
||||
auto& ser1 = createSerializer();
|
||||
ser1.ext2b(pd1, PointerObserver{});
|
||||
ser1.ext4b(pd2, PointerObserver{});
|
||||
@@ -225,7 +287,9 @@ TEST_F(SerializeExtensionPointerSerialization, PointerIdsStartsFromOne) {
|
||||
EXPECT_THAT(res, Eq(0));
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerSerialization, PointerObserversDoesntSerializeObject) {
|
||||
TEST_F(SerializeExtensionPointerSerialization,
|
||||
PointerObserversDoesntSerializeObject)
|
||||
{
|
||||
auto& ser1 = createSerializer();
|
||||
ser1.ext2b(pd1, PointerObserver{});
|
||||
ser1.ext4b(pd2, PointerObserver{});
|
||||
@@ -234,7 +298,9 @@ TEST_F(SerializeExtensionPointerSerialization, PointerObserversDoesntSerializeOb
|
||||
EXPECT_THAT(sctx1.ser->adapter().writtenBytesCount(), Eq(3));
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerSerialization, ReferencedByPointerSerializesIdAndObject) {
|
||||
TEST_F(SerializeExtensionPointerSerialization,
|
||||
ReferencedByPointerSerializesIdAndObject)
|
||||
{
|
||||
auto& ser1 = createSerializer();
|
||||
ser1.ext2b(d1, ReferencedByPointer{});
|
||||
ser1.ext4b(d2, ReferencedByPointer{});
|
||||
@@ -254,13 +320,16 @@ TEST_F(SerializeExtensionPointerSerialization, ReferencedByPointerSerializesIdAn
|
||||
EXPECT_THAT(id, Eq(2));
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerSerialization, PointerOwnerSerializesIdAndObject) {
|
||||
TEST_F(SerializeExtensionPointerSerialization,
|
||||
PointerOwnerSerializesIdAndObject)
|
||||
{
|
||||
auto& ser1 = createSerializer();
|
||||
ser1.ext4b(pd2, PointerOwner{});
|
||||
ser1.ext(pd3, PointerOwner{});
|
||||
auto& des1 = createDeserializer();
|
||||
// 2x ids + int32_t + MyStruct1
|
||||
EXPECT_THAT(sctx1.ser->adapter().writtenBytesCount(), Eq(2 + 4 + MyStruct1::SIZE));
|
||||
EXPECT_THAT(sctx1.ser->adapter().writtenBytesCount(),
|
||||
Eq(2 + 4 + MyStruct1::SIZE));
|
||||
size_t id;
|
||||
bitsery::details::readSize(sctx1.des->adapter(), id, 0, std::false_type{});
|
||||
des1.value4b(r2);
|
||||
@@ -270,12 +339,14 @@ TEST_F(SerializeExtensionPointerSerialization, PointerOwnerSerializesIdAndObject
|
||||
EXPECT_THAT(r3, Eq(*pd3));
|
||||
}
|
||||
|
||||
class SerializeExtensionPointerDeserialization : public SerializeExtensionPointerSerialization {
|
||||
class SerializeExtensionPointerDeserialization
|
||||
: public SerializeExtensionPointerSerialization
|
||||
{
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
TEST_F(SerializeExtensionPointerDeserialization, ReferencedByPointer) {
|
||||
TEST_F(SerializeExtensionPointerDeserialization, ReferencedByPointer)
|
||||
{
|
||||
auto& ser = createSerializer();
|
||||
ser.ext2b(d1, ReferencedByPointer{});
|
||||
ser.ext4b(d2, ReferencedByPointer{});
|
||||
@@ -290,28 +361,36 @@ TEST_F(SerializeExtensionPointerDeserialization, ReferencedByPointer) {
|
||||
EXPECT_THAT(r3, Eq(d3));
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerDeserialization, WhenReferencedByPointerReadsNullPointerThenInvalidPointerError) {
|
||||
TEST_F(SerializeExtensionPointerDeserialization,
|
||||
WhenReferencedByPointerReadsNullPointerThenInvalidPointerError)
|
||||
{
|
||||
auto& ser = createSerializer();
|
||||
bitsery::details::writeSize(sctx1.ser->adapter(), 0u);
|
||||
ser.ext2b(d1, ReferencedByPointer{});
|
||||
auto& des = createDeserializer();
|
||||
des.ext2b(r1, ReferencedByPointer{});
|
||||
EXPECT_THAT(sctx1.des->adapter().error(), Eq(bitsery::ReaderError::InvalidPointer));
|
||||
EXPECT_THAT(sctx1.des->adapter().error(),
|
||||
Eq(bitsery::ReaderError::InvalidPointer));
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerDeserialization, WhenNonNullPointerIsNullThenInvalidPointerError) {
|
||||
TEST_F(SerializeExtensionPointerDeserialization,
|
||||
WhenNonNullPointerIsNullThenInvalidPointerError)
|
||||
{
|
||||
createSerializer();
|
||||
bitsery::details::writeSize(sctx1.ser->adapter(), 0u);
|
||||
auto& des1 = createDeserializer();
|
||||
des1.ext2b(p1null, PointerOwner{ PointerType::NotNull });
|
||||
EXPECT_THAT(sctx1.des->adapter().error(), Eq(bitsery::ReaderError::InvalidPointer));
|
||||
EXPECT_THAT(sctx1.des->adapter().error(),
|
||||
Eq(bitsery::ReaderError::InvalidPointer));
|
||||
|
||||
auto& des2 = createDeserializer();
|
||||
des2.ext2b(p1null, PointerObserver{ PointerType::NotNull });
|
||||
EXPECT_THAT(sctx1.des->adapter().error(), Eq(bitsery::ReaderError::InvalidPointer));
|
||||
EXPECT_THAT(sctx1.des->adapter().error(),
|
||||
Eq(bitsery::ReaderError::InvalidPointer));
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerDeserialization, PointerOwnerCreatesObjects) {
|
||||
TEST_F(SerializeExtensionPointerDeserialization, PointerOwnerCreatesObjects)
|
||||
{
|
||||
auto& ser = createSerializer();
|
||||
ser.ext2b(pd1, PointerOwner{});
|
||||
ser.ext4b(pd2, PointerOwner{});
|
||||
@@ -330,7 +409,8 @@ TEST_F(SerializeExtensionPointerDeserialization, PointerOwnerCreatesObjects) {
|
||||
EXPECT_THAT(*p3null, Eq(*pd3));
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerDeserialization, PointerOwnerDestroysObjects) {
|
||||
TEST_F(SerializeExtensionPointerDeserialization, PointerOwnerDestroysObjects)
|
||||
{
|
||||
auto& ser = createSerializer();
|
||||
ser.ext2b(p1null, PointerOwner{});
|
||||
ser.ext4b(p2null, PointerOwner{});
|
||||
@@ -350,7 +430,8 @@ TEST_F(SerializeExtensionPointerDeserialization, PointerOwnerDestroysObjects) {
|
||||
EXPECT_THAT(pr3, ::testing::IsNull());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerDeserialization, PointerObserver) {
|
||||
TEST_F(SerializeExtensionPointerDeserialization, PointerObserver)
|
||||
{
|
||||
auto& ser = createSerializer();
|
||||
// first owner, than observer
|
||||
ser.ext4b(d2, ReferencedByPointer{});
|
||||
@@ -377,7 +458,8 @@ TEST_F(SerializeExtensionPointerDeserialization, PointerObserver) {
|
||||
EXPECT_THAT(pr3, Eq(&r3));
|
||||
}
|
||||
|
||||
struct Test1Data {
|
||||
struct Test1Data
|
||||
{
|
||||
std::vector<MyStruct1> vdata;
|
||||
std::vector<MyStruct1*> vptr;
|
||||
MyStruct1 o1;
|
||||
@@ -386,19 +468,18 @@ struct Test1Data {
|
||||
int32_t* pi1;
|
||||
|
||||
template<typename S>
|
||||
void serialize(S &s) {
|
||||
void serialize(S& s)
|
||||
{
|
||||
// set container elements to be candidates for non-owning pointers
|
||||
s.container(vdata, 100, [](S& s, MyStruct1 &d) {
|
||||
s.ext(d, ReferencedByPointer{});
|
||||
});
|
||||
s.container(
|
||||
vdata, 100, [](S& s, MyStruct1& d) { s.ext(d, ReferencedByPointer{}); });
|
||||
// contains non owning pointers
|
||||
//
|
||||
// IMPORTANT !!!
|
||||
// ALWAYS ACCEPT BY REFERENCE like this: T* (&obj)
|
||||
//
|
||||
s.container(vptr, 100, [](S& s, MyStruct1 *(&d)) {
|
||||
s.ext(d, PointerObserver{});
|
||||
});
|
||||
s.container(
|
||||
vptr, 100, [](S& s, MyStruct1*(&d)) { s.ext(d, PointerObserver{}); });
|
||||
// just a regular fields
|
||||
s.object(o1);
|
||||
s.value4b(i1);
|
||||
@@ -406,11 +487,11 @@ struct Test1Data {
|
||||
s.ext(po1, PointerObserver{});
|
||||
// owner
|
||||
s.ext4b(pi1, PointerOwner{});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
TEST(SerializeExtensionPointer, IntegrationTest) {
|
||||
TEST(SerializeExtensionPointer, IntegrationTest)
|
||||
{
|
||||
|
||||
Test1Data data{};
|
||||
data.vdata.push_back({ 165, -45 });
|
||||
@@ -455,7 +536,9 @@ TEST(SerializeExtensionPointer, IntegrationTest) {
|
||||
delete res.pi1;
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionPointer, PointerOwnerWithNonPolymorphicTypeCanUseLambdaOverload) {
|
||||
TEST(SerializeExtensionPointer,
|
||||
PointerOwnerWithNonPolymorphicTypeCanUseLambdaOverload)
|
||||
{
|
||||
const int32_t NEW_VALUE = 2;
|
||||
const int32_t OLD_VALUE = 1;
|
||||
MyStruct1* data = new MyStruct1{ NEW_VALUE, NEW_VALUE };
|
||||
@@ -481,7 +564,8 @@ TEST(SerializeExtensionPointer, PointerOwnerWithNonPolymorphicTypeCanUseLambdaOv
|
||||
delete res;
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionPointer, ReferencedByPointerCanUseLambdaOverload) {
|
||||
TEST(SerializeExtensionPointer, ReferencedByPointerCanUseLambdaOverload)
|
||||
{
|
||||
const int32_t NEW_VALUE = 2;
|
||||
const int32_t OLD_VALUE = 1;
|
||||
MyStruct1 data = MyStruct1{ NEW_VALUE, NEW_VALUE };
|
||||
@@ -504,7 +588,8 @@ TEST(SerializeExtensionPointer, ReferencedByPointerCanUseLambdaOverload) {
|
||||
EXPECT_THAT(res.i2, Eq(OLD_VALUE)); // we didn't serialized that
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionPointer, PointerOwnerCanUseValueOverload) {
|
||||
TEST(SerializeExtensionPointer, PointerOwnerCanUseValueOverload)
|
||||
{
|
||||
auto* data = new int64_t{ 49845894 };
|
||||
auto* res = new int64_t{ -78548415 };
|
||||
|
||||
@@ -519,7 +604,8 @@ TEST(SerializeExtensionPointer, PointerOwnerCanUseValueOverload) {
|
||||
delete res;
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionPointer, ReferencedByPointerCanUseValueOverload) {
|
||||
TEST(SerializeExtensionPointer, ReferencedByPointerCanUseValueOverload)
|
||||
{
|
||||
int64_t data{ 49845894 };
|
||||
int64_t res{ -78548415 };
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,12 +20,11 @@
|
||||
// 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,59 +34,75 @@ 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 {
|
||||
struct Base
|
||||
{
|
||||
uint8_t x{};
|
||||
|
||||
virtual ~Base() = default;
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S &s, Base &o) {
|
||||
void
|
||||
serialize(S& s, Base& o)
|
||||
{
|
||||
s.value1b(o.x);
|
||||
}
|
||||
|
||||
struct Derived1 : virtual Base {
|
||||
struct Derived1 : virtual Base
|
||||
{
|
||||
uint8_t y1{};
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S &s, Derived1 &o) {
|
||||
void
|
||||
serialize(S& s, Derived1& o)
|
||||
{
|
||||
s.ext(o, VirtualBaseClass<Base>{});
|
||||
s.value1b(o.y1);
|
||||
}
|
||||
|
||||
struct Derived2 : virtual Base {
|
||||
struct Derived2 : virtual Base
|
||||
{
|
||||
uint8_t y2{};
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S &s, Derived2 &o) {
|
||||
void
|
||||
serialize(S& s, Derived2& o)
|
||||
{
|
||||
s.ext(o, VirtualBaseClass<Base>{});
|
||||
s.value1b(o.y2);
|
||||
}
|
||||
|
||||
struct MultipleVirtualInheritance : Derived1, Derived2 {
|
||||
struct MultipleVirtualInheritance
|
||||
: Derived1
|
||||
, Derived2
|
||||
{
|
||||
int8_t z{};
|
||||
|
||||
MultipleVirtualInheritance() = default;
|
||||
|
||||
MultipleVirtualInheritance(uint8_t x_, uint8_t y1_, uint8_t y2_, int8_t z_) {
|
||||
MultipleVirtualInheritance(uint8_t x_, uint8_t y1_, uint8_t y2_, int8_t z_)
|
||||
{
|
||||
x = x_;
|
||||
y1 = y1_;
|
||||
y2 = y2_;
|
||||
@@ -95,85 +110,95 @@ struct MultipleVirtualInheritance : Derived1, Derived2 {
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
void serialize(S &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 {
|
||||
};
|
||||
struct NoRelationshipSpecifiedDerived : Base
|
||||
{};
|
||||
|
||||
//these classes will be used to "cheat" a little bit when testing deserialization flows
|
||||
struct BaseClone {
|
||||
// these classes will be used to "cheat" a little bit when testing
|
||||
// deserialization flows
|
||||
struct BaseClone
|
||||
{
|
||||
uint8_t x{};
|
||||
|
||||
virtual ~BaseClone() = default;
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S &s, BaseClone &o) {
|
||||
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 {
|
||||
|
||||
template<>
|
||||
struct PolymorphicBaseClass<Base> : PolymorphicDerivedClasses<Derived1, Derived2> {
|
||||
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
|
||||
// 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> {
|
||||
// struct PolymorphicBaseClass<Derived1> :
|
||||
// PolymorphicDerivedClasses<MultipleVirtualInheritance> {
|
||||
// };
|
||||
|
||||
template<>
|
||||
struct PolymorphicBaseClass<Derived2> : PolymorphicDerivedClasses<MultipleVirtualInheritance> {
|
||||
struct PolymorphicBaseClass<Derived2>
|
||||
: PolymorphicDerivedClasses<MultipleVirtualInheritance>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SerializeExtensionPointerPolymorphicTypes : public testing::Test {
|
||||
class SerializeExtensionPointerPolymorphicTypes : public testing::Test
|
||||
{
|
||||
public:
|
||||
|
||||
TContext plctx{};
|
||||
SerContext sctx{};
|
||||
|
||||
typename SerContext::TSerializer& createSerializer() {
|
||||
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>{});
|
||||
std::get<2>(plctx).registerBasesList<SerContext::TSerializer>(
|
||||
bitsery::ext::PolymorphicClassesList<Base>{});
|
||||
return res;
|
||||
}
|
||||
|
||||
typename SerContext::TDeserializer& createDeserializer() {
|
||||
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>{});
|
||||
std::get<2>(plctx).registerBasesList<SerContext::TDeserializer>(
|
||||
bitsery::ext::PolymorphicClassesList<Base>{});
|
||||
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(SerializeExtensionPointerPolymorphicTypes, Data0Result0) {
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data0Result0)
|
||||
{
|
||||
Base* baseData = nullptr;
|
||||
createSerializer().ext(baseData, PointerOwner{});
|
||||
Base* baseRes = nullptr;
|
||||
@@ -183,7 +208,8 @@ TEST_F(SerializeExtensionPointerPolymorphicTypes, Data0Result0) {
|
||||
EXPECT_THAT(baseData, ::testing::IsNull());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data0Result1) {
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data0Result1)
|
||||
{
|
||||
Base* baseData = nullptr;
|
||||
createSerializer().ext(baseData, PointerOwner{});
|
||||
|
||||
@@ -194,7 +220,8 @@ TEST_F(SerializeExtensionPointerPolymorphicTypes, Data0Result1) {
|
||||
EXPECT_THAT(baseData, ::testing::IsNull());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data1Result0) {
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data1Result0)
|
||||
{
|
||||
Derived1 d1{};
|
||||
d1.x = 3;
|
||||
d1.y1 = 78;
|
||||
@@ -214,7 +241,8 @@ TEST_F(SerializeExtensionPointerPolymorphicTypes, Data1Result0) {
|
||||
delete baseRes;
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data1Result1) {
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes, Data1Result1)
|
||||
{
|
||||
Derived1 d1{};
|
||||
d1.x = 3;
|
||||
d1.y1 = 78;
|
||||
@@ -233,7 +261,9 @@ TEST_F(SerializeExtensionPointerPolymorphicTypes, Data1Result1) {
|
||||
EXPECT_THAT(res->y1, Eq(data->y1));
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes, ComplexTypeWithVirtualInheritanceData1Result0) {
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes,
|
||||
ComplexTypeWithVirtualInheritanceData1Result0)
|
||||
{
|
||||
MultipleVirtualInheritance md1{};
|
||||
md1.x = 3;
|
||||
md1.y1 = 78;
|
||||
@@ -257,7 +287,9 @@ TEST_F(SerializeExtensionPointerPolymorphicTypes, ComplexTypeWithVirtualInherita
|
||||
delete baseRes;
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes, WhenResultIsDifferentTypeThenRecreate) {
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes,
|
||||
WhenResultIsDifferentTypeThenRecreate)
|
||||
{
|
||||
MultipleVirtualInheritance md1{};
|
||||
md1.x = 3;
|
||||
md1.y1 = 78;
|
||||
@@ -266,24 +298,31 @@ TEST_F(SerializeExtensionPointerPolymorphicTypes, WhenResultIsDifferentTypeThenR
|
||||
Base* baseData = &md1;
|
||||
createSerializer().ext(baseData, PointerOwner{});
|
||||
Base* baseRes = new Derived1{};
|
||||
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance *>(baseRes), ::testing::IsNull());
|
||||
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance*>(baseRes),
|
||||
::testing::IsNull());
|
||||
createDeserializer().ext(baseRes, PointerOwner{});
|
||||
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance *>(baseRes), ::testing::NotNull());
|
||||
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
|
||||
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;
|
||||
@@ -295,34 +334,42 @@ TEST_F(SerializeExtensionPointerPolymorphicTypes,
|
||||
|
||||
#endif
|
||||
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes,
|
||||
CompileTimeTypeIsDerivedAndReachableFromBaseRegisteredWithPolymorphicContext) {
|
||||
TEST_F(
|
||||
SerializeExtensionPointerPolymorphicTypes,
|
||||
CompileTimeTypeIsDerivedAndReachableFromBaseRegisteredWithPolymorphicContext)
|
||||
{
|
||||
|
||||
MultipleVirtualInheritance md;
|
||||
Derived2 *derivedData = &md;//this class is not registered via PolymorphicContext
|
||||
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());
|
||||
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance*>(derivedRes),
|
||||
::testing::IsNull());
|
||||
createDeserializer().ext(derivedRes, PointerOwner{});
|
||||
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance *>(derivedRes), ::testing::NotNull());
|
||||
EXPECT_THAT(dynamic_cast<MultipleVirtualInheritance*>(derivedRes),
|
||||
::testing::NotNull());
|
||||
delete derivedRes;
|
||||
|
||||
}
|
||||
|
||||
|
||||
TEST_F(SerializeExtensionPointerPolymorphicTypes,
|
||||
WhenPolymorphicTypeNotFoundDuringDeserializionThenInvalidPointerError) {
|
||||
WhenPolymorphicTypeNotFoundDuringDeserializionThenInvalidPointerError)
|
||||
{
|
||||
|
||||
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
|
||||
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>{});
|
||||
pc.registerBasesList<SerContext::TDeserializer>(
|
||||
bitsery::ext::PolymorphicClassesList<BaseClone>{});
|
||||
des.ext(baseRes, PointerOwner{});
|
||||
EXPECT_THAT(sctx.des->adapter().error(), Eq(bitsery::ReaderError::InvalidPointer));
|
||||
EXPECT_THAT(sctx.des->adapter().error(),
|
||||
Eq(bitsery::ReaderError::InvalidPointer));
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,13 +20,12 @@
|
||||
// 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,27 +35,34 @@ 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 {
|
||||
struct Base
|
||||
{
|
||||
Base() = default;
|
||||
|
||||
explicit Base(uint64_t v) : x{v} {}
|
||||
explicit Base(uint64_t v)
|
||||
: x{ v }
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t x{};
|
||||
|
||||
@@ -64,16 +70,24 @@ struct Base {
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, Base& o) {
|
||||
void
|
||||
serialize(S& s, Base& o)
|
||||
{
|
||||
s.value8b(o.x);
|
||||
}
|
||||
|
||||
struct Derived1 : Base {
|
||||
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) {
|
||||
friend bool operator==(const Derived1& lhs, const Derived1& rhs)
|
||||
{
|
||||
return lhs.x == rhs.x && lhs.y1 == rhs.y1;
|
||||
}
|
||||
|
||||
@@ -81,98 +95,123 @@ struct Derived1 : Base {
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, Derived1& o) {
|
||||
void
|
||||
serialize(S& s, Derived1& o)
|
||||
{
|
||||
s.ext(o, BaseClass<Base>{});
|
||||
s.value8b(o.y1);
|
||||
}
|
||||
|
||||
struct Derived2 : Base {
|
||||
struct Derived2 : Base
|
||||
{
|
||||
uint64_t y1{};
|
||||
uint64_t y2{};
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, Derived2& o) {
|
||||
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 {
|
||||
// polymorphic structure that contains polymorphic pointer, to test memory
|
||||
// resource propagation
|
||||
struct PolyPtrWithPolyPtrBase
|
||||
{
|
||||
std::unique_ptr<Base> ptr{};
|
||||
|
||||
virtual ~PolyPtrWithPolyPtrBase() = default;
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, PolyPtrWithPolyPtrBase& o) {
|
||||
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) {
|
||||
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 {
|
||||
|
||||
template<>
|
||||
struct PolymorphicBaseClass<Base> : PolymorphicDerivedClasses<Derived1, Derived2> {
|
||||
struct PolymorphicBaseClass<Base>
|
||||
: PolymorphicDerivedClasses<Derived1, Derived2>
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct PolymorphicBaseClass<PolyPtrWithPolyPtrBase> : PolymorphicDerivedClasses<DerivedPolyPtrWithPolyPtr> {
|
||||
struct PolymorphicBaseClass<PolyPtrWithPolyPtrBase>
|
||||
: PolymorphicDerivedClasses<DerivedPolyPtrWithPolyPtr>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// this class is for testing
|
||||
struct TestAllocInfo {
|
||||
struct TestAllocInfo
|
||||
{
|
||||
void* ptr;
|
||||
size_t bytes;
|
||||
size_t alignment;
|
||||
size_t typeId;
|
||||
|
||||
friend bool operator==(const TestAllocInfo& lhs, const TestAllocInfo& rhs) {
|
||||
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);
|
||||
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 {
|
||||
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);
|
||||
bitsery::ext::MemResourceNewDelete{}.deallocate(
|
||||
ptr, bytes, alignment, typeId);
|
||||
}
|
||||
|
||||
std::vector<TestAllocInfo> allocs{};
|
||||
std::vector<TestAllocInfo> deallocs{};
|
||||
};
|
||||
|
||||
class SerializeExtensionPointerWithAllocator : public testing::Test {
|
||||
class SerializeExtensionPointerWithAllocator : public testing::Test
|
||||
{
|
||||
public:
|
||||
|
||||
TContext plctx{};
|
||||
SerContext sctx{};
|
||||
|
||||
typename SerContext::TSerializer& createSerializer() {
|
||||
typename SerContext::TSerializer& createSerializer()
|
||||
{
|
||||
auto& res = sctx.createSerializer(plctx);
|
||||
std::get<2>(plctx).clear();
|
||||
// bind serializer with classes
|
||||
@@ -181,7 +220,8 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
typename SerContext::TDeserializer& createDeserializer() {
|
||||
typename SerContext::TDeserializer& createDeserializer()
|
||||
{
|
||||
auto& res = sctx.createDeserializer(plctx);
|
||||
std::get<2>(plctx).clear();
|
||||
// bind deserializer with classes
|
||||
@@ -190,16 +230,14 @@ public:
|
||||
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);
|
||||
@@ -217,13 +255,16 @@ TEST_F(SerializeExtensionPointerWithAllocator, CanSetDefaultMemoryResourceInPoin
|
||||
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.allocs[0].typeId,
|
||||
Eq(bitsery::ext::StandardRTTI::get<Derived1>()));
|
||||
EXPECT_THAT(memRes.deallocs.size(), Eq(0u));
|
||||
delete dData;
|
||||
delete dRes;
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerWithAllocator, CorrectlyDeallocatesPreviousInstance) {
|
||||
TEST_F(SerializeExtensionPointerWithAllocator,
|
||||
CorrectlyDeallocatesPreviousInstance)
|
||||
{
|
||||
MemResourceForTest memRes{};
|
||||
std::get<0>(plctx).setMemResource(&memRes);
|
||||
|
||||
@@ -240,17 +281,21 @@ TEST_F(SerializeExtensionPointerWithAllocator, CorrectlyDeallocatesPreviousInsta
|
||||
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.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(memRes.deallocs[0].typeId,
|
||||
Eq(bitsery::ext::StandardRTTI::get<Derived2>()));
|
||||
|
||||
delete dData;
|
||||
delete dRes;
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionPointerWithAllocator, DefaultDeleterIsNotUsedForStdUniquePtr) {
|
||||
TEST_F(SerializeExtensionPointerWithAllocator,
|
||||
DefaultDeleterIsNotUsedForStdUniquePtr)
|
||||
{
|
||||
MemResourceForTest memRes{};
|
||||
std::get<0>(plctx).setMemResource(&memRes);
|
||||
|
||||
@@ -263,41 +308,47 @@ TEST_F(SerializeExtensionPointerWithAllocator, DefaultDeleterIsNotUsedForStdUniq
|
||||
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.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) {
|
||||
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});
|
||||
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.deallocs[0].typeId,
|
||||
Eq(bitsery::ext::StandardRTTI::get<Derived1>()));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(SerializeExtensionPointerWithAllocator, CanSetMemResourcePerPointer) {
|
||||
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});
|
||||
createSerializer().ext(
|
||||
baseData, PointerOwner{ bitsery::ext::PointerType::Nullable, &memRes2 });
|
||||
Base* baseRes = new Derived2;
|
||||
createDeserializer().ext(baseRes, PointerOwner{bitsery::ext::PointerType::Nullable, &memRes2});
|
||||
createDeserializer().ext(
|
||||
baseRes, PointerOwner{ bitsery::ext::PointerType::Nullable, &memRes2 });
|
||||
|
||||
auto dData = dynamic_cast<Derived1*>(baseData);
|
||||
auto dRes = dynamic_cast<Derived1*>(baseRes);
|
||||
@@ -309,59 +360,71 @@ TEST_F(SerializeExtensionPointerWithAllocator, CanSetMemResourcePerPointer) {
|
||||
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.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(memRes2.deallocs[0].typeId,
|
||||
Eq(bitsery::ext::StandardRTTI::get<Derived2>()));
|
||||
|
||||
delete dData;
|
||||
delete dRes;
|
||||
}
|
||||
|
||||
|
||||
TEST_F(SerializeExtensionPointerWithAllocator, MemResourceSetPerPointerByDefaultDoNotPropagate) {
|
||||
TEST_F(SerializeExtensionPointerWithAllocator,
|
||||
MemResourceSetPerPointerByDefaultDoNotPropagate)
|
||||
{
|
||||
MemResourceForTest memRes1{};
|
||||
MemResourceForTest memRes2{};
|
||||
std::get<0>(plctx).setMemResource(&memRes1);
|
||||
|
||||
auto data = std::unique_ptr<PolyPtrWithPolyPtrBase>(new PolyPtrWithPolyPtrBase{});
|
||||
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});
|
||||
createSerializer().ext(
|
||||
data, StdSmartPtr{ bitsery::ext::PointerType::Nullable, &memRes2 });
|
||||
|
||||
auto res = std::unique_ptr<PolyPtrWithPolyPtrBase>(new DerivedPolyPtrWithPolyPtr{});
|
||||
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});
|
||||
|
||||
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
|
||||
// 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) {
|
||||
TEST_F(SerializeExtensionPointerWithAllocator,
|
||||
MemResourceSetPerPointerCanPropagate)
|
||||
{
|
||||
MemResourceForTest memRes1{};
|
||||
MemResourceForTest memRes2{};
|
||||
std::get<0>(plctx).setMemResource(&memRes1);
|
||||
|
||||
auto data = std::unique_ptr<PolyPtrWithPolyPtrBase>(new PolyPtrWithPolyPtrBase{});
|
||||
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});
|
||||
createSerializer().ext(
|
||||
data, StdSmartPtr{ bitsery::ext::PointerType::Nullable, &memRes2, true });
|
||||
|
||||
auto res = std::unique_ptr<PolyPtrWithPolyPtrBase>(new DerivedPolyPtrWithPolyPtr{});
|
||||
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});
|
||||
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
|
||||
// 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));
|
||||
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -23,15 +23,16 @@
|
||||
#include <bitsery/ext/std_bitset.h>
|
||||
#include <bitsery/ext/value_range.h>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include "serialization_test_utils.h"
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
using StdBitset = bitsery::ext::StdBitset;
|
||||
using ValueRange = bitsery::ext::ValueRange<int>;
|
||||
|
||||
using testing::Eq;
|
||||
|
||||
TEST(SerializeExtensionStdBitset, BitsetSmallerThanULongLong) {
|
||||
TEST(SerializeExtensionStdBitset, BitsetSmallerThanULongLong)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
|
||||
std::bitset<31> data;
|
||||
@@ -47,7 +48,8 @@ TEST(SerializeExtensionStdBitset, BitsetSmallerThanULongLong) {
|
||||
EXPECT_THAT(res, Eq(data));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdBitset, BitsetSmallerThanULongLong2) {
|
||||
TEST(SerializeExtensionStdBitset, BitsetSmallerThanULongLong2)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
|
||||
std::bitset<9> data;
|
||||
@@ -59,8 +61,8 @@ TEST(SerializeExtensionStdBitset, BitsetSmallerThanULongLong2) {
|
||||
EXPECT_THAT(res, Eq(data));
|
||||
}
|
||||
|
||||
|
||||
TEST(SerializeExtensionStdBitset, BitsetLargerThanULongLong) {
|
||||
TEST(SerializeExtensionStdBitset, BitsetLargerThanULongLong)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
|
||||
std::bitset<200> data;
|
||||
@@ -76,7 +78,8 @@ TEST(SerializeExtensionStdBitset, BitsetLargerThanULongLong) {
|
||||
EXPECT_THAT(res, Eq(data));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdBitset, BitsetSmallerThanULongLongBitPackingEnabled) {
|
||||
TEST(SerializeExtensionStdBitset, BitsetSmallerThanULongLongBitPackingEnabled)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
|
||||
std::bitset<12> data;
|
||||
@@ -86,11 +89,13 @@ TEST(SerializeExtensionStdBitset, BitsetSmallerThanULongLongBitPackingEnabled) {
|
||||
std::bitset<12> res{};
|
||||
int other_res{};
|
||||
|
||||
ctx.createSerializer().enableBitPacking([&data, &other_data](SerializationContext::TSerializerBPEnabled& sbp) {
|
||||
ctx.createSerializer().enableBitPacking(
|
||||
[&data, &other_data](SerializationContext::TSerializerBPEnabled& sbp) {
|
||||
sbp.ext(data, StdBitset{});
|
||||
sbp.ext(other_data, ValueRange{ 1000, 1015 });
|
||||
});
|
||||
ctx.createDeserializer().enableBitPacking([&res, &other_res](SerializationContext::TDeserializerBPEnabled& dbp) {
|
||||
ctx.createDeserializer().enableBitPacking(
|
||||
[&res, &other_res](SerializationContext::TDeserializerBPEnabled& dbp) {
|
||||
dbp.ext(res, StdBitset{});
|
||||
dbp.ext(other_res, ValueRange{ 1000, 1015 });
|
||||
});
|
||||
@@ -99,7 +104,8 @@ TEST(SerializeExtensionStdBitset, BitsetSmallerThanULongLongBitPackingEnabled) {
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(2));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdBitset, BitsetLargerThanULongLongBitPackingEnabled) {
|
||||
TEST(SerializeExtensionStdBitset, BitsetLargerThanULongLongBitPackingEnabled)
|
||||
{
|
||||
SerializationContext ctx;
|
||||
|
||||
std::bitset<204> data;
|
||||
@@ -110,11 +116,13 @@ TEST(SerializeExtensionStdBitset, BitsetLargerThanULongLongBitPackingEnabled) {
|
||||
std::bitset<204> res{};
|
||||
int other_res{};
|
||||
|
||||
ctx.createSerializer().enableBitPacking([&data, &other_data](SerializationContext::TSerializerBPEnabled& sbp) {
|
||||
ctx.createSerializer().enableBitPacking(
|
||||
[&data, &other_data](SerializationContext::TSerializerBPEnabled& sbp) {
|
||||
sbp.ext(data, StdBitset{});
|
||||
sbp.ext(other_data, ValueRange{ 1000, 1015 });
|
||||
});
|
||||
ctx.createDeserializer().enableBitPacking([&res, &other_res](SerializationContext::TDeserializerBPEnabled& dbp) {
|
||||
ctx.createDeserializer().enableBitPacking(
|
||||
[&res, &other_res](SerializationContext::TDeserializerBPEnabled& dbp) {
|
||||
dbp.ext(res, StdBitset{});
|
||||
dbp.ext(other_res, ValueRange{ 1000, 1015 });
|
||||
});
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -22,15 +22,16 @@
|
||||
|
||||
#include <bitsery/ext/std_chrono.h>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include "serialization_test_utils.h"
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
using StdDuration = bitsery::ext::StdDuration;
|
||||
using StdTimePoint = bitsery::ext::StdTimePoint;
|
||||
|
||||
using testing::Eq;
|
||||
|
||||
TEST(SerializeExtensionStdChrono, IntegralDuration) {
|
||||
TEST(SerializeExtensionStdChrono, IntegralDuration)
|
||||
{
|
||||
SerializationContext ctx1;
|
||||
using Hours = std::chrono::duration<int32_t, std::ratio<60>>;
|
||||
|
||||
@@ -42,7 +43,8 @@ TEST(SerializeExtensionStdChrono, IntegralDuration) {
|
||||
EXPECT_THAT(res, Eq(data));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdChrono, IntegralTimePoint) {
|
||||
TEST(SerializeExtensionStdChrono, IntegralTimePoint)
|
||||
{
|
||||
SerializationContext ctx1;
|
||||
using Duration = std::chrono::duration<int64_t, std::milli>;
|
||||
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
|
||||
@@ -55,7 +57,8 @@ TEST(SerializeExtensionStdChrono, IntegralTimePoint) {
|
||||
EXPECT_THAT(res, Eq(data));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdChrono, FloatDuration) {
|
||||
TEST(SerializeExtensionStdChrono, FloatDuration)
|
||||
{
|
||||
SerializationContext ctx1;
|
||||
using Hours = std::chrono::duration<float, std::ratio<60>>;
|
||||
|
||||
@@ -67,7 +70,8 @@ TEST(SerializeExtensionStdChrono, FloatDuration) {
|
||||
EXPECT_THAT(res, Eq(data));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdChrono, FloatTimePoint) {
|
||||
TEST(SerializeExtensionStdChrono, FloatTimePoint)
|
||||
{
|
||||
SerializationContext ctx1;
|
||||
using Duration = std::chrono::duration<double, std::milli>;
|
||||
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,52 +20,56 @@
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
#include <bitsery/ext/std_map.h>
|
||||
#include <bitsery/ext/entropy.h>
|
||||
#include <unordered_map>
|
||||
#include <bitsery/ext/std_map.h>
|
||||
#include <bitsery/traits/string.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include "serialization_test_utils.h"
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
using StdMap = bitsery::ext::StdMap;
|
||||
|
||||
using testing::Eq;
|
||||
|
||||
template<typename Container>
|
||||
Container createData() {
|
||||
Container
|
||||
createData()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
template<>
|
||||
std::unordered_map<std::string, MyStruct1> createData<std::unordered_map<std::string, MyStruct1>>() {
|
||||
return {
|
||||
std::make_pair("some key", MyStruct1{874,456}),
|
||||
std::unordered_map<std::string, MyStruct1>
|
||||
createData<std::unordered_map<std::string, MyStruct1>>()
|
||||
{
|
||||
return { std::make_pair("some key", MyStruct1{ 874, 456 }),
|
||||
std::make_pair("other key", MyStruct1{ -34, 8645 }),
|
||||
std::make_pair("secret key", MyStruct1{-4878,3468975})
|
||||
};
|
||||
std::make_pair("secret key", MyStruct1{ -4878, 3468975 }) };
|
||||
}
|
||||
|
||||
template<>
|
||||
std::unordered_multimap<int32_t, float> createData<std::unordered_multimap<int32_t, float>>() {
|
||||
return {
|
||||
std::pair<int32_t , float>(545, 45.485f),
|
||||
std::unordered_multimap<int32_t, float>
|
||||
createData<std::unordered_multimap<int32_t, float>>()
|
||||
{
|
||||
return { std::pair<int32_t, float>(545, 45.485f),
|
||||
std::pair<int32_t, float>(6748, -7891.5f),
|
||||
std::pair<int32_t , float>(845, -457.0f)
|
||||
};
|
||||
std::pair<int32_t, float>(845, -457.0f) };
|
||||
}
|
||||
|
||||
template<>
|
||||
std::map<MyEnumClass, MyStruct1> createData<std::map<MyEnumClass, MyStruct1>>() {
|
||||
return {
|
||||
std::make_pair(MyEnumClass::E3, MyStruct1{874,456}),
|
||||
std::map<MyEnumClass, MyStruct1>
|
||||
createData<std::map<MyEnumClass, MyStruct1>>()
|
||||
{
|
||||
return { std::make_pair(MyEnumClass::E3, MyStruct1{ 874, 456 }),
|
||||
std::make_pair(MyEnumClass::E6, MyStruct1{ -34, 8645 }),
|
||||
std::make_pair(MyEnumClass::E2, MyStruct1{-4878,3468975})
|
||||
};
|
||||
std::make_pair(MyEnumClass::E2, MyStruct1{ -4878, 3468975 }) };
|
||||
}
|
||||
|
||||
template<>
|
||||
std::multimap<int32_t ,int64_t> createData<std::multimap<int32_t ,int64_t>>() {
|
||||
std::multimap<int32_t, int64_t>
|
||||
createData<std::multimap<int32_t, int64_t>>()
|
||||
{
|
||||
return { // these are optimized with range and entropy
|
||||
std::pair<int32_t, int64_t>(-45, -984196845ll),
|
||||
std::pair<int32_t, int64_t>(54, 1ll),
|
||||
@@ -74,7 +78,8 @@ std::multimap<int32_t ,int64_t> createData<std::multimap<int32_t ,int64_t>>() {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class SerializeExtensionStdMap : public testing::Test {
|
||||
class SerializeExtensionStdMap : public testing::Test
|
||||
{
|
||||
public:
|
||||
using TContainer = T;
|
||||
|
||||
@@ -82,19 +87,20 @@ public:
|
||||
TContainer res{};
|
||||
};
|
||||
|
||||
using SerializeExtensionStdMapTypes = ::testing::Types<
|
||||
std::unordered_map<std::string, MyStruct1>,
|
||||
using SerializeExtensionStdMapTypes =
|
||||
::testing::Types<std::unordered_map<std::string, MyStruct1>,
|
||||
std::unordered_multimap<int32_t, float>,
|
||||
std::map<MyEnumClass, MyStruct1>,
|
||||
std::multimap<int32_t ,int64_t>
|
||||
>;
|
||||
std::multimap<int32_t, int64_t>>;
|
||||
|
||||
TYPED_TEST_SUITE(SerializeExtensionStdMap, SerializeExtensionStdMapTypes, );
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, std::unordered_map<std::string, MyStruct1>& o) {
|
||||
void
|
||||
serialize(S& s, std::unordered_map<std::string, MyStruct1>& o)
|
||||
{
|
||||
s.ext(o, StdMap{ 10 }, [](S& s, std::string& key, MyStruct1& value) {
|
||||
s.text1b(key, 100);
|
||||
s.object(value);
|
||||
@@ -102,7 +108,9 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, std::unordered_multimap<int32_t, float>& o) {
|
||||
void
|
||||
serialize(S& s, std::unordered_multimap<int32_t, float>& o)
|
||||
{
|
||||
s.ext(o, StdMap{ 10 }, [](S& s, int32_t& key, float& value) {
|
||||
s.value4b(key);
|
||||
s.value4b(value);
|
||||
@@ -110,7 +118,9 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, std::map<MyEnumClass , MyStruct1>& o) {
|
||||
void
|
||||
serialize(S& s, std::map<MyEnumClass, MyStruct1>& o)
|
||||
{
|
||||
s.ext(o, StdMap{ 10 }, [](S& s, MyEnumClass& key, MyStruct1& value) {
|
||||
s.value4b(key);
|
||||
s.object(value);
|
||||
@@ -118,7 +128,9 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, std::multimap<int32_t ,int64_t>& o) {
|
||||
void
|
||||
serialize(S& s, std::multimap<int32_t, int64_t>& o)
|
||||
{
|
||||
s.ext(o, StdMap{ 10 }, [](S& s, int32_t& key, int64_t& value) {
|
||||
s.enableBitPacking([&key, &value](typename S::BPEnabledType& sbp) {
|
||||
int64_t values[3]{ 1ll, 2ll, 3ll };
|
||||
@@ -128,10 +140,10 @@ namespace bitsery {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdMap, SerializeAndDeserializeEquals) {
|
||||
TYPED_TEST(SerializeExtensionStdMap, SerializeAndDeserializeEquals)
|
||||
{
|
||||
SerializationContext ctx1;
|
||||
ctx1.createSerializer().object(this->src);
|
||||
ctx1.createDeserializer().object(this->res);
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,9 +20,8 @@
|
||||
// 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>
|
||||
|
||||
#if __cplusplus > 201402L
|
||||
|
||||
@@ -37,12 +36,15 @@ using BPDes = SerializationContext::TDeserializer::BPEnabledType;
|
||||
using testing::Eq;
|
||||
|
||||
template<typename T>
|
||||
void test(SerializationContext& ctx, const T& v, T& r) {
|
||||
void
|
||||
test(SerializationContext& ctx, const T& v, T& r)
|
||||
{
|
||||
ctx.createSerializer().ext4b(v, StdOptional{});
|
||||
ctx.createDeserializer().ext4b(r, StdOptional{});
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdOptional, EmptyOptional) {
|
||||
TEST(SerializeExtensionStdOptional, EmptyOptional)
|
||||
{
|
||||
std::optional<int32_t> t1{};
|
||||
std::optional<int32_t> r1{};
|
||||
|
||||
@@ -51,7 +53,6 @@ TEST(SerializeExtensionStdOptional, EmptyOptional) {
|
||||
EXPECT_THAT(ctx1.getBufferSize(), Eq(1));
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
|
||||
|
||||
r1 = 3;
|
||||
SerializationContext ctx2;
|
||||
test(ctx2, t1, r1);
|
||||
@@ -59,7 +60,8 @@ TEST(SerializeExtensionStdOptional, EmptyOptional) {
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdOptional, OptionalHasValue) {
|
||||
TEST(SerializeExtensionStdOptional, OptionalHasValue)
|
||||
{
|
||||
std::optional<int32_t> t1{ 43 };
|
||||
std::optional<int32_t> r1{ 52 };
|
||||
|
||||
@@ -73,17 +75,16 @@ TEST(SerializeExtensionStdOptional, OptionalHasValue) {
|
||||
test(ctx2, t1, r1);
|
||||
EXPECT_THAT(ctx2.getBufferSize(), Eq(1 + sizeof(int)));
|
||||
EXPECT_THAT(t1.value(), Eq(r1.value()));
|
||||
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdOptional, AlignAfterStateWriteRead) {
|
||||
TEST(SerializeExtensionStdOptional, AlignAfterStateWriteRead)
|
||||
{
|
||||
std::optional<int32_t> t1{ 43 };
|
||||
std::optional<int32_t> r1{ 52 };
|
||||
auto range = bitsery::ext::ValueRange<int>{ 40, 60 };
|
||||
|
||||
SerializationContext ctx;
|
||||
ctx.createSerializer().enableBitPacking([&t1, &range](BPSer& ser) {
|
||||
|
||||
ser.ext(t1, StdOptional(true), [&range](BPSer& ser, int32_t& v) {
|
||||
ser.ext(v, range);
|
||||
});
|
||||
@@ -98,7 +99,8 @@ TEST(SerializeExtensionStdOptional, AlignAfterStateWriteRead) {
|
||||
EXPECT_THAT(t1.value(), Eq(r1.value()));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdOptional, NoAlignAfterStateWriteRead) {
|
||||
TEST(SerializeExtensionStdOptional, NoAlignAfterStateWriteRead)
|
||||
{
|
||||
std::optional<int32_t> t1{ 43 };
|
||||
std::optional<int32_t> r1{ 52 };
|
||||
auto range = bitsery::ext::ValueRange<int>{ 40, 60 };
|
||||
@@ -121,7 +123,8 @@ TEST(SerializeExtensionStdOptional, NoAlignAfterStateWriteRead) {
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma message("C++17 and /Zc:__cplusplus option is required to enable std::optional tests")
|
||||
#pragma message( \
|
||||
"C++17 and /Zc:__cplusplus option is required to enable std::optional tests")
|
||||
#else
|
||||
#pragma message("C++17 is required to enable std::optional tests")
|
||||
#endif
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -22,14 +22,15 @@
|
||||
|
||||
#include <bitsery/ext/std_queue.h>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include "serialization_test_utils.h"
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
using StdQueue = bitsery::ext::StdQueue;
|
||||
|
||||
using testing::Eq;
|
||||
|
||||
//inherit from queue so we could take underlying container, because priority queue doesn't have equal operator defined
|
||||
// inherit from queue so we could take underlying container, because priority
|
||||
// queue doesn't have equal operator defined
|
||||
template<typename T, typename C>
|
||||
struct PriorityQueueCnt : public std::priority_queue<T, C>
|
||||
{
|
||||
@@ -46,12 +47,15 @@ struct PriorityQueueCnt : public std::priority_queue<T, C>
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void test(SerializationContext& ctx, const T& v, T& r) {
|
||||
void
|
||||
test(SerializationContext& ctx, const T& v, T& r)
|
||||
{
|
||||
ctx.createSerializer().ext4b(v, StdQueue{ 10 });
|
||||
ctx.createDeserializer().ext4b(r, StdQueue{ 10 });
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdQueue, QueueDefaultContainer) {
|
||||
TEST(SerializeExtensionStdQueue, QueueDefaultContainer)
|
||||
{
|
||||
std::queue<int32_t> t1{};
|
||||
t1.push(3);
|
||||
t1.push(-4854);
|
||||
@@ -62,7 +66,8 @@ TEST(SerializeExtensionStdQueue, QueueDefaultContainer) {
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdQueue, QueueVectorContainer) {
|
||||
TEST(SerializeExtensionStdQueue, QueueVectorContainer)
|
||||
{
|
||||
std::queue<int32_t, std::vector<int32_t>> t1{};
|
||||
t1.push(3);
|
||||
t1.push(-4854);
|
||||
@@ -73,7 +78,8 @@ TEST(SerializeExtensionStdQueue, QueueVectorContainer) {
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdQueue, PriorityQueueDefaultContainer) {
|
||||
TEST(SerializeExtensionStdQueue, PriorityQueueDefaultContainer)
|
||||
{
|
||||
std::priority_queue<int32_t> t1{};
|
||||
t1.push(3);
|
||||
t1.push(-4854);
|
||||
@@ -86,7 +92,8 @@ TEST(SerializeExtensionStdQueue, PriorityQueueDefaultContainer) {
|
||||
EXPECT_THAT(ct1, Eq(cr1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdQueue, PriorityQueueDequeContainer) {
|
||||
TEST(SerializeExtensionStdQueue, PriorityQueueDequeContainer)
|
||||
{
|
||||
std::priority_queue<int32_t, std::deque<int32_t>> t1{};
|
||||
t1.push(678);
|
||||
t1.push(-44);
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -23,56 +23,60 @@
|
||||
#include <bitsery/ext/std_set.h>
|
||||
#include <set>
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include "serialization_test_utils.h"
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
using StdSet = bitsery::ext::StdSet;
|
||||
|
||||
using testing::Eq;
|
||||
|
||||
template<typename T>
|
||||
class SerializeExtensionStdSet : public testing::Test {
|
||||
class SerializeExtensionStdSet : public testing::Test
|
||||
{
|
||||
public:
|
||||
using TContainer = T;
|
||||
const TContainer src = { 4, 8, 48, 4, 9845, 64, 8 };
|
||||
TContainer res{ 78, 74, 154, 8 };
|
||||
};
|
||||
|
||||
using SerializeExtensionStdSetTypes = ::testing::Types<
|
||||
std::unordered_set<int32_t>,
|
||||
using SerializeExtensionStdSetTypes =
|
||||
::testing::Types<std::unordered_set<int32_t>,
|
||||
std::unordered_multiset<int32_t>,
|
||||
std::set<int32_t>,
|
||||
std::multiset<int32_t>>;
|
||||
|
||||
TYPED_TEST_SUITE(SerializeExtensionStdSet, SerializeExtensionStdSetTypes, );
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSet, ValuesSyntaxDifferentSetTypes) {
|
||||
TYPED_TEST(SerializeExtensionStdSet, ValuesSyntaxDifferentSetTypes)
|
||||
{
|
||||
SerializationContext ctx1;
|
||||
ctx1.createSerializer().ext4b(this->src, StdSet{ 10 });
|
||||
ctx1.createDeserializer().ext4b(this->res, StdSet{ 10 });
|
||||
EXPECT_THAT(this->res, Eq(this->src));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdSet, ObjectSyntax) {
|
||||
TEST(SerializeExtensionStdSet, ObjectSyntax)
|
||||
{
|
||||
SerializationContext ctx1;
|
||||
std::set<MyStruct1> t1{MyStruct1{874 ,456}, MyStruct1{-874, -456}, MyStruct1{4894,0}};
|
||||
std::set<MyStruct1> t1{ MyStruct1{ 874, 456 },
|
||||
MyStruct1{ -874, -456 },
|
||||
MyStruct1{ 4894, 0 } };
|
||||
std::set<MyStruct1> r1{};
|
||||
ctx1.createSerializer().ext(t1, StdSet{ 10 });
|
||||
ctx1.createDeserializer().ext(r1, StdSet{ 10 });
|
||||
EXPECT_THAT(r1, Eq(t1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdSet, FunctionSyntax) {
|
||||
TEST(SerializeExtensionStdSet, FunctionSyntax)
|
||||
{
|
||||
SerializationContext ctx1;
|
||||
std::unordered_multiset<int32_t> t1{ 54, -484, 841, 79 };
|
||||
std::unordered_multiset<int32_t> r1{ 74, 878, 15, 16, -7, 5, -4, 8, 7 };
|
||||
auto& ser = ctx1.createSerializer();
|
||||
ser.ext(t1, StdSet{10}, [](decltype(ser)& ser, int32_t& v) {
|
||||
ser.value4b(v);
|
||||
});
|
||||
ser.ext(
|
||||
t1, StdSet{ 10 }, [](decltype(ser)& ser, int32_t& v) { ser.value4b(v); });
|
||||
auto& des = ctx1.createDeserializer();
|
||||
des.ext(r1, StdSet{10}, [](decltype(des)& des, int32_t& v) {
|
||||
des.value4b(v);
|
||||
});
|
||||
des.ext(
|
||||
r1, StdSet{ 10 }, [](decltype(des)& des, int32_t& v) { des.value4b(v); });
|
||||
EXPECT_THAT(r1, Eq(t1));
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -24,87 +24,102 @@
|
||||
#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;
|
||||
|
||||
using bitsery::ext::InheritanceContext;
|
||||
using bitsery::ext::PointerLinkingContext;
|
||||
using bitsery::ext::PointerType;
|
||||
using bitsery::ext::PolymorphicContext;
|
||||
using bitsery::ext::StandardRTTI;
|
||||
using bitsery::ext::PointerType;
|
||||
|
||||
using bitsery::ext::StdSmartPtr;
|
||||
using bitsery::ext::PointerObserver;
|
||||
using bitsery::ext::StdSmartPtr;
|
||||
|
||||
using testing::Eq;
|
||||
using testing::Ne;
|
||||
|
||||
struct Base {
|
||||
struct Base
|
||||
{
|
||||
uint8_t x{};
|
||||
|
||||
virtual ~Base() = default;
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, Base& o) {
|
||||
void
|
||||
serialize(S& s, Base& o)
|
||||
{
|
||||
s.value1b(o.x);
|
||||
}
|
||||
|
||||
struct Derived : virtual Base {
|
||||
struct Derived : virtual Base
|
||||
{
|
||||
uint8_t y{};
|
||||
|
||||
Derived() = default;
|
||||
|
||||
Derived(uint8_t x_, uint8_t y_) {
|
||||
Derived(uint8_t x_, uint8_t y_)
|
||||
{
|
||||
x = x_;
|
||||
y = y_;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, Derived& o) {
|
||||
void
|
||||
serialize(S& s, Derived& o)
|
||||
{
|
||||
s.ext(o, VirtualBaseClass<Base>{});
|
||||
s.value1b(o.y);
|
||||
}
|
||||
|
||||
struct MoreDerived : Derived {
|
||||
struct MoreDerived : Derived
|
||||
{
|
||||
uint8_t z{};
|
||||
|
||||
MoreDerived() = default;
|
||||
|
||||
MoreDerived(uint8_t x_, uint8_t y_, uint8_t z_) : Derived(x_, y_) {
|
||||
MoreDerived(uint8_t x_, uint8_t y_, uint8_t z_)
|
||||
: Derived(x_, y_)
|
||||
{
|
||||
z = z_;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s, MoreDerived& o) {
|
||||
void
|
||||
serialize(S& s, MoreDerived& o)
|
||||
{
|
||||
s.ext(o, BaseClass<Derived>{});
|
||||
s.value1b(o.z);
|
||||
}
|
||||
|
||||
//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 {
|
||||
|
||||
template<>
|
||||
struct PolymorphicBaseClass<Base> : PolymorphicDerivedClasses<Derived> {
|
||||
struct PolymorphicBaseClass<Base> : PolymorphicDerivedClasses<Derived>
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct PolymorphicBaseClass<Derived> : PolymorphicDerivedClasses<MoreDerived> {
|
||||
struct PolymorphicBaseClass<Derived> : PolymorphicDerivedClasses<MoreDerived>
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class SerializeExtensionStdSmartPtrNonPolymorphicType : public testing::Test {
|
||||
class SerializeExtensionStdSmartPtrNonPolymorphicType : public testing::Test
|
||||
{
|
||||
public:
|
||||
template<typename U>
|
||||
using TPtr = typename T::template TData<U>;
|
||||
@@ -113,48 +128,52 @@ public:
|
||||
using TContext = std::tuple<PointerLinkingContext>;
|
||||
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;
|
||||
|
||||
TContext plctx{};
|
||||
SerContext sctx{};
|
||||
|
||||
typename SerContext::TSerializer& createSerializer() {
|
||||
typename SerContext::TSerializer& createSerializer()
|
||||
{
|
||||
return sctx.createSerializer(plctx);
|
||||
}
|
||||
|
||||
typename SerContext::TDeserializer& createDeserializer() {
|
||||
typename SerContext::TDeserializer& createDeserializer()
|
||||
{
|
||||
return sctx.createDeserializer(plctx);
|
||||
}
|
||||
|
||||
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()); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class SerializeExtensionStdSmartPtrPolymorphicType : public testing::Test {
|
||||
class SerializeExtensionStdSmartPtrPolymorphicType : public testing::Test
|
||||
{
|
||||
public:
|
||||
template<typename U>
|
||||
using TPtr = typename T::template TData<U>;
|
||||
using TExt = typename T::TExt;
|
||||
|
||||
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;
|
||||
|
||||
TContext plctx{};
|
||||
SerContext sctx{};
|
||||
|
||||
typename SerContext::TSerializer& createSerializer() {
|
||||
typename SerContext::TSerializer& createSerializer()
|
||||
{
|
||||
auto& res = sctx.createSerializer(plctx);
|
||||
std::get<2>(plctx).clear();
|
||||
// bind serializer with classes
|
||||
@@ -163,7 +182,8 @@ public:
|
||||
return res;
|
||||
}
|
||||
|
||||
typename SerContext::TDeserializer& createDeserializer() {
|
||||
typename SerContext::TDeserializer& createDeserializer()
|
||||
{
|
||||
auto& res = sctx.createDeserializer(plctx);
|
||||
std::get<2>(plctx).clear();
|
||||
// bind deserializer with classes
|
||||
@@ -172,40 +192,39 @@ public:
|
||||
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()); }
|
||||
};
|
||||
|
||||
struct UniquePtrTest {
|
||||
struct UniquePtrTest
|
||||
{
|
||||
template<typename T>
|
||||
using TData = std::unique_ptr<T>;
|
||||
using TExt = StdSmartPtr;
|
||||
};
|
||||
|
||||
struct SharedPtrTest {
|
||||
struct SharedPtrTest
|
||||
{
|
||||
template<typename T>
|
||||
using TData = std::shared_ptr<T>;
|
||||
using TExt = StdSmartPtr;
|
||||
};
|
||||
|
||||
using TestingWithNonPolymorphicTypes = ::testing::Types<
|
||||
UniquePtrTest,
|
||||
SharedPtrTest>;
|
||||
using TestingWithNonPolymorphicTypes =
|
||||
::testing::Types<UniquePtrTest, SharedPtrTest>;
|
||||
|
||||
TYPED_TEST_SUITE(SerializeExtensionStdSmartPtrNonPolymorphicType, TestingWithNonPolymorphicTypes,);
|
||||
TYPED_TEST_SUITE(SerializeExtensionStdSmartPtrNonPolymorphicType,
|
||||
TestingWithNonPolymorphicTypes, );
|
||||
|
||||
using TestingWithPolymorphicTypes = ::testing::Types<
|
||||
UniquePtrTest,
|
||||
SharedPtrTest>;
|
||||
using TestingWithPolymorphicTypes =
|
||||
::testing::Types<UniquePtrTest, SharedPtrTest>;
|
||||
|
||||
TYPED_TEST_SUITE(SerializeExtensionStdSmartPtrPolymorphicType, TestingWithPolymorphicTypes,);
|
||||
TYPED_TEST_SUITE(SerializeExtensionStdSmartPtrPolymorphicType,
|
||||
TestingWithPolymorphicTypes, );
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data0Result0) {
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data0Result0)
|
||||
{
|
||||
using Ptr = typename TestFixture::template TPtr<MyStruct1>;
|
||||
using Ext = typename TestFixture::TExt;
|
||||
|
||||
@@ -218,7 +237,8 @@ TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data0Result0) {
|
||||
EXPECT_THAT(res.get(), ::testing::IsNull());
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data0Result1) {
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data0Result1)
|
||||
{
|
||||
using Ptr = typename TestFixture::template TPtr<MyStruct1>;
|
||||
using Ext = typename TestFixture::TExt;
|
||||
|
||||
@@ -231,7 +251,8 @@ TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data0Result1) {
|
||||
EXPECT_THAT(res.get(), ::testing::IsNull());
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data1Result0) {
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data1Result0)
|
||||
{
|
||||
using Ptr = typename TestFixture::template TPtr<MyStruct1>;
|
||||
using Ext = typename TestFixture::TExt;
|
||||
|
||||
@@ -246,7 +267,8 @@ TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data1Result0) {
|
||||
EXPECT_THAT(res->i2, Eq(data->i2));
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data1Result1) {
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data1Result1)
|
||||
{
|
||||
using Ptr = typename TestFixture::template TPtr<MyStruct1>;
|
||||
using Ext = typename TestFixture::TExt;
|
||||
|
||||
@@ -261,7 +283,9 @@ TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data1Result1) {
|
||||
EXPECT_THAT(res->i2, Eq(data->i2));
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, CanUseLambdaOverload) {
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType,
|
||||
CanUseLambdaOverload)
|
||||
{
|
||||
using Ptr = typename TestFixture::template TPtr<MyStruct1>;
|
||||
using Ext = typename TestFixture::TExt;
|
||||
|
||||
@@ -273,15 +297,15 @@ TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, CanUseLambdaOverload
|
||||
});
|
||||
Ptr res{ new MyStruct1{ 97, 12 } };
|
||||
auto& des = this->createDeserializer();
|
||||
des.ext(res, Ext{}, [](decltype(des)& des, MyStruct1& o) {
|
||||
des.value4b(o.i1);
|
||||
});
|
||||
des.ext(
|
||||
res, Ext{}, [](decltype(des)& des, MyStruct1& o) { des.value4b(o.i1); });
|
||||
|
||||
EXPECT_THAT(res->i1, Eq(data->i1));
|
||||
EXPECT_THAT(res->i2, Ne(data->i2));
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, CanUseValueOverload) {
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, CanUseValueOverload)
|
||||
{
|
||||
using Ptr = typename TestFixture::template TPtr<uint16_t>;
|
||||
using Ext = typename TestFixture::TExt;
|
||||
|
||||
@@ -292,7 +316,9 @@ TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, CanUseValueOverload)
|
||||
EXPECT_THAT(*res, Eq(*data));
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, FirstPtrThenPointerObserver) {
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType,
|
||||
FirstPtrThenPointerObserver)
|
||||
{
|
||||
using Ptr = typename TestFixture::template TPtr<uint16_t>;
|
||||
using Ext = typename TestFixture::TExt;
|
||||
|
||||
@@ -310,7 +336,9 @@ TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, FirstPtrThenPointerO
|
||||
EXPECT_THAT(resObs, Eq(res.get()));
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, FirstPointerObserverThenPtr) {
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType,
|
||||
FirstPointerObserverThenPtr)
|
||||
{
|
||||
using Ptr = typename TestFixture::template TPtr<uint16_t>;
|
||||
using Ext = typename TestFixture::TExt;
|
||||
|
||||
@@ -327,7 +355,8 @@ TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, FirstPointerObserver
|
||||
EXPECT_THAT(resObs, Eq(res.get()));
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, Data0Result0) {
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, Data0Result0)
|
||||
{
|
||||
using Ptr = typename TestFixture::template TPtr<Base>;
|
||||
using Ext = typename TestFixture::TExt;
|
||||
|
||||
@@ -340,7 +369,8 @@ TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, Data0Result0) {
|
||||
EXPECT_THAT(baseData.get(), ::testing::IsNull());
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, Data0Result1) {
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, Data0Result1)
|
||||
{
|
||||
using Ptr = typename TestFixture::template TPtr<Base>;
|
||||
using Ext = typename TestFixture::TExt;
|
||||
|
||||
@@ -354,7 +384,8 @@ TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, Data0Result1) {
|
||||
EXPECT_THAT(baseData.get(), ::testing::IsNull());
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, Data1Result0) {
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, Data1Result0)
|
||||
{
|
||||
using Ptr = typename TestFixture::template TPtr<Base>;
|
||||
using Ext = typename TestFixture::TExt;
|
||||
|
||||
@@ -372,7 +403,9 @@ TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, Data1Result0) {
|
||||
EXPECT_THAT(res->y, Eq(data->y));
|
||||
}
|
||||
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, DataAndResultWithDifferentRuntimeTypes) {
|
||||
TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType,
|
||||
DataAndResultWithDifferentRuntimeTypes)
|
||||
{
|
||||
using Ptr = typename TestFixture::template TPtr<Base>;
|
||||
using Ext = typename TestFixture::TExt;
|
||||
|
||||
@@ -390,49 +423,51 @@ TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, DataAndResultWithDiffer
|
||||
EXPECT_THAT(res->y, Eq(data->y));
|
||||
}
|
||||
|
||||
class SerializeExtensionStdSmartSharedPtr : public testing::Test {
|
||||
class SerializeExtensionStdSmartSharedPtr : public testing::Test
|
||||
{
|
||||
public:
|
||||
|
||||
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;
|
||||
|
||||
TContext plctx{};
|
||||
SerContext sctx{};
|
||||
|
||||
typename SerContext::TSerializer& createSerializer() {
|
||||
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>{});
|
||||
std::get<2>(plctx).registerBasesList<SerContext::TSerializer>(
|
||||
bitsery::ext::PolymorphicClassesList<Base>{});
|
||||
return res;
|
||||
}
|
||||
|
||||
typename SerContext::TDeserializer& createDeserializer() {
|
||||
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>{});
|
||||
std::get<2>(plctx).registerBasesList<SerContext::TDeserializer>(
|
||||
bitsery::ext::PolymorphicClassesList<Base>{});
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t getBufferSize() const {
|
||||
return sctx.getBufferSize();
|
||||
}
|
||||
size_t getBufferSize() const { return sctx.getBufferSize(); }
|
||||
|
||||
bool isPointerContextValid() {
|
||||
return std::get<0>(plctx).isValid();
|
||||
}
|
||||
bool isPointerContextValid() { return std::get<0>(plctx).isValid(); }
|
||||
|
||||
void clearSharedState() {
|
||||
return std::get<0>(plctx).clearSharedState();
|
||||
}
|
||||
void clearSharedState() { return std::get<0>(plctx).clearSharedState(); }
|
||||
};
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, SameSharedObjectIsSerializedOnce) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, SameSharedObjectIsSerializedOnce)
|
||||
{
|
||||
|
||||
std::shared_ptr<Base> baseData1{ new Derived{ 3, 78 } };
|
||||
std::shared_ptr<Base> baseData2{ baseData1 };
|
||||
@@ -449,7 +484,9 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, SameSharedObjectIsSerializedOnce) {
|
||||
EXPECT_TRUE(isPointerContextValid());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, PointerLinkingContextCorrectlyClearSharedState) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr,
|
||||
PointerLinkingContextCorrectlyClearSharedState)
|
||||
{
|
||||
|
||||
std::shared_ptr<Base> baseData1{ new Derived{ 3, 78 } };
|
||||
|
||||
@@ -464,7 +501,8 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, PointerLinkingContextCorrectlyClearS
|
||||
EXPECT_TRUE(isPointerContextValid());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, CorrectlyManagesSameSharedObject) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, CorrectlyManagesSameSharedObject)
|
||||
{
|
||||
|
||||
std::shared_ptr<Base> baseData1{ new Derived{ 3, 78 } };
|
||||
std::shared_ptr<Base> baseData2{ new Derived{ 55, 11 } };
|
||||
@@ -495,7 +533,8 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, CorrectlyManagesSameSharedObject) {
|
||||
EXPECT_TRUE(isPointerContextValid());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, FirstSharedThenWeakPtr) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, FirstSharedThenWeakPtr)
|
||||
{
|
||||
|
||||
std::shared_ptr<Base> baseData1{ new Derived{ 3, 78 } };
|
||||
std::weak_ptr<Base> baseData11{ baseData1 };
|
||||
@@ -526,7 +565,8 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, FirstSharedThenWeakPtr) {
|
||||
EXPECT_TRUE(isPointerContextValid());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, FirstWeakThenSharedPtr) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, FirstWeakThenSharedPtr)
|
||||
{
|
||||
|
||||
std::shared_ptr<MyStruct1> baseData1{ new MyStruct1{ 3, 78 } };
|
||||
std::weak_ptr<MyStruct1> baseData11{ baseData1 };
|
||||
@@ -546,7 +586,6 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, FirstWeakThenSharedPtr) {
|
||||
|
||||
clearSharedState();
|
||||
|
||||
|
||||
EXPECT_THAT(*baseData1, Eq(*baseRes1));
|
||||
EXPECT_THAT(baseRes1.use_count(), Eq(1));
|
||||
EXPECT_THAT(baseRes2.use_count(), Eq(0));
|
||||
@@ -556,7 +595,8 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, FirstWeakThenSharedPtr) {
|
||||
EXPECT_TRUE(isPointerContextValid());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, WeakPtrFirstPolymorphicData0Result1) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, WeakPtrFirstPolymorphicData0Result1)
|
||||
{
|
||||
|
||||
std::shared_ptr<Base> baseData1{};
|
||||
std::weak_ptr<Base> baseData2{};
|
||||
@@ -570,7 +610,6 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WeakPtrFirstPolymorphicData0Result1)
|
||||
des.ext(baseRes2, StdSmartPtr{});
|
||||
des.ext(baseRes1, StdSmartPtr{});
|
||||
|
||||
|
||||
clearSharedState();
|
||||
|
||||
EXPECT_THAT(baseRes1.use_count(), Eq(0));
|
||||
@@ -579,7 +618,9 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WeakPtrFirstPolymorphicData0Result1)
|
||||
EXPECT_TRUE(isPointerContextValid());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, WeakPtrFirstNonPolymorphicData0Result1) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr,
|
||||
WeakPtrFirstNonPolymorphicData0Result1)
|
||||
{
|
||||
|
||||
std::shared_ptr<MyStruct2> baseData1{};
|
||||
std::weak_ptr<MyStruct2> baseData2{};
|
||||
@@ -587,13 +628,13 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WeakPtrFirstNonPolymorphicData0Resul
|
||||
ser.ext(baseData2, StdSmartPtr{});
|
||||
ser.ext(baseData1, StdSmartPtr{});
|
||||
|
||||
std::shared_ptr<MyStruct2> baseRes1{new MyStruct2{MyStruct2::MyEnum::V4, {1, 87}}};
|
||||
std::shared_ptr<MyStruct2> baseRes1{ new MyStruct2{ MyStruct2::MyEnum::V4,
|
||||
{ 1, 87 } } };
|
||||
std::weak_ptr<MyStruct2> baseRes2{ baseRes1 };
|
||||
auto& des = createDeserializer();
|
||||
des.ext(baseRes2, StdSmartPtr{});
|
||||
des.ext(baseRes1, StdSmartPtr{});
|
||||
|
||||
|
||||
clearSharedState();
|
||||
|
||||
EXPECT_THAT(baseRes1.use_count(), Eq(0));
|
||||
@@ -602,7 +643,8 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WeakPtrFirstNonPolymorphicData0Resul
|
||||
EXPECT_TRUE(isPointerContextValid());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, FewPtrsAreEmpty) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, FewPtrsAreEmpty)
|
||||
{
|
||||
|
||||
std::shared_ptr<Base> baseData1{ new Derived{ 3, 78 } };
|
||||
std::shared_ptr<Base> baseData2{};
|
||||
@@ -635,8 +677,8 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, FewPtrsAreEmpty) {
|
||||
EXPECT_TRUE(isPointerContextValid());
|
||||
}
|
||||
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, WhenResultObjectExistsSameType) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, WhenResultObjectExistsSameType)
|
||||
{
|
||||
|
||||
std::shared_ptr<Base> baseData1{ new Derived{ 3, 78 } };
|
||||
auto& ser = createSerializer();
|
||||
@@ -653,7 +695,8 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WhenResultObjectExistsSameType) {
|
||||
EXPECT_TRUE(isPointerContextValid());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, WhenResultObjectExistsDifferentType) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, WhenResultObjectExistsDifferentType)
|
||||
{
|
||||
|
||||
std::shared_ptr<Base> baseData1{ new Derived{ 3, 78 } };
|
||||
auto& ser = createSerializer();
|
||||
@@ -671,7 +714,9 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WhenResultObjectExistsDifferentType)
|
||||
EXPECT_TRUE(isPointerContextValid());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, WhenOnlyWeakPtrIsSerializedThenPointerCointextIsInvalid) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr,
|
||||
WhenOnlyWeakPtrIsSerializedThenPointerCointextIsInvalid)
|
||||
{
|
||||
std::shared_ptr<Base> tmp{ new Derived{ 3, 78 } };
|
||||
std::weak_ptr<Base> baseData1{ tmp };
|
||||
auto& ser = createSerializer();
|
||||
@@ -680,7 +725,9 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WhenOnlyWeakPtrIsSerializedThenPoint
|
||||
EXPECT_FALSE(isPointerContextValid());
|
||||
}
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, WhenOnlyWeakPtrIsDeserializedThenPointerCointextIsInvalid) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr,
|
||||
WhenOnlyWeakPtrIsDeserializedThenPointerCointextIsInvalid)
|
||||
{
|
||||
std::shared_ptr<Base> baseData1{ new Derived{ 3, 78 } };
|
||||
auto& ser = createSerializer();
|
||||
ser.ext(baseData1, StdSmartPtr{});
|
||||
@@ -694,21 +741,27 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, WhenOnlyWeakPtrIsDeserializedThenPoi
|
||||
EXPECT_THAT(baseRes1.use_count(), Eq(1));
|
||||
clearSharedState();
|
||||
EXPECT_THAT(baseRes1.use_count(), Eq(0));
|
||||
|
||||
}
|
||||
|
||||
struct TestSharedFromThis : public std::enable_shared_from_this<TestSharedFromThis> {
|
||||
struct TestSharedFromThis
|
||||
: public std::enable_shared_from_this<TestSharedFromThis>
|
||||
{
|
||||
float x{};
|
||||
|
||||
explicit TestSharedFromThis() : std::enable_shared_from_this<TestSharedFromThis>() {}
|
||||
explicit TestSharedFromThis()
|
||||
: std::enable_shared_from_this<TestSharedFromThis>()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename S>
|
||||
void serialize(S& s) {
|
||||
void serialize(S& s)
|
||||
{
|
||||
s.value4b(x);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, EnableSharedFromThis) {
|
||||
TEST_F(SerializeExtensionStdSmartSharedPtr, EnableSharedFromThis)
|
||||
{
|
||||
std::shared_ptr<TestSharedFromThis> dataPtr(new TestSharedFromThis{});
|
||||
std::shared_ptr<TestSharedFromThis> resPtr{};
|
||||
createSerializer().ext(dataPtr, StdSmartPtr{});
|
||||
@@ -719,16 +772,17 @@ TEST_F(SerializeExtensionStdSmartSharedPtr, EnableSharedFromThis) {
|
||||
EXPECT_THAT(resPtr2.use_count(), Eq(2));
|
||||
}
|
||||
|
||||
struct CustomDeleter {
|
||||
void operator()(Base* p) {
|
||||
delete p;
|
||||
}
|
||||
struct CustomDeleter
|
||||
{
|
||||
void operator()(Base* p) { delete p; }
|
||||
};
|
||||
|
||||
class SerializeExtensionStdSmartUniquePtr : public SerializeExtensionStdSmartSharedPtr {
|
||||
};
|
||||
class SerializeExtensionStdSmartUniquePtr
|
||||
: public SerializeExtensionStdSmartSharedPtr
|
||||
{};
|
||||
|
||||
TEST_F(SerializeExtensionStdSmartUniquePtr, WithCustomDeleter) {
|
||||
TEST_F(SerializeExtensionStdSmartUniquePtr, WithCustomDeleter)
|
||||
{
|
||||
std::unique_ptr<Base, CustomDeleter> dataPtr(new Derived{ 87, 7 });
|
||||
std::unique_ptr<Base, CustomDeleter> resPtr{};
|
||||
createSerializer().ext(dataPtr, StdSmartPtr{});
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,23 +20,24 @@
|
||||
// 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/std_stack.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include "serialization_test_utils.h"
|
||||
|
||||
|
||||
using StdStack = bitsery::ext::StdStack;
|
||||
|
||||
using testing::Eq;
|
||||
|
||||
|
||||
template<typename T>
|
||||
void test(SerializationContext& ctx, const T& v, T& r) {
|
||||
void
|
||||
test(SerializationContext& ctx, const T& v, T& r)
|
||||
{
|
||||
ctx.createSerializer().ext4b(v, StdStack{ 10 });
|
||||
ctx.createDeserializer().ext4b(r, StdStack{ 10 });
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdStack, DefaultContainer) {
|
||||
TEST(SerializeExtensionStdStack, DefaultContainer)
|
||||
{
|
||||
std::stack<int32_t> t1{};
|
||||
t1.push(3);
|
||||
t1.push(-4854);
|
||||
@@ -47,7 +48,8 @@ TEST(SerializeExtensionStdStack, DefaultContainer) {
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdStack, VectorContainer) {
|
||||
TEST(SerializeExtensionStdStack, VectorContainer)
|
||||
{
|
||||
std::stack<int32_t, std::vector<int32_t>> t1{};
|
||||
t1.push(3);
|
||||
t1.push(-4854);
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,8 +20,8 @@
|
||||
// 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;
|
||||
|
||||
@@ -32,8 +32,11 @@ using testing::Eq;
|
||||
template<typename T, size_t N>
|
||||
using OverloadValue = bitsery::ext::OverloadValue<T, N>;
|
||||
|
||||
TEST(SerializeExtensionStdTuple, UseDefaultSerializeFunction) {
|
||||
std::tuple<MyStruct1, MyStruct2> t1{MyStruct1{-789, 45}, MyStruct2{MyStruct2::MyEnum::V3, MyStruct1{}}};
|
||||
TEST(SerializeExtensionStdTuple, UseDefaultSerializeFunction)
|
||||
{
|
||||
std::tuple<MyStruct1, MyStruct2> t1{
|
||||
MyStruct1{ -789, 45 }, MyStruct2{ MyStruct2::MyEnum::V3, MyStruct1{} }
|
||||
};
|
||||
std::tuple<MyStruct1, MyStruct2> r1{};
|
||||
SerializationContext ctx;
|
||||
ctx.createSerializer().ext(t1, bitsery::ext::StdTuple{});
|
||||
@@ -41,29 +44,32 @@ TEST(SerializeExtensionStdTuple, UseDefaultSerializeFunction) {
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdTuple, ValueTypesCanBeSerializedWithLambdaAndOrCallableObject) {
|
||||
TEST(SerializeExtensionStdTuple,
|
||||
ValueTypesCanBeSerializedWithLambdaAndOrCallableObject)
|
||||
{
|
||||
std::tuple<float, int32_t> t1{ 123.456f, -898754656 };
|
||||
std::tuple<float, int32_t> r1{};
|
||||
SerializationContext ctx;
|
||||
auto exec = [](auto& s, auto& o) {
|
||||
s.ext(o, bitsery::ext::StdTuple{
|
||||
[](auto& s1, float& o1) {
|
||||
s1.value4b(o1);
|
||||
},
|
||||
OverloadValue<int32_t, 4>{}
|
||||
});
|
||||
s.ext(o,
|
||||
bitsery::ext::StdTuple{ [](auto& s1, float& o1) { s1.value4b(o1); },
|
||||
OverloadValue<int32_t, 4>{} });
|
||||
};
|
||||
ctx.createSerializer().object(t1, exec);
|
||||
ctx.createDeserializer().object(r1, exec);
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdTuple, CanOverloadDefaultSerializeFunction) {
|
||||
std::tuple<MyStruct1, MyStruct2> t1{MyStruct1{-789, 45}, MyStruct2{MyStruct2::MyEnum::V3, MyStruct1{}}};
|
||||
TEST(SerializeExtensionStdTuple, CanOverloadDefaultSerializeFunction)
|
||||
{
|
||||
std::tuple<MyStruct1, MyStruct2> t1{
|
||||
MyStruct1{ -789, 45 }, MyStruct2{ MyStruct2::MyEnum::V3, MyStruct1{} }
|
||||
};
|
||||
std::tuple<MyStruct1, MyStruct2> r1{};
|
||||
SerializationContext ctx;
|
||||
auto exec = [](auto& s, auto& o) {
|
||||
s.ext(o, bitsery::ext::StdTuple{
|
||||
s.ext(o,
|
||||
bitsery::ext::StdTuple{
|
||||
[](auto& s1, MyStruct1& o1) {
|
||||
s1.value4b(o1.i1);
|
||||
// do not serialize other element, it should be 0 (default)
|
||||
@@ -77,7 +83,8 @@ TEST(SerializeExtensionStdTuple, CanOverloadDefaultSerializeFunction) {
|
||||
EXPECT_THAT(std::get<0>(t1).i2, ::testing::Ne(std::get<0>(r1).i2));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdTuple, EmptyTuple) {
|
||||
TEST(SerializeExtensionStdTuple, EmptyTuple)
|
||||
{
|
||||
std::tuple<> t1{};
|
||||
std::tuple<> r1{};
|
||||
SerializationContext ctx;
|
||||
@@ -86,40 +93,48 @@ TEST(SerializeExtensionStdTuple, EmptyTuple) {
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
struct NonDefaultConstructable {
|
||||
explicit NonDefaultConstructable(float x) : _x{x} {}
|
||||
struct NonDefaultConstructable
|
||||
{
|
||||
explicit NonDefaultConstructable(float x)
|
||||
: _x{ x }
|
||||
{
|
||||
}
|
||||
|
||||
float _x;
|
||||
|
||||
bool operator==(const NonDefaultConstructable& rhs) const {
|
||||
bool operator==(const NonDefaultConstructable& rhs) const
|
||||
{
|
||||
return _x == rhs._x;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class bitsery::Access;
|
||||
|
||||
NonDefaultConstructable() : _x{0.0f} {};
|
||||
NonDefaultConstructable()
|
||||
: _x{ 0.0f } {};
|
||||
};
|
||||
|
||||
TEST(SerializeExtensionStdTuple, NonDefaultConstructable) {
|
||||
TEST(SerializeExtensionStdTuple, NonDefaultConstructable)
|
||||
{
|
||||
std::tuple<NonDefaultConstructable> t1{ 34.0f };
|
||||
std::tuple<NonDefaultConstructable> r1{ 8.0f };
|
||||
SerializationContext ctx;
|
||||
ctx.createSerializer().ext(t1, bitsery::ext::StdTuple{
|
||||
[](auto& s, NonDefaultConstructable& v) {
|
||||
s.value4b(v._x);
|
||||
},
|
||||
ctx.createSerializer().ext(
|
||||
t1,
|
||||
bitsery::ext::StdTuple{
|
||||
[](auto& s, NonDefaultConstructable& v) { s.value4b(v._x); },
|
||||
});
|
||||
ctx.createDeserializer().ext(r1, bitsery::ext::StdTuple{
|
||||
[](auto& s, NonDefaultConstructable& v) {
|
||||
s.value4b(v._x);
|
||||
},
|
||||
ctx.createDeserializer().ext(
|
||||
r1,
|
||||
bitsery::ext::StdTuple{
|
||||
[](auto& s, NonDefaultConstructable& v) { s.value4b(v._x); },
|
||||
});
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma message("C++17 and /Zc:__cplusplus option is required to enable std::tuple tests")
|
||||
#pragma message( \
|
||||
"C++17 and /Zc:__cplusplus option is required to enable std::tuple tests")
|
||||
#else
|
||||
#pragma message("C++17 is required to enable std::tuple tests")
|
||||
#endif
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
// 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,
|
||||
@@ -20,9 +20,8 @@
|
||||
// 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>
|
||||
|
||||
#if __cplusplus > 201402L
|
||||
|
||||
@@ -33,7 +32,8 @@ using testing::Eq;
|
||||
template<typename T, size_t N>
|
||||
using OverloadValue = bitsery::ext::OverloadValue<T, N>;
|
||||
|
||||
TEST(SerializeExtensionStdVariant, UseSerializeFunction) {
|
||||
TEST(SerializeExtensionStdVariant, UseSerializeFunction)
|
||||
{
|
||||
|
||||
std::variant<MyStruct1, MyStruct2> t1{ MyStruct1{ 978, 15 } };
|
||||
std::variant<MyStruct1, MyStruct2> r1{ MyStruct2{} };
|
||||
@@ -43,9 +43,12 @@ TEST(SerializeExtensionStdVariant, UseSerializeFunction) {
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdVariant, WhenTwoIndicesWithSameTypeThenDeserializeCorrectIndex) {
|
||||
TEST(SerializeExtensionStdVariant,
|
||||
WhenTwoIndicesWithSameTypeThenDeserializeCorrectIndex)
|
||||
{
|
||||
|
||||
std::variant<MyStruct1, MyStruct2, MyStruct1> t1{std::in_place_index_t<2>{}, MyStruct1{978, 15}};
|
||||
std::variant<MyStruct1, MyStruct2, MyStruct1> t1{ std::in_place_index_t<2>{},
|
||||
MyStruct1{ 978, 15 } };
|
||||
std::variant<MyStruct1, MyStruct2, MyStruct1> r1{ MyStruct2{} };
|
||||
SerializationContext ctx;
|
||||
ctx.createSerializer().ext(t1, bitsery::ext::StdVariant{});
|
||||
@@ -53,48 +56,49 @@ TEST(SerializeExtensionStdVariant, WhenTwoIndicesWithSameTypeThenDeserializeCorr
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdVariant, ValueTypesCanBeSerializedWithLambda) {
|
||||
TEST(SerializeExtensionStdVariant, ValueTypesCanBeSerializedWithLambda)
|
||||
{
|
||||
|
||||
std::variant<float, char, MyStruct1> t1{ 5.6f };
|
||||
std::variant<float, char, MyStruct1> r1{ MyStruct1{} };
|
||||
SerializationContext ctx;
|
||||
auto fncFloat = [](auto& s, float& v) {
|
||||
s.value4b(v);
|
||||
};
|
||||
auto fncChar = [](auto& s, char& v) {
|
||||
s.value1b(v);
|
||||
};
|
||||
auto fncFloat = [](auto& s, float& v) { s.value4b(v); };
|
||||
auto fncChar = [](auto& s, char& v) { s.value1b(v); };
|
||||
ctx.createSerializer().ext(t1, bitsery::ext::StdVariant{ fncFloat, fncChar });
|
||||
ctx.createDeserializer().ext(r1, bitsery::ext::StdVariant{fncFloat, fncChar});
|
||||
ctx.createDeserializer().ext(r1,
|
||||
bitsery::ext::StdVariant{ fncFloat, fncChar });
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdVariant, ValueTypesCanBeSerializedWithLambdaAndOrCallableObject) {
|
||||
TEST(SerializeExtensionStdVariant,
|
||||
ValueTypesCanBeSerializedWithLambdaAndOrCallableObject)
|
||||
{
|
||||
std::variant<float, char, MyStruct1> t1{ 'Z' };
|
||||
std::variant<float, char, MyStruct1> r1{ MyStruct1{} };
|
||||
SerializationContext ctx;
|
||||
auto fncFloat = [](auto& s, float& v) {
|
||||
s.value4b(v);
|
||||
};
|
||||
auto fncFloat = [](auto& s, float& v) { s.value4b(v); };
|
||||
|
||||
ctx.createSerializer().ext(t1, bitsery::ext::StdVariant{fncFloat, OverloadValue<char, 1>{}});
|
||||
ctx.createDeserializer().ext(r1, bitsery::ext::StdVariant{fncFloat, OverloadValue<char, 1>{}});
|
||||
ctx.createSerializer().ext(
|
||||
t1, bitsery::ext::StdVariant{ fncFloat, OverloadValue<char, 1>{} });
|
||||
ctx.createDeserializer().ext(
|
||||
r1, bitsery::ext::StdVariant{ fncFloat, OverloadValue<char, 1>{} });
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
TEST(SerializeExtensionStdVariant, CanOverloadDefaultSerializationFunction) {
|
||||
TEST(SerializeExtensionStdVariant, CanOverloadDefaultSerializationFunction)
|
||||
{
|
||||
std::variant<MyStruct2, MyStruct1, int32_t> t1{ MyStruct1{ 5, 9 } };
|
||||
std::variant<MyStruct2, MyStruct1, int32_t> r1{ MyStruct1{} };
|
||||
SerializationContext ctx;
|
||||
auto exec = [](auto& s, std::variant<MyStruct2, MyStruct1, int32_t>& o) {
|
||||
using S = decltype(s);
|
||||
s.ext(o, bitsery::ext::StdVariant{
|
||||
[](S& s, MyStruct1& v) {
|
||||
s.ext(o,
|
||||
bitsery::ext::StdVariant{ [](S& s, MyStruct1& v) {
|
||||
s.value4b(v.i1);
|
||||
//do not serialize other element, it should be 0 (default)
|
||||
// do not serialize other element, it
|
||||
// should be 0 (default)
|
||||
},
|
||||
OverloadValue<int32_t, 4>{}
|
||||
});
|
||||
OverloadValue<int32_t, 4>{} });
|
||||
};
|
||||
|
||||
ctx.createSerializer().object(t1, exec);
|
||||
@@ -102,35 +106,42 @@ TEST(SerializeExtensionStdVariant, CanOverloadDefaultSerializationFunction) {
|
||||
EXPECT_THAT(std::get<1>(r1).i2, Eq(0));
|
||||
}
|
||||
|
||||
|
||||
struct NonDefaultConstructable {
|
||||
explicit NonDefaultConstructable(float x) : _x{x} {}
|
||||
struct NonDefaultConstructable
|
||||
{
|
||||
explicit NonDefaultConstructable(float x)
|
||||
: _x{ x }
|
||||
{
|
||||
}
|
||||
|
||||
float _x;
|
||||
|
||||
bool operator==(const NonDefaultConstructable& rhs) const {
|
||||
bool operator==(const NonDefaultConstructable& rhs) const
|
||||
{
|
||||
return _x == rhs._x;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class bitsery::Access;
|
||||
|
||||
NonDefaultConstructable() : _x{0.0f} {};
|
||||
NonDefaultConstructable()
|
||||
: _x{ 0.0f } {};
|
||||
};
|
||||
|
||||
TEST(SerializeExtensionStdVariant, CanUseNonDefaultConstructableTypes) {
|
||||
std::variant<NonDefaultConstructable, MyStruct1, int32_t> t1{NonDefaultConstructable{123.456f}};
|
||||
TEST(SerializeExtensionStdVariant, CanUseNonDefaultConstructableTypes)
|
||||
{
|
||||
std::variant<NonDefaultConstructable, MyStruct1, int32_t> t1{
|
||||
NonDefaultConstructable{ 123.456f }
|
||||
};
|
||||
std::variant<NonDefaultConstructable, MyStruct1, int32_t> r1{ MyStruct1{} };
|
||||
SerializationContext ctx;
|
||||
|
||||
auto exec = [](auto& s, std::variant<NonDefaultConstructable, MyStruct1, int32_t>& o) {
|
||||
auto exec = [](auto& s,
|
||||
std::variant<NonDefaultConstructable, MyStruct1, int32_t>& o) {
|
||||
using S = decltype(s);
|
||||
s.ext(o, bitsery::ext::StdVariant{
|
||||
[](S& s, NonDefaultConstructable& v) {
|
||||
s.value4b(v._x);
|
||||
},
|
||||
OverloadValue<int32_t, 4>{}
|
||||
});
|
||||
s.ext(o,
|
||||
bitsery::ext::StdVariant{
|
||||
[](S& s, NonDefaultConstructable& v) { s.value4b(v._x); },
|
||||
OverloadValue<int32_t, 4>{} });
|
||||
};
|
||||
|
||||
ctx.createSerializer().object(t1, exec);
|
||||
@@ -139,18 +150,17 @@ TEST(SerializeExtensionStdVariant, CanUseNonDefaultConstructableTypes) {
|
||||
EXPECT_THAT(t1, Eq(r1));
|
||||
}
|
||||
|
||||
|
||||
TEST(SerializeExtensionStdVariant, CorrectlyHandleMonoState) {
|
||||
TEST(SerializeExtensionStdVariant, CorrectlyHandleMonoState)
|
||||
{
|
||||
std::variant<std::monostate, NonDefaultConstructable, MyStruct1> t1{};
|
||||
std::variant<std::monostate, NonDefaultConstructable, MyStruct1> r1{};
|
||||
SerializationContext ctx;
|
||||
|
||||
auto exec = [](auto& s, auto& o) {
|
||||
using S = decltype(s);
|
||||
s.ext(o, bitsery::ext::StdVariant{
|
||||
[](S& s, NonDefaultConstructable& v) {
|
||||
s.value4b(v._x);
|
||||
},
|
||||
s.ext(o,
|
||||
bitsery::ext::StdVariant{
|
||||
[](S& s, NonDefaultConstructable& v) { s.value4b(v._x); },
|
||||
});
|
||||
};
|
||||
|
||||
@@ -164,11 +174,11 @@ TEST(SerializeExtensionStdVariant, CorrectlyHandleMonoState) {
|
||||
ctx1.createSerializer().ext(t2, bitsery::ext::StdVariant{});
|
||||
ctx1.createDeserializer().ext(r2, bitsery::ext::StdVariant{});
|
||||
EXPECT_THAT(t2, Eq(r2));
|
||||
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma message("C++17 and /Zc:__cplusplus option is required to enable std::variant tests")
|
||||
#pragma message( \
|
||||
"C++17 and /Zc:__cplusplus option is required to enable std::variant tests")
|
||||
#else
|
||||
#pragma message("C++17 is required to enable std::variant tests")
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user