#pragma once #include #include #include #include #include "JSON.h" #include "Format.h" namespace clice::support { namespace 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 struct storage { inline static T value; }; template consteval 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 } } // namespace impl template struct Struct { constexpr inline static bool reflectable = std::is_aggregate_v> && std::is_default_constructible_v>; constexpr static std::size_t member_count() { return impl::member_count(); } constexpr static T& instance() { return impl::storage::value; } template constexpr static auto collcet_members(Object&& object) { // clang-format off constexpr std::size_t count = member_count(); if constexpr(count == 0) { return std::tuple{}; } else 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 } }; /// To check if the type is reflectable. template concept reflectable = Struct::reflectable; /// Turn the return value of the callable to bool. template constexpr auto foldable(const Callable& callable) { return [&](auto&&... args) { using Ret = std::invoke_result_t; if constexpr(std::is_void_v) { callable(args...); return true; } else { return bool(callable(args...)); } }; } template constexpr bool foreach(Object&& object, const Callback& callable) { using S = Struct>; constexpr auto count = S::member_count(); auto members = S::collcet_members(object); constexpr auto static_members = S::collcet_members(S::instance()); return [&](std::index_sequence) { return (foldable(callable)(impl::member_name(static_members)>(), *std::get(members)) && ...); }(std::make_index_sequence{}); } /// Invoke callback for each member of lhs and rhs, return false /// in callback to abort the iteration. Return true if all members are visited. template constexpr bool foreach(LHS&& lhs, RHS&& rhs, const Callback& callback) { using L = Struct>; using R = Struct>; static_assert(L::member_count() == R::member_count(), "Member count mismatch"); return [&](std::index_sequence) { return (foldable(callback)(*std::get(L::collcet_members(lhs)), *std::get(R::collcet_members(rhs))) && ...); }(std::make_index_sequence{}); } } // namespace clice::support namespace clice::json { template struct Serde { constexpr inline static bool state = !support::foreach(support::Struct::instance(), [](auto, auto&& member) { return !json::stateful_serde>; }); template static json::Value serialize(const T& t, Serdes&&... serdes) { json::Object object; support::foreach(t, [&](std::string_view name, auto&& member) { object.try_emplace(llvm::StringRef(name), json::serialize(member, std::forward(serdes)...)); }); return object; } template static T deserialize(const json::Value& value, Serdes&&... serdes) { assert(value.kind() == json::Value::Object && "Expect an object"); auto object = value.getAsObject(); T t; support::foreach(t, [&](std::string_view name, auto&& member) { auto v = object->get(llvm::StringRef(name)); assert(v && "Member not found"); member = json::deserialize>( *v, std::forward(serdes)...); }); return t; } }; } // namespace clice::json /// FIXME: // template // struct std::formatter : std::formatter { // using Base = std::formatter; // // template // constexpr auto parse(ParseContext& ctx) { // return Base::parse(ctx); // } // // template // auto format(const T& t, FormatContext& ctx) { // return Base::format(clice::json::serialize(t), ctx); // } // };