From 1a2872c815f0c7ed1f702b004b69ec2b4fa545fc Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Fri, 13 Mar 2020 22:42:37 -0400 Subject: [PATCH] Starts to build an easy `set` interface. --- Machines/Apple/Macintosh/Macintosh.cpp | 3 - OSBindings/SDL/main.cpp | 3 + Reflection/Struct.h | 78 ++++++++++++++++++++++++-- 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/Machines/Apple/Macintosh/Macintosh.cpp b/Machines/Apple/Macintosh/Macintosh.cpp index f8b1306c4..b9ceedf4c 100644 --- a/Machines/Apple/Macintosh/Macintosh.cpp +++ b/Machines/Apple/Macintosh/Macintosh.cpp @@ -51,9 +51,6 @@ namespace { constexpr int CLOCK_RATE = 7833600; - -Analyser::Static::Macintosh::Target nothing; - } namespace Apple { diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index 04a898a83..f7eaa114a 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -39,6 +39,9 @@ namespace { +/// Takes an enum-style camel-case string (e.g. Mac128k) and +//std::string + struct MachineRunner { MachineRunner() { frame_lock_.clear(); diff --git a/Reflection/Struct.h b/Reflection/Struct.h index a040761a7..058de8b13 100644 --- a/Reflection/Struct.h +++ b/Reflection/Struct.h @@ -15,6 +15,8 @@ #include #include +#include "Enum.h" + namespace Reflection { #define DeclareField(Name) declare(&Name, #Name) @@ -22,9 +24,75 @@ namespace Reflection { struct Struct { virtual std::vector all_keys() = 0; virtual const std::type_info *type_of(const std::string &name) = 0; - virtual void set(const std::string &name, const void *value) = 0; - virtual const void *get(const std::string &name) = 0; + virtual void set_raw(const std::string &name, const void *value) = 0; + virtual const void *get_raw(const std::string &name) = 0; virtual ~Struct() {} + + /*! + Attempts to set the property @c name to @c value ; will perform limited type conversions. + + @returns @c true if t + */ + template bool set(const std::string &name, Type value) { + return false; + } + + /*! + Setting an int: + + * to an int copies the int; + * to an int64_t promotes the int; and + * to a registered enum, copies the int. + */ + template <> bool set(const std::string &name, int value) { + const auto target_type = type_of(name); + if(!target_type) return false; + + // No need to convert an int or a registered enum. + if(*target_type == typeid(int) || !Reflection::Enum::name(*target_type).empty()) { + set_raw(name, &value); + return true; + } + + // Promote to an int64_t. + if(*target_type == typeid(int64_t)) { + const auto int64 = int64_t(value); + set_raw(name, &int64); + return true; + } + + return false; + } + + /*! + Setting a string: + + * to an enum, if the string names a member of the enum, sets the value. + */ + template <> bool set(const std::string &name, const std::string &value) { + const auto target_type = type_of(name); + if(!target_type) return false; + + if(Reflection::Enum::name(*target_type).empty()) { + return false; + } + + const auto enum_value = Reflection::Enum::from_string(*target_type, value); + if(enum_value == std::string::npos) { + return false; + } + + int int_value = int(enum_value); + set_raw(name, &int_value); + + return true; + } + + template <> bool set(const std::string &name, const char *value) { + const std::string string(value); + return set(name, string); + } + }; struct Serialisable { @@ -35,13 +103,13 @@ struct Serialisable { virtual bool deserialise(const std::vector &source) = 0; }; -template class StructImpl: public Struct, public Serialisable { +template class StructImpl: public 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. */ - const void *get(const std::string &name) final { + const void *get_raw(const std::string &name) final { const auto iterator = contents_.find(name); if(iterator == contents_.end()) return nullptr; return reinterpret_cast(this) + iterator->second.offset; @@ -52,7 +120,7 @@ template class StructImpl: public Struct, public Serialisable { It is the caller's responsibility to provide an appropriate type of data. */ - void set(const std::string &name, const void *value) final { + void set_raw(const std::string &name, const void *value) final { const auto iterator = contents_.find(name); if(iterator == contents_.end()) return; memcpy(reinterpret_cast(this) + iterator->second.offset, value, iterator->second.size);