/* * 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. */ // clang-format off #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ylt/reflection/member_count.hpp" #include "ylt/reflection/internal/arg_list_macro.hpp" #if __has_include() #include #endif #include "derived_helper.hpp" #include "foreach_macro.h" #include "marco.h" #include "util.h" #include "ylt/reflection/template_switch.hpp" #include "ylt/reflection/member_ptr.hpp" #if __cpp_concepts >= 201907L #include #endif namespace struct_pack { enum sp_config : uint64_t { DEFAULT = 0, DISABLE_TYPE_INFO = 0b1, ENABLE_TYPE_INFO = 0b10, DISABLE_ALL_META_INFO = 0b11, ENCODING_WITH_VARINT = 0b100, USE_FAST_VARINT = 0b1000 }; namespace detail { template using get_args_type = remove_cvref_t>, std::tuple>::type>; template constexpr auto get_types(); template typename Op, typename... Contexts, std::size_t... I> constexpr void for_each_impl(std::index_sequence, Contexts &...contexts) { using type = decltype(get_types()); (Op, I>{}(contexts...), ...); } template typename Op, typename... Contexts> constexpr void for_each(Contexts &...contexts) { using type = decltype(get_types()); for_each_impl(std::make_index_sequence>(), contexts...); } template constexpr std::size_t members_count(); template constexpr std::size_t pack_align(); template constexpr std::size_t alignment(); } // namespace detail template constexpr std::size_t members_count = detail::members_count(); template constexpr std::size_t pack_alignment_v = 0; template constexpr std::size_t alignment_v = 0; #if __cpp_concepts >= 201907L template concept writer_t = requires(T t) { t.write((const char *)nullptr, std::size_t{}); }; template concept reader_t = requires(T t) { t.read((char *)nullptr, std::size_t{}); t.ignore(std::size_t{}); t.tellg(); }; template concept view_reader_t = reader_t && requires(T t) { { t.read_view(std::size_t{}) } -> std::convertible_to; }; #else template struct writer_t_impl : std::false_type {}; template struct writer_t_impl().write( (const char *)nullptr, std::size_t{}))>> : std::true_type {}; template constexpr bool writer_t = writer_t_impl::value; template struct reader_t_impl : std::false_type {}; template struct reader_t_impl< T, std::void_t().read((char *)nullptr, std::size_t{})), decltype(std::declval().ignore(std::size_t{})), decltype(std::declval().tellg())>> : std::true_type {}; template constexpr bool reader_t = reader_t_impl::value; template struct view_reader_t_impl : std::false_type {}; template struct view_reader_t_impl< T, std::void_t().read_view(std::size_t{}))>> : std::true_type {}; template constexpr bool view_reader_t = reader_t &&view_reader_t_impl::value; #endif #if __cpp_concepts >= 201907L template concept can_reserve = requires(T t) { t.reserve(std::size_t{}); }; template concept can_shrink_to_fit = requires(T t) { t.shrink_to_fit(); }; #else template struct can_reserve_impl : std::false_type {}; template struct can_reserve_impl< T, std::void_t().reserve(std::size_t{}))>> : std::true_type {}; template constexpr bool can_reserve = can_reserve_impl::value; template struct can_shrink_to_fit_impl : std::false_type {}; template struct can_shrink_to_fit_impl< T, std::void_t().shrink_to_fit())>> : std::true_type {}; template constexpr bool can_shrink_to_fit = can_shrink_to_fit_impl::value; #endif template struct compatible; namespace detail { #if __cpp_concepts >= 201907L template concept has_user_defined_id = requires { typename std::integral_constant; }; template concept has_user_defined_id_ADL = requires { typename std::integral_constant; }; #else template struct has_user_defined_id_impl : std::false_type {}; template struct has_user_defined_id_impl< T, std::void_t>> : std::true_type {}; template constexpr bool has_user_defined_id = has_user_defined_id_impl::value; template struct constant_checker{}; template struct has_user_defined_id_ADL_impl : std::false_type {}; #ifdef _MSC_VER // FIXME: we can't check if it's compile-time calculated in msvc with C++17 template struct has_user_defined_id_ADL_impl< T, std::void_t> : std::true_type {}; #else template struct has_user_defined_id_ADL_impl< T, std::void_t>> : std::true_type {}; #endif template constexpr bool has_user_defined_id_ADL = has_user_defined_id_ADL_impl::value; #endif #if __cpp_concepts >= 201907L template concept is_base_class = requires (T* t) { std::is_same_vget_struct_pack_id())>; typename struct_pack::detail::derived_class_set_t; }; #else template struct is_base_class_impl : std::false_type {}; template struct is_base_class_impl< T, std::void_t< std::enable_ifget_struct_pack_id()), uint32_t>>, typename struct_pack::detail::derived_class_set_t>> : std::true_type {}; template constexpr bool is_base_class=is_base_class_impl::value; #endif #if __cpp_concepts >= 201907L template concept deserialize_view = requires(Type container) { container.size(); container.data(); }; #else template struct deserialize_view_impl : std::false_type {}; template struct deserialize_view_impl< T, std::void_t().size()),decltype(std::declval().data())>> : std::true_type {}; template constexpr bool deserialize_view = deserialize_view_impl::value; #endif struct memory_writer { char *buffer; STRUCT_PACK_INLINE void write(const char *data, std::size_t len) { memcpy(buffer, data, len); buffer += len; } }; #if __cpp_concepts >= 201907L template concept container_adapter = requires(Type container) { typename remove_cvref_t::value_type; container.size(); container.pop(); }; #else template struct container_adapter_impl : std::false_type {}; template struct container_adapter_impl::value_type, decltype(std::declval().size()), decltype(std::declval().pop())>> : std::true_type {}; template constexpr bool container_adapter = container_adapter_impl::value; #endif #if __cpp_concepts >= 201907L template concept container = requires(Type container) { typename remove_cvref_t::value_type; container.size(); container.begin(); container.end(); }; #else template struct container_impl : std::false_type {}; template struct container_impl::value_type, decltype(std::declval().size()), decltype(std::declval().begin()), decltype(std::declval().end())>> : std::true_type {}; template constexpr bool container = container_impl::value; #endif template constexpr bool is_char_t = std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v #ifdef __cpp_lib_char8_t || std::is_same_v #endif ; #if __cpp_concepts >= 201907L template concept string = container && requires(Type container) { requires is_char_t::value_type>; container.length(); container.data(); }; #else template struct string_impl : std::false_type {}; template struct string_impl::value_type>>, decltype(std::declval().length()), decltype(std::declval().data())>> : std::true_type {}; template constexpr bool string = string_impl::value && container; #endif #if __cpp_concepts >= 201907L template concept string_view = string && !requires(Type container) { container.resize(std::size_t{}); }; #else template struct string_view_impl : std::true_type {}; template struct string_view_impl().resize(std::size_t{}))>> : std::false_type {}; template constexpr bool string_view = string && string_view_impl::value; #endif #if __cpp_concepts >= 201907L template concept span = container && requires(Type t) { Type{(typename Type::value_type*)nullptr ,std::size_t{} }; t.subspan(std::size_t{},std::size_t{}); }; #else template struct span_impl : std::false_type {}; template struct span_impl().subspan(std::size_t{},std::size_t{}))>> : std::true_type {}; template constexpr bool span = container && span_impl::value; #endif #if __cpp_concepts >= 201907L template concept dynamic_span = span && Type::extent == SIZE_MAX; #else template struct dynamic_span_impl : std::false_type {}; template struct dynamic_span_impl>> : std::true_type {}; template constexpr bool dynamic_span = span && dynamic_span_impl::value; #endif template constexpr bool static_span = span && !dynamic_span; #if __cpp_lib_span >= 202002L && __cpp_concepts>=201907L template concept continuous_container = string || (container && requires(Type container) { std::span{container}; }); #else template constexpr inline bool is_std_basic_string_v = false; template constexpr inline bool is_std_basic_string_v> = true; template constexpr inline bool is_std_vector_v = false; template constexpr inline bool is_std_vector_v> = true; template constexpr bool continuous_container = string || (container && (is_std_vector_v || is_std_basic_string_v)); #endif #if __cpp_concepts >= 201907L template concept map_container = container && requires(Type container) { typename remove_cvref_t::mapped_type; }; #else template struct map_container_impl : std::false_type {}; template struct map_container_impl::mapped_type>> : std::true_type {}; template constexpr bool map_container = container && map_container_impl::value; #endif #if __cpp_concepts >= 201907L template concept hash_map_container = map_container && requires(Type container) { typename remove_cvref_t::hasher; }; #else template struct hash_map_container_impl : std::false_type {}; template struct hash_map_container_impl::hasher>> : std::true_type {}; template constexpr bool hash_map_container = map_container && hash_map_container_impl::value; #endif template constexpr inline bool is_std_unordered_map_v = false; template constexpr inline bool is_std_unordered_map_v> = true; template constexpr inline bool is_std_unordered_map_v> = true; #if __cpp_concepts >= 201907L template concept set_container = container && requires { typename remove_cvref_t::key_type; }; #else template struct set_container_impl : std::false_type {}; template struct set_container_impl::key_type>> : std::true_type {}; template constexpr bool set_container = container && set_container_impl::value; #endif #if __cpp_concepts >= 201907L template concept bitset = requires (Type t){ t.flip(); t.set(); t.reset(); t.count(); } && (Type{}.size()+7)/8 == sizeof(Type); #else template struct bitset_impl : std::false_type {}; template struct bitset_impl().flip()), decltype(std::declval().set()), decltype(std::declval().reset()), decltype(std::declval().count()), decltype(std::declval().size())>> : std::true_type {}; template constexpr bool bitset_size_checker() { if constexpr (bitset_impl::value) { return (T{}.size()+7)/8==sizeof(T); } else { return false; } } template constexpr bool bitset = bitset_impl::value && bitset_size_checker(); #endif #if __cpp_concepts >= 201907L template concept tuple = requires(Type tuple) { std::get<0>(tuple); sizeof(std::tuple_size>); }; #else template struct tuple_impl : std::false_type {}; template struct tuple_impl(std::declval())), decltype(sizeof(std::tuple_size>::value))>> : std::true_type {}; template constexpr bool tuple = tuple_impl::value; #endif #if __cpp_concepts >= 201907L template concept user_defined_refl = ylt::reflection::is_out_ylt_refl_v || ylt::reflection::is_inner_ylt_refl_v; #else template constexpr bool user_defined_refl = ylt::reflection::is_out_ylt_refl_v || ylt::reflection::is_inner_ylt_refl_v; #endif #if __cpp_concepts >= 201907L template concept user_defined_config_by_ADL = std::is_same_v())),struct_pack::sp_config>; #else template struct user_defined_config_by_ADL_impl : std::false_type {}; template struct user_defined_config_by_ADL_impl())),struct_pack::sp_config>>>> : std::true_type {}; template constexpr bool user_defined_config_by_ADL = user_defined_config_by_ADL_impl::value; #endif template constexpr decltype(auto) delay_sp_config_eval() { if constexpr (sizeof(T)==0) { return (T*)nullptr; } else { return (sp_config*)nullptr; } } #if __cpp_concepts >= 201907L template concept has_default_config = std::is_same_v()){})),struct_pack::sp_config>; #else template struct has_default_config_impl : std::false_type {}; template struct has_default_config_impl()){})),struct_pack::sp_config>>>> : std::true_type {}; template constexpr bool has_default_config = has_default_config_impl::value; #endif #if __cpp_concepts >= 201907L template concept user_defined_config = requires { Type::struct_pack_config; }; #else template struct user_defined_config_impl : std::false_type {}; template struct user_defined_config_impl> : std::true_type {}; template constexpr bool user_defined_config = user_defined_config_impl::value; #endif struct memory_reader; #if __cpp_concepts >= 201907L template concept user_defined_serialization = requires (Type& t) { sp_serialize_to(std::declval(),(const Type&)t); {sp_deserialize_to(std::declval(),t)} -> std::same_as; {sp_get_needed_size((const Type&)t)}->std::same_as; }; template concept user_defined_type_name = requires { { sp_set_type_name((Type*)nullptr) } -> std::same_as; }; #else template struct user_defined_serialization_impl : std::false_type {}; template struct user_defined_serialization_impl(),std::declval())), std::enable_if(),std::declval())), struct_pack::err_code>, std::enable_if())), std::string_view>>>>> : std::true_type {}; template constexpr bool user_defined_serialization = user_defined_serialization_impl::value; template struct user_defined_type_name_impl : std::false_type {}; template struct user_defined_type_name_impl>>> : std::true_type {}; template constexpr bool user_defined_type_name = user_defined_type_name_impl::value; #endif #if __cpp_concepts >= 201907L template concept tuple_size = requires(Type tuple) { std::tuple_size>::value; }; #else template struct tuple_size_impl : std::false_type {}; template struct tuple_size_impl>::value)>> : std::true_type {}; template constexpr bool tuple_size = tuple_size_impl::value; #endif #if __cpp_concepts >= 201907L template concept array = requires(Type arr) { arr.size(); std::tuple_size>{}; }; #else template struct array_impl : std::false_type {}; template struct array_impl().size()), decltype(std::tuple_size>{})>> : std::true_type {}; template constexpr bool array = array_impl::value; #endif template constexpr bool c_array = std::is_array_v && std::extent_v> > 0; #if __cpp_concepts >= 201907L template concept pair = requires(Type p) { typename remove_cvref_t::first_type; typename remove_cvref_t::second_type; p.first; p.second; }; #else template struct pair_impl : std::false_type {}; template struct pair_impl::first_type, typename remove_cvref_t::second_type, decltype(std::declval().first), decltype(std::declval().second)>> : std::true_type {}; template constexpr bool pair = pair_impl::value; #endif #if __cpp_concepts >= 201907L template concept unique_ptr = requires(Type ptr) { ptr.operator*(); typename remove_cvref_t::element_type; } &&!requires(Type ptr, Type ptr2) { ptr = ptr2; }; #else template struct unique_ptr_impl : std::false_type {}; template struct unique_ptr_impl::element_type, decltype(std::declval().operator*())>> : std::true_type {}; template constexpr bool unique_ptr = unique_ptr_impl::value; #endif template constexpr inline bool is_compatible_v = false; template constexpr inline bool is_compatible_v> = true; template constexpr inline bool is_variant_v = false; template constexpr inline bool is_variant_v> = true; template constexpr inline bool is_trivial_tuple = false; template class varint; template class sint; template constexpr bool varintable_t = std::is_same_v> || std::is_same_v> || std::is_same_v> || std::is_same_v>; template constexpr bool sintable_t = std::is_same_v> || std::is_same_v>; template constexpr bool varint_t = varintable_t || sintable_t || ((parent_tag&struct_pack::ENCODING_WITH_VARINT) && (std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v)); template constexpr inline bool is_trivial_view_v = false; template constexpr uint64_t get_parent_tag(); template struct is_trivial_serializable { private: template static constexpr bool class_visit_helper(std::index_sequence) { return (is_trivial_serializable, ignore_compatible_field,parent_tag_>::value && ...); } public: static constexpr bool solve() { if constexpr (user_defined_serialization) { return false; } else if constexpr (std::is_same_v) { return true; } else if constexpr (std::is_abstract_v) { return false; } else if constexpr (varint_t) { return false; } else if constexpr (is_compatible_v || is_trivial_view_v) { return ignore_compatible_field; } else if constexpr (std::is_enum_v || std::is_fundamental_v || bitset #if (__GNUC__ || __clang__) && defined(STRUCT_PACK_ENABLE_INT128) || std::is_same_v<__int128,T> || std::is_same_v #endif ) { return true; } else if constexpr (array) { return is_trivial_serializable::value; } else if constexpr (c_array) { return is_trivial_serializable::type, ignore_compatible_field>::value; } else if constexpr (!pair && tuple && !is_trivial_tuple) { return false; } else if constexpr (user_defined_refl) { return false; } else if constexpr (container || ylt::reflection::optional || is_variant_v || unique_ptr || ylt::reflection::expected || container_adapter) { return false; } else if constexpr (pair) { return is_trivial_serializable::value && is_trivial_serializable::value; } else if constexpr (is_trivial_tuple) { return class_visit_helper(std::make_index_sequence>{}); } else if constexpr (std::is_class_v) { constexpr auto tag = get_parent_tag(); using U = decltype(get_types()); return class_visit_helper(std::make_index_sequence>{}); } else return false; } static inline constexpr bool value = is_trivial_serializable,ignore_compatible_field,parent_tag>::solve(); }; } template ::value>> struct trivial_view; namespace detail { #if __cpp_concepts < 201907L template struct trivially_copyable_container_impl : std::false_type {}; template struct trivially_copyable_container_impl::value>>> : std::true_type {}; template constexpr bool trivially_copyable_container = continuous_container && trivially_copyable_container_impl::value; #else template constexpr bool trivially_copyable_container = continuous_container && requires(Type container) { requires is_trivial_serializable::value; }; #endif template constexpr inline bool is_trivial_view_v> = true; template constexpr std::size_t members_count() { return ylt::reflection::members_count_v; } template constexpr decltype(auto) STRUCT_PACK_INLINE visit_members(Object &&object, Visitor &&visitor) { using type = remove_cvref_t; constexpr auto Count = struct_pack::members_count; if constexpr (Count == 0 && std::is_class_v && !std::is_same_v) { static_assert(!sizeof(type), "1. If the struct is empty, which is not allowed in struct_pack type system.\n" "2. If the strut is not empty, it means struct_pack can't calculate your struct members' count. You can use macro YLT_REFL(Typename, field1, field2...)."); } // If you see any structured binding error in the follow line, it // means struct_pack can't calculate your struct's members count // correctly. // The best way is use macro YLT_REFL(Typename, field1, field2...) // See the src/struct_pack/example/non_aggregated_type.cpp for more details. // // You can also to mark it manually. // For example, there is a struct named Hello, // and it has 3 members. // // You can mark it as: // // template <> // constexpr size_t struct_pack::members_count = 3; return ylt::reflection::visit_members(std::forward(object), std::forward(visitor)); } } // namespace detail #if __cpp_concepts >= 201907L template concept checkable_reader_t = reader_t && requires(T t) { t.check(std::size_t{}); }; #else template struct checkable_reader_t_impl : std::false_type {}; template struct checkable_reader_t_impl< T, std::void_t().check(std::size_t{}))>> : std::true_type {}; template constexpr bool checkable_reader_t = reader_t &&checkable_reader_t_impl::value; #endif } // namespace struct_pack // This marco is only for compatible with old version. Please instead it by YLT_REFL #define STRUCT_PACK_REFL(Type,...) \ YLT_REFL(Type,__VA_ARGS__)