diff --git a/Analyser/Static/Acorn/Target.hpp b/Analyser/Static/Acorn/Target.hpp index 31d3e93aa..7c312e1fd 100644 --- a/Analyser/Static/Acorn/Target.hpp +++ b/Analyser/Static/Acorn/Target.hpp @@ -17,7 +17,7 @@ namespace Analyser { namespace Static { namespace Acorn { -struct Target: public ::Analyser::Static::Target, public Reflection::Struct { +struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl { bool has_adfs = false; bool has_dfs = false; bool should_shift_restart = false; diff --git a/Analyser/Static/AmstradCPC/Target.hpp b/Analyser/Static/AmstradCPC/Target.hpp index bb35a034d..765b2f04f 100644 --- a/Analyser/Static/AmstradCPC/Target.hpp +++ b/Analyser/Static/AmstradCPC/Target.hpp @@ -18,7 +18,7 @@ namespace Analyser { namespace Static { namespace AmstradCPC { -struct Target: public ::Analyser::Static::Target, public Reflection::Struct { +struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl { ReflectableEnum(Model, CPC464, CPC664, CPC6128); Model model = Model::CPC464; std::string loading_command; diff --git a/Analyser/Static/AppleII/Target.hpp b/Analyser/Static/AppleII/Target.hpp index fb4409a47..e1a6141cc 100644 --- a/Analyser/Static/AppleII/Target.hpp +++ b/Analyser/Static/AppleII/Target.hpp @@ -17,7 +17,7 @@ namespace Analyser { namespace Static { namespace AppleII { -struct Target: public ::Analyser::Static::Target, public Reflection::Struct { +struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl { ReflectableEnum(Model, II, IIplus, diff --git a/Analyser/Static/Commodore/Target.hpp b/Analyser/Static/Commodore/Target.hpp index 8655da9cc..d207cf0bd 100644 --- a/Analyser/Static/Commodore/Target.hpp +++ b/Analyser/Static/Commodore/Target.hpp @@ -18,7 +18,7 @@ namespace Analyser { namespace Static { namespace Commodore { -struct Target: public ::Analyser::Static::Target, public Reflection::Struct { +struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl { enum class MemoryModel { Unexpanded, EightKB, diff --git a/Analyser/Static/MSX/Target.hpp b/Analyser/Static/MSX/Target.hpp index 685a3dc7a..f7c7ddbac 100644 --- a/Analyser/Static/MSX/Target.hpp +++ b/Analyser/Static/MSX/Target.hpp @@ -18,7 +18,7 @@ namespace Analyser { namespace Static { namespace MSX { -struct Target: public ::Analyser::Static::Target, public Reflection::Struct { +struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl { bool has_disk_drive = false; std::string loading_command; diff --git a/Analyser/Static/Macintosh/Target.hpp b/Analyser/Static/Macintosh/Target.hpp index e4a588d2e..9b8aab7e7 100644 --- a/Analyser/Static/Macintosh/Target.hpp +++ b/Analyser/Static/Macintosh/Target.hpp @@ -16,7 +16,7 @@ namespace Analyser { namespace Static { namespace Macintosh { -struct Target: public ::Analyser::Static::Target, public Reflection::Struct { +struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl { ReflectableEnum(Model, Mac128k, Mac512k, Mac512ke, MacPlus); Model model = Model::MacPlus; diff --git a/Analyser/Static/Oric/Target.hpp b/Analyser/Static/Oric/Target.hpp index 281c3b7f8..114b6a4a3 100644 --- a/Analyser/Static/Oric/Target.hpp +++ b/Analyser/Static/Oric/Target.hpp @@ -18,7 +18,7 @@ namespace Analyser { namespace Static { namespace Oric { -struct Target: public ::Analyser::Static::Target, public Reflection::Struct { +struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl { ReflectableEnum(ROM, BASIC10, BASIC11, diff --git a/Analyser/Static/ZX8081/Target.hpp b/Analyser/Static/ZX8081/Target.hpp index e3c100d61..b85e2cce8 100644 --- a/Analyser/Static/ZX8081/Target.hpp +++ b/Analyser/Static/ZX8081/Target.hpp @@ -18,7 +18,7 @@ namespace Analyser { namespace Static { namespace ZX8081 { -struct Target: public ::Analyser::Static::Target, public Reflection::Struct { +struct Target: public ::Analyser::Static::Target, public Reflection::StructImpl { ReflectableEnum(MemoryModel, Unexpanded, SixteenKB, diff --git a/Machines/Utility/MachineForTarget.cpp b/Machines/Utility/MachineForTarget.cpp index ece5a9f02..721ea68e8 100644 --- a/Machines/Utility/MachineForTarget.cpp +++ b/Machines/Utility/MachineForTarget.cpp @@ -8,6 +8,7 @@ #include "MachineForTarget.hpp" +// Sources for runtime options. #include "../AmstradCPC/AmstradCPC.hpp" #include "../Apple/AppleII/AppleII.hpp" #include "../Apple/Macintosh/Macintosh.hpp" @@ -21,6 +22,17 @@ #include "../Oric/Oric.hpp" #include "../ZX8081/ZX8081.hpp" +// Sources for construction options. +#include "../../Analyser/Static/Acorn/Target.hpp" +#include "../../Analyser/Static/AmstradCPC/Target.hpp" +#include "../../Analyser/Static/AppleII/Target.hpp" +#include "../../Analyser/Static/AtariST/Target.hpp" +#include "../../Analyser/Static/Commodore/Target.hpp" +#include "../../Analyser/Static/Macintosh/Target.hpp" +#include "../../Analyser/Static/MSX/Target.hpp" +#include "../../Analyser/Static/Oric/Target.hpp" +#include "../../Analyser/Static/ZX8081/Target.hpp" + #include "../../Analyser/Dynamic/MultiMachine/MultiMachine.hpp" #include "TypedDynamicMachine.hpp" @@ -155,3 +167,23 @@ std::map>> Machin return options; } + +std::map> Machine::ConstructionOptionsByMachineName() { + std::map> options; + +#define Add(Name) \ + options.emplace(std::make_pair(LongNameForTargetMachine(Analyser::Machine::Name), new Analyser::Static::Name::Target)); + + Add(AmstradCPC); + Add(AppleII); +// Add(AtariST); +// Add(Electron); +// options.emplace(std::make_pair(LongNameForTargetMachine(Analyser::Machine::Electron), Electron::get_options())); +// options.emplace(std::make_pair(LongNameForTargetMachine(Analyser::Machine::Macintosh), Apple::Macintosh::get_options())); + Add(MSX); + Add(Oric); +// options.emplace(std::make_pair(LongNameForTargetMachine(Analyser::Machine::Vic20), Commodore::Vic20::get_options())); + Add(ZX8081); + + return options; +} diff --git a/Machines/Utility/MachineForTarget.hpp b/Machines/Utility/MachineForTarget.hpp index 0b156c7c7..6cc29bcae 100644 --- a/Machines/Utility/MachineForTarget.hpp +++ b/Machines/Utility/MachineForTarget.hpp @@ -10,10 +10,12 @@ #define MachineForTarget_hpp #include "../../Analyser/Static/StaticAnalyser.hpp" +#include "../../Reflection/Struct.h" #include "../DynamicMachine.hpp" #include +#include #include #include @@ -53,6 +55,8 @@ std::string LongNameForTargetMachine(const Analyser::Machine target); */ std::map>> AllOptionsByMachineName(); +std::map> ConstructionOptionsByMachineName(); + } #endif /* MachineForTarget_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal Kiosk.xcscheme b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal Kiosk.xcscheme index f84023923..5a6721911 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal Kiosk.xcscheme +++ b/OSBindings/Mac/Clock Signal.xcodeproj/xcshareddata/xcschemes/Clock Signal Kiosk.xcscheme @@ -31,7 +31,7 @@ + isEnabled = "NO"> + + diff --git a/OSBindings/SDL/main.cpp b/OSBindings/SDL/main.cpp index 13a566feb..04a898a83 100644 --- a/OSBindings/SDL/main.cpp +++ b/OSBindings/SDL/main.cpp @@ -34,6 +34,9 @@ #include "../../Outputs/OpenGL/ScanTarget.hpp" #include "../../Outputs/OpenGL/Screenshot.hpp" +#include "../../Reflection/Enum.h" +#include "../../Reflection/Struct.h" + namespace { struct MachineRunner { @@ -478,7 +481,7 @@ int main(int argc, char *argv[]) { std::cout << "Use alt+enter to toggle full screen display. Use control+shift+V to paste text." << std::endl; std::cout << "Required machine type and configuration is determined from the file. Machines with further options:" << std::endl << std::endl; - auto all_options = Machine::AllOptionsByMachineName(); + const auto all_options = Machine::AllOptionsByMachineName(); for(const auto &machine_options: all_options) { std::cout << machine_options.first << ":" << std::endl; for(const auto &option: machine_options.second) { @@ -499,6 +502,32 @@ int main(int argc, char *argv[]) { } std::cout << std::endl; } + + const auto construction_options = Machine::ConstructionOptionsByMachineName(); + for(const auto &options: construction_options) { + std::cout << options.first << ":" << std::endl; + for(const auto &option: options.second->all_keys()) { + std::cout << '\t' << "--" << option; + const auto type = options.second->type_of(option); + + // Is this a registered enum? If so, list options. + if(!Reflection::Enum::name(*type).empty()) { + std::cout << "={"; + bool is_first = true; + for(const auto &value: Reflection::Enum::all_values(*type)) { + if(!is_first) std::cout << '|'; + is_first = false; + std::cout << value; + } + std::cout << "}"; + } + + // TODO: if not a registered enum... then assume it was a Boolean? + std::cout << std::endl; + } + + std::cout << std::endl; + } return EXIT_SUCCESS; } diff --git a/Reflection/Enum.h b/Reflection/Enum.h index 0a9e86a9c..85e38b7c9 100644 --- a/Reflection/Enum.h +++ b/Reflection/Enum.h @@ -72,19 +72,20 @@ class Enum { } members_by_type_.emplace(std::make_pair(&typeid(Type), result)); + names_by_type_.emplace(std::make_pair(&typeid(Type), std::string(name))); } /*! @returns the declared name of the enum @c Type if it has been registered; the empty string otherwise. */ - template const std::string &name() { + template static 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) { + static 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; @@ -93,14 +94,14 @@ class Enum { /*! @returns the number of members of the enum @c Type if it has been registered; 0 otherwise. */ - template size_t size() { + template static 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) { + static size_t size(const std::type_info &type) { const auto entry = members_by_type_.find(&type); if(entry == members_by_type_.end()) return std::string::npos; return entry->second.size(); @@ -109,32 +110,48 @@ class Enum { /*! @returns A @c std::string name for the enum value @c e. */ - template static const std::string &toString(Type e) { - return toString(typeid(Type), size_t(e)); + template static const std::string &to_string(Type e) { + return to_string(typeid(Type), size_t(e)); } /*! @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) { + static const std::string &to_string(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 vector naming the members of the enum with type_info @c type if it has been registered; an empty vector otherwise. + */ + static const std::vector &all_values(const std::type_info &type) { + const auto entry = members_by_type_.find(&type); + if(entry == members_by_type_.end()) return empty_vector_; + return entry->second; + } + + /*! + @returns a vector naming the members of the enum @c Type type if it has been registered; an empty vector otherwise. + */ + template static const std::vector &all_values() { + return all_values(typeid(Type)); + } + /*! @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)); + template static Type from_string(const std::string &str) { + return Type(from_string(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) { + static size_t from_string(const std::type_info &type, const std::string &str) { const auto entry = members_by_type_.find(&type); if(entry == members_by_type_.end()) return std::string::npos; const auto iterator = std::find(entry->second.begin(), entry->second.end(), str); @@ -146,6 +163,7 @@ class Enum { static inline std::unordered_map> members_by_type_; static inline std::unordered_map names_by_type_; static inline const std::string empty_string_; + static inline const std::vector empty_vector_; }; } diff --git a/Reflection/Struct.h b/Reflection/Struct.h index 1d434781c..86772b010 100644 --- a/Reflection/Struct.h +++ b/Reflection/Struct.h @@ -19,16 +19,24 @@ namespace Reflection { #define DeclareField(Name) declare(&Name, #Name) -template class Struct { +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 ~Struct() {} +}; + +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. */ - template const Type *get(const std::string &name) { + const void *get(const std::string &name) final { const auto iterator = contents_.find(name); if(iterator == contents_.end()) return nullptr; - return reinterpret_cast(reinterpret_cast(this) + iterator->second.offset); + return reinterpret_cast(this) + iterator->second.offset; } /*! @@ -36,16 +44,16 @@ template class Struct { It is the caller's responsibility to provide an appropriate type of data. */ - template void set(const std::string &name, const Type &value) { + void set(const std::string &name, const void *value) final { const auto iterator = contents_.find(name); if(iterator == contents_.end()) return; - *reinterpret_cast(reinterpret_cast(this) + iterator->second.offset) = value; + memcpy(reinterpret_cast(this) + iterator->second.offset, value, iterator->second.size); } /*! @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) final { const auto iterator = contents_.find(name); if(iterator == contents_.end()) return nullptr; return iterator->second.type; @@ -54,7 +62,7 @@ template class Struct { /*! @returns A vector of all declared fields for this struct. */ - std::vector all_keys() { + std::vector all_keys() final { std::vector keys; for(const auto &pair: contents_) { keys.push_back(pair.first); @@ -82,7 +90,7 @@ template class Struct { contents_.emplace( std::make_pair( name, - Field(typeid(Type), reinterpret_cast(t) - reinterpret_cast(this)) + Field(typeid(Type), reinterpret_cast(t) - reinterpret_cast(this), sizeof(Type)) )); } @@ -96,9 +104,9 @@ template class Struct { private: struct Field { const std::type_info *type; - ssize_t offset; - Field(const std::type_info &type, ssize_t offset) : - type(&type), offset(offset) {} + ssize_t offset, size; + Field(const std::type_info &type, ssize_t offset, size_t size) : + type(&type), offset(offset), size(size) {} }; static inline std::unordered_map contents_; };