From e2f299e1a4f3bea6cbb1fdd6b0835d40553fdea8 Mon Sep 17 00:00:00 2001 From: ykiko Date: Tue, 3 Sep 2024 20:51:53 +0800 Subject: [PATCH] update Reflection. --- .clang-format | 4 +- include/Support/Reflection.h | 182 +++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 include/Support/Reflection.h diff --git a/.clang-format b/.clang-format index b899d756..bc8c33a5 100644 --- a/.clang-format +++ b/.clang-format @@ -48,7 +48,7 @@ EmptyLineBeforeAccessModifier: Always AllowAllArgumentsOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false AllowBreakBeforeNoexceptSpecifier: Never -AllowShortBlocksOnASingleLine: Always +AllowShortBlocksOnASingleLine: Empty AllowShortCaseLabelsOnASingleLine: true AllowShortCompoundRequirementOnASingleLine: true AllowShortEnumsOnASingleLine: true @@ -99,4 +99,4 @@ SortIncludes: Never SortUsingDeclarations: Never IncludeBlocks: Merge -WhitespaceSensitiveMacros: ["PK_PROTECTED", "LUA_PROTECTED"] +ForEachMacros: ["REFLECTABLE_RECORD"] diff --git a/include/Support/Reflection.h b/include/Support/Reflection.h new file mode 100644 index 00000000..f34cc647 --- /dev/null +++ b/include/Support/Reflection.h @@ -0,0 +1,182 @@ +#pragma once + +// support basic reflection through template meta programming +#include +#include +#include + +namespace clice::impl { + +struct Any { + consteval Any(std::size_t); + + template + consteval operator T () const; +}; + +template +consteval auto test() { + return [](std::index_sequence) { + return requires { T{Any(I)...}; }; + }(std::make_index_sequence{}); +} + +template +consteval auto member_count() { + if constexpr(test() && !test()) { + return N; + } else { + return member_count(); + } +} + +template +struct Wrapper { + T value; + + constexpr Wrapper(T value) : value(value) {} +}; + +template +constexpr auto member_name() { + std::string_view name = std::source_location::current().function_name(); +#if __GNUC__ && (!__clang__) && (!_MSC_VER) + std::size_t start = name.rfind("::") + 2; + std::size_t end = name.rfind(')'); + return name.substr(start, end - start); +#elif __clang__ + std::size_t start = name.rfind(".") + 1; + std::size_t end = name.rfind('}'); + return name.substr(start, end - start); +#elif _MSC_VER + std::size_t start = name.rfind("->") + 2; + std::size_t end = name.rfind('}'); + return name.substr(start, end - start); +#else + static_assert(false, "Not supported compiler"); +#endif +} + +template +constexpr auto collcet_members(Object&& object) { + // clang-format off + if constexpr(count == 1) { + auto&& [a] = object; + return std::tuple{&a}; + } else if constexpr(count == 2) { + auto&& [a, b] = object; + return std::tuple{&a, &b}; + } else if constexpr(count == 3) { + auto&& [a, b, c] = object; + return std::tuple{&a, &b, &c}; + } else if constexpr(count == 4) { + auto&& [a, b, c, d] = object; + return std::tuple{&a, &b, &c, &d}; + } else if constexpr(count == 5) { + auto&& [a, b, c, d, e] = object; + return std::tuple{&a, &b, &c, &d, &e}; + } else if constexpr(count == 6) { + auto&& [a, b, c, d, e, f] = object; + return std::tuple{&a, &b, &c, &d, &e, &f}; + } else if constexpr(count == 7) { + auto&& [a, b, c, d, e, f, g] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g}; + } else if constexpr(count == 8) { + auto&& [a, b, c, d, e, f, g, h] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h}; + } else if constexpr(count == 9) { + auto&& [a, b, c, d, e, f, g, h, i] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i}; + } else if constexpr(count == 10) { + auto&& [a, b, c, d, e, f, g, h, i, j] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j}; + } else if constexpr(count == 11) { + auto&& [a, b, c, d, e, f, g, h, i, j, k] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k}; + } else if constexpr(count == 12) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l}; + } else if constexpr(count == 13) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m}; + } else if constexpr(count == 14) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n}; + } else if constexpr(count == 15) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o}; + } else if constexpr(count == 16) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p}; + } else if constexpr(count == 17) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q}; + } else if constexpr(count == 18) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r}; + } else if constexpr(count == 19) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r, &s}; + } else if constexpr(count == 20) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r, &s, &t}; + } else if constexpr(count == 21) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r, &s, &t, &u}; + } else if constexpr(count == 22) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r, &s, &t, &u, &v}; + } else if constexpr(count == 23) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r, &s, &t, &u, &v, &w}; + } else if constexpr(count == 24) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r, &s, &t, &u, &v, &w, &x}; + } else if constexpr(count == 25) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r, &s, &t, &u, &v, &w, &x, &y}; + } else if constexpr(count == 26) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r, &s, &t, &u, &v, &w, &x, &y, &z}; + } else if constexpr(count == 27) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, _0] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r, &s, &t, &u, &v, &w, &x, &y, &z, &_0}; + } else if constexpr(count == 28) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, _0, _1] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r, &s, &t, &u, &v, &w, &x, &y, &z, &_0, &_1}; + } else if constexpr(count == 29) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, _0, _1, _2] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r, &s, &t, &u, &v, &w, &x, &y, &z, &_0, &_1, &_2}; + } else if constexpr(count == 30) { + auto&& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, _0, _1, _2, _3] = object; + return std::tuple{&a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k, &l, &m, &n, &o, &p, &q, &r, &s, &t, &u, &v, &w, &x, &y, &z, &_0, &_1, &_2, &_3}; + } else { + static_assert(count <= 30, "Not supported member count"); + } + // clang-format on +} + +template +struct Storage { + inline static T value; +}; + +} // namespace clice::impl + +namespace clice { + +template +concept Reflectable = std::is_aggregate_v> && std::is_default_constructible_v>; + +template +constexpr void for_each(Object&& object, const Callback& callback) { + using T = std::decay_t; + constexpr auto count = impl::member_count(); + auto members = impl::collcet_members(object); + constexpr auto static_members = impl::collcet_members(impl::Storage::value); + [&](std::index_sequence) { + (callback(impl::member_name(static_members)>(), *std::get(members)), ...); + }(std::make_index_sequence{}); +} + +}; // namespace clice