mirror of
https://github.com/fraillt/bitsery.git
synced 2026-08-28 22:18:29 +00:00
buffer writer improvements
This commit is contained in:
@@ -3,12 +3,13 @@
|
||||
|
||||
### Features
|
||||
|
||||
* now all serializer/deserializer functions return void, to avoid undefined behaviour for functions parameters evaluation when using method chaining. There was no benefits apart from *nicer* syntax, but could have undefined behaviour when building complex serialization flows.
|
||||
* changed BufferWriter/Reader config, added *FixedBufferSize* bool parameter for *BufferWriter* for much better serializer performance (more than 50% improvement). Default is old behavour - using back_insert_iterator when writing.
|
||||
* 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.
|
||||
* user friendly 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.1"></a>
|
||||
# [2.0.1](https://github.com/fraillt/bitsery/compare/v2.0.0...v2.0.1) (2017-08-12)
|
||||
|
||||
|
||||
@@ -135,4 +135,4 @@ serialize(des, res); //des-> Deserializer, data-> Player
|
||||
|
||||
You have learned how to write *serialize* function for your type, that works with serialization and deserialization. You also learned that deserialization is very similar to serialization, but has runtime error checking.
|
||||
|
||||
In [next chapter](composition.md) you'll learn more serialization/deserialization functions and how to compose them efficiently to add default or custom serialization/deserialization behaviour.
|
||||
In [next chapter](composition.md) you'll learn how to compose complex serialization/deserialization flows efficiently.
|
||||
|
||||
@@ -24,7 +24,6 @@ SERIALIZE(Player) {
|
||||
s.value4(o.pos.y);
|
||||
s.value4(o.pos.z);
|
||||
s.text1(o.name);
|
||||
return s;
|
||||
}
|
||||
|
||||
Player createData() {
|
||||
|
||||
@@ -26,16 +26,15 @@
|
||||
#define BITSERY_BUFFER_READER_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
template<typename Config>
|
||||
struct BasicBufferReader {
|
||||
using ValueType = typename Config::BufferValueType;
|
||||
using ScratchType = typename Config::BufferScrathType;
|
||||
using BufferType = typename Config::BufferType;
|
||||
using ValueType = typename BufferType::value_type;
|
||||
using ScratchType = typename details::SCRATCH_TYPE<ValueType>::type;
|
||||
|
||||
BasicBufferReader(const ValueType *data, size_t size) : _pos{data}, _end{data + size} {
|
||||
static_assert(std::is_unsigned<ValueType>(), "Config::BufferValueType must be unsigned");
|
||||
@@ -45,11 +44,10 @@ namespace bitsery {
|
||||
static_assert(sizeof(ValueType) == 1, "currently only supported BufferValueType is 1 byte");
|
||||
}
|
||||
|
||||
explicit BasicBufferReader(const std::vector<ValueType> &buf) : BasicBufferReader(buf.data(), buf.size()) {
|
||||
}
|
||||
BasicBufferReader(typename BufferType::iterator begin, typename BufferType::iterator end)
|
||||
: BasicBufferReader(std::addressof(*begin), std::distance(begin, end)) {}
|
||||
|
||||
template<size_t N>
|
||||
explicit BasicBufferReader(const ValueType (&data)[N]): BasicBufferReader(data, N) {
|
||||
explicit BasicBufferReader(const BufferType &buf) : BasicBufferReader(buf.data(), buf.size()) {
|
||||
}
|
||||
|
||||
BasicBufferReader(const BasicBufferReader &) = delete;
|
||||
|
||||
@@ -27,10 +27,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
@@ -62,11 +59,11 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
void flush() {
|
||||
|
||||
_bitsCount += (8 - (_bitsCount % 8)) % 8;
|
||||
}
|
||||
|
||||
//get size in bytes
|
||||
size_t getSize() const {
|
||||
size_t getWrittenBytesCount() const {
|
||||
return _bitsCount / 8;
|
||||
}
|
||||
|
||||
@@ -77,11 +74,13 @@ namespace bitsery {
|
||||
|
||||
template<typename Config>
|
||||
struct BasicBufferWriter {
|
||||
using ValueType = typename Config::BufferValueType;
|
||||
using ScratchType = typename Config::BufferScrathType;
|
||||
using BufferType = typename Config::BufferType;
|
||||
using ValueType = typename BufferType::value_type;
|
||||
using ScratchType = typename details::SCRATCH_TYPE<ValueType>::type;
|
||||
using BufferContext = details::WriteBufferContext<BufferType, Config::FixedBufferSize>;
|
||||
|
||||
explicit BasicBufferWriter(std::vector<ValueType> &buffer) : _outIt{std::back_inserter(buffer)} {
|
||||
static_assert(std::is_unsigned<ValueType>(), "Config::BufferValueType must be unsigned");
|
||||
explicit BasicBufferWriter(BufferType &buffer) : _bufferContext{buffer} {
|
||||
static_assert(std::is_unsigned<ValueType>(), "Config::BufferType::value_type 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");
|
||||
@@ -148,6 +147,9 @@ namespace bitsery {
|
||||
}
|
||||
}
|
||||
|
||||
size_t getWrittenBytesCount() const {
|
||||
return _bufferContext.getWrittenBytesCount();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -161,13 +163,13 @@ namespace bitsery {
|
||||
void _directWriteSwapTag(const T *v, size_t count, std::true_type) {
|
||||
std::for_each(v, std::next(v, count), [this](const T &v) {
|
||||
const auto res = details::swap(v);
|
||||
std::copy_n(reinterpret_cast<const ValueType *>(&res), sizeof(T), _outIt);
|
||||
_bufferContext.write(reinterpret_cast<const ValueType *>(&res), sizeof(T));
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
_bufferContext.write(reinterpret_cast<const ValueType *>(v), count * sizeof(T));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -207,7 +209,7 @@ namespace bitsery {
|
||||
|
||||
|
||||
const ValueType _MASK = std::numeric_limits<ValueType>::max();
|
||||
std::back_insert_iterator<std::vector<ValueType>> _outIt;
|
||||
BufferContext _bufferContext;
|
||||
ScratchType _scratch{};
|
||||
size_t _scratchBits{};
|
||||
};
|
||||
|
||||
@@ -25,13 +25,14 @@
|
||||
#define BITSERY_COMMON_H
|
||||
|
||||
#include "details/buffer_common.h"
|
||||
#include <vector>
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
struct DefaultConfig {
|
||||
static constexpr EndiannessType NetworkEndianness = EndiannessType::LittleEndian;
|
||||
using BufferValueType = uint8_t;
|
||||
using BufferScrathType = uint16_t;
|
||||
static constexpr bool FixedBufferSize = false;//false means that buffer is resizable and will be used back_insert_iterator for insertion, for reading has no effect.
|
||||
using BufferType = std::vector<uint8_t>;//buffer value type must be unsigned, currently only uint8_t supported
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -40,11 +41,11 @@ namespace bitsery {
|
||||
|
||||
#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)
|
||||
void 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)
|
||||
friend void serialize(S& s, T& o)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace bitsery {
|
||||
template<typename T>
|
||||
DeltaDeserializer &object(T &&obj) {
|
||||
if (getChangedState(obj))
|
||||
return serialize(*this, std::forward<T>(obj));
|
||||
serialize(*this, std::forward<T>(obj));
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,8 +42,9 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
Deserializer &object(T &&obj) {
|
||||
return details::SerializeFunction<Deserializer, T>::invoke(*this, std::forward<T>(obj));
|
||||
void object(T &&obj) {
|
||||
if (_isValid)
|
||||
details::SerializeFunction<Deserializer, T>::invoke(*this, std::forward<T>(obj));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -51,29 +52,23 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<size_t VSIZE, typename T, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
|
||||
Deserializer &value(T &v) {
|
||||
void value(T &v) {
|
||||
static_assert(std::numeric_limits<T>::is_iec559, "");
|
||||
if (_isValid) {
|
||||
if (_isValid)
|
||||
_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) {
|
||||
void value(T &v) {
|
||||
using UT = std::underlying_type_t<T>;
|
||||
if (_isValid) {
|
||||
if (_isValid)
|
||||
_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) {
|
||||
if (_isValid) {
|
||||
void value(T &v) {
|
||||
if (_isValid)
|
||||
_isValid = _reader.template readBytes<VSIZE>(v);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -81,9 +76,9 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T, typename Fnc>
|
||||
Deserializer &custom(T &&obj, Fnc &&fnc) {
|
||||
fnc(*this, std::forward<T>(obj));
|
||||
return *this;
|
||||
void custom(T &&obj, Fnc &&fnc) {
|
||||
if (_isValid)
|
||||
fnc(*this, std::forward<T>(obj));
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -91,37 +86,36 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
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;
|
||||
void extension(T &obj, Ext &&ext, Fnc &&fnc) {
|
||||
if (_isValid)
|
||||
ext.deserialize(obj, *this, std::forward<Fnc>(fnc));
|
||||
};
|
||||
|
||||
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;
|
||||
void extension(T &obj, Ext &&ext) {
|
||||
if (_isValid)
|
||||
ext.deserialize(obj, *this, [](auto &s, auto &v) { s.template value<VSIZE>(v); });
|
||||
};
|
||||
|
||||
template<typename T, typename Ext>
|
||||
Deserializer &extension(T &obj, Ext &&ext) {
|
||||
ext.deserialize(obj, *this, [](auto &s, auto &v) { s.object(v); });
|
||||
return *this;
|
||||
void extension(T &obj, Ext &&ext) {
|
||||
if (_isValid)
|
||||
ext.deserialize(obj, *this, [](auto &s, auto &v) { s.object(v); });
|
||||
};
|
||||
|
||||
/*
|
||||
* bool
|
||||
*/
|
||||
|
||||
Deserializer &boolBit(bool &v) {
|
||||
void boolBit(bool &v) {
|
||||
if (_isValid) {
|
||||
unsigned char tmp;
|
||||
_isValid = _reader.readBits(tmp, 1);
|
||||
v = tmp == 1;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Deserializer &boolByte(bool &v) {
|
||||
void boolByte(bool &v) {
|
||||
if (_isValid) {
|
||||
unsigned char tmp;
|
||||
_isValid = _reader.template readBytes<1>(tmp);
|
||||
@@ -129,7 +123,6 @@ namespace bitsery {
|
||||
_isValid = tmp < 2;
|
||||
v = tmp == 1;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -137,21 +130,20 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
Deserializer &range(T &v, const RangeSpec <T> &range) {
|
||||
void range(T &v, const RangeSpec<T> &range) {
|
||||
if (_isValid) {
|
||||
_isValid = _reader.readBits(reinterpret_cast<details::SAME_SIZE_UNSIGNED<T> &>(v), range.bitsRequired);
|
||||
details::setRangeValue(v, range);
|
||||
if (_isValid)
|
||||
_isValid = details::isRangeValid(v, range);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
* substitution overloads
|
||||
*/
|
||||
template<typename T, size_t N, typename Fnc>
|
||||
Deserializer &substitution(T &v, const std::array<T, N> &expectedValues, Fnc &&fnc) {
|
||||
void substitution(T &v, const std::array<T, N> &expectedValues, Fnc &&fnc) {
|
||||
size_t index;
|
||||
range(index, {{}, N + 1});
|
||||
if (_isValid) {
|
||||
@@ -160,11 +152,10 @@ namespace bitsery {
|
||||
else
|
||||
fnc(*this, v);
|
||||
}
|
||||
return *this;
|
||||
};
|
||||
|
||||
template<size_t VSIZE, typename T, size_t N>
|
||||
Deserializer &substitution(T &v, const std::array<T, N> &expectedValues) {
|
||||
void substitution(T &v, const std::array<T, N> &expectedValues) {
|
||||
size_t index;
|
||||
range(index, {{}, N + 1});
|
||||
if (_isValid) {
|
||||
@@ -173,11 +164,10 @@ namespace bitsery {
|
||||
else
|
||||
value<VSIZE>(v);
|
||||
}
|
||||
return *this;
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
Deserializer &substitution(T &v, const std::array<T, N> &expectedValues) {
|
||||
void substitution(T &v, const std::array<T, N> &expectedValues) {
|
||||
size_t index;
|
||||
range(index, {{}, N + 1});
|
||||
if (_isValid) {
|
||||
@@ -186,7 +176,6 @@ namespace bitsery {
|
||||
else
|
||||
object(v);
|
||||
}
|
||||
return *this;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -194,18 +183,17 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
Deserializer &text(std::basic_string<T> &str, size_t maxSize) {
|
||||
void text(std::basic_string<T> &str, size_t maxSize) {
|
||||
size_t size;
|
||||
readSize(size, maxSize);
|
||||
if (_isValid) {
|
||||
str.resize(size);
|
||||
procContainer<VSIZE>(std::begin(str), std::end(str), std::true_type{});
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T, size_t N>
|
||||
Deserializer &text(T (&str)[N]) {
|
||||
void text(T (&str)[N]) {
|
||||
size_t size;
|
||||
readSize(size, N - 1);
|
||||
if (_isValid) {
|
||||
@@ -214,7 +202,6 @@ namespace bitsery {
|
||||
//null-terminated string
|
||||
str[size] = {};
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -222,36 +209,33 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T, typename Fnc>
|
||||
Deserializer &container(T &&obj, size_t maxSize, Fnc &&fnc) {
|
||||
void container(T &&obj, size_t maxSize, Fnc &&fnc) {
|
||||
decltype(obj.size()) size{};
|
||||
readSize(size, maxSize);
|
||||
if (_isValid) {
|
||||
obj.resize(size);
|
||||
procContainer(std::begin(obj), std::end(obj), std::forward<Fnc>(fnc));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
Deserializer &container(T &obj, size_t maxSize) {
|
||||
void container(T &obj, size_t maxSize) {
|
||||
decltype(obj.size()) size{};
|
||||
readSize(size, maxSize);
|
||||
if (_isValid) {
|
||||
obj.resize(size);
|
||||
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::false_type{});
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Deserializer &container(T &obj, size_t maxSize) {
|
||||
void container(T &obj, size_t maxSize) {
|
||||
decltype(obj.size()) size{};
|
||||
readSize(size, maxSize);
|
||||
if (_isValid) {
|
||||
obj.resize(size);
|
||||
procContainer(std::begin(obj), std::end(obj));
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -261,46 +245,39 @@ namespace bitsery {
|
||||
//std::array overloads
|
||||
|
||||
template<typename T, size_t N, typename Fnc>
|
||||
Deserializer &array(std::array<T, N> &arr, Fnc &&fnc) {
|
||||
void 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) {
|
||||
void 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) {
|
||||
void array(std::array<T, N> &arr) {
|
||||
procContainer(std::begin(arr), std::end(arr));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//c-style array overloads
|
||||
|
||||
template<typename T, size_t N, typename Fnc>
|
||||
Deserializer &array(T (&arr)[N], Fnc &&fnc) {
|
||||
void 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]) {
|
||||
void 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]) {
|
||||
void array(T (&arr)[N]) {
|
||||
procContainer(std::begin(arr), std::end(arr));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Deserializer &align() {
|
||||
void align() {
|
||||
_reader.align();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
@@ -310,100 +287,94 @@ namespace bitsery {
|
||||
//overloads for functions with explicit type size
|
||||
|
||||
template<typename T>
|
||||
Deserializer &value1(T &&v) { return value<1>(std::forward<T>(v)); }
|
||||
void value1(T &&v) { value<1>(std::forward<T>(v)); }
|
||||
|
||||
template<typename T>
|
||||
Deserializer &value2(T &&v) { return value<2>(std::forward<T>(v)); }
|
||||
void value2(T &&v) { value<2>(std::forward<T>(v)); }
|
||||
|
||||
template<typename T>
|
||||
Deserializer &value4(T &&v) { return value<4>(std::forward<T>(v)); }
|
||||
void value4(T &&v) { value<4>(std::forward<T>(v)); }
|
||||
|
||||
template<typename T>
|
||||
Deserializer &value8(T &&v) { return value<8>(std::forward<T>(v)); }
|
||||
void value8(T &&v) { 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));
|
||||
};
|
||||
void extension1(T &v, Ext &&ext) { 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));
|
||||
};
|
||||
void extension2(T &v, Ext &&ext) { 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));
|
||||
};
|
||||
void extension4(T &v, Ext &&ext) { 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));
|
||||
};
|
||||
void extension8(T &v, Ext &&ext) { 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);
|
||||
};
|
||||
void substitution1(T &v, const std::array<T, N> &expectedValues) { 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);
|
||||
};
|
||||
void substitution2(T &v, const std::array<T, N> &expectedValues) { 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);
|
||||
};
|
||||
void substitution4(T &v, const std::array<T, N> &expectedValues) { 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);
|
||||
};
|
||||
void substitution8(T &v, const std::array<T, N> &expectedValues) { substitution<8>(v, expectedValues); };
|
||||
|
||||
template<typename T>
|
||||
Deserializer &text1(std::basic_string<T> &str, size_t maxSize) {
|
||||
return text<1>(str, maxSize);
|
||||
}
|
||||
void text1(std::basic_string<T> &str, size_t maxSize) { text<1>(str, maxSize); }
|
||||
|
||||
template<typename T>
|
||||
Deserializer &text2(std::basic_string<T> &str, size_t maxSize) {
|
||||
return text<2>(str, maxSize);
|
||||
}
|
||||
void text2(std::basic_string<T> &str, size_t maxSize) { text<2>(str, maxSize); }
|
||||
|
||||
template<typename T>
|
||||
Deserializer &text4(std::basic_string<T> &str, size_t maxSize) {
|
||||
return text<4>(str, maxSize);
|
||||
}
|
||||
void text4(std::basic_string<T> &str, size_t maxSize) { text<4>(str, maxSize); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Deserializer &text1(T (&str)[N]) { return text<1>(str); }
|
||||
void text1(T (&str)[N]) { text<1>(str); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Deserializer &text2(T (&str)[N]) { return text<2>(str); }
|
||||
void text2(T (&str)[N]) { text<2>(str); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Deserializer &text4(T (&str)[N]) { return text<4>(str); }
|
||||
void text4(T (&str)[N]) { text<4>(str); }
|
||||
|
||||
template<typename T>
|
||||
Deserializer &container1(T &&obj, size_t maxSize) {
|
||||
return container<1>(std::forward<T>(obj), maxSize);
|
||||
}
|
||||
void container1(T &&obj, size_t maxSize) { 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);
|
||||
}
|
||||
void container2(T &&obj, size_t maxSize) { 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);
|
||||
}
|
||||
void container4(T &&obj, size_t maxSize) { 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);
|
||||
}
|
||||
void container8(T &&obj, size_t maxSize) { container<8>(std::forward<T>(obj), maxSize); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void array1(std::array<T, N> &arr) { array<1>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void array2(std::array<T, N> &arr) { array<2>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void array4(std::array<T, N> &arr) { array<4>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void array8(std::array<T, N> &arr) { array<8>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void array1(T (&arr)[N]) { array<1>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void array2(T (&arr)[N]) { array<2>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void array4(T (&arr)[N]) { array<4>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void array8(T (&arr)[N]) { array<8>(arr); }
|
||||
|
||||
private:
|
||||
Reader &_reader;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <type_traits>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
@@ -93,6 +94,80 @@ namespace bitsery {
|
||||
: EndiannessType::BigEndian;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct SCRATCH_TYPE {
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SCRATCH_TYPE<uint8_t> {
|
||||
using type = uint16_t;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SCRATCH_TYPE<uint16_t> {
|
||||
using type = uint32_t;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SCRATCH_TYPE<uint32_t> {
|
||||
using type = uint64_t;
|
||||
};
|
||||
|
||||
template<typename Buffer, bool isFixed>
|
||||
class WriteBufferContext {
|
||||
};
|
||||
|
||||
template<typename Buffer>
|
||||
class WriteBufferContext<Buffer, true> {
|
||||
public:
|
||||
using ValueType = typename Buffer::value_type;
|
||||
using IteratorType = typename Buffer::iterator;
|
||||
|
||||
explicit WriteBufferContext(Buffer &buffer)
|
||||
: _buffer{buffer},
|
||||
_outIt{buffer.begin()} {
|
||||
}
|
||||
|
||||
void write(const ValueType *data, size_t size) {
|
||||
_outIt = std::copy_n(data, size, _outIt);
|
||||
}
|
||||
|
||||
size_t getWrittenBytesCount() const {
|
||||
return std::distance(_buffer.begin(), _outIt) * sizeof(ValueType);
|
||||
}
|
||||
|
||||
private:
|
||||
Buffer &_buffer;
|
||||
IteratorType _outIt;
|
||||
};
|
||||
|
||||
template<typename Buffer>
|
||||
class WriteBufferContext<Buffer, false> {
|
||||
public:
|
||||
using ValueType = typename Buffer::value_type;
|
||||
using IteratorType = std::back_insert_iterator<Buffer>;
|
||||
|
||||
explicit WriteBufferContext(Buffer &buffer)
|
||||
: _buffer{buffer},
|
||||
_outIt{std::back_insert_iterator<Buffer>(buffer)},
|
||||
_initialSize{buffer.size()} {
|
||||
}
|
||||
|
||||
void write(const ValueType *data, size_t size) {
|
||||
std::copy_n(data, size, _outIt);
|
||||
}
|
||||
|
||||
size_t getWrittenBytesCount() const {
|
||||
return (std::distance(_buffer.begin(), _buffer.end()) - _initialSize) * sizeof(ValueType);
|
||||
}
|
||||
|
||||
private:
|
||||
Buffer &_buffer;
|
||||
IteratorType _outIt;
|
||||
size_t _initialSize;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -201,18 +201,17 @@ namespace bitsery {
|
||||
|
||||
template<typename S, typename T, typename Enabled = void>
|
||||
struct SerializeFunction {
|
||||
static S &invoke(S &s, T &v) {
|
||||
static void 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
|
||||
std::is_same<void, decltype(serialize(std::declval<S &>(), std::declval<T &>()))>::value
|
||||
>::type> {
|
||||
static S &invoke(S &s, T &v) {
|
||||
return serialize(s, v);
|
||||
static void invoke(S &s, T &v) {
|
||||
serialize(s, v);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -42,8 +42,8 @@ namespace bitsery {
|
||||
* object function
|
||||
*/
|
||||
template<typename T>
|
||||
Serializer &object(T &&obj) {
|
||||
return details::SerializeFunction<Serializer, T>::invoke(*this, std::forward<T>(obj));
|
||||
void object(T &&obj) {
|
||||
details::SerializeFunction<Serializer, T>::invoke(*this, std::forward<T>(obj));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -51,22 +51,19 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<size_t VSIZE, typename T, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
|
||||
Serializer &value(const T &v) {
|
||||
void 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) {
|
||||
void 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) {
|
||||
void value(const T &v) {
|
||||
_writter.template writeBytes<VSIZE>(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -74,9 +71,8 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T, typename Fnc>
|
||||
Serializer &custom(T &&obj, Fnc &&fnc) {
|
||||
void custom(T &&obj, Fnc &&fnc) {
|
||||
fnc(*this, std::forward<T>(obj));
|
||||
return *this;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -84,35 +80,32 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T, typename Ext, typename Fnc>
|
||||
Serializer &extension(const T &obj, Ext &&ext, Fnc &&fnc) {
|
||||
void 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) {
|
||||
void 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) {
|
||||
void extension(const T &obj, Ext &&ext) {
|
||||
ext.serialize(obj, *this, [](auto &s, auto &v) { s.object(v); });
|
||||
return *this;
|
||||
};
|
||||
|
||||
/*
|
||||
* bool
|
||||
*/
|
||||
|
||||
Serializer &boolBit(bool v) {
|
||||
void boolBit(bool v) {
|
||||
_writter.writeBits(static_cast<unsigned char>(v ? 1 : 0), 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Serializer &boolByte(bool v) {
|
||||
void boolByte(bool v) {
|
||||
_writter.template writeBytes<1>(static_cast<unsigned char>(v ? 1 : 0));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -120,41 +113,37 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
Serializer &range(const T &v, const RangeSpec<T> &range) {
|
||||
void 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);
|
||||
return *this;
|
||||
using BT = decltype(details::getRangeValue(v, range));
|
||||
_writter.template writeBits<BT>(details::getRangeValue(v, range), range.bitsRequired);
|
||||
}
|
||||
|
||||
/*
|
||||
* substitution overloads
|
||||
*/
|
||||
template<typename T, size_t N, typename Fnc>
|
||||
Serializer &substitution(const T &v, const std::array<T, N> &expectedValues, Fnc &&fnc) {
|
||||
void substitution(const T &v, const std::array<T, N> &expectedValues, Fnc &&fnc) {
|
||||
auto index = details::findSubstitutionIndex(v, expectedValues);
|
||||
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) {
|
||||
void substitution(const T &v, const std::array<T, N> &expectedValues) {
|
||||
auto index = details::findSubstitutionIndex(v, expectedValues);
|
||||
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) {
|
||||
void substitution(const T &v, const std::array<T, N> &expectedValues) {
|
||||
auto index = details::findSubstitutionIndex(v, expectedValues);
|
||||
range(index, {{}, N + 1});
|
||||
if (!index)
|
||||
object(v);
|
||||
return *this;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -162,22 +151,20 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
Serializer &text(const std::basic_string<T> &str, size_t maxSize) {
|
||||
void text(const std::basic_string<T> &str, size_t maxSize) {
|
||||
assert(str.size() <= maxSize);
|
||||
auto first = std::begin(str);
|
||||
auto last = std::end(str);
|
||||
writeSize(std::distance(first, last));
|
||||
procContainer<VSIZE>(first, last, std::true_type{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T, size_t N>
|
||||
Serializer &text(const T (&str)[N]) {
|
||||
void 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));
|
||||
procContainer<VSIZE>(first, last, std::true_type{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -185,29 +172,26 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T, typename Fnc>
|
||||
Serializer &container(const T &obj, size_t maxSize, Fnc &&fnc) {
|
||||
void 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));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
Serializer &container(const T &obj, size_t maxSize) {
|
||||
void container(const T &obj, size_t maxSize) {
|
||||
static_assert(VSIZE > 0, "");
|
||||
assert(obj.size() <= maxSize);
|
||||
writeSize(obj.size());
|
||||
//todo optimisation is possible for contigous containers, but currently there is no compile-time check for this
|
||||
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::false_type{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Serializer &container(const T &obj, size_t maxSize) {
|
||||
void container(const T &obj, size_t maxSize) {
|
||||
assert(obj.size() <= maxSize);
|
||||
writeSize(obj.size());
|
||||
procContainer(std::begin(obj), std::end(obj));
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -217,48 +201,41 @@ namespace bitsery {
|
||||
//std::array overloads
|
||||
|
||||
template<typename T, size_t N, typename Fnc>
|
||||
Serializer &array(const std::array<T, N> &arr, Fnc &&fnc) {
|
||||
void 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) {
|
||||
void 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) {
|
||||
void array(const std::array<T, N> &arr) {
|
||||
procContainer(std::begin(arr), std::end(arr));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//c-style array overloads
|
||||
|
||||
template<typename T, size_t N, typename Fnc>
|
||||
Serializer &array(const T (&arr)[N], Fnc &&fnc) {
|
||||
void 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]) {
|
||||
void 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]) {
|
||||
void array(const T (&arr)[N]) {
|
||||
procContainer(std::begin(arr), std::end(arr));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Serializer &align() {
|
||||
void align() {
|
||||
_writter.align();
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
@@ -270,124 +247,102 @@ namespace bitsery {
|
||||
//overloads for functions with explicit type size
|
||||
|
||||
template<typename T>
|
||||
Serializer &value1(T &&v) { return value<1>(std::forward<T>(v)); }
|
||||
void value1(T &&v) { value<1>(std::forward<T>(v)); }
|
||||
|
||||
template<typename T>
|
||||
Serializer &value2(T &&v) { return value<2>(std::forward<T>(v)); }
|
||||
void value2(T &&v) { value<2>(std::forward<T>(v)); }
|
||||
|
||||
template<typename T>
|
||||
Serializer &value4(T &&v) { return value<4>(std::forward<T>(v)); }
|
||||
void value4(T &&v) { value<4>(std::forward<T>(v)); }
|
||||
|
||||
template<typename T>
|
||||
Serializer &value8(T &&v) { return value<8>(std::forward<T>(v)); }
|
||||
void value8(T &&v) { value<8>(std::forward<T>(v)); }
|
||||
|
||||
template<typename T, typename Ext>
|
||||
Serializer &extension1(const T &v, Ext &&ext) {
|
||||
return extension<1>(v, std::forward<Ext>(ext));
|
||||
};
|
||||
void extension1(const T &v, Ext &&ext) { extension<1>(v, std::forward<Ext>(ext)); };
|
||||
|
||||
template<typename T, typename Ext>
|
||||
Serializer &extension2(const T &v, Ext &&ext) {
|
||||
return extension<2>(v, std::forward<Ext>(ext));
|
||||
};
|
||||
void extension2(const T &v, Ext &&ext) { 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));
|
||||
};
|
||||
void extension4(const T &v, Ext &&ext) { 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));
|
||||
void extension8(const T &v, Ext &&ext) { extension<8>(v, std::forward<Ext>(ext)); };
|
||||
|
||||
template<typename T, size_t N>
|
||||
void substitution1(const T &v, const std::array<T, N> &expectedValues) {
|
||||
substitution<1>(v, expectedValues);
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
Serializer &substitution1(const T &v, const std::array<T, N> &expectedValues) {
|
||||
return substitution<1>(v, expectedValues);
|
||||
void substitution2(const T &v, const std::array<T, N> &expectedValues) {
|
||||
substitution<2>(v, expectedValues);
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
Serializer &substitution2(const T &v, const std::array<T, N> &expectedValues) {
|
||||
return substitution<2>(v, expectedValues);
|
||||
void substitution4(const T &v, const std::array<T, N> &expectedValues) {
|
||||
substitution<4>(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);
|
||||
void substitution8(const T &v, const std::array<T, N> &expectedValues) {
|
||||
substitution<8>(v, expectedValues);
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
Serializer &text1(const std::basic_string<T> &str, size_t maxSize) {
|
||||
return text<1>(str, maxSize);
|
||||
}
|
||||
void text1(const std::basic_string<T> &str, size_t maxSize) { text<1>(str, maxSize); }
|
||||
|
||||
template<typename T>
|
||||
Serializer &text2(const std::basic_string<T> &str, size_t maxSize) {
|
||||
return text<2>(str, maxSize);
|
||||
}
|
||||
void text2(const std::basic_string<T> &str, size_t maxSize) { text<2>(str, maxSize); }
|
||||
|
||||
template<typename T>
|
||||
Serializer &text4(const std::basic_string<T> &str, size_t maxSize) {
|
||||
return text<4>(str, maxSize);
|
||||
}
|
||||
void text4(const std::basic_string<T> &str, size_t maxSize) { text<4>(str, maxSize); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Serializer &text1(const T (&str)[N]) { return text<1>(str); }
|
||||
void text1(const T (&str)[N]) { text<1>(str); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Serializer &text2(const T (&str)[N]) { return text<2>(str); }
|
||||
void text2(const T (&str)[N]) { text<2>(str); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Serializer &text4(const T (&str)[N]) { return text<4>(str); }
|
||||
void text4(const T (&str)[N]) { text<4>(str); }
|
||||
|
||||
template<typename T>
|
||||
Serializer &container1(T &&obj, size_t maxSize) {
|
||||
return container<1>(std::forward<T>(obj), maxSize);
|
||||
}
|
||||
void container1(T &&obj, size_t maxSize) { 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);
|
||||
}
|
||||
void container2(T &&obj, size_t maxSize) { 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);
|
||||
}
|
||||
void container4(T &&obj, size_t maxSize) { 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);
|
||||
}
|
||||
void container8(T &&obj, size_t maxSize) { 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); }
|
||||
void array1(const std::array<T, N> &arr) { array<1>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Serializer &array2(const std::array<T, N> &arr) { return array<2>(arr); }
|
||||
void array2(const std::array<T, N> &arr) { array<2>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Serializer &array4(const std::array<T, N> &arr) { return array<4>(arr); }
|
||||
void array4(const std::array<T, N> &arr) { array<4>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Serializer &array8(const std::array<T, N> &arr) { return array<8>(arr); }
|
||||
void array8(const std::array<T, N> &arr) { array<8>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Serializer &array1(const T (&arr)[N]) { return array<1>(arr); }
|
||||
void array1(const T (&arr)[N]) { array<1>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Serializer &array2(const T (&arr)[N]) { return array<2>(arr); }
|
||||
void array2(const T (&arr)[N]) { array<2>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Serializer &array4(const T (&arr)[N]) { return array<4>(arr); }
|
||||
void array4(const T (&arr)[N]) { array<4>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
Serializer &array8(const T (&arr)[N]) { return array<8>(arr); }
|
||||
void array8(const T (&arr)[N]) { array<8>(arr); }
|
||||
|
||||
private:
|
||||
Writter &_writter;
|
||||
@@ -418,8 +373,7 @@ namespace bitsery {
|
||||
//true_type means, that we can copy whole buffer
|
||||
template<size_t VSIZE, typename It>
|
||||
void procContainer(It first, It last, std::true_type) {
|
||||
if (first != last)
|
||||
_writter.template writeBuffer<VSIZE>(&(*first), std::distance(first, last));
|
||||
_writter.template writeBuffer<VSIZE>(&(*first), std::distance(first, last));
|
||||
};
|
||||
|
||||
//process by calling functions
|
||||
|
||||
@@ -30,7 +30,7 @@ using testing::Eq;
|
||||
using testing::ContainerEq;
|
||||
using bitsery::BufferWriter;
|
||||
using bitsery::BufferReader;
|
||||
using Buffer = std::vector<bitsery::DefaultConfig::BufferValueType>;
|
||||
using Buffer = bitsery::DefaultConfig::BufferType;
|
||||
|
||||
struct IntegralUnsignedTypes {
|
||||
uint32_t a;
|
||||
|
||||
@@ -31,7 +31,7 @@ using testing::Eq;
|
||||
using testing::ContainerEq;
|
||||
using bitsery::BufferWriter;
|
||||
using bitsery::BufferReader;
|
||||
using Buffer = std::vector<bitsery::DefaultConfig::BufferValueType>;
|
||||
using Buffer = bitsery::DefaultConfig::BufferType;
|
||||
|
||||
struct IntegralTypes {
|
||||
int64_t a;
|
||||
@@ -124,7 +124,7 @@ TEST(BufferBytesOperations, BufferReaderUsingDataPlusSizeCtor) {
|
||||
EXPECT_THAT(data.f, ContainerEq(res.f));
|
||||
}
|
||||
|
||||
TEST(BufferBytesOperations, BufferReaderUsingCArrayCtor) {
|
||||
TEST(BufferBytesOperations, BufferReaderUsingIteratorsCtor) {
|
||||
//setup data
|
||||
auto data =getInitializedIntegralTypes();
|
||||
//create and write to buffer
|
||||
@@ -133,10 +133,8 @@ TEST(BufferBytesOperations, BufferReaderUsingCArrayCtor) {
|
||||
writeIntegralTypesToBuffer(bw, data);
|
||||
|
||||
ASSERT_THAT(std::distance(buf.begin(), buf.end()), Eq(18));
|
||||
uint8_t cArrBuf[18];
|
||||
std::copy(buf.begin(), buf.end(), cArrBuf);
|
||||
//read from buffer
|
||||
BufferReader br{cArrBuf};
|
||||
BufferReader br{buf.begin(), buf.end()};
|
||||
IntegralTypes res{};
|
||||
EXPECT_THAT(br.readBytes<4>(res.b), Eq(true));
|
||||
EXPECT_THAT(br.readBytes<1>(res.f[0]), Eq(true));
|
||||
|
||||
@@ -30,7 +30,7 @@ using testing::Eq;
|
||||
using testing::ContainerEq;
|
||||
using bitsery::EndiannessType;
|
||||
using bitsery::DefaultConfig;
|
||||
using Buffer = std::vector<bitsery::DefaultConfig::BufferValueType>;
|
||||
using Buffer = bitsery::DefaultConfig::BufferType;
|
||||
|
||||
constexpr EndiannessType getInverseEndianness(EndiannessType e) {
|
||||
return e == EndiannessType::LittleEndian
|
||||
@@ -40,8 +40,8 @@ constexpr EndiannessType getInverseEndianness(EndiannessType e) {
|
||||
|
||||
struct InverseEndiannessConfig {
|
||||
static constexpr bitsery::EndiannessType NetworkEndianness = getInverseEndianness(DefaultConfig::NetworkEndianness);
|
||||
using BufferValueType = DefaultConfig::BufferValueType;
|
||||
using BufferScrathType = DefaultConfig::BufferScrathType;
|
||||
static constexpr bool FixedBufferSize = DefaultConfig::FixedBufferSize;
|
||||
using BufferType = DefaultConfig::BufferType;
|
||||
};
|
||||
|
||||
struct IntegralTypes {
|
||||
@@ -147,7 +147,7 @@ struct IntegralUnsignedTypes {
|
||||
|
||||
TEST(BufferEndianness, WhenBufferValueTypeIs1ByteThenBitOperationsIsNotAffectedByEndianness) {
|
||||
//fill initial values
|
||||
static_assert(sizeof(DefaultConfig::BufferValueType) == 1, "currently only 1 byte size, value size is supported");
|
||||
static_assert(sizeof(DefaultConfig::BufferType::value_type) == 1, "currently only 1 byte size, value size is supported");
|
||||
//fill initial values
|
||||
constexpr IntegralUnsignedTypes src {
|
||||
0x0000334455667788,//bits 19
|
||||
|
||||
@@ -33,8 +33,12 @@ TEST(SerializeBooleans, BoolAsBit) {
|
||||
bool t2{false};
|
||||
bool res1;
|
||||
bool res2;
|
||||
ctx.createSerializer().boolBit(t1).boolBit(t2);
|
||||
ctx.createDeserializer().boolBit(res1).boolBit(res2);
|
||||
auto ser = ctx.createSerializer();
|
||||
ser.boolBit(t1);
|
||||
ser.boolBit(t2);
|
||||
auto des = ctx.createDeserializer();
|
||||
des.boolBit(res1);
|
||||
des.boolBit(res2);
|
||||
|
||||
EXPECT_THAT(res1, Eq(t1));
|
||||
EXPECT_THAT(res2, Eq(t2));
|
||||
@@ -47,8 +51,12 @@ TEST(SerializeBooleans, BoolAsByte) {
|
||||
bool t2{false};
|
||||
bool res1;
|
||||
bool res2;
|
||||
ctx.createSerializer().boolByte(t1).boolByte(t2);
|
||||
ctx.createDeserializer().boolByte(res1).boolByte(res2);
|
||||
auto ser = ctx.createSerializer();
|
||||
ser.boolByte(t1);
|
||||
ser.boolByte(t2);
|
||||
auto des = ctx.createDeserializer();
|
||||
des.boolByte(res1);
|
||||
des.boolByte(res2);
|
||||
|
||||
EXPECT_THAT(res1, Eq(t1));
|
||||
EXPECT_THAT(res2, Eq(t2));
|
||||
|
||||
@@ -67,12 +67,14 @@ TEST(SerializeFSArrayStdArray, CustomFunctionThatSerializesAnEmptyByteEveryEleme
|
||||
auto ser = ctx.createSerializer();
|
||||
ser.array(src, [](auto &s, auto& v) {
|
||||
char tmp{};
|
||||
s.object(v).value1(tmp);
|
||||
s.object(v);
|
||||
s.value1(tmp);
|
||||
});
|
||||
auto des = ctx.createDeserializer();
|
||||
des.array(res, [](auto &s, auto& v) {
|
||||
char tmp{};
|
||||
s.object(v).value1(tmp);
|
||||
s.object(v);
|
||||
s.value1(tmp);
|
||||
});
|
||||
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(src.size() * (MyStruct1::SIZE + sizeof(char))));
|
||||
@@ -118,12 +120,14 @@ TEST(SerializeFSArrayCArray, CustomFunctionThatSerializesAnEmptyByteEveryElement
|
||||
auto ser = ctx.createSerializer();
|
||||
ser.array(src, [](auto& s, auto& v) {
|
||||
char tmp{};
|
||||
s.object(v).value1(tmp);
|
||||
s.object(v);
|
||||
s.value1(tmp);
|
||||
});
|
||||
auto des = ctx.createDeserializer();
|
||||
des.array(res, [](auto& s, auto& v) {
|
||||
char tmp{};
|
||||
s.object(v).value1(tmp);
|
||||
s.object(v);
|
||||
s.value1(tmp);
|
||||
});
|
||||
|
||||
EXPECT_THAT(ctx.getBufferSize(), Eq(std::extent<decltype(src)>::value * (MyStruct1::SIZE + sizeof(char))));
|
||||
|
||||
@@ -60,13 +60,12 @@ SERIALIZE(Z)
|
||||
{
|
||||
s.object(o.x);
|
||||
s.object(o.y);
|
||||
return s;
|
||||
}
|
||||
|
||||
SERIALIZE(X)
|
||||
{
|
||||
return s.template value<sizeof(o.x)>(o.x)
|
||||
.template text<1>(o.s, 1000);
|
||||
s.template value<sizeof(o.x)>(o.x);
|
||||
s.template text<1>(o.s, 1000);
|
||||
}
|
||||
|
||||
SERIALIZE(Y)
|
||||
@@ -77,7 +76,6 @@ SERIALIZE(Y)
|
||||
s.array(o.arr, writeInt);
|
||||
s.array(o.carr, writeInt);
|
||||
s.container(o.vx, 10000, [](auto& s, auto& v) { s.object(v); });
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +155,7 @@ TEST(DeltaSerializer, GeneralConceptTest) {
|
||||
yNew.vx[1].s = "bla";
|
||||
yNew.vx.push_back(X{ 3 });
|
||||
|
||||
std::vector<bitsery::DefaultConfig::BufferValueType> buf;
|
||||
bitsery::DefaultConfig::BufferType buf;
|
||||
bitsery::BufferWriter bw{ buf };
|
||||
bitsery::DeltaSerializer<bitsery::BufferWriter, Y> ser(bw, y, yNew);
|
||||
serialize(ser, yNew);
|
||||
|
||||
@@ -33,20 +33,23 @@
|
||||
*/
|
||||
|
||||
struct MyStruct1 {
|
||||
MyStruct1(int v1, int v2):i1{v1}, i2{v2} {}
|
||||
MyStruct1():MyStruct1{0,0} {}
|
||||
MyStruct1(int v1, int v2) : i1{v1}, i2{v2} {}
|
||||
|
||||
MyStruct1() : MyStruct1{0, 0} {}
|
||||
|
||||
int i1;
|
||||
int i2;
|
||||
bool operator == (const MyStruct1& rhs) const {
|
||||
|
||||
bool operator==(const MyStruct1 &rhs) const {
|
||||
return i1 == rhs.i1 && i2 == rhs.i2;
|
||||
}
|
||||
|
||||
static constexpr size_t SIZE = sizeof(MyStruct1::i1) + sizeof(MyStruct1::i2);
|
||||
};
|
||||
|
||||
SERIALIZE(MyStruct1) {
|
||||
return s.
|
||||
template value<sizeof(o.i1)>(o.i1).
|
||||
template value<sizeof(o.i2)>(o.i2);
|
||||
s.template value<sizeof(o.i1)>(o.i1);
|
||||
s.template value<sizeof(o.i2)>(o.i2);
|
||||
}
|
||||
|
||||
enum class MyEnumClass {
|
||||
@@ -58,26 +61,28 @@ struct MyStruct2 {
|
||||
V1, V2, V3, V4, V5, V6
|
||||
};
|
||||
|
||||
MyStruct2(MyEnum e, MyStruct1 s):e1{e}, s1{s} {}
|
||||
MyStruct2():MyStruct2{V1,{0,0}} {}
|
||||
MyStruct2(MyEnum e, MyStruct1 s) : e1{e}, s1{s} {}
|
||||
|
||||
MyStruct2() : MyStruct2{V1, {0, 0}} {}
|
||||
|
||||
MyEnum e1;
|
||||
MyStruct1 s1;
|
||||
bool operator == (const MyStruct2& rhs) const {
|
||||
|
||||
bool operator==(const MyStruct2 &rhs) const {
|
||||
return e1 == rhs.e1 && s1 == rhs.s1;
|
||||
}
|
||||
|
||||
static constexpr size_t SIZE = MyStruct1::SIZE + sizeof(MyStruct2::e1);
|
||||
};
|
||||
|
||||
SERIALIZE(MyStruct2) {
|
||||
return s.
|
||||
template value<sizeof(o.e1)>(o.e1).
|
||||
object(o.s1);
|
||||
s.template value<sizeof(o.e1)>(o.e1);
|
||||
s.object(o.s1);
|
||||
}
|
||||
|
||||
|
||||
class SerializationContext {
|
||||
std::vector<bitsery::DefaultConfig::BufferValueType> buf{};
|
||||
bitsery::DefaultConfig::BufferType buf{};
|
||||
std::unique_ptr<bitsery::BufferWriter> bw;
|
||||
std::unique_ptr<bitsery::BufferReader> br;
|
||||
public:
|
||||
@@ -89,6 +94,7 @@ public:
|
||||
size_t getBufferSize() const {
|
||||
return buf.size();
|
||||
}
|
||||
|
||||
//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
|
||||
static size_t containerSizeSerializedBytesCount(size_t elemsCount) {
|
||||
|
||||
Reference in New Issue
Block a user