Skip to content

Commit

Permalink
[struct_pack] add config DISABLE_ALL_META_INFO
Browse files Browse the repository at this point in the history
  • Loading branch information
poor-circle committed Nov 9, 2023
1 parent 47925f5 commit 34aba19
Show file tree
Hide file tree
Showing 25 changed files with 841 additions and 230 deletions.
230 changes: 175 additions & 55 deletions include/ylt/struct_pack.hpp

Large diffs are not rendered by default.

92 changes: 53 additions & 39 deletions include/ylt/struct_pack/calculate_size.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
#pragma once

#include <cstdint>

#include "alignment.hpp"
#include "marco.h"
#include "reflection.hpp"
Expand All @@ -23,6 +25,7 @@
#include "type_trait.hpp"
#include "util.h"
#include "varint.hpp"
#include "ylt/struct_pack/type_calculate.hpp"

namespace struct_pack {

Expand Down Expand Up @@ -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_; }
Expand All @@ -189,53 +192,64 @@ get_serialize_runtime_info(const Args &...args) {
using Type = get_args_type<Args...>;
constexpr bool has_compatible = serialize_static_config<Type>::has_compatible;
constexpr bool has_type_literal = check_if_add_type_literal<conf, Type>();
constexpr bool disable_hash_head = check_if_disable_hash_head<conf, Type>();
constexpr bool has_container = check_if_has_container<Type>();
constexpr bool has_compile_time_determined_meta_info =
check_has_metainfo<conf, Type>();
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<Args...>();
// struct_pack::get_type_literal<Args...>().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<Args...>();
// struct_pack::get_type_literal<Args...>().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;
Expand Down
19 changes: 0 additions & 19 deletions include/ylt/struct_pack/derived_helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,25 +169,6 @@ struct deserialize_one_derived_class_helper {
}
};

template <typename DerivedClasses, typename size_type, typename version>
struct deserialize_one_compatible_in_derived_class_helper {
template <size_t index, typename unpacker, typename Pointer>
static STRUCT_PACK_INLINE constexpr struct_pack::errc run(unpacker *self,
Pointer &base) {
if constexpr (index >= std::tuple_size_v<DerivedClasses>) {
unreachable();
}
else {
using derived_class = std::tuple_element_t<index, DerivedClasses>;
#ifdef STRUCT_PACK_RTTI_ENABLED
assert(dynamic_cast<derived_class *>(base.get()));
#endif
return self->template deserialize_one<size_type::value, version::value>(
*(derived_class *)base.get());
}
}
};

template <typename Base>
using derived_class_set_t = decltype(struct_pack_derived_decl((Base *)nullptr));

Expand Down
9 changes: 5 additions & 4 deletions include/ylt/struct_pack/packer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,7 @@ class packer {
template <uint64_t conf, typename T, typename... Args>
static constexpr uint32_t STRUCT_PACK_INLINE calculate_hash_head() {
constexpr uint32_t raw_types_code = calculate_raw_hash<T, Args...>();
if constexpr (serialize_static_config<serialize_type>::has_compatible ||
check_if_add_type_literal<conf, serialize_type>()) {
if constexpr (check_has_metainfo<conf, T>()) {
return raw_types_code + 1;
}
else { // default case, only has hash_code
Expand All @@ -91,7 +90,9 @@ class packer {
constexpr void STRUCT_PACK_INLINE serialize_metainfo() {
constexpr auto hash_head = calculate_hash_head<conf, T, Args...>() |
(is_default_size_type ? 0 : 1);
write_wrapper<sizeof(uint32_t)>(writer_, (char *)&hash_head);
if constexpr (!check_if_disable_hash_head<conf, serialize_type>()) {
write_wrapper<sizeof(uint32_t)>(writer_, (char *)&hash_head);
}
if constexpr (hash_head % 2) { // has more metainfo
auto metainfo = info.metainfo();
write_wrapper<sizeof(char)>(writer_, (char *)&metainfo);
Expand Down Expand Up @@ -412,7 +413,7 @@ class packer {
const serialize_buffer_size &info;
};

template <uint64_t conf = type_info_config::automatic,
template <uint64_t conf = sp_config::DEFAULT,
#if __cpp_concepts >= 201907L
struct_pack::writer_t Writer,
#else
Expand Down
24 changes: 24 additions & 0 deletions include/ylt/struct_pack/reflection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename... Args>
Expand Down Expand Up @@ -534,6 +542,22 @@ template <typename T, typename = void>
constexpr bool user_defined_refl = user_defined_refl_impl<T>::value;
#endif

#if __cpp_concepts >= 201907L
template <typename Type>
concept user_defined_config = std::is_same_v<decltype(set_sp_config(std::declval<Type*>())),struct_pack::sp_config>;
#else
template <typename T, typename = void>
struct user_defined_config_impl : std::false_type {};

template <typename T>
struct user_defined_config_impl<T, std::void_t<
std::enable_if_t<std::is_same_v<decltype(set_sp_config(std::declval<T*>())),struct_pack::sp_config>>>>
: std::true_type {};

template <typename T>
constexpr bool user_defined_config = user_defined_refl_impl<T>::value;
#endif

#if __cpp_concepts >= 201907L
template <typename Type>
concept tuple_size = requires(Type tuple) {
Expand Down
136 changes: 127 additions & 9 deletions include/ylt/struct_pack/type_calculate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,28 +653,146 @@ struct serialize_static_config {
};
} // namespace detail

enum type_info_config { automatic = 0, disable = 1, enable = 2 };

template <typename T>
constexpr inline type_info_config enable_type_info =
type_info_config::automatic;
namespace detail {

template <uint64_t conf, typename T>
constexpr bool check_if_add_type_literal() {
if constexpr (conf == type_info_config::automatic) {
if constexpr (enable_type_info<T> == type_info_config::automatic) {
constexpr auto config = conf & 0b11;
if constexpr (config == sp_config::DEFAULT) {
if constexpr (struct_pack::detail::user_defined_config<T>) {
constexpr auto config = set_sp_config((T *)nullptr) & 0b11;
if constexpr (config == sp_config::DEFAULT) {
return serialize_static_config<T>::has_type_literal;
}
else {
return config == sp_config::ENABLE_TYPE_INFO;
}
}
else {
return serialize_static_config<T>::has_type_literal;
}
}
else {
return config == sp_config::ENABLE_TYPE_INFO;
}
}

template <typename Arg, typename... ParentArgs>
constexpr bool check_if_has_container();

template <typename Arg, typename... ParentArgs, std::size_t... I>
constexpr bool check_if_has_container_helper(std::index_sequence<I...> idx) {
return ((check_if_has_container<remove_cvref_t<std::tuple_element_t<I, Arg>>,
ParentArgs...>()) ||
...);
}

template <typename Arg, typename... ParentArgs, std::size_t... I>
constexpr bool check_if_has_container_variant_helper(
std::index_sequence<I...> idx) {
return ((check_if_has_container<
remove_cvref_t<std::variant_alternative_t<I, Arg>>, Arg,
ParentArgs...>()) ||
...);
}

template <typename Arg, typename... ParentArgs>
constexpr bool check_if_has_container() {
if constexpr (is_trivial_view_v<Arg>) {
return check_if_has_container<typename Arg::value_type, ParentArgs...>();
}
else {
constexpr std::size_t has_cycle = check_circle<Arg, ParentArgs...>();
if constexpr (has_cycle != 0) {
return false;
}
else {
return enable_type_info<T> == type_info_config::enable;
constexpr auto id = get_type_id<Arg>();
if constexpr (id == type_id::struct_t) {
using Args = decltype(get_types<Arg>());
return check_if_has_container_helper<Args, Arg, ParentArgs...>(
std::make_index_sequence<std::tuple_size_v<Args>>());
}
else if constexpr (id == type_id::variant_t) {
constexpr auto sz = std::variant_size_v<Arg>;
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<Arg, ParentArgs...>(
std::make_index_sequence<std::variant_size_v<Arg>>());
}
else if constexpr (id == type_id::array_t) {
return check_if_has_container<
remove_cvref_t<decltype(std::declval<Arg>()[0])>, Arg,
ParentArgs...>();
}
else if constexpr (id == type_id::bitset_t) {
return false;
}
else if constexpr (unique_ptr<Arg>) {
return check_if_has_container<
remove_cvref_t<typename Arg::element_type>, 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<remove_cvref_t<typename Arg::value_type>,
Arg, ParentArgs...>();
}
else if constexpr (id == type_id::expected_t) {
return check_if_has_container<remove_cvref_t<typename Arg::value_type>,
Arg, ParentArgs...>() ||
check_if_has_container<remove_cvref_t<typename Arg::error_type>,
Arg, ParentArgs...>();
}
else {
return false;
}
}
}
}

template <uint64_t conf, typename T>
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<T>) {
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 <uint64_t conf, typename T>
constexpr bool check_if_disable_hash_head() {
if constexpr (check_if_disable_hash_head_impl<conf, T>()) {
static_assert(
!check_if_compatible_element_exist<decltype(get_types<T>())>(),
"It's not allow add compatible member when you disable hash head");
return true;
}
else {
return conf == type_info_config::enable;
return false;
}
}

template <uint64_t conf, typename T>
constexpr bool check_has_metainfo() {
return serialize_static_config<T>::has_compatible ||
(!check_if_disable_hash_head<conf, T>() &&
check_if_add_type_literal<conf, T>()) ||
((check_if_disable_hash_head<conf, T>() &&
check_if_has_container<T>()));
}

template <typename U>
constexpr auto get_types() {
using T = remove_cvref_t<U>;
Expand Down
Loading

0 comments on commit 34aba19

Please sign in to comment.