diff --git a/include/ylt/reflection/internal/arg_list_macro.hpp b/include/ylt/reflection/internal/arg_list_macro.hpp new file mode 100644 index 000000000..12cb82a1a --- /dev/null +++ b/include/ylt/reflection/internal/arg_list_macro.hpp @@ -0,0 +1,11 @@ +#pragma once +#include "common_macro.hpp" + +#define WRAP_ARGS0(w, o) +#define WRAP_ARGS1(w, o, _1) w(o, _1) +#include "generate/arg_list_macro_gen.hpp" + +#define WRAP_ARGS_(w, object, ...) \ + YLT_CONCAT(WRAP_ARGS, YLT_ARG_COUNT(__VA_ARGS__)) \ + (w, object, __VA_ARGS__) +#define WRAP_ARGS(w, object, ...) WRAP_ARGS_(w, object, __VA_ARGS__) \ No newline at end of file diff --git a/include/ylt/reflection/internal/args_count.hpp b/include/ylt/reflection/internal/args_count.hpp new file mode 100644 index 000000000..ec93dd61d --- /dev/null +++ b/include/ylt/reflection/internal/args_count.hpp @@ -0,0 +1,26 @@ +#pragma once + +#define YLT_MACRO_EXPAND(...) __VA_ARGS__ + +#define YLT_ARG_COUNT(...) \ + YLT_MACRO_EXPAND(YLT_ARG_COUNT_IMPL( \ + 0, ##__VA_ARGS__, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, \ + 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, \ + 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, \ + 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, \ + 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, \ + 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, \ + 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \ + 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) + +#define YLT_ARG_COUNT_IMPL( \ + _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, \ + _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, \ + _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, \ + _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, \ + _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75, _76, \ + _77, _78, _79, _80, _81, _82, _83, _84, _85, _86, _87, _88, _89, _90, _91, \ + _92, _93, _94, _95, _96, _97, _98, _99, _100, _101, _102, _103, _104, \ + _105, _106, _107, _108, _109, _110, _111, _112, _113, _114, _115, _116, \ + _117, _118, _119, _120, _121, _122, _123, _124, N, ...) \ + N diff --git a/include/ylt/reflection/internal/common_macro.hpp b/include/ylt/reflection/internal/common_macro.hpp new file mode 100644 index 000000000..df7f0032a --- /dev/null +++ b/include/ylt/reflection/internal/common_macro.hpp @@ -0,0 +1,16 @@ +#pragma once +#include "args_count.hpp" +#define YLT_CONCAT_(l, r) l##r + +#define YLT_CONCAT(l, r) YLT_CONCAT_(l, r) + +#define CONCAT_MEMBER(t, x) t.x + +#define CONCAT_ADDR(T, x) &T::x + +#define CONCAT_NAME(t, x) #x + +namespace ylt::reflection { +template +struct identity {}; +} // namespace ylt::reflection \ No newline at end of file diff --git a/include/ylt/reflection/internal/generate/arg_list_macro_gen.hpp b/include/ylt/reflection/internal/generate/arg_list_macro_gen.hpp new file mode 100644 index 000000000..8e594813b --- /dev/null +++ b/include/ylt/reflection/internal/generate/arg_list_macro_gen.hpp @@ -0,0 +1,136 @@ +/*The following boilerplate code was generated using a Python script: +macro = "#define WRAP_ARGS" +with open("generated_args.txt", "w", encoding="utf-8") as codefile: + codefile.write( + "\n".join( + [ + f"{macro}{i}(w,o,_1, ...) w(o, _1), +WRAP_ARGS{i-1}(w,o,__VA_ARGS__)" for i in range(2, 126) + ] + ) + ) +*/ +#define WRAP_ARGS2(w, o, _1, ...) w(o, _1), WRAP_ARGS1(w, o, __VA_ARGS__) +#define WRAP_ARGS3(w, o, _1, ...) w(o, _1), WRAP_ARGS2(w, o, __VA_ARGS__) +#define WRAP_ARGS4(w, o, _1, ...) w(o, _1), WRAP_ARGS3(w, o, __VA_ARGS__) +#define WRAP_ARGS5(w, o, _1, ...) w(o, _1), WRAP_ARGS4(w, o, __VA_ARGS__) +#define WRAP_ARGS6(w, o, _1, ...) w(o, _1), WRAP_ARGS5(w, o, __VA_ARGS__) +#define WRAP_ARGS7(w, o, _1, ...) w(o, _1), WRAP_ARGS6(w, o, __VA_ARGS__) +#define WRAP_ARGS8(w, o, _1, ...) w(o, _1), WRAP_ARGS7(w, o, __VA_ARGS__) +#define WRAP_ARGS9(w, o, _1, ...) w(o, _1), WRAP_ARGS8(w, o, __VA_ARGS__) +#define WRAP_ARGS10(w, o, _1, ...) w(o, _1), WRAP_ARGS9(w, o, __VA_ARGS__) +#define WRAP_ARGS11(w, o, _1, ...) w(o, _1), WRAP_ARGS10(w, o, __VA_ARGS__) +#define WRAP_ARGS12(w, o, _1, ...) w(o, _1), WRAP_ARGS11(w, o, __VA_ARGS__) +#define WRAP_ARGS13(w, o, _1, ...) w(o, _1), WRAP_ARGS12(w, o, __VA_ARGS__) +#define WRAP_ARGS14(w, o, _1, ...) w(o, _1), WRAP_ARGS13(w, o, __VA_ARGS__) +#define WRAP_ARGS15(w, o, _1, ...) w(o, _1), WRAP_ARGS14(w, o, __VA_ARGS__) +#define WRAP_ARGS16(w, o, _1, ...) w(o, _1), WRAP_ARGS15(w, o, __VA_ARGS__) +#define WRAP_ARGS17(w, o, _1, ...) w(o, _1), WRAP_ARGS16(w, o, __VA_ARGS__) +#define WRAP_ARGS18(w, o, _1, ...) w(o, _1), WRAP_ARGS17(w, o, __VA_ARGS__) +#define WRAP_ARGS19(w, o, _1, ...) w(o, _1), WRAP_ARGS18(w, o, __VA_ARGS__) +#define WRAP_ARGS20(w, o, _1, ...) w(o, _1), WRAP_ARGS19(w, o, __VA_ARGS__) +#define WRAP_ARGS21(w, o, _1, ...) w(o, _1), WRAP_ARGS20(w, o, __VA_ARGS__) +#define WRAP_ARGS22(w, o, _1, ...) w(o, _1), WRAP_ARGS21(w, o, __VA_ARGS__) +#define WRAP_ARGS23(w, o, _1, ...) w(o, _1), WRAP_ARGS22(w, o, __VA_ARGS__) +#define WRAP_ARGS24(w, o, _1, ...) w(o, _1), WRAP_ARGS23(w, o, __VA_ARGS__) +#define WRAP_ARGS25(w, o, _1, ...) w(o, _1), WRAP_ARGS24(w, o, __VA_ARGS__) +#define WRAP_ARGS26(w, o, _1, ...) w(o, _1), WRAP_ARGS25(w, o, __VA_ARGS__) +#define WRAP_ARGS27(w, o, _1, ...) w(o, _1), WRAP_ARGS26(w, o, __VA_ARGS__) +#define WRAP_ARGS28(w, o, _1, ...) w(o, _1), WRAP_ARGS27(w, o, __VA_ARGS__) +#define WRAP_ARGS29(w, o, _1, ...) w(o, _1), WRAP_ARGS28(w, o, __VA_ARGS__) +#define WRAP_ARGS30(w, o, _1, ...) w(o, _1), WRAP_ARGS29(w, o, __VA_ARGS__) +#define WRAP_ARGS31(w, o, _1, ...) w(o, _1), WRAP_ARGS30(w, o, __VA_ARGS__) +#define WRAP_ARGS32(w, o, _1, ...) w(o, _1), WRAP_ARGS31(w, o, __VA_ARGS__) +#define WRAP_ARGS33(w, o, _1, ...) w(o, _1), WRAP_ARGS32(w, o, __VA_ARGS__) +#define WRAP_ARGS34(w, o, _1, ...) w(o, _1), WRAP_ARGS33(w, o, __VA_ARGS__) +#define WRAP_ARGS35(w, o, _1, ...) w(o, _1), WRAP_ARGS34(w, o, __VA_ARGS__) +#define WRAP_ARGS36(w, o, _1, ...) w(o, _1), WRAP_ARGS35(w, o, __VA_ARGS__) +#define WRAP_ARGS37(w, o, _1, ...) w(o, _1), WRAP_ARGS36(w, o, __VA_ARGS__) +#define WRAP_ARGS38(w, o, _1, ...) w(o, _1), WRAP_ARGS37(w, o, __VA_ARGS__) +#define WRAP_ARGS39(w, o, _1, ...) w(o, _1), WRAP_ARGS38(w, o, __VA_ARGS__) +#define WRAP_ARGS40(w, o, _1, ...) w(o, _1), WRAP_ARGS39(w, o, __VA_ARGS__) +#define WRAP_ARGS41(w, o, _1, ...) w(o, _1), WRAP_ARGS40(w, o, __VA_ARGS__) +#define WRAP_ARGS42(w, o, _1, ...) w(o, _1), WRAP_ARGS41(w, o, __VA_ARGS__) +#define WRAP_ARGS43(w, o, _1, ...) w(o, _1), WRAP_ARGS42(w, o, __VA_ARGS__) +#define WRAP_ARGS44(w, o, _1, ...) w(o, _1), WRAP_ARGS43(w, o, __VA_ARGS__) +#define WRAP_ARGS45(w, o, _1, ...) w(o, _1), WRAP_ARGS44(w, o, __VA_ARGS__) +#define WRAP_ARGS46(w, o, _1, ...) w(o, _1), WRAP_ARGS45(w, o, __VA_ARGS__) +#define WRAP_ARGS47(w, o, _1, ...) w(o, _1), WRAP_ARGS46(w, o, __VA_ARGS__) +#define WRAP_ARGS48(w, o, _1, ...) w(o, _1), WRAP_ARGS47(w, o, __VA_ARGS__) +#define WRAP_ARGS49(w, o, _1, ...) w(o, _1), WRAP_ARGS48(w, o, __VA_ARGS__) +#define WRAP_ARGS50(w, o, _1, ...) w(o, _1), WRAP_ARGS49(w, o, __VA_ARGS__) +#define WRAP_ARGS51(w, o, _1, ...) w(o, _1), WRAP_ARGS50(w, o, __VA_ARGS__) +#define WRAP_ARGS52(w, o, _1, ...) w(o, _1), WRAP_ARGS51(w, o, __VA_ARGS__) +#define WRAP_ARGS53(w, o, _1, ...) w(o, _1), WRAP_ARGS52(w, o, __VA_ARGS__) +#define WRAP_ARGS54(w, o, _1, ...) w(o, _1), WRAP_ARGS53(w, o, __VA_ARGS__) +#define WRAP_ARGS55(w, o, _1, ...) w(o, _1), WRAP_ARGS54(w, o, __VA_ARGS__) +#define WRAP_ARGS56(w, o, _1, ...) w(o, _1), WRAP_ARGS55(w, o, __VA_ARGS__) +#define WRAP_ARGS57(w, o, _1, ...) w(o, _1), WRAP_ARGS56(w, o, __VA_ARGS__) +#define WRAP_ARGS58(w, o, _1, ...) w(o, _1), WRAP_ARGS57(w, o, __VA_ARGS__) +#define WRAP_ARGS59(w, o, _1, ...) w(o, _1), WRAP_ARGS58(w, o, __VA_ARGS__) +#define WRAP_ARGS60(w, o, _1, ...) w(o, _1), WRAP_ARGS59(w, o, __VA_ARGS__) +#define WRAP_ARGS61(w, o, _1, ...) w(o, _1), WRAP_ARGS60(w, o, __VA_ARGS__) +#define WRAP_ARGS62(w, o, _1, ...) w(o, _1), WRAP_ARGS61(w, o, __VA_ARGS__) +#define WRAP_ARGS63(w, o, _1, ...) w(o, _1), WRAP_ARGS62(w, o, __VA_ARGS__) +#define WRAP_ARGS64(w, o, _1, ...) w(o, _1), WRAP_ARGS63(w, o, __VA_ARGS__) +#define WRAP_ARGS65(w, o, _1, ...) w(o, _1), WRAP_ARGS64(w, o, __VA_ARGS__) +#define WRAP_ARGS66(w, o, _1, ...) w(o, _1), WRAP_ARGS65(w, o, __VA_ARGS__) +#define WRAP_ARGS67(w, o, _1, ...) w(o, _1), WRAP_ARGS66(w, o, __VA_ARGS__) +#define WRAP_ARGS68(w, o, _1, ...) w(o, _1), WRAP_ARGS67(w, o, __VA_ARGS__) +#define WRAP_ARGS69(w, o, _1, ...) w(o, _1), WRAP_ARGS68(w, o, __VA_ARGS__) +#define WRAP_ARGS70(w, o, _1, ...) w(o, _1), WRAP_ARGS69(w, o, __VA_ARGS__) +#define WRAP_ARGS71(w, o, _1, ...) w(o, _1), WRAP_ARGS70(w, o, __VA_ARGS__) +#define WRAP_ARGS72(w, o, _1, ...) w(o, _1), WRAP_ARGS71(w, o, __VA_ARGS__) +#define WRAP_ARGS73(w, o, _1, ...) w(o, _1), WRAP_ARGS72(w, o, __VA_ARGS__) +#define WRAP_ARGS74(w, o, _1, ...) w(o, _1), WRAP_ARGS73(w, o, __VA_ARGS__) +#define WRAP_ARGS75(w, o, _1, ...) w(o, _1), WRAP_ARGS74(w, o, __VA_ARGS__) +#define WRAP_ARGS76(w, o, _1, ...) w(o, _1), WRAP_ARGS75(w, o, __VA_ARGS__) +#define WRAP_ARGS77(w, o, _1, ...) w(o, _1), WRAP_ARGS76(w, o, __VA_ARGS__) +#define WRAP_ARGS78(w, o, _1, ...) w(o, _1), WRAP_ARGS77(w, o, __VA_ARGS__) +#define WRAP_ARGS79(w, o, _1, ...) w(o, _1), WRAP_ARGS78(w, o, __VA_ARGS__) +#define WRAP_ARGS80(w, o, _1, ...) w(o, _1), WRAP_ARGS79(w, o, __VA_ARGS__) +#define WRAP_ARGS81(w, o, _1, ...) w(o, _1), WRAP_ARGS80(w, o, __VA_ARGS__) +#define WRAP_ARGS82(w, o, _1, ...) w(o, _1), WRAP_ARGS81(w, o, __VA_ARGS__) +#define WRAP_ARGS83(w, o, _1, ...) w(o, _1), WRAP_ARGS82(w, o, __VA_ARGS__) +#define WRAP_ARGS84(w, o, _1, ...) w(o, _1), WRAP_ARGS83(w, o, __VA_ARGS__) +#define WRAP_ARGS85(w, o, _1, ...) w(o, _1), WRAP_ARGS84(w, o, __VA_ARGS__) +#define WRAP_ARGS86(w, o, _1, ...) w(o, _1), WRAP_ARGS85(w, o, __VA_ARGS__) +#define WRAP_ARGS87(w, o, _1, ...) w(o, _1), WRAP_ARGS86(w, o, __VA_ARGS__) +#define WRAP_ARGS88(w, o, _1, ...) w(o, _1), WRAP_ARGS87(w, o, __VA_ARGS__) +#define WRAP_ARGS89(w, o, _1, ...) w(o, _1), WRAP_ARGS88(w, o, __VA_ARGS__) +#define WRAP_ARGS90(w, o, _1, ...) w(o, _1), WRAP_ARGS89(w, o, __VA_ARGS__) +#define WRAP_ARGS91(w, o, _1, ...) w(o, _1), WRAP_ARGS90(w, o, __VA_ARGS__) +#define WRAP_ARGS92(w, o, _1, ...) w(o, _1), WRAP_ARGS91(w, o, __VA_ARGS__) +#define WRAP_ARGS93(w, o, _1, ...) w(o, _1), WRAP_ARGS92(w, o, __VA_ARGS__) +#define WRAP_ARGS94(w, o, _1, ...) w(o, _1), WRAP_ARGS93(w, o, __VA_ARGS__) +#define WRAP_ARGS95(w, o, _1, ...) w(o, _1), WRAP_ARGS94(w, o, __VA_ARGS__) +#define WRAP_ARGS96(w, o, _1, ...) w(o, _1), WRAP_ARGS95(w, o, __VA_ARGS__) +#define WRAP_ARGS97(w, o, _1, ...) w(o, _1), WRAP_ARGS96(w, o, __VA_ARGS__) +#define WRAP_ARGS98(w, o, _1, ...) w(o, _1), WRAP_ARGS97(w, o, __VA_ARGS__) +#define WRAP_ARGS99(w, o, _1, ...) w(o, _1), WRAP_ARGS98(w, o, __VA_ARGS__) +#define WRAP_ARGS100(w, o, _1, ...) w(o, _1), WRAP_ARGS99(w, o, __VA_ARGS__) +#define WRAP_ARGS101(w, o, _1, ...) w(o, _1), WRAP_ARGS100(w, o, __VA_ARGS__) +#define WRAP_ARGS102(w, o, _1, ...) w(o, _1), WRAP_ARGS101(w, o, __VA_ARGS__) +#define WRAP_ARGS103(w, o, _1, ...) w(o, _1), WRAP_ARGS102(w, o, __VA_ARGS__) +#define WRAP_ARGS104(w, o, _1, ...) w(o, _1), WRAP_ARGS103(w, o, __VA_ARGS__) +#define WRAP_ARGS105(w, o, _1, ...) w(o, _1), WRAP_ARGS104(w, o, __VA_ARGS__) +#define WRAP_ARGS106(w, o, _1, ...) w(o, _1), WRAP_ARGS105(w, o, __VA_ARGS__) +#define WRAP_ARGS107(w, o, _1, ...) w(o, _1), WRAP_ARGS106(w, o, __VA_ARGS__) +#define WRAP_ARGS108(w, o, _1, ...) w(o, _1), WRAP_ARGS107(w, o, __VA_ARGS__) +#define WRAP_ARGS109(w, o, _1, ...) w(o, _1), WRAP_ARGS108(w, o, __VA_ARGS__) +#define WRAP_ARGS110(w, o, _1, ...) w(o, _1), WRAP_ARGS109(w, o, __VA_ARGS__) +#define WRAP_ARGS111(w, o, _1, ...) w(o, _1), WRAP_ARGS110(w, o, __VA_ARGS__) +#define WRAP_ARGS112(w, o, _1, ...) w(o, _1), WRAP_ARGS111(w, o, __VA_ARGS__) +#define WRAP_ARGS113(w, o, _1, ...) w(o, _1), WRAP_ARGS112(w, o, __VA_ARGS__) +#define WRAP_ARGS114(w, o, _1, ...) w(o, _1), WRAP_ARGS113(w, o, __VA_ARGS__) +#define WRAP_ARGS115(w, o, _1, ...) w(o, _1), WRAP_ARGS114(w, o, __VA_ARGS__) +#define WRAP_ARGS116(w, o, _1, ...) w(o, _1), WRAP_ARGS115(w, o, __VA_ARGS__) +#define WRAP_ARGS117(w, o, _1, ...) w(o, _1), WRAP_ARGS116(w, o, __VA_ARGS__) +#define WRAP_ARGS118(w, o, _1, ...) w(o, _1), WRAP_ARGS117(w, o, __VA_ARGS__) +#define WRAP_ARGS119(w, o, _1, ...) w(o, _1), WRAP_ARGS118(w, o, __VA_ARGS__) +#define WRAP_ARGS120(w, o, _1, ...) w(o, _1), WRAP_ARGS119(w, o, __VA_ARGS__) +#define WRAP_ARGS121(w, o, _1, ...) w(o, _1), WRAP_ARGS120(w, o, __VA_ARGS__) +#define WRAP_ARGS122(w, o, _1, ...) w(o, _1), WRAP_ARGS121(w, o, __VA_ARGS__) +#define WRAP_ARGS123(w, o, _1, ...) w(o, _1), WRAP_ARGS122(w, o, __VA_ARGS__) +#define WRAP_ARGS124(w, o, _1, ...) w(o, _1), WRAP_ARGS123(w, o, __VA_ARGS__) +#define WRAP_ARGS125(w, o, _1, ...) w(o, _1), WRAP_ARGS124(w, o, __VA_ARGS__) diff --git a/include/ylt/reflection/member_count.hpp b/include/ylt/reflection/member_count.hpp index 8c91ea6b4..73be4c83d 100644 --- a/include/ylt/reflection/member_count.hpp +++ b/include/ylt/reflection/member_count.hpp @@ -6,6 +6,8 @@ #include #include +#include "user_reflect_macro.hpp" + namespace ylt::reflection { template using remove_cvref_t = std::remove_cv_t>; @@ -161,7 +163,13 @@ inline constexpr std::size_t members_count_impl() { template inline constexpr std::size_t members_count() { using type = remove_cvref_t; - if constexpr (internal::tuple_size) { + if constexpr (is_out_ylt_refl_v) { + return refl_member_count(ylt::reflection::identity{}); + } + else if constexpr (is_inner_ylt_refl_v) { + return type::refl_member_count(ylt::reflection::identity{}); + } + else if constexpr (internal::tuple_size) { return std::tuple_size::value; } else { diff --git a/include/ylt/reflection/member_names.hpp b/include/ylt/reflection/member_names.hpp index 8f68d47df..53b564e40 100644 --- a/include/ylt/reflection/member_names.hpp +++ b/include/ylt/reflection/member_names.hpp @@ -2,10 +2,8 @@ #include #include -#include "template_string.hpp" -#if (__has_include() || defined(__clang__) || defined(_MSC_VER)) || \ - (defined(__GNUC__) && __GNUC__ > 10) #include "member_ptr.hpp" +#include "template_string.hpp" namespace ylt::reflection { @@ -54,15 +52,25 @@ template inline constexpr std::array> get_member_names() { constexpr size_t Count = members_count_v; - constexpr auto tp = struct_to_tuple(); - - std::array arr; - [&](std::index_sequence) mutable { - ((arr[Is] = internal::get_member_name(tp))>()), - ...); + using type = remove_cvref_t; + if constexpr (is_out_ylt_refl_v) { + return refl_member_names(ylt::reflection::identity{}); + } + else if constexpr (is_inner_ylt_refl_v) { + return type::refl_member_names(ylt::reflection::identity{}); + } + else { + constexpr auto tp = struct_to_tuple(); + + std::array arr; + [&](std::index_sequence) mutable { + ((arr[Is] = + internal::get_member_name(tp))>()), + ...); + } + (std::make_index_sequence{}); + return arr; } - (std::make_index_sequence{}); - return arr; } template @@ -101,7 +109,7 @@ inline constexpr auto tuple_to_variant(std::tuple) { template using struct_variant_t = decltype(tuple_to_variant( - std::declval>())>)); + std::declval>())>)); template constexpr auto member_names_map = internal::get_member_names_map(); @@ -137,10 +145,12 @@ inline constexpr size_t index_of(std::string_view name) { return arr.size(); } +#if __has_include() template inline constexpr size_t index_of() { return index_of(name.str()); } +#endif template inline constexpr std::string_view name_of() { @@ -160,7 +170,7 @@ inline constexpr std::string_view name_of(size_t index) { } template -inline constexpr void for_each(Visit func) { +inline constexpr void for_each(Visit&& func) { constexpr auto& arr = member_names; [&](std::index_sequence) mutable { if constexpr (std::is_invocable_v) { @@ -180,4 +190,3 @@ inline constexpr void for_each(Visit func) { } } // namespace ylt::reflection -#endif diff --git a/include/ylt/reflection/member_ptr.hpp b/include/ylt/reflection/member_ptr.hpp index 00808667e..2499958ce 100644 --- a/include/ylt/reflection/member_ptr.hpp +++ b/include/ylt/reflection/member_ptr.hpp @@ -104,12 +104,30 @@ inline constexpr auto struct_to_tuple() { template inline constexpr auto object_to_tuple(T& t) { - return internal::tuple_view(t); + using type = remove_cvref_t; + if constexpr (is_out_ylt_refl_v) { + return refl_object_to_tuple(t); + } + else if constexpr (is_inner_ylt_refl_v) { + return type::refl_object_to_tuple(t); + } + else { + return internal::tuple_view(t); + } } template > inline constexpr decltype(auto) visit_members(T&& t, Visitor&& visitor) { - return internal::tuple_view(std::forward(t), - std::forward(visitor)); + using type = remove_cvref_t; + if constexpr (is_out_ylt_refl_v) { + return refl_visit_members(t, visitor); + } + else if constexpr (is_inner_ylt_refl_v) { + return type::refl_object_to_tuple(t, visitor); + } + else { + return internal::tuple_view(std::forward(t), + std::forward(visitor)); + } } } // namespace ylt::reflection diff --git a/include/ylt/reflection/member_value.hpp b/include/ylt/reflection/member_value.hpp index 05dba3368..85d9dd9c4 100644 --- a/include/ylt/reflection/member_value.hpp +++ b/include/ylt/reflection/member_value.hpp @@ -4,13 +4,10 @@ #include #include +#include "member_names.hpp" #include "template_string.hpp" #include "template_switch.hpp" -#if (__has_include() || defined(__clang__) || defined(_MSC_VER)) || \ - (defined(__GNUC__) && __GNUC__ > 10) -#include "member_names.hpp" - namespace ylt::reflection { namespace internal { @@ -118,11 +115,13 @@ inline constexpr auto& get(T& t) { return std::get(ref_tp); } +#if __has_include() template inline constexpr auto& get(T& t) { constexpr size_t index = index_of(); return get(t); } +#endif template inline size_t index_of(T& t, Field& value) { @@ -146,7 +145,6 @@ inline constexpr std::string_view name_of(T& t, Field& value) { return arr[index]; } -#endif template inline constexpr void for_each(T&& t, Visit&& func) { @@ -158,8 +156,6 @@ inline constexpr void for_each(T&& t, Visit&& func) { }); } else { -#if __has_include() || defined(__clang__) || defined(_MSC_VER) || \ - (defined(__GNUC__) && __GNUC__ > 10) constexpr auto arr = member_names; if constexpr (std::is_invocable_v) { visit_members(t, [&](auto&... args) { @@ -184,14 +180,13 @@ inline constexpr void for_each(T&& t, Visit&& func) { "std::string_view, size_t], at least has field_value and " "make sure keep the order of arguments"); } -#endif } } } // namespace ylt::reflection -#if __has_include() || defined(__clang__) || defined(_MSC_VER) || \ - (defined(__GNUC__) && __GNUC__ > 10) +#if (defined(__GNUC__) && __GNUC__ > 10) || \ + ((defined(__clang__) || defined(_MSC_VER)) && __has_include()) template inline constexpr auto operator""_ylts() { return s; diff --git a/include/ylt/reflection/private_visitor.hpp b/include/ylt/reflection/private_visitor.hpp new file mode 100644 index 000000000..c6459dbc8 --- /dev/null +++ b/include/ylt/reflection/private_visitor.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "internal/common_macro.hpp" + +namespace ylt::reflection { +template +struct private_visitor { + friend inline constexpr auto get_private_ptrs( + const ylt::reflection::identity&) { + constexpr auto tp = std::make_tuple(field...); + return tp; + } +}; +} // namespace ylt::reflection diff --git a/include/ylt/reflection/user_reflect_macro.hpp b/include/ylt/reflection/user_reflect_macro.hpp new file mode 100644 index 000000000..52b2115a6 --- /dev/null +++ b/include/ylt/reflection/user_reflect_macro.hpp @@ -0,0 +1,130 @@ +#pragma once +#include +#include +#include + +#include "internal/arg_list_macro.hpp" + +namespace ylt::reflection { +template +struct member_traits { + using value_type = T; +}; + +template +struct member_traits { + using owner_type = Owner; + using value_type = T; +}; + +template +using member_value_type_t = typename member_traits::value_type; + +#define YLT_REFL(STRUCT, ...) \ + template \ + inline static constexpr decltype(auto) refl_visit_members( \ + STRUCT &t, Visitor &&visitor) { \ + return visitor(WRAP_ARGS(CONCAT_MEMBER, t, __VA_ARGS__)); \ + } \ + template \ + inline static constexpr decltype(auto) refl_visit_members( \ + const STRUCT &t, Visitor &&visitor) { \ + return visitor(WRAP_ARGS(CONCAT_MEMBER, t, __VA_ARGS__)); \ + } \ + inline static decltype(auto) refl_object_to_tuple(STRUCT &t) { \ + return std::tie(WRAP_ARGS(CONCAT_MEMBER, t, __VA_ARGS__)); \ + } \ + inline static constexpr decltype(auto) refl_member_names( \ + const ylt::reflection::identity &t) { \ + constexpr std::array arr{ \ + WRAP_ARGS(CONCAT_NAME, t, __VA_ARGS__)}; \ + return arr; \ + } \ + inline static constexpr std::size_t refl_member_count( \ + const ylt::reflection::identity &t) { \ + return (std::size_t)YLT_ARG_COUNT(__VA_ARGS__); \ + } + +template +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 +inline constexpr auto visit_private_fields(T &t, Visitor &&visitor) { + auto tp = get_private_ptrs(identity{}); + return visit_private_fields_impl(t, tp, visitor); +} + +#define YLT_REFL_PRIVATE_(STRUCT, ...) \ + namespace ylt::reflection { \ + inline constexpr auto get_private_ptrs(const identity &t); \ + template struct private_visitor; \ + template \ + inline static constexpr decltype(auto) refl_visit_members( \ + STRUCT &t, Visitor &&visitor) { \ + return visit_private_fields(t, visitor); \ + } \ + inline static decltype(auto) refl_object_to_tuple(STRUCT &t) { \ + auto tp = get_private_ptrs(identity{}); \ + auto to_ref = [&t](auto... fields) { \ + return std::tie(t.*fields...); \ + }; \ + return std::apply(to_ref, tp); \ + } \ + inline static constexpr std::size_t refl_member_count( \ + const ylt::reflection::identity &t) { \ + return (std::size_t)YLT_ARG_COUNT(__VA_ARGS__); \ + } \ + } + +#define YLT_REFL_PRIVATE(STRUCT, ...) \ + inline static constexpr decltype(auto) refl_member_names( \ + const ylt::reflection::identity &t) { \ + constexpr std::array arr{ \ + WRAP_ARGS(CONCAT_NAME, t, __VA_ARGS__)}; \ + return arr; \ + } \ + YLT_REFL_PRIVATE_(STRUCT, WRAP_ARGS(CONCAT_ADDR, STRUCT, __VA_ARGS__)) + +template +struct is_out_ylt_refl : std::false_type {}; + +template +struct is_out_ylt_refl>()))>> + : std::true_type {}; + +template +constexpr bool is_out_ylt_refl_v = is_out_ylt_refl::value; + +template +struct is_inner_ylt_refl : std::false_type {}; + +template +struct is_inner_ylt_refl< + T, std::void_t().refl_member_count( + std::declval>()))>> : std::true_type {}; + +template +constexpr bool is_inner_ylt_refl_v = is_inner_ylt_refl::value; + +template +struct is_ylt_refl : std::false_type {}; + +template +inline constexpr bool is_ylt_refl_v = is_ylt_refl::value; + +template +struct is_ylt_refl>> + : std::true_type {}; + +template +struct is_ylt_refl>> : std::true_type { +}; +} // namespace ylt::reflection diff --git a/src/reflection/tests/test_reflection.cpp b/src/reflection/tests/test_reflection.cpp index bf6b90bb6..b97e09330 100644 --- a/src/reflection/tests/test_reflection.cpp +++ b/src/reflection/tests/test_reflection.cpp @@ -1,19 +1,28 @@ #include #include +#include "ylt/reflection/member_value.hpp" +#include "ylt/reflection/private_visitor.hpp" #include "ylt/reflection/template_switch.hpp" +#include "ylt/reflection/user_reflect_macro.hpp" + +using namespace ylt::reflection; #define DOCTEST_CONFIG_IMPLEMENT #include "doctest.h" -#if (__has_include() || defined(__clang__) || defined(_MSC_VER)) || \ - (defined(__GNUC__) && __GNUC__ > 10) +struct simple { + int color; + int id; + std::string str; + int age; +}; +#if (defined(__GNUC__) && __GNUC__ > 10) || defined(__clang__) || \ + defined(_MSC_VER) #include "ylt/reflection/member_names.hpp" #include "ylt/reflection/member_value.hpp" -using namespace ylt::reflection; - struct sub { int id; }; @@ -44,13 +53,6 @@ TEST_CASE("test member names") { std::array{"color", "id", "s", "str", "arr"}); } -struct simple { - int color; - int id; - std::string str; - int age; -}; - struct point_t { int x; int y; @@ -58,8 +60,8 @@ struct point_t { void test_pointer() { simple t{}; - auto&& [a, b, c, d] = t; - size_t offset1 = (const char*)(&a) - (const char*)(&t); + auto&& [o, b, c, d] = t; + size_t offset1 = (const char*)(&o) - (const char*)(&t); size_t offset2 = (const char*)(&b) - (const char*)(&t); size_t offset3 = (const char*)(&c) - (const char*)(&t); size_t offset4 = (const char*)(&d) - (const char*)(&t); @@ -81,8 +83,10 @@ void test_pt() { static_assert(y == 4); CHECK(y == 4); +#if __has_include() constexpr auto x = get<"x"_ylts>(pt); static_assert(x == 2); +#endif } TEST_CASE("test member value") { @@ -114,11 +118,13 @@ TEST_CASE("test member value") { auto& age1 = get(p, "age"); CHECK(age1 == 6); +#if __has_include() auto& age2 = get<"age"_ylts>(p); CHECK(age2 == 6); auto& var1 = get<"str"_ylts>(p); CHECK(var1 == "hello reflection"); +#endif test_pt(); @@ -172,14 +178,16 @@ TEST_CASE("test member value") { constexpr std::string_view name2 = name_of(2); CHECK(name2 == "str"); +#if __has_include() constexpr size_t idx = index_of(); CHECK(idx == 2); - constexpr size_t idx1 = index_of("str"); - CHECK(idx1 == 2); - constexpr size_t idx2 = index_of(); CHECK(idx2 == 4); +#endif + + constexpr size_t idx1 = index_of("str"); + CHECK(idx1 == 2); size_t idx3 = index_of("no_such"); CHECK(idx3 == 4); @@ -233,6 +241,220 @@ TEST_CASE("test visitor") { #endif +struct dummy_t { + int id; + std::string name; + int age; + YLT_REFL(dummy_t, id, name, age); +}; + +struct dummy_t2 { + int id; + std::string name; + int age; +}; +YLT_REFL(dummy_t2, id, name, age); + +struct dummy_t3 { + int id; + std::string name; + int age; +}; + +struct dummy_t4 { + int id; + std::string name; + int age; + + public: + dummy_t4() {} +}; +constexpr std::size_t refl_member_count( + const ylt::reflection::identity& t) { + return 3; +} + +struct dummy_t5 { + private: + int id = 42; + std::string name = "tom"; + int age = 20; + + public: + int& get_id() { return id; } + std::string& get_name() { return name; } + int& get_age() { return age; } + + const int& get_id() const { return id; } + const std::string& get_name() const { return name; } + const int& get_age() const { return age; } +}; +YLT_REFL(dummy_t5, get_id(), get_name(), get_age()); + +struct simple2 { + int color; + int id; + std::string str; + int age; + simple2() = default; + simple2(int a, int b, std::string c, int d) + : color(a), id(b), str(c), age(d) {} +}; +YLT_REFL(simple2, color, id, str, age); + +TEST_CASE("test macros") { + static_assert(!std::is_aggregate_v); + simple2 t{2, 10, "hello reflection", 6}; + constexpr auto arr = member_names; + static_assert(arr.size() == 4); + constexpr auto map = member_names_map; + constexpr size_t index = map.at("age"); + CHECK(index == 3); + constexpr size_t size = members_count_v; + static_assert(size == 3); + + auto ref_tp = object_to_tuple(t); + auto& c = std::get<0>(ref_tp); + c = 10; + CHECK(t.color == 10); + + using Tuple = decltype(struct_to_tuple()); + std::cout << type_string() << "\n"; + + constexpr size_t size2 = members_count_v; + static_assert(size2 == 3); + + constexpr size_t size3 = members_count_v; + static_assert(size3 == 3); + + constexpr size_t size4 = members_count(); + static_assert(size4 == 3); + + constexpr size_t size5 = members_count_v; + static_assert(size5 == 3); + + dummy_t5 d5{}; + refl_visit_members(d5, [](auto&... args) { + CHECK(sizeof...(args) == 3); + ((std::cout << args << ", "), ...); + std::cout << "\n"; + }); + + visit_members(d5, [](auto&... args) { + CHECK(sizeof...(args) == 3); + ((std::cout << args << ", "), ...); + std::cout << "\n"; + }); + + for_each(d5, [](auto& arg) { + std::cout << arg << "\n"; + }); + + auto& age1 = get(t, "age"); + CHECK(age1 == 6); + + auto str2 = get<2>(t); + CHECK(str2 == "hello reflection"); + + auto var = get(t, 3); + CHECK(*std::get<3>(var) == 6); + +#if __has_include() + auto& age2 = get<"age"_ylts>(t); + CHECK(age2 == 6); + + auto& var1 = get<"str"_ylts>(t); + CHECK(var1 == "hello reflection"); + + constexpr size_t idx = index_of(); + CHECK(idx == 2); + + constexpr size_t idx2 = index_of(); + CHECK(idx2 == 4); +#endif + + constexpr std::string_view name1 = name_of(); + CHECK(name1 == "str"); + + constexpr std::string_view name2 = name_of(2); + CHECK(name2 == "str"); + + constexpr size_t idx1 = index_of("str"); + CHECK(idx1 == 2); + + size_t idx3 = index_of("no_such"); + CHECK(idx3 == 4); + + size_t idx4 = index_of(t, age1); + CHECK(idx4 == 3); + + auto name3 = name_of(t, age1); + CHECK(name3 == "age"); + + int no_such = 100; + size_t idx5 = index_of(t, no_such); + CHECK(idx5 == 4); + + for_each(t, [](auto& arg) { + if constexpr (std::is_same_v>) { + arg = "test"; + } + std::cout << arg << "\n"; + }); + CHECK(t.str == "test"); + + for_each([](std::string_view field_name, size_t index) { + std::cout << index << ", " << field_name << "\n"; + }); + + for_each([](std::string_view field_name) { + std::cout << field_name << "\n"; + }); +} + +class Bank_t { + int id; + std::string name; + + public: + Bank_t(int i, std::string str) : id(i), name(str) {} +}; +YLT_REFL_PRIVATE(Bank_t, id, name); + +class private_struct { + int a; + int b; + + public: + private_struct(int x, int y) : a(x), b(y) {} +}; +YLT_REFL_PRIVATE(private_struct, a, b); + +TEST_CASE("test visit private") { + Bank_t bank(1, "ok"); + constexpr auto tp = get_private_ptrs(identity{}); + refl_visit_members(bank, [](auto&... args) { + ((std::cout << args << " "), ...); + std::cout << "\n"; + }); + + private_struct st(2, 4); + refl_visit_members(st, [](auto&... args) { + ((std::cout << args << " "), ...); + std::cout << "\n"; + }); + + auto ref_tp = refl_object_to_tuple(st); + std::get<1>(ref_tp) = 8; + + auto names = refl_member_names(identity{}); + auto names1 = refl_member_names(identity{}); + auto count = refl_member_count(identity{}); + + auto id = bank.*(std::get<0>(tp)); // 1 + auto name = bank.*(std::get<1>(tp)); // ok +} + DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); } DOCTEST_MSVC_SUPPRESS_WARNING_POP