// // Created by Mindaugas Vinkelis on 17.1.3. // #ifndef TMP_SERIALIZER_H #define TMP_SERIALIZER_H #include "Common.h" #include namespace bitsery { /* * functions for range */ template::value>::type * = nullptr> bool isRangeValid(const T &v, const RangeSpec &r) { return !(r.min > v || v > r.max); } template::value>::type * = nullptr> bool isRangeValid(const T &v, const RangeSpec &r) { using VT = std::underlying_type_t; return !(static_cast(r.min) > static_cast(v) || static_cast(v) > static_cast(r.max)); } template::value>::type * = nullptr> auto getRangeValue(const T &v, const RangeSpec &r) { return static_cast>(v - r.min); }; template::value>::type * = nullptr> auto getRangeValue(const T &v, const RangeSpec &r) { return static_cast>(v) - static_cast>(r.min); }; template::value>::type * = nullptr> auto getRangeValue(const T &v, const RangeSpec &r) { using VT = SAME_SIZE_UNSIGNED; const VT maxUint = (static_cast(1) << r.bitsRequired) - 1; const auto ratio = (v - r.min) / (r.max - r.min); return static_cast(ratio * maxUint); }; /* * functions for substitution */ template size_t findSubstitutionIndex(const T &v, const std::array &defValues) { auto index{1u}; for (auto &d:defValues) { if (d == v) return index; ++index; } return 0u; }; template class Serializer { public: Serializer(Writter &w) : _writter{w} {}; template Serializer& object(const T &obj) { return serialize(*this, obj); } /* * value overloads */ template::value>::type * = nullptr> Serializer& value(const T &v) { static_assert(std::numeric_limits::is_iec559, ""); static_assert(std::numeric_limits::is_iec559, ""); constexpr size_t ValueSize = VSIZE == 0 ? sizeof(T) : VSIZE; _writter.template writeBytes(reinterpret_cast &>(v)); return *this; } template::value>::type * = nullptr> Serializer& value(const T &v) { constexpr size_t ValueSize = VSIZE == 0 ? sizeof(T) : VSIZE; _writter.template writeBytes(reinterpret_cast &>(v)); return *this; } template::value>::type * = nullptr> Serializer& value(const T &v) { constexpr size_t ValueSize = VSIZE == 0 ? sizeof(T) : VSIZE; _writter.template writeBytes(v); return *this; } /* * range */ template Serializer& range(const T &v, const RangeSpec &range) { assert(isRangeValid(v, range)); _writter.template writeBits(getRangeValue(v, range), range.bitsRequired); return *this; } /* * substitution overloads */ template Serializer& substitution(const T &v, const std::array &expectedValues, Fnc &&fnc) { auto index = findSubstitutionIndex(v, expectedValues); range(index, {{}, N +1}); if (!index) fnc(v); return *this; }; template Serializer& substitution(const T &v, const std::array &expectedValues) { auto index = findSubstitutionIndex(v, expectedValues); range(index, {{}, N +1}); if (!index) ProcessAnyType::serialize(*this, v); return *this; }; template Serializer& substitution(const T &v, const std::array &expectedValues) { auto index = findSubstitutionIndex(v, expectedValues); range(index, {{}, N +1}); if (!index) ProcessAnyType>::serialize(*this, v); return *this; }; /* * text overloads */ template Serializer& text(const std::basic_string &str, size_t maxSize) { assert(str.size() <= maxSize); procText(str.data(), str.size()); return *this; } template Serializer& text(const T (&str)[N]) { procText(str, std::min(std::char_traits::length(str), N - 1)); return *this; } /* * container overloads */ template Serializer& container(const T &obj, Fnc &&fnc, size_t maxSize) { assert(obj.size() <= maxSize); writeLength(obj.size()); for (auto &v: obj) fnc(v); return *this; } template Serializer& container(const T &obj, size_t maxSize) { assert(obj.size() <= maxSize); writeLength(obj.size()); procContainer(obj); return *this; } template Serializer& container(const T &obj, size_t maxSize) { assert(obj.size() <= maxSize); writeLength(obj.size()); procContainer>(obj); return *this; } /* * array overloads (fixed size array (std::array, and c-style array)) */ //std::array overloads template Serializer& array(const std::array &arr, Fnc &&fnc) { for (auto &v: arr) fnc(v); return *this; } template Serializer& array(const std::array &arr) { procContainer(arr); return *this; } template Serializer& array(const std::array &arr) { procContainer>(arr); return *this; } //c-style array overloads template Serializer& array(const T (&arr)[N], Fnc &&fnc) { const T *end = arr + N; for (const T *tmp = arr; tmp != end; ++tmp) fnc(*tmp); return *this; } template Serializer& array(const T (&arr)[N]) { procCArray(arr); return *this; } template Serializer& array(const T (&arr)[N]) { procCArray>(arr); return *this; } private: Writter &_writter; void writeLength(const size_t size) { _writter.writeBits(size, 32); } template void procContainer(T &&obj) { //todo could be improved for arithmetic types in contiguous containers (std::vector, std::array) (keep in mind std::vector specialization) for (auto &v: obj) ProcessAnyType::serialize(*this, v); }; template void procCArray(T (&arr)[N]) { //todo could be improved for arithmetic types const T *end = arr + N; for (const T *it = arr; it != end; ++it) ProcessAnyType::serialize(*this, *it); }; template void procText(const T *str, size_t size) { writeLength(size); if (size) _writter.template writeBuffer(str, size); } }; } #endif //TMP_SERIALIZER_H