#pragma once #include #include #include #include #include #include "reflection/forward.h" #include "reflection/object.h" #include "reflection/proxy.h" #define BIND_F(expr) [](auto &_) -> decltype(auto) { return expr; } #define REFLECTION_F(expr) \ [=](Obj & obj, std::string name) { return Object(expr, std::move(name)); } #define CONST_REFLECTION_F(expr) \ [=](Obj const & obj, std::string name) { \ return Object(expr, std::move(name)); \ } namespace reflection { template constexpr auto is_final_reflection = std::is_same_v || std::is_fundamental_v || std::is_enum_v; template class Reflection { public: operator bool() const { return true; } static Getter getter(std::string_view id) { if (auto it = const_members_.find(id); it != const_members_.end()) { return it->second; } throw std::out_of_range("no id in reflection"); } static Accessor accessor(std::string_view id) { if (auto it = members_.find(id); it != members_.end()) { return it->second; } throw std::out_of_range("no id in reflection"); } template Reflection & bind(std::string_view id, R (Obj::*get)() const, void (Obj::*set)(I)) { using V = std::decay_t; members_.emplace(id, REFLECTION_F(Proxy(obj, get, set))); const_members_.emplace(id, CONST_REFLECTION_F((obj.*get)())); return *this; } template Reflection & bind(std::string_view id, R Obj::*member, void (Obj::*set)(I)) { using V = std::decay_t; members_.emplace(id, REFLECTION_F(Proxy(obj, member, set))); const_members_.emplace(id, CONST_REFLECTION_F(obj.*member)); return *this; } template Reflection & bind(std::string_view id, R (Obj::*get)() const, std::decay_t & (Obj::*acc)()) { members_.emplace(id, REFLECTION_F((obj.*acc)())); const_members_.emplace(id, CONST_REFLECTION_F((obj.*get)())); return *this; } template Reflection & bind(std::string_view id, T (Obj::*get)() const) { const_members_.emplace(id, CONST_REFLECTION_F((obj.*get)())); return *this; } template Reflection & bind(std::string_view id, T Obj::*member) { members_.emplace(id, REFLECTION_F(obj.*member)); const_members_.emplace(id, CONST_REFLECTION_F(obj.*member)); return *this; } template Reflection & bind(std::string_view id, Get get, Set set) { using V = std::decay_t>; members_.emplace(id, REFLECTION_F(Proxy(obj, get, set))); const_members_.emplace(id, CONST_REFLECTION_F(get(obj))); return *this; } template Reflection & bind(std::string_view id, Get get) { if constexpr (!std::is_const_v>) { members_.emplace(id, REFLECTION_F(get(obj))); } else { members_.emplace(id, CONST_REFLECTION_F(get(obj))); } const_members_.emplace(id, CONST_REFLECTION_F(get(obj))); return *this; } private: static Cache> members_; static Cache> const_members_; }; template class Reflection>> { public: static Getter getter(std::string_view) { throw std::logic_error("unreflectable"); } static Accessor accessor(std::string_view) { throw std::logic_error("unreflectable"); } }; template class Reflection { public: static auto getter(std::string_view id) { return [f = Reflection::getter(id)](T const * ptr, std::string name) { return f(*ptr, std::move(name)); }; } static auto accessor(std::string_view id) { return [f = Reflection::accessor(id)](T * ptr, std::string name) { return f(*ptr, std::move(name)); }; } }; template Cache> Reflection::members_; template Cache> Reflection::const_members_; } #undef REFLECTION_F #undef CONST_REFLECTION_F