// // Created by Mindaugas Vinkelis on 17.1.3. // #ifndef TMP_SERIALIZER_H #define TMP_SERIALIZER_H #include "Common.h" #include 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; } /* * text overloads */ template Serializer& text(const std::basic_string& str) { 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) { writeLength(obj.size()); for (auto& v: obj) fnc(v); return *this; } template Serializer& container(const T& obj) { writeLength(obj.size()); procContainer(obj); return *this; } template Serializer& container(const T& obj) { 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); } }; /* * 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); }; #endif //TMP_SERIALIZER_H