diff --git a/Reflection/Struct.h b/Reflection/Struct.h index 250396b76..0f6e83f19 100644 --- a/Reflection/Struct.h +++ b/Reflection/Struct.h @@ -9,25 +9,32 @@ #ifndef Struct_h #define Struct_h -#include #include +#include +#include #include #include namespace Reflection { -class Struct { +template class Struct { public: - template const Type &get(const std::string &name) { - return *std::any_cast(contents_[name]); + template const Type *get(const std::string &name) { + const auto iterator = contents_.find(name); + if(iterator == contents_.end()) return nullptr; + return reinterpret_cast(reinterpret_cast(this) + iterator->second.offset); } template void set(const std::string &name, const Type &value) { - *std::any_cast(contents_[name]) = value; + const auto iterator = contents_.find(name); + if(iterator == contents_.end()) return; + *reinterpret_cast(reinterpret_cast(this) + iterator->second.offset) = value; } - const std::type_info &type_of(const std::string &name) { - return contents_[name].type(); + const std::type_info *type_of(const std::string &name) { + const auto iterator = contents_.find(name); + if(iterator == contents_.end()) return nullptr; + return iterator->second.type; } std::vector all_keys() { @@ -39,12 +46,40 @@ class Struct { } protected: + /* + This interface requires reflective structs to declare all fields; + specifically they should call: + + declare_field(&field1, "field1"); + declare_field(&field2, "field2"); + + Fields are registered in class storage. So callers can use needs_declare() + to determine whether a class of this type has already established the + reflective fields. + */ template void declare(Type *t, const std::string &name) { - contents_[name] = t; + contents_.emplace( + std::make_pair( + name, + Field(typeid(Type), reinterpret_cast(t) - reinterpret_cast(this)) + )); + } + + /*! + @returns @c true if this + */ + bool needs_declare() { + return !contents_.size(); } private: - std::unordered_map contents_; + struct Field { + const std::type_info *type; + ssize_t offset; + Field(const std::type_info &type, ssize_t offset) : + type(&type), offset(offset) {} + }; + static inline std::unordered_map contents_; }; }