//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_SERIALIZER_H #define BITSERY_SERIALIZER_H #include "Common.h" #include namespace bitsery { /* * functions for range */ 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; } /* * bool */ Serializer& boolBit(bool v) { _writter.template writeBits(static_cast(v ? 1 : 0), 1); return *this; } Serializer& boolByte(bool v) { _writter.template writeBytes<1>(static_cast(v ? 1 : 0)); 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); writeSize(obj.size()); for (auto &v: obj) fnc(v); return *this; } template Serializer& container(const T &obj, size_t maxSize) { assert(obj.size() <= maxSize); writeSize(obj.size()); procContainer(obj); return *this; } template Serializer& container(const T &obj, size_t maxSize) { assert(obj.size() <= maxSize); writeSize(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 writeSize(const size_t size) { if (size < 0x80u) { _writter.writeBits(1u, 1); _writter.writeBits(size, 7); } else if (size < 0x4000u) { _writter.writeBits(2u,2); _writter.writeBits(size, 14); } else { assert(size < 0x40000000u); _writter.writeBits(0u,2); _writter.writeBits(size, 30); } } 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) { writeSize(size); if (size) _writter.template writeBuffer(str, size); } }; } #endif //BITSERY_SERIALIZER_H