initial concept commit

This commit is contained in:
fraillt
2017-02-07 07:26:23 +02:00
commit 0fb7b0986d
16 changed files with 1533 additions and 0 deletions

111
include/BufferReader.h Normal file
View File

@@ -0,0 +1,111 @@
//
// Created by Mindaugas Vinkelis on 2016-11-11.
//
#ifndef PROJECT_TEMPLATE_BUFFER_READER_H
#define PROJECT_TEMPLATE_BUFFER_READER_H
#include "Common.h"
#include <algorithm>
struct BufferReader {
using value_type = uint8_t;
BufferReader(const std::vector<uint8_t>& buf):_buf{buf}, _pos{std::begin(buf)}{
}
template<size_t SIZE, typename T>
bool ReadBytes(T& v) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
using UT = typename std::make_unsigned<T>::type;
return m_scratch
? ReadBits<SIZE * 8>(reinterpret_cast<UT&>(v))
: directRead(&v, 1);
}
template<size_t SIZE, typename T>
bool ReadBuffer(T* buf, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
if (m_scratchBits) {
//todo implement
// using UT = typename std::make_unsigned<T>::type;
// WriteBits<SIZE * 8 * count>(reinterpret_cast<const UT&>(v));
} else {
return directRead(buf, count);
}
return true;
}
template<size_t SIZE, typename T>
bool ReadBits(T& v) {
static_assert(std::is_integral<T>() && std::is_unsigned<T>(), "");
static_assert(SIZE > 0 && SIZE <= BITS_SIZE<T>, "");
const auto bytesRequired = SIZE > m_scratchBits
? ((SIZE - 1 - m_scratchBits) >> 3) + 1u
: 0u;
if (static_cast<size_t>(std::distance(_pos, std::end(_buf))) < bytesRequired )
return false;
ReadBitsInternal(v, SIZE);
return true;
}
template <typename T>
void ReadBitsInternal(T& v, size_t size) {
auto bitsLeft = size;
T res{};
while (bitsLeft > 0) {
auto bits = std::min(bitsLeft, BITS_SIZE<value_type>);
if ( m_scratchBits < bits ) {
value_type tmp;
std::copy_n(_pos, 1, reinterpret_cast<value_type *>(&tmp));
std::advance(_pos, 1);
m_scratch |= static_cast<SCRATCH_TYPE>(tmp) << m_scratchBits;
m_scratchBits += BITS_SIZE<value_type>;
}
auto shiftedRes = static_cast<T>(m_scratch & ( (static_cast<SCRATCH_TYPE>(1)<<bits) - 1 )) << (size - bitsLeft);
res |= shiftedRes;
m_scratch >>= bits;
m_scratchBits -= bits;
bitsLeft -= bits;
}
v = res;
}
bool isCompleted() const {
return _pos == std::end(_buf);
}
private:
const std::vector<value_type>& _buf;
decltype(std::begin(_buf)) _pos;
template <typename T>
bool directRead(T* v, size_t count) {
static_assert(!std::is_const<T>::value, "");
const auto bytesCount = sizeof(T) * count;
if (static_cast<size_t>(std::distance(_pos, std::end(_buf))) < bytesCount)
return false;
std::copy_n(_pos, bytesCount, reinterpret_cast<value_type *>(v));
std::advance(_pos, bytesCount);
return true;
}
using SCRATCH_TYPE = typename BIGGER_TYPE<value_type>::type;
SCRATCH_TYPE m_scratch{};
size_t m_scratchBits{}; ///< Number of bits currently in the scratch buffer. If the user wants to read more bits than this, we have to go fetch another dword from memory.
};
#endif //PROJECT_TEMPLATE_BUFFER_READER_H

137
include/BufferWriter.h Normal file
View File

@@ -0,0 +1,137 @@
//
// Created by Mindaugas Vinkelis on 2016-11-11.
//
#ifndef PROJECT_TEMPLATE_BUFFER_WRITER_H
#define PROJECT_TEMPLATE_BUFFER_WRITER_H
#include "Common.h"
#include <algorithm>
struct MeasureSize {
template<size_t SIZE, typename T>
void WriteBytes(const T& ) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
_bytesCount += SIZE;
}
template<size_t SIZE, typename T>
void WriteBits(const T& ) {
static_assert(std::is_integral<T>() && std::is_unsigned<T>(), "");
static_assert(SIZE > 0 && SIZE <= BITS_SIZE<T>, "");
_bytesCount += SIZE * 8;
}
template<size_t SIZE, typename T>
void WriteBuffer(const T* , size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
_bytesCount += SIZE * count;
}
size_t getSize() const {
return _bytesCount;
}
private:
size_t _bytesCount{};
};
struct BufferWriter {
using value_type = uint8_t;
BufferWriter(std::vector<uint8_t>& buffer):_buf{buffer}, _outIt{std::back_inserter(buffer)} {
}
template<size_t SIZE, typename T>
void WriteBytes(const T& v) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
if (m_scratchBits) {
using UT = typename std::make_unsigned<T>::type;
WriteBits<SIZE * 8>(reinterpret_cast<const UT&>(v));
} else {
directWrite(&v,1);
}
}
template<size_t SIZE, typename T>
void WriteBuffer(const T* buf, size_t count) {
static_assert(std::is_integral<T>(), "");
static_assert(sizeof(T) == SIZE, "");
if (m_scratchBits) {
//todo implement
// using UT = typename std::make_unsigned<T>::type;
// WriteBits<SIZE * 8 * count>(reinterpret_cast<const UT&>(v));
} else {
directWrite(buf, count);
}
}
template<size_t SIZE, typename T>
void WriteBits(const T& v) {
static_assert(std::is_integral<T>() && std::is_unsigned<T>(), "");
static_assert(SIZE > 0 && SIZE <= BITS_SIZE<T>, "");
WriteBitsInternal(v, SIZE);
}
template <typename T>
void WriteBitsInternal(const T& v, size_t size) {
auto value = v;
auto bitsLeft = size;
while (bitsLeft > 0) {
auto bits = std::min(bitsLeft, BITS_SIZE<value_type>);
m_scratch |= static_cast<SCRATCH_TYPE>( value ) << m_scratchBits;
m_scratchBits += bits;
if ( m_scratchBits >= BITS_SIZE<value_type> ) {
auto tmp = static_cast<value_type>(m_scratch & bufTypeMask);
directWrite(&tmp, 1);
m_scratch >>= BITS_SIZE<value_type>;
m_scratchBits -= BITS_SIZE<value_type>;
value >>= BITS_SIZE<value_type>;
}
bitsLeft -= bits;
}
}
void Flush() {
if ( m_scratchBits )
{
auto tmp = static_cast<value_type>( m_scratch & bufTypeMask );
directWrite(&tmp, 1);
m_scratch >>= m_scratchBits;
m_scratchBits -= m_scratchBits;
}
}
private:
template <typename T>
void directWrite(const T* v, size_t count) {
const auto bytesSize = sizeof(T) * count;
const auto pos = _buf.size();
_buf.resize(pos + bytesSize);
std::copy_n(reinterpret_cast<const value_type *>(v), bytesSize, _buf.data()+pos);
}
const value_type bufTypeMask = 0xFF;
using SCRATCH_TYPE = typename BIGGER_TYPE<value_type>::type;
std::vector<value_type>& _buf;
std::back_insert_iterator<std::vector<value_type>> _outIt;
SCRATCH_TYPE m_scratch{};
size_t m_scratchBits{};
//size_t _bufSize{};
};
#endif //PROJECT_TEMPLATE_BUFFER_WRITER_H

106
include/Common.h Normal file
View File

@@ -0,0 +1,106 @@
//
// Created by fraillt on 17.1.5.
//
#ifndef TMP_COMMON_H
#define TMP_COMMON_H
#include <stdint.h>
template <typename T>
constexpr size_t BITS_SIZE = sizeof(T) << 3;
template <typename T>
struct BIGGER_TYPE {};
template <>
struct BIGGER_TYPE<uint8_t> {
typedef uint16_t type;
};
template <>
struct BIGGER_TYPE<uint16_t> {
typedef uint32_t type;
};
template <>
struct BIGGER_TYPE<uint32_t> {
typedef uint64_t type;
};
template <>
struct BIGGER_TYPE<int8_t> {
typedef int16_t type;
};
template <>
struct BIGGER_TYPE<int16_t> {
typedef int32_t type;
};
template <>
struct BIGGER_TYPE<int32_t> {
typedef int64_t type;
};
template <>
struct BIGGER_TYPE<char> {
typedef int16_t type;
};
template <size_t SIZE, typename T>
constexpr size_t DEFAULT_OR_SIZE =SIZE == 0 ? sizeof(T) : SIZE;
template <size_t SIZE>
struct ProcessAnyType {
template <typename S, typename T>
static void serialize(S& s, T&& v) {
s.value<SIZE>(std::forward<T>(v));
}
};
template <>
struct ProcessAnyType<0> {
template <typename S, typename T>
static void serialize(S& s, T&& v) {
s.object(std::forward<T>(v));
}
};
#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)
class ObjectMemoryPosition {
public:
template <typename T>
ObjectMemoryPosition(const T& oldObj, const T& newObj)
:ObjectMemoryPosition{reinterpret_cast<const char*>(&oldObj), reinterpret_cast<const char*>(&newObj), sizeof(T)}
{
}
template <typename T>
bool isFieldsEquals(const T& newObjField) {
return *getOldObjectField(newObjField) == newObjField;
}
template <typename T>
const T* getOldObjectField(const T& field) {
auto offset = reinterpret_cast<const char*>(&field) - newObj;
return reinterpret_cast<const T*>(oldObj + offset);
}
private:
ObjectMemoryPosition(const char* objOld, const char* objNew, size_t )
:oldObj{objOld},
newObj{objNew}
{
}
const char* oldObj;
const char* newObj;
};
#endif //TMP_COMMON_H

185
include/DeltaDeserializer.h Normal file
View File

@@ -0,0 +1,185 @@
//
// Created by fraillt on 17.1.10.
//
#ifndef TMP_DELTADESERIALIZER_H
#define TMP_DELTADESERIALIZER_H
#include <array>
#include <stack>
#include <algorithm>
#include "Common.h"
template<typename Reader, typename TObj>
class DeltaDeserializer {
public:
DeltaDeserializer(Reader& w, const TObj& oldObj, const TObj& newObj)
:_reader{w},
_oldObj{oldObj},
_newObj{newObj},
_objMemPos(std::deque<ObjectMemoryPosition>(1, ObjectMemoryPosition{oldObj, newObj})),
_isNewElement{false}
{
};
template<size_t SIZE = 0, typename T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
DeltaDeserializer& value(T& v) {
if (getChangedState(v)) {
constexpr size_t ValueSize = SIZE == 0 ? sizeof(T) : SIZE;
_reader.template ReadBytes<ValueSize>(v);
}
return *this;
}
template <typename T>
DeltaDeserializer& object(T&& obj) {
if (getChangedState(obj))
return serialize(*this, std::forward<T>(obj));
return *this;
}
template<typename T>
DeltaDeserializer& text(T&& str) {
return withContainer(str, [this](auto& v) { value<1>(v);});
}
template<typename T, size_t N, typename Fnc>
DeltaDeserializer & withArray(std::array<T,N> &arr, Fnc&& fnc) {
if (getChangedState(arr)) {
if (!_isNewElement) {
const auto old = *_objMemPos.top().getOldObjectField(arr);
processContainer(std::begin(old), std::end(old), std::begin(arr), std::end(arr), fnc);
} else {
for (auto& v:arr)
fnc(v);
}
}
return *this;
}
template<typename T, size_t N, typename Fnc>
DeltaDeserializer& withArray(T (&arr)[N], Fnc&& fnc) {
if (getChangedState(arr)) {
if (!_isNewElement) {
const auto old = *_objMemPos.top().getOldObjectField(arr);
T* tmp = arr;
processContainer(old, old + N, tmp, tmp + N, fnc);
} else {
T* tmp = arr;
for (auto i=0u; i < N; ++i, ++tmp)
fnc(*tmp);
}
}
return *this;
}
template <typename T, typename Fnc>
DeltaDeserializer& withContainer(T& obj, Fnc&& fnc) {
if(getChangedState(obj)) {
size_t newSize{};
_reader.template ReadBits<32>(newSize);
if (!_isNewElement) {
auto old = *_objMemPos.top().getOldObjectField(obj);
if (old.size() != newSize)
obj.resize(newSize);
processContainer(std::begin(old), std::end(old), std::begin(obj), std::end(obj), std::forward<Fnc>(fnc));
} else {
obj.resize(newSize);
for (auto& v:obj)
fnc(v);
}
}
return *this;
}
private:
Reader& _reader;
const TObj& _oldObj;
const TObj& _newObj;
std::stack<ObjectMemoryPosition> _objMemPos;
bool _isNewElement;
template <typename T>
bool getChangedState(T& obj) {
if (!_isNewElement) {
if (!readChangedState()) {
obj = *_objMemPos.top().getOldObjectField(obj);
return false;
}
}
return true;
}
template <typename T, size_t N>
bool getChangedState(T (&arr)[N]) {
if (!_isNewElement) {
if (!readChangedState()) {
auto old = *_objMemPos.top().getOldObjectField(arr);
auto end = arr + N;
auto pOld = old;
for (auto p=arr; p != end; ++p, ++pOld)
*p = *pOld;
return false;
}
}
return true;
}
template <typename TConstIt, typename TIt, typename Fnc>
bool processContainer(TConstIt oldBegin, TConstIt oldEnd, TIt begin, TIt end, Fnc&& fnc) {
auto offset = readIndexOffset();
auto p = begin;
auto pOld = oldBegin;
for (; p != end && pOld != oldEnd; ++p, ++pOld) {
if (offset) {
*p = *pOld;
--offset;
} else {
_objMemPos.emplace(ObjectMemoryPosition{*pOld, *p});
fnc(*p);
_objMemPos.pop();
offset = readIndexOffset();
}
}
if (offset != 0 && pOld != oldEnd)
return false;
_isNewElement = true;
for (; p != end; ++p, --offset)
fnc(*p);
_isNewElement = false;
return offset == 0;
}
bool readChangedState() {
unsigned char res{};
_reader.template ReadBits<1>(res);
return res;
}
size_t readIndexOffset() {
//special case, if items are updated sequentialy
unsigned char tmp{};
_reader.template ReadBits<1>(tmp);
if (tmp) {
return 0u;
}
else {
size_t res{};
_reader.template ReadBits<1>(tmp);
if (tmp > 0)
_reader.template ReadBits<4>(res);
else
_reader.template ReadBits<32>(res);
return res;
}
}
};
#endif //TMP_DELTADESERIALIZER_H

182
include/DeltaSerializer.h Normal file
View File

@@ -0,0 +1,182 @@
//
// Created by fraillt on 17.1.10.
//
#ifndef TMP_DELTASERIALIZER_H
#define TMP_DELTASERIALIZER_H
#include <array>
#include <stack>
#include <algorithm>
#include "Common.h"
template<typename Writter, typename TObj>
class DeltaSerializer {
public:
DeltaSerializer(Writter& w, const TObj& oldObj, const TObj& newObj)
:_writter{w},
_oldObj{oldObj},
_newObj{newObj},
_objMemPos(std::deque<ObjectMemoryPosition>(1, ObjectMemoryPosition{oldObj, newObj})),
_isNewElement{false}
{
};
template<size_t SIZE = 0, typename T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
DeltaSerializer& value(const T& v) {
if (setChangedState(v)) {
constexpr size_t ValueSize = SIZE == 0 ? sizeof(T) : SIZE;
_writter.template WriteBytes<ValueSize>(v);
}
return *this;
}
template <typename T>
DeltaSerializer& object(T&& obj) {
if (setChangedState(obj)) {
serialize(*this, std::forward<T>(obj));
}
return *this;
}
template<typename T>
DeltaSerializer& text(T&& str) {
return withContainer(str, [this](auto& v) { value<1>(v);});
}
template<typename T, size_t N, typename Fnc>
DeltaSerializer & withArray(const std::array<T,N> &arr, Fnc&& fnc) {
if (setChangedState(arr)) {
if (!_isNewElement) {
const auto& old = *_objMemPos.top().getOldObjectField(arr);
processContainer(std::begin(old), std::end(old), std::begin(arr), std::end(arr), fnc);
} else {
for (auto& v:arr)
fnc(v);
}
}
return *this;
}
template<typename T, size_t N, typename Fnc>
DeltaSerializer& withArray(const T (&arr)[N], Fnc&& fnc) {
if (setChangedState(arr)) {
if (!_isNewElement) {
auto old = *_objMemPos.top().getOldObjectField(arr);
const T* tmp = arr;
processContainer(old, old + N, tmp, tmp + N, fnc);
} else {
const T* tmp = arr;
for (auto i=0u; i < N; ++i, ++tmp)
fnc(*tmp);
}
}
return *this;
}
template <typename T, typename Fnc>
DeltaSerializer& withContainer(T&& obj, Fnc&& fnc) {
if(setChangedState(obj)) {
_writter.template WriteBits<32>(obj.size());
if (!_isNewElement) {
auto old = *_objMemPos.top().getOldObjectField(obj);
processContainer(std::begin(old), std::end(old), std::begin(obj), std::end(obj), std::forward<Fnc>(fnc));
} else {
for (auto& v:obj)
fnc(v);
}
}
return *this;
}
private:
Writter& _writter;
const TObj& _oldObj;
const TObj& _newObj;
std::stack<ObjectMemoryPosition> _objMemPos;
bool _isNewElement;
template <typename T>
bool setChangedState(const T& obj) {
if (!_isNewElement) {
auto res = !_objMemPos.top().isFieldsEquals(obj);
writeChangedState(res);
return res;
}
return true;
}
template <typename T, size_t N>
bool setChangedState(const T (&arr)[N]) {
if (!_isNewElement) {
auto old = *_objMemPos.top().getOldObjectField(arr);
auto end = arr + N;
bool changed{};
for (auto p=arr, pOld=old; p != end; ++p, ++pOld) {
if (!(*p == *pOld)) {
changed = true;
break;
}
}
writeChangedState(changed);
return changed;
}
return true;
}
template <typename T, typename Fnc>
void processContainer(const T oldBegin, const T oldEnd, const T begin, const T end, Fnc&& fnc) {
auto misMatch = std::mismatch(oldBegin, oldEnd, begin, end);
auto lastChanged = begin;
while (misMatch.first != oldEnd && misMatch.second != end) {
writeIndexOffset(std::distance(lastChanged, misMatch.second));
_objMemPos.emplace(ObjectMemoryPosition{*misMatch.first, *misMatch.second});
fnc(*misMatch.second);
_objMemPos.pop();
++misMatch.first;
++misMatch.second;
lastChanged = misMatch.second;
misMatch = std::mismatch(misMatch.first, oldEnd, misMatch.second, end);
}
auto p = misMatch.second;
//write items left
writeIndexOffset(std::distance(lastChanged, end));
//write old elements
for (auto pOld = misMatch.first; p != end && pOld != oldEnd; ++p, ++pOld) {
_objMemPos.emplace(ObjectMemoryPosition{*pOld, *p});
fnc(*p);
_objMemPos.pop();
}
//write new elements
_isNewElement = true;
for (; p != end; ++p)
fnc(*p);
_isNewElement = false;
}
void writeChangedState(bool state) {
_writter.template WriteBits<1>(state ? 1u : 0u);
}
void writeIndexOffset(const size_t offset) {
//special case, if items are updated sequentialy
if (offset == 0) {
_writter.template WriteBits<1>(1u);
} else {
_writter.template WriteBits<1>(0u);
auto smallOffset = offset < 16;
_writter.template WriteBits<1>(smallOffset ? 1u : 0u);
if (smallOffset)
_writter.template WriteBits<4>(offset);
else
_writter.template WriteBits<32>(offset);
}
}
};
#endif //TMP_DELTASERIALIZER_H

116
include/Deserializer.h Normal file
View File

@@ -0,0 +1,116 @@
//
// Created by Mindaugas Vinkelis on 17.1.9.
//
#ifndef TMP_DESERIALIZER_H
#define TMP_DESERIALIZER_H
#include <array>
template<typename Reader>
class Deserializer {
public:
Deserializer(Reader& r):_reader{r} {};
template <typename T>
Deserializer& object(T&& obj) {
return serialize(*this, std::forward<T>(obj));
}
template<size_t SIZE = 0, typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
Deserializer& value(T& v) {
static_assert(std::numeric_limits<float>::is_iec559, "");
static_assert(std::numeric_limits<double>::is_iec559, "");
constexpr size_t ValueSize = SIZE == 0 ? sizeof(T) : SIZE;
using CT = std::conditional_t<std::is_same<T,float>::value, uint32_t, uint64_t>;
static_assert(sizeof(CT) == ValueSize, "");
_reader.template ReadBytes<ValueSize>(reinterpret_cast<CT&>(v));
return *this;
}
template<size_t SIZE = 0, typename T, typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
Deserializer& value(T& v) {
constexpr size_t ValueSize = SIZE == 0 ? sizeof(T) : SIZE;
using UT = std::underlying_type_t<T>;
_reader.template ReadBytes<ValueSize>(reinterpret_cast<UT&>(v));
return *this;
}
template<size_t SIZE = 0, typename T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
Deserializer& value(T& v) {
constexpr size_t ValueSize = SIZE == 0 ? sizeof(T) : SIZE;
_reader.template ReadBytes<ValueSize>(v);
return *this;
}
template <size_t SIZE = 1, typename T>
Deserializer& text(std::basic_string<T>& str) {
size_t size;
readLength(size);
std::vector<T> buf(size);
_reader.template ReadBuffer<SIZE>(buf.data(), size);
str.assign(buf.data(), size);
// str.resize(size);
// if (size)
// _reader.template ReadBuffer<SIZE>(str.data(), size);
return *this;
}
template<typename T, size_t N, typename Fnc>
Deserializer & withArray(std::array<T,N> &arr, Fnc && fnc) {
for (auto& v: arr)
fnc(v);
return *this;
}
template<typename T, size_t N, typename Fnc>
Deserializer& withArray(T (&arr)[N], Fnc&& fnc) {
T* tmp = arr;
for (auto i = 0u; i < N; ++i, ++tmp)
fnc(*tmp);
return *this;
}
template <typename T, typename Fnc>
Deserializer& withContainer(T&& obj, Fnc&& fnc) {
decltype(obj.size()) size{};
readLength(size);
obj.resize(size);
for (auto& v:obj)
fnc(v);
return *this;
}
template <typename T>
Deserializer& withContainer(T&& obj) {
decltype(obj.size()) size{};
readLength(size);
obj.resize(size);
for (auto& v: obj)
object(v);
return *this;
}
template <size_t SIZE, typename T>
Deserializer& withContainer(T&& obj) {
constexpr size_t ValueSize = SIZE == 0 ? sizeof(T) : SIZE;
writeLength(obj.size());
for (auto& v: obj)
value<ValueSize>(v);
return *this;
}
private:
Reader& _reader;
void readLength(size_t& size) {
_reader.template ReadBits<32>(size);
}
};
#endif //TMP_DESERIALIZER_H

120
include/Serializer.h Normal file
View File

@@ -0,0 +1,120 @@
//
// Created by Mindaugas Vinkelis on 17.1.3.
//
#ifndef TMP_SERIALIZER_H
#define TMP_SERIALIZER_H
#include <array>
template<typename Writter>
class Serializer {
public:
Serializer(Writter& w):_writter{w} {};
template <typename T>
Serializer& object(T&& obj) {
return serialize(*this, std::forward<T>(obj));
}
template<size_t SIZE = 0, typename T, typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr>
Serializer& value(const T& v) {
static_assert(std::numeric_limits<float>::is_iec559, "");
static_assert(std::numeric_limits<double>::is_iec559, "");
constexpr size_t ValueSize = SIZE == 0 ? sizeof(T) : SIZE;
using CT = std::conditional_t<std::is_same<T,float>::value, uint32_t, uint64_t>;
_writter.template WriteBytes<ValueSize>(reinterpret_cast<const CT&>(v));
return *this;
}
template<size_t SIZE = 0, typename T, typename std::enable_if<std::is_enum<T>::value>::type* = nullptr>
Serializer& value(const T& v) {
constexpr size_t ValueSize = SIZE == 0 ? sizeof(T) : SIZE;
_writter.template WriteBytes<ValueSize>(reinterpret_cast<const std::underlying_type_t<T>&>(v));
return *this;
}
template<size_t SIZE = 0, typename T, typename std::enable_if<std::is_integral<T>::value>::type* = nullptr>
Serializer& value(const T& v) {
constexpr size_t ValueSize = SIZE == 0 ? sizeof(T) : SIZE;
_writter.template WriteBytes<ValueSize>(v);
return *this;
}
template <size_t SIZE = 1, typename T>
Serializer& text(const std::basic_string<T>& str) {
procText<SIZE>(str.data());
return *this;
}
template<size_t SIZE=1, typename T, size_t N>
Serializer& text(const T (&str)[N]) {
procText<SIZE>(str);
return *this;
}
template<typename T, size_t N, typename Fnc>
Serializer & withArray(const std::array<T,N> &arr, Fnc&& fnc) {
for (auto& v: arr)
fnc(v);
return *this;
}
template<typename T, size_t N, typename Fnc>
Serializer& withArray(const T (&arr)[N], Fnc&& fnc) {
const T* end = arr + N;
for (const T* tmp = arr; tmp != end; ++tmp)
fnc(*tmp);
return *this;
}
template <typename T, typename Fnc>
Serializer& withContainer(T&& obj, Fnc&& fnc) {
writeLength(obj.size());
for (auto& v: obj)
fnc(v);
return *this;
}
template <typename T>
Serializer& withContainer(T&& obj) {
writeLength(obj.size());
procContainer<0>(std::forward<T>(obj));
return *this;
}
template <size_t SIZE=0, typename T, typename std::enable_if<std::is_arithmetic<T>::value && std::is_enum<T>::value>::type>
Serializer& withContainer(T&& obj) {
writeLength(obj.size());
//procContainer<SIZE == 0 ? sizeof(T) : SIZE>(std::forward<T>(obj));
procContainer<DEFAULT_OR_SIZE<SIZE,T>>(std::forward<T>(obj));
return *this;
}
private:
Writter& _writter;
void writeLength(const size_t size) {
_writter.template WriteBits<32>(size);
}
template <size_t SIZE, typename T>
void procContainer(T&& obj) {
for (auto& v: obj)
ProcessAnyType<SIZE>::serialize(*this, v);
};
template <size_t SIZE, typename T>
void procText(const T* str) {
const auto size = std::char_traits<T>::length(str);
writeLength(size);
if (size)
_writter.template WriteBuffer<SIZE>(str, size);
}
};
#endif //TMP_SERIALIZER_H