diff --git a/README.md b/README.md index 9d325795e..811586a2d 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ More examples [here](https://github.com/alibaba/yalantinglibs/tree/main/src/coro Based on compile-time reflection, very easy to use, high performance serialization library, struct_pack is a header only library, it is used by coro_rpc now. -Only one line code to finish serialization and deserialization, 2-50x faster than protobuf. +Only one line code to finish serialization and deserialization, 2-20x faster than protobuf. ### quick example ```cpp diff --git a/include/ylt/struct_pack/calculate_size.hpp b/include/ylt/struct_pack/calculate_size.hpp index f9133da36..a89f3d1ff 100644 --- a/include/ylt/struct_pack/calculate_size.hpp +++ b/include/ylt/struct_pack/calculate_size.hpp @@ -263,10 +263,21 @@ constexpr bool STRUCT_PACK_INLINE has_64bits_varint() { } } -template +template +constexpr std::size_t STRUCT_PACK_INLINE get_int_len() { + if (has_64bits_varint()) { + return 8; + } + else { + return 4; + } +} + +template constexpr void STRUCT_PACK_INLINE get_fast_varint_width_impl( const Arg &item, int &non_zero_cnt32, int &non_zero_cnt64, - uint64_t &unsigned_max, int64_t &signed_max) { + unsigned_t &unsigned_max, signed_t &signed_max) { if constexpr (varint_t) { if (get_varint_value(item)) { if constexpr (sizeof(Arg) == 4) { @@ -280,27 +291,29 @@ constexpr void STRUCT_PACK_INLINE get_fast_varint_width_impl( } if constexpr (std::is_unsigned_v>) { - unsigned_max = std::max(unsigned_max, get_varint_value(item)); + unsigned_max = + std::max(unsigned_max, get_varint_value(item)); } else { signed_max = - std::max(signed_max, get_varint_value(item) > 0 - ? get_varint_value(item) - : -(get_varint_value(item) + 1)); + std::max(signed_max, get_varint_value(item) > 0 + ? get_varint_value(item) + : -(get_varint_value(item) + 1)); } } } } -template +template constexpr int STRUCT_PACK_INLINE -get_fast_varint_width_from_max(uint64_t unsigned_max, int64_t signed_max) { +get_fast_varint_width_from_max(unsigned_t unsigned_max, signed_t signed_max) { int width_unsigned = 0, width_signed = 0; if constexpr (has_unsigned_varint()) { if SP_LIKELY (unsigned_max <= UINT8_MAX) { width_unsigned = 0; } - else if (unsigned_max <= UINT16_MAX) { + else if SP_LIKELY (unsigned_max <= UINT16_MAX) { width_unsigned = 1; } else if (unsigned_max <= UINT32_MAX) { @@ -314,7 +327,7 @@ get_fast_varint_width_from_max(uint64_t unsigned_max, int64_t signed_max) { if SP_LIKELY (signed_max <= INT8_MAX) { width_signed = 0; } - else if (signed_max <= INT16_MAX) { + else if SP_LIKELY (signed_max <= INT16_MAX) { width_signed = 1; } else if (signed_max <= INT32_MAX) { @@ -342,8 +355,8 @@ get_fast_varint_width_from_max(uint64_t unsigned_max, int64_t signed_max) { template constexpr int STRUCT_PACK_INLINE get_fast_varint_width(const Args &...items) { - uint64_t unsigned_max = 0; - int64_t signed_max = 0; + typename uint_t()>::type unsigned_max = 0; + typename int_t()>::type signed_max = 0; int non_zero_cnt32 = 0, non_zero_cnt64 = 0; (get_fast_varint_width_impl(items, non_zero_cnt32, non_zero_cnt64, unsigned_max, signed_max), diff --git a/include/ylt/struct_pack/packer.hpp b/include/ylt/struct_pack/packer.hpp index 4cd02e791..c3d996dde 100644 --- a/include/ylt/struct_pack/packer.hpp +++ b/include/ylt/struct_pack/packer.hpp @@ -100,9 +100,9 @@ class packer { } if constexpr (hash_head % 2) { // has more metainfo auto metainfo = info.metainfo(); - std::size_t sz = info.size(); write_wrapper(writer_, (char *)&metainfo); if constexpr (serialize_static_config::has_compatible) { + std::size_t sz = info.size(); switch (metainfo & 0b11) { case 1: low_bytes_write_wrapper<2>(writer_, sz); @@ -148,23 +148,24 @@ class packer { } } - template + template static constexpr void STRUCT_PACK_INLINE get_fast_varint_width_impl(char (&vec)[sz], unsigned int &i, const Arg &item, - uint64_t &unsigned_max, int64_t &signed_max) { + unsigned_t &unsigned_max, signed_t &signed_max) { if constexpr (varint_t) { if (get_varint_value(item) != 0) { vec[i / 8] |= (0b1 << (i % 8)); if constexpr (std::is_unsigned_v>) { unsigned_max = - std::max(unsigned_max, get_varint_value(item)); + std::max(unsigned_max, get_varint_value(item)); } else { - signed_max = std::max(signed_max, - get_varint_value(item) > 0 - ? get_varint_value(item) - : -(get_varint_value(item) + 1)); + signed_max = std::max(signed_max, + get_varint_value(item) > 0 + ? get_varint_value(item) + : -(get_varint_value(item) + 1)); } } ++i; @@ -174,8 +175,8 @@ class packer { template static constexpr int STRUCT_PACK_INLINE get_fast_varint_width(char (&vec)[sz], const Args &...items) { - uint64_t unsigned_max = 0; - int64_t signed_max = 0; + typename uint_t()>::type unsigned_max = 0; + typename int_t()>::type signed_max = 0; unsigned int i = 0; (get_fast_varint_width_impl(vec, i, items, unsigned_max, signed_max), @@ -535,35 +536,40 @@ STRUCT_PACK_MAY_INLINE void serialize_to(Writer &writer, #endif static_assert(sizeof...(args) > 0); detail::packer> o(writer, info); - switch ((info.metainfo() & 0b11000) >> 3) { - case 0: - o.template serialize(args...); - break; + if constexpr (!check_if_has_container>()) { + o.template serialize(args...); + } + else { + switch ((info.metainfo() & 0b11000) >> 3) { + case 0: + o.template serialize(args...); + break; #ifdef STRUCT_PACK_OPTIMIZE - case 1: - o.template serialize(args...); - break; - case 2: - o.template serialize(args...); - break; - case 3: - if constexpr (sizeof(std::size_t) >= 8) { - o.template serialize(args...); - } - else { - unreachable(); - } - break; + case 1: + o.template serialize(args...); + break; + case 2: + o.template serialize(args...); + break; + case 3: + if constexpr (sizeof(std::size_t) >= 8) { + o.template serialize(args...); + } + else { + unreachable(); + } + break; #else - case 1: - case 2: - case 3: - o.template serialize(args...); - break; + case 1: + case 2: + case 3: + o.template serialize(args...); + break; #endif - default: - detail::unreachable(); - break; - }; + default: + detail::unreachable(); + break; + }; + } } } // namespace struct_pack::detail \ No newline at end of file diff --git a/include/ylt/struct_pack/util.h b/include/ylt/struct_pack/util.h index 7ba44f791..988899928 100644 --- a/include/ylt/struct_pack/util.h +++ b/include/ylt/struct_pack/util.h @@ -137,7 +137,9 @@ void string_set_length_hacker(std::string &, std::size_t); template inline void resize(std::basic_string &raw_str, std::size_t sz) { std::string &str = *reinterpret_cast(&raw_str); -#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) || \ +#if defined(__SANITIZE_ADDRESS__) + raw_str.resize(sz); +#elif defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) || \ defined(_MSVC_STL_VERSION) if (sz > str.capacity()) { str.reserve(sz); @@ -193,7 +195,9 @@ template class vector_thief::_Mypair), template inline void resize(std::vector &raw_vec, std::size_t sz) { -#if defined(__GLIBCXX__) || \ +#if defined(__SANITIZE_ADDRESS__) + raw_vec.resize(sz); +#elif defined(__GLIBCXX__) || \ (defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_ASAN)) || \ defined(_MSVC_STL_VERSION) std::vector &vec = *reinterpret_cast *>(&raw_vec); diff --git a/include/ylt/struct_pack/varint.hpp b/include/ylt/struct_pack/varint.hpp index 4eef1bfce..9e2037346 100644 --- a/include/ylt/struct_pack/varint.hpp +++ b/include/ylt/struct_pack/varint.hpp @@ -52,6 +52,29 @@ struct int_t<8> { using type = int64_t; }; +template +struct uint_t; + +template <> +struct uint_t<1> { + using type = uint8_t; +}; + +template <> +struct uint_t<2> { + using type = uint16_t; +}; + +template <> +struct uint_t<4> { + using type = uint32_t; +}; + +template <> +struct uint_t<8> { + using type = uint64_t; +}; + template class varint { public: diff --git a/src/struct_pack/benchmark/config.hpp b/src/struct_pack/benchmark/config.hpp index 6f1c7238d..135570867 100644 --- a/src/struct_pack/benchmark/config.hpp +++ b/src/struct_pack/benchmark/config.hpp @@ -15,11 +15,23 @@ enum class LibType { PROTOBUF, FLATBUFFER, }; -enum class SampleType { RECT, RECTS, PERSON, PERSONS, MONSTER, MONSTERS }; +enum class SampleType { + RECT, + RECTS, + VAR_RECT, + VAR_RECTS, + PERSON, + PERSONS, + MONSTER, + MONSTERS +}; inline const std::unordered_map g_sample_name_map = { {SampleType::RECT, "1 rect"}, {SampleType::RECTS, std::to_string(OBJECT_COUNT) + " rects"}, + {SampleType::VAR_RECT, "1 rect(with fast varint edcode)"}, + {SampleType::VAR_RECTS, + std::to_string(OBJECT_COUNT) + " rects(with fast varint edcode)"}, {SampleType::PERSON, "1 person"}, {SampleType::PERSONS, std::to_string(OBJECT_COUNT) + " persons"}, {SampleType::MONSTER, "1 monster"}, diff --git a/src/struct_pack/benchmark/data_def.hpp b/src/struct_pack/benchmark/data_def.hpp index c4decac67..677337547 100644 --- a/src/struct_pack/benchmark/data_def.hpp +++ b/src/struct_pack/benchmark/data_def.hpp @@ -15,6 +15,7 @@ */ #pragma once +#include "ylt/struct_pack.hpp" #include "ylt/struct_pack/reflection.hpp" #if __has_include() #define HAVE_MSGPACK 1 @@ -60,6 +61,28 @@ inline constexpr struct_pack::sp_config set_sp_config( return struct_pack::DISABLE_ALL_META_INFO; } +template +struct rect2 { + T x; + T y; + T width; + T height; +#ifdef HAVE_MSGPACK + MSGPACK_DEFINE(x, y, width, height); +#endif +}; + +inline constexpr struct_pack::sp_config set_sp_config(rect2 *) { + return struct_pack::sp_config{struct_pack::sp_config::DISABLE_ALL_META_INFO | + struct_pack::sp_config::USE_FAST_VARINT | + struct_pack::sp_config::ENCODING_WITH_VARINT}; +} + +inline constexpr struct_pack::sp_config set_sp_config( + std::vector> *) { + return struct_pack::sp_config{struct_pack::DISABLE_ALL_META_INFO}; +} + enum Color : uint8_t { Red, Green, Blue }; struct Vec3 { diff --git a/src/struct_pack/benchmark/flatbuffer_sample.hpp b/src/struct_pack/benchmark/flatbuffer_sample.hpp index 5f49e7e69..796023576 100644 --- a/src/struct_pack/benchmark/flatbuffer_sample.hpp +++ b/src/struct_pack/benchmark/flatbuffer_sample.hpp @@ -35,7 +35,7 @@ inline void create(flatbuffers::FlatBufferBuilder &builder, size_t object_count) { static std::vector rects_vector; rects_vector.clear(); - rects_vector.assign(object_count, fb::rect32{1, 11, 1111, 1111111}); + rects_vector.assign(object_count, fb::rect32{1, 0, 11, 1}); auto rects = builder.CreateVectorOfStructs(rects_vector); auto orc = fb::Createrect32s(builder, rects); builder.Finish(orc); @@ -44,7 +44,7 @@ inline void create(flatbuffers::FlatBufferBuilder &builder, template <> inline void create(flatbuffers::FlatBufferBuilder &builder, size_t object_count) { - const auto orc = fb::rect32{1, 11, 1111, 1111111}; + const auto orc = fb::rect32{1, 0, 11, 1}; auto offset = builder.CreateStruct(orc); builder.Finish(offset); } diff --git a/src/struct_pack/benchmark/protobuf_sample.hpp b/src/struct_pack/benchmark/protobuf_sample.hpp index aa6c2179e..bdeaeeed8 100644 --- a/src/struct_pack/benchmark/protobuf_sample.hpp +++ b/src/struct_pack/benchmark/protobuf_sample.hpp @@ -27,9 +27,9 @@ inline auto create_rects(size_t object_count) { for (int i = 0; i < object_count; i++) { mygame::rect32 *rc = rcs.add_rect32_list(); rc->set_x(1); - rc->set_y(11); - rc->set_width(1111); - rc->set_height(111111); + rc->set_y(0); + rc->set_width(11); + rc->set_height(1); } return rcs; } diff --git a/src/struct_pack/benchmark/sample.hpp b/src/struct_pack/benchmark/sample.hpp index 25e45a35f..471d304db 100644 --- a/src/struct_pack/benchmark/sample.hpp +++ b/src/struct_pack/benchmark/sample.hpp @@ -19,25 +19,16 @@ struct base_sample { void print_buffer_size(LibType type) { auto lib_name = get_lib_name(type); - for (auto sample_type : g_sample_type_vec) { + for (auto iter : buf_size_map_) { std::string prefix = lib_name; - prefix.append(" serialize ").append(get_sample_name(sample_type)); + prefix.append(" serialize ").append(get_sample_name(iter.first)); auto space_str = get_space_str(prefix.size(), 36); - std::cout << prefix << space_str - << " buffer size = " << buffer_size(sample_type) << "\n"; + std::cout << prefix << space_str << " buffer size = " << iter.second + << "\n"; } } - virtual std::size_t buffer_size(SampleType type) const { - auto it = buf_size_map_.find(type); - if (it == buf_size_map_.end()) { - throw std::runtime_error("unknown sample type"); - } - - return it->second; - } - auto &get_ser_time_elapsed_map() { return ser_time_elapsed_map_; } auto &get_deser_time_elapsed_map() { return deser_time_elapsed_map_; } diff --git a/src/struct_pack/benchmark/struct_pack_sample.hpp b/src/struct_pack/benchmark/struct_pack_sample.hpp index af2d3e9f0..abaa05cab 100644 --- a/src/struct_pack/benchmark/struct_pack_sample.hpp +++ b/src/struct_pack/benchmark/struct_pack_sample.hpp @@ -11,7 +11,7 @@ #include "sample.hpp" inline auto create_rects(size_t object_count) { - rect rc{1, 11, 1111, 111111}; + rect rc{1, 0, 11, 1}; std::vector> v{}; for (std::size_t i = 0; i < object_count; i++) { v.push_back(rc); @@ -19,6 +19,15 @@ inline auto create_rects(size_t object_count) { return v; } +inline auto create_rect2s(size_t object_count) { + rect2 rc{1, 0, 11, 1}; + std::vector> v{}; + for (std::size_t i = 0; i < object_count; i++) { + v.push_back(rc); + } + return v; +} + inline auto create_persons(size_t object_count) { std::vector v{}; person p{432798, "tom", 24, 65536.42}; @@ -74,11 +83,14 @@ struct struct_pack_sample : public base_sample { rects_ = create_rects(OBJECT_COUNT); persons_ = create_persons(OBJECT_COUNT); monsters_ = create_monsters(OBJECT_COUNT); + rect2s_ = create_rect2s(OBJECT_COUNT); } void do_serialization() override { serialize(SampleType::RECT, rects_[0]); serialize(SampleType::RECTS, rects_); + serialize(SampleType::VAR_RECT, rect2s_[0]); + serialize(SampleType::VAR_RECTS, rect2s_); serialize(SampleType::PERSON, persons_[0]); serialize(SampleType::PERSONS, persons_); serialize(SampleType::MONSTER, monsters_[0]); @@ -88,6 +100,8 @@ struct struct_pack_sample : public base_sample { void do_deserialization() override { deserialize(SampleType::RECT, rects_[0]); deserialize(SampleType::RECTS, rects_); + deserialize(SampleType::VAR_RECT, rect2s_[0]); + deserialize(SampleType::VAR_RECTS, rect2s_); deserialize(SampleType::PERSON, persons_[0]); deserialize(SampleType::PERSONS, persons_); deserialize(SampleType::MONSTER, monsters_[0]); @@ -140,6 +154,7 @@ struct struct_pack_sample : public base_sample { deser_time_elapsed_map_.emplace(sample_type, ns); } + std::vector> rect2s_; std::vector> rects_; std::vector persons_; std::vector monsters_; diff --git a/src/struct_pack/benchmark/struct_pb_sample.hpp b/src/struct_pack/benchmark/struct_pb_sample.hpp index 23dc83c94..71621e732 100644 --- a/src/struct_pack/benchmark/struct_pb_sample.hpp +++ b/src/struct_pack/benchmark/struct_pb_sample.hpp @@ -17,7 +17,7 @@ namespace struct_pb_sample { inline auto create_rects(std::size_t object_count) { rect32s rcs; for (int i = 0; i < object_count; ++i) { - rect32 rc{.x = 1, .y = 11, .width = 1111, .height = 111111}; + rect32 rc{1, 0, 11, 1}; rcs.rect32_list.emplace_back(rc); } return rcs; diff --git a/src/struct_pack/examples/serialize_config.cpp b/src/struct_pack/examples/serialize_config.cpp index 657408268..2ee531e78 100644 --- a/src/struct_pack/examples/serialize_config.cpp +++ b/src/struct_pack/examples/serialize_config.cpp @@ -16,6 +16,8 @@ #include +#include "ylt/struct_pack/reflection.hpp" + #define STRUCT_PACK_OPTIMIZE // add this macro to speed up // serialize/deserialize but it will cost more // time to compile @@ -26,15 +28,25 @@ // add this macro to enable support of int128/uint128 #include -using var_int = struct_pack::var_int32_t; struct rect { - var_int a, b, c, d; + int a, b, c, d; bool operator==(const rect& o) const { return a == o.a && b == o.b && c == o.c && d == o.d; } + constexpr static auto struct_pack_config = + struct_pack::DISABLE_ALL_META_INFO | struct_pack::ENCODING_WITH_VARINT | + struct_pack::USE_FAST_VARINT; }; +// Or,you can also use ADL helper function to config it. this function should +// in the same namespace of type +inline constexpr struct_pack::sp_config set_sp_config(rect*) { + return struct_pack::sp_config{struct_pack::DISABLE_ALL_META_INFO | + struct_pack::ENCODING_WITH_VARINT | + struct_pack::USE_FAST_VARINT}; +} + //clang-format off void serialize_config() { // serialize with config @@ -49,12 +61,6 @@ void serialize_config() { assert(result.value() == r); } -// or, you can also use ADL helper function to config it. this function should -// in the same namespace of type -inline constexpr struct_pack::sp_config set_sp_config(rect*) { - return struct_pack::DISABLE_ALL_META_INFO; -} - void serialize_config_by_ADL() { // serialize with config rect r{1, -1, 0, 5}; diff --git a/website/docs/en/guide/what_is_yalantinglibs.md b/website/docs/en/guide/what_is_yalantinglibs.md index 6b0798e99..97a533eee 100644 --- a/website/docs/en/guide/what_is_yalantinglibs.md +++ b/website/docs/en/guide/what_is_yalantinglibs.md @@ -155,7 +155,7 @@ More examples [here](https://github.com/alibaba/yalantinglibs/tree/main/src/coro Based on compile-time reflection, very easy to use, high performance serialization library, struct_pack is a header only library, it is used by coro_rpc now. -Only one line code to finish serialization and deserialization, 2-50x faster than protobuf. +Only one line code to finish serialization and deserialization, 2-20x faster than protobuf. [English Introduction](https://alibaba.github.io/yalantinglibs/en/struct_pack/struct_pack_intro.html) diff --git a/website/docs/en/index.md b/website/docs/en/index.md index 0996fbe6f..e63d8d72a 100644 --- a/website/docs/en/index.md +++ b/website/docs/en/index.md @@ -17,7 +17,7 @@ hero: features: - title: struct_pack - details: Only one line code to finish serialization and deserialization, 2-50x faster than protobuf. + details: Only one line code to finish serialization and deserialization, 2-20x faster than protobuf. - title: coro_rpc details: Very easy-to-use, coroutine-based, high performance rpc framework with C++20, more than 2000w qps in echo scene. - title: struct_json\struct_xml\struct_yaml diff --git a/website/docs/en/struct_pack/struct_pack_tips.md b/website/docs/en/struct_pack/struct_pack_tips.md index d611d6aa5..9a885c24a 100644 --- a/website/docs/en/struct_pack/struct_pack_tips.md +++ b/website/docs/en/struct_pack/struct_pack_tips.md @@ -40,9 +40,13 @@ struct_pack allows user to configure the content of the metadata via `struct_pac | DISABLE_TYPE_INFO | Prohibit storing full type information in serialized data, even in DEBUG mode| | ENABLE_TYPE_INFO | Prohibit storing full type information in serialized data, even in DEBUG mode| | DISABLE_META_INFO| Force full type information to be stored in serialized data, even if not in DEBUG mode| +| ENCODING_WITH_VARINT| encode integer(int32_t,int64_t,uint32_t,uint64_t) as variable length coding| +| USE_FAST_VARINT| encode integer(int32_t,int64_t,uint32_t,uint64_t) as fast variable length coding| Note that when serialization is configured with the DISABLE_META_INFO option, it must be ensured that deserialization also uses this option, otherwise the behavior is undefined and the probability is that deserialization will fail. +Also, note that if structure A nests structure B, the configuration for A will not take effect for B. + For example: ```cpp struct rect { @@ -50,7 +54,20 @@ struct rect { }; ``` -### Using ADL as a Serialization Configuration +### config by class static member + +Just add a constexpr static member named `struct_pack_config` to the class + +```cpp +struct rect { + int a, b, c, d; + constexpr static auto struct_pack_config = struct_pack::DISABLE_ALL_META_INFO; +}; +``` + +### config by ADL + +ADL configuration takes precedence over class static member. we can declare a function `set_sp_config` in the same namespace of type `rect`: @@ -60,17 +77,17 @@ inline constexpr struct_pack::sp_config set_sp_config(rect*) { } ``` -### Configuration using template parameters +### config by template parameters -For example +This method has the highest priority and requires the configuration to be passed in as a template parameter each time it is serialised. + +Note that the `USE_FAST_VARINT` and `ENCODING_WITH_VARINT` configurations are ineffective here. ```cpp auto buffer = struct_pack::serialize(rect{}); auto result = struct_pack::deserialize(buffer); ``` -When both are configured, the template parameter takes precedence over the ADL. - Currently we do not allow the `DISABLE_ALL_META_INFO` configuration to be enabled with a compatible field. ## Type requires diff --git a/website/docs/zh/index.md b/website/docs/zh/index.md index bd9948bc1..6abd3287b 100644 --- a/website/docs/zh/index.md +++ b/website/docs/zh/index.md @@ -17,7 +17,7 @@ hero: features: - title: struct_pack - details: 只需要一行代码完成序列化和反序列化, 比 protobuf 快 2-50 倍. + details: 只需要一行代码完成序列化和反序列化, 比 protobuf 快 2-20 倍. - title: coro_rpc details: Very easy-to-use, coroutine-based, high performance rpc framework with C++20, more than 2000w qps in echo scene. - title: struct_json\struct_xml\struct_yaml diff --git a/website/docs/zh/struct_pack/struct_pack_intro.md b/website/docs/zh/struct_pack/struct_pack_intro.md index f468f3648..c5ba233ff 100644 --- a/website/docs/zh/struct_pack/struct_pack_intro.md +++ b/website/docs/zh/struct_pack/struct_pack_intro.md @@ -166,6 +166,16 @@ assert(nested2) assert(nested2==nested1); ``` +## 对整数启用变长压缩编码 + +```cpp +struct rect { + int a,b,c,d; + constexpr static auto struct_pack_config = struct_pack::ENCODING_WITH_VARINT| struct_pack::USE_FAST_VARINT; +}; + +``` + ## 自定义功能支持 ### 用户自定义反射 diff --git a/website/docs/zh/struct_pack/struct_pack_tips.md b/website/docs/zh/struct_pack/struct_pack_tips.md index 606eca8ea..a713bc844 100644 --- a/website/docs/zh/struct_pack/struct_pack_tips.md +++ b/website/docs/zh/struct_pack/struct_pack_tips.md @@ -41,18 +41,35 @@ struct_pack允许通过`struct_pack::sp_config`来配置序列化生成的元数 | DISABLE_TYPE_INFO |禁止在序列化数据中存储完整类型信息,即使在DEBUG模式下| | ENABLE_TYPE_INFO | 强制在序列化数据中存储完整类型信息,即使不在DEBUG模式下| | DISABLE_META_INFO| 禁用元信息和4字节的类型校验码,从而减小二进制数据的体积| +| ENCODING_WITH_VARINT| 当前结构体的整数(int32_t,int64_t,uint32_t,uint64_t)将启用变长编码| +| USE_FAST_VARINT| 对整数启用快速变长编码,该编码具有更好的反序列化性能,小字段下体积也更小| 需要注意的是,当序列化配置了DISABLE_META_INFO选项时,必须保证反序列化也使用了该选项,否则行为未定义,大概率反序列化会失败。 +此外,需要注意的是,如果结构体A嵌套了结构体B,则对A的配置不会对B生效。 + 假设有类型: ```cpp struct rect { - var_int a, b, c, d; + int a, b, c, d; +}; +``` + +### 通过类静态成员配置 + +在类中添加一个constexpr static的成员struct_pack_config即可 + +```cpp +struct rect { + int a, b, c, d; + constexpr static auto struct_pack_config = struct_pack::DISABLE_ALL_META_INFO; }; ``` -### 使用ADL作为序列化配置 +### 通过ADL配置 -在类型`rect`相同的namespace 下添加函数`set_sp_config`即可。 +ADL配置的优先级高于类的静态成员。 + +用户只需要在类型`rect`相同的namespace 下添加函数`set_sp_config`即可。 ```cpp inline constexpr struct_pack::sp_config set_sp_config(rect*) { @@ -60,9 +77,11 @@ inline constexpr struct_pack::sp_config set_sp_config(rect*) { } ``` -### 使用模板参数配置 +### 通过模板参数配置 + +该方法具有最高的优先级,要求每次序列化时都将配置作为模板参数传入。 -该方法要求每次序列化时都将配置作为模板参数传入: +需要注意的是`USE_FAST_VARINT`和`ENCODING_WITH_VARINT`配置在此处设置无效。 ```cpp auto buffer = struct_pack::serialize(rect{});