diff --git a/include/ylt/struct_pack.hpp b/include/ylt/struct_pack.hpp index 772358f4f..5a6f82db6 100644 --- a/include/ylt/struct_pack.hpp +++ b/include/ylt/struct_pack.hpp @@ -134,14 +134,13 @@ STRUCT_PACK_INLINE constexpr decltype(auto) get_type_literal() { } } -template +template [[nodiscard]] STRUCT_PACK_INLINE constexpr serialize_buffer_size get_needed_size(const Args &...args) { return detail::get_serialize_runtime_info(args...); } -template +template STRUCT_PACK_INLINE void serialize_to(Writer &writer, const Args &...args) { static_assert(sizeof...(args) > 0); if constexpr (struct_pack::writer_t) { @@ -165,7 +164,7 @@ STRUCT_PACK_INLINE void serialize_to(Writer &writer, const Args &...args) { } } -template +template void STRUCT_PACK_INLINE serialize_to(char *buffer, serialize_buffer_size info, const Args &...args) noexcept { static_assert(sizeof...(args) > 0); @@ -173,7 +172,7 @@ void STRUCT_PACK_INLINE serialize_to(char *buffer, serialize_buffer_size info, struct_pack::detail::serialize_to(writer, info, args...); } -template = 201907L detail::struct_pack_buffer Buffer, #else @@ -202,7 +201,7 @@ template < #else typename Buffer = std::vector, #endif - uint64_t conf = type_info_config::automatic, typename... Args> + typename... Args> [[nodiscard]] STRUCT_PACK_INLINE Buffer serialize(const Args &...args) { #if __cpp_concepts < 201907L static_assert(detail::struct_pack_buffer, @@ -210,7 +209,7 @@ template < #endif static_assert(sizeof...(args) > 0); Buffer buffer; - serialize_to(buffer, args...); + serialize_to(buffer, args...); return buffer; } @@ -220,7 +219,44 @@ template < #else typename Buffer = std::vector, #endif - uint64_t conf = type_info_config::automatic, typename... Args> + typename... Args> +[[nodiscard]] STRUCT_PACK_INLINE Buffer +serialize_with_offset(std::size_t offset, const Args &...args) { +#if __cpp_concepts < 201907L + static_assert(detail::struct_pack_buffer, + "The buffer is not satisfied struct_pack_buffer requirement!"); +#endif + static_assert(sizeof...(args) > 0); + Buffer buffer; + serialize_to_with_offset(buffer, offset, args...); + return buffer; +} + +template = 201907L + detail::struct_pack_buffer Buffer = std::vector, +#else + typename Buffer = std::vector, +#endif + typename... Args> +[[nodiscard]] STRUCT_PACK_INLINE Buffer serialize(const Args &...args) { +#if __cpp_concepts < 201907L + static_assert(detail::struct_pack_buffer, + "The buffer is not satisfied struct_pack_buffer requirement!"); +#endif + static_assert(sizeof...(args) > 0); + Buffer buffer; + serialize_to(buffer, args...); + return buffer; +} + +template = 201907L + detail::struct_pack_buffer Buffer = std::vector, +#else + typename Buffer = std::vector, +#endif + typename... Args> [[nodiscard]] STRUCT_PACK_INLINE Buffer serialize_with_offset(std::size_t offset, const Args &...args) { #if __cpp_concepts < 201907L @@ -234,37 +270,41 @@ serialize_with_offset(std::size_t offset, const Args &...args) { } #if __cpp_concepts >= 201907L -template +template #else template < - typename T, typename... Args, typename View, + uint64_t conf = sp_config::DEFAULT, typename T, typename... Args, + typename View, typename = std::enable_if_t>> #endif [[nodiscard]] STRUCT_PACK_INLINE struct_pack::errc deserialize_to( T &t, const View &v, Args &...args) { detail::memory_reader reader{(const char *)v.data(), (const char *)v.data() + v.size()}; - detail::unpacker in(reader); + detail::unpacker in(reader); return in.deserialize(t, args...); } -template +template [[nodiscard]] STRUCT_PACK_INLINE struct_pack::errc deserialize_to( T &t, const char *data, size_t size, Args &...args) { detail::memory_reader reader{data, data + size}; - detail::unpacker in(reader); + detail::unpacker in(reader); return in.deserialize(t, args...); } #if __cpp_concepts >= 201907L -template +template #else -template >> #endif [[nodiscard]] STRUCT_PACK_INLINE struct_pack::errc deserialize_to( T &t, Reader &reader, Args &...args) { - detail::unpacker in(reader); + detail::unpacker in(reader); std::size_t consume_len; auto old_pos = reader.tellg(); auto ret = in.deserialize_with_len(consume_len, t, args...); @@ -292,16 +332,18 @@ template = 201907L -template +template #else -template >> #endif [[nodiscard]] STRUCT_PACK_INLINE struct_pack::errc deserialize_to( T &t, const View &v, size_t &consume_len, Args &...args) { detail::memory_reader reader{(const char *)v.data(), (const char *)v.data() + v.size()}; - detail::unpacker in(reader); + detail::unpacker in(reader); auto ret = in.deserialize_with_len(consume_len, t, args...); if SP_LIKELY (ret == errc{}) { consume_len = (std::max)((size_t)(reader.now - v.data()), consume_len); @@ -312,11 +354,11 @@ template +template [[nodiscard]] STRUCT_PACK_INLINE struct_pack::errc deserialize_to( T &t, const char *data, size_t size, size_t &consume_len, Args &...args) { detail::memory_reader reader{data, data + size}; - detail::unpacker in(reader); + detail::unpacker in(reader); auto ret = in.deserialize_with_len(consume_len, t, args...); if SP_LIKELY (ret == errc{}) { consume_len = (std::max)((size_t)(reader.now - data), consume_len); @@ -328,9 +370,11 @@ template } #if __cpp_concepts >= 201907L -template +template #else -template +template #endif [[nodiscard]] STRUCT_PACK_INLINE struct_pack::errc deserialize_to_with_offset( T &t, const View &v, size_t &offset, Args &...args) { @@ -341,7 +385,7 @@ template return ret; } -template +template [[nodiscard]] STRUCT_PACK_INLINE struct_pack::errc deserialize_to_with_offset( T &t, const char *data, size_t size, size_t &offset, Args &...args) { size_t sz; @@ -351,13 +395,13 @@ template } #if __cpp_concepts >= 201907L -template +template #else -template >> #endif [[nodiscard]] STRUCT_PACK_INLINE auto deserialize(const View &v) { - expected, struct_pack::errc> ret; + expected, struct_pack::errc> ret; auto errc = deserialize_to(ret.value(), v); if SP_UNLIKELY (errc != struct_pack::errc{}) { ret = unexpected{errc}; @@ -365,10 +409,10 @@ template +template [[nodiscard]] STRUCT_PACK_INLINE auto deserialize(const char *data, size_t size) { - expected, struct_pack::errc> ret; + expected, struct_pack::errc> ret; if (auto errc = deserialize_to(ret.value(), data, size); errc != struct_pack::errc{}) { ret = unexpected{errc}; @@ -376,13 +420,13 @@ template return ret; } #if __cpp_concepts >= 201907L -template +template #else -template >> #endif [[nodiscard]] STRUCT_PACK_INLINE auto deserialize(Reader &v) { - expected, struct_pack::errc> ret; + expected, struct_pack::errc> ret; auto errc = deserialize_to(ret.value(), v); if SP_UNLIKELY (errc != struct_pack::errc{}) { ret = unexpected{errc}; @@ -391,13 +435,13 @@ template = 201907L -template +template #else -template +template #endif [[nodiscard]] STRUCT_PACK_INLINE auto deserialize(const View &v, size_t &consume_len) { - expected, struct_pack::errc> ret; + expected, struct_pack::errc> ret; auto errc = deserialize_to(ret.value(), v, consume_len); if SP_UNLIKELY (errc != struct_pack::errc{}) { ret = unexpected{errc}; @@ -405,10 +449,10 @@ template return ret; } -template +template [[nodiscard]] STRUCT_PACK_INLINE auto deserialize(const char *data, size_t size, size_t &consume_len) { - expected, struct_pack::errc> ret; + expected, struct_pack::errc> ret; auto errc = deserialize_to(ret.value(), data, size, consume_len); if SP_UNLIKELY (errc != struct_pack::errc{}) { ret = unexpected{errc}; @@ -417,13 +461,80 @@ template } #if __cpp_concepts >= 201907L -template +template +#else +template >> +#endif +[[nodiscard]] STRUCT_PACK_INLINE auto deserialize(const View &v) { + expected, struct_pack::errc> ret; + auto errc = deserialize_to(ret.value(), v); + if SP_UNLIKELY (errc != struct_pack::errc{}) { + ret = unexpected{errc}; + } + return ret; +} + +template +[[nodiscard]] STRUCT_PACK_INLINE auto deserialize(const char *data, + size_t size) { + expected, struct_pack::errc> ret; + if (auto errc = deserialize_to(ret.value(), data, size); + errc != struct_pack::errc{}) { + ret = unexpected{errc}; + } + return ret; +} + +#if __cpp_concepts >= 201907L +template +#else +template >> +#endif +[[nodiscard]] STRUCT_PACK_INLINE auto deserialize(Reader &v) { + expected, struct_pack::errc> ret; + auto errc = deserialize_to(ret.value(), v); + if SP_UNLIKELY (errc != struct_pack::errc{}) { + ret = unexpected{errc}; + } + return ret; +} + +#if __cpp_concepts >= 201907L +template #else -template +template +#endif +[[nodiscard]] STRUCT_PACK_INLINE auto deserialize(const View &v, + size_t &consume_len) { + expected, struct_pack::errc> ret; + auto errc = deserialize_to(ret.value(), v, consume_len); + if SP_UNLIKELY (errc != struct_pack::errc{}) { + ret = unexpected{errc}; + } + return ret; +} + +template +[[nodiscard]] STRUCT_PACK_INLINE auto deserialize(const char *data, size_t size, + size_t &consume_len) { + expected, struct_pack::errc> ret; + auto errc = deserialize_to(ret.value(), data, size, consume_len); + if SP_UNLIKELY (errc != struct_pack::errc{}) { + ret = unexpected{errc}; + } + return ret; +} + +#if __cpp_concepts >= 201907L +template +#else +template #endif [[nodiscard]] STRUCT_PACK_INLINE auto deserialize_with_offset(const View &v, size_t &offset) { - expected, struct_pack::errc> ret; + expected, struct_pack::errc> ret; auto errc = deserialize_to_with_offset(ret.value(), v, offset); if SP_UNLIKELY (errc != struct_pack::errc{}) { ret = unexpected{errc}; @@ -431,11 +542,11 @@ template return ret; } -template +template [[nodiscard]] STRUCT_PACK_INLINE auto deserialize_with_offset(const char *data, size_t size, size_t &offset) { - expected, struct_pack::errc> ret; + expected, struct_pack::errc> ret; auto errc = deserialize_to_with_offset(ret.value(), data, size, offset); if SP_UNLIKELY (errc != struct_pack::errc{}) { ret = unexpected{errc}; @@ -444,9 +555,11 @@ template } #if __cpp_concepts >= 201907L -template +template #else -template >> #endif [[nodiscard]] STRUCT_PACK_INLINE struct_pack::errc get_field_to(Field &dst, @@ -457,11 +570,12 @@ template in(reader); return in.template get_field(dst); } -template +template [[nodiscard]] STRUCT_PACK_INLINE struct_pack::errc get_field_to( Field &dst, const char *data, size_t size) { using T_Field = std::tuple_element_t())>; @@ -469,14 +583,16 @@ template "The dst's type is not correct. It should be as same as the " "T's Ith field's type"); detail::memory_reader reader{data, data + size}; - detail::unpacker in(reader); + detail::unpacker in(reader); return in.template get_field(dst); } #if __cpp_concepts >= 201907L -template +template #else -template >> #endif [[nodiscard]] STRUCT_PACK_INLINE struct_pack::errc get_field_to( @@ -485,14 +601,16 @@ template , "The dst's type is not correct. It should be as same as the " "T's Ith field's type"); - detail::unpacker in(reader); + detail::unpacker in(reader); return in.template get_field(dst); } #if __cpp_concepts >= 201907L -template +template #else -template >> #endif [[nodiscard]] STRUCT_PACK_INLINE auto get_field(const View &v) { @@ -505,7 +623,7 @@ template +template [[nodiscard]] STRUCT_PACK_INLINE auto get_field(const char *data, size_t size) { using T_Field = std::tuple_element_t())>; expected ret; @@ -516,9 +634,11 @@ template return ret; } #if __cpp_concepts >= 201907L -template +template #else -template >> #endif [[nodiscard]] STRUCT_PACK_INLINE auto get_field(Reader &reader) { diff --git a/include/ylt/struct_pack/calculate_size.hpp b/include/ylt/struct_pack/calculate_size.hpp index 664970d34..27ab65429 100644 --- a/include/ylt/struct_pack/calculate_size.hpp +++ b/include/ylt/struct_pack/calculate_size.hpp @@ -15,6 +15,8 @@ */ #pragma once +#include + #include "alignment.hpp" #include "marco.h" #include "reflection.hpp" @@ -23,6 +25,7 @@ #include "type_trait.hpp" #include "util.h" #include "varint.hpp" +#include "ylt/struct_pack/type_calculate.hpp" namespace struct_pack { @@ -173,7 +176,7 @@ struct serialize_buffer_size { unsigned char metainfo_; public: - constexpr serialize_buffer_size() : len_(sizeof(uint32_t)), metainfo_(0) {} + constexpr serialize_buffer_size() : len_(0), metainfo_(0) {} constexpr std::size_t size() const { return len_; } constexpr unsigned char metainfo() const { return metainfo_; } constexpr operator std::size_t() const { return len_; } @@ -189,53 +192,64 @@ get_serialize_runtime_info(const Args &...args) { using Type = get_args_type; constexpr bool has_compatible = serialize_static_config::has_compatible; constexpr bool has_type_literal = check_if_add_type_literal(); + constexpr bool disable_hash_head = check_if_disable_hash_head(); + constexpr bool has_container = check_if_has_container(); + constexpr bool has_compile_time_determined_meta_info = + check_has_metainfo(); serialize_buffer_size ret; auto sz_info = calculate_payload_size(args...); - - if SP_LIKELY (sz_info.max_size < (int64_t{1} << 8)) { - ret.len_ += sz_info.total + sz_info.size_cnt; - ret.metainfo_ = 0b00000; - constexpr bool has_compile_time_determined_meta_info = - has_compatible || has_type_literal; - if constexpr (has_compile_time_determined_meta_info) { - ret.len_ += sizeof(unsigned char); - } + if constexpr (has_compile_time_determined_meta_info) { + ret.len_ = sizeof(unsigned char); + } + if constexpr (!has_container) { + ret.len_ += sz_info.total; } else { - if (sz_info.max_size < (int64_t{1} << 16)) { - ret.len_ += sz_info.total + sz_info.size_cnt * 2; - ret.metainfo_ = 0b01000; - } - else if (sz_info.max_size < (int64_t{1} << 32)) { - ret.len_ += sz_info.total + sz_info.size_cnt * 4; - ret.metainfo_ = 0b10000; + if SP_LIKELY (sz_info.max_size < (int64_t{1} << 8)) { + ret.len_ += sz_info.total + sz_info.size_cnt; } else { - ret.len_ += sz_info.total + sz_info.size_cnt * 8; - ret.metainfo_ = 0b11000; + if (sz_info.max_size < (int64_t{1} << 16)) { + ret.len_ += sz_info.total + sz_info.size_cnt * 2; + ret.metainfo_ = 0b01000; + } + else if (sz_info.max_size < (int64_t{1} << 32)) { + ret.len_ += sz_info.total + sz_info.size_cnt * 4; + ret.metainfo_ = 0b10000; + } + else { + ret.len_ += sz_info.total + sz_info.size_cnt * 8; + ret.metainfo_ = 0b11000; + } + if constexpr (!has_compile_time_determined_meta_info) { + ret.len_ += sizeof(unsigned char); + } + // size_type >= 1 , has metainfo } - // size_type >= 1 , has metainfo - ret.len_ += sizeof(unsigned char); - } - if constexpr (has_type_literal) { - constexpr auto type_literal = struct_pack::get_type_literal(); - // struct_pack::get_type_literal().size() crash in clang13. Bug? - ret.len_ += type_literal.size() + 1; - ret.metainfo_ |= 0b100; } - if constexpr (has_compatible) { // calculate bytes count of serialize - // length - if SP_LIKELY (ret.len_ + 2 < (int64_t{1} << 16)) { - ret.len_ += 2; - ret.metainfo_ |= 0b01; + if constexpr (!disable_hash_head) { + ret.len_ += sizeof(uint32_t); // for record hash code + if constexpr (has_type_literal) { + constexpr auto type_literal = struct_pack::get_type_literal(); + // struct_pack::get_type_literal().size() crash in clang13. + // Bug? + ret.len_ += type_literal.size() + 1; + ret.metainfo_ |= 0b100; } - else if (ret.len_ + 4 < (int64_t{1} << 32)) { - ret.len_ += 4; - ret.metainfo_ |= 0b10; - } - else { - ret.len_ += 8; - ret.metainfo_ |= 0b11; + if constexpr (has_compatible) { // calculate bytes count of serialize + // length + if SP_LIKELY (ret.len_ + 2 < (int64_t{1} << 16)) { + ret.len_ += 2; + ret.metainfo_ |= 0b01; + } + else if (ret.len_ + 4 < (int64_t{1} << 32)) { + ret.len_ += 4; + ret.metainfo_ |= 0b10; + } + else { + ret.len_ += 8; + ret.metainfo_ |= 0b11; + } } } return ret; diff --git a/include/ylt/struct_pack/derived_helper.hpp b/include/ylt/struct_pack/derived_helper.hpp index 5a47eb543..ebc1e69a4 100644 --- a/include/ylt/struct_pack/derived_helper.hpp +++ b/include/ylt/struct_pack/derived_helper.hpp @@ -169,25 +169,6 @@ struct deserialize_one_derived_class_helper { } }; -template -struct deserialize_one_compatible_in_derived_class_helper { - template - static STRUCT_PACK_INLINE constexpr struct_pack::errc run(unpacker *self, - Pointer &base) { - if constexpr (index >= std::tuple_size_v) { - unreachable(); - } - else { - using derived_class = std::tuple_element_t; -#ifdef STRUCT_PACK_RTTI_ENABLED - assert(dynamic_cast(base.get())); -#endif - return self->template deserialize_one( - *(derived_class *)base.get()); - } - } -}; - template using derived_class_set_t = decltype(struct_pack_derived_decl((Base *)nullptr)); diff --git a/include/ylt/struct_pack/packer.hpp b/include/ylt/struct_pack/packer.hpp index d9310bd2d..4a4e937ec 100644 --- a/include/ylt/struct_pack/packer.hpp +++ b/include/ylt/struct_pack/packer.hpp @@ -78,8 +78,7 @@ class packer { template static constexpr uint32_t STRUCT_PACK_INLINE calculate_hash_head() { constexpr uint32_t raw_types_code = calculate_raw_hash(); - if constexpr (serialize_static_config::has_compatible || - check_if_add_type_literal()) { + if constexpr (check_has_metainfo()) { return raw_types_code + 1; } else { // default case, only has hash_code @@ -91,7 +90,9 @@ class packer { constexpr void STRUCT_PACK_INLINE serialize_metainfo() { constexpr auto hash_head = calculate_hash_head() | (is_default_size_type ? 0 : 1); - write_wrapper(writer_, (char *)&hash_head); + if constexpr (!check_if_disable_hash_head()) { + write_wrapper(writer_, (char *)&hash_head); + } if constexpr (hash_head % 2) { // has more metainfo auto metainfo = info.metainfo(); write_wrapper(writer_, (char *)&metainfo); @@ -412,7 +413,7 @@ class packer { const serialize_buffer_size &info; }; -template = 201907L struct_pack::writer_t Writer, #else diff --git a/include/ylt/struct_pack/reflection.hpp b/include/ylt/struct_pack/reflection.hpp index e09f8973e..d706683f5 100644 --- a/include/ylt/struct_pack/reflection.hpp +++ b/include/ylt/struct_pack/reflection.hpp @@ -37,6 +37,14 @@ #include "util.h" namespace struct_pack { + +enum sp_config { + DEFAULT = 0, + DISABLE_TYPE_INFO = 0b1, + ENABLE_TYPE_INFO = 0b10, + DISABLE_ALL_META_INFO = 0b11 +}; + namespace detail { template @@ -534,6 +542,22 @@ template constexpr bool user_defined_refl = user_defined_refl_impl::value; #endif +#if __cpp_concepts >= 201907L + template + concept user_defined_config = std::is_same_v())),struct_pack::sp_config>; +#else + template + struct user_defined_config_impl : std::false_type {}; + + template + struct user_defined_config_impl())),struct_pack::sp_config>>>> + : std::true_type {}; + + template + constexpr bool user_defined_config = user_defined_refl_impl::value; +#endif + #if __cpp_concepts >= 201907L template concept tuple_size = requires(Type tuple) { diff --git a/include/ylt/struct_pack/type_calculate.hpp b/include/ylt/struct_pack/type_calculate.hpp index 19a9aba39..365283830 100644 --- a/include/ylt/struct_pack/type_calculate.hpp +++ b/include/ylt/struct_pack/type_calculate.hpp @@ -653,28 +653,146 @@ struct serialize_static_config { }; } // namespace detail -enum type_info_config { automatic = 0, disable = 1, enable = 2 }; - -template -constexpr inline type_info_config enable_type_info = - type_info_config::automatic; namespace detail { template constexpr bool check_if_add_type_literal() { - if constexpr (conf == type_info_config::automatic) { - if constexpr (enable_type_info == type_info_config::automatic) { + constexpr auto config = conf & 0b11; + if constexpr (config == sp_config::DEFAULT) { + if constexpr (struct_pack::detail::user_defined_config) { + constexpr auto config = set_sp_config((T *)nullptr) & 0b11; + if constexpr (config == sp_config::DEFAULT) { + return serialize_static_config::has_type_literal; + } + else { + return config == sp_config::ENABLE_TYPE_INFO; + } + } + else { return serialize_static_config::has_type_literal; } + } + else { + return config == sp_config::ENABLE_TYPE_INFO; + } +} + +template +constexpr bool check_if_has_container(); + +template +constexpr bool check_if_has_container_helper(std::index_sequence idx) { + return ((check_if_has_container>, + ParentArgs...>()) || + ...); +} + +template +constexpr bool check_if_has_container_variant_helper( + std::index_sequence idx) { + return ((check_if_has_container< + remove_cvref_t>, Arg, + ParentArgs...>()) || + ...); +} + +template +constexpr bool check_if_has_container() { + if constexpr (is_trivial_view_v) { + return check_if_has_container(); + } + else { + constexpr std::size_t has_cycle = check_circle(); + if constexpr (has_cycle != 0) { + return false; + } else { - return enable_type_info == type_info_config::enable; + constexpr auto id = get_type_id(); + if constexpr (id == type_id::struct_t) { + using Args = decltype(get_types()); + return check_if_has_container_helper( + std::make_index_sequence>()); + } + else if constexpr (id == type_id::variant_t) { + constexpr auto sz = std::variant_size_v; + static_assert(sz > 0, "empty param of std::variant is not allowed!"); + static_assert(sz < 256, "too many alternative type in variant!"); + return check_if_has_container_variant_helper( + std::make_index_sequence>()); + } + else if constexpr (id == type_id::array_t) { + return check_if_has_container< + remove_cvref_t()[0])>, Arg, + ParentArgs...>(); + } + else if constexpr (id == type_id::bitset_t) { + return false; + } + else if constexpr (unique_ptr) { + return check_if_has_container< + remove_cvref_t, Arg, ParentArgs...>(); + } + else if constexpr (id == type_id::container_t || + id == type_id::string_t || + id == type_id::set_container_t || + id == type_id::map_container_t) { + return true; + } + else if constexpr (id == type_id::optional_t || + id == type_id::compatible_t) { + return check_if_has_container, + Arg, ParentArgs...>(); + } + else if constexpr (id == type_id::expected_t) { + return check_if_has_container, + Arg, ParentArgs...>() || + check_if_has_container, + Arg, ParentArgs...>(); + } + else { + return false; + } } } +} + +template +constexpr bool check_if_disable_hash_head_impl() { + constexpr auto config = conf & 0b11; + if constexpr (config != sp_config::DISABLE_ALL_META_INFO) { + if constexpr (struct_pack::detail::user_defined_config) { + constexpr auto config = set_sp_config((T *)nullptr) & 0b11; + if constexpr (config == sp_config::DISABLE_ALL_META_INFO) { + return true; + } + } + return false; + } + return true; +} + +template +constexpr bool check_if_disable_hash_head() { + if constexpr (check_if_disable_hash_head_impl()) { + static_assert( + !check_if_compatible_element_exist())>(), + "It's not allow add compatible member when you disable hash head"); + return true; + } else { - return conf == type_info_config::enable; + return false; } } +template +constexpr bool check_has_metainfo() { + return serialize_static_config::has_compatible || + (!check_if_disable_hash_head() && + check_if_add_type_literal()) || + ((check_if_disable_hash_head() && + check_if_has_container())); +} + template constexpr auto get_types() { using T = remove_cvref_t; diff --git a/include/ylt/struct_pack/unpacker.hpp b/include/ylt/struct_pack/unpacker.hpp index 65f3a592e..6bdeb5bd0 100644 --- a/include/ylt/struct_pack/unpacker.hpp +++ b/include/ylt/struct_pack/unpacker.hpp @@ -81,7 +81,7 @@ struct memory_reader { }; #if __cpp_concepts >= 201907L -template +template #else template #endif @@ -502,46 +502,73 @@ class unpacker { STRUCT_PACK_INLINE std::pair deserialize_metainfo() { uint32_t current_types_code; - if constexpr (is_MD5_reader_wrapper) { - reader_.read_head((char *)¤t_types_code); + if constexpr (check_if_disable_hash_head()) { + if constexpr (is_MD5_reader_wrapper) { + static_assert(!sizeof(T), + "it's illegal if you want to deserialize a derived class " + "without md5"); + } + else if constexpr (check_if_has_container()) { + unsigned char metainfo; + if SP_UNLIKELY (!read_wrapper( + reader_, (char *)&metainfo)) { + return {struct_pack::errc::no_buffer_space, 0}; + } + size_type_ = (metainfo & 0b11000) >> 3; + return {}; + } + else { + size_type_ = 0; + return {}; + } } else { - if SP_UNLIKELY (!read_wrapper( - reader_, (char *)¤t_types_code)) { - return {struct_pack::errc::no_buffer_space, 0}; + if constexpr (is_MD5_reader_wrapper) { + reader_.read_head((char *)¤t_types_code); + if SP_LIKELY (current_types_code % 2 == 0) // unexist metainfo + { + size_type_ = 0; + return {}; + } + } + else { + if SP_UNLIKELY (!read_wrapper( + reader_, (char *)¤t_types_code)) { + return {struct_pack::errc::no_buffer_space, 0}; + } + constexpr uint32_t types_code = get_types_code(); + if SP_UNLIKELY ((current_types_code / 2) != (types_code / 2)) { + return {struct_pack::errc::invalid_buffer, 0}; + } + if SP_LIKELY (current_types_code % 2 == 0) // unexist metainfo + { + size_type_ = 0; + return {}; + } } - constexpr uint32_t types_code = get_types_code(); - if SP_UNLIKELY ((current_types_code / 2) != (types_code / 2)) { - return {struct_pack::errc::invalid_buffer, 0}; + unsigned char metainfo; + if SP_UNLIKELY (!read_wrapper(reader_, + (char *)&metainfo)) { + return {struct_pack::errc::no_buffer_space, 0}; } - } - if SP_LIKELY (current_types_code % 2 == 0) // unexist extended metainfo - { - size_type_ = 0; - return {}; - } - unsigned char metainfo; - if SP_UNLIKELY (!read_wrapper(reader_, - (char *)&metainfo)) { - return {struct_pack::errc::no_buffer_space, 0}; - } - std::pair ret; - auto compatible_sz_len = metainfo & 0b11; - if (compatible_sz_len) { - ret = deserialize_compatible(compatible_sz_len); - if SP_UNLIKELY (ret.first != errc{}) { - return ret; + std::pair ret; + auto compatible_sz_len = metainfo & 0b11; + if (compatible_sz_len) { + ret = deserialize_compatible(compatible_sz_len); + if SP_UNLIKELY (ret.first != errc{}) { + return ret; + } } - } - auto has_type_literal = metainfo & 0b100; - if (has_type_literal) { - auto ec = deserialize_type_literal(); - if SP_UNLIKELY (ec != errc{}) { - return {ec, 0}; + auto has_type_literal = metainfo & 0b100; + if (has_type_literal) { + auto ec = deserialize_type_literal(); + if SP_UNLIKELY (ec != errc{}) { + return {ec, 0}; + } } + size_type_ = (metainfo & 0b11000) >> 3; + return ret; } - size_type_ = (metainfo & 0b11000) >> 3; - return ret; } template diff --git a/src/struct_pack/benchmark/data_def.hpp b/src/struct_pack/benchmark/data_def.hpp index 7cba80996..c4decac67 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/reflection.hpp" #if __has_include() #define HAVE_MSGPACK 1 #endif @@ -50,6 +51,15 @@ struct rect { #endif }; +inline constexpr struct_pack::sp_config set_sp_config(rect *) { + return struct_pack::DISABLE_ALL_META_INFO; +} + +inline constexpr struct_pack::sp_config set_sp_config( + std::vector> *) { + return 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 39d05c318..5f49e7e69 100644 --- a/src/struct_pack/benchmark/flatbuffer_sample.hpp +++ b/src/struct_pack/benchmark/flatbuffer_sample.hpp @@ -222,10 +222,13 @@ struct flatbuffer_sample_t : public base_sample { uint64_t ns = 0; std::string bench_name = name() + " deserialize " + get_sample_name(sample_type); - ScopedTimer timer(bench_name.data(), ns); - for (int i = 0; i < ITERATIONS; ++i) { - auto obj = flatbuffers::GetRoot(builder.GetBufferPointer()); - no_op((char *)obj); + { + ScopedTimer timer(bench_name.data(), ns); + for (int i = 0; i < ITERATIONS; ++i) { + auto obj = + flatbuffers::GetRoot(builder.GetBufferPointer()); + no_op((char *)obj); + } } deser_time_elapsed_map_.emplace(sample_type, ns); } diff --git a/src/struct_pack/examples/CMakeLists.txt b/src/struct_pack/examples/CMakeLists.txt index 3b8d34d87..dafe28f08 100644 --- a/src/struct_pack/examples/CMakeLists.txt +++ b/src/struct_pack/examples/CMakeLists.txt @@ -18,4 +18,4 @@ else() # include_directories(include) # include_directories(include/ylt/thirdparty) endif() -add_executable(struct_pack_example basic_usage.cpp non_aggregated_type.cpp main.cpp) \ No newline at end of file +add_executable(struct_pack_example basic_usage.cpp non_aggregated_type.cpp serialize_config.cpp main.cpp) \ No newline at end of file diff --git a/src/struct_pack/examples/basic_usage.cpp b/src/struct_pack/examples/basic_usage.cpp index 4ddb51a42..7a6f31380 100644 --- a/src/struct_pack/examples/basic_usage.cpp +++ b/src/struct_pack/examples/basic_usage.cpp @@ -60,10 +60,6 @@ struct person { //clang-format off void basic_usage() { - std::vector a = {1, 2, 3}; - auto sz = - struct_pack::get_needed_size(a); - person p{20, "tom"}; person p2{/*.age =*/21, /*.name =*/"Betty"}; diff --git a/src/struct_pack/examples/main.cpp b/src/struct_pack/examples/main.cpp index 8adb941f7..d43e44c55 100644 --- a/src/struct_pack/examples/main.cpp +++ b/src/struct_pack/examples/main.cpp @@ -16,6 +16,7 @@ void basic_usage(); void non_aggregated_type(); +void serialize_config(); int main() { basic_usage(); diff --git a/src/struct_pack/examples/serialize_config.cpp b/src/struct_pack/examples/serialize_config.cpp new file mode 100644 index 000000000..efd811b74 --- /dev/null +++ b/src/struct_pack/examples/serialize_config.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023, Alibaba Group Holding Limited; + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#define STRUCT_PACK_OPTIMIZE // add this macro to speed up + // serialize/deserialize but it will cost more + // time to compile +#define STRUCT_PACK_ENABLE_UNPORTABLE_TYPE // add this macro to enable + // unportable type like wchar_t, + // std::wstring +// #define STRUCT_PACK_ENABLE_INT128 +// 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; + bool operator==(const rect& o) const { + return a == o.a && b == o.b && c == o.c && d == o.d; + } +}; + +//clang-format off +void serialize_config() { + // serialize with config + rect r{1, -1, 0, 5}; + auto buffer = + struct_pack::serialize( + r); + // only need 4 bytes + assert(buffer.size() == 4); + // deserialize with config + auto result = + struct_pack::deserialize( + buffer); + 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}; + auto buffer = struct_pack::serialize(r); + // only need 4 bytes + assert(buffer.size() == 4); + // deserialize with config + auto result = struct_pack::deserialize(buffer); + assert(result.value() == r); +} diff --git a/src/struct_pack/tests/CMakeLists.txt b/src/struct_pack/tests/CMakeLists.txt index 4f34d7a28..fa4c284c0 100644 --- a/src/struct_pack/tests/CMakeLists.txt +++ b/src/struct_pack/tests/CMakeLists.txt @@ -14,6 +14,7 @@ add_executable(struct_pack_test test_non_aggregated_type.cpp test_derived.cpp test_cross_platform.cpp + test_disable_meta_info.cpp main.cpp ) add_test(NAME struct_pack_test COMMAND struct_pack_test) diff --git a/src/struct_pack/tests/test_compile_time_calculate.cpp b/src/struct_pack/tests/test_compile_time_calculate.cpp index e5a06b02c..e949f3b24 100644 --- a/src/struct_pack/tests/test_compile_time_calculate.cpp +++ b/src/struct_pack/tests/test_compile_time_calculate.cpp @@ -5,6 +5,7 @@ #include "doctest.h" #include "test_struct.hpp" +#include "ylt/struct_pack/type_calculate.hpp" #if __cplusplus >= 202002L #include #endif @@ -449,3 +450,28 @@ TEST_CASE("test user defined ID") { struct_pack::get_type_literal()); } } +template +struct test_has_container0 { + T hi; +}; + +template +struct test_has_container { + int a; + double b; + std::array>, int, int>, 10> + c; +}; + +TEST_CASE("test has container") { + static_assert( + !struct_pack::detail::check_if_has_container>()); + static_assert(struct_pack::detail::check_if_has_container< + test_has_container>>()); + static_assert(struct_pack::detail::check_if_has_container< + test_has_container>()); + static_assert(struct_pack::detail::check_if_has_container< + test_has_container>>()); + static_assert(struct_pack::detail::check_if_has_container< + test_has_container>>()); +} \ No newline at end of file diff --git a/src/struct_pack/tests/test_cross_platform.cpp b/src/struct_pack/tests/test_cross_platform.cpp index a5d4d75f9..85c004256 100644 --- a/src/struct_pack/tests/test_cross_platform.cpp +++ b/src/struct_pack/tests/test_cross_platform.cpp @@ -13,12 +13,12 @@ void data_gen() { { std::ofstream ifs("binary_data/test_cross_platform.dat"); auto object = create_complicated_object(); - serialize_to(ifs, object); + serialize_to(ifs, object); } { std::ofstream ifs("binary_data/test_cross_platform_without_debug_info.dat"); auto object = create_complicated_object(); - serialize_to(ifs, object); + serialize_to(ifs, object); } } diff --git a/src/struct_pack/tests/test_data_struct.cpp b/src/struct_pack/tests/test_data_struct.cpp index 99f9ac7bd..f9cc0259a 100644 --- a/src/struct_pack/tests/test_data_struct.cpp +++ b/src/struct_pack/tests/test_data_struct.cpp @@ -625,7 +625,7 @@ TEST_CASE("test bitset") { SUBCASE("test serialize size") { std::bitset<255> ar; constexpr auto sz = - struct_pack::get_needed_size( + struct_pack::get_needed_size( ar); static_assert(sz.size() == 36); } diff --git a/src/struct_pack/tests/test_derived.cpp b/src/struct_pack/tests/test_derived.cpp index f0c0ac546..939df7467 100644 --- a/src/struct_pack/tests/test_derived.cpp +++ b/src/struct_pack/tests/test_derived.cpp @@ -95,7 +95,8 @@ TEST_CASE("testing derived") { auto f21 = Base::deserialize(vecs[3]); auto f41 = Base::deserialize(vecs[4]); auto base1 = Base::deserialize(vecs[5]); - CHECK(*(foo*)(f1->get()) == f); + auto &i=*(foo*)(f1->get()); + CHECK(i == f); CHECK(*(foo2*)(f21->get()) == f2); CHECK(*(bar*)(b1->get()) == b); CHECK(*(gua*)(g1->get()) == g); diff --git a/src/struct_pack/tests/test_derived.hpp b/src/struct_pack/tests/test_derived.hpp index 015582a37..f27e675e1 100644 --- a/src/struct_pack/tests/test_derived.hpp +++ b/src/struct_pack/tests/test_derived.hpp @@ -6,9 +6,6 @@ #include "doctest.h" #include "ylt/struct_pack.hpp" -#include "ylt/struct_pack/derived_helper.hpp" -#include "ylt/struct_pack/derived_marco.hpp" -#include "ylt/struct_pack/util.h" namespace test2 { struct base { diff --git a/src/struct_pack/tests/test_disable_meta_info.cpp b/src/struct_pack/tests/test_disable_meta_info.cpp new file mode 100644 index 000000000..e55b29406 --- /dev/null +++ b/src/struct_pack/tests/test_disable_meta_info.cpp @@ -0,0 +1,148 @@ +#include + +#include "doctest.h" +#include "test_struct.hpp" +#include "ylt/struct_pack.hpp" +#include "ylt/struct_pack/error_code.hpp" +#include "ylt/struct_pack/reflection.hpp" + +TEST_CASE("test serialize/deserialize rect") { + { + rect r{1, 11, 333, 44444}, r2{333, 222, 444, 11}; + auto buffer = + struct_pack::serialize( + r); + CHECK(buffer.size() == sizeof(rect)); + auto ec = struct_pack::deserialize_to< + struct_pack::sp_config::DISABLE_ALL_META_INFO>(r2, buffer); + CHECK(ec == struct_pack::errc::ok); + CHECK(r == r2); + } + { + rect r{1, 11, 333, 44444}; + std::string buffer; + struct_pack::serialize_to( + buffer, r); + CHECK(buffer.size() == sizeof(rect)); + auto result = + struct_pack::deserialize(buffer); + CHECK(result.has_value()); + CHECK(r == *result); + } + { + rect r{1, 11, 333, 44444}, r2{333, 222, 444, 11}; + auto buffer = + struct_pack::serialize( + r); + CHECK(buffer.size() == sizeof(rect)); + auto ec = struct_pack::deserialize_to< + struct_pack::sp_config::DISABLE_ALL_META_INFO>(r2, buffer.data(), + buffer.size()); + CHECK(ec == struct_pack::errc::ok); + CHECK(r == r2); + } + { + rect r{1, 11, 333, 44444}; + std::string buffer; + struct_pack::serialize_to( + buffer, r); + CHECK(buffer.size() == sizeof(rect)); + auto result = + struct_pack::deserialize(buffer.data(), buffer.size()); + CHECK(result.has_value()); + CHECK(r == *result); + } +} + +inline constexpr struct_pack::sp_config set_sp_config(rect*) { + return struct_pack::DISABLE_ALL_META_INFO; +} + +TEST_CASE("test serialize/deserialize rect by ADL") { + { + rect r{1, 11, 333, 44444}, r2{333, 222, 444, 11}; + auto buffer = struct_pack::serialize(r); + CHECK(buffer.size() == sizeof(rect)); + auto ec = struct_pack::deserialize_to(r2, buffer); + CHECK(ec == struct_pack::errc::ok); + CHECK(r == r2); + } + { + rect r{1, 11, 333, 44444}; + std::string buffer; + struct_pack::serialize_to(buffer, r); + CHECK(buffer.size() == sizeof(rect)); + auto result = struct_pack::deserialize(buffer); + CHECK(result.has_value()); + CHECK(r == *result); + } + { + rect r{1, 11, 333, 44444}, r2{333, 222, 444, 11}; + auto buffer = struct_pack::serialize(r); + CHECK(buffer.size() == sizeof(rect)); + auto ec = struct_pack::deserialize_to(r2, buffer.data(), buffer.size()); + CHECK(ec == struct_pack::errc::ok); + CHECK(r == r2); + } + { + rect r{1, 11, 333, 44444}; + std::string buffer; + struct_pack::serialize_to(buffer, r); + CHECK(buffer.size() == sizeof(rect)); + auto result = struct_pack::deserialize(buffer.data(), buffer.size()); + CHECK(result.has_value()); + CHECK(r == *result); + } +} + +TEST_CASE("test serialize/deserialize person") { + { + person r{25, "Betty"}, r2{0, "none"}; + auto buffer = + struct_pack::serialize(r); + CHECK(buffer.size() == 11); + auto ec = struct_pack::deserialize_to< + struct_pack::sp_config::DISABLE_ALL_META_INFO>(r2, buffer); + CHECK(ec == struct_pack::errc::ok); + CHECK(r == r2); + } + { + person r{25, "Betty"}; + std::string buffer; + struct_pack::serialize_to( + buffer, r); + CHECK(buffer.size() == 11); + auto result = + struct_pack::deserialize(buffer); + CHECK(result.has_value()); + CHECK(r == *result); + } + { + person r{25, "Betty"}, r2{0, "none"}; + auto buffer = + struct_pack::serialize( + r); + CHECK(buffer.size() == 11); + auto ec = struct_pack::deserialize_to< + struct_pack::sp_config::DISABLE_ALL_META_INFO>(r2, buffer.data(), + buffer.size()); + CHECK(ec == struct_pack::errc::ok); + CHECK(r == r2); + } + { + person r{25, "Betty"}; + std::string buffer; + struct_pack::serialize_to( + buffer, r); + CHECK(buffer.size() == 11); + auto result = + struct_pack::deserialize(buffer.data(), buffer.size()); + CHECK(result.has_value()); + CHECK(r == *result); + } +} \ No newline at end of file diff --git a/src/struct_pack/tests/test_serialize.cpp b/src/struct_pack/tests/test_serialize.cpp index bd3852fc7..5ede30d02 100644 --- a/src/struct_pack/tests/test_serialize.cpp +++ b/src/struct_pack/tests/test_serialize.cpp @@ -667,22 +667,19 @@ struct person_with_type_info { std::string name; }; -namespace struct_pack { -template <> -constexpr inline auto enable_type_info = - type_info_config::enable; -}; +constexpr inline struct_pack::sp_config set_sp_config(person_with_type_info *) { + return sp_config::ENABLE_TYPE_INFO; +} struct person_with_no_type_info { int age; std::string name; }; -namespace struct_pack { -template <> -constexpr inline auto enable_type_info = - type_info_config::disable; -}; +constexpr inline struct_pack::sp_config set_sp_config( + person_with_no_type_info *) { + return sp_config::DISABLE_TYPE_INFO; +} TEST_CASE("test type info config") { SUBCASE("test_person") { @@ -693,8 +690,8 @@ TEST_CASE("test type info config") { auto buffer = serialize(person{24, "Betty"}); CHECK(buffer.size() == size); static_assert( - detail::check_if_add_type_literal() == false); + detail::check_if_add_type_literal() == + false); } #else { @@ -703,29 +700,31 @@ TEST_CASE("test type info config") { auto buffer = serialize(person{24, "Betty"}); CHECK(buffer.size() == size); static_assert( - detail::check_if_add_type_literal() == true); + detail::check_if_add_type_literal() == + true); } #endif { auto size = - get_needed_size(person{24, "Betty"}); + get_needed_size(person{24, "Betty"}); CHECK(size == 14); - auto buffer = serialize, type_info_config::disable>( + auto buffer = serialize( person{24, "Betty"}); CHECK(buffer.size() == size); - static_assert(detail::check_if_add_type_literal() == false); + static_assert( + detail::check_if_add_type_literal() == false); } { auto size = - get_needed_size(person{24, "Betty"}); + get_needed_size(person{24, "Betty"}); CHECK(size == 21); - auto buffer = serialize, type_info_config::enable>( + auto buffer = serialize( person{24, "Betty"}); CHECK(buffer.size() == size); - static_assert(detail::check_if_add_type_literal() == true); + static_assert( + detail::check_if_add_type_literal() == true); } } SUBCASE("test_person_with_type_info") { @@ -735,29 +734,29 @@ TEST_CASE("test type info config") { auto buffer = serialize(person_with_type_info{24, "Betty"}); CHECK(buffer.size() == size); static_assert( - detail::check_if_add_type_literal() == true); } { - auto size = get_needed_size( + auto size = get_needed_size( person_with_type_info{24, "Betty"}); CHECK(size == 14); - auto buffer = serialize, type_info_config::disable>( + auto buffer = serialize( person_with_type_info{24, "Betty"}); CHECK(buffer.size() == size); static_assert( - detail::check_if_add_type_literal() == false); } { - auto size = get_needed_size( + auto size = get_needed_size( person_with_type_info{24, "Betty"}); CHECK(size == 21); - auto buffer = serialize, type_info_config::enable>( + auto buffer = serialize( person_with_type_info{24, "Betty"}); CHECK(buffer.size() == size); static_assert( - detail::check_if_add_type_literal() == true); } } @@ -768,31 +767,31 @@ TEST_CASE("test type info config") { auto buffer = serialize(person_with_no_type_info{24, "Betty"}); CHECK(buffer.size() == size); static_assert( - detail::check_if_add_type_literal() == false); } { - auto size = get_needed_size( + auto size = get_needed_size( person_with_no_type_info{24, "Betty"}); CHECK(size == 14); - auto buffer = serialize, type_info_config::disable>( + auto buffer = serialize( person_with_no_type_info{24, "Betty"}); CHECK(buffer.size() == size); static_assert( - detail::check_if_add_type_literal() == false); } { - auto size = get_needed_size( + auto size = get_needed_size( person_with_no_type_info{24, "Betty"}); CHECK(size == 21); - auto buffer = serialize, type_info_config::enable>( + auto buffer = serialize( person_with_no_type_info{24, "Betty"}); CHECK(buffer.size() == size); static_assert( - detail::check_if_add_type_literal() == true); } @@ -891,14 +890,14 @@ TEST_CASE("test free functions") { TEST_CASE("test variant size_type") { { std::string str(255, 'A'); - auto ret = serialize(str); + auto ret = serialize(str); CHECK(ret.size() == 260); auto str2 = deserialize(ret); CHECK(str == str2); } { std::string str(256, 'A'); - auto ret = serialize(str); + auto ret = serialize(str); CHECK(ret[4] == 0b01000); CHECK(ret.size() == 263); auto str2 = deserialize(ret); @@ -907,7 +906,7 @@ TEST_CASE("test variant size_type") { } { std::string str(65535, 'A'); - auto ret = serialize(str); + auto ret = serialize(str); CHECK(ret[4] == 0b01000); CHECK(ret.size() == 65542); auto str2 = deserialize(ret); @@ -916,7 +915,7 @@ TEST_CASE("test variant size_type") { } { std::string str(65536, 'A'); - auto ret = serialize(str); + auto ret = serialize(str); CHECK(ret[4] == 0b10000); CHECK(ret.size() == 65545); auto str2 = deserialize(ret); @@ -928,7 +927,7 @@ TEST_CASE("test variant size_type") { // { // std::string str((1ull << 32) - 1, 'A'); // auto ret = - // serialize( + // serialize( // str); // CHECK(ret[4] == 0b10000); // CHECK(ret.size() == (1ull << 32) + 8); @@ -939,7 +938,7 @@ TEST_CASE("test variant size_type") { // { // std::string str((1ull << 32), 'A'); // auto ret = - // serialize( + // serialize( // str); // CHECK(ret[4] == 0b11000); // CHECK(ret.size() == (1ull << 32) + 13); diff --git a/src/struct_pack/tests/test_struct.hpp b/src/struct_pack/tests/test_struct.hpp index a66218a37..36a6c826f 100644 --- a/src/struct_pack/tests/test_struct.hpp +++ b/src/struct_pack/tests/test_struct.hpp @@ -14,6 +14,14 @@ #include #include #include + +struct rect { + int a, b, c, d; + auto operator==(const rect &rhs) const { + return a == rhs.a && b == rhs.b && c == rhs.c && d == rhs.d; + } +}; + struct person { int age; std::string name; diff --git a/src/struct_pack/tests/test_varint.cpp b/src/struct_pack/tests/test_varint.cpp index 6916584c9..f40198bb5 100644 --- a/src/struct_pack/tests/test_varint.cpp +++ b/src/struct_pack/tests/test_varint.cpp @@ -810,8 +810,7 @@ TEST_CASE("test varint zip size") { std::vector vec; for (int i = 0; i < 100; ++i) vec.push_back(rand() % 128 - 64); auto buf = - struct_pack::serialize(vec); + struct_pack::serialize(vec); CHECK(buf.size() == 4 + 1 + 1 * 100); CHECK(detail::calculate_payload_size(vec).total == 100); CHECK(detail::calculate_payload_size(vec).size_cnt == 1); @@ -820,8 +819,7 @@ TEST_CASE("test varint zip size") { std::vector vec; for (int i = 0; i < 100; ++i) vec.push_back(rand() % 128 - 64); auto buf = - struct_pack::serialize(vec); + struct_pack::serialize(vec); CHECK(buf.size() == 4 + 1 + 1 * 100); CHECK(detail::calculate_payload_size(vec).total == 100); CHECK(detail::calculate_payload_size(vec).size_cnt == 1); @@ -830,8 +828,7 @@ TEST_CASE("test varint zip size") { std::vector vec; for (int i = 0; i < 100; ++i) vec.push_back(rand() % 128); auto buf = - struct_pack::serialize(vec); + struct_pack::serialize(vec); CHECK(buf.size() == 4 + 1 + 1 * 100); CHECK(detail::calculate_payload_size(vec).total == 100); CHECK(detail::calculate_payload_size(vec).size_cnt == 1); @@ -840,8 +837,7 @@ TEST_CASE("test varint zip size") { std::vector vec; for (int i = 0; i < 100; ++i) vec.push_back(rand() % 128); auto buf = - struct_pack::serialize(vec); + struct_pack::serialize(vec); CHECK(buf.size() == 4 + 1 + 1 * 100); CHECK(detail::calculate_payload_size(vec).total == 100); CHECK(detail::calculate_payload_size(vec).size_cnt == 1); diff --git a/website/docs/en/struct_pack/struct_pack_tips.md b/website/docs/en/struct_pack/struct_pack_tips.md index 612fccb5e..a03071753 100644 --- a/website/docs/en/struct_pack/struct_pack_tips.md +++ b/website/docs/en/struct_pack/struct_pack_tips.md @@ -31,10 +31,47 @@ struct_pack will save the data as little-endian even if the arch is big-endian. 4. define macro `STRUCT_PACK_OPTIMIZE`. ## Type Check struct_pack will generate a name for the serialized type during compilation, and get a 32-bit MD5 based on the string, then take its upper 31 bits for type check. When deserializing, it will check whether the hash code stored is the same as the type to be deserialized. -In order to alleviate possible hash collisions, in debug mode, struct_pack will store the complete type name instead of hash code. Therefore, the binary size in debug mode is slightly larger than release. User can also enable it manually by add option `struct_pack::type_info_config::enable`: +In order to alleviate possible hash collisions, in debug mode, struct_pack will store the complete type name instead of hash code. Therefore, the binary size in debug mode is slightly larger than release. +## 序列化设置 +struct_pack allows user to configure the content of the metadata via `struct_pack::sp_config`, which currently has the following settings: +| enum value | description | +| ----------- | ------------------ | +| DEFAULT |default value | +| 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| + +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. + +For example: +```cpp +struct rect { + var_int a, b, c, d; +}; +``` + +### Using ADL as a Serialization Configuration + +we can declare a function `set_sp_config` in the same namespace of type `rect`: ```cpp -auto result=struct_pack::serialize(person); +inline constexpr struct_pack::sp_config set_sp_config(rect*) { + return struct_pack::DISABLE_ALL_META_INFO; +} ``` + +### Configuration using template parameters + +For example + +```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 1. The type to serialize should be legal struct_pack type.。See document:[struct_pack type system](https://alibaba.github.io/yalantinglibs/en/struct_pack/struct_pack_type_system.html)。 diff --git a/website/docs/zh/struct_pack/struct_pack_tips.md b/website/docs/zh/struct_pack/struct_pack_tips.md index b73bcf6ef..d890da578 100644 --- a/website/docs/zh/struct_pack/struct_pack_tips.md +++ b/website/docs/zh/struct_pack/struct_pack_tips.md @@ -33,10 +33,44 @@ struct_pack即使在大端架构下,也会将数据保存为小端格式。当 ## 类型校验 struct_pack在编译期会根据被序列化的对象的类型生成类型字符串,并根据该字符串生成一个32位的MD5并取其高31位作为类型校验码。反序列化时会检查校验码是否和待反序列化的类型相同。 为了缓解可能出现的哈希冲突,在debug模式下,struct_pack会存储完整的类型字符串。因此debug模式下生成的二进制体积比release略大。 -用户也可以通过`struct_pack::type_info_config::enable`手动控制是否启动类型字符串。 +## 序列化设置 +struct_pack允许通过`struct_pack::sp_config`来配置序列化生成的元数据内容,目前的设置项有以下几个: +| 枚举值 | 作用 | +| ----------- | ------------------ | +| DEFAULT |默认值 | +| DISABLE_TYPE_INFO |禁止在序列化数据中存储完整类型信息,即使在DEBUG模式下| +| ENABLE_TYPE_INFO | 强制在序列化数据中存储完整类型信息,即使不在DEBUG模式下| +| DISABLE_META_INFO| 禁用元信息和4字节的类型校验码,从而减小二进制数据的体积| +需要注意的是,当序列化配置了DISABLE_META_INFO选项时,必须保证反序列化也使用了该选项,否则行为未定义,大概率反序列化会失败。 + +假设有类型: ```cpp -auto result=struct_pack::serialize(person); +struct rect { + var_int a, b, c, d; +}; ``` + +### 使用ADL作为序列化配置 + +在类型`rect`相同的namespace 下添加函数`set_sp_config`即可 +```cpp +inline constexpr struct_pack::sp_config set_sp_config(rect*) { + return struct_pack::DISABLE_ALL_META_INFO; +} +``` + +### 使用模板参数配置 + +该方法要求每次序列化时都将配置作为模板参数传入: + +```cpp +auto buffer = struct_pack::serialize(rect{}); +auto result = struct_pack::deserialize(buffer); +``` + +当同时配置了两者时,模板参数的优先级高于ADL。 +目前我们不允许在具有compatible字段的情况下启用`DISABLE_ALL_META_INFO`配置。 + ## 类型约束 1. 序列化的类型必须是struct_pack类型系统中的合法类型。详见:struct_pack的类型系统。See document:[struct_pack 类型系统](https://alibaba.github.io/yalantinglibs/zh/struct_pack/struct_pack_type_system.html)。