8 Commits

Author SHA1 Message Date
Mindaugas Vinkelis
03f2c3c8b5 bugfix in enableBitPacking 2019-06-27 10:08:48 +03:00
Luli2020
aca3139600 Added serializer/deserializer "cereal like" interface
Added interface BasicSerializer &operator()(T &&head, TArgs &&... tail) and BasicDeserializer &operator()(T &&head, TArgs &&... tail), which are cereal like intefaces so such format of serialization functions were possible:

template<class Archive>
void serialize(Archive & ar, DataType& d){
    ar(d.data1, d.data2....);
}
2019-06-27 08:07:57 +03:00
Mindaugas Vinkelis
c1ae593fb4 travis-ci-update 2019-06-27 08:08:05 +03:00
Mindaugas Vinkelis
ddca8e4ad0 extensions for tuple, variant and chrono types 2019-03-12 14:54:04 +02:00
Mindaugas Vinkelis
1fe2b398fc Merge pull request #12 from ArekSredzki/fix-quickMeasureSize
Fix quickMeasureSize<T>() compilation.
2019-01-30 11:49:37 +02:00
Arek Sredzki
574ec69cca Fix quickMeasureSize<T>() compilation. 2019-01-30 01:44:34 -08:00
Mindaugas Vinkelis
8e94596a6f Merge pull request #11 from ArekSredzki/misc-documentation-improvements
Fix various grammatical and spelling mistakes within the docs
2019-01-18 14:37:59 +02:00
Arek Sredzki
fac2c8a7ce Fix various grammatical and spelling mistakes within the docs 2019-01-17 10:31:58 -08:00
40 changed files with 1294 additions and 81 deletions

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@
build/
cmake-build-*
CTestConfig.cmake
Testing/

View File

@@ -1,18 +1,55 @@
dist: xenial
language: cpp
compiler:
  - gcc
  # clang
# CXX_COMPILER and CC_COMPILER is defined, because travis will override CC and CXX environment variables
# We'll need to override them back "before_install"
matrix:
include:
- addons:
apt:
packages:
- g++-5
env:
- CXXSTD=11
- CXX_COMPILER=g++-5
- CC_COMPILER=gcc-5
- addons:
apt:
packages:
- clang-3.9
env:
- CXXSTD=11
- CXX_COMPILER=clang++-3.9
- CC_COMPILER=clang-3.9
- addons:
apt:
packages:
- g++-7
sources:
- ubuntu-toolchain-r-test
env:
- CXXSTD=17
- CXX_COMPILER=g++-7
- CC_COMPILER=gcc-7
- addons:
apt:
packages:
- libstdc++-7-dev
- clang-8
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-8
- sourceline: 'deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
env:
- CXXSTD=17
- CXX_COMPILER=clang++-8
- CC_COMPILER=clang-8
before_install:
# C++14
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
- sudo apt-get update -qq
- export CXX=$CXX_COMPILER
- export CC=$CC_COMPILER
install:
- sudo apt-get install -qq g++-5 lcov
- sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-5 90
- sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-5 90
- wget https://github.com/google/googletest/archive/release-1.8.0.tar.gz
- tar xf release-1.8.0.tar.gz
- cd googletest-release-1.8.0
@@ -22,9 +59,12 @@ install:
- cd ..
before_script:
  - mkdir build
  - cd build
  - cmake -DBITSERY_BUILD_TESTS=ON ..
- mkdir build
- cd build
  - cmake -DBITSERY_BUILD_TESTS=ON -DCMAKE_CXX_STANDARD=$CXXSTD ..
script: make && (cd tests && ctest)
script:
- make
- cd tests
- ctest

View File

@@ -1,3 +1,24 @@
# [4.6.1](https://github.com/fraillt/bitsery/compare/v4.6.0...v4.6.1) (2019-06-27)
### Features
* flexible syntax now also supports `cereal` like serialization interface (thanks to [Luli2020](https://github.com/Luli2020))
### Bug fixes
* when using `enableBitPacking`, internal context (i.e. context<T>()) in serializer/deserializer was not copied to/from new bitpacking enabled instance.
# [4.6.0](https://github.com/fraillt/bitsery/compare/v4.5.1...v4.6.0) (2019-03-12)
### Features
* new extensions **StdTuple** and **StdVariant** for `std::tuple` and `std::variant`. These are the first extensions that requires C++17, or higher, standard enabled.
Although `std::tuple` is C++11 type, but from usage perspective it has exactly the same requirements as `std::variant` and relies heavily on having class template argument deduction guides to make it convenient to use.
You can easily use `std::tuple` without any extension at all, so the main motivation was to create convenient interface for **StdVariant** and use the same interface for **StdTuple** as well.
* instead of providing custom lambda to overload each type in tuple or variant, there was added several helper callable objects.
**OverloadValue** wrapper around `s.value<N>(o)`, **OverloadExtValue** wrapper around `s.ext<N>(o, Ext{})` and **OverloadExtObject** wrapper around `s.ext(o, Ext{})`.
* new extensions **StdDuration** and **StdTimePoint** for `std::chrono::duration` and `std::chrono::time_point`.
### Improvements
tests now uses `gtest_discover_tests` function, to automatically discover tests, which requires CMake 3.10.
# [4.5.1](https://github.com/fraillt/bitsery/compare/v4.5.0...v4.5.1) (2019-01-16)
### Improvements

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.1)
project(bitsery
LANGUAGES CXX
VERSION 4.5.1)
VERSION 4.6.1)
#======== build options ===================================
option(BITSERY_BUILD_EXAMPLES "Build examples" OFF)

View File

@@ -23,7 +23,7 @@ All cross-platform requirements are enforced at compile time, so serialized data
* fine-grained bit-level serialization control.
* Easily extendable for any type.
* Allows flexible or/and verbose syntax for better serialization control.
* Configurable endianess support.
* Configurable endianness support.
* No macros.
## Why to use bitsery
@@ -96,6 +96,8 @@ This documentation comprises these parts:
Works with C++11 compiler, no additional dependencies, include `<bitsery/bitsery.h>` and you're done.
> some **bitsery** extensions might require higher C++ standard (e.g. `StdVariant`)
## Platforms
This library was tested on

View File

@@ -15,7 +15,9 @@ Library design:
Core Serializer/Deserializer functions (alphabetical order):
* `operator()` (4.6.1) (when flexible syntax is enabled)
* `align` (1.0.0)
* `archive` (4.0.0) (when flexible syntax is enabled)
* `boolValue` (4.0.0)
* `container` (1.0.0)
* `ext` (2.0.0)
@@ -35,12 +37,16 @@ Serializer/Deserializer extensions via `ext` method (alphabetical order):
* `PointerOwner` (4.1.0)
* `PointerObserver` (4.1.0)
* `ReferencedByPointer` (4.1.0)
* `StdDuration` (4.6.0)
* `StdMap` (3.0.0)
* `StdOptional` (2.0.0)
* `StdQueue` (4.0.0)
* `StdSet` (4.0.0)
* `StdSmartPrt` (4.3.0)
* `StdStack` (4.0.0)
* `StdTimePoint` (4.6.0)
* `StdTuple` (4.6.0) (requires c++17)
* `StdVariant` (4.6.0) (requires c++17)
* `ValueRange` (3.0.0)
* `VirtualBaseClass` (4.2.0)

View File

@@ -33,12 +33,12 @@ Now let's review features in more detail.
* **Cross-platform compatible.** if same code compiles on Android, PS3 console, and your PC either x64 or x86 architecture, you are 100% sure it works.
To achieve this, bitsery specifically defines size of underlying data, hence syntax is *value\<2\>* (alias function *value2b*) instead or *value*, or *container2b* for element type of 16bits, eg int16_t.
Bitsery also applies endianess transformation if nessesarry.
* **Flexible syntax.** if you don't like like writing code with explicitly specifying underlying type size, like *container2b* or *value8b* you can use flexible syntax.
Bitsery also applies endianness transformation if necessary.
* **Flexible syntax.** If you don't like like writing code with explicitly specifying underlying type size, like *container2b* or *value8b*, you can use flexible syntax.
Just include <bitsery/flexible.h> and can write like in [cereal](http://uscilab.github.io/cereal/).
But do it on your own risk, and static assert using *assertFundamentalTypeSizes* function if you're planing to use it accross multiple platforms.
But do it on your own risk, and static assert using *assertFundamentalTypeSizes* function if you're planing to use it across multiple platforms.
* **Optimized for speed and space.** library itself doesn't do any allocations (except if you use backward/forward compatibility) so data writing/reading is fast as memcpy to/from your buffer.
It also doesn't serialize any type information, all information needed is writen in your code!
It also doesn't serialize any type information, all information needed is written in your code!
* **No code generation required: no IDL or metadata** since it doesn't support any other formats except binary, it doesn't need any metadata.
* **Runtime error checking on deserialization** library designed to be save with untrusted network data, that's why all overloads that work on containers has *maxSize* value, unless container is static size like *std::array*, this way bitsery ensures that no malicious data crash you.
* **Supports forward/backward compatibility for your types** library has optional forward/backward compatibility for types implemented in *AdapterReader/Writer* by allowing to have inner data sessions inside buffer.
@@ -65,5 +65,5 @@ Bitsery allows to use bit-level operations and has two extensions that use them:
You want to support your custom container, its fine there is *ContainerTraits* for this, only few methods required to implement.
To use same container for buffer writing/reading add specialization to *BufferAdapterTraits*.
You want to customize serialization flow - use extensions, only two methods to define, and *ExtensionTraits* to further customize usage.
* **Configurable endianess support.** default is *Little Endian*, but if your primary target is PowerPC architecture, eg. PlayStation3, just change your configuration to be *Big Endian*.
* **Configurable endianness support.** default is *Little Endian*, but if your primary target is PowerPC architecture, eg. PlayStation3, just change your configuration to be *Big Endian*.
* **No macros.** Not so much to say, if you are like me, then it's a feature :)

View File

@@ -2,11 +2,11 @@
This is a quick guide to get **bitsery** up and running in a matter of minutes.
The only prerequisite for running bitsery is a modern C++11 compliant compiler, such as GCC 4.9.4, clang 3.4, MSVC 2015, or newer.
Older versions might work, but it is not tested.
Older versions might work, but they have not been tested.
## Get bitsery
bitsery can be directly included in your project or installed anywhere you can access header files.
**bitsery** can be directly included in your project or installed anywhere you can access header files.
Grab the latest version, and include directory `bitsery_base_dir/include/` to your project.
There's nothing to build or make - **bitsery** is header only.
@@ -27,11 +27,14 @@ using InputAdapter = InputBufferAdapter<Buffer>;
```
**bitsery** is very lightweight, so we need to explicitly include what we need.
* `<bitsery/bitsery.h>` is a core header, that includes our Serializer and Deserializer
* `<bitsery/adapter/buffer.h>` in order to write/read data we need specific adapter, depending on what underlying buffer will be. In this example we'll be using std::vector as our buffer, so we include buffer adapter.
* <bitsery/traits/...> traits tells library how efficiently serialize particular container.
create alias types for *InputAdapter* and *OutputAdapter* using our vector as buffer.
Include | Description
--|--
`<bitsery/bitsery.h>` | This is a core header, that includes our Serializer and Deserializer.
`<bitsery/adapter/buffer.h>` | In order to write/read data, we need a specific adapter, depending on what underlying buffer will be. In this example, we'll be using `std::vector` as our buffer, so we include the buffer adapter.
`<bitsery/traits/...>` | Traits tell the library how to efficiently serialize a particular container. Many common STL containers are supported out of the box.
Create alias types for *InputAdapter* and *OutputAdapter* using our vector as buffer.
## Add serialization method for your type
@@ -124,4 +127,4 @@ int main() {
}
```
**currently documentation and tutorial is progress, but for more usage examples see examples folder**
**currently documentation and tutorial is progress, but for more usage examples see examples folder**

View File

@@ -0,0 +1,115 @@
#include <bitsery/bitsery.h>
#include <bitsery/adapter/buffer.h>
#include <bitsery/traits/vector.h>
// include extensions to work with tuples and variants
// these extesions only work with C++17
#if __cplusplus > 201402L
#include <bitsery/ext/std_tuple.h>
#include <bitsery/ext/std_variant.h>
// let's include this extension to make it more interesting :)
#include <bitsery/ext/compact_value.h>
struct MyStruct {
std::vector<int32_t> v{};
float f{};
bool operator==(const MyStruct& rhs) const {
return v == rhs.v && f == rhs.f;
}
};
template<typename S>
void serialize(S& s, MyStruct& o) {
s.container4b(o.v, 1000);
s.value4b(o.f);
}
// this will be the type that we want to serialize/deserialize
using MyTuple = std::tuple<float, MyStruct>;
using MyVariant = std::variant<int64_t, MyTuple, MyStruct>;
// for convenience
using namespace bitsery;
// 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, 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, 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);}
ext::OverloadValue<float, 4>{},
// it is not required to provide MyStruct overload, because it we have defined 'serialize' function for it
});
},
// this might also be useful if you want to overload using extension
ext::OverloadExtValue<int64_t, 8, ext::CompactValue>{},
// you can even go further and instead of writing lambda for MyTuple you can as well compose the same functionality
// with OverloadExtObject, like this:
// (comment out MyTuple lambda, and uncomment this)
// ext::OverloadExtObject<MyTuple, ext::StdTuple<ext::OverloadValue<float, 4>>>{},
// we can also override default 'serialize' function by creating an overloading for that type
[](S& s, MyStruct& o) {
s.value4b(o.f);
s.container(o.v, 1000, [&s](int32_t& v) {
s.ext4b(v, ext::CompactValue{});
});
},
// NOTE.
// it is possible to provide "auto" as type parameter
// this will allow you to override all default 'serialize' functions
// but in this case it will not be called, because we have explicitly provided overloads for all variant types
// also note, that first parameter (serializer) is also "auto", this is required, so that it would be least specialized case
// otherwise it will not compile if you any ext::Overload* helper defined, because it will have ambiguous definitions
// (ext::OverLoad* defines (templated_type& s, concrete_type& o) and lambda would be (concrete_type& s, templated_type& o))
[](auto& , auto& ) {
assert(false);
}
});
}
//some helper types
using Buffer = std::vector<uint8_t>;
using OutputAdapter = OutputBufferAdapter<Buffer>;
using InputAdapter = InputBufferAdapter<Buffer>;
int main() {
//set some random data
MyVariant data{MyTuple{-7549, {{-451, 2, 968, 75, 4, 156, 49}, 874.4f}}};
// MyVariant data{MyStruct{{-451, 2, 968, 75, 4, 156, 49}, 874.4f}};
MyVariant res{};
//create buffer to store data
Buffer buffer;
//use quick serialization function,
//it will use default configuration to setup all the nesessary steps
//and serialize data to container
auto writtenSize = 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 = quickDeserialization<InputAdapter>({buffer.begin(), writtenSize}, res);
assert(state.first == ReaderError::NoError && state.second);
assert(data == res);
}
#else
#if defined(_MSC_VER)
#pragma message("example works only on c++17")
#else
#warning "example works only on c++17"
#endif
int main() {
return 0;
}
#endif

View File

@@ -19,11 +19,12 @@ struct MyStruct {
void serialize(S& s) {
//now we can use flexible syntax with
s.archive(i, e, fs);
// flexible syntax also supports `cereal` like serialization interface by calling operator()
// s(i, e, fs);
}
};
using namespace bitsery;
//some helper types

View File

@@ -124,7 +124,7 @@ namespace bitsery {
void directRead(T *v, size_t count) {
static_assert(!std::is_const<T>::value, "");
_inputAdapter.read(reinterpret_cast<TValue *>(v), sizeof(T) * count);
//swap each byte if nessesarry
//swap each byte if necessary
_swapDataBits(v, count, std::integral_constant<bool,
Config::NetworkEndianness != details::getSystemEndianness()>{});
}
@@ -258,6 +258,20 @@ namespace bitsery {
}
};
namespace details {
// used in "making friends" with non-wrapped deserializer type
template <typename TReader>
struct GetNonWrappedAdapterReader {
using Reader = TReader;
};
template <typename TWrapped>
struct GetNonWrappedAdapterReader<AdapterReaderBitPackingWrapper<TWrapped>> {
using Reader = TWrapped;
};
}
}
#endif //BITSERY_ADAPTER_READER_H

View File

@@ -330,6 +330,19 @@ namespace bitsery {
TWriter& _writer;
};
namespace details {
// used in "making friends" with non-wrapped serializer type
template <typename TWriter>
struct GetNonWrappedAdapterWriter {
using Writer = TWriter;
};
template <typename TWrapped>
struct GetNonWrappedAdapterWriter<AdapterWriterBitPackingWrapper<TWrapped>> {
using Writer = TWrapped;
};
}
}
#endif //BITSERY_ADAPTER_WRITER_H

View File

@@ -25,7 +25,7 @@
#define BITSERY_BITSERY_H
#define BITSERY_MAJOR_VERSION 4
#define BITSERY_MINOR_VERSION 5
#define BITSERY_MINOR_VERSION 6
#define BITSERY_PATCH_VERSION 1
#define BITSERY_QUOTE_MACRO(name) #name

View File

@@ -29,7 +29,7 @@
namespace bitsery {
/*
* endianess
* endianness
*/
enum class EndiannessType {
LittleEndian,

View File

@@ -102,6 +102,13 @@ namespace bitsery {
archive(std::forward<TArgs>(tail)...);
}
template <typename T, typename... TArgs>
BasicDeserializer &operator()(T &&head, TArgs &&... tail) {
details::ArchiveFunction<BasicDeserializer, T>::invoke(*this, std::forward<T>(head));
archive(std::forward<TArgs>(tail)...);
return *this;
}
/*
* value
*/
@@ -331,6 +338,8 @@ namespace bitsery {
private:
friend AdapterAccess;
// this is required when creating bitpacking serializer, to access internal context
friend class BasicDeserializer<typename details::GetNonWrappedAdapterReader<TAdapterReader>::Reader, TContext>;
TAdapterReader _reader;
TContext* _context;
@@ -406,7 +415,10 @@ namespace bitsery {
void procEnableBitPacking(const Fnc& fnc, std::false_type) {
//create serializer using bitpacking wrapper
BPEnabledType tmp(_reader, _context);
// move internal context to and from of bitpacking enabled serializer
tmp._internalContext = std::move(_internalContext);
fnc(tmp);
_internalContext = std::move(tmp._internalContext);
}
//these are dummy functions for extensions that have TValue = void

View File

@@ -35,7 +35,7 @@ namespace bitsery {
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 nessesarry to work with iterators
//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;
}

View File

@@ -242,6 +242,10 @@ namespace bitsery {
selectSerializeFnc(s, v, SelectSerializeFnc<TDecayed>{});
}
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),

View File

@@ -149,6 +149,7 @@ namespace bitsery {
}
namespace traits {
template<typename T>
struct ExtensionTraits<ext::CompactValue, T> {
using TValue = T;
@@ -168,6 +169,14 @@ namespace bitsery {
static constexpr bool SupportLambdaOverload = false;
};
template<typename T, bool Check>
struct ExtensionTraits<details::CompactValueImpl<Check>, T> {
using TValue = T;
static constexpr bool SupportValueOverload = !Check;
static constexpr bool SupportObjectOverload = Check;
static constexpr bool SupportLambdaOverload = false;
};
}
}

View File

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

View File

@@ -24,24 +24,13 @@
#ifndef BITSERY_EXT_STD_OPTIONAL_H
#define BITSERY_EXT_STD_OPTIONAL_H
//this module do not include optional, but expects it to be declared in std::optional
//if you're using experimental optional from <experimental/optional>
//add it in std namespace like this:
//namespace std {
// template <typename T>
// using optional = experimental::optional<T>;
//}
#include <type_traits>
#include "../traits/core/traits.h"
#include "../details/serialization_common.h"
#include <optional>
namespace bitsery {
namespace ext {
template<typename T>
using std_optional = ::std::optional<T>;
class StdOptional {
public:
@@ -50,37 +39,27 @@ namespace bitsery {
* @param alignBeforeData only makes sense when bit-packing enabled, by default aligns after writing/reading bool state of optional
*/
explicit StdOptional(bool alignBeforeData=true):_alignBeforeData{alignBeforeData} {}
template<typename T>
constexpr void assertType() const {
using TOpt = typename std::remove_cv<T>::type;
using TVal = typename TOpt::value_type;
static_assert(std::is_same<TOpt, std_optional<TVal>>(), "");
}
template<typename Ser, typename Writer, typename T, typename Fnc>
void serialize(Ser &ser, Writer &, const T &obj, Fnc &&fnc) const {
assertType<T>();
void serialize(Ser &ser, Writer &, const std::optional<T> &obj, Fnc &&fnc) const {
ser.boolValue(static_cast<bool>(obj));
if (_alignBeforeData)
ser.align();
if (obj)
fnc(const_cast<typename T::value_type & >(*obj));
fnc(const_cast<T&>(*obj));
}
template<typename Des, typename Reader, typename T, typename Fnc>
void deserialize(Des &des, Reader &, T &obj, Fnc &&fnc) const {
assertType<T>();
void deserialize(Des &des, Reader &, std::optional<T> &obj, Fnc &&fnc) const {
bool exists{};
des.boolValue(exists);
if (_alignBeforeData)
des.align();
if (exists) {
auto tmp{::bitsery::Access::create<typename T::value_type>()};
fnc(tmp);
obj = tmp;
obj = ::bitsery::Access::create<T>();
fnc(*obj);
} else {
//experimental optional doesnt have .reset method
obj = T{};
obj = std::nullopt;
}
}
private:
@@ -90,8 +69,8 @@ namespace bitsery {
namespace traits {
template<typename T>
struct ExtensionTraits<ext::StdOptional, T> {
using TValue = typename T::value_type;
struct ExtensionTraits<ext::StdOptional, std::optional<T>> {
using TValue = T;
static constexpr bool SupportValueOverload = true;
static constexpr bool SupportObjectOverload = true;
static constexpr bool SupportLambdaOverload = true;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -100,6 +100,13 @@ namespace bitsery {
archive(std::forward<TArgs>(tail)...);
}
template <typename T, typename... TArgs>
BasicSerializer &operator()(T &&head, TArgs &&... tail) {
details::ArchiveFunction<BasicSerializer, T>::invoke(*this, std::forward<T>(head));
archive(std::forward<TArgs>(tail)...);
return *this;
}
/*
* value overloads
*/
@@ -328,11 +335,14 @@ namespace bitsery {
private:
friend AdapterAccess;
// this is required when creating bitpacking serializer, to access internal context
friend class BasicSerializer<typename details::GetNonWrappedAdapterWriter<TAdapterWriter>::Writer, TContext>;
TAdapterWriter _writer;
TContext* _context;
typename TWriter::TConfig::InternalContext _internalContext;
//process value types
//false_type means that we must process all elements individually
template<size_t VSIZE, typename It>
@@ -397,7 +407,10 @@ namespace bitsery {
void procEnableBitPacking(const Fnc& fnc, std::false_type) {
//create serializer using bitpacking wrapper
BPEnabledType tmp(_writer, _context);
// move internal context to and from of bitpacking enabled serializer
tmp._internalContext = std::move(_internalContext);
fnc(tmp);
_internalContext = std::move(tmp._internalContext);
}
//these are dummy functions for extensions that have TValue = void
@@ -416,6 +429,7 @@ namespace bitsery {
};
//helper type
template <typename Adapter>
using Serializer = BasicSerializer<AdapterWriter<Adapter, DefaultConfig>>;
@@ -432,7 +446,7 @@ namespace bitsery {
template <typename T>
size_t quickMeasureSize(const T& value) {
BasicSerializer<MeasureSize> ser {nullptr};
BasicSerializer<MeasureSize> ser{MeasureSize{}};
ser.object(value);
auto& w = AdapterAccess::getWriter(ser);
w.flush();

View File

@@ -4,4 +4,3 @@ set(CTEST_DROP_METHOD "http")
set(CTEST_DROP_SITE "my.cdash.org")
set(CTEST_DROP_LOCATION "/submit.php?project=bitsery")
set(CTEST_DROP_SITE_CDASH TRUE)

View File

@@ -6,7 +6,6 @@ set(CTEST_BINARY_DIRECTORY "build")
set(ENV{CXXFLAGS} "--coverage")
#when using Ninja generator, ctest_coverage cannot find files...
set(CTEST_CMAKE_GENERATOR "CodeBlocks - Unix Makefiles")
#set(CTEST_USE_LAUNCHERS 1)
set(CTEST_COVERAGE_COMMAND "gcov")

View File

@@ -5,4 +5,4 @@ COV_INFO=$TESTS_BUILD_DIR/bitsery_coverage.info
lcov --directory $TESTS_BUILD_DIR --capture --output-file $COV_INFO
lcov --extract $COV_INFO '*include/bitsery*' --output-file $COV_INFO.clean
genhtml --output-directory $TESTS_BUILD_DIR/coverage_web $COV_INFO.clean
xdg-open $TESTS_BUILD_DIR/coverage_web/index.html
x-www-browser $TESTS_BUILD_DIR/coverage_web/index.html

View File

@@ -20,7 +20,7 @@
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#SOFTWARE.
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.10)
project(bitsery_tests CXX)
find_package(GTest 1.8 REQUIRED)
@@ -31,11 +31,6 @@ endif()
file(GLOB TestSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
message(WARNING "extension tests for optional is disable for VS, because VS currenty doesn't have <optional>")
list(REMOVE_ITEM TestSourceFiles ${CMAKE_CURRENT_SOURCE_DIR}/serialization_ext_std_optional.cpp)
endif()
enable_testing()
foreach (TestFile ${TestSourceFiles})
@@ -46,8 +41,9 @@ foreach (TestFile ${TestSourceFiles})
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
target_compile_options(${TestName} PRIVATE -Wextra -Wno-missing-braces -Wpedantic -Weffc++ -Wno-c++14-extensions)
endif()
gtest_discover_tests(${TestName})
add_test(NAME ${TestName} COMMAND $<TARGET_FILE:${TestName}>)
# add_test(NAME ${TestName} COMMAND $<TARGET_FILE:${TestName}>)
endforeach()
#======================= setup development environment ====================

View File

@@ -35,6 +35,17 @@
#include <bitsery/flexible/set.h>
#include <bitsery/flexible/unordered_set.h>
#include <bitsery/flexible/memory.h>
#include <bitsery/flexible/chrono.h>
#if __cplusplus > 201402L
#include <bitsery/flexible/tuple.h>
#include <bitsery/flexible/variant.h>
#else
#if defined(_MSC_VER)
#pragma message("tuple and variant only works with c++17")
#else
#warning "tuple and variant only works with c++17"
#endif
#endif
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
@@ -388,6 +399,33 @@ TEST(FlexibleSyntax, StdSmartPtr) {
EXPECT_THAT(*resUnique1, Eq(*dataUnique1));
}
TEST(FlexibleSyntax, StdDuration) {
std::chrono::duration<int64_t, std::milli> t1{54654};
EXPECT_TRUE(procArchive(t1) == t1);
}
TEST(FlexibleSyntax, StdTimePoint) {
using Duration = std::chrono::duration<double, std::milli>;
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
TP data{Duration{874656.4798}};
EXPECT_TRUE(procArchive(data) == data);
}
#if __cplusplus > 201402L
TEST(FlexibleSyntax, StdTuple) {
std::tuple<int, std::string, std::vector<char>> t1{5,"hello hello", {'A','B','C'}};
EXPECT_TRUE(procArchive(t1) == t1);
}
TEST(FlexibleSyntax, StdVariant) {
std::variant<float, std::string, std::chrono::milliseconds> t1{std::string("hello hello")};
EXPECT_TRUE(procArchive(t1) == t1);
}
#endif
TEST(FlexibleSyntax, NestedTypes) {
std::unordered_map<std::string, std::vector<std::string>> t1;
t1.emplace("my key", std::vector<std::string>{"very", "nice", "string"});

View File

@@ -139,6 +139,24 @@ TEST(DeserializeNonDefaultConstructible, ResultStdForwardListShouldShrink) {
EXPECT_THAT(res.begin(), Eq(res.end()));
}
{
// also check if correctly expands if source is bigger than destination
SerializationContext ctx{};
std::forward_list<NonDefaultConstructible> data{};
data.push_front(NonDefaultConstructible{1});
data.push_front(NonDefaultConstructible{14});
std::forward_list<NonDefaultConstructible> res{};
ctx.createSerializer().container(data, 10);
ctx.createDeserializer().container(res, 10);
auto resIt = res.begin();
for (auto it = data.begin(); it != data.end(); ++it, ++resIt) {
EXPECT_THAT(*resIt, Eq(*it));
}
EXPECT_THAT(resIt, Eq(res.end()));
}
}
TEST(DeserializeNonDefaultConstructible, StdSet) {

View File

@@ -130,4 +130,32 @@ TEST(SerializationContext, ContextIfExistsReturnsNullWhenTypeDoesntExists) {
DeserializerConfigWithContext<double, int, char> des{InputAdapter{buf.begin(), 1}, &extCtx2};
EXPECT_THAT(des.contextOrNull<double>(), ::testing::NotNull());
EXPECT_THAT(des.contextOrNull<float>(), ::testing::IsNull());
}
}
TEST(SerializationContext, WhenBitPackingIsEnabledThenInternalContextIsMovedToNewInstanceAndMovedBackAfterwards) {
Buffer buf{};
using Ser = SerializerConfigWithContext<void, int>;
using BPSer = typename Ser::BPEnabledType;
using Des = DeserializerConfigWithContext<void, int>;
using BPDes = typename Des::BPEnabledType;
Ser ser{buf, nullptr};
*ser.context<int>() = 1;
EXPECT_THAT(*ser.context<int>(), Eq(1));
ser.enableBitPacking([](BPSer& s) {
EXPECT_THAT(*s.context<int>(), Eq(1));
*s.context<int>() = 2;
});
EXPECT_THAT(*ser.context<int>(), Eq(2));
Des des{InputAdapter{buf.begin(), 1}, nullptr};
*des.context<int>() = 3;
EXPECT_THAT(*des.context<int>(), Eq(3));
des.enableBitPacking([](BPDes& d) {
EXPECT_THAT(*d.context<int>(), Eq(3));
*d.context<int>() = 4;
});
EXPECT_THAT(*des.context<int>(), Eq(4));
}

View File

@@ -26,7 +26,6 @@
#include "serialization_test_utils.h"
#include <bitsery/traits/array.h>
#include <iostream>
#include <bitset>
#include <chrono>

View File

@@ -0,0 +1,81 @@
//MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
#include <bitsery/ext/std_chrono.h>
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
using StdDuration = bitsery::ext::StdDuration;
using StdTimePoint = bitsery::ext::StdTimePoint;
using testing::Eq;
TEST(SerializeExtensionStdChrono, IntegralDuration) {
SerializationContext ctx1;
using Hours = std::chrono::duration<int32_t, std::ratio<60>>;
Hours data{43};
Hours res{};
ctx1.createSerializer().ext4b(data, StdDuration{});
ctx1.createDeserializer().ext4b(res, StdDuration{});
EXPECT_THAT(res, Eq(data));
}
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>;
TP data{Duration{243}};
TP res{};
ctx1.createSerializer().ext8b(data, StdTimePoint{});
ctx1.createDeserializer().ext8b(res, StdTimePoint{});
EXPECT_THAT(res, Eq(data));
}
TEST(SerializeExtensionStdChrono, FloatDuration) {
SerializationContext ctx1;
using Hours = std::chrono::duration<float, std::ratio<60>>;
Hours data{43.5f};
Hours res{};
ctx1.createSerializer().ext4b(data, StdDuration{});
ctx1.createDeserializer().ext4b(res, StdDuration{});
EXPECT_THAT(res, Eq(data));
}
TEST(SerializeExtensionStdChrono, FloatTimePoint) {
SerializationContext ctx1;
using Duration = std::chrono::duration<double, std::milli>;
using TP = std::chrono::time_point<std::chrono::system_clock, Duration>;
TP data{Duration{243457.4}};
TP res{};
ctx1.createSerializer().ext8b(data, StdTimePoint{});
ctx1.createDeserializer().ext8b(res, StdTimePoint{});
EXPECT_THAT(res, Eq(data));
}

View File

@@ -26,11 +26,9 @@
#if __cplusplus > 201402L
#include <optional>
#include <bitsery/ext/std_optional.h>
#include <bitsery/ext/value_range.h>
using StdOptional = bitsery::ext::StdOptional;
using BPSer = SerializationContext::TSerializer::BPEnabledType;
@@ -122,6 +120,10 @@ TEST(SerializeExtensionStdOptional, NoAlignAfterStateWriteRead) {
EXPECT_THAT(t1.value(), Eq(r1.value()));
}
#else
#if defined(_MSC_VER)
#pragma message("Tests for StdOptional requires C++17")
#else
#warning "Tests for StdOptional requires C++17"
#endif
#endif

View File

@@ -0,0 +1,129 @@
//MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
using testing::Eq;
#if __cplusplus > 201402L
#include <bitsery/ext/std_tuple.h>
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{}}};
std::tuple<MyStruct1, MyStruct2> r1{};
SerializationContext ctx;
ctx.createSerializer().ext(t1, bitsery::ext::StdTuple{});
ctx.createDeserializer().ext(r1, bitsery::ext::StdTuple{});
EXPECT_THAT(t1, Eq(r1));
}
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) {
using S = decltype(s);
s.ext(o, bitsery::ext::StdTuple{
[](auto& s1, float& o1) {
s1.value4b(o1);
},
OverloadValue<int32_t, 4>{}
});
};
exec(ctx.createSerializer(), t1);
exec(ctx.createDeserializer(), r1);
EXPECT_THAT(t1, Eq(r1));
}
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) {
using S = decltype(s);
s.ext(o, bitsery::ext::StdTuple{
[](auto& s1, MyStruct1& o1) {
s1.value4b(o1.i1);
//do not serialize other element, it should be 0 (default)
},
});
};
exec(ctx.createSerializer(), t1);
exec(ctx.createDeserializer(), r1);
EXPECT_THAT(std::get<1>(t1), Eq(std::get<1>(r1)));
EXPECT_THAT(std::get<0>(t1).i1, Eq(std::get<0>(r1).i1));
EXPECT_THAT(std::get<0>(t1).i2, ::testing::Ne(std::get<0>(r1).i2));
}
TEST(SerializeExtensionStdTuple, EmptyTuple) {
std::tuple<> t1{};
std::tuple<> r1{};
SerializationContext ctx;
ctx.createSerializer().ext(t1, bitsery::ext::StdTuple{});
ctx.createDeserializer().ext(r1, bitsery::ext::StdTuple{});
EXPECT_THAT(t1, Eq(r1));
}
struct NonDefaultConstructable {
explicit NonDefaultConstructable(float x) : _x{x} {}
float _x;
bool operator==(const NonDefaultConstructable& rhs) const {
return _x == rhs._x;
}
private:
friend class bitsery::Access;
NonDefaultConstructable() : _x{0.0f} {};
};
TEST(SerializeExtensionStdTuple, NonDefaultConstructable) {
std::tuple<NonDefaultConstructable> t1{34};
std::tuple<NonDefaultConstructable> r1{8};
SerializationContext ctx;
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);
},
});
EXPECT_THAT(t1, Eq(r1));
}
#else
#if defined(_MSC_VER)
#pragma message("Tests for StdTuple requires C++17")
#else
#warning "Tests for StdTuple requires C++17"
#endif
#endif

View File

@@ -0,0 +1,178 @@
//MIT License
//
//Copyright (c) 2019 Mindaugas Vinkelis
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.
#include <gmock/gmock.h>
#include "serialization_test_utils.h"
#if __cplusplus > 201402L
using testing::Eq;
#include <bitsery/ext/std_variant.h>
template<typename T, size_t N>
using OverloadValue = bitsery::ext::OverloadValue<T, N>;
TEST(SerializeExtensionStdVariant, UseSerializeFunction) {
std::variant<MyStruct1, MyStruct2> t1{MyStruct1{978, 15}};
std::variant<MyStruct1, MyStruct2> r1{MyStruct2{}};
SerializationContext ctx;
ctx.createSerializer().ext(t1, bitsery::ext::StdVariant{});
ctx.createDeserializer().ext(r1, bitsery::ext::StdVariant{});
EXPECT_THAT(t1, Eq(r1));
}
TEST(SerializeExtensionStdVariant, WhenTwoIndicesWithSameTypeThenDeserializeCorrectIndex) {
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{});
ctx.createDeserializer().ext(r1, bitsery::ext::StdVariant{});
EXPECT_THAT(t1, Eq(r1));
}
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);
};
ctx.createSerializer().ext(t1, bitsery::ext::StdVariant{fncFloat, fncChar});
ctx.createDeserializer().ext(r1, bitsery::ext::StdVariant{fncFloat, fncChar});
EXPECT_THAT(t1, Eq(r1));
}
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& ser = ctx.createSerializer();
ser.ext(t1, bitsery::ext::StdVariant{fncFloat, OverloadValue<char, 1>{}});
auto& des = ctx.createDeserializer();
des.ext(r1, bitsery::ext::StdVariant{fncFloat, OverloadValue<char, 1>{}});
EXPECT_THAT(t1, Eq(r1));
}
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.value4b(v.i1);
//do not serialize other element, it should be 0 (default)
},
OverloadValue<int32_t, 4>{}
});
};
exec(ctx.createSerializer(), t1);
exec(ctx.createDeserializer(), r1);
EXPECT_THAT(std::get<1>(r1).i2, Eq(0));
}
struct NonDefaultConstructable {
explicit NonDefaultConstructable(float x) : _x{x} {}
float _x;
bool operator==(const NonDefaultConstructable& rhs) const {
return _x == rhs._x;
}
private:
friend class bitsery::Access;
NonDefaultConstructable() : _x{0.0f} {};
};
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) {
using S = decltype(s);
s.ext(o, bitsery::ext::StdVariant{
[](S& s, NonDefaultConstructable& v) {
s.value4b(v._x);
},
OverloadValue<int32_t, 4>{}
});
};
exec(ctx.createSerializer(), t1);
exec(ctx.createDeserializer(), r1);
EXPECT_THAT(t1, Eq(r1));
}
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);
},
});
};
exec(ctx.createSerializer(), t1);
exec(ctx.createDeserializer(), r1);
EXPECT_THAT(t1, Eq(r1));
std::variant<std::monostate> t2{};
std::variant<std::monostate> r2{};
SerializationContext ctx1;
ctx1.createSerializer().ext(t2, bitsery::ext::StdVariant{});
ctx1.createDeserializer().ext(r2, bitsery::ext::StdVariant{});
EXPECT_THAT(t2, Eq(r2));
}
#else
#if defined(_MSC_VER)
#pragma message("Tests for StdVariant requires C++17")
#else
#warning "Tests for StdVariant requires C++17"
#endif
#endif

View File

@@ -134,7 +134,7 @@ public:
}
//since all containers .size() method returns size_t, it cannot be directly serialized, because size_t is platform dependant
//this function returns number of bytes writen to buffer, when reading/writing size of container
//this function returns number of bytes written to buffer, when reading/writing size of container
static size_t containerSizeSerializedBytesCount(size_t elemsCount) {
if (elemsCount < 0x80u)
return 1;