mirror of
https://github.com/fraillt/bitsery.git
synced 2026-06-08 00:03:54 +00:00
flexible syntax
This commit is contained in:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -1,5 +1,18 @@
|
||||
# [3.0.0](https://github.com/fraillt/bitsery/compare/v2.0.1...v3.0.0) (2017-09-21)
|
||||
|
||||
new flexible syntax
|
||||
traits changed,
|
||||
container get isContiguous
|
||||
text is separate from container, only has length, and addNUL
|
||||
buffer traits removed difference type
|
||||
improved reading, writing performance (because of isContiguous and difference_type)
|
||||
|
||||
todo write tests:
|
||||
bufferreader accepts const data
|
||||
|
||||
|
||||
# [3.0.0](https://github.com/fraillt/bitsery/compare/v2.0.1...v3.0.0) (2017-09-21)
|
||||
|
||||
### Features
|
||||
|
||||
* refactored interface, now works with C++11 compiler.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <bitsery/bitsery.h>
|
||||
#include <bitsery/ext/growable.h>
|
||||
#include <array>
|
||||
#include <bitsery/traits/string.h>
|
||||
#include <bitsery/traits/array.h>
|
||||
|
||||
namespace MyTypes {
|
||||
|
||||
@@ -62,10 +63,11 @@ namespace MyTypes {
|
||||
|
||||
using namespace bitsery;
|
||||
|
||||
using Buffer =std::array<uint8_t, 1000000>;
|
||||
//change configuration
|
||||
struct NonDefaultConfig: public bitsery::DefaultConfig {
|
||||
//change underlying buffer
|
||||
using BufferType = std::array<uint8_t, 1000000>;
|
||||
using BufferType = Buffer;
|
||||
};
|
||||
|
||||
|
||||
@@ -76,7 +78,7 @@ int main() {
|
||||
|
||||
//create serializer
|
||||
//1) create buffer to store data
|
||||
std::array<uint8_t, 1000000> buffer{};
|
||||
Buffer buffer{};
|
||||
//2) create buffer writer that is able to write bytes or bits to buffer
|
||||
BasicBufferWriter<NonDefaultConfig> bw{buffer};
|
||||
//3) create serializer
|
||||
|
||||
@@ -35,14 +35,13 @@ namespace bitsery {
|
||||
struct BasicBufferReader {
|
||||
|
||||
using BufferType = typename Config::BufferType;
|
||||
using ValueType = typename details::BufferContainerTraits<BufferType>::TValue;
|
||||
using ValueType = typename details::ContainerTraits<BufferType>::TValue;
|
||||
using BufferIteratorType = typename details::BufferContainerTraits<BufferType>::TIterator;
|
||||
using ScratchType = typename details::SCRATCH_TYPE<ValueType>::type;
|
||||
|
||||
BasicBufferReader(ValueType* begin, ValueType* end)
|
||||
:_pos{begin},
|
||||
_end{end},
|
||||
_session{*this, _pos, _end}
|
||||
BasicBufferReader(BufferIteratorType data, BufferIteratorType end)
|
||||
: _bufferContext{data, end},
|
||||
_session{*this, _bufferContext}
|
||||
{
|
||||
static_assert(std::is_unsigned<ValueType>(), "Config::BufferValueType must be unsigned");
|
||||
static_assert(std::is_unsigned<ScratchType>(), "Config::BufferScrathType must be unsigned");
|
||||
@@ -52,7 +51,7 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
BasicBufferReader(BufferRange<BufferIteratorType> range)
|
||||
:BasicBufferReader(std::addressof(*range.begin()), std::addressof(*range.end())) {
|
||||
:BasicBufferReader(range.begin(), range.end()) {
|
||||
static_assert(std::is_same<
|
||||
typename std::iterator_traits<BufferIteratorType>::iterator_category,
|
||||
std::random_access_iterator_tag>::value,
|
||||
@@ -114,24 +113,18 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
bool isCompletedSuccessfully() const {
|
||||
return _pos == _end && !_session.hasActiveSessions();
|
||||
return _bufferContext.isCompletedSuccessfully() && !_session.hasActiveSessions();
|
||||
}
|
||||
|
||||
BufferReaderError getError() const {
|
||||
auto res = std::distance(_end, _pos);
|
||||
if (res > 0) {
|
||||
auto err = static_cast<BufferReaderError>(res);
|
||||
if (_session.hasActiveSessions() && err == BufferReaderError::BUFFER_OVERFLOW)
|
||||
return BufferReaderError::NO_ERROR;
|
||||
return err;
|
||||
}
|
||||
return BufferReaderError::NO_ERROR;
|
||||
auto err = _bufferContext.getError();
|
||||
if (_session.hasActiveSessions() && err == BufferReaderError::BUFFER_OVERFLOW)
|
||||
return BufferReaderError::NO_ERROR;
|
||||
return err;
|
||||
}
|
||||
|
||||
void setError(BufferReaderError error) {
|
||||
_end = _pos;
|
||||
//to avoid creating temporary for error state, mark an error by passing _pos after the _end
|
||||
std::advance(_pos, static_cast<size_t>(error));
|
||||
return _bufferContext.setError(error);
|
||||
}
|
||||
|
||||
void beginSession() {
|
||||
@@ -149,35 +142,21 @@ namespace bitsery {
|
||||
}
|
||||
|
||||
private:
|
||||
ValueType* _pos;
|
||||
ValueType* _end;
|
||||
details::ReadBufferContext<BufferType> _bufferContext;
|
||||
ScratchType m_scratch{};
|
||||
size_t m_scratchBits{};
|
||||
typename std::conditional<Config::BufferSessionsEnabled,
|
||||
details::BufferSessionsReader<BasicBufferReader<Config>, ValueType*>,
|
||||
details::BufferSessionsReader<BasicBufferReader<Config>, details::ReadBufferContext<BufferType>>,
|
||||
details::DisabledBufferSessionsReader<Config>>::type
|
||||
_session;
|
||||
|
||||
template<typename T>
|
||||
void directRead(T *v, size_t count) {
|
||||
static_assert(!std::is_const<T>::value, "");
|
||||
const auto bytesCount = sizeof(T) * count;
|
||||
|
||||
if (std::distance(_pos, _end) >= static_cast<typename details::BufferContainerTraits<BufferType>::TDifference>(bytesCount)) {
|
||||
|
||||
std::memcpy(reinterpret_cast<ValueType *>(v), _pos, bytesCount);
|
||||
_pos += bytesCount;
|
||||
|
||||
//swap each byte if nessesarry
|
||||
_swapDataBits(v, count, std::integral_constant<bool,
|
||||
Config::NetworkEndianness != details::getSystemEndianness()>{});
|
||||
} else {
|
||||
//set everything to zeros
|
||||
std::memset(v, 0, bytesCount);
|
||||
|
||||
if (getError() == BufferReaderError::NO_ERROR)
|
||||
setError(BufferReaderError::BUFFER_OVERFLOW);
|
||||
}
|
||||
_bufferContext.read(reinterpret_cast<ValueType *>(v), sizeof(T) * count);
|
||||
//swap each byte if nessesarry
|
||||
_swapDataBits(v, count, std::integral_constant<bool,
|
||||
Config::NetworkEndianness != details::getSystemEndianness()>{});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -95,9 +95,9 @@ namespace bitsery {
|
||||
template<typename Config>
|
||||
struct BasicBufferWriter {
|
||||
using BufferType = typename Config::BufferType;
|
||||
using ValueType = typename details::BufferContainerTraits<BufferType>::TValue;
|
||||
using ValueType = typename details::ContainerTraits<BufferType>::TValue;
|
||||
using ScratchType = typename details::SCRATCH_TYPE<ValueType>::type;
|
||||
using BufferContext = details::WriteBufferContext<BufferType, details::BufferContainerTraits<BufferType>::isResizable>;
|
||||
using BufferContext = details::WriteBufferContext<BufferType, details::ContainerTraits<BufferType>::isResizable>;
|
||||
|
||||
explicit BasicBufferWriter(BufferType &buffer)
|
||||
: _bufferContext{buffer}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#define BITSERY_COMMON_H
|
||||
|
||||
#include <vector>
|
||||
#include "traits/vector.h"
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
|
||||
@@ -50,7 +50,8 @@ namespace bitsery {
|
||||
|
||||
template<typename T>
|
||||
void object(T &&obj) {
|
||||
details::SerializeFunction<BasicDeserializer, T>::invoke(*this, std::forward<T>(obj));
|
||||
using TValue = typename std::decay<T>::type;
|
||||
details::SerializeFunction<BasicDeserializer, TValue>::invoke(*this, std::forward<T>(obj));
|
||||
}
|
||||
|
||||
template<typename T, typename Fnc>
|
||||
@@ -58,25 +59,25 @@ namespace bitsery {
|
||||
fnc(std::forward<T>(obj));
|
||||
};
|
||||
|
||||
/*
|
||||
* functionality, that enables simpler serialization syntax, by including additional header
|
||||
*/
|
||||
template<typename T, typename ... TArgs>
|
||||
void archive(T &&head, TArgs &&... tail) {
|
||||
//serialize object
|
||||
details::ArchiveFunction<BasicDeserializer, T>::invoke(*this, std::forward<T>(head));
|
||||
//expand other elements
|
||||
archive(std::forward<TArgs>(tail)...);
|
||||
}
|
||||
|
||||
/*
|
||||
* value overloads
|
||||
*/
|
||||
|
||||
template<size_t VSIZE, typename T, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
|
||||
template<size_t VSIZE, typename T, typename std::enable_if<details::IsFundamentalType<T>::value>::type * = nullptr>
|
||||
void value(T &v) {
|
||||
static_assert(std::numeric_limits<T>::is_iec559, "");
|
||||
_reader.template readBytes<VSIZE>(reinterpret_cast<details::SAME_SIZE_UNSIGNED<T> &>(v));
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T, typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
|
||||
void value(T &v) {
|
||||
using UT = typename std::underlying_type<T>::type;
|
||||
_reader.template readBytes<VSIZE>(reinterpret_cast<UT &>(v));
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
|
||||
void value(T &v) {
|
||||
_reader.template readBytes<VSIZE>(v);
|
||||
using TValue = typename details::IntegralFromFundamental<T>::TValue;
|
||||
_reader.template readBytes<VSIZE>(reinterpret_cast<TValue &>(v));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -84,29 +85,26 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T, typename Ext, typename Fnc>
|
||||
void ext(T &obj, Ext &&extension, Fnc &&fnc) {
|
||||
using ExtType = typename std::decay<Ext>::type;
|
||||
static_assert(details::ExtensionTraits<ExtType,T>::SupportLambdaOverload,
|
||||
void ext(T &obj, const Ext &extension, Fnc &&fnc) {
|
||||
static_assert(details::ExtensionTraits<Ext,T>::SupportLambdaOverload,
|
||||
"extension doesn't support overload with lambda");
|
||||
extension.deserialize(*this, _reader, obj, std::forward<Fnc>(fnc));
|
||||
};
|
||||
|
||||
template<size_t VSIZE, typename T, typename Ext>
|
||||
void ext(T &obj, Ext &&extension) {
|
||||
using ExtType = typename std::decay<Ext>::type;
|
||||
static_assert(details::ExtensionTraits<ExtType,T>::SupportValueOverload,
|
||||
void ext(T &obj, const Ext &extension) {
|
||||
static_assert(details::ExtensionTraits<Ext,T>::SupportValueOverload,
|
||||
"extension doesn't support overload with `value<N>`");
|
||||
using ExtVType = typename details::ExtensionTraits<ExtType, T>::TValue;
|
||||
using ExtVType = typename details::ExtensionTraits<Ext, T>::TValue;
|
||||
using VType = typename std::conditional<std::is_void<ExtVType>::value, details::DummyType, ExtVType>::type;
|
||||
extension.deserialize(*this, _reader, obj, [this](VType &v) { value<VSIZE>(v); });
|
||||
};
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext(T &obj, Ext &&extension) {
|
||||
using ExtType = typename std::decay<Ext>::type;
|
||||
static_assert(details::ExtensionTraits<ExtType,T>::SupportObjectOverload,
|
||||
void ext(T &obj, const Ext &extension) {
|
||||
static_assert(details::ExtensionTraits<Ext,T>::SupportObjectOverload,
|
||||
"extension doesn't support overload with `object`");
|
||||
using ExtVType = typename details::ExtensionTraits<ExtType, T>::TValue;
|
||||
using ExtVType = typename details::ExtensionTraits<Ext, T>::TValue;
|
||||
using VType = typename std::conditional<std::is_void<ExtVType>::value, details::DummyType, ExtVType>::type;
|
||||
extension.deserialize(*this, _reader, obj, [this](VType &v) { object(v); });
|
||||
};
|
||||
@@ -135,42 +133,21 @@ namespace bitsery {
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void text(T &str, size_t maxSize) {
|
||||
static_assert(details::TextTraits<T>::isResizable,
|
||||
static_assert(details::ContainerTraits<T>::isResizable,
|
||||
"use text(T&) overload without `maxSize` for static containers");
|
||||
size_t size;
|
||||
details::readSize(_reader, size, maxSize);
|
||||
details::TextTraits<T>::resize(str, size);
|
||||
auto begin = std::begin(str);
|
||||
auto end = std::next(begin, size);
|
||||
procContainer<VSIZE>(begin, end, std::true_type{});
|
||||
//null terminated character at the end
|
||||
*end = {};
|
||||
size_t length;
|
||||
details::readSize(_reader, length, maxSize);
|
||||
details::ContainerTraits<T>::resize(str, length + (details::TextTraits<T>::addNUL ? 1u : 0u));
|
||||
procText<VSIZE>(str, length);
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void text(T &str) {
|
||||
static_assert(!details::TextTraits<T>::isResizable,
|
||||
static_assert(!details::ContainerTraits<T>::isResizable,
|
||||
"use text(T&, size_t) overload with `maxSize` for dynamic containers");
|
||||
size_t size;
|
||||
auto begin = std::begin(str);
|
||||
auto containerEnd = std::end(str);
|
||||
assert(begin != containerEnd);
|
||||
details::readSize(_reader, size, static_cast<size_t>(std::distance(begin, containerEnd) - 1));
|
||||
//end of string, not en
|
||||
auto end = std::next(begin, size);
|
||||
procContainer<VSIZE>(std::begin(str), std::end(str), std::true_type{});
|
||||
//null terminated character at the end
|
||||
*end = {};
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T, size_t N>
|
||||
void text(T (&str)[N]) {
|
||||
size_t size;
|
||||
details::readSize(_reader, size, N - 1);
|
||||
auto first = std::begin(str);
|
||||
procContainer<VSIZE>(first, std::next(first, size), std::true_type{});
|
||||
//null-terminated string
|
||||
str[size] = {};
|
||||
size_t length;
|
||||
details::readSize(_reader, length, details::ContainerTraits<T>::size(str));
|
||||
procText<VSIZE>(str, length);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -197,7 +174,7 @@ namespace bitsery {
|
||||
size_t size{};
|
||||
details::readSize(_reader, size, maxSize);
|
||||
details::ContainerTraits<T>::resize(obj, size);
|
||||
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::false_type{});
|
||||
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::integral_constant<bool, details::ContainerTraits<T>::isContiguous>{});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -223,7 +200,7 @@ namespace bitsery {
|
||||
static_assert(!details::ContainerTraits<T>::isResizable,
|
||||
"use container(T&, size_t) overload with `maxSize` for dynamic containers");
|
||||
static_assert(VSIZE > 0, "");
|
||||
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::false_type{});
|
||||
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::integral_constant<bool, details::ContainerTraits<T>::isContiguous>{});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -233,23 +210,6 @@ namespace bitsery {
|
||||
procContainer(std::begin(obj), std::end(obj));
|
||||
}
|
||||
|
||||
//c-style array overloads
|
||||
|
||||
template<typename T, size_t N, typename Fnc>
|
||||
void container(T (&arr)[N], Fnc &&fnc) {
|
||||
procContainer(std::begin(arr), std::end(arr), std::forward<Fnc>(fnc));
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T, size_t N>
|
||||
void container(T (&arr)[N]) {
|
||||
procContainer<VSIZE>(std::begin(arr), std::end(arr), std::true_type{});
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
void container(T (&arr)[N]) {
|
||||
procContainer(std::begin(arr), std::end(arr));
|
||||
}
|
||||
|
||||
void align() {
|
||||
_reader.align();
|
||||
}
|
||||
@@ -289,14 +249,14 @@ namespace bitsery {
|
||||
template<typename T>
|
||||
void text4b(T &str, size_t maxSize) { text<4>(str, maxSize); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void text1b(T (&str)[N]) { text<1>(str); }
|
||||
template<typename T>
|
||||
void text1b(T &str) { text<1>(str); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void text2b(T (&str)[N]) { text<2>(str); }
|
||||
template<typename T>
|
||||
void text2b(T &str) { text<2>(str); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void text4b(T (&str)[N]) { text<4>(str); }
|
||||
template<typename T>
|
||||
void text4b(T &str) { text<4>(str); }
|
||||
|
||||
template<typename T>
|
||||
void container1b(T &&obj, size_t maxSize) { container<1>(std::forward<T>(obj), maxSize); }
|
||||
@@ -322,19 +282,6 @@ namespace bitsery {
|
||||
template<typename T>
|
||||
void container8b(T &&obj) { container<8>(std::forward<T>(obj)); }
|
||||
|
||||
|
||||
template<typename T, size_t N>
|
||||
void container1b(T (&arr)[N]) { container<1>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void container2b(T (&arr)[N]) { container<2>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void container4b(T (&arr)[N]) { container<4>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void container8b(T (&arr)[N]) { container<8>(arr); }
|
||||
|
||||
private:
|
||||
BasicBufferReader<Config> &_reader;
|
||||
void* _context;
|
||||
@@ -351,8 +298,10 @@ 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) {
|
||||
using TValue = typename std::decay<decltype(*first)>::type;
|
||||
using TIntegral = typename details::IntegralFromFundamental<TValue>::TValue;
|
||||
if (first != last)
|
||||
_reader.template readBuffer<VSIZE>(&(*first), std::distance(first, last));
|
||||
_reader.template readBuffer<VSIZE>(reinterpret_cast<TIntegral*>(&(*first)), std::distance(first, last));
|
||||
};
|
||||
|
||||
//process by calling functions
|
||||
@@ -369,6 +318,17 @@ namespace bitsery {
|
||||
object(*first);
|
||||
};
|
||||
|
||||
template <size_t VSIZE, typename T>
|
||||
void procText(T& str, size_t length) {
|
||||
auto begin = std::begin(str);
|
||||
//end of string, not end of container
|
||||
auto end = std::next(begin, length);
|
||||
procContainer<VSIZE>(begin, end, std::integral_constant<bool, details::ContainerTraits<T>::isContiguous>{});
|
||||
//null terminated character at the end
|
||||
if (details::TextTraits<T>::addNUL)
|
||||
*end = {};
|
||||
}
|
||||
|
||||
//these are dummy functions for extensions that have TValue = void
|
||||
void object(details::DummyType&) {
|
||||
|
||||
@@ -379,6 +339,10 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
//dummy function, that stops archive variadic arguments expansion
|
||||
void archive() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//helper type
|
||||
|
||||
@@ -140,8 +140,8 @@ namespace bitsery {
|
||||
|
||||
template <typename Config>
|
||||
struct DisabledBufferSessionsReader {
|
||||
template <typename TReader, typename TIterator>
|
||||
DisabledBufferSessionsReader(TReader& , TIterator& , TIterator& ) {
|
||||
template <typename TReader, typename TBufferContext>
|
||||
DisabledBufferSessionsReader(TReader& , TBufferContext& ) {
|
||||
}
|
||||
|
||||
void begin() {
|
||||
@@ -208,38 +208,42 @@ namespace bitsery {
|
||||
std::stack<size_t> _sessionIndex;
|
||||
};
|
||||
|
||||
template <typename TReader, typename TIterator>
|
||||
template <typename TReader, typename TBufferContext>
|
||||
struct BufferSessionsReader {
|
||||
BufferSessionsReader(TReader& r, TIterator& begin, TIterator& end)
|
||||
using TIterator = typename TReader::BufferIteratorType;
|
||||
|
||||
BufferSessionsReader(TReader& r, TBufferContext& bufferContext)
|
||||
:_reader{r},
|
||||
_begin{begin},
|
||||
_pos{begin},
|
||||
_end{end}
|
||||
_begin{bufferContext._pos},
|
||||
_context{bufferContext}
|
||||
{
|
||||
}
|
||||
void begin() {
|
||||
if (_sessions.empty())
|
||||
initializeSessions();
|
||||
if (_sessions.empty()) {
|
||||
if (!initializeSessions())
|
||||
return;
|
||||
}
|
||||
|
||||
//save end position for current session
|
||||
_sessionsStack.push(_end);
|
||||
_sessionsStack.push(_context._end);
|
||||
if (_nextSessionIt != std::end(_sessions)) {
|
||||
if (std::distance(_pos, _end) > 0) {
|
||||
if (std::distance(_context._pos, _context._end) > 0) {
|
||||
//set end position for new session
|
||||
auto newEnd = std::next(_begin, *_nextSessionIt);
|
||||
if (std::distance(newEnd, _end) < 0)
|
||||
if (std::distance(newEnd, _context._end) < 0)
|
||||
{
|
||||
//new session cannot end further than current end
|
||||
_reader.setError(BufferReaderError::INVALID_BUFFER_DATA);
|
||||
return;
|
||||
}
|
||||
_end = newEnd;
|
||||
_context._end = newEnd;
|
||||
++_nextSessionIt;
|
||||
}
|
||||
//if we reached the end, means that there is no more data to read, hence there is no more sessions to advance to
|
||||
} else {
|
||||
//there is no data to read anymore
|
||||
//pos == end or buffer overflow while session is active
|
||||
if (!(_pos == _end || _reader.getError() == BufferReaderError::NO_ERROR)) {
|
||||
if (!(_context._pos == _context._end || _reader.getError() == BufferReaderError::NO_ERROR)) {
|
||||
_reader.setError(BufferReaderError::INVALID_BUFFER_DATA);
|
||||
}
|
||||
}
|
||||
@@ -252,18 +256,18 @@ namespace bitsery {
|
||||
//_pos == _end : same versions
|
||||
//distance(_pos,_end) > 0: reading newer version
|
||||
//getError() == BUFFER_OVERFLOW: reading older version
|
||||
auto dist = std::distance(_pos, _end);
|
||||
auto dist = std::distance(_context._pos, _context._end);
|
||||
if (dist > 0) {
|
||||
//newer version might have some inner sessions, try to find the one after current ends
|
||||
auto currPos = static_cast<size_t>(std::distance(_begin, _end));
|
||||
auto currPos = static_cast<size_t>(std::distance(_begin, _context._end));
|
||||
for (; _nextSessionIt != std::end(_sessions); ++_nextSessionIt) {
|
||||
if (*_nextSessionIt > currPos)
|
||||
break;
|
||||
}
|
||||
}
|
||||
_pos = _end;
|
||||
_context._pos = _context._end;
|
||||
//restore end position
|
||||
_end = _sessionsStack.top();
|
||||
_context._end = _sessionsStack.top();
|
||||
_sessionsStack.pop();
|
||||
}
|
||||
}
|
||||
@@ -275,23 +279,21 @@ namespace bitsery {
|
||||
private:
|
||||
TReader& _reader;
|
||||
TIterator _begin;
|
||||
TIterator& _pos;
|
||||
TIterator& _end;
|
||||
|
||||
TBufferContext& _context;
|
||||
std::vector<size_t> _sessions{};
|
||||
std::vector<size_t>::iterator _nextSessionIt{};
|
||||
std::stack<TIterator> _sessionsStack{};
|
||||
|
||||
void initializeSessions() {
|
||||
bool initializeSessions() {
|
||||
//save current position
|
||||
auto currPos = _pos;
|
||||
auto currPos = _context._pos;
|
||||
//read size
|
||||
if (std::distance(_pos, _end) < 2) {
|
||||
if (std::distance(_context._pos, _context._end) < 2) {
|
||||
_reader.setError(BufferReaderError::INVALID_BUFFER_DATA);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
auto endSessionsSizesIt = std::next(_end, -2);
|
||||
_pos = endSessionsSizesIt;
|
||||
auto endSessionsSizesIt = std::next(_context._end, -2);
|
||||
_context._pos = endSessionsSizesIt;
|
||||
size_t sessionsOffset{};
|
||||
uint16_t high;
|
||||
_reader.template readBytes<2>(high);
|
||||
@@ -299,10 +301,10 @@ namespace bitsery {
|
||||
|
||||
if (high >= 0x8000u) {
|
||||
endSessionsSizesIt = std::next(endSessionsSizesIt, -2);
|
||||
_pos = endSessionsSizesIt;
|
||||
if (std::distance(_begin, _pos) < 0) {
|
||||
_context._pos = endSessionsSizesIt;
|
||||
if (std::distance(_begin, _context._pos) < 0) {
|
||||
_reader.setError(BufferReaderError::INVALID_BUFFER_DATA);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
uint16_t low;
|
||||
_reader.template readBytes<2>(low);
|
||||
@@ -313,25 +315,26 @@ namespace bitsery {
|
||||
} else
|
||||
sessionsOffset = high;
|
||||
|
||||
auto bufferSize = std::distance(_begin, _end);
|
||||
auto bufferSize = std::distance(_begin, _context._end);
|
||||
if (static_cast<size_t>(bufferSize) < sessionsOffset) {
|
||||
_reader.setError(BufferReaderError::INVALID_BUFFER_DATA);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
//we can initialy resizes to this value, and we'll shrink it after reading
|
||||
//read session sizes
|
||||
auto sessionsIt = std::back_inserter(_sessions);
|
||||
_pos = std::next(_end, -sessionsOffset);
|
||||
while (std::distance(_pos, endSessionsSizesIt) > 0) {
|
||||
_context._pos = std::next(_context._end, -sessionsOffset);
|
||||
while (std::distance(_context._pos, endSessionsSizesIt) > 0) {
|
||||
size_t size;
|
||||
details::readSize(_reader, size, bufferSize);
|
||||
*sessionsIt++ = size;
|
||||
}
|
||||
_sessions.shrink_to_fit();
|
||||
//set iterators to data
|
||||
_pos = currPos;
|
||||
_end = std::next(_end, -sessionsOffset);
|
||||
_context._pos = currPos;
|
||||
_context._end = std::next(_context._end, -sessionsOffset);
|
||||
_nextSessionIt = std::begin(_sessions);//set before first session;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -344,77 +347,133 @@ namespace bitsery {
|
||||
template<typename Buffer>
|
||||
class WriteBufferContext<Buffer, false> {
|
||||
public:
|
||||
using TValue = typename BufferContainerTraits<Buffer>::TValue;
|
||||
using TValue = typename ContainerTraits<Buffer>::TValue;
|
||||
using TIterator = typename BufferContainerTraits<Buffer>::TIterator;
|
||||
using TDifference = typename BufferContainerTraits<Buffer>::TDifference;
|
||||
|
||||
|
||||
explicit WriteBufferContext(Buffer &buffer)
|
||||
: _buffer{buffer},
|
||||
_outIt{std::addressof(*std::begin(buffer))},
|
||||
_end{std::addressof(*std::end(buffer))}
|
||||
_outIt{std::begin(buffer)},
|
||||
_end{std::end(buffer)}
|
||||
{
|
||||
}
|
||||
|
||||
void write(const TValue *data, size_t size) {
|
||||
assert(std::distance(_outIt, _end) >= static_cast<TDifference>(size));
|
||||
memcpy(_outIt, data, size);
|
||||
auto tmp = _outIt;
|
||||
_outIt += size;
|
||||
assert(std::distance(_outIt, _end) >= 0);
|
||||
memcpy(std::addressof(*tmp), data, size);
|
||||
}
|
||||
|
||||
BufferRange<TIterator> getWrittenRange() const {
|
||||
auto begin = std::begin(_buffer);
|
||||
return BufferRange<TIterator>{begin, std::next(begin, _outIt - std::addressof(*begin))};
|
||||
return BufferRange<TIterator>{std::begin(_buffer), _outIt};
|
||||
}
|
||||
|
||||
private:
|
||||
Buffer &_buffer;
|
||||
TValue* _outIt;
|
||||
TValue* _end;
|
||||
TIterator _outIt;
|
||||
TIterator _end;
|
||||
};
|
||||
|
||||
template<typename Buffer>
|
||||
class WriteBufferContext<Buffer, true> {
|
||||
public:
|
||||
using TValue = typename BufferContainerTraits<Buffer>::TValue;
|
||||
using TValue = typename ContainerTraits<Buffer>::TValue;
|
||||
using TIterator = typename BufferContainerTraits<Buffer>::TIterator;
|
||||
using TDifference = typename BufferContainerTraits<Buffer>::TDifference;
|
||||
|
||||
explicit WriteBufferContext(Buffer &buffer)
|
||||
: _buffer{buffer}
|
||||
{
|
||||
//resize buffer immediately, because we need output iterator at valid position
|
||||
if (ContainerTraits<Buffer>::size(buffer) == 0u) {
|
||||
BufferContainerTraits<Buffer>::increaseBufferSize(_buffer);
|
||||
}
|
||||
getIterators(0);
|
||||
}
|
||||
|
||||
void write(const TValue *data, size_t size) {
|
||||
if ((_end - _outIt) >= static_cast< TDifference >(size)) {
|
||||
std::memcpy(_outIt, data, size);
|
||||
_outIt += size;
|
||||
auto tmp = _outIt;
|
||||
_outIt += size;
|
||||
if (std::distance(_outIt , _end) >= 0) {
|
||||
std::memcpy(std::addressof(*tmp), data, size);
|
||||
} else {
|
||||
_outIt -= size;
|
||||
//get current position before invalidating iterators
|
||||
auto pos = std::distance(std::addressof(*std::begin(_buffer)), _outIt);
|
||||
const auto pos = std::distance(std::begin(_buffer), _outIt);
|
||||
//increase container size
|
||||
BufferContainerTraits<Buffer>::increaseBufferSize(_buffer);
|
||||
//restore iterators
|
||||
getIterators(pos);
|
||||
getIterators(static_cast<size_t>(pos));
|
||||
write(data, size);
|
||||
}
|
||||
}
|
||||
|
||||
BufferRange<TIterator> getWrittenRange() const {
|
||||
auto begin = std::begin(_buffer);
|
||||
return BufferRange<TIterator>{begin, std::next(begin, _outIt - std::addressof(*begin))};
|
||||
return BufferRange<TIterator>{std::begin(_buffer), _outIt};
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void getIterators(TDifference writePos) {
|
||||
_end = std::addressof(*std::end(_buffer));
|
||||
_outIt = std::addressof(*std::next(std::begin(_buffer), writePos));
|
||||
void getIterators(size_t writePos) {
|
||||
_end = std::end(_buffer);
|
||||
_outIt = std::next(std::begin(_buffer), writePos);
|
||||
}
|
||||
Buffer &_buffer;
|
||||
TValue* _outIt;
|
||||
TValue* _end;
|
||||
TIterator _outIt;
|
||||
TIterator _end;
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <typename Buffer>
|
||||
class ReadBufferContext {
|
||||
public:
|
||||
using TValue = typename ContainerTraits<Buffer>::TValue;
|
||||
using TIterator = typename BufferContainerTraits<Buffer>::TIterator;
|
||||
|
||||
ReadBufferContext(TIterator begin, TIterator end)
|
||||
:_pos{begin},
|
||||
_end{end}
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void read(TValue* data, size_t size) {
|
||||
//for optimization
|
||||
auto tmp = _pos;
|
||||
_pos += size;
|
||||
if (std::distance(_pos, _end) >= 0) {
|
||||
std::memcpy(data, std::addressof(*tmp), size);
|
||||
} else {
|
||||
_pos -= size;
|
||||
//set everything to zeros
|
||||
std::memset(data, 0, size);
|
||||
|
||||
if (getError() == BufferReaderError::NO_ERROR)
|
||||
setError(BufferReaderError::BUFFER_OVERFLOW);
|
||||
}
|
||||
}
|
||||
|
||||
BufferReaderError getError() const {
|
||||
auto res = std::distance(_end, _pos);
|
||||
if (res > 0) {
|
||||
auto err = static_cast<BufferReaderError>(res);
|
||||
return err;
|
||||
}
|
||||
return BufferReaderError::NO_ERROR;
|
||||
}
|
||||
|
||||
void setError(BufferReaderError error) {
|
||||
_end = _pos;
|
||||
//to avoid creating temporary for error state, mark an error by passing _pos after the _end
|
||||
std::advance(_pos, static_cast<size_t>(error));
|
||||
}
|
||||
|
||||
bool isCompletedSuccessfully() const {
|
||||
return _pos == _end;
|
||||
}
|
||||
|
||||
TIterator _pos;
|
||||
TIterator _end;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
123
include/bitsery/details/flexible_common.h
Normal file
123
include/bitsery/details/flexible_common.h
Normal file
@@ -0,0 +1,123 @@
|
||||
//MIT License
|
||||
//
|
||||
//Copyright (c) 2017 Mindaugas Vinkelis
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
#ifndef BITSERY_DETAILS_FLEXIBLE_COMMON_H
|
||||
#define BITSERY_DETAILS_FLEXIBLE_COMMON_H
|
||||
|
||||
#include "traits.h"
|
||||
|
||||
namespace bitsery {
|
||||
namespace flexible {
|
||||
|
||||
//these function overloads is required to apply maxSize, and optimize for fundamental types
|
||||
//for contigous arrays of fundamenal types, memcpy will be applied
|
||||
|
||||
template<typename S, typename T, typename std::enable_if<
|
||||
details::IsFundamentalType<typename details::ContainerTraits<T>::TValue>::value
|
||||
&& details::ContainerTraits<T>::isResizable
|
||||
>::type * = nullptr>
|
||||
void processContainer(S &s, T &c, size_t maxSize = std::numeric_limits<size_t>::max()) {
|
||||
using TValue = typename details::ContainerTraits<T>::TValue;
|
||||
s.template container<sizeof(TValue)>(c, maxSize);
|
||||
}
|
||||
|
||||
template<typename S, typename T, typename std::enable_if<
|
||||
!details::IsFundamentalType<typename details::ContainerTraits<T>::TValue>::value
|
||||
&& details::ContainerTraits<T>::isResizable
|
||||
>::type * = nullptr>
|
||||
void processContainer(S &s, T &c, size_t maxSize = std::numeric_limits<size_t>::max()) {
|
||||
s.container(c, maxSize);
|
||||
}
|
||||
|
||||
template<typename S, typename T, typename std::enable_if<
|
||||
details::IsFundamentalType<typename details::ContainerTraits<T>::TValue>::value
|
||||
&& !details::ContainerTraits<T>::isResizable
|
||||
>::type * = nullptr>
|
||||
void processContainer(S &s, T &c) {
|
||||
using TValue = typename details::ContainerTraits<T>::TValue;
|
||||
s.template container<sizeof(TValue)>(c);
|
||||
}
|
||||
|
||||
template<typename S, typename T, typename std::enable_if<
|
||||
!details::IsFundamentalType<typename details::ContainerTraits<T>::TValue>::value
|
||||
&& !details::ContainerTraits<T>::isResizable
|
||||
>::type * = nullptr>
|
||||
void processContainer(S &s, T &c) {
|
||||
s.container(c);
|
||||
}
|
||||
|
||||
//overloads for text processing to apply maxSize
|
||||
|
||||
template<typename S, typename T, typename std::enable_if<
|
||||
details::ContainerTraits<T>::isResizable>::type * = nullptr>
|
||||
void processText(S &s, T &c, size_t maxSize = std::numeric_limits<size_t>::max()) {
|
||||
using TValue = typename details::ContainerTraits<T>::TValue;
|
||||
s.template text<sizeof(TValue)>(c, maxSize);
|
||||
}
|
||||
|
||||
template<typename S, typename T, typename std::enable_if<
|
||||
!details::ContainerTraits<T>::isResizable>::type * = nullptr>
|
||||
void processText(S &s, T &c) {
|
||||
using TValue = typename details::ContainerTraits<T>::TValue;
|
||||
s.template text<sizeof(TValue)>(c);
|
||||
}
|
||||
|
||||
|
||||
//all wrapper functions, that modify behaviour, should inherit from this
|
||||
struct ArchiveWrapperFnc {
|
||||
|
||||
};
|
||||
|
||||
//this type is used to differentiate between container and text behaviour
|
||||
template<typename T, size_t N, bool isText>
|
||||
struct CArray : public ArchiveWrapperFnc {
|
||||
CArray(T (&data_)[N]) : data{data_} {};
|
||||
T (&data)[N];
|
||||
};
|
||||
|
||||
template<typename S, typename T, size_t N>
|
||||
void serialize(S &s, CArray<T, N, true> &str) {
|
||||
processText(s, str.data);
|
||||
}
|
||||
|
||||
template<typename S, typename T, size_t N>
|
||||
void serialize(S &s, CArray<T, N, false> &obj) {
|
||||
processContainer(s, obj.data);
|
||||
}
|
||||
|
||||
//used to set max container size
|
||||
template<typename T>
|
||||
struct MaxSize : public ArchiveWrapperFnc {
|
||||
MaxSize(T &data_, size_t maxSize_) : data{data_}, maxSize{maxSize_} {};
|
||||
T &data;
|
||||
size_t maxSize;
|
||||
};
|
||||
|
||||
template<typename S, typename T>
|
||||
void serialize(S &s, const MaxSize<T> &ms) {
|
||||
processContainer(s, ms.data, ms.maxSize);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif //BITSERY_DETAILS_FLEXIBLE_COMMON_H
|
||||
@@ -28,25 +28,54 @@
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
//this allows to call private serialize method for the class
|
||||
//just make friend it to that class
|
||||
struct Access {
|
||||
template<typename S, typename T>
|
||||
static auto serialize(S &s, T &obj) -> decltype(obj.serialize(s)) {
|
||||
obj.serialize(s);
|
||||
}
|
||||
};
|
||||
|
||||
namespace details {
|
||||
|
||||
template<typename T, typename Enable = void>
|
||||
struct SAME_SIZE_UNSIGNED_TYPE {
|
||||
using type = typename std::make_unsigned<T>::type;
|
||||
//used for extensions, when extension TValue = void
|
||||
struct DummyType {
|
||||
};
|
||||
|
||||
/*
|
||||
* this includes all integral types floats and enums(except bool)
|
||||
*/
|
||||
template<typename T>
|
||||
struct IsFundamentalType : std::integral_constant<bool,
|
||||
std::is_enum<T>::value
|
||||
|| std::is_floating_point<T>::value
|
||||
|| std::is_integral<T>::value> {
|
||||
};
|
||||
|
||||
template<typename T, typename Integral = void>
|
||||
struct IntegralFromFundamental {
|
||||
using TValue = T;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SAME_SIZE_UNSIGNED_TYPE<T, typename std::enable_if<std::is_enum<T>::value>::type> {
|
||||
using type = typename std::make_unsigned<typename std::underlying_type<T>::type>::type;
|
||||
struct IntegralFromFundamental<T, typename std::enable_if<std::is_enum<T>::value>::type> {
|
||||
using TValue = typename std::underlying_type<T>::type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct SAME_SIZE_UNSIGNED_TYPE<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
|
||||
using type = typename std::conditional<std::is_same<T, float>::value, uint32_t, uint64_t>::type;
|
||||
struct IntegralFromFundamental<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
|
||||
using TValue = typename std::conditional<std::is_same<T, float>::value, uint32_t, uint64_t>::type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using SAME_SIZE_UNSIGNED = typename SAME_SIZE_UNSIGNED_TYPE<T>::type;
|
||||
struct UnsignedFromFundamental {
|
||||
using type = typename std::make_unsigned<typename IntegralFromFundamental<T>::TValue>::type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using SAME_SIZE_UNSIGNED = typename UnsignedFromFundamental<T>::type;
|
||||
|
||||
|
||||
/*
|
||||
* functions for object serialization
|
||||
@@ -54,28 +83,62 @@ namespace bitsery {
|
||||
|
||||
template<typename S, typename T, typename Enabled = void>
|
||||
struct SerializeFunction {
|
||||
|
||||
static void invoke(S &s, T &v) {
|
||||
static_assert(!std::is_void<Enabled>::value,
|
||||
"\nPlease define 'serialize' function for your type:\n"
|
||||
"\nPlease define 'serialize' function for your type (inside or outside of class):\n"
|
||||
" template<typename S>\n"
|
||||
" void serialize(S& s, <YourType>& o)\n"
|
||||
" void serialize(S& s)\n"
|
||||
" {\n"
|
||||
" ...\n"
|
||||
" }\n");
|
||||
}
|
||||
};
|
||||
|
||||
//check for serialize(s,o) support
|
||||
template<typename S, typename T>
|
||||
struct SerializeFunction<S, T, typename std::enable_if<
|
||||
std::is_same<void, decltype(serialize(std::declval<S &>(), std::declval<T &>()))>::value
|
||||
std::is_same<void, decltype((void) serialize(std::declval<S &>(), std::declval<T &>()))>::value
|
||||
>::type> {
|
||||
|
||||
static void invoke(S &s, T &v) {
|
||||
serialize(s, v);
|
||||
}
|
||||
};
|
||||
|
||||
//used for extensions, when extension TValue = void
|
||||
struct DummyType {
|
||||
//check for o.serialize(s) support through static class Access
|
||||
template<typename S, typename T>
|
||||
struct SerializeFunction<S, T, typename std::enable_if<
|
||||
std::is_same<void, decltype(Access::serialize(std::declval<S &>(), std::declval<T &>()))>::value
|
||||
>::type> {
|
||||
|
||||
static void invoke(S &s, T &v) {
|
||||
Access::serialize(s, v);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* functions for object serialization
|
||||
*/
|
||||
|
||||
template<typename S, typename T, typename Enabled = void>
|
||||
struct ArchiveFunction {
|
||||
|
||||
static void invoke(S &s, T &v) {
|
||||
static_assert(!std::is_void<Enabled>::value,
|
||||
"\nPlease include 'flexible.h' to use 'archive' function:\n");
|
||||
}
|
||||
};
|
||||
|
||||
template<typename S, typename T>
|
||||
struct ArchiveFunction<S, T, typename std::enable_if<
|
||||
std::is_same<void, decltype((void)archiveProcess(std::declval<S &>(), std::declval<T &&>()))>::value
|
||||
>::type> {
|
||||
|
||||
static void invoke(S &s, T &&obj) {
|
||||
archiveProcess(s, std::forward<T>(obj));
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -24,20 +24,10 @@
|
||||
#define BITSERY_DETAILS_TRAITS_H
|
||||
|
||||
#include <type_traits>
|
||||
#include <string>
|
||||
|
||||
namespace bitsery {
|
||||
namespace details {
|
||||
|
||||
/*
|
||||
* helper traits that is used internaly, or by other traits
|
||||
*/
|
||||
template <typename T, typename = int>
|
||||
struct IsResizable : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct IsResizable <T, decltype((void)std::declval<T>().resize(1u), 0)> : std::true_type {};
|
||||
|
||||
/*
|
||||
* core library traits, used to extend library for custom types
|
||||
*/
|
||||
@@ -63,100 +53,88 @@ namespace bitsery {
|
||||
template<typename T>
|
||||
struct ContainerTraits {
|
||||
|
||||
using TValue = typename T::value_type;
|
||||
|
||||
//default behaviour is resizable if container has method T::resize(size_t)
|
||||
static constexpr bool isResizable = IsResizable<T>::value;
|
||||
using TValue = void;
|
||||
|
||||
static constexpr bool isResizable = false;
|
||||
//contiguous arrays has oppurtunity to memcpy whole buffer directly when using funtamental types
|
||||
//contiguous doesn't nesessary equal to random access iterator.
|
||||
//contiguous hopefully will be available in c++20
|
||||
static constexpr bool isContiguous = false;
|
||||
//resize function, called only if container is resizable
|
||||
static void resize(T& container, size_t size) {
|
||||
container.resize(size);
|
||||
static_assert(std::is_void<T>::value,
|
||||
"Define ContainerTraits or include from <bitsery/traits/...> to use as container");
|
||||
}
|
||||
|
||||
//get container size
|
||||
static size_t size(const T& container) {
|
||||
return container.size();
|
||||
static_assert(std::is_void<T>::value,
|
||||
"Define ContainerTraits or include from <bitsery/traits/...> to use as container");
|
||||
return 0u;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//specialization for C style array
|
||||
template<typename T, size_t N>
|
||||
struct ContainerTraits<T[N]> {
|
||||
using TValue = T;
|
||||
static constexpr bool isResizable = IsResizable<T>::value;
|
||||
static void resize(T (&container)[N], size_t size) {
|
||||
}
|
||||
static constexpr bool isResizable = false;
|
||||
static constexpr bool isContiguous = true;
|
||||
static size_t size(const T (&container)[N]) {
|
||||
return N;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//traits for text
|
||||
//specialization for initializer list, even though it cannot be deserialized to.
|
||||
template<typename T>
|
||||
struct TextTraits {
|
||||
|
||||
static constexpr bool isResizable = true;
|
||||
|
||||
//resize is without null-terminated character as with std::string,
|
||||
//but null terminated character will always be written
|
||||
//if you container doesn't add null-terminated character automaticaly, resize it to size+1;
|
||||
static void resize(T& container, size_t size) {
|
||||
container.resize(size);
|
||||
}
|
||||
|
||||
//used for serialization to get text length
|
||||
//length is until null-terminated character, size and length might not be equal
|
||||
static size_t length(const T& container) {
|
||||
auto begin = std::begin(container);
|
||||
using TValue = typename std::decay<decltype(*begin)>::type;
|
||||
return std::char_traits<TValue>::length(std::addressof(*begin));
|
||||
}
|
||||
};
|
||||
|
||||
//text traits specialization for std::string
|
||||
//for std::string return length as size(), for faster performance, so we don't need to traverse string to find null-terminated characeter
|
||||
//although it is not correct behaviour, meaning that string might have null-terminated characters in the middle,
|
||||
//but in this case it your decision if you store buffer in string and serialize it as a text.
|
||||
template<typename ... Args>
|
||||
struct TextTraits<std::basic_string<Args...>> {
|
||||
|
||||
static constexpr bool isResizable = true;
|
||||
|
||||
//resize is without null-terminated character as with std::string,
|
||||
//but null terminated character will always be written
|
||||
//if you container doesn't add null-terminated character automaticaly, resize it to size+1;
|
||||
static void resize(std::basic_string<Args...>& container, size_t size) {
|
||||
container.resize(size);
|
||||
}
|
||||
|
||||
//used for serialization to get text length
|
||||
//length is until null-terminated character, size and length might not be equal
|
||||
static size_t length(const std::basic_string<Args...>& container) {
|
||||
struct ContainerTraits<std::initializer_list<T>> {
|
||||
using TValue = T;
|
||||
static constexpr bool isResizable = false;
|
||||
static constexpr bool isContiguous = true;
|
||||
static size_t size(const std::initializer_list<T>& container) {
|
||||
return container.size();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//traits for text, default adds null-terminated character at the end
|
||||
template<typename T>
|
||||
struct TextTraits {
|
||||
|
||||
//if container is not null-terminated by default, add NUL at the end
|
||||
static constexpr bool addNUL = true;
|
||||
|
||||
//get length of null terminated container
|
||||
static size_t length(const T& container) {
|
||||
static_assert(std::is_void<T>::value,
|
||||
"Define TextTraits or include from <bitsery/traits/...> to use as text");
|
||||
return 0u;
|
||||
}
|
||||
};
|
||||
|
||||
//traits only for buffer reader/writer
|
||||
template <typename T>
|
||||
struct BufferContainerTraits: public ContainerTraits<T> {
|
||||
struct BufferContainerTraits {
|
||||
//this function is only applies to resizable containers
|
||||
|
||||
//this function is only used by BufferWriter, when writing data to buffer,
|
||||
//it is called only current buffer size is not enough to write.
|
||||
//it is used to dramaticaly improve performance by updating buffer directly
|
||||
//instead of using back_insert_iterator to append each byte to buffer.
|
||||
//thats why BufferWriter return range iterators
|
||||
|
||||
static void increaseBufferSize(T& container) {
|
||||
//use default implementation behaviour;
|
||||
//call push_back to use default resize strategy
|
||||
container.push_back({});
|
||||
//after allocation resize to take all capacity
|
||||
container.resize(container.capacity());
|
||||
static_assert(std::is_void<T>::value,
|
||||
"Define BufferContainerTraits or include from <bitsery/traits/...> to use as buffer");
|
||||
}
|
||||
|
||||
using TDifference = typename T::difference_type;
|
||||
using TIterator = typename T::iterator;
|
||||
using TIterator = void;
|
||||
};
|
||||
|
||||
//specialization for c-style buffer
|
||||
template <typename T, size_t N>
|
||||
struct BufferContainerTraits<T[N]> {
|
||||
using TIterator = T*;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
100
include/bitsery/flexible.h
Normal file
100
include/bitsery/flexible.h
Normal file
@@ -0,0 +1,100 @@
|
||||
//MIT License
|
||||
//
|
||||
//Copyright (c) 2017 Mindaugas Vinkelis
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
|
||||
#ifndef BITSERY_FLEXIBLE_H
|
||||
#define BITSERY_FLEXIBLE_H
|
||||
|
||||
#include "details/serialization_common.h"
|
||||
#include "bitsery/details/flexible_common.h"
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
namespace flexible {
|
||||
|
||||
//overload when T is reference type
|
||||
template<typename S, typename T>
|
||||
void archiveProcessImpl(S &s, T &&head, std::true_type) {
|
||||
s.object(std::forward<T>(head));
|
||||
};
|
||||
|
||||
//overload when T is rvalue type, only allowable for behaviour modifying functions for deserializer
|
||||
template<typename S, typename T>
|
||||
void archiveProcessImpl(S &s, T &&head, std::false_type) {
|
||||
static_assert(std::is_base_of<ArchiveWrapperFnc, T>::value,
|
||||
"\nOnly archive behaviour modifying functions can be passed by rvalue to deserializer\n");
|
||||
serialize(s, head);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
//define function that enables s.archive(....) usage
|
||||
template<typename S, typename T>
|
||||
void archiveProcess(S &s, T &&head) {
|
||||
flexible::archiveProcessImpl(s, std::forward<T>(head), std::is_reference<T>{});
|
||||
}
|
||||
|
||||
//wrapper functions that enables to serialize as container or string
|
||||
template<typename T, size_t N>
|
||||
flexible::CArray<T, N, true> asText(T (&str)[N]) {
|
||||
return {str};
|
||||
};
|
||||
|
||||
template<typename T, size_t N>
|
||||
flexible::CArray<T, N, false> asContainer(T (&obj)[N]) {
|
||||
return {obj};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
flexible::MaxSize<T> maxSize(T& obj, size_t max) {
|
||||
return {obj, max};
|
||||
}
|
||||
|
||||
|
||||
//define serialize function for fundamental types
|
||||
template<typename S>
|
||||
void serialize(S &s, bool &v) {
|
||||
s.boolByte(v);
|
||||
}
|
||||
|
||||
template<typename S, typename T, typename std::enable_if<details::IsFundamentalType<T>::value>::type * = nullptr>
|
||||
void serialize(S &s, T &v) {
|
||||
s.template value<sizeof(T)>(v);
|
||||
};
|
||||
|
||||
//define serialization for c-style container
|
||||
|
||||
//if array is integral type, specify explicitly how to process: as text or container
|
||||
template<typename S, typename T, size_t N, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
|
||||
void serialize(S &s, T (&v)[N]) {
|
||||
static_assert(N == 0,
|
||||
"\nPlease use 'asText(obj)' or 'asContainer(obj)' when using c-style array with integral types\n");
|
||||
};
|
||||
|
||||
template<typename S, typename T, size_t N, typename std::enable_if<!std::is_integral<T>::value>::type * = nullptr>
|
||||
void serialize(S &s, T (&obj)[N]) {
|
||||
s.container(obj);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //BITSERY_FLEXIBLE_H
|
||||
37
include/bitsery/flexible/array.h
Normal file
37
include/bitsery/flexible/array.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//MIT License
|
||||
//
|
||||
//Copyright (c) 2017 Mindaugas Vinkelis
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
|
||||
#ifndef BITSERY_FLEXIBLE_TYPE_ARRAY_H
|
||||
#define BITSERY_FLEXIBLE_TYPE_ARRAY_H
|
||||
|
||||
#include "../traits/array.h"
|
||||
#include "../details/flexible_common.h"
|
||||
|
||||
namespace bitsery {
|
||||
template<typename S, typename T, size_t N>
|
||||
void serialize(S &s, std::array<T, N> &obj) {
|
||||
flexible::processContainer(s, obj);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //BITSERY_FLEXIBLE_TYPE_ARRAY_H
|
||||
37
include/bitsery/flexible/list.h
Normal file
37
include/bitsery/flexible/list.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//MIT License
|
||||
//
|
||||
//Copyright (c) 2017 Mindaugas Vinkelis
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
|
||||
#ifndef BITSERY_FLEXIBLE_TYPE_LIST_H
|
||||
#define BITSERY_FLEXIBLE_TYPE_LIST_H
|
||||
|
||||
#include "../traits/list.h"
|
||||
#include "../details/flexible_common.h"
|
||||
|
||||
namespace bitsery {
|
||||
template<typename S, typename ... TArgs>
|
||||
void serialize(S &s, std::list<TArgs... > &obj) {
|
||||
flexible::processContainer(s, obj);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //BITSERY_FLEXIBLE_TYPE_LIST_H
|
||||
43
include/bitsery/flexible/map.h
Normal file
43
include/bitsery/flexible/map.h
Normal file
@@ -0,0 +1,43 @@
|
||||
//MIT License
|
||||
//
|
||||
//Copyright (c) 2017 Mindaugas Vinkelis
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
|
||||
#ifndef BITSERY_FLEXIBLE_TYPE_MAP_H
|
||||
#define BITSERY_FLEXIBLE_TYPE_MAP_H
|
||||
|
||||
#include <map>
|
||||
#include "../ext/container_map.h"
|
||||
|
||||
namespace bitsery {
|
||||
template<typename S, typename ... TArgs>
|
||||
void serialize(S &s, std::map<TArgs ... > &obj) {
|
||||
using TKey = typename std::map<TArgs...>::key_type;
|
||||
using TValue = typename std::map<TArgs...>::mapped_type;
|
||||
s.ext(obj, ext::ContainerMap{std::numeric_limits<size_t>::max()},
|
||||
[&s](TKey& key, TValue& value) {
|
||||
s.object(key);
|
||||
s.object(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#endif //BITSERY_FLEXIBLE_TYPE_MAP_H
|
||||
37
include/bitsery/flexible/string.h
Normal file
37
include/bitsery/flexible/string.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//MIT License
|
||||
//
|
||||
//Copyright (c) 2017 Mindaugas Vinkelis
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
|
||||
#ifndef BITSERY_FLEXIBLE_TYPE_STRING_H
|
||||
#define BITSERY_FLEXIBLE_TYPE_STRING_H
|
||||
|
||||
#include "../traits/string.h"
|
||||
#include "../details/flexible_common.h"
|
||||
|
||||
namespace bitsery {
|
||||
template<typename S, typename T, typename ... TArgs>
|
||||
void serialize(S &s, std::basic_string<T, TArgs...> &str) {
|
||||
flexible::processContainer(s, str);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //BITSERY_FLEXIBLE_TYPE_STRING_H
|
||||
43
include/bitsery/flexible/unordered_map.h
Normal file
43
include/bitsery/flexible/unordered_map.h
Normal file
@@ -0,0 +1,43 @@
|
||||
//MIT License
|
||||
//
|
||||
//Copyright (c) 2017 Mindaugas Vinkelis
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
|
||||
#ifndef BITSERY_FLEXIBLE_TYPE_UNORDERED_MAP_H
|
||||
#define BITSERY_FLEXIBLE_TYPE_UNORDERED_MAP_H
|
||||
|
||||
#include <unordered_map>
|
||||
#include "../ext/container_map.h"
|
||||
|
||||
namespace bitsery {
|
||||
template<typename S, typename ... TArgs>
|
||||
void serialize(S &s, std::unordered_map<TArgs ... > &obj) {
|
||||
using TKey = typename std::unordered_map<TArgs...>::key_type;
|
||||
using TValue = typename std::unordered_map<TArgs...>::mapped_type;
|
||||
s.ext(obj, ext::ContainerMap{std::numeric_limits<size_t>::max()},
|
||||
[&s](TKey& key, TValue& value) {
|
||||
s.object(key);
|
||||
s.object(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#endif //BITSERY_FLEXIBLE_TYPE_UNORDERED_MAP_H
|
||||
37
include/bitsery/flexible/vector.h
Normal file
37
include/bitsery/flexible/vector.h
Normal file
@@ -0,0 +1,37 @@
|
||||
//MIT License
|
||||
//
|
||||
//Copyright (c) 2017 Mindaugas Vinkelis
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
|
||||
#ifndef BITSERY_FLEXIBLE_TYPE_VECTOR_H
|
||||
#define BITSERY_FLEXIBLE_TYPE_VECTOR_H
|
||||
|
||||
#include "../traits/vector.h"
|
||||
#include "../details/flexible_common.h"
|
||||
|
||||
namespace bitsery {
|
||||
template<typename S, typename ... TArgs>
|
||||
void serialize(S &s, std::vector<TArgs... > &obj) {
|
||||
flexible::processContainer(s, obj);
|
||||
}
|
||||
}
|
||||
|
||||
#endif //BITSERY_FLEXIBLE_TYPE_VECTOR_H
|
||||
@@ -30,9 +30,6 @@
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename Config>
|
||||
class BasicSerializer {
|
||||
public:
|
||||
@@ -59,24 +56,25 @@ namespace bitsery {
|
||||
fnc(const_cast<T& >(obj));
|
||||
};
|
||||
|
||||
/*
|
||||
* functionality, that enables simpler serialization syntax, by including additional header
|
||||
*/
|
||||
template<typename T, typename ... TArgs>
|
||||
void archive(T &&head, TArgs &&... tail) {
|
||||
//serialize object
|
||||
details::ArchiveFunction<BasicSerializer, T>::invoke(*this, std::forward<T>(head));
|
||||
//expand other elements
|
||||
archive(std::forward<TArgs>(tail)...);
|
||||
}
|
||||
|
||||
/*
|
||||
* value overloads
|
||||
*/
|
||||
|
||||
template<size_t VSIZE, typename T, typename std::enable_if<std::is_floating_point<T>::value>::type * = nullptr>
|
||||
template<size_t VSIZE, typename T, typename std::enable_if<details::IsFundamentalType<T>::value>::type * = nullptr>
|
||||
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));
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T, typename std::enable_if<std::is_enum<T>::value>::type * = nullptr>
|
||||
void value(const T &v) {
|
||||
_writter.template writeBytes<VSIZE>(reinterpret_cast<const typename std::underlying_type<T>::type &>(v));
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T, typename std::enable_if<std::is_integral<T>::value>::type * = nullptr>
|
||||
void value(const T &v) {
|
||||
_writter.template writeBytes<VSIZE>(v);
|
||||
using TValue = typename details::IntegralFromFundamental<T>::TValue;
|
||||
_writter.template writeBytes<VSIZE>(reinterpret_cast<const TValue &>(v));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -84,29 +82,26 @@ namespace bitsery {
|
||||
*/
|
||||
|
||||
template<typename T, typename Ext, typename Fnc>
|
||||
void ext(const T &obj, Ext &&extension, Fnc &&fnc) {
|
||||
using ExtType = typename std::decay<Ext>::type;
|
||||
static_assert(details::ExtensionTraits<ExtType,T>::SupportLambdaOverload,
|
||||
void ext(const T &obj, const Ext &extension, Fnc &&fnc) {
|
||||
static_assert(details::ExtensionTraits<Ext,T>::SupportLambdaOverload,
|
||||
"extension doesn't support overload with lambda");
|
||||
extension.serialize(*this, _writter, obj, std::forward<Fnc>(fnc));
|
||||
};
|
||||
|
||||
template<size_t VSIZE, typename T, typename Ext>
|
||||
void ext(const T &obj, Ext &&extension) {
|
||||
using ExtType = typename std::decay<Ext>::type;
|
||||
static_assert(details::ExtensionTraits<ExtType,T>::SupportValueOverload,
|
||||
void ext(const T &obj, const Ext &extension) {
|
||||
static_assert(details::ExtensionTraits<Ext,T>::SupportValueOverload,
|
||||
"extension doesn't support overload with `value<N>`");
|
||||
using ExtVType = typename details::ExtensionTraits<ExtType, T>::TValue;
|
||||
using ExtVType = typename details::ExtensionTraits<Ext, T>::TValue;
|
||||
using VType = typename std::conditional<std::is_void<ExtVType>::value, details::DummyType, ExtVType>::type;
|
||||
extension.serialize(*this, _writter, obj, [this](VType &v) { value<VSIZE>(v); });
|
||||
};
|
||||
|
||||
template<typename T, typename Ext>
|
||||
void ext(const T &obj, Ext &&extension) {
|
||||
using ExtType = typename std::decay<Ext>::type;
|
||||
static_assert(details::ExtensionTraits<ExtType,T>::SupportObjectOverload,
|
||||
void ext(const T &obj, const Ext &extension) {
|
||||
static_assert(details::ExtensionTraits<Ext,T>::SupportObjectOverload,
|
||||
"extension doesn't support overload with `object`");
|
||||
using ExtVType = typename details::ExtensionTraits<ExtType, T>::TValue;
|
||||
using ExtVType = typename details::ExtensionTraits<Ext, T>::TValue;
|
||||
using VType = typename std::conditional<std::is_void<ExtVType>::value, details::DummyType, ExtVType>::type;
|
||||
extension.serialize(*this, _writter, obj, [this](VType &v) { object(v); });
|
||||
};
|
||||
@@ -129,37 +124,16 @@ namespace bitsery {
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void text(const T &str, size_t maxSize) {
|
||||
static_assert(details::TextTraits<T>::isResizable,
|
||||
static_assert(details::ContainerTraits<T>::isResizable,
|
||||
"use text(const T&) overload without `maxSize` for static container");
|
||||
auto size = details::TextTraits<T>::length(str);
|
||||
//size can be equal to maxSize
|
||||
assert(size <= maxSize);
|
||||
details::writeSize(_writter, size);
|
||||
auto begin = std::begin(str);
|
||||
procContainer<VSIZE>(begin, std::next(begin, size), std::true_type{});
|
||||
procText<VSIZE>(str, maxSize);
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T>
|
||||
void text(const T &str) {
|
||||
static_assert(!details::TextTraits<T>::isResizable,
|
||||
static_assert(!details::ContainerTraits<T>::isResizable,
|
||||
"use text(const T&, size_t) overload with `maxSize` for dynamic containers");
|
||||
auto size = details::TextTraits<T>::length(str);
|
||||
auto begin = std::begin(str);
|
||||
auto end = std::end(str);
|
||||
//size must be less than container capacity, because we need to store null-terminated character
|
||||
assert(size < std::distance(begin, end));
|
||||
details::writeSize(_writter, size);
|
||||
|
||||
procContainer<VSIZE>(begin, std::next(begin, size), std::true_type{});
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T, size_t N>
|
||||
void text(const T (&str)[N]) {
|
||||
auto size = details::TextTraits<T[N]>::length(str);
|
||||
assert(size < N);
|
||||
details::writeSize(_writter, size);
|
||||
auto begin = std::begin(str);
|
||||
procContainer<VSIZE>(begin, std::next(begin, size), std::true_type{});
|
||||
procText<VSIZE>(str, details::ContainerTraits<T>::size(str));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -187,8 +161,8 @@ namespace bitsery {
|
||||
auto size = details::ContainerTraits<T>::size(obj);
|
||||
assert(size <= maxSize);
|
||||
details::writeSize(_writter, 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{});
|
||||
|
||||
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::integral_constant<bool, details::ContainerTraits<T>::isContiguous>{});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -215,8 +189,7 @@ namespace bitsery {
|
||||
static_assert(!details::ContainerTraits<T>::isResizable,
|
||||
"use container(const T&, size_t) overload with `maxSize` for dynamic containers");
|
||||
static_assert(VSIZE > 0, "");
|
||||
//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{});
|
||||
procContainer<VSIZE>(std::begin(obj), std::end(obj), std::integral_constant<bool, details::ContainerTraits<T>::isContiguous>{});
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -226,24 +199,6 @@ namespace bitsery {
|
||||
procContainer(std::begin(obj), std::end(obj));
|
||||
}
|
||||
|
||||
//c-style array overloads
|
||||
|
||||
template<typename T, size_t N, typename Fnc>
|
||||
void container(const T (&arr)[N], Fnc &&fnc) {
|
||||
procContainer(std::begin(arr), std::end(arr), std::forward<Fnc>(fnc));
|
||||
}
|
||||
|
||||
template<size_t VSIZE, typename T, size_t N>
|
||||
void container(const T (&arr)[N]) {
|
||||
static_assert(VSIZE > 0, "");
|
||||
procContainer<VSIZE>(std::begin(arr), std::end(arr), std::true_type{});
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
void container(const T (&arr)[N]) {
|
||||
procContainer(std::begin(arr), std::end(arr));
|
||||
}
|
||||
|
||||
void align() {
|
||||
_writter.align();
|
||||
}
|
||||
@@ -283,14 +238,14 @@ namespace bitsery {
|
||||
template<typename T>
|
||||
void text4b(const T &str, size_t maxSize) { text<4>(str, maxSize); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void text1b(const T (&str)[N]) { text<1, T, N>(str); }
|
||||
template<typename T>
|
||||
void text1b(const T &str) { text<1>(str); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void text2b(const T (&str)[N]) { text<2, T, N>(str); }
|
||||
template<typename T>
|
||||
void text2b(const T &str) { text<2>(str); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void text4b(const T (&str)[N]) { text<4, T, N>(str); }
|
||||
template<typename T>
|
||||
void text4b(const T &str) { text<4>(str); }
|
||||
|
||||
template<typename T>
|
||||
void container1b(T &&obj, size_t maxSize) { container<1>(std::forward<T>(obj), maxSize); }
|
||||
@@ -316,18 +271,6 @@ namespace bitsery {
|
||||
template<typename T>
|
||||
void container8b(T &&obj) { container<8>(std::forward<T>(obj)); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void container1b(const T (&arr)[N]) { container<1>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void container2b(const T (&arr)[N]) { container<2>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void container4b(const T (&arr)[N]) { container<4>(arr); }
|
||||
|
||||
template<typename T, size_t N>
|
||||
void container8b(const T (&arr)[N]) { container<8>(arr); }
|
||||
|
||||
private:
|
||||
BasicBufferWriter<Config> &_writter;
|
||||
void* _context;
|
||||
@@ -344,7 +287,10 @@ 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) {
|
||||
_writter.template writeBuffer<VSIZE>(&(*first), std::distance(first, last));
|
||||
using TValue = typename std::decay<decltype(*first)>::type;
|
||||
using TIntegral = typename details::IntegralFromFundamental<TValue>::TValue;
|
||||
if (first != last)
|
||||
_writter.template writeBuffer<VSIZE>(reinterpret_cast<const TIntegral*>(&(*first)), std::distance(first, last));
|
||||
};
|
||||
|
||||
//process by calling functions
|
||||
@@ -356,6 +302,16 @@ namespace bitsery {
|
||||
}
|
||||
};
|
||||
|
||||
//process text,
|
||||
template<size_t VSIZE, typename T>
|
||||
void procText(const T& str, size_t maxSize) {
|
||||
auto length = details::TextTraits<T>::length(str);
|
||||
assert((length + (details::TextTraits<T>::addNUL ? 1u : 0u)) <= maxSize);
|
||||
details::writeSize(_writter, length);
|
||||
auto begin = std::begin(str);
|
||||
procContainer<VSIZE>(begin, std::next(begin, length), std::integral_constant<bool, details::ContainerTraits<T>::isContiguous>{});
|
||||
};
|
||||
|
||||
//process object types
|
||||
template<typename It>
|
||||
void procContainer(It first, It last) {
|
||||
@@ -373,6 +329,10 @@ namespace bitsery {
|
||||
|
||||
}
|
||||
|
||||
//dummy function, that stops archive variadic arguments expansion
|
||||
void archive() {
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//helper type
|
||||
|
||||
44
include/bitsery/traits/array.h
Normal file
44
include/bitsery/traits/array.h
Normal file
@@ -0,0 +1,44 @@
|
||||
//MIT License
|
||||
//
|
||||
//Copyright (c) 2017 Mindaugas Vinkelis
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
|
||||
#ifndef BITSERY_TRAITS_ARRAY_H
|
||||
#define BITSERY_TRAITS_ARRAY_H
|
||||
|
||||
#include "helper/std_defaults.h"
|
||||
#include <array>
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
namespace details {
|
||||
template<typename T, size_t N>
|
||||
struct ContainerTraits<std::array<T, N>>
|
||||
:public StdContainer<std::array<T, N>, false, true> {};
|
||||
|
||||
template<typename T, size_t N>
|
||||
struct BufferContainerTraits<std::array<T, N>>
|
||||
:public StdContainerForBuffer<std::array<T, N>> {};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //BITSERY_TYPE_TRAITS_ARRAY_H
|
||||
50
include/bitsery/traits/vector.h
Normal file
50
include/bitsery/traits/vector.h
Normal file
@@ -0,0 +1,50 @@
|
||||
//MIT License
|
||||
//
|
||||
//Copyright (c) 2017 Mindaugas Vinkelis
|
||||
//
|
||||
//Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
//of this software and associated documentation files (the "Software"), to deal
|
||||
//in the Software without restriction, including without limitation the rights
|
||||
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
//copies of the Software, and to permit persons to whom the Software is
|
||||
//furnished to do so, subject to the following conditions:
|
||||
//
|
||||
//The above copyright notice and this permission notice shall be included in all
|
||||
//copies or substantial portions of the Software.
|
||||
//
|
||||
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
//SOFTWARE.
|
||||
|
||||
|
||||
#ifndef BITSERY_TRAITS_VECTOR_H
|
||||
#define BITSERY_TRAITS_VECTOR_H
|
||||
|
||||
#include "helper/std_defaults.h"
|
||||
#include <vector>
|
||||
|
||||
namespace bitsery {
|
||||
|
||||
namespace details {
|
||||
template<typename ... TArgs>
|
||||
struct ContainerTraits<std::vector<TArgs...>>
|
||||
:public StdContainer<std::vector<TArgs...>, true, true> {};
|
||||
|
||||
//bool vector is not contiguous, do not copy it directly to buffer
|
||||
template<typename Allocator>
|
||||
struct ContainerTraits<std::vector<bool, Allocator>>
|
||||
:public StdContainer<std::vector<bool, Allocator>, true, false> {};
|
||||
|
||||
template<typename ... TArgs>
|
||||
struct BufferContainerTraits<std::vector<TArgs...>>
|
||||
:public StdContainerForBuffer<std::vector<TArgs...>> {};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //BITSERY_TRAITS_VECTOR_H
|
||||
@@ -145,7 +145,7 @@ struct IntegralUnsignedTypes {
|
||||
|
||||
TEST(BufferEndianness, WhenBufferValueTypeIs1ByteThenBitOperationsIsNotAffectedByEndianness) {
|
||||
//fill initial values
|
||||
static_assert(sizeof(bitsery::details::BufferContainerTraits<DefaultConfig::BufferType>::TValue) == 1, "currently only 1 byte size, value size is supported");
|
||||
static_assert(sizeof(bitsery::details::ContainerTraits<DefaultConfig::BufferType>::TValue) == 1, "currently only 1 byte size, value size is supported");
|
||||
//fill initial values
|
||||
constexpr IntegralUnsignedTypes src {
|
||||
0x0000334455667788,//bits 19
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include "serialization_test_utils.h"
|
||||
#include <bitsery/traits/string.h>
|
||||
|
||||
using testing::Eq;
|
||||
using bitsery::BufferWriter;
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <bitsery/buffer_writer.h>
|
||||
#include <bitsery/buffer_reader.h>
|
||||
#include <bitsery/details/serialization_common.h>
|
||||
#include <bitsery/traits/array.h>
|
||||
#include <bitsery/traits/vector.h>
|
||||
|
||||
using testing::Eq;
|
||||
using testing::ContainerEq;
|
||||
|
||||
@@ -25,9 +25,12 @@
|
||||
#include <gmock/gmock.h>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
// #include <deque>
|
||||
#include "serialization_test_utils.h"
|
||||
#include <bitsery/traits/array.h>
|
||||
#include <bitsery/traits/list.h>
|
||||
#include <bitsery/traits/deque.h>
|
||||
|
||||
|
||||
|
||||
using testing::ContainerEq;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <bitsery/ext/container_map.h>
|
||||
#include <bitsery/ext/entropy.h>
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <bitsery/traits/string.h>
|
||||
|
||||
using ContainerMap = bitsery::ext::ContainerMap;
|
||||
|
||||
|
||||
@@ -24,8 +24,7 @@
|
||||
#include <gmock/gmock.h>
|
||||
#include "serialization_test_utils.h"
|
||||
#include <bitsery/ext/entropy.h>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <bitsery/traits/list.h>
|
||||
|
||||
using namespace testing;
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ using namespace testing;
|
||||
using bitsery::ext::Growable;
|
||||
|
||||
using Buffer = typename bitsery::DefaultConfig::BufferType;
|
||||
using DiffType = typename bitsery::details::BufferContainerTraits<Buffer>::TDifference;
|
||||
|
||||
struct DataV1 {
|
||||
int32_t v1;
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include "serialization_test_utils.h"
|
||||
#include <bitsery/traits/string.h>
|
||||
#include <bitsery/traits/array.h>
|
||||
|
||||
using testing::Eq;
|
||||
using testing::StrEq;
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include "serialization_test_utils.h"
|
||||
#include <bitsery/traits/string.h>
|
||||
|
||||
using namespace testing;
|
||||
|
||||
TEST(SerializeText, BasicString) {
|
||||
@@ -113,6 +115,5 @@ TEST(SerializeText, WhenCArrayNotNullterminatedThenAssert) {
|
||||
char16_t t1[CARR_LENGTH]{u"some text"};
|
||||
//make last character not nullterminated
|
||||
t1[CARR_LENGTH-1] = 'x';
|
||||
|
||||
EXPECT_DEATH(ctx.createSerializer().text<2>(t1), "");
|
||||
}
|
||||
Reference in New Issue
Block a user