include/ylt/reflection/user_reflect_macro.hpp (143 lines of code) (raw):

#pragma once #include <string_view> #include <tuple> #include <type_traits> #include "internal/arg_list_macro.hpp" namespace ylt::reflection { template <typename T> using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>; template <class T> struct member_traits { using value_type = T; }; template <class T, class Owner> struct member_traits<T Owner::*> { using owner_type = Owner; using value_type = T; }; template <class T> using member_value_type_t = typename member_traits<T>::value_type; #define YLT_REFL(STRUCT, ...) \ template <typename Visitor> \ inline static constexpr decltype(auto) refl_visit_members( \ STRUCT &t, Visitor &&visitor) { \ return visitor(WRAP_ARGS(CONCAT_MEMBER, t, ##__VA_ARGS__)); \ } \ template <typename Visitor> \ inline static constexpr decltype(auto) refl_visit_members( \ const STRUCT &t, Visitor &&visitor) { \ return visitor(WRAP_ARGS(CONCAT_MEMBER, t, ##__VA_ARGS__)); \ } \ [[maybe_unused]] inline static decltype(auto) refl_object_to_tuple( \ STRUCT &t) { \ return std::tie(WRAP_ARGS(CONCAT_MEMBER, t, ##__VA_ARGS__)); \ } \ [[maybe_unused]] inline static decltype(auto) refl_object_to_tuple( \ const STRUCT &t) { \ return std::tie(WRAP_ARGS(CONCAT_MEMBER, t, ##__VA_ARGS__)); \ } \ [[maybe_unused]] inline static constexpr decltype(auto) refl_member_names( \ const ylt::reflection::identity<STRUCT> &t) { \ constexpr std::array<std::string_view, YLT_ARG_COUNT(__VA_ARGS__)> arr{ \ WRAP_ARGS(CONCAT_NAME, t, ##__VA_ARGS__)}; \ return arr; \ } \ [[maybe_unused]] inline static constexpr std::size_t refl_member_count( \ const ylt::reflection::identity<STRUCT> &t) { \ return (std::size_t)YLT_ARG_COUNT(__VA_ARGS__); \ } template <typename T, typename Tuple, typename Visitor> inline constexpr auto visit_private_fields_impl(T &&t, const Tuple &tp, Visitor &&visitor) { return std::apply( [&](auto... args) { return visitor(t.*args...); }, tp); } template <typename T, typename Visitor> inline constexpr auto visit_private_fields(T &&t, Visitor &&visitor) { auto tp = get_private_ptrs( identity<std::remove_const_t<std::remove_reference_t<T>>>{}); return visit_private_fields_impl(std::forward<T>(t), tp, visitor); } template <typename T> inline static decltype(auto) refl_object_to_tuple_impl(T &&t) { auto tp = get_private_ptrs( identity<std::remove_const_t<std::remove_reference_t<T>>>{}); auto to_ref = [&t](auto... fields) { return std::tie(t.*fields...); }; return std::apply(to_ref, tp); } #define YLT_REFL_PRIVATE_(STRUCT, ...) \ namespace ylt::reflection { \ inline constexpr auto get_private_ptrs(const identity<STRUCT> &t); \ template struct private_visitor<STRUCT, ##__VA_ARGS__>; \ } \ template <typename Visitor> \ inline static constexpr decltype(auto) refl_visit_members( \ STRUCT &t, Visitor &&visitor) { \ return visit_private_fields(t, std::forward<Visitor>(visitor)); \ } \ template <typename Visitor> \ inline static constexpr decltype(auto) refl_visit_members( \ const STRUCT &t, Visitor &&visitor) { \ return visit_private_fields(t, std::forward<Visitor>(visitor)); \ } \ [[maybe_unused]] inline static decltype(auto) refl_object_to_tuple( \ STRUCT &t) { \ return refl_object_to_tuple_impl(t); \ } \ [[maybe_unused]] inline static decltype(auto) refl_object_to_tuple( \ const STRUCT &t) { \ return refl_object_to_tuple_impl(t); \ } \ [[maybe_unused]] inline static constexpr std::size_t refl_member_count( \ const ylt::reflection::identity<STRUCT> &t) { \ return (std::size_t)YLT_ARG_COUNT(__VA_ARGS__); \ } #define YLT_REFL_PRIVATE(STRUCT, ...) \ [[maybe_unused]] inline static constexpr decltype(auto) refl_member_names( \ const ylt::reflection::identity<STRUCT> &t) { \ constexpr std::array<std::string_view, YLT_ARG_COUNT(__VA_ARGS__)> arr{ \ WRAP_ARGS(CONCAT_NAME, t, ##__VA_ARGS__)}; \ return arr; \ } \ YLT_REFL_PRIVATE_(STRUCT, WRAP_ARGS(CONCAT_ADDR, STRUCT, ##__VA_ARGS__)) template <typename T, typename = void> struct is_out_ylt_refl : std::false_type {}; template <typename T> struct is_out_ylt_refl<T, std::void_t<decltype(refl_member_count( std::declval<ylt::reflection::identity<T>>()))>> : std::true_type {}; template <typename T> constexpr bool is_out_ylt_refl_v = is_out_ylt_refl<T>::value; template <typename T, typename = void> struct is_inner_ylt_refl : std::false_type {}; template <typename T> struct is_inner_ylt_refl< T, std::void_t<decltype(std::declval<T>().refl_member_count( std::declval<ylt::reflection::identity<T>>()))>> : std::true_type {}; template <typename T> constexpr bool is_inner_ylt_refl_v = is_inner_ylt_refl<T>::value; template <typename T, typename = void> struct is_ylt_refl : std::false_type {}; template <typename T> inline constexpr bool is_ylt_refl_v = is_ylt_refl<remove_cvref_t<T>>::value; template <typename T> struct is_ylt_refl<T, std::enable_if_t<is_inner_ylt_refl_v<T>>> : std::true_type {}; template <typename T> struct is_ylt_refl<T, std::enable_if_t<is_out_ylt_refl_v<T>>> : std::true_type { }; template <typename T, typename = void> struct is_custom_reflect : std::false_type {}; template <typename T> struct is_custom_reflect< T, std::void_t<decltype(ylt_custom_reflect((T *)nullptr))>> : std::true_type {}; template <typename T> inline constexpr bool is_custom_refl_v = is_custom_reflect<remove_cvref_t<T>>::value; } // namespace ylt::reflection