#pragma once #include #include template class reflection { private: template using Field = T Object::*; template using map = std::unordered_map; private: template static map> s_reflector; static map s_fieldname; private: template static std::ptrdiff_t offset(Field field) { return std::ptrdiff_t(&(reinterpret_cast(NULL)->*field)); } static std::string_view name(std::ptrdiff_t offset) { auto it = s_fieldname.find(offset); if (it == s_fieldname.end()) { return ""; } return it->second; } public: reflection(); template static bool exists(std::string const & name) { return s_reflector.count(name); } template static Field get_pointer(std::string const & name) { auto it = s_reflector.find(name); if (it == s_reflector.end()) { return nullptr; } return it->second; } template static std::string_view name(Object const * ptr, T const & data) { return name(std::ptrdiff_t(&data) - std::ptrdiff_t(ptr)); } template static std::string_view name(Object const & obj, T const & data) { return name(&obj, data); } template static std::string_view name(Field field) { return name(offset(field)); } template static void bind(Field field, std::string const & name, std::string const & /*discard*/ = "") { s_fieldname.emplace(offset(field), name); s_reflector.emplace(name, field); } }; #define REFLECT_MEMBER_PP_IMPL2(type, field, ...) \ bind(&type::field, ##__VA_ARGS__, #field) #define REFLECT_MEMBER_PP_IMPL(type, field, ...) \ REFLECT_MEMBER_PP_IMPL2(type, field, ##__VA_ARGS__) #define UNWRAP(...) __VA_ARGS__ #define REFLECT_MEMBER_PP2(data, elem) REFLECT_MEMBER_PP_IMPL(data, UNWRAP elem) #define REFLECT_MEMBER_PP(r, data, elem) REFLECT_MEMBER_PP2(data, elem); #include #include #define CONCAT2(A, B) A##B #define CONCAT(A, B) CONCAT2(A, B) #define CREATE_REFLECTION(type, ...) \ template <> reflection::reflection() { \ BOOST_PP_SEQ_FOR_EACH(REFLECT_MEMBER_PP, type, \ BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)) \ } \ static reflection CONCAT(reflector_, __LINE__) {} template template std::unordered_map reflection::s_reflector; template std::unordered_map reflection::s_fieldname;