mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 08:49:37 +00:00
Beefs up documentation on this miniature sort-of reflection.
This commit is contained in:
parent
7e8b86e9bb
commit
044a2b67e1
@ -23,7 +23,7 @@ struct Target: public ::Analyser::Static::Target, public Reflection::Struct<Targ
|
|||||||
// Boilerplate for declaring fields and potential values.
|
// Boilerplate for declaring fields and potential values.
|
||||||
if(needs_declare()) {
|
if(needs_declare()) {
|
||||||
declare(&model, "model");
|
declare(&model, "model");
|
||||||
Reflection::Enum::declare<Model>(EnumDeclaration(Model));
|
AnnounceEnum(Model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5117,7 +5117,6 @@
|
|||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
|
||||||
CODE_SIGN_ENTITLEMENTS = "Clock Signal/Clock Signal.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "Clock Signal/Clock Signal.entitlements";
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
@ -5164,7 +5163,6 @@
|
|||||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CLANG_WARN__EXIT_TIME_DESTRUCTORS = YES;
|
|
||||||
CODE_SIGN_ENTITLEMENTS = "Clock Signal/Clock Signal.entitlements";
|
CODE_SIGN_ENTITLEMENTS = "Clock Signal/Clock Signal.entitlements";
|
||||||
CODE_SIGN_IDENTITY = "Apple Development";
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
@ -22,11 +22,39 @@ namespace Reflection {
|
|||||||
enum class Name: Type { Mac128k, Mac512k, Mac512ke, MacPlus }; \
|
enum class Name: Type { Mac128k, Mac512k, Mac512ke, MacPlus }; \
|
||||||
constexpr static const char *__declaration##Name = #__VA_ARGS__;
|
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<Name>(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 {
|
class Enum {
|
||||||
public:
|
public:
|
||||||
template <typename Type> 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 <typename Type> static void declare(const char *name, const char *declaration) {
|
||||||
const char *d_ptr = declaration;
|
const char *d_ptr = declaration;
|
||||||
|
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
@ -46,43 +74,77 @@ class Enum {
|
|||||||
members_by_type_.emplace(std::make_pair(&typeid(Type), result));
|
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 <typename Type> 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 <typename Type> size_t size() {
|
template <typename Type> size_t size() {
|
||||||
return size(typeid(Type));
|
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) {
|
size_t size(const std::type_info &type) {
|
||||||
const auto entry = members_by_type_.find(&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();
|
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 <typename EnumType> static const std::string &toString(EnumType e) {
|
template <typename Type> static const std::string &toString(Type e) {
|
||||||
const auto entry = members_by_type_.find(&typeid(EnumType));
|
return toString(typeid(Type), size_t(e));
|
||||||
if(entry == members_by_type_.end()) return empty_string_;
|
|
||||||
return entry->second[size_t(e)];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@returns A value of @c EnumType name for the name @c str, or @c EnumType(-1) if
|
@returns A @c std::string name for the enum value @c e from the enum with type_info @c type.
|
||||||
the string is not found.
|
*/
|
||||||
|
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 <typename Type> Type fromString(const std::string &str) {
|
template <typename Type> Type fromString(const std::string &str) {
|
||||||
return Type(fromString(typeid(Type), 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) {
|
size_t fromString(const std::type_info &type, const std::string &str) {
|
||||||
const auto entry = members_by_type_.find(&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;
|
||||||
const auto iterator = std::find(entry->second.begin(), entry->second.end(), str);
|
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());
|
return size_t(iterator - entry->second.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static inline std::unordered_map<const std::type_info *, std::vector<std::string>> members_by_type_;
|
static inline std::unordered_map<const std::type_info *, std::vector<std::string>> members_by_type_;
|
||||||
|
static inline std::unordered_map<const std::type_info *, std::string> names_by_type_;
|
||||||
static inline const std::string empty_string_;
|
static inline const std::string empty_string_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -19,24 +19,39 @@ namespace Reflection {
|
|||||||
|
|
||||||
template <typename Owner> class Struct {
|
template <typename Owner> class Struct {
|
||||||
public:
|
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 <typename Type> const Type *get(const std::string &name) {
|
template <typename Type> const Type *get(const std::string &name) {
|
||||||
const auto iterator = contents_.find(name);
|
const auto iterator = contents_.find(name);
|
||||||
if(iterator == contents_.end()) return nullptr;
|
if(iterator == contents_.end()) return nullptr;
|
||||||
return reinterpret_cast<Type *>(reinterpret_cast<uint8_t *>(this) + iterator->second.offset);
|
return reinterpret_cast<Type *>(reinterpret_cast<uint8_t *>(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 <typename Type> void set(const std::string &name, const Type &value) {
|
template <typename Type> void set(const std::string &name, const Type &value) {
|
||||||
const auto iterator = contents_.find(name);
|
const auto iterator = contents_.find(name);
|
||||||
if(iterator == contents_.end()) return;
|
if(iterator == contents_.end()) return;
|
||||||
*reinterpret_cast<Type *>(reinterpret_cast<uint8_t *>(this) + iterator->second.offset) = value;
|
*reinterpret_cast<Type *>(reinterpret_cast<uint8_t *>(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 std::type_info *type_of(const std::string &name) {
|
||||||
const auto iterator = contents_.find(name);
|
const auto iterator = contents_.find(name);
|
||||||
if(iterator == contents_.end()) return nullptr;
|
if(iterator == contents_.end()) return nullptr;
|
||||||
return iterator->second.type;
|
return iterator->second.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@returns A vector of all declared fields for this struct.
|
||||||
|
*/
|
||||||
std::vector<std::string> all_keys() {
|
std::vector<std::string> all_keys() {
|
||||||
std::vector<std::string> keys;
|
std::vector<std::string> keys;
|
||||||
for(const auto &pair: contents_) {
|
for(const auto &pair: contents_) {
|
||||||
@ -70,15 +85,7 @@ template <typename Owner> class Struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Provides the original declaration of an enum.
|
@returns @c true if this subclass of @c Struct has not yet declared any fields.
|
||||||
*/
|
|
||||||
template <typename Type> void declare_enum(Type *t, const char *declaration) {
|
|
||||||
// TODO: something.
|
|
||||||
printf("%s\n", declaration);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
@returns @c true if this
|
|
||||||
*/
|
*/
|
||||||
bool needs_declare() {
|
bool needs_declare() {
|
||||||
return !contents_.size();
|
return !contents_.size();
|
||||||
|
Loading…
Reference in New Issue
Block a user