From 5b3ca7b2e79d2ca5f04ab70ebef6760bf2a362ce Mon Sep 17 00:00:00 2001 From: Igor Korsukov Date: Thu, 17 Jul 2025 11:49:17 +0300 Subject: [PATCH] replaced msgpack implementation --- src/framework/global/CMakeLists.txt | 2 +- src/framework/global/serialization/msgpack.h | 95 +- .../{msgpack.cpp => msgpack_forward.h} | 14 +- src/framework/global/tests/msgpack_tests.cpp | 122 +- .../global/thirdparty/cppack/README.md | 53 - .../global/thirdparty/cppack/msgpack.hpp | 1058 ---------------- .../global/thirdparty/kors_msgpack/.gitignore | 2 + .../global/thirdparty/kors_msgpack/LICENSE | 21 + .../global/thirdparty/kors_msgpack/README.md | 2 + .../kors_msgpack/example/CMakeLists.txt | 13 + .../thirdparty/kors_msgpack/example/main.cpp | 466 +++++++ .../thirdparty/kors_msgpack/example/msgpack.h | 9 + .../thirdparty/kors_msgpack/msgpack/msgpack.h | 1080 +++++++++++++++++ src/framework/global/types/bytearray.cpp | 11 + src/framework/global/types/bytearray.h | 2 + 15 files changed, 1789 insertions(+), 1161 deletions(-) rename src/framework/global/serialization/{msgpack.cpp => msgpack_forward.h} (76%) delete mode 100644 src/framework/global/thirdparty/cppack/README.md delete mode 100644 src/framework/global/thirdparty/cppack/msgpack.hpp create mode 100644 src/framework/global/thirdparty/kors_msgpack/.gitignore create mode 100644 src/framework/global/thirdparty/kors_msgpack/LICENSE create mode 100644 src/framework/global/thirdparty/kors_msgpack/README.md create mode 100644 src/framework/global/thirdparty/kors_msgpack/example/CMakeLists.txt create mode 100644 src/framework/global/thirdparty/kors_msgpack/example/main.cpp create mode 100644 src/framework/global/thirdparty/kors_msgpack/example/msgpack.h create mode 100644 src/framework/global/thirdparty/kors_msgpack/msgpack/msgpack.h diff --git a/src/framework/global/CMakeLists.txt b/src/framework/global/CMakeLists.txt index 42d1391343d21..1f442a48356f8 100644 --- a/src/framework/global/CMakeLists.txt +++ b/src/framework/global/CMakeLists.txt @@ -146,8 +146,8 @@ set(MODULE_SRC ${CMAKE_CURRENT_LIST_DIR}/serialization/json.h ${CMAKE_CURRENT_LIST_DIR}/serialization/xmldom.cpp ${CMAKE_CURRENT_LIST_DIR}/serialization/xmldom.h - ${CMAKE_CURRENT_LIST_DIR}/serialization/msgpack.cpp ${CMAKE_CURRENT_LIST_DIR}/serialization/msgpack.h + ${CMAKE_CURRENT_LIST_DIR}/serialization/msgpack_forward.h ${CMAKE_CURRENT_LIST_DIR}/concurrency/taskscheduler.h ${CMAKE_CURRENT_LIST_DIR}/concurrency/concurrent.h diff --git a/src/framework/global/serialization/msgpack.h b/src/framework/global/serialization/msgpack.h index bb37a9bb2a239..9f85b36d5df3a 100644 --- a/src/framework/global/serialization/msgpack.h +++ b/src/framework/global/serialization/msgpack.h @@ -21,30 +21,77 @@ */ #pragma once -#include "../thirdparty/cppack/msgpack.hpp" +#include "msgpack_forward.h" #include "../types/bytearray.h" +#include "../types/string.h" +#include "../types/number.h" -namespace muse { -class MsgPack -{ -public: - MsgPack() = default; - - template - static ByteArray pack(const Types&... args) - { - msgpack::Packer p; - p.process(args ...); - const std::vector& d = p.vector(); - return ByteArray(&d[0], d.size()); - } - - template - static bool unpack(const ByteArray& data, Types&... args) - { - auto unpacker = msgpack::Unpacker(data.constData(), data.size()); - unpacker.process(args ...); - return unpacker.ec != msgpack::UnpackerError::OutOfRange; - } -}; +void pack_custom(std::vector& data, const muse::String& value); +bool unpack_custom(muse::msgpack::Cursor& cursor, muse::String& value); + +template +void pack_custom(std::vector& data, const muse::number_t& value); +template +bool unpack_custom(muse::msgpack::Cursor& cursor, muse::number_t& value); + +#include "../thirdparty/kors_msgpack/msgpack/msgpack.h" + +// muse standart types +inline void pack_custom(std::vector& data, const muse::String& value) +{ + muse::msgpack::Packer::pack(data, value.toStdString()); +} + +inline bool unpack_custom(muse::msgpack::Cursor& cursor, muse::String& value) +{ + std::string str; + bool ok = muse::msgpack::UnPacker::unpack(cursor, str); + value = muse::String::fromStdString(str); + return ok; +} + +template +inline void pack_custom(std::vector& data, const muse::number_t& value) +{ + muse::msgpack::Packer::pack(data, value.raw()); +} + +template +inline bool unpack_custom(muse::msgpack::Cursor& cursor, muse::number_t& value) +{ + T val = {}; + bool ok = muse::msgpack::UnPacker::unpack(cursor, val); + value = muse::number_t(val); + return ok; +} + +// pack / unpack +namespace muse::msgpack { +template +static inline void pack(std::vector& data, const Types&... args) +{ + Packer::pack(data, args ...); +} + +template +static inline ByteArray pack(const Types&... args) +{ + ByteArray ba; + std::vector& vdata = ba.vdata(); + vdata.clear(); + Packer::pack(vdata, args ...); + return ba; +} + +template +static inline bool unpack(muse::msgpack::Cursor& cursor, Types&... args) +{ + return UnPacker::unpack(cursor, args ...); +} + +template +static inline bool unpack(const ByteArray& data, Types&... args) +{ + return UnPacker::unpack(data.constVData(), args ...); +} } diff --git a/src/framework/global/serialization/msgpack.cpp b/src/framework/global/serialization/msgpack_forward.h similarity index 76% rename from src/framework/global/serialization/msgpack.cpp rename to src/framework/global/serialization/msgpack_forward.h index 51dc4a5bcee6b..460a473b509f4 100644 --- a/src/framework/global/serialization/msgpack.cpp +++ b/src/framework/global/serialization/msgpack_forward.h @@ -19,4 +19,16 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "msgpack.h" +#pragma once + +namespace kors::msgpack { +class Packer; +class UnPacker; +class Cursor; +} + +namespace muse::msgpack { +using Packer = kors::msgpack::Packer; +using UnPacker = kors::msgpack::UnPacker; +using Cursor = kors::msgpack::Cursor; +} diff --git a/src/framework/global/tests/msgpack_tests.cpp b/src/framework/global/tests/msgpack_tests.cpp index e7ccf7f0806f4..fed34ee556935 100644 --- a/src/framework/global/tests/msgpack_tests.cpp +++ b/src/framework/global/tests/msgpack_tests.cpp @@ -24,67 +24,117 @@ #include #include +namespace muse { +struct ObjectCustom { + int32_t i32 = 0; + std::string str; +}; +} + +#include "serialization/msgpack_forward.h" + +void pack_custom(std::vector& data, const muse::ObjectCustom& value); +bool unpack_custom(muse::msgpack::Cursor& cursor, muse::ObjectCustom& value); + #include "serialization/msgpack.h" -#include "types/bytearray.h" + +void pack_custom(std::vector& data, const muse::ObjectCustom& value) +{ + muse::msgpack::pack(data, value.i32, value.str); +} + +bool unpack_custom(muse::msgpack::Cursor& cursor, muse::ObjectCustom& value) +{ + return muse::msgpack::unpack(cursor, value.i32, value.str); +} using namespace muse; -class Global_Ser_MsgPack : public ::testing::Test +class Global_Ser_Msgpack : public ::testing::Test { public: }; -struct Object { +struct ObjectWithPack { + int32_t i32 = 0; uint64_t ui64 = 0; - double real = 0.0; + float float32 = 0.0; + double float64 = 0.0; std::string str; bool b = false; std::vector vi; std::map map; - // origin way template void pack(T& pack) { - pack(ui64, real, str, b, vi, map); + pack(i32, ui64, float32, float64, str, b, vi, map); } }; -TEST_F(Global_Ser_MsgPack, WriteRead) +TEST_F(Global_Ser_Msgpack, String) +{ + String str1 = u"Hello World!"; + + ByteArray data = msgpack::pack(str1); + + String str2; + + bool ok = msgpack::unpack(data, str2); + + EXPECT_TRUE(ok); + EXPECT_EQ(str1, str2); +} + +TEST_F(Global_Ser_Msgpack, Number) +{ + number_t num1_1 = 0.34f; + number_t num1_2 = 46.0; + number_t num1_3 = 57; + + ByteArray data = msgpack::pack(num1_1, num1_2, num1_3); + + number_t num2_1; + number_t num2_2; + number_t num2_3; + + bool ok = msgpack::unpack(data, num2_1, num2_2, num2_3); + + EXPECT_TRUE(ok); + EXPECT_EQ(num1_1, num2_1); + EXPECT_EQ(num1_2, num2_2); + EXPECT_EQ(num1_3, num2_3); +} + +TEST_F(Global_Ser_Msgpack, ObjectWithPack) { ByteArray data; // Write { - Object obj; + ObjectWithPack obj; + obj.i32 = 12; obj.ui64 = 42; - obj.real = 4.2; + obj.float32 = 0.42f; + obj.float64 = 42.42; obj.str = "42"; - obj.vi = { 4, 2 }; obj.b = true; + obj.vi = { 4, 2 }; obj.map = { { "42", 42 } }; - // origin - std::vector vd = msgpack::pack(obj); - - // muse wrap - data = MsgPack::pack(obj.ui64, obj.real, obj.str, obj.b, obj.vi, obj.map); - - EXPECT_TRUE(data == ByteArray::fromRawData(&vd[0], vd.size())); + data = msgpack::pack(obj); } // Read { - // origin - // Object obj = msgpack::unpack(data.constData(), data.size()); - - // muse wrap - Object obj; - bool ok = MsgPack::unpack(data, obj.ui64, obj.real, obj.str, obj.b, obj.vi, obj.map); + ObjectWithPack obj; + bool ok = msgpack::unpack(data, obj); EXPECT_TRUE(ok); + EXPECT_EQ(obj.i32, 12); EXPECT_EQ(obj.ui64, 42); - EXPECT_DOUBLE_EQ(obj.real, 4.2); + EXPECT_FLOAT_EQ(obj.float32, 0.42f); + EXPECT_DOUBLE_EQ(obj.float64, 42.42); EXPECT_EQ(obj.str, "42"); EXPECT_EQ(obj.b, true); EXPECT_EQ(obj.vi.size(), 2); @@ -94,3 +144,27 @@ TEST_F(Global_Ser_MsgPack, WriteRead) EXPECT_EQ(obj.map["42"], 42); } } + +TEST_F(Global_Ser_Msgpack, ObjectCustom) +{ + ByteArray data; + + // Write + { + ObjectCustom obj; + obj.i32 = 12; + obj.str = "ha ha ha"; + + data = msgpack::pack(obj); + } + + // Read + { + ObjectCustom obj; + bool ok = msgpack::unpack(data, obj); + EXPECT_TRUE(ok); + + EXPECT_EQ(obj.i32, 12); + EXPECT_EQ(obj.str, "ha ha ha"); + } +} diff --git a/src/framework/global/thirdparty/cppack/README.md b/src/framework/global/thirdparty/cppack/README.md deleted file mode 100644 index a1f7b68435a13..0000000000000 --- a/src/framework/global/thirdparty/cppack/README.md +++ /dev/null @@ -1,53 +0,0 @@ -https://github.com/mikeloomisgg/cppack -# cppack -A modern (c++17 required) implementation of the [msgpack spec](https://github.com/msgpack/msgpack/blob/master/spec.md). - -Msgpack is a binary serialization specification. It allows you to save and load application objects like classes and structs over networks, to files, and between programs and even different languages. - -Check out [this blog](https://mikeloomisgg.github.io/2019-07-02-making-a-serialization-library/) for my rational creating this library. - -## Features -- Fast and compact -- Full test coverage -- Easy to use -- Automatic type handling -- Open source MIT license -- Easy error handling - -### Single Header only template library -Want to use this library? Just #include the header and you're good to go. Its less than 1000 lines of code. - - -### Cereal style packaging -Easily pack objects into byte arrays using a pack free function: - -```c++ -struct Person { - std::string name; - uint16_t age; - std::vector aliases; - - template - void msgpack(T &pack) { - pack(name, age, aliases); - } -}; - -int main() { - auto person = Person{"John", 22, {"Ripper", "Silverhand"}}; - - auto data = msgpack::pack(person); // Pack your object - auto john = msgpack::unpack(data.data()); // Unpack it -} -``` - -[More Examples](msgpack/tests/examples.cpp) - - -### Roadmap -- Support for extension types - - The msgpack spec allows for additional types to be enumerated as Extensions. If reasonable use cases come about for this feature then it may be added. -- Name/value pairs - - The msgpack spec uses the 'map' type differently than this library. This library implements maps in which key/value pairs must all have the same value types. -- Endian conversion shortcuts - - On platforms that already hold types in big endian, the serialization could be optimized using type traits. diff --git a/src/framework/global/thirdparty/cppack/msgpack.hpp b/src/framework/global/thirdparty/cppack/msgpack.hpp deleted file mode 100644 index c8333f5121da2..0000000000000 --- a/src/framework/global/thirdparty/cppack/msgpack.hpp +++ /dev/null @@ -1,1058 +0,0 @@ -// -// Created by Mike Loomis on 6/22/2019. -// - -#ifndef CPPACK_PACKER_HPP -#define CPPACK_PACKER_HPP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace msgpack { -enum class UnpackerError { - OutOfRange = 1 -}; - -struct UnpackerErrCategory : public std::error_category { - public: - const char *name() const noexcept override { - return "unpacker"; - }; - - std::string message(int ev) const override { - switch (static_cast(ev)) { - case msgpack::UnpackerError::OutOfRange: - return "tried to dereference out of range during deserialization"; - default: - return "(unrecognized error)"; - } - }; -}; - -const UnpackerErrCategory theUnpackerErrCategory{}; - -inline -std::error_code make_error_code(msgpack::UnpackerError e) { - return {static_cast(e), theUnpackerErrCategory}; -} -} - -namespace std { -template<> -struct is_error_code_enum : public true_type {}; -} - -namespace msgpack { - -enum FormatConstants : uint8_t { - // positive fixint = 0x00 - 0x7f - // fixmap = 0x80 - 0x8f - // fixarray = 0x90 - 0x9a - // fixstr = 0xa0 - 0xbf - // negative fixint = 0xe0 - 0xff - - nil = 0xc0, - false_bool = 0xc2, - true_bool = 0xc3, - bin8 = 0xc4, - bin16 = 0xc5, - bin32 = 0xc6, - ext8 = 0xc7, - ext16 = 0xc8, - ext32 = 0xc9, - float32 = 0xca, - float64 = 0xcb, - uint8 = 0xcc, - uint16 = 0xcd, - uint32 = 0xce, - uint64 = 0xcf, - int8 = 0xd0, - int16 = 0xd1, - int32 = 0xd2, - int64 = 0xd3, - fixext1 = 0xd4, - fixext2 = 0xd5, - fixext4 = 0xd6, - fixext8 = 0xd7, - fixext16 = 0xd8, - str8 = 0xd9, - str16 = 0xda, - str32 = 0xdb, - array16 = 0xdc, - array32 = 0xdd, - map16 = 0xde, - map32 = 0xdf -}; - -template -struct is_container { - static const bool value = false; -}; - -template -struct is_container > { - static const bool value = true; -}; - -template -struct is_container > { - static const bool value = true; -}; - -template -struct is_container > { - static const bool value = true; -}; - -template -struct is_container > { - static const bool value = true; -}; - -template -struct is_container > { - static const bool value = true; -}; - -template -struct is_stdarray { - static const bool value = false; -}; - -template -struct is_stdarray> { - static const bool value = true; -}; - -template -struct is_map { - static const bool value = false; -}; - -template -struct is_map > { - static const bool value = true; -}; - -template -struct is_map > { - static const bool value = true; -}; - -class Packer { - public: - - template - void operator()(const Types &... args) { - (pack_type(std::forward(args)), ...); - } - - template - void process(const Types &... args) { - (pack_type(std::forward(args)), ...); - } - - const std::vector &vector() const { - return serialized_object; - } - - void clear() { - serialized_object.clear(); - } - - private: - std::vector serialized_object; - - template - void pack_type(const T &value) { - if constexpr(is_map::value) { - pack_map(value); - } else if constexpr (is_container::value || is_stdarray::value) { - pack_array(value); - } else { - auto recursive_packer = Packer{}; - const_cast(value).pack(recursive_packer); - pack_type(recursive_packer.vector()); - } - } - - template - void pack_type(const std::chrono::time_point &value) { - pack_type(value.time_since_epoch().count()); - } - - template - void pack_array(const T &array) { - if (array.size() < 16) { - auto size_mask = uint8_t(0b10010000); - serialized_object.emplace_back(uint8_t(array.size() | size_mask)); - } else if (array.size() < std::numeric_limits::max()) { - serialized_object.emplace_back(array16); - for (auto i = sizeof(uint16_t); i > 0; --i) { - serialized_object.emplace_back(uint8_t(array.size() >> (8U * (i - 1)) & 0xff)); - } - } else if (array.size() < std::numeric_limits::max()) { - serialized_object.emplace_back(array32); - for (auto i = sizeof(uint32_t); i > 0; --i) { - serialized_object.emplace_back(uint8_t(array.size() >> (8U * (i - 1)) & 0xff)); - } - } else { - return; // Give up if string is too long - } - for (const auto &elem : array) { - pack_type(elem); - } - } - - template - void pack_map(const T &map) { - if (map.size() < 16) { - auto size_mask = uint8_t(0b10000000); - serialized_object.emplace_back(uint8_t(map.size() | size_mask)); - } else if (map.size() < std::numeric_limits::max()) { - serialized_object.emplace_back(map16); - for (auto i = sizeof(uint16_t); i > 0; --i) { - serialized_object.emplace_back(uint8_t(map.size() >> (8U * (i - 1)) & 0xff)); - } - } else if (map.size() < std::numeric_limits::max()) { - serialized_object.emplace_back(map32); - for (auto i = sizeof(uint32_t); i > 0; --i) { - serialized_object.emplace_back(uint8_t(map.size() >> (8U * (i - 1)) & 0xff)); - } - } - for (const auto &elem : map) { - pack_type(std::get<0>(elem)); - pack_type(std::get<1>(elem)); - } - } - - std::bitset<64> twos_complement(int64_t value) { - if (value < 0) { - auto abs_v = llabs(value); - return ~abs_v + 1; - } else { - return {(uint64_t) value}; - } - } - - std::bitset<32> twos_complement(int32_t value) { - if (value < 0) { - auto abs_v = abs(value); - return ~abs_v + 1; - } else { - return {(uint32_t) value}; - } - } - - std::bitset<16> twos_complement(int16_t value) { - if (value < 0) { - auto abs_v = abs(value); - return ~abs_v + 1; - } else { - return {(uint16_t) value}; - } - } - - std::bitset<8> twos_complement(int8_t value) { - if (value < 0) { - auto abs_v = abs(value); - return ~abs_v + 1; - } else { - return {(uint8_t) value}; - } - } -}; - -template<> -inline -void Packer::pack_type(const int8_t &value) { - if (value > 31 || value < -32) { - serialized_object.emplace_back(int8); - } - serialized_object.emplace_back(uint8_t(twos_complement(value).to_ulong())); -} - -template<> -inline -void Packer::pack_type(const int16_t &value) { - if (abs(value) < abs(std::numeric_limits::min())) { - pack_type(int8_t(value)); - } else { - serialized_object.emplace_back(int16); - auto serialize_value = uint16_t(twos_complement(value).to_ulong()); - for (auto i = sizeof(value); i > 0; --i) { - serialized_object.emplace_back(uint8_t(serialize_value >> (8U * (i - 1)) & 0xff)); - } - } -} - -template<> -inline -void Packer::pack_type(const int32_t &value) { - if (abs(value) < abs(std::numeric_limits::min())) { - pack_type(int16_t(value)); - } else { - serialized_object.emplace_back(int32); - auto serialize_value = uint32_t(twos_complement(value).to_ulong()); - for (auto i = sizeof(value); i > 0; --i) { - serialized_object.emplace_back(uint8_t(serialize_value >> (8U * (i - 1)) & 0xff)); - } - } -} - -template<> -inline -void Packer::pack_type(const int64_t &value) { - if (llabs(value) < llabs(std::numeric_limits::min()) && value != std::numeric_limits::min()) { - pack_type(int32_t(value)); - } else { - serialized_object.emplace_back(int64); - auto serialize_value = uint64_t(twos_complement(value).to_ullong()); - for (auto i = sizeof(value); i > 0; --i) { - serialized_object.emplace_back(uint8_t(serialize_value >> (8U * (i - 1)) & 0xff)); - } - } -} - -template<> -inline -void Packer::pack_type(const uint8_t &value) { - if (value <= 0x7f) { - serialized_object.emplace_back(value); - } else { - serialized_object.emplace_back(uint8); - serialized_object.emplace_back(value); - } -} - -template<> -inline -void Packer::pack_type(const uint16_t &value) { - if (value > std::numeric_limits::max()) { - serialized_object.emplace_back(uint16); - for (auto i = sizeof(value); i > 0U; --i) { - serialized_object.emplace_back(uint8_t(value >> (8U * (i - 1)) & 0xff)); - } - } else { - pack_type(uint8_t(value)); - } -} - -template<> -inline -void Packer::pack_type(const uint32_t &value) { - if (value > std::numeric_limits::max()) { - serialized_object.emplace_back(uint32); - for (auto i = sizeof(value); i > 0U; --i) { - serialized_object.emplace_back(uint8_t(value >> (8U * (i - 1)) & 0xff)); - } - } else { - pack_type(uint16_t(value)); - } -} - -template<> -inline -void Packer::pack_type(const uint64_t &value) { - if (value > std::numeric_limits::max()) { - serialized_object.emplace_back(uint64); - for (auto i = sizeof(value); i > 0U; --i) { - serialized_object.emplace_back(uint8_t(value >> (8U * (i - 1)) & 0xff)); - } - } else { - pack_type(uint32_t(value)); - } -} - -template<> -inline -void Packer::pack_type(const std::nullptr_t &/*value*/) { - serialized_object.emplace_back(nil); -} - -template<> -inline -void Packer::pack_type(const bool &value) { - if (value) { - serialized_object.emplace_back(true_bool); - } else { - serialized_object.emplace_back(false_bool); - } -} - -template<> -inline -void Packer::pack_type(const float &value) { - double integral_part; - auto fractional_remainder = float(modf(value, &integral_part)); - - if (fractional_remainder == 0) { // Just pack as int - pack_type(int64_t(integral_part)); - } else { - static_assert(std::numeric_limits::radix == 2); // TODO: Handle decimal floats - auto exponent = ilogb(value); - float full_mantissa = value / float(scalbn(1.0, exponent)); - auto sign_mask = std::bitset<32>(uint32_t(std::signbit(full_mantissa)) << 31); - auto excess_127_exponent_mask = std::bitset<32>(uint32_t(exponent + 127) << 23); - auto normalized_mantissa_mask = std::bitset<32>(); - float implied_mantissa = fabs(full_mantissa) - 1.0f; - for (auto i = 23U; i > 0; --i) { - integral_part = 0; - implied_mantissa *= 2; - implied_mantissa = float(modf(implied_mantissa, &integral_part)); - if (uint8_t(integral_part) == 1) { - normalized_mantissa_mask |= std::bitset<32>(uint32_t(1 << (i - 1))); - } - } - - uint32_t ieee754_float32 = (sign_mask | excess_127_exponent_mask | normalized_mantissa_mask).to_ulong(); - serialized_object.emplace_back(float32); - for (auto i = sizeof(uint32_t); i > 0; --i) { - serialized_object.emplace_back(uint8_t(ieee754_float32 >> (8U * (i - 1)) & 0xff)); - } - } -} - -template<> -inline -void Packer::pack_type(const double &value) { - double integral_part; - double fractional_remainder = modf(value, &integral_part); - - if (fractional_remainder == 0) { // Just pack as int - pack_type(int64_t(integral_part)); - } else { - static_assert(std::numeric_limits::radix == 2); // TODO: Handle decimal floats - auto exponent = ilogb(value); - double full_mantissa = value / scalbn(1.0, exponent); - auto sign_mask = std::bitset<64>(uint64_t(std::signbit(full_mantissa)) << 63); - auto excess_127_exponent_mask = std::bitset<64>(uint64_t(exponent + 1023) << 52); - auto normalized_mantissa_mask = std::bitset<64>(); - double implied_mantissa = fabs(full_mantissa) - 1.0f; - - for (auto i = 52U; i > 0; --i) { - integral_part = 0; - implied_mantissa *= 2; - implied_mantissa = modf(implied_mantissa, &integral_part); - if (uint8_t(integral_part) == 1) { - normalized_mantissa_mask |= std::bitset<64>(uint64_t(1) << (i - 1)); - } - } - auto ieee754_float64 = (sign_mask | excess_127_exponent_mask | normalized_mantissa_mask).to_ullong(); - serialized_object.emplace_back(float64); - for (auto i = sizeof(ieee754_float64); i > 0; --i) { - serialized_object.emplace_back(uint8_t(ieee754_float64 >> (8U * (i - 1)) & 0xff)); - } - } -} - -template<> -inline -void Packer::pack_type(const std::string &value) { - if (value.size() < 32) { - serialized_object.emplace_back(uint8_t(value.size()) | 0b10100000); - } else if (value.size() < std::numeric_limits::max()) { - serialized_object.emplace_back(str8); - serialized_object.emplace_back(uint8_t(value.size())); - } else if (value.size() < std::numeric_limits::max()) { - serialized_object.emplace_back(str16); - for (auto i = sizeof(uint16_t); i > 0; --i) { - serialized_object.emplace_back(uint8_t(value.size() >> (8U * (i - 1)) & 0xff)); - } - } else if (value.size() < std::numeric_limits::max()) { - serialized_object.emplace_back(str32); - for (auto i = sizeof(uint32_t); i > 0; --i) { - serialized_object.emplace_back(uint8_t(value.size() >> (8U * (i - 1)) & 0xff)); - } - } else { - return; // Give up if string is too long - } - for (char i : value) { - serialized_object.emplace_back(static_cast(i)); - } -} - -template<> -inline -void Packer::pack_type(const std::vector &value) { - if (value.size() < std::numeric_limits::max()) { - serialized_object.emplace_back(bin8); - serialized_object.emplace_back(uint8_t(value.size())); - } else if (value.size() < std::numeric_limits::max()) { - serialized_object.emplace_back(bin16); - for (auto i = sizeof(uint16_t); i > 0; --i) { - serialized_object.emplace_back(uint8_t(value.size() >> (8U * (i - 1)) & 0xff)); - } - } else if (value.size() < std::numeric_limits::max()) { - serialized_object.emplace_back(bin32); - for (auto i = sizeof(uint32_t); i > 0; --i) { - serialized_object.emplace_back(uint8_t(value.size() >> (8U * (i - 1)) & 0xff)); - } - } else { - return; // Give up if vector is too large - } - for (const auto &elem : value) { - serialized_object.emplace_back(elem); - } -} - -class Unpacker { - public: - Unpacker() : data_pointer(nullptr), data_end(nullptr) {}; - - Unpacker(const uint8_t *data_start, std::size_t bytes) - : data_pointer(data_start), data_end(data_start + bytes) {}; - - template - void operator()(Types &... args) { - (unpack_type(std::forward(args)), ...); - } - - template - void process(Types &... args) { - (unpack_type(std::forward(args)), ...); - } - - void set_data(const uint8_t *pointer, std::size_t size) { - data_pointer = pointer; - data_end = data_pointer + size; - } - - std::error_code ec{}; - - private: - const uint8_t *data_pointer; - const uint8_t *data_end; - - uint8_t safe_data() { - if (data_pointer < data_end) - return *data_pointer; - ec = UnpackerError::OutOfRange; - return 0; - } - - void safe_increment(int64_t bytes = 1) { - if (data_end - data_pointer >= 0) { - data_pointer += bytes; - } else { - ec = UnpackerError::OutOfRange; - } - } - - template - void unpack_type(T &value) { - if constexpr(is_map::value) { - unpack_map(value); - } else if constexpr (is_container::value) { - unpack_array(value); - } else if constexpr (is_stdarray::value) { - unpack_stdarray(value); - } else { - auto recursive_data = std::vector{}; - unpack_type(recursive_data); - - auto recursive_unpacker = Unpacker{recursive_data.data(), recursive_data.size()}; - value.pack(recursive_unpacker); - ec = recursive_unpacker.ec; - } - } - - template - void unpack_type(std::chrono::time_point &value) { - using RepType = typename std::chrono::time_point::rep; - using DurationType = Duration; - using TimepointType = typename std::chrono::time_point; - auto placeholder = RepType{}; - unpack_type(placeholder); - value = TimepointType(DurationType(placeholder)); - } - - template - void unpack_array(T &array) { - using ValueType = typename T::value_type; - if (safe_data() == array32) { - safe_increment(); - std::size_t array_size = 0; - for (auto i = sizeof(uint32_t); i > 0; --i) { - array_size += uint32_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - std::vector x{}; - for (auto i = 0U; i < array_size; ++i) { - ValueType val{}; - unpack_type(val); - array.emplace_back(val); - } - } else if (safe_data() == array16) { - safe_increment(); - std::size_t array_size = 0; - for (auto i = sizeof(uint16_t); i > 0; --i) { - array_size += uint16_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - for (auto i = 0U; i < array_size; ++i) { - ValueType val{}; - unpack_type(val); - array.emplace_back(val); - } - } else { - std::size_t array_size = safe_data() & 0b00001111; - safe_increment(); - for (auto i = 0U; i < array_size; ++i) { - ValueType val{}; - unpack_type(val); - array.emplace_back(val); - } - } - } - - template - void unpack_stdarray(T &array) { - using ValueType = typename T::value_type; - auto vec = std::vector{}; - unpack_array(vec); - std::copy(vec.begin(), vec.end(), array.begin()); - } - - template - void unpack_map(T &map) { - using KeyType = typename T::key_type; - using MappedType = typename T::mapped_type; - if (safe_data() == map32) { - safe_increment(); - std::size_t map_size = 0; - for (auto i = sizeof(uint32_t); i > 0; --i) { - map_size += uint32_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - std::vector x{}; - for (auto i = 0U; i < map_size; ++i) { - KeyType key{}; - MappedType value{}; - unpack_type(key); - unpack_type(value); - map.insert_or_assign(key, value); - } - } else if (safe_data() == map16) { - safe_increment(); - std::size_t map_size = 0; - for (auto i = sizeof(uint16_t); i > 0; --i) { - map_size += uint16_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - for (auto i = 0U; i < map_size; ++i) { - KeyType key{}; - MappedType value{}; - unpack_type(key); - unpack_type(value); - map.insert_or_assign(key, value); - } - } else { - std::size_t map_size = safe_data() & 0b00001111; - safe_increment(); - for (auto i = 0U; i < map_size; ++i) { - KeyType key{}; - MappedType value{}; - unpack_type(key); - unpack_type(value); - map.insert_or_assign(key, value); - } - } - } -}; - -template<> -inline -void Unpacker::unpack_type(int8_t &value) { - if (safe_data() == int8) { - safe_increment(); - value = safe_data(); - safe_increment(); - } else { - value = safe_data(); - safe_increment(); - } -} - -template<> -inline -void Unpacker::unpack_type(int16_t &value) { - if (safe_data() == int16) { - safe_increment(); - std::bitset<16> bits; - for (auto i = sizeof(uint16_t); i > 0; --i) { - bits |= uint16_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - if (bits[15]) { - value = -1 * (uint16_t((~bits).to_ulong()) + 1); - } else { - value = uint16_t(bits.to_ulong()); - } - } else if (safe_data() == int8) { - int8_t val; - unpack_type(val); - value = val; - } else { - value = safe_data(); - safe_increment(); - } -} - -template<> -inline -void Unpacker::unpack_type(int32_t &value) { - if (safe_data() == int32) { - safe_increment(); - std::bitset<32> bits; - for (auto i = sizeof(uint32_t); i > 0; --i) { - bits |= uint32_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - if (bits[31]) { - value = -1 * ((~bits).to_ulong() + 1); - } else { - value = bits.to_ulong(); - } - } else if (safe_data() == int16) { - int16_t val; - unpack_type(val); - value = val; - } else if (safe_data() == int8) { - int8_t val; - unpack_type(val); - value = val; - } else { - value = safe_data(); - safe_increment(); - } -} - -template<> -inline -void Unpacker::unpack_type(int64_t &value) { - if (safe_data() == int64) { - safe_increment(); - std::bitset<64> bits; - for (auto i = sizeof(value); i > 0; --i) { - bits |= std::bitset<8>(safe_data()).to_ullong() << 8 * (i - 1); - safe_increment(); - } - if (bits[63]) { - value = -1 * ((~bits).to_ullong() + 1); - } else { - value = bits.to_ullong(); - } - } else if (safe_data() == int32) { - int32_t val; - unpack_type(val); - value = val; - } else if (safe_data() == int16) { - int16_t val; - unpack_type(val); - value = val; - } else if (safe_data() == int8) { - int8_t val; - unpack_type(val); - value = val; - } else { - value = safe_data(); - safe_increment(); - } -} - -template<> -inline -void Unpacker::unpack_type(uint8_t &value) { - if (safe_data() == uint8) { - safe_increment(); - value = safe_data(); - safe_increment(); - } else { - value = safe_data(); - safe_increment(); - } -} - -template<> -inline -void Unpacker::unpack_type(uint16_t &value) { - if (safe_data() == uint16) { - safe_increment(); - for (auto i = sizeof(uint16_t); i > 0; --i) { - value += safe_data() << 8 * (i - 1); - safe_increment(); - } - } else if (safe_data() == uint8) { - safe_increment(); - value = safe_data(); - safe_increment(); - } else { - value = safe_data(); - safe_increment(); - } -} - -template<> -inline -void Unpacker::unpack_type(uint32_t &value) { - if (safe_data() == uint32) { - safe_increment(); - for (auto i = sizeof(uint32_t); i > 0; --i) { - value += safe_data() << 8 * (i - 1); - safe_increment(); - } - } else if (safe_data() == uint16) { - safe_increment(); - for (auto i = sizeof(uint16_t); i > 0; --i) { - value += safe_data() << 8 * (i - 1); - safe_increment(); - } - } else if (safe_data() == uint8) { - safe_increment(); - value = safe_data(); - safe_increment(); - } else { - value = safe_data(); - safe_increment(); - } -} - -template<> -inline -void Unpacker::unpack_type(uint64_t &value) { - if (safe_data() == uint64) { - safe_increment(); - for (auto i = sizeof(uint64_t); i > 0; --i) { - value += uint64_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - } else if (safe_data() == uint32) { - safe_increment(); - for (auto i = sizeof(uint32_t); i > 0; --i) { - value += uint64_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - data_pointer++; - } else if (safe_data() == uint16) { - safe_increment(); - for (auto i = sizeof(uint16_t); i > 0; --i) { - value += uint64_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - } else if (safe_data() == uint8) { - safe_increment(); - value = safe_data(); - safe_increment(); - } else { - value = safe_data(); - safe_increment(); - } -} - -template<> -inline -void Unpacker::unpack_type(std::nullptr_t &/*value*/) { - safe_increment(); -} - -template<> -inline -void Unpacker::unpack_type(bool &value) { - value = safe_data() != 0xc2; - safe_increment(); -} - -template<> -inline -void Unpacker::unpack_type(float &value) { - if (safe_data() == float32) { - safe_increment(); - uint32_t data = 0; - for (auto i = sizeof(uint32_t); i > 0; --i) { - data += safe_data() << 8 * (i - 1); - safe_increment(); - } - auto bits = std::bitset<32>(data); - auto mantissa = 1.0f; - for (auto i = 23U; i > 0; --i) { - if (bits[i - 1]) { - mantissa += 1.0f / (1 << (24 - i)); - } - } - if (bits[31]) { - mantissa *= -1; - } - uint8_t exponent = 0; - for (auto i = 0U; i < 8; ++i) { - exponent += bits[i + 23] << i; - } - exponent -= 127; - value = ldexp(mantissa, exponent); - } else { - if (safe_data() == int8 || safe_data() == int16 || safe_data() == int32 || safe_data() == int64) { - int64_t val = 0; - unpack_type(val); - value = float(val); - } else { - uint64_t val = 0; - unpack_type(val); - value = float(val); - } - } -} - -template<> -inline -void Unpacker::unpack_type(double &value) { - if (safe_data() == float64) { - safe_increment(); - uint64_t data = 0; - for (auto i = sizeof(uint64_t); i > 0; --i) { - data += uint64_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - auto bits = std::bitset<64>(data); - auto mantissa = 1.0; - for (auto i = 52U; i > 0; --i) { - if (bits[i - 1]) { - mantissa += 1.0 / (uint64_t(1) << (53 - i)); - } - } - if (bits[63]) { - mantissa *= -1; - } - uint16_t exponent = 0; - for (auto i = 0U; i < 11; ++i) { - exponent += bits[i + 52] << i; - } - exponent -= 1023; - value = ldexp(mantissa, exponent); - } else { - if (safe_data() == int8 || safe_data() == int16 || safe_data() == int32 || safe_data() == int64) { - int64_t val = 0; - unpack_type(val); - value = float(val); - } else { - uint64_t val = 0; - unpack_type(val); - value = float(val); - } - } -} - -template<> -inline -void Unpacker::unpack_type(std::string &value) { - std::size_t str_size = 0; - if (safe_data() == str32) { - safe_increment(); - for (auto i = sizeof(uint32_t); i > 0; --i) { - str_size += uint32_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - } else if (safe_data() == str16) { - safe_increment(); - for (auto i = sizeof(uint16_t); i > 0; --i) { - str_size += uint16_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - } else if (safe_data() == str8) { - safe_increment(); - for (auto i = sizeof(uint8_t); i > 0; --i) { - str_size += uint8_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - } else { - str_size = safe_data() & 0b00011111; - safe_increment(); - } - if (data_pointer + str_size <= data_end) { - value = std::string{data_pointer, data_pointer + str_size}; - safe_increment(str_size); - } else { - ec = UnpackerError::OutOfRange; - } -} - -template<> -inline -void Unpacker::unpack_type(std::vector &value) { - std::size_t bin_size = 0; - if (safe_data() == bin32) { - safe_increment(); - for (auto i = sizeof(uint32_t); i > 0; --i) { - bin_size += uint32_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - } else if (safe_data() == bin16) { - safe_increment(); - for (auto i = sizeof(uint16_t); i > 0; --i) { - bin_size += uint16_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - } else { - safe_increment(); - for (auto i = sizeof(uint8_t); i > 0; --i) { - bin_size += uint8_t(safe_data()) << 8 * (i - 1); - safe_increment(); - } - } - if (data_pointer + bin_size <= data_end) { - value = std::vector{data_pointer, data_pointer + bin_size}; - safe_increment(bin_size); - } else { - ec = UnpackerError::OutOfRange; - } -} - -template -std::vector pack(PackableObject &obj) { - auto packer = Packer{}; - obj.pack(packer); - return packer.vector(); -} - -template -std::vector pack(PackableObject &&obj) { - auto packer = Packer{}; - obj.pack(packer); - return packer.vector(); -} - -template -UnpackableObject unpack(const uint8_t *data_start, const std::size_t size, std::error_code &ec) { - auto obj = UnpackableObject{}; - auto unpacker = Unpacker(data_start, size); - obj.pack(unpacker); - ec = unpacker.ec; - return obj; -} - -template -UnpackableObject unpack(const uint8_t *data_start, const std::size_t size) { - std::error_code ec{}; - return unpack(data_start, size, ec); -} - -template -UnpackableObject unpack(const std::vector &data, std::error_code &ec) { - return unpack(data.data(), data.size(), ec); -} - -template -UnpackableObject unpack(const std::vector &data) { - std::error_code ec; - return unpack(data.data(), data.size(), ec); -} -} - -#endif //CPPACK_PACKER_HPP diff --git a/src/framework/global/thirdparty/kors_msgpack/.gitignore b/src/framework/global/thirdparty/kors_msgpack/.gitignore new file mode 100644 index 0000000000000..996ee8959f07b --- /dev/null +++ b/src/framework/global/thirdparty/kors_msgpack/.gitignore @@ -0,0 +1,2 @@ +*.user +build* diff --git a/src/framework/global/thirdparty/kors_msgpack/LICENSE b/src/framework/global/thirdparty/kors_msgpack/LICENSE new file mode 100644 index 0000000000000..b09d4be686dbd --- /dev/null +++ b/src/framework/global/thirdparty/kors_msgpack/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Igor Korsukov + +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. diff --git a/src/framework/global/thirdparty/kors_msgpack/README.md b/src/framework/global/thirdparty/kors_msgpack/README.md new file mode 100644 index 0000000000000..2507b353b1768 --- /dev/null +++ b/src/framework/global/thirdparty/kors_msgpack/README.md @@ -0,0 +1,2 @@ +# kors_msgpack +Simple implementation of packing in msgpack for C++ diff --git a/src/framework/global/thirdparty/kors_msgpack/example/CMakeLists.txt b/src/framework/global/thirdparty/kors_msgpack/example/CMakeLists.txt new file mode 100644 index 0000000000000..cf3140bb4b68e --- /dev/null +++ b/src/framework/global/thirdparty/kors_msgpack/example/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.14) + +project(msgpack_example LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +add_executable(${PROJECT_NAME} + main.cpp + msgpack.h +) diff --git a/src/framework/global/thirdparty/kors_msgpack/example/main.cpp b/src/framework/global/thirdparty/kors_msgpack/example/main.cpp new file mode 100644 index 0000000000000..c82f3b2c373b9 --- /dev/null +++ b/src/framework/global/thirdparty/kors_msgpack/example/main.cpp @@ -0,0 +1,466 @@ +#include +#include +#include +#include +#include +#include + +#include "msgpack.h" + +using namespace app::msgpack; + +constexpr bool ALL_TEST = false; +constexpr bool NIL_TEST = false; +constexpr bool BOOL_TEST = false; +constexpr bool INT8_TEST = false; +constexpr bool INT16_TEST = false; +constexpr bool INT32_TEST = false; +constexpr bool INT64_TEST = false; +constexpr bool REAL_TEST = false; +constexpr bool STR_TEST = false; +constexpr bool BIN_TEST = false; +constexpr bool ARR_TEST = false; +constexpr bool MAP_TEST = false; +constexpr bool CUSTOM_TEST = true; + +inline constexpr bool is_equal(float v1, float v2) +{ + constexpr float compare_float_epsilon = 1e-5f; + return std::abs(v1 - v2) <= std::max(std::abs(v1), std::abs(v2)) * compare_float_epsilon; +} + +inline constexpr bool is_equal(double v1, double v2) +{ + constexpr double compare_float_epsilon = 1e-9; + return std::abs(v1 - v2) <= std::max(std::abs(v1), std::abs(v2)) * compare_float_epsilon; +} + +struct ObjectWithPack { + int i = 0; + std::string str; + + template + void pack(T& p) + { + p(i, str); + } + + bool operator==(const ObjectWithPack& o) const + { + return i == o.i && str == o.str; + } +}; + +struct ObjectWithPackUnPack { + int i = 0; + std::string str; + + template + void pack(T& p) const + { + p(i, str); + } + + template + void unpack(T& p) + { + p(i, str); + } + + bool operator==(const ObjectWithPackUnPack& o) const + { + return i == o.i && str == o.str; + } +}; + +struct ObjectWithLowLevel { + int i = 0; + std::string str; + + void pack(std::vector& data) const + { + Packer::pack(data, i, str); + } + + void unpack(Cursor& c) + { + UnPacker::unpack(c, i, str); + } + + bool operator==(const ObjectWithPackUnPack& o) const + { + return i == o.i && str == o.str; + } +}; + +struct ObjectCustomPackUnPack { + int i = 0; + std::string str; + + bool operator==(const ObjectCustomPackUnPack& o) const + { + return i == o.i && str == o.str; + } +}; + +template +void pack_custom(T& p, const ObjectCustomPackUnPack& o) +{ + p(o.i, o.str); +} + +template +void unpack_custom(T& p, ObjectCustomPackUnPack& o) +{ + p(o.i, o.str); +} + +struct ObjectCustomLowLevel { + int i = 0; + std::string str; + + bool operator==(const ObjectCustomLowLevel& o) const + { + return i == o.i && str == o.str; + } +}; + +void pack_custom(std::vector& data, const ObjectCustomLowLevel& o) +{ + Packer::pack(data, o.i, o.str); +} + +bool unpack_custom(Cursor& c, ObjectCustomLowLevel& o) +{ + return UnPacker::unpack(c, o.i, o.str); +} + +int main(int argc, char* argv[]) +{ + std::cout << "Hello World, I am MsgPack" << std::endl; + + // nil + if (ALL_TEST || NIL_TEST) { + std::vector data; + Packer::pack(data, nullptr); + std::nullptr_t null; + bool ok = UnPacker::unpack(data, null); + + assert(ok); + } + + // bool + if (ALL_TEST || BOOL_TEST) { + std::vector data; + bool val1_t = true; + bool val1_f = false; + Packer::pack(data, val1_t, val1_f); + + bool val2_t = false; + bool val2_f = true; + bool ok = UnPacker::unpack(data, val2_t, val2_f); + + assert(ok); + assert(val1_t == val2_t); + assert(val1_f == val2_f); + } + + // int8_t, uint8_t + if (ALL_TEST || INT8_TEST) { + std::vector data; + int8_t val1_1 = 126; // positive fixint + int8_t val1_2 = -5; // negative fixint + int8_t val1_3 = -42; // regular int8_t + uint8_t val1_4 = 124; // positive fixint + uint8_t val1_5 = 234; // regular uint8_t + Packer::pack(data, val1_1, val1_2, val1_3, val1_4, val1_5); + + int8_t val2_1 = 0; + int8_t val2_2 = 0; + int8_t val2_3 = 0; + uint8_t val2_4 = 0; + uint8_t val2_5 = 0; + bool ok = UnPacker::unpack(data, val2_1, val2_2, val2_3, val2_4, val2_5); + + assert(ok); + assert(val1_1 == val2_1); + assert(val1_2 == val2_2); + assert(val1_3 == val2_3); + assert(val1_4 == val2_4); + assert(val1_5 == val2_5); + + // unpack 8 to 16 + int16_t val3_1 = 0; + int16_t val3_2 = 0; + int16_t val3_3 = 0; + uint16_t val3_4 = 0; + uint16_t val3_5 = 0; + ok = UnPacker::unpack(data, val3_1, val3_2, val3_3, val3_4, val3_5); + + assert(ok); + assert(val1_1 == val3_1); + assert(val1_2 == val3_2); + assert(val1_3 == val3_3); + assert(val1_4 == val3_4); + assert(val1_5 == val3_5); + } + + // int16_t, uint16_t + if (ALL_TEST || INT16_TEST) { + std::vector data; + int16_t val1_1 = 126; // positive fixint + int16_t val1_2 = -5; // negative fixint + int16_t val1_3 = 346; // regular int16_t + int16_t val1_4 = -42; // regular int16_t + uint16_t val1_5 = 124; // positive fixint + uint16_t val1_6 = 348; // regular uint16_t + Packer::pack(data, val1_1, val1_2, val1_3, val1_4, val1_5, val1_6); + + int16_t val2_1 = 0; + int16_t val2_2 = 0; + int16_t val2_3 = 0; + int16_t val2_4 = 0; + uint16_t val2_5 = 0; + uint16_t val2_6 = 0; + bool ok = UnPacker::unpack(data, val2_1, val2_2, val2_3, val2_4, val2_5, val2_6); + + assert(ok); + assert(val1_1 == val2_1); + assert(val1_2 == val2_2); + assert(val1_3 == val2_3); + assert(val1_4 == val2_4); + assert(val1_5 == val2_5); + assert(val1_6 == val2_6); + } + + // int32_t, uint32_t + if (ALL_TEST || INT32_TEST) { + std::vector data; + int32_t val1_1 = 126; // positive fixint + int32_t val1_2 = -5; // negative fixint + int32_t val1_3 = 346; // regular int32_t + int32_t val1_4 = -42; // regular int32_t + uint32_t val1_5 = 124; // positive fixint + uint32_t val1_6 = 348; // regular uint32_t + Packer::pack(data, val1_1, val1_2, val1_3, val1_4, val1_5, val1_6); + + int32_t val2_1 = 0; + int32_t val2_2 = 0; + int32_t val2_3 = 0; + int32_t val2_4 = 0; + uint32_t val2_5 = 0; + uint32_t val2_6 = 0; + bool ok = UnPacker::unpack(data, val2_1, val2_2, val2_3, val2_4, val2_5, val2_6); + + assert(ok); + assert(val1_1 == val2_1); + assert(val1_2 == val2_2); + assert(val1_3 == val2_3); + assert(val1_4 == val2_4); + assert(val1_5 == val2_5); + assert(val1_6 == val2_6); + } + + // int64_t, uint64_t + if (ALL_TEST || INT64_TEST) { + std::vector data; + int64_t val1_1 = 126; // positive fixint + int64_t val1_2 = -5; // negative fixint + int64_t val1_3 = 346; // regular int64_t + int64_t val1_4 = -42; // regular int64_t + uint64_t val1_5 = 124; // positive fixint + uint64_t val1_6 = 348; // regular uint64_t + Packer::pack(data, val1_1, val1_2, val1_3, val1_4, val1_5, val1_6); + + int64_t val2_1 = 0; + int64_t val2_2 = 0; + int64_t val2_3 = 0; + int64_t val2_4 = 0; + uint64_t val2_5 = 0; + uint64_t val2_6 = 0; + bool ok = UnPacker::unpack(data, val2_1, val2_2, val2_3, val2_4, val2_5, val2_6); + + assert(ok); + assert(val1_1 == val2_1); + assert(val1_2 == val2_2); + assert(val1_3 == val2_3); + assert(val1_4 == val2_4); + assert(val1_5 == val2_5); + assert(val1_6 == val2_6); + } + + // float, double + if (ALL_TEST || REAL_TEST) { + std::vector data; + float val1_1 = 0.42f; + float val1_2 = 42.0f; + float val1_3 = -0.42f; + float val1_4 = -42.0f; + double val1_5 = 0.84; + double val1_6 = 84.0; + double val1_7 = -0.84; + double val1_8 = -84.0; + Packer::pack(data, val1_1, val1_2, val1_3, val1_4, val1_5, val1_6, val1_7, val1_8); + + float val2_1 = 0.0f; + float val2_2 = 0.0f; + float val2_3 = 0.0f; + float val2_4 = 0.0f; + double val2_5 = 0.0; + double val2_6 = 0.0; + double val2_7 = 0.0; + double val2_8 = 0.0; + bool ok = UnPacker::unpack(data, val2_1, val2_2, val2_3, val2_4, val2_5, val2_6, val2_7, val2_8); + + assert(ok); + assert(is_equal(val1_1, val2_1)); + assert(is_equal(val1_2, val2_2)); + assert(is_equal(val1_3, val2_3)); + assert(is_equal(val1_4, val2_4)); + assert(is_equal(val1_5, val2_5)); + assert(is_equal(val1_6, val2_6)); + assert(is_equal(val1_7, val2_7)); + assert(is_equal(val1_8, val2_8)); + } + + // string + if (ALL_TEST || STR_TEST) { + std::vector data; + + std::string str1_fix = "Hello World!"; // size < 31 + std::string str1_8 = std::string(234, '1'); + std::string str1_16 = std::string(270, '2'); + std::string str1_32 = std::string(66535, '4'); + + Packer::pack(data, str1_fix, str1_8, str1_16, str1_32); + + std::string str2_fix; + std::string str2_8; + std::string str2_16; + std::string str2_32; + + bool ok = UnPacker::unpack(data, str2_fix, str2_8, str2_16, str2_32); + + assert(ok); + assert(str1_fix == str2_fix); + assert(str1_8 == str2_8); + assert(str1_16 == str2_16); + assert(str1_32 == str2_32); + } + + // bin + if (ALL_TEST || BIN_TEST) { + std::vector data; + + std::vector v1_8 = std::vector(234, 1); + std::vector v1_16 = std::vector(270, 2); + std::vector v1_32 = std::vector(66535, 4); + + Packer::pack(data, v1_8, v1_16, v1_32); + + std::vector v2_8; + std::vector v2_16; + std::vector v2_32; + + bool ok = UnPacker::unpack(data, v2_8, v2_16, v2_32); + + assert(ok); + assert(v1_8 == v2_8); + assert(v1_16 == v2_16); + assert(v1_32 == v2_32); + } + + // array + if (ALL_TEST || ARR_TEST) { + std::vector data; + + std::vector v1_8 = std::vector(12, 1); + std::list v1_16 = std::list(270, 2); + std::set v1_32; + for (size_t i; i < 66535; ++i) { + v1_32.insert(4); + } + + Packer::pack(data, v1_8, v1_16, v1_32); + + std::vector v2_8; + std::list v2_16; + std::set v2_32; + + bool ok = UnPacker::unpack(data, v2_8, v2_16, v2_32); + + assert(ok); + assert(v1_8 == v2_8); + assert(v1_16 == v2_16); + assert(v1_32 == v2_32); + } + + // map + if (ALL_TEST || MAP_TEST) { + std::vector data; + + std::map v1_8; + for (int16_t i; i < 12; ++i) { + v1_8.insert({ i, 1 }); + } + + std::map v1_16; + for (int16_t i; i < 270; ++i) { + v1_8.insert({ i, 1 }); + } + + std::map v1_32; + for (int32_t i; i < 66535; ++i) { + v1_8.insert({ i, 1 }); + } + + Packer::pack(data, v1_8, v1_16, v1_32); + + std::map v2_8; + std::map v2_16; + std::map v2_32; + + bool ok = UnPacker::unpack(data, v2_8, v2_16, v2_32); + + assert(ok); + assert(v1_8 == v2_8); + assert(v1_16 == v2_16); + assert(v1_32 == v2_32); + } + + // custom + if (ALL_TEST || CUSTOM_TEST) { + std::vector data; + + ObjectWithPack obj1_1; + obj1_1.i = 42; + obj1_1.str = "42"; + + ObjectWithPackUnPack obj1_2; + obj1_2.i = 42; + obj1_2.str = "42"; + + ObjectCustomPackUnPack obj1_3; + obj1_3.i = 42; + obj1_3.str = "42"; + + ObjectCustomLowLevel obj1_4; + obj1_4.i = 42; + obj1_4.str = "42"; + + Packer::pack(data, obj1_1, obj1_2, obj1_3, obj1_4); + + ObjectWithPack obj2_1; + ObjectWithPackUnPack obj2_2; + ObjectCustomPackUnPack obj2_3; + ObjectCustomLowLevel obj2_4; + + bool ok = UnPacker::unpack(data, obj2_1, obj2_2, obj2_3, obj2_4); + + assert(ok); + assert(obj1_1 == obj2_1); + assert(obj1_2 == obj2_2); + assert(obj1_3 == obj2_3); + assert(obj1_4 == obj2_4); + } +} diff --git a/src/framework/global/thirdparty/kors_msgpack/example/msgpack.h b/src/framework/global/thirdparty/kors_msgpack/example/msgpack.h new file mode 100644 index 0000000000000..f3d16debf855c --- /dev/null +++ b/src/framework/global/thirdparty/kors_msgpack/example/msgpack.h @@ -0,0 +1,9 @@ +#pragma once + +#include "../msgpack/msgpack.h" // kors + +namespace app::msgpack { +using Packer = kors::msgpack::Packer; +using UnPacker = kors::msgpack::UnPacker; +using Cursor = kors::msgpack::Cursor; +} diff --git a/src/framework/global/thirdparty/kors_msgpack/msgpack/msgpack.h b/src/framework/global/thirdparty/kors_msgpack/msgpack/msgpack.h new file mode 100644 index 0000000000000..655ed2a5bedeb --- /dev/null +++ b/src/framework/global/thirdparty/kors_msgpack/msgpack/msgpack.h @@ -0,0 +1,1080 @@ +/* +MIT License + +Copyright (c) 2025 Igor Korsukov + +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. +*/ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace kors::msgpack { + +enum Format : uint8_t { + // positive fixint = 0x00 - 0x7f + fixmap = 0x80, //0x80 - 0x8f + fixarray = 0x90, //0x90 - 0x9a + fixstr = 0xa0, //0xa0 - 0xbf + // negative fixint = 0xe0 - 0xff + + nil = 0xc0, + false_bool = 0xc2, + true_bool = 0xc3, + bin8 = 0xc4, + bin16 = 0xc5, + bin32 = 0xc6, + ext8 = 0xc7, + ext16 = 0xc8, + ext32 = 0xc9, + float32 = 0xca, + float64 = 0xcb, + uint8 = 0xcc, + uint16 = 0xcd, + uint32 = 0xce, + uint64 = 0xcf, + int8 = 0xd0, + int16 = 0xd1, + int32 = 0xd2, + int64 = 0xd3, + fixext1 = 0xd4, + fixext2 = 0xd5, + fixext4 = 0xd6, + fixext8 = 0xd7, + fixext16 = 0xd8, + str8 = 0xd9, + str16 = 0xda, + str32 = 0xdb, + array16 = 0xdc, + array32 = 0xdd, + map16 = 0xde, + map32 = 0xdf +}; + +struct Cursor { + const uint8_t* current = nullptr; + const uint8_t* end = nullptr; + bool error = false; + + Cursor(const uint8_t* start, size_t size) + : current(start), end(start + size) {} + + inline size_t remain() const { + return end - current; + } + + inline const uint8_t* pdata() { + if (current < end) { + return current; + } + error = true; + return nullptr; + } + + inline uint8_t data() { + if (current < end) { + return *current; + } + error = true; + return 0; + } + + inline void next(int64_t bytes = 1) { + if (remain() >= bytes) { + current += bytes; + } else { + error = true; + } + } + + inline uint8_t read() { + uint8_t b = data(); + next(); + return b; + } +}; + +template +struct is_container : std::false_type {}; + +template +struct is_container().begin()), +decltype(std::declval().end()), +decltype(std::declval().size()) +>> : std::true_type {}; + +template +struct is_map : std::false_type {}; + +template +struct is_map().first), +decltype(std::declval().second) +>> : std::true_type {}; + +template +struct has_reserve : std::false_type {}; + +template +struct has_reserve().reserve()) +>> : std::true_type {}; + +template +struct has_emplace_back : std::false_type {}; + +template +struct has_emplace_back().emplace_back()) +>> : std::true_type {}; + +class Packer; + +template +struct has_pack_packer : std::false_type {}; + +template +struct has_pack_packer().pack(std::declval())) +>> : std::true_type {}; + +template +struct has_pack_const_packer : std::false_type {}; + +template +struct has_pack_const_packer().pack(std::declval())) +>> : std::true_type {}; + +template +struct has_pack_data : std::false_type {}; + +template +struct has_pack_data().pack(std::declval&>())) +>> : std::true_type {}; + +template +struct has_func_pack_custom_packer : std::false_type {}; + +template +struct has_func_pack_custom_packer(), std::declval()))> + > : std::true_type {}; + +class UnPacker; + +template +struct has_pack_unpacker : std::false_type {}; + +template +struct has_pack_unpacker().pack(std::declval())) +>> : std::true_type {}; + +template +struct has_unpack_unpacker : std::false_type {}; + +template +struct has_unpack_unpacker().unpack(std::declval())) +>> : std::true_type {}; + +template +struct has_unpack_cursor : std::false_type {}; + +template +struct has_unpack_cursor().unpack(std::declval())) +>> : std::true_type {}; + +template +struct has_func_unpack_custom_unpacker : std::false_type {}; + +template +struct has_func_unpack_custom_unpacker(), std::declval()))> + > : std::true_type {}; + +// Nil +inline void pack_type(std::vector& data, const std::nullptr_t&/*value*/) { + data.emplace_back(nil); +} + +inline bool unpack_type(Cursor& cursor, std::nullptr_t& /*value*/) { + cursor.next(); + return true; +} + +// Bool +inline void pack_type(std::vector& data, const bool& value) { + if (value) { + data.emplace_back(true_bool); + } else { + data.emplace_back(false_bool); + } +} + +inline bool unpack_type(Cursor& cursor, bool& value) { + value = cursor.read() != 0xc2; + return true; +} + +// Int family +template +inline bool pack_fixint(std::vector& data, const T& value) { + + // positive fixint + if (value >= 0 && value <= 127) { + data.emplace_back(static_cast(value)); + return true; + } + + // negative fixint + if (value >= -32 && value <= -1) { + data.emplace_back(static_cast(0xE0 | (static_cast(value + 32)))); + return true; + } + + return false; +} + +template +inline bool unpack_fixint(Cursor& cursor, T& value) { + + // positive fixint + uint8_t byte = cursor.data(); + if ((byte & 0x80) == 0) { + value = static_cast(byte); + cursor.next(); + return true; + } + + // negative fixint + if ((byte & 0xE0) == 0xE0) { + value = static_cast(static_cast(byte & 0x1F) - 32); + cursor.next(); + return true; + } + + return false; +} + +inline void pack_type(std::vector& data, const int8_t& value) { + if (pack_fixint(data, value)) { + return; + } + + data.emplace_back(int8); + data.emplace_back(static_cast(value)); +} + +inline bool unpack_type(Cursor& cursor, int8_t& value) { + if (unpack_fixint(cursor, value)) { + return true; + } else if (cursor.data() == int8) { + cursor.next(); + value = static_cast(cursor.read()); + return true; + } + return false; +} + +inline void pack_type(std::vector& data, const uint8_t& value) { + if (pack_fixint(data, value)) { + return; + } + + data.emplace_back(uint8); + data.emplace_back(value); +} + +inline bool unpack_type(Cursor& cursor, uint8_t& value) { + if (unpack_fixint(cursor, value)) { + return true; + } else if (cursor.data() == uint8) { + cursor.next(); + value = cursor.read(); + return true; + } + return false; +} + +template +constexpr bool is_fit_in_type(U value) noexcept { + return value >= std::numeric_limits::min() && + value <= std::numeric_limits::max(); +} + +inline void pack_type(std::vector& data, const int16_t& value) { + if (is_fit_in_type(value)) { + pack_type(data, static_cast(value)); + } else { + data.emplace_back(int16); + uint16_t uvalue = static_cast(value); + data.emplace_back(static_cast((uvalue >> 8) & 0xFF)); + data.emplace_back(static_cast(uvalue & 0xFF)); + } +} + +inline bool unpack_type(Cursor& cursor, int16_t& value) { + + if (int8_t i8 = 0; unpack_type(cursor, i8)) { + value = static_cast(i8); + return true; + } else if (cursor.data() == int16) { + cursor.next(); + uint8_t high = cursor.read(); + uint8_t low = cursor.read(); + uint16_t uvalue = (static_cast(high) << 8) | low; + value = static_cast(uvalue); + return true; + } + + return false; +} + +inline void pack_type(std::vector& data, const uint16_t& value) { + if (is_fit_in_type(value)) { + pack_type(data, static_cast(value)); + } else { + data.emplace_back(uint16); + data.emplace_back(static_cast((value >> 8) & 0xFF)); + data.emplace_back(static_cast(value & 0xFF)); + } +} + +inline bool unpack_type(Cursor& cursor, uint16_t& value) { + + if (uint8_t ui8 = 0; unpack_type(cursor, ui8)) { + value = static_cast(ui8); + return true; + } else if (cursor.data() == uint16) { + cursor.next(); + uint8_t high = cursor.read(); + uint8_t low = cursor.read(); + value = (static_cast(high) << 8) | low; + return true; + } + + return false; +} + +inline void pack_type(std::vector& data, const int32_t& value) { + if (is_fit_in_type(value)) { + pack_type(data, static_cast(value)); + } else { + data.emplace_back(int32); + uint32_t uvalue = static_cast(value); + data.emplace_back(static_cast((uvalue >> 24) & 0xFF)); + data.emplace_back(static_cast((uvalue >> 16) & 0xFF)); + data.emplace_back(static_cast((uvalue >> 8) & 0xFF)); + data.emplace_back(static_cast(uvalue & 0xFF)); + } +} + +inline bool unpack_type(Cursor& cursor, int32_t& value) { + + if (int16_t i16 = 0; unpack_type(cursor, i16)) { + value = static_cast(i16); + return true; + } else if (cursor.data() == int32) { + cursor.next(); + uint32_t ui32 = 0; + for (int i = 0; i < 4; ++i) { + uint8_t byte = cursor.read(); + ui32 = (ui32 << 8) | byte; + } + value = static_cast(ui32); + return true; + } + + return false; +} + +inline void pack_type(std::vector& data, const uint32_t& value) { + if (is_fit_in_type(value)) { + pack_type(data, static_cast(value)); + } else { + data.emplace_back(uint32); + data.emplace_back(static_cast((value >> 24) & 0xFF)); + data.emplace_back(static_cast((value >> 16) & 0xFF)); + data.emplace_back(static_cast((value >> 8) & 0xFF)); + data.emplace_back(static_cast(value & 0xFF)); + } +} + +inline bool unpack_type(Cursor& cursor, uint32_t& value) { + + if (uint16_t ui16 = 0; unpack_type(cursor, ui16)) { + value = static_cast(ui16); + return true; + } else if (cursor.data() == uint32) { + cursor.next(); + uint32_t ui32 = 0; + for (int i = 0; i < 4; ++i) { + uint8_t byte = cursor.read(); + ui32 = (ui32 << 8) | byte; + } + value = ui32; + return true; + } + + return false; +} + +inline void pack_type(std::vector& data, const int64_t& value) { + if (is_fit_in_type(value)) { + pack_type(data, static_cast(value)); + } else { + data.emplace_back(int64); + uint64_t uvalue = static_cast(value); + for (int i = 7; i >= 0; --i) { + data.emplace_back(static_cast((uvalue >> (i * 8)) & 0xFF)); + } + } +} + +inline bool unpack_type(Cursor& cursor, int64_t& value) { + + if (int32_t i32 = 0; unpack_type(cursor, i32)) { + value = static_cast(i32); + return true; + } else if (cursor.data() == int64) { + cursor.next(); + uint64_t ui64 = 0; + for (int i = 0; i < 4; ++i) { + uint8_t byte = cursor.read(); + ui64 = (ui64 << 8) | byte; + } + value = static_cast(ui64); + return true; + } + + return false; +} + +inline void pack_type(std::vector& data, const uint64_t& value) { + if (is_fit_in_type(value)) { + pack_type(data, static_cast(value)); + } else { + data.emplace_back(uint64); + for (int i = 7; i >= 0; --i) { + data.emplace_back(static_cast((value >> (i * 8)) & 0xFF)); + } + } +} + +inline bool unpack_type(Cursor& cursor, uint64_t& value) { + + if (uint32_t ui32 = 0; unpack_type(cursor, ui32)) { + value = static_cast(ui32); + return true; + } else if (cursor.data() == uint64) { + cursor.next(); + uint64_t ui64 = 0; + for (int i = 0; i < 4; ++i) { + uint8_t byte = cursor.read(); + ui64 = (ui64 << 8) | byte; + } + value = ui64; + return true; + } + + return false; +} + +// Float/Double +inline void pack_type(std::vector& data, const float& value) { + + data.emplace_back(float32); + + uint32_t bin = 0; + static_assert(sizeof(float) == sizeof(uint32_t), "Float size mismatch"); + std::memcpy(&bin, &value, sizeof(float)); + + data.emplace_back(static_cast((bin >> 24) & 0xFF)); + data.emplace_back(static_cast((bin >> 16) & 0xFF)); + data.emplace_back(static_cast((bin >> 8) & 0xFF)); + data.emplace_back(static_cast(bin & 0xFF)); +} + +inline bool unpack_type(Cursor& cursor, float& value) { + + if (cursor.data() == float32) { + cursor.next(); + + uint32_t bin = 0; + for (int i = 0; i < 4; ++i) { + uint8_t byte = cursor.read(); + bin = (bin << 8) | byte; + } + + static_assert(sizeof(float) == sizeof(uint32_t), "Float size mismatch"); + std::memcpy(&value, &bin, sizeof(float)); + + return true; + } + + return false; +} + +inline void pack_type(std::vector& data, const double& value) { + + data.emplace_back(float64); + uint64_t bin = 0; + static_assert(sizeof(double) == sizeof(uint64_t), "Double size mismatch"); + std::memcpy(&bin, &value, sizeof(double)); + + for (int i = 7; i >= 0; --i) { + data.emplace_back(static_cast((bin >> (i * 8)) & 0xFF)); + } +} + +inline bool unpack_type(Cursor& cursor, double& value) { + + if (float f32 = 0; unpack_type(cursor, f32)) { + value = static_cast(f32); + return true; + } else if (cursor.data() == float64) { + cursor.next(); + + uint64_t bin = 0; + for (int i = 0; i < 8; ++i) { + uint8_t byte = cursor.read(); + bin = (bin << 8) | byte; + } + + static_assert(sizeof(double) == sizeof(uint64_t), "Double size mismatch"); + std::memcpy(&value, &bin, sizeof(double)); + + return true; + } + + return false; +} + +// string +inline void pack_type(std::vector& data, const std::string& value) { + + const size_t len = value.size(); + + if (len <= 31) { + data.emplace_back(static_cast(fixstr | len)); + } else if (len <= 0xFF) { + data.emplace_back(str8); + data.emplace_back(static_cast(len)); + } + else if (len <= 0xFFFF) { + data.emplace_back(str16); + data.emplace_back(static_cast((len >> 8) & 0xFF)); + data.emplace_back(static_cast(len & 0xFF)); + } + else if (len <= 0xFFFFFFFF) { + data.emplace_back(str32); + data.emplace_back(static_cast((len >> 24) & 0xFF)); + data.emplace_back(static_cast((len >> 16) & 0xFF)); + data.emplace_back(static_cast((len >> 8) & 0xFF)); + data.emplace_back(static_cast(len & 0xFF)); + } else { + // too long for MessagePack + return; + } + + data.reserve(data.size() + len + 5); + for (char i : value) { + data.emplace_back(static_cast(i)); + } +} + +inline bool unpack_type(Cursor& cursor, std::string& value) { + + size_t len = 0; + uint8_t marker = cursor.read(); + if ((marker & 0xE0) == fixstr) { + len = marker & 0x1F; + } else if (marker == str8) { + len = cursor.read();; + } else if (marker == str16) { + uint16_t ui16 = 0; + for (int i = 0; i < 2; ++i) { + uint8_t byte = cursor.read(); + ui16 = (ui16 << 8) | byte; + } + len = ui16; + } else if (marker == str32) { + uint32_t ui32 = 0; + for (int i = 0; i < 4; ++i) { + uint8_t byte = cursor.read(); + ui32 = (ui32 << 8) | byte; + } + len = ui32; + } else { + // invalid string marker + return false; + } + + if (cursor.remain() < len) { + cursor.error = true; + return false; + } + + value = std::string(cursor.pdata(), cursor.pdata() + len); + cursor.next(len); + + return true; +} + +// bin +inline void pack_type(std::vector& data, const std::vector& value) { + + const size_t len = value.size(); + + if (len <= 0xFF) { + data.emplace_back(bin8); + data.emplace_back(static_cast(len)); + } + else if (len <= 0xFFFF) { + data.emplace_back(bin16); + data.emplace_back(static_cast((len >> 8) & 0xFF)); + data.emplace_back(static_cast(len & 0xFF)); + } + else if (len <= 0xFFFFFFFF) { + data.emplace_back(bin32); + data.emplace_back(static_cast((len >> 24) & 0xFF)); + data.emplace_back(static_cast((len >> 16) & 0xFF)); + data.emplace_back(static_cast((len >> 8) & 0xFF)); + data.emplace_back(static_cast(len & 0xFF)); + } else { + // too long for MessagePack + return; + } + + data.reserve(data.size() + len + 5); + for (uint8_t i : value) { + data.emplace_back(i); + } +} + +inline bool unpack_type(Cursor& cursor, std::vector& value) { + + size_t len = 0; + uint8_t marker = cursor.read(); + if (marker == bin8) { + len = cursor.read();; + } else if (marker == bin16) { + uint16_t ui16 = 0; + for (int i = 0; i < 2; ++i) { + uint8_t byte = cursor.read(); + ui16 = (ui16 << 8) | byte; + } + len = ui16; + } else if (marker == bin32) { + uint32_t ui32 = 0; + for (int i = 0; i < 4; ++i) { + uint8_t byte = cursor.read(); + ui32 = (ui32 << 8) | byte; + } + len = ui32; + } else { + // invalid bin marker + return false; + } + + if (cursor.remain() < len) { + cursor.error = true; + return false; + } + + value = std::vector(cursor.pdata(), cursor.pdata() + len); + cursor.next(len); + + return true; +} + +// array +template +void pack_array(std::vector& data, const T& array) { + + const size_t len = array.size(); + + if (len < 16) { + data.emplace_back(uint8_t(fixarray | len)); + } else if (len <= 0xFFFF) { + data.emplace_back(array16); + data.emplace_back(static_cast((len >> 8) & 0xFF)); + data.emplace_back(static_cast(len & 0xFF)); + } else if (len <= 0xFFFFFFFF) { + data.emplace_back(array32); + data.emplace_back(static_cast((len >> 24) & 0xFF)); + data.emplace_back(static_cast((len >> 16) & 0xFF)); + data.emplace_back(static_cast((len >> 8) & 0xFF)); + data.emplace_back(static_cast(len & 0xFF)); + } else { + // too long for MessagePack + return; + } + + for (const auto& elem : array) { + pack_type(data, elem); + } +} + +template +inline bool unpack_array(Cursor& cursor, T& array) { + + size_t len = 0; + uint8_t marker = cursor.read(); + if ((marker & 0xF0) == fixarray) { + len = marker & 0xF; + } else if (marker == array16) { + uint16_t ui16 = 0; + for (int i = 0; i < 2; ++i) { + uint8_t byte = cursor.read(); + ui16 = (ui16 << 8) | byte; + } + len = ui16; + } else if (marker == array32) { + uint32_t ui32 = 0; + for (int i = 0; i < 4; ++i) { + uint8_t byte = cursor.read(); + ui32 = (ui32 << 8) | byte; + } + len = ui32; + } else { + // invalid marker + return false; + } + + using ValueType = typename T::value_type; + + if constexpr (has_reserve::value) { + array.reserve(len); + } + + for (size_t i = 0; i < len; ++i) { + ValueType val{}; + bool ok = unpack_type(cursor, val); + if (!ok) { + return false; + } + + if constexpr (has_emplace_back::value) { + array.emplace_back(std::move(val)); + } else { + array.emplace(std::move(val)); + } + } + + return true; +} + +// map +template +void pack_map(std::vector& data, const T& map) { + + const size_t len = map.size(); + + if (len < 16) { + data.emplace_back(uint8_t(fixmap | len)); + } else if (len <= 0xFFFF) { + data.emplace_back(map16); + data.emplace_back(static_cast((len >> 8) & 0xFF)); + data.emplace_back(static_cast(len & 0xFF)); + } else if (len <= 0xFFFFFFFF) { + data.emplace_back(map32); + data.emplace_back(static_cast((len >> 24) & 0xFF)); + data.emplace_back(static_cast((len >> 16) & 0xFF)); + data.emplace_back(static_cast((len >> 8) & 0xFF)); + data.emplace_back(static_cast(len & 0xFF)); + } else { + // too long for MessagePack + return; + } + + for (const auto &elem : map) { + pack_type(data, std::get<0>(elem)); + pack_type(data, std::get<1>(elem)); + } +} + +template +inline bool unpack_map(Cursor& cursor, T& map) { + + size_t len = 0; + uint8_t marker = cursor.read(); + if ((marker & 0xF0) == fixmap) { + len = marker & 0xF; + } else if (marker == map16) { + uint16_t ui16 = 0; + for (int i = 0; i < 2; ++i) { + uint8_t byte = cursor.read(); + ui16 = (ui16 << 8) | byte; + } + len = ui16; + } else if (marker == map32) { + uint32_t ui32 = 0; + for (int i = 0; i < 4; ++i) { + uint8_t byte = cursor.read(); + ui32 = (ui32 << 8) | byte; + } + len = ui32; + } else { + // invalid marker + return false; + } + + using KeyType = typename T::key_type; + using MappedType = typename T::mapped_type; + + for (size_t i = 0; i < len; ++i) { + KeyType key{}; + MappedType value{}; + bool ok = unpack_type(cursor, key); + if (!ok) { + return false; + } + + ok = unpack_type(cursor, value); + if (!ok) { + return false; + } + + map.insert_or_assign(key, value); + } + + return true; +} + +// pack by packer +template +void pack_packer(std::vector& data, const T& value); +template +void pack_const_packer(std::vector& data, const T& value); +template +void pack_custom_packer(std::vector& data, const T& value); + +// unpack by unpacker +template +bool pack_unpacker(Cursor& cursor, T& value); +template +bool unpack_unpacker(Cursor& cursor, T& value); +template +bool unpack_custom_unpacker(Cursor& cursor, T& value); + +template +void pack_type(std::vector& data, const T& value) { + + if constexpr(is_map::value) { + pack_map(data, value); + } else if constexpr(is_container::value) { + pack_array(data, value); + } else { + // custom + if constexpr(has_pack_data::value && !has_pack_const_packer::value) { + value.pack(data); + } else if constexpr(has_pack_const_packer::value) { + pack_const_packer(data, value); + } else if constexpr(has_pack_packer::value) { + pack_packer(data, value); + } else if constexpr (has_func_pack_custom_packer::value) { + pack_custom_packer(data, value); + } else { + pack_custom(data, value); + } + } +} + +template +bool unpack_type(Cursor& cursor, T& value) { + + if constexpr(is_map::value) { + return unpack_map(cursor, value); + } else if constexpr(is_container::value) { + return unpack_array(cursor, value); + } else { + // custom + if constexpr(has_unpack_cursor::value && !has_unpack_unpacker::value) { + value.unpack(cursor); + } else if constexpr(has_unpack_unpacker::value) { + return unpack_unpacker(cursor, value); + } else if constexpr(has_pack_unpacker::value) { + return pack_unpacker(cursor, value); + } else if constexpr (has_func_unpack_custom_unpacker::value) { + return unpack_custom_unpacker(cursor, value); + } else { + return unpack_custom(cursor, value); + } + } + + return false; +} + +class Packer +{ +public: + + Packer(std::vector& d) + : m_ref(d) {} + + Packer() + : m_ref(m_data) {} + + template + static void pack(std::vector& data, const Types &... args) { + do_pack(data, args...); + } + + template + void operator()(const Types &... args) { + do_pack(m_ref, args...); + } + + template + void process(const Types &... args) { + do_pack(m_ref, args...); + } + + const std::vector& data() const { + return m_ref; + } + +private: + template + static void do_pack(std::vector& data, const Types &... args) { + (pack_type(data, std::forward(args)), ...); + } + + std::vector m_data; + std::vector& m_ref; +}; + +class UnPacker +{ +public: + + UnPacker(Cursor& cursor) + : m_cursor(cursor) {} + + UnPacker(const uint8_t* start, std::size_t size) + : m_cursor(Cursor(start, size)) {} + + UnPacker(const std::vector& data) + : m_cursor(Cursor(&data[0], data.size())) {} + + template + static bool unpack(Cursor& c, Types&... args) { + return do_unpack(c, args...); + } + + template + static bool unpack(const uint8_t* start, std::size_t size, Types&... args) { + Cursor c(start, size); + return do_unpack(c, args...); + } + + template + static bool unpack(const std::vector& data, Types&... args) { + Cursor c(&data[0], data.size()); + return do_unpack(c, args...); + } + + template + void operator()(Types&... args) { + m_success = do_unpack(m_cursor, args...); + } + + template + bool process(Types&... args) { + m_success = do_unpack(m_cursor, args...); + return success(); + } + + bool success() const { return m_success; } + +private: + template + static bool do_unpack(Cursor& c, Types&... args) { + bool ok = (unpack_type(c, std::forward(args)), ...); + return ok && !c.error; + } + + bool m_success = true; + Cursor m_cursor; +}; + +template +inline void pack_packer(std::vector& data, const T& value) +{ + Packer p(data); + const_cast(value).pack(p); +} + +template +inline void pack_const_packer(std::vector& data, const T& value) +{ + Packer p(data); + value.pack(p); +} + +template +inline void pack_custom_packer(std::vector& data, const T& value) +{ + Packer p(data); + pack_custom(p, value); +} + +template +inline bool pack_unpacker(Cursor& cursor, T& value) +{ + UnPacker u(cursor); + value.pack(u); + return u.success(); +} + +template +inline bool unpack_unpacker(Cursor& cursor, T& value) +{ + UnPacker u(cursor); + value.unpack(u); + return u.success(); +} + +template +inline bool unpack_custom_unpacker(Cursor& cursor, T& value) +{ + UnPacker u(cursor); + unpack_custom(u, value); + return u.success(); +} +} diff --git a/src/framework/global/types/bytearray.cpp b/src/framework/global/types/bytearray.cpp index 055b1f78fa52e..0e95d5e9cd5ff 100644 --- a/src/framework/global/types/bytearray.cpp +++ b/src/framework/global/types/bytearray.cpp @@ -76,6 +76,12 @@ uint8_t* ByteArray::data() return m_data->data(); } +std::vector& ByteArray::vdata() +{ + detach(); + return *m_data.get(); +} + const uint8_t* ByteArray::constData() const { if (m_raw.data) { @@ -90,6 +96,11 @@ const char* ByteArray::constChar() const return reinterpret_cast(constData()); } +const std::vector& ByteArray::constVData() const +{ + return *m_data.get(); +} + size_t ByteArray::size() const { if (m_raw.data) { diff --git a/src/framework/global/types/bytearray.h b/src/framework/global/types/bytearray.h index dbe039d9636bf..fa0ef43a6a9d8 100644 --- a/src/framework/global/types/bytearray.h +++ b/src/framework/global/types/bytearray.h @@ -49,8 +49,10 @@ class ByteArray bool operator!=(const ByteArray& other) const { return !operator==(other); } uint8_t* data(); + std::vector& vdata(); const uint8_t* constData() const; const char* constChar() const; // data as char* + const std::vector& constVData() const; size_t size() const; bool empty() const;