include/ylt/standalone/iguana/common.hpp (239 lines of code) (raw):

#pragma once #include <any> #include "util.hpp" namespace iguana { struct iguana_adl_t {}; namespace detail { template <typename T> struct identity {}; struct field_info { size_t offset; std::string_view type_name; }; struct base { virtual void to_pb(std::string& str) const {} virtual void from_pb(std::string_view str) {} virtual void to_xml(std::string& str) const {} virtual void from_xml(std::string_view str) {} virtual void to_json(std::string& str) const {} virtual void from_json(std::string_view str) {} virtual void to_yaml(std::string& str) const {} virtual void from_yaml(std::string_view str) {} virtual std::vector<std::string_view> get_fields_name() const { return {}; } virtual std::any get_field_any(std::string_view name) const { return {}; } virtual iguana::detail::field_info get_field_info( std::string_view name) const { return {}; } template <typename T> T& get_field_value(std::string_view name) { auto info = get_field_info(name); check_field<T>(name, info); auto ptr = (((char*)this) + info.offset); return *((T*)ptr); } template <typename T, typename FiledType = T> void set_field_value(std::string_view name, T val) { auto info = get_field_info(name); check_field<FiledType>(name, info); auto ptr = (((char*)this) + info.offset); static_assert(std::is_constructible_v<FiledType, T>, "can not assign"); *((FiledType*)ptr) = std::move(val); } virtual ~base() {} private: template <typename T> void check_field(std::string_view name, const field_info& info) { if (info.offset == 0) { throw std::invalid_argument(std::string(name) + " field not exist "); } #if defined(__clang__) || defined(_MSC_VER) || \ (defined(__GNUC__) && __GNUC__ > 8) if (info.type_name != iguana::type_string<T>()) { std::string str = "type is not match: can not assign "; str.append(iguana::type_string<T>()); str.append(" to ").append(info.type_name); throw std::invalid_argument(str); } #endif } }; inline std::unordered_map<std::string_view, std::function<std::shared_ptr<base>()>> g_pb_map; template <typename T> struct field_type_t; template <typename... Args> struct field_type_t<std::tuple<Args...>> { using value_type = std::variant<Args...>; }; template <typename T> constexpr size_t count_variant_size() { if constexpr (is_variant<T>::value) { return std::variant_size_v<T>; } else { return 1; } } template <typename T, size_t... I> constexpr size_t tuple_type_count_impl(std::index_sequence<I...>) { return ( (count_variant_size<member_value_type_t<std::tuple_element_t<I, T>>>() + ...)); } template <typename T> constexpr size_t tuple_type_count() { return tuple_type_count_impl<T>( std::make_index_sequence<std::tuple_size_v<T>>{}); } template <typename T, size_t Size, typename Tuple, size_t... I> constexpr auto inline get_members_impl(Tuple&& tp, std::index_sequence<I...>) { return frozen::unordered_map<uint32_t, T, sizeof...(I)>{ {std::get<I>(tp).field_no, T{std::in_place_index<I>, std::move(std::get<I>(tp))}}...}; } template <typename T, typename = void> struct is_custom_reflection : std::false_type {}; template <typename T> struct is_custom_reflection< T, std::void_t<decltype(get_members_impl(std::declval<T*>()))>> : std::true_type {}; template <typename T> inline constexpr bool is_custom_reflection_v = is_custom_reflection<ylt::reflection::remove_cvref_t<T>>::value; // owner_type: parant type, value_type: member value type, SubType: subtype from // variant template <typename Owner, typename Value, size_t FieldNo, typename ElementType = Value> struct pb_field_t { using owner_type = ylt::reflection::remove_cvref_t<Owner>; using value_type = Value; using sub_type = ElementType; // constexpr pb_field_t() = default; auto& value(owner_type& value) const { auto member_ptr = (value_type*)((char*)(&value) + offset); return *member_ptr; } auto const& value(const owner_type& value) const { auto member_ptr = (value_type*)((char*)(&value) + offset); return *member_ptr; } size_t offset; std::string_view field_name; inline static constexpr uint32_t field_no = FieldNo; }; template <size_t I, typename ValueType, typename Array> constexpr inline auto get_field_no_impl(Array& arr, size_t& index) { arr[I] = index; if constexpr (is_variant<ValueType>::value) { constexpr size_t variant_size = std::variant_size_v<ValueType>; index += (variant_size); } else { index++; return; } } template <typename Tuple, size_t... I> inline constexpr auto get_field_no(std::index_sequence<I...>) { std::array<size_t, sizeof...(I)> arr{}; size_t index = 0; (get_field_no_impl< I, ylt::reflection::remove_cvref_t<std::tuple_element_t<I, Tuple>>>( arr, index), ...); return arr; } template <typename T, typename value_type, size_t field_no, size_t... I> constexpr inline auto build_pb_variant_fields(size_t offset, std::string_view name, std::index_sequence<I...>) { return std::tuple( pb_field_t<T, value_type, field_no + I + 1, std::variant_alternative_t<I, value_type>>{offset, name}...); } template <typename T, size_t field_no, typename ValueType> constexpr inline auto build_pb_fields_impl(size_t offset, std::string_view name) { using value_type = ylt::reflection::remove_cvref_t<ValueType>; using U = std::remove_reference_t<T>; if constexpr (is_variant<value_type>::value) { constexpr uint32_t variant_size = std::variant_size_v<value_type>; return build_pb_variant_fields<U, value_type, field_no>( offset, name, std::make_index_sequence<variant_size>{}); } else { return std::tuple(pb_field_t<U, value_type, field_no + 1>{offset, name}); } } template <typename Tuple, typename T, typename Array, size_t... I> inline auto build_pb_fields(const Array& offset_arr, std::index_sequence<I...>) { constexpr auto arr = ylt::reflection::get_member_names<T>(); constexpr std::array<size_t, sizeof...(I)> indexs = get_field_no<Tuple>(std::make_index_sequence<sizeof...(I)>{}); return std::tuple_cat( build_pb_fields_impl<T, indexs[I], std::tuple_element_t<I, Tuple>>( offset_arr[I], arr[I])...); } template <typename T> inline auto get_pb_members_tuple(T&& t) { using U = ylt::reflection::remove_cvref_t<T>; if constexpr (ylt_refletable_v<U>) { static auto& offset_arr = ylt::reflection::internal::get_member_offset_arr( ylt::reflection::internal::wrapper<U>::value); using Tuple = decltype(ylt::reflection::object_to_tuple(std::declval<U>())); return build_pb_fields<Tuple, T>( offset_arr, std::make_index_sequence<std::tuple_size_v<Tuple>>{}); } else if constexpr (is_custom_reflection_v<U>) { return get_members_impl((U*)nullptr); } else { static_assert(!sizeof(T), "not a reflectable type"); } } template <typename T> inline auto get_members(T&& t) { if constexpr (ylt_refletable_v<T> || is_custom_reflection_v<T>) { static auto tp = get_pb_members_tuple(std::forward<T>(t)); using Tuple = std::decay_t<decltype(tp)>; using value_type = typename field_type_t<Tuple>::value_type; constexpr auto Size = tuple_type_count<Tuple>(); return get_members_impl<value_type, Size>(tp, std::make_index_sequence<Size>{}); } else { static_assert(!sizeof(T), "expected reflection or custom reflection"); } } } // namespace detail template <typename T> inline bool register_type() { #if defined(__clang__) || defined(_MSC_VER) || \ (defined(__GNUC__) && __GNUC__ > 8) if constexpr (std::is_base_of_v<detail::base, T>) { auto it = detail::g_pb_map.emplace(type_string<T>(), [] { return std::make_shared<T>(); }); return it.second; } else { return true; } #else return true; #endif } template <typename T, typename U> IGUANA_INLINE constexpr size_t member_offset(T* t, U T::*member) { return (char*)&(t->*member) - (char*)t; } template <auto ptr, size_t field_no> IGUANA_INLINE auto build_pb_field(std::string_view name) { using owner = typename ylt::reflection::member_traits<decltype(ptr)>::owner_type; using value_type = typename ylt::reflection::member_traits<decltype(ptr)>::value_type; size_t offset = member_offset((owner*)nullptr, ptr); return iguana::detail::pb_field_t<owner, value_type, field_no>{offset, name}; } } // namespace iguana