From 044a2b67e19e17ec97a55e055cff00d6f3dbb255 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 11 Mar 2020 22:06:16 -0400 Subject: [PATCH] Beefs up documentation on this miniature sort-of reflection. --- Analyser/Static/Macintosh/Target.hpp | 2 +- .../Clock Signal.xcodeproj/project.pbxproj | 2 - Reflection/Enum.h | 86 ++++++++++++++++--- Reflection/Struct.h | 25 ++++-- 4 files changed, 91 insertions(+), 24 deletions(-) diff --git a/Analyser/Static/Macintosh/Target.hpp b/Analyser/Static/Macintosh/Target.hpp index e9cbc82df..86295e31a 100644 --- a/Analyser/Static/Macintosh/Target.hpp +++ b/Analyser/Static/Macintosh/Target.hpp @@ -23,7 +23,7 @@ struct Target: public ::Analyser::Static::Target, public Reflection::Struct(EnumDeclaration(Model)); + AnnounceEnum(Model); } } diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index c7f57a85b..ee4db8516 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -5117,7 +5117,6 @@ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; - CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; CODE_SIGN_ENTITLEMENTS = "Clock Signal/Clock Signal.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; @@ -5164,7 +5163,6 @@ CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES; CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES; - CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES; CODE_SIGN_ENTITLEMENTS = "Clock Signal/Clock Signal.entitlements"; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; diff --git a/Reflection/Enum.h b/Reflection/Enum.h index 9db6bb1a7..1410d6a4c 100644 --- a/Reflection/Enum.h +++ b/Reflection/Enum.h @@ -22,11 +22,39 @@ namespace Reflection { enum class Name: Type { Mac128k, Mac512k, Mac512ke, MacPlus }; \ constexpr static const char *__declaration##Name = #__VA_ARGS__; -#define EnumDeclaration(Name) __declaration##Name +#define EnumDeclaration(Name) #Name, __declaration##Name +#define AnnounceEnum(Name) ::Reflection::Enum::declare(EnumDeclaration(Name)) + +/*! + This provides a very slight version of enum reflection; you can introspect only: + + * enums have been registered, along with the text of their declarations; + * provided that those enums do not declare specific values for their members. + + The macros above help avoid duplication of the declaration, making this just mildly less + terrible than it might have been. + + No guarantees of speed or any other kind of efficiency are offered. +*/ class Enum { public: - template static void declare(const char *declaration) { + /*! + Registers @c name and the entries within @c declaration for the enum type @c Type. + + Assuming the caller used the macros above, a standard pattern where both things can be placed in + the same namespace might look like: + + ReflectableEnum(MyEnum, int, A, B, C); + + ... + + AnnounceEnum(MyEnum) + + If AnnounceEnum cannot be placed into the same namespace as ReflectableEnum, see the + EnumDeclaration macro. + */ + template static void declare(const char *name, const char *declaration) { const char *d_ptr = declaration; std::vector result; @@ -46,43 +74,77 @@ class Enum { members_by_type_.emplace(std::make_pair(&typeid(Type), result)); } + /*! + @returns the declared name of the enum @c Type if it has been registered; the empty string otherwise. + */ + template const std::string &name() { + return name(typeid(Type)); + } + + /*! + @returns the declared name of the enum with type_info @c type if it has been registered; the empty string otherwise. + */ + const std::string &name(const std::type_info &type) { + const auto entry = names_by_type_.find(&type); + if(entry == names_by_type_.end()) return empty_string_; + return entry->second; + } + + /*! + @returns the number of members of the enum @c Type if it has been registered; 0 otherwise. + */ template size_t size() { return size(typeid(Type)); } + /*! + @returns the number of members of the enum with type_info @c type if it has been registered; @c std::string::npos otherwise. + */ size_t size(const std::type_info &type) { const auto entry = members_by_type_.find(&type); - if(entry == members_by_type_.end()) return 0; + if(entry == members_by_type_.end()) return std::string::npos; return entry->second.size(); } /*! - @returns A @c string_view name for the enum value @c e. + @returns A @c std::string name for the enum value @c e. */ - template static const std::string &toString(EnumType e) { - const auto entry = members_by_type_.find(&typeid(EnumType)); - if(entry == members_by_type_.end()) return empty_string_; - return entry->second[size_t(e)]; + template static const std::string &toString(Type e) { + return toString(typeid(Type), size_t(e)); } /*! - @returns A value of @c EnumType name for the name @c str, or @c EnumType(-1) if - the string is not found. + @returns A @c std::string name for the enum value @c e from the enum with type_info @c type. + */ + static const std::string &toString(const std::type_info &type, size_t e) { + const auto entry = members_by_type_.find(&type); + if(entry == members_by_type_.end()) return empty_string_; + return entry->second[e]; + } + + /*! + @returns A value of @c Type for the name @c str, or @c EnumType(std::string::npos) if + the name is not found. */ template Type fromString(const std::string &str) { return Type(fromString(typeid(Type), str)); } + /*! + @returns A value for the name @c str in the enum with type_info @c type , or @c std::string::npos if + the name is not found. + */ size_t fromString(const std::type_info &type, const std::string &str) { const auto entry = members_by_type_.find(&type); - if(entry == members_by_type_.end()) return 0; + if(entry == members_by_type_.end()) return std::string::npos; const auto iterator = std::find(entry->second.begin(), entry->second.end(), str); - if(iterator == entry->second.end()) return 0; + if(iterator == entry->second.end()) return std::string::npos; return size_t(iterator - entry->second.begin()); } private: static inline std::unordered_map> members_by_type_; + static inline std::unordered_map names_by_type_; static inline const std::string empty_string_; }; diff --git a/Reflection/Struct.h b/Reflection/Struct.h index 7e55d702a..27b7c28dd 100644 --- a/Reflection/Struct.h +++ b/Reflection/Struct.h @@ -19,24 +19,39 @@ namespace Reflection { template class Struct { public: + /*! + @returns the value of type @c Type that is loaded from the offset registered for the field @c name. + It is the caller's responsibility to provide an appropriate type of data. + */ 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); } + /*! + Stores the @c value of type @c Type to the offset registered for the field @c name. + + It is the caller's responsibility to provide an appropriate type of data. + */ template void set(const std::string &name, const Type &value) { const auto iterator = contents_.find(name); if(iterator == contents_.end()) return; *reinterpret_cast(reinterpret_cast(this) + iterator->second.offset) = value; } + /*! + @returns @c type_info for the field @c name. + */ 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; } + /*! + @returns A vector of all declared fields for this struct. + */ std::vector all_keys() { std::vector keys; for(const auto &pair: contents_) { @@ -70,15 +85,7 @@ template class Struct { } /*! - Provides the original declaration of an enum. - */ - template void declare_enum(Type *t, const char *declaration) { - // TODO: something. - printf("%s\n", declaration); - } - - /*! - @returns @c true if this + @returns @c true if this subclass of @c Struct has not yet declared any fields. */ bool needs_declare() { return !contents_.size();