ext function redesign and documentation

This commit is contained in:
fraillt
2017-08-11 16:11:55 +03:00
parent 4ad65f8384
commit 1986491173
20 changed files with 570 additions and 249 deletions

View File

@@ -1,3 +1,14 @@
<a name="2.1.0"></a>
# [2.1.0](https://github.com/fraillt/bitsery/compare/v2.0.0...v2.1.0) (2017-08-07)
### Features
* added **SERIALIZE_FRIEND** macro to be able to serialize private struct fields
* static_assert when trying to serialize object, that doesn't have **serialize** function defined.
* added **custom** function to override default behaviour for **object** serialization
* renamed function **ext** to **extension** and changed its interface, to make it more easy to extend
<a name="2.0.0"></a>
# [2.0.0](https://github.com/fraillt/bitsery/compare/v1.1.1...v2.0.0) (2017-07-25)
@@ -30,10 +41,10 @@
### Features
Serialization functions:
* **value** - primitive types (ints, enums, floats)
* **value** - [fundamental types](doc/design/fundamental_types.md)
* **container** - dynamic size containers
* **array** - fixed size containers
* **text** - for c-array and std::string
* **range** - compresion for primitive types (e.g. int between [255..512] will take up 8bits
* **range** - compresion for fundamental types (e.g. int between [255..512] will take up 8bits
* **substitution** - default value from list (e.g. 4d vector, that is most of the time equals to [0,0,0,1] can store only 1bit)
* **boolBit**/**boolByte** - serialize bool, as 1bit or 1byte.
* **boolBit**/**boolByte** - serialize bool, as 1bit or 1byte.

View File

@@ -2,16 +2,22 @@
Header only C++ binary serialization library.
It is designed around the networking requirements for multiplayer real-time fast paced games as first person shooters.
All cross-platform requirements are enforced at compile time, so serialized data do not store any run-time type information and is as small as possible.
Furthermore knowing your specific requirements
> **bitsery** is looking for your feedback.
## Features
**bitsery** is looking for your feedback.
* Has configurable endianess support.
* Can serialize all common types: arithmetic types, enums, containers and text.
* Has advanced features like value ranges and default values.
* Is extensible, for types that requires different serialization and deserialization logic (e.g. pointers)
* Has error checking on deserialization, and asserts on serialization runtime errors.
* Cross-platform compatible
* 2-in-1 declarative control flow, same code for serialization and deserialization.
* Configurable endianess support.
* Advanced serialization features like value ranges and entrophy encoding.
* Easy to extend for types that requires different serialization and deserialization logic (e.g. pointers, or geometry compression).
* Error checking at runtime on deserialization, and asserts on serialization errors.
## Example
```cpp

38
doc/README.md Normal file
View File

@@ -0,0 +1,38 @@
To get the most out of **Bitsery**, start with the [tutorial](tutorial/README.md).
Once you're familiar with the library consider the following reference material.
Library design:
* [fundamental types](design/fundamental_types.md)
* [serializer/deserializer functions overloads](design/function_overload.md)
* [extending library functionality](design/extensions.md)
Serializer/Deserializer functions (alphabetical order):
* [align](fnc_array.md)
* [array](fnc_array.md)
* [boolBit/Byte](fnc_bool.md)
* [container](fnc_container.md)
* [custom](fnc_custom.md)
* [extension](fnc_extension.md)
* [isValid](fnc_isValid.md)
* [object](fnc_object.md)
* [range](fnc_range.md)
* [substitution](fnc_substitution.md)
* [text](fnc_text.md)
* [value](fnc_value.md)
BasicBufferWriter/Reader functions:
* [writeBits](bb_write_bits.md)
Tips and tricks:
Advanced topics:
FAQ:
* [Known limitations](limitations.md)
Other:
* [Why Bitsery?](why-bitsery.md)
* [Contributing](../CONTRIBUTING.md)
* [Change log](../CHANGELOG.md)

0
doc/design/extensions.md Normal file
View File

View File

View File

@@ -0,0 +1 @@
int char (except bool)

9
doc/tutorial/README.md Normal file
View File

@@ -0,0 +1,9 @@
The grand plan for this tutorial is to learn how to serialize/deserialize any object efficiently in time and space, so you could focus on other, more interesting things.
This tutorial will cover these main topics:
* [Hello World](hello_world.md) how to set up and to serialize a [fundamental value](../design/fundamental.md).
* [2 in 1](two_in_one.md) how to write one control flow for both, serialization and deserialization.
* [Squeeze Me!](compression.md) how to compress your data if you know what it stores.
* [Anything is Possible](extensions.md) how to extend library for your custom container, compress geometry and more.
* [Little or Big](endianness.md) how to change Endianness if you want best performance on PowerPC

View File

View File

View File

@@ -27,11 +27,15 @@ struct MyStruct {
uint32_t i;
MyEnum e;
std::vector<float> fs;
char16_t x;
bool y;
};
//define how object should be serialized/deserialized
SERIALIZE(MyStruct) {
return s.
value1(o.y).
value2(o.x).
value4(o.i).
value2(o.e).
container4(o.fs, 10);

View File

@@ -25,7 +25,7 @@
#define BITSERY_BITSERY_H
#define BITSERY_MAJOR_VERSION 2
#define BITSERY_MINOR_VERSION 0
#define BITSERY_MINOR_VERSION 1
#define BITSERY_PATCH_VERSION 0
#define BITSERY_QUOTE_MACRO(name) #name

View File

@@ -32,31 +32,34 @@
namespace bitsery {
template <typename Config>
template<typename Config>
struct BasicBufferReader {
using ValueType = typename Config::BufferValueType;
using ScratchType = typename Config::BufferScrathType;
BasicBufferReader(const ValueType* data, size_t size) : _pos{data}, _end{data + size}
{
BasicBufferReader(const ValueType *data, size_t size) : _pos{data}, _end{data + size} {
static_assert(std::is_unsigned<ValueType>(), "Config::BufferValueType must be unsigned");
static_assert(std::is_unsigned<ScratchType>(), "Config::BufferScrathType must be unsigned");
static_assert(sizeof(ValueType)*2 == sizeof(ScratchType), "ScratchType must be 2x bigger than value type");
static_assert(sizeof(ValueType) * 2 == sizeof(ScratchType),
"ScratchType must be 2x bigger than value type");
static_assert(sizeof(ValueType) == 1, "currently only supported BufferValueType is 1 byte");
}
explicit BasicBufferReader(const std::vector<ValueType> &buf) : BasicBufferReader(buf.data(), buf.size()) {
}
template <size_t N>
explicit BasicBufferReader(const ValueType (&data)[N]): BasicBufferReader(data, N)
{
template<size_t N>
explicit BasicBufferReader(const ValueType (&data)[N]): BasicBufferReader(data, N) {
}
BasicBufferReader(const BasicBufferReader&) = delete;
BasicBufferReader& operator=(const BasicBufferReader& ) = delete;
BasicBufferReader(BasicBufferReader&&) noexcept = default;
BasicBufferReader& operator=(BasicBufferReader&&) noexcept = default;
BasicBufferReader(const BasicBufferReader &) = delete;
BasicBufferReader &operator=(const BasicBufferReader &) = delete;
BasicBufferReader(BasicBufferReader &&) noexcept = default;
BasicBufferReader &operator=(BasicBufferReader &&) noexcept = default;
~BasicBufferReader() noexcept = default;
@@ -116,8 +119,8 @@ namespace bitsery {
}
private:
const ValueType* _pos;
const ValueType* _end;
const ValueType *_pos;
const ValueType *_end;
template<typename T>
bool directRead(T *v, size_t count) {
@@ -136,7 +139,7 @@ namespace bitsery {
template<typename T>
void _swapDataBits(T *v, size_t count, std::true_type) {
std::for_each(v, std::next(v, count), [this](T& v) { v = details::swap(v); });
std::for_each(v, std::next(v, count), [this](T &v) { v = details::swap(v); });
}
template<typename T>

View File

@@ -57,6 +57,14 @@ namespace bitsery {
_bitsCount += details::BITS_SIZE<T> * count;
}
void align() {
_bitsCount += 8 - (_bitsCount % 8);
}
void flush() {
}
//get size in bytes
size_t getSize() const {
return _bitsCount / 8;
@@ -67,7 +75,7 @@ namespace bitsery {
};
template <typename Config>
template<typename Config>
struct BasicBufferWriter {
using ValueType = typename Config::BufferValueType;
using ScratchType = typename Config::BufferScrathType;
@@ -75,14 +83,19 @@ namespace bitsery {
explicit BasicBufferWriter(std::vector<ValueType> &buffer) : _outIt{std::back_inserter(buffer)} {
static_assert(std::is_unsigned<ValueType>(), "Config::BufferValueType must be unsigned");
static_assert(std::is_unsigned<ScratchType>(), "Config::BufferScrathType must be unsigned");
static_assert(sizeof(ValueType)*2 == sizeof(ScratchType), "ScratchType must be 2x bigger than value type");
static_assert(sizeof(ValueType) * 2 == sizeof(ScratchType),
"ScratchType must be 2x bigger than value type");
static_assert(sizeof(ValueType) == 1, "currently only supported BufferValueType is 1 byte");
}
BasicBufferWriter(const BasicBufferWriter&) = delete;
BasicBufferWriter& operator=(const BasicBufferWriter& ) = delete;
BasicBufferWriter(BasicBufferWriter&&) noexcept = default;
BasicBufferWriter& operator=(BasicBufferWriter&&) noexcept = default;
BasicBufferWriter(const BasicBufferWriter &) = delete;
BasicBufferWriter &operator=(const BasicBufferWriter &) = delete;
BasicBufferWriter(BasicBufferWriter &&) noexcept = default;
BasicBufferWriter &operator=(BasicBufferWriter &&) noexcept = default;
~BasicBufferWriter() noexcept = default;
template<size_t SIZE, typename T>
@@ -139,22 +152,22 @@ namespace bitsery {
private:
template<typename T>
void directWrite(T&& v, size_t count) {
void directWrite(T &&v, size_t count) {
_directWriteSwapTag(std::forward<T>(v), count, std::integral_constant<bool,
Config::NetworkEndianness != details::getSystemEndianness()>{});
}
template<typename T>
void _directWriteSwapTag(const T *v, size_t count, std::true_type) {
std::for_each(v, std::next(v, count), [this](const T& v) {
std::for_each(v, std::next(v, count), [this](const T &v) {
const auto res = details::swap(v);
std::copy_n(reinterpret_cast<const ValueType*>(&res), sizeof(T), _outIt);
std::copy_n(reinterpret_cast<const ValueType *>(&res), sizeof(T), _outIt);
});
}
template<typename T>
void _directWriteSwapTag(const T *v, size_t count, std::false_type) {
std::copy_n(reinterpret_cast<const ValueType*>(v), count * sizeof(T), _outIt);
std::copy_n(reinterpret_cast<const ValueType *>(v), count * sizeof(T), _outIt);
}
template<typename T>

View File

@@ -38,10 +38,15 @@ namespace bitsery {
* serializer macro, serialize function specialization that accepts T& and const T&
*/
#define SERIALIZE(ObjectType) \
template <typename S, typename T, typename std::enable_if<std::is_same<T, ObjectType>::value || std::is_same<T, const ObjectType>::value>::type* = nullptr> \
S& serialize(S& s, T& o)
#define SERIALIZE_FRIEND(ObjectType) \
template <typename S, typename T, typename std::enable_if<std::is_same<T, ObjectType>::value || std::is_same<T, const ObjectType>::value>::type* = nullptr> \
friend S& serialize(S& s, T& o)
}
#endif //BITSERY_COMMON_H

View File

@@ -35,57 +35,84 @@ namespace bitsery {
template<typename Reader>
class Deserializer {
public:
Deserializer(Reader& r):_reader{r}, _isValid{true} {};
Deserializer(Reader &r) : _reader{r}, _isValid{true} {};
template <typename T>
Deserializer& object(T&& obj) {
return serialize(*this, std::forward<T>(obj));
/*
* object function
*/
template<typename T>
Deserializer &object(T &&obj) {
return details::SerializeFunction<Deserializer, T>::invoke(*this, std::forward<T>(obj));
}
//in c++17 change "class" to typename
template <template <typename> class Extension, typename TValue, typename Fnc>
Deserializer& ext(TValue& v, Fnc&& fnc) {
static_assert(!std::is_const<TValue>(), "");
Extension<TValue> ext{v};
ext.deserialize(*this, std::forward<Fnc>(fnc));
return *this;
};
/*
* value overloads
*/
template<size_t VSIZE, typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
Deserializer& value(T& v) {
template<size_t VSIZE, typename T, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
Deserializer &value(T &v) {
static_assert(std::numeric_limits<T>::is_iec559, "");
if (_isValid) {
_isValid = _reader.template readBytes<VSIZE>(reinterpret_cast<details::SAME_SIZE_UNSIGNED<T>&>(v));
_isValid = _reader.template readBytes<VSIZE>(reinterpret_cast<details::SAME_SIZE_UNSIGNED<T> &>(v));
}
return *this;
}
template<size_t VSIZE, typename T, typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
Deserializer& value(T& v) {
template<size_t VSIZE, typename T, typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
Deserializer &value(T &v) {
using UT = std::underlying_type_t<T>;
if (_isValid) {
_isValid = _reader.template readBytes<VSIZE>(reinterpret_cast<UT&>(v));
_isValid = _reader.template readBytes<VSIZE>(reinterpret_cast<UT &>(v));
}
return *this;
}
template<size_t VSIZE, typename T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
Deserializer& value(T& v) {
template<size_t VSIZE, typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
Deserializer &value(T &v) {
if (_isValid) {
_isValid = _reader.template readBytes<VSIZE>(v);
}
return *this;
}
/*
* custom function
*/
template<typename T, typename Fnc>
Deserializer &custom(T &&obj, Fnc &&fnc) {
fnc(*this, std::forward<T>(obj));
return *this;
};
/*
* extension functions
*/
template<typename T, typename Ext, typename Fnc>
Deserializer &extension(T &obj, Ext &&ext, Fnc &&fnc) {
ext.deserialize(obj, *this, std::forward<Fnc>(fnc));
return *this;
};
template<size_t VSIZE, typename T, typename Ext>
Deserializer &extension(T &obj, Ext &&ext) {
ext.deserialize(obj, *this, [](auto &s, auto &v) { s.template value<VSIZE>(v); });
return *this;
};
template<typename T, typename Ext>
Deserializer &extension(T &obj, Ext &&ext) {
ext.deserialize(obj, *this, [](auto &s, auto &v) { s.object(v); });
return *this;
};
/*
* bool
*/
Deserializer& boolBit(bool& v) {
Deserializer &boolBit(bool &v) {
if (_isValid) {
unsigned char tmp;
_isValid = _reader.readBits(tmp, 1);
@@ -94,7 +121,7 @@ namespace bitsery {
return *this;
}
Deserializer& boolByte(bool& v) {
Deserializer &boolByte(bool &v) {
if (_isValid) {
unsigned char tmp;
_isValid = _reader.template readBytes<1>(tmp);
@@ -109,10 +136,10 @@ namespace bitsery {
* range
*/
template <typename T>
Deserializer& range(T& v, const RangeSpec<T>& range) {
template<typename T>
Deserializer &range(T &v, const RangeSpec <T> &range) {
if (_isValid) {
_isValid = _reader.readBits(reinterpret_cast<details::SAME_SIZE_UNSIGNED<T>&>(v), range.bitsRequired);
_isValid = _reader.readBits(reinterpret_cast<details::SAME_SIZE_UNSIGNED<T> &>(v), range.bitsRequired);
details::setRangeValue(v, range);
if (_isValid)
_isValid = details::isRangeValid(v, range);
@@ -124,12 +151,12 @@ namespace bitsery {
* substitution overloads
*/
template<typename T, size_t N, typename Fnc>
Deserializer& substitution(T& v, const std::array<T,N>& expectedValues, Fnc&& fnc) {
Deserializer &substitution(T &v, const std::array<T, N> &expectedValues, Fnc &&fnc) {
size_t index;
range(index, {{}, N + 1});
if (_isValid) {
if (index)
v = expectedValues[index-1];
v = expectedValues[index - 1];
else
fnc(*this, v);
}
@@ -137,12 +164,12 @@ namespace bitsery {
};
template<size_t VSIZE, typename T, size_t N>
Deserializer& substitution(T& v, const std::array<T,N>& expectedValues) {
Deserializer &substitution(T &v, const std::array<T, N> &expectedValues) {
size_t index;
range(index, {{}, N + 1});
if (_isValid) {
if (index)
v = expectedValues[index-1];
v = expectedValues[index - 1];
else
value<VSIZE>(v);
}
@@ -150,12 +177,12 @@ namespace bitsery {
};
template<typename T, size_t N>
Deserializer& substitution(T& v, const std::array<T,N>& expectedValues) {
Deserializer &substitution(T &v, const std::array<T, N> &expectedValues) {
size_t index;
range(index, {{}, N + 1});
if (_isValid) {
if (index)
v = expectedValues[index-1];
v = expectedValues[index - 1];
else
object(v);
}
@@ -166,8 +193,8 @@ namespace bitsery {
* text overloads
*/
template <size_t VSIZE, typename T>
Deserializer& text(std::basic_string<T>& str, size_t maxSize) {
template<size_t VSIZE, typename T>
Deserializer &text(std::basic_string<T> &str, size_t maxSize) {
size_t size;
readSize(size, maxSize);
if (_isValid) {
@@ -178,9 +205,9 @@ namespace bitsery {
}
template<size_t VSIZE, typename T, size_t N>
Deserializer& text(T (&str)[N]) {
Deserializer &text(T (&str)[N]) {
size_t size;
readSize(size, N-1);
readSize(size, N - 1);
if (_isValid) {
auto first = std::begin(str);
procContainer<VSIZE>(first, std::next(first, size), std::true_type{});
@@ -194,8 +221,8 @@ namespace bitsery {
* container overloads
*/
template <typename T, typename Fnc>
Deserializer& container(T&& obj, size_t maxSize, Fnc&& fnc) {
template<typename T, typename Fnc>
Deserializer &container(T &&obj, size_t maxSize, Fnc &&fnc) {
decltype(obj.size()) size{};
readSize(size, maxSize);
if (_isValid) {
@@ -205,8 +232,8 @@ namespace bitsery {
return *this;
}
template <size_t VSIZE, typename T>
Deserializer& container(T& obj, size_t maxSize) {
template<size_t VSIZE, typename T>
Deserializer &container(T &obj, size_t maxSize) {
decltype(obj.size()) size{};
readSize(size, maxSize);
if (_isValid) {
@@ -216,8 +243,8 @@ namespace bitsery {
return *this;
}
template <typename T>
Deserializer& container(T& obj, size_t maxSize) {
template<typename T>
Deserializer &container(T &obj, size_t maxSize) {
decltype(obj.size()) size{};
readSize(size, maxSize);
if (_isValid) {
@@ -234,19 +261,19 @@ namespace bitsery {
//std::array overloads
template<typename T, size_t N, typename Fnc>
Deserializer& array(std::array<T,N> &arr, Fnc && fnc) {
Deserializer &array(std::array<T, N> &arr, Fnc &&fnc) {
procContainer(std::begin(arr), std::end(arr), std::forward<Fnc>(fnc));
return *this;
}
template<size_t VSIZE, typename T, size_t N>
Deserializer& array(std::array<T,N> &arr) {
Deserializer &array(std::array<T, N> &arr) {
procContainer<VSIZE>(std::begin(arr), std::end(arr), std::true_type{});
return *this;
}
template<typename T, size_t N>
Deserializer& array(std::array<T,N> &arr) {
Deserializer &array(std::array<T, N> &arr) {
procContainer(std::begin(arr), std::end(arr));
return *this;
}
@@ -254,69 +281,134 @@ namespace bitsery {
//c-style array overloads
template<typename T, size_t N, typename Fnc>
Deserializer& array(T (&arr)[N], Fnc&& fnc) {
Deserializer &array(T (&arr)[N], Fnc &&fnc) {
procContainer(std::begin(arr), std::end(arr), std::forward<Fnc>(fnc));
return *this;
}
template<size_t VSIZE, typename T, size_t N>
Deserializer& array(T (&arr)[N]) {
Deserializer &array(T (&arr)[N]) {
procContainer<VSIZE>(std::begin(arr), std::end(arr), std::true_type{});
return *this;
}
template<typename T, size_t N>
Deserializer& array(T (&arr)[N]) {
Deserializer &array(T (&arr)[N]) {
procContainer(std::begin(arr), std::end(arr));
return *this;
}
bool isValid() const {
return _isValid;
}
Deserializer& align() {
Deserializer &align() {
_reader.align();
return *this;
}
bool isValid() const {
return _isValid;
}
//overloads for functions with explicit type size
template<typename T> Deserializer& value1(T &&v) { return value<1>(std::forward<T>(v)); }
template<typename T> Deserializer& value2(T &&v) { return value<2>(std::forward<T>(v)); }
template<typename T> Deserializer& value4(T &&v) { return value<4>(std::forward<T>(v)); }
template<typename T> Deserializer& value8(T &&v) { return value<8>(std::forward<T>(v)); }
template<typename T, size_t N> Deserializer& substitution1
(T &v, const std::array<T, N> &expectedValues) { return substitution<1>(v, expectedValues); };
template<typename T, size_t N> Deserializer& substitution2
(T &v, const std::array<T, N> &expectedValues) { return substitution<2>(v, expectedValues); };
template<typename T, size_t N> Deserializer& substitution4
(T &v, const std::array<T, N> &expectedValues) { return substitution<4>(v, expectedValues); };
template<typename T, size_t N> Deserializer& substitution8
(T &v, const std::array<T, N> &expectedValues) { return substitution<8>(v, expectedValues); };
template<typename T>
Deserializer &value1(T &&v) { return value<1>(std::forward<T>(v)); }
template<typename T> Deserializer& text1(std::basic_string<T> &str, size_t maxSize) {
return text<1>(str, maxSize); }
template<typename T> Deserializer& text2(std::basic_string<T> &str, size_t maxSize) {
return text<2>(str, maxSize); }
template<typename T> Deserializer& text4(std::basic_string<T> &str, size_t maxSize) {
return text<4>(str, maxSize); }
template<typename T>
Deserializer &value2(T &&v) { return value<2>(std::forward<T>(v)); }
template<typename T, size_t N> Deserializer& text1(T (&str)[N]) { return text<1>(str); }
template<typename T, size_t N> Deserializer& text2(T (&str)[N]) { return text<2>(str); }
template<typename T, size_t N> Deserializer& text4(T (&str)[N]) { return text<4>(str); }
template<typename T>
Deserializer &value4(T &&v) { return value<4>(std::forward<T>(v)); }
template<typename T> Deserializer& container1(T &&obj, size_t maxSize) {
return container<1>(std::forward<T>(obj), maxSize); }
template<typename T> Deserializer& container2(T &&obj, size_t maxSize) {
return container<2>(std::forward<T>(obj), maxSize); }
template<typename T> Deserializer& container4(T &&obj, size_t maxSize) {
return container<4>(std::forward<T>(obj), maxSize); }
template<typename T> Deserializer& container8(T &&obj, size_t maxSize) {
return container<8>(std::forward<T>(obj), maxSize); }
template<typename T>
Deserializer &value8(T &&v) { return value<8>(std::forward<T>(v)); }
template<typename T, typename Ext>
Deserializer &extension1(T &v, Ext &&ext) {
return extension<1>(v, std::forward<Ext>(ext));
};
template<typename T, typename Ext>
Deserializer &extension2(T &v, Ext &&ext) {
return extension<2>(v, std::forward<Ext>(ext));
};
template<typename T, typename Ext>
Deserializer &extension4(T &v, Ext &&ext) {
return extension<4>(v, std::forward<Ext>(ext));
};
template<typename T, typename Ext>
Deserializer &extension8(T &v, Ext &&ext) {
return extension<8>(v, std::forward<Ext>(ext));
};
template<typename T, size_t N>
Deserializer &substitution1(T &v, const std::array<T, N> &expectedValues) {
return substitution<1>(v, expectedValues);
};
template<typename T, size_t N>
Deserializer &substitution2(T &v, const std::array<T, N> &expectedValues) {
return substitution<2>(v, expectedValues);
};
template<typename T, size_t N>
Deserializer &substitution4(T &v, const std::array<T, N> &expectedValues) {
return substitution<4>(v, expectedValues);
};
template<typename T, size_t N>
Deserializer &substitution8(T &v, const std::array<T, N> &expectedValues) {
return substitution<8>(v, expectedValues);
};
template<typename T>
Deserializer &text1(std::basic_string<T> &str, size_t maxSize) {
return text<1>(str, maxSize);
}
template<typename T>
Deserializer &text2(std::basic_string<T> &str, size_t maxSize) {
return text<2>(str, maxSize);
}
template<typename T>
Deserializer &text4(std::basic_string<T> &str, size_t maxSize) {
return text<4>(str, maxSize);
}
template<typename T, size_t N>
Deserializer &text1(T (&str)[N]) { return text<1>(str); }
template<typename T, size_t N>
Deserializer &text2(T (&str)[N]) { return text<2>(str); }
template<typename T, size_t N>
Deserializer &text4(T (&str)[N]) { return text<4>(str); }
template<typename T>
Deserializer &container1(T &&obj, size_t maxSize) {
return container<1>(std::forward<T>(obj), maxSize);
}
template<typename T>
Deserializer &container2(T &&obj, size_t maxSize) {
return container<2>(std::forward<T>(obj), maxSize);
}
template<typename T>
Deserializer &container4(T &&obj, size_t maxSize) {
return container<4>(std::forward<T>(obj), maxSize);
}
template<typename T>
Deserializer &container8(T &&obj, size_t maxSize) {
return container<8>(std::forward<T>(obj), maxSize);
}
private:
Reader& _reader;
Reader &_reader;
bool _isValid;
void readSize(size_t &size, size_t maxSize) {
size = {};
if (_isValid) {
@@ -330,9 +422,9 @@ namespace bitsery {
_isValid = _reader.readBits(secondBit, 1);
if (_isValid) {
if (secondBit) {
_isValid = _reader.readBits(size,14);
_isValid = _reader.readBits(size, 14);
} else {
_isValid = _reader.readBits(size,30);
_isValid = _reader.readBits(size, 30);
}
}
}
@@ -346,7 +438,7 @@ namespace bitsery {
//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) {
for (;_isValid && first != last; ++first)
for (; _isValid && first != last; ++first)
value<VSIZE>(*first);
};
@@ -361,14 +453,14 @@ namespace bitsery {
//process by calling functions
template<typename It, typename Fnc>
void procContainer(It first, It last, Fnc fnc) {
for (;_isValid && first != last; ++first)
for (; _isValid && first != last; ++first)
fnc(*this, *first);
};
//process object types
template<typename It>
void procContainer(It first, It last) {
for (;_isValid && first != last; ++first)
for (; _isValid && first != last; ++first)
object(*first);
};

View File

@@ -45,7 +45,7 @@ namespace bitsery {
struct swapImpl {
static uint64_t exec(uint64_t value) {
#ifdef __GNUC__
return __builtin_bswap64( value );
return __builtin_bswap64(value);
#else
value = ( value & 0x00000000FFFFFFFF ) << 32 | ( value & 0xFFFFFFFF00000000 ) >> 32;
value = ( value & 0x0000FFFF0000FFFF ) << 16 | ( value & 0xFFFF0000FFFF0000 ) >> 16;
@@ -54,18 +54,16 @@ namespace bitsery {
#endif
}
static uint32_t exec(uint32_t value)
{
static uint32_t exec(uint32_t value) {
#ifdef __GNUC__
return __builtin_bswap32( value );
return __builtin_bswap32(value);
#else
return ( value & 0x000000ff ) << 24 | ( value & 0x0000ff00 ) << 8 | ( value & 0x00ff0000 ) >> 8 | ( value & 0xff000000 ) >> 24;
#endif
}
static uint16_t exec(uint16_t value)
{
return ( value & 0x00ff ) << 8 | ( value & 0xff00 ) >> 8;
static uint16_t exec(uint16_t value) {
return (value & 0x00ff) << 8 | (value & 0xff00) >> 8;
}
static uint8_t exec(uint8_t value) {
@@ -73,24 +71,26 @@ namespace bitsery {
}
};
template <typename TValue>
template<typename TValue>
TValue swap(TValue value) {
constexpr size_t TSize = sizeof(TValue);
using UT = typename std::conditional<TSize == 1, uint8_t,
typename std::conditional<TSize == 2, uint16_t,
typename std::conditional<TSize == 4, uint32_t , uint64_t>::type>::type>::type;
typename std::conditional<TSize == 4, uint32_t, uint64_t>::type>::type>::type;
return swapImpl::exec(static_cast<UT>(value));
}
//add test data in separate struct, because some compilers only support constexpr functions with return-only body
struct EndiannessTestData {
static constexpr uint32_t _sample4Bytes = 0x01020304;
static constexpr uint8_t _sample1stByte = (const uint8_t&)_sample4Bytes;
static constexpr uint8_t _sample1stByte = (const uint8_t &) _sample4Bytes;
};
constexpr EndiannessType getSystemEndianness() {
static_assert(EndiannessTestData::_sample1stByte == 0x04 || EndiannessTestData::_sample1stByte == 0x01, "system must be either little or big endian");
return EndiannessTestData::_sample1stByte == 0x04 ? EndiannessType::LittleEndian : EndiannessType::BigEndian;
static_assert(EndiannessTestData::_sample1stByte == 0x04 || EndiannessTestData::_sample1stByte == 0x01,
"system must be either little or big endian");
return EndiannessTestData::_sample1stByte == 0x04 ? EndiannessType::LittleEndian
: EndiannessType::BigEndian;
}
}

View File

@@ -49,7 +49,7 @@ namespace bitsery {
template<typename T>
using SAME_SIZE_UNSIGNED = typename SAME_SIZE_UNSIGNED_TYPE<T>::type;
template <typename T>
template<typename T>
constexpr size_t getSize(T v, size_t s) {
return v > 0 ? getSize(v / 2, s + 1) : s;
}
@@ -149,21 +149,21 @@ namespace bitsery {
return static_cast<VT>(ratio * maxUint);
};
template<typename T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
void setRangeValue(T& v, const RangeSpec<T>& r) {
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 = std::underlying_type_t<T>;
reinterpret_cast<VT&>(v) += static_cast<VT>(r.min);
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 = SAME_SIZE_UNSIGNED<T>;
const auto intRep = reinterpret_cast<UIT&>(v);
const auto intRep = reinterpret_cast<UIT &>(v);
const UIT maxUint = (static_cast<UIT>(1) << r.bitsRequired) - 1;
v = r.min + (static_cast<T>(intRep) / maxUint) * (r.max - r.min);
};
@@ -195,6 +195,26 @@ namespace bitsery {
return 0u;
};
/*
* functions for object serialization
*/
template<typename S, typename T, typename Enabled = void>
struct SerializeFunction {
static S &invoke(S &s, T &v) {
static_assert(!std::is_void<Enabled>::value, "please define 'serialize' function.");
return s;
}
};
template<typename S, typename T>
struct SerializeFunction<S, T, typename std::enable_if<
std::is_same<S &, decltype(serialize(std::declval<S &>(), std::declval<T &>()))>::value
>::type> {
static S &invoke(S &s, T &v) {
return serialize(s, v);
}
};
/*
* delta functions
@@ -205,7 +225,8 @@ namespace bitsery {
template<typename T>
ObjectMemoryPosition(const T &oldObj, const T &newObj)
:ObjectMemoryPosition{reinterpret_cast<const char *>(&oldObj), reinterpret_cast<const char *>(&newObj),
:ObjectMemoryPosition{reinterpret_cast<const char *>(&oldObj),
reinterpret_cast<const char *>(&newObj),
sizeof(T)} {
}

View File

@@ -24,40 +24,52 @@
#ifndef BITSERY_EXT_OPTIONAL_H
#define BITSERY_EXT_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>;
//}
namespace bitsery {
namespace ext {
template <typename T>
template<typename T>
using std_optional = ::std::optional<T>;
template <typename T>
class optional {
public:
explicit optional(T& v):_value{v} {
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>>(), "");
static_assert(std::is_default_constructible<TVal>::value, "");
};
template <typename TSerializer, typename Fnc>
void serialize(TSerializer& ser, const Fnc& fnc) {
ser.boolByte(static_cast<bool>(_value));
if (_value)
fnc(ser, *_value);
template<typename T, typename Ser, typename Fnc>
void serialize(const T &obj, Ser &ser, Fnc &&fnc) const {
assertType<T>();
ser.boolByte(static_cast<bool>(obj));
if (obj)
fnc(ser, *obj);
}
template <typename TSerializer, typename Fnc>
void deserialize(TSerializer& ser, const Fnc& fnc) {
template<typename T, typename Des, typename Fnc>
void deserialize(T &obj, Des &des, Fnc &&fnc) const {
assertType<T>();
bool exists{};
ser.boolByte(exists);
des.boolByte(exists);
if (exists) {
typename T::value_type tmp{};
fnc(ser, tmp);
_value = tmp;
fnc(des, tmp);
obj = tmp;
} else {
_value = T{};
//experimental optional doesnt have .reset method
obj = T{};
}
}
private:
T& _value;
};
}

View File

@@ -38,53 +38,79 @@ namespace bitsery {
public:
Serializer(Writter &w) : _writter{w} {};
/*
* object function
*/
template<typename T>
Serializer& object(const T &obj) {
return serialize(*this, obj);
Serializer &object(T &&obj) {
return details::SerializeFunction<Serializer, T>::invoke(*this, std::forward<T>(obj));
}
//in c++17 change "class" to typename
template <template <typename> class Extension, typename TValue, typename Fnc>
Serializer& ext(const TValue& v, Fnc&& fnc ) {
Extension<const TValue> ext{v};
ext.serialize(*this, std::forward<Fnc>(fnc));
return *this;
};
/*
* value overloads
*/
template<size_t VSIZE, typename T, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
Serializer& value(const T &v) {
Serializer &value(const T &v) {
static_assert(std::numeric_limits<T>::is_iec559, "");
_writter.template writeBytes<VSIZE>(reinterpret_cast<const details::SAME_SIZE_UNSIGNED<T> &>(v));
return *this;
}
template<size_t VSIZE, typename T, typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
Serializer& value(const T &v) {
Serializer &value(const T &v) {
_writter.template writeBytes<VSIZE>(reinterpret_cast<const std::underlying_type_t<T> &>(v));
return *this;
}
template<size_t VSIZE, typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
Serializer& value(const T &v) {
Serializer &value(const T &v) {
_writter.template writeBytes<VSIZE>(v);
return *this;
}
/*
* custom function
*/
template<typename T, typename Fnc>
Serializer &custom(T &&obj, Fnc &&fnc) {
fnc(*this, std::forward<T>(obj));
return *this;
};
/*
* extension functions
*/
template<typename T, typename Ext, typename Fnc>
Serializer &extension(const T &obj, Ext &&ext, Fnc &&fnc) {
ext.serialize(obj, *this, std::forward<Fnc>(fnc));
return *this;
};
template<size_t VSIZE, typename T, typename Ext>
Serializer &extension(const T &obj, Ext &&ext) {
ext.serialize(obj, *this, [](auto &s, auto &v) { s.template value<VSIZE>(v); });
return *this;
};
template<typename T, typename Ext>
Serializer &extension(const T &obj, Ext &&ext) {
ext.serialize(obj, *this, [](auto &s, auto &v) { s.object(v); });
return *this;
};
/*
* bool
*/
Serializer& boolBit(bool v) {
Serializer &boolBit(bool v) {
_writter.writeBits(static_cast<unsigned char>(v ? 1 : 0), 1);
return *this;
}
Serializer& boolByte(bool v) {
Serializer &boolByte(bool v) {
_writter.template writeBytes<1>(static_cast<unsigned char>(v ? 1 : 0));
return *this;
}
@@ -94,9 +120,10 @@ namespace bitsery {
*/
template<typename T>
Serializer& range(const T &v, const RangeSpec<T> &range) {
Serializer &range(const T &v, const RangeSpec<T> &range) {
assert(details::isRangeValid(v, range));
_writter.template writeBits<decltype(details::getRangeValue(v, range))>(details::getRangeValue(v, range), range.bitsRequired);
_writter.template writeBits<decltype(details::getRangeValue(v, range))>(details::getRangeValue(v, range),
range.bitsRequired);
return *this;
}
@@ -104,27 +131,27 @@ namespace bitsery {
* substitution overloads
*/
template<typename T, size_t N, typename Fnc>
Serializer& substitution(const T &v, const std::array<T, N> &expectedValues, Fnc &&fnc) {
Serializer &substitution(const T &v, const std::array<T, N> &expectedValues, Fnc &&fnc) {
auto index = details::findSubstitutionIndex(v, expectedValues);
range(index, {{}, N +1});
range(index, {{}, N + 1});
if (!index)
fnc(*this, v);
return *this;
};
template<size_t VSIZE, typename T, size_t N>
Serializer& substitution(const T &v, const std::array<T, N> &expectedValues) {
Serializer &substitution(const T &v, const std::array<T, N> &expectedValues) {
auto index = details::findSubstitutionIndex(v, expectedValues);
range(index, {{}, N +1});
range(index, {{}, N + 1});
if (!index)
value<VSIZE>(v);
return *this;
};
template<typename T, size_t N>
Serializer& substitution(const T &v, const std::array<T, N> &expectedValues) {
Serializer &substitution(const T &v, const std::array<T, N> &expectedValues) {
auto index = details::findSubstitutionIndex(v, expectedValues);
range(index, {{}, N +1});
range(index, {{}, N + 1});
if (!index)
object(v);
return *this;
@@ -135,7 +162,7 @@ namespace bitsery {
*/
template<size_t VSIZE, typename T>
Serializer& text(const std::basic_string<T> &str, size_t maxSize) {
Serializer &text(const std::basic_string<T> &str, size_t maxSize) {
assert(str.size() <= maxSize);
auto first = std::begin(str);
auto last = std::end(str);
@@ -145,7 +172,7 @@ namespace bitsery {
}
template<size_t VSIZE, typename T, size_t N>
Serializer& text(const T (&str)[N]) {
Serializer &text(const T (&str)[N]) {
auto first = std::begin(str);
auto last = std::next(first, std::min(std::char_traits<T>::length(str), N - 1));
writeSize(std::distance(first, last));
@@ -158,7 +185,7 @@ namespace bitsery {
*/
template<typename T, typename Fnc>
Serializer& container(const T &obj, size_t maxSize, Fnc &&fnc) {
Serializer &container(const T &obj, size_t maxSize, Fnc &&fnc) {
assert(obj.size() <= maxSize);
writeSize(obj.size());
procContainer(std::begin(obj), std::end(obj), std::forward<Fnc>(fnc));
@@ -166,7 +193,7 @@ namespace bitsery {
}
template<size_t VSIZE, typename T>
Serializer& container(const T &obj, size_t maxSize) {
Serializer &container(const T &obj, size_t maxSize) {
static_assert(VSIZE > 0, "");
assert(obj.size() <= maxSize);
writeSize(obj.size());
@@ -176,7 +203,7 @@ namespace bitsery {
}
template<typename T>
Serializer& container(const T &obj, size_t maxSize) {
Serializer &container(const T &obj, size_t maxSize) {
assert(obj.size() <= maxSize);
writeSize(obj.size());
procContainer(std::begin(obj), std::end(obj));
@@ -190,20 +217,20 @@ namespace bitsery {
//std::array overloads
template<typename T, size_t N, typename Fnc>
Serializer& array(const std::array<T, N> &arr, Fnc &&fnc) {
Serializer &array(const std::array<T, N> &arr, Fnc &&fnc) {
procContainer(std::begin(arr), std::end(arr), std::forward<Fnc>(fnc));
return *this;
}
template<size_t VSIZE, typename T, size_t N>
Serializer& array(const std::array<T, N> &arr) {
Serializer &array(const std::array<T, N> &arr) {
static_assert(VSIZE > 0, "");
procContainer<VSIZE>(std::begin(arr), std::end(arr), std::true_type{});
return *this;
}
template<typename T, size_t N>
Serializer& array(const std::array<T, N> &arr) {
Serializer &array(const std::array<T, N> &arr) {
procContainer(std::begin(arr), std::end(arr));
return *this;
}
@@ -211,73 +238,156 @@ namespace bitsery {
//c-style array overloads
template<typename T, size_t N, typename Fnc>
Serializer& array(const T (&arr)[N], Fnc &&fnc) {
Serializer &array(const T (&arr)[N], Fnc &&fnc) {
procContainer(std::begin(arr), std::end(arr), std::forward<Fnc>(fnc));
return *this;
}
template<size_t VSIZE, typename T, size_t N>
Serializer& array(const T (&arr)[N]) {
Serializer &array(const T (&arr)[N]) {
static_assert(VSIZE > 0, "");
procContainer<VSIZE>(std::begin(arr), std::end(arr), std::true_type{});
return *this;
}
template<typename T, size_t N>
Serializer& array(const T (&arr)[N]) {
Serializer &array(const T (&arr)[N]) {
procContainer(std::begin(arr), std::end(arr));
return *this;
}
Serializer& align() {
Serializer &align() {
_writter.align();
return *this;
}
bool isValid() const {
//serialization cannot fail, it doesn't handle out of memory exception
return true;
}
//overloads for functions with explicit type size
template<typename T> Serializer& value1(T &&v) { return value<1>(std::forward<T>(v)); }
template<typename T> Serializer& value2(T &&v) { return value<2>(std::forward<T>(v)); }
template<typename T> Serializer& value4(T &&v) { return value<4>(std::forward<T>(v)); }
template<typename T> Serializer& value8(T &&v) { return value<8>(std::forward<T>(v)); }
template<typename T, size_t N> Serializer& substitution1
(const T &v, const std::array<T, N> &expectedValues) { return substitution<1>(v, expectedValues); };
template<typename T, size_t N> Serializer& substitution2
(const T &v, const std::array<T, N> &expectedValues) { return substitution<2>(v, expectedValues); };
template<typename T, size_t N> Serializer& substitution4
(const T &v, const std::array<T, N> &expectedValues) { return substitution<4>(v, expectedValues); };
template<typename T, size_t N> Serializer& substitution8
(const T &v, const std::array<T, N> &expectedValues) { return substitution<8>(v, expectedValues); };
template<typename T>
Serializer &value1(T &&v) { return value<1>(std::forward<T>(v)); }
template<typename T> Serializer& text1(const std::basic_string<T> &str, size_t maxSize) {
return text<1>(str, maxSize); }
template<typename T> Serializer& text2(const std::basic_string<T> &str, size_t maxSize) {
return text<2>(str, maxSize); }
template<typename T> Serializer& text4(const std::basic_string<T> &str, size_t maxSize) {
return text<4>(str, maxSize); }
template<typename T>
Serializer &value2(T &&v) { return value<2>(std::forward<T>(v)); }
template<typename T, size_t N> Serializer& text1(const T (&str)[N]) { return text<1>(str); }
template<typename T, size_t N> Serializer& text2(const T (&str)[N]) { return text<2>(str); }
template<typename T, size_t N> Serializer& text4(const T (&str)[N]) { return text<4>(str); }
template<typename T>
Serializer &value4(T &&v) { return value<4>(std::forward<T>(v)); }
template<typename T> Serializer& container1(T &&obj, size_t maxSize) {
return container<1>(std::forward<T>(obj), maxSize); }
template<typename T> Serializer& container2(T &&obj, size_t maxSize) {
return container<2>(std::forward<T>(obj), maxSize); }
template<typename T> Serializer& container4(T &&obj, size_t maxSize) {
return container<4>(std::forward<T>(obj), maxSize); }
template<typename T> Serializer& container8(T &&obj, size_t maxSize) {
return container<8>(std::forward<T>(obj), maxSize); }
template<typename T>
Serializer &value8(T &&v) { return value<8>(std::forward<T>(v)); }
template<typename T, size_t N> Serializer& array1(const std::array<T, N> &arr) { return array<1>(arr); }
template<typename T, size_t N> Serializer& array2(const std::array<T, N> &arr) { return array<2>(arr); }
template<typename T, size_t N> Serializer& array4(const std::array<T, N> &arr) { return array<4>(arr); }
template<typename T, size_t N> Serializer& array8(const std::array<T, N> &arr) { return array<8>(arr); }
template<typename T, typename Ext>
Serializer &extension1(const T &v, Ext &&ext) {
return extension<1>(v, std::forward<Ext>(ext));
};
template<typename T, size_t N> Serializer& array1(const T (&arr)[N]) { return array<1>(arr); }
template<typename T, size_t N> Serializer& array2(const T (&arr)[N]) { return array<2>(arr); }
template<typename T, size_t N> Serializer& array4(const T (&arr)[N]) { return array<4>(arr); }
template<typename T, size_t N> Serializer& array8(const T (&arr)[N]) { return array<8>(arr); }
template<typename T, typename Ext>
Serializer &extension2(const T &v, Ext &&ext) {
return extension<2>(v, std::forward<Ext>(ext));
};
template<typename T, typename Ext>
Serializer &extension4(const T &v, Ext &&ext) {
return extension<4>(v, std::forward<Ext>(ext));
};
template<typename T, typename Ext>
Serializer &extension8(const T &v, Ext &&ext) {
return extension<8>(v, std::forward<Ext>(ext));
};
template<typename T, size_t N>
Serializer &substitution1(const T &v, const std::array<T, N> &expectedValues) {
return substitution<1>(v, expectedValues);
};
template<typename T, size_t N>
Serializer &substitution2(const T &v, const std::array<T, N> &expectedValues) {
return substitution<2>(v, expectedValues);
};
template<typename T, size_t N>
Serializer &substitution4(const T &v, const std::array<T, N> &expectedValues) {
return substitution<4>(v, expectedValues);
};
template<typename T, size_t N>
Serializer &substitution8(const T &v, const std::array<T, N> &expectedValues) {
return substitution<8>(v, expectedValues);
};
template<typename T>
Serializer &text1(const std::basic_string<T> &str, size_t maxSize) {
return text<1>(str, maxSize);
}
template<typename T>
Serializer &text2(const std::basic_string<T> &str, size_t maxSize) {
return text<2>(str, maxSize);
}
template<typename T>
Serializer &text4(const std::basic_string<T> &str, size_t maxSize) {
return text<4>(str, maxSize);
}
template<typename T, size_t N>
Serializer &text1(const T (&str)[N]) { return text<1>(str); }
template<typename T, size_t N>
Serializer &text2(const T (&str)[N]) { return text<2>(str); }
template<typename T, size_t N>
Serializer &text4(const T (&str)[N]) { return text<4>(str); }
template<typename T>
Serializer &container1(T &&obj, size_t maxSize) {
return container<1>(std::forward<T>(obj), maxSize);
}
template<typename T>
Serializer &container2(T &&obj, size_t maxSize) {
return container<2>(std::forward<T>(obj), maxSize);
}
template<typename T>
Serializer &container4(T &&obj, size_t maxSize) {
return container<4>(std::forward<T>(obj), maxSize);
}
template<typename T>
Serializer &container8(T &&obj, size_t maxSize) {
return container<8>(std::forward<T>(obj), maxSize);
}
template<typename T, size_t N>
Serializer &array1(const std::array<T, N> &arr) { return array<1>(arr); }
template<typename T, size_t N>
Serializer &array2(const std::array<T, N> &arr) { return array<2>(arr); }
template<typename T, size_t N>
Serializer &array4(const std::array<T, N> &arr) { return array<4>(arr); }
template<typename T, size_t N>
Serializer &array8(const std::array<T, N> &arr) { return array<8>(arr); }
template<typename T, size_t N>
Serializer &array1(const T (&arr)[N]) { return array<1>(arr); }
template<typename T, size_t N>
Serializer &array2(const T (&arr)[N]) { return array<2>(arr); }
template<typename T, size_t N>
Serializer &array4(const T (&arr)[N]) { return array<4>(arr); }
template<typename T, size_t N>
Serializer &array8(const T (&arr)[N]) { return array<8>(arr); }
private:
Writter &_writter;
@@ -287,11 +397,11 @@ namespace bitsery {
_writter.writeBits(1u, 1);
_writter.writeBits(size, 7);
} else if (size < 0x4000u) {
_writter.writeBits(2u,2);
_writter.writeBits(2u, 2);
_writter.writeBits(size, 14);
} else {
assert(size < 0x40000000u);
_writter.writeBits(0u,2);
_writter.writeBits(0u, 2);
_writter.writeBits(size, 30);
}
}
@@ -300,7 +410,7 @@ namespace bitsery {
//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) {
for (;first != last; ++first)
for (; first != last; ++first)
value<VSIZE>(*first);
};
@@ -315,14 +425,14 @@ namespace bitsery {
//process by calling functions
template<typename It, typename Fnc>
void procContainer(It first, It last, Fnc fnc) {
for (;first != last; ++first)
for (; first != last; ++first)
fnc(*this, *first);
};
//process object types
template<typename It>
void procContainer(It first, It last) {
for (;first != last; ++first)
for (; first != last; ++first)
object(*first);
};

View File

@@ -36,24 +36,20 @@
#include <bitsery/ext/optional.h>
template <typename T>
using extoptional = bitsery::ext::optional<T>;
using extoptional = bitsery::ext::optional;
using testing::Eq;
template <typename T>
void test(SerializationContext& ctx, const T& v, T& r) {
auto fnc = [](auto ser, auto& v) {
ser.template value<sizeof(v)>(v);
};
ctx.createSerializer().ext<extoptional>(v, fnc);
ctx.createDeserializer().ext<extoptional>(r, fnc);
ctx.createSerializer().extension4(v, extoptional{});
ctx.createDeserializer().extension4(r, extoptional{});
}
TEST(SerializeExtensionOptional, EmptyOptional) {
std::optional<int> t1{};
std::optional<int> r1{};
std::optional<int32_t> t1{};
std::optional<int32_t> r1{};
SerializationContext ctx1;
test(ctx1,t1, r1);
@@ -69,8 +65,8 @@ TEST(SerializeExtensionOptional, EmptyOptional) {
}
TEST(SerializeExtensionOptional, OptionalHasValue) {
std::optional<int> t1{43};
std::optional<int> r1{52};
std::optional<int32_t> t1{43};
std::optional<int32_t> r1{52};
SerializationContext ctx1;
test(ctx1,t1, r1);