#pragma once #include #include #include #include #include #include "reflection/forward.h" #include "reflection/object.h" #include "reflection/proxy.h" #define REFLECTION(expr) \ [=](Obj & obj, std::string name) { return Object(expr, std::move(name)); } #define CONST_REFLECTION(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; 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, T (Obj::*get)() const, void (Obj::*set)(V)) { members_.emplace(id, REFLECTION(Proxy(obj, get, set))); const_members_.emplace(id, CONST_REFLECTION((obj.*get)())); return *this; } template Reflection & bind(std::string_view id, T Obj::*member) { members_.emplace(id, REFLECTION(obj.*member)); const_members_.emplace(id, CONST_REFLECTION(obj.*member)); return *this; } template Reflection & bind(std::string_view id, T Obj::*member) { TypeConversion convert; members_.emplace(id, CONST_REFLECTION(convert(obj.*member))); const_members_.emplace(id, CONST_REFLECTION(convert(obj.*member))); 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_; }