diff --git a/Reflection/Struct.cpp b/Reflection/Struct.cpp index 2a2d80736..c3b676805 100644 --- a/Reflection/Struct.cpp +++ b/Reflection/Struct.cpp @@ -110,13 +110,13 @@ bool Reflection::fuzzy_set(Struct &target, const std::string &name, const std::s // MARK: - Getters -template bool Reflection::get(const Struct &target, const std::string &name, Type &value) { +template bool Reflection::get(const Struct &target, const std::string &name, Type &value, size_t offset) { const auto target_type = target.type_of(name); if(!target_type) return false; // If type is a direct match, copy. if(*target_type == typeid(Type)) { - memcpy(&value, target.get(name), sizeof(Type)); + memcpy(&value, reinterpret_cast(target.get(name)) + offset * sizeof(Type), sizeof(Type)); return true; } @@ -131,14 +131,58 @@ template bool Reflection::get(const Struct &target, const std::s return false; } -template Type Reflection::get(const Struct &target, const std::string &name) { +template Type Reflection::get(const Struct &target, const std::string &name, size_t offset) { Type value{}; - get(target, name, value); + get(target, name, value, offset); return value; } // MARK: - Description +void Reflection::Struct::append(std::ostringstream &stream, const std::string &key, const std::type_info *const type, size_t offset) const { + // Output Bools as yes/no. + if(*type == typeid(bool)) { + stream << ::Reflection::get(*this, key, offset); + return; + } + + // Output Ints of all sizes as hex. +#define OutputIntC(int_type, cast_type) if(*type == typeid(int_type)) { stream << std::setfill('0') << std::setw(sizeof(int_type)*2) << std::hex << cast_type(::Reflection::get(*this, key, offset)); return; } +#define OutputInt(int_type) OutputIntC(int_type, int_type) + OutputIntC(int8_t, int16_t); + OutputIntC(uint8_t, uint16_t); + OutputInt(int16_t); + OutputInt(uint16_t); + OutputInt(int32_t); + OutputInt(uint32_t); + OutputInt(int64_t); + OutputInt(uint64_t); +#undef OutputInt +#undef OutputIntC + + // Output floats and strings natively. +#define OutputNative(val_type) if(*type == typeid(val_type)) { stream << ::Reflection::get(*this, key, offset); return; } + OutputNative(float); + OutputNative(double); + OutputNative(char *); + OutputNative(std::string); +#undef OutputNative + + // Output the current value of any enums. + if(!Enum::name(*type).empty()) { + const int value = ::Reflection::get(*this, key, offset); + stream << Enum::to_string(*type, value); + return; + } + + // Recurse to deal with embedded objects. + if(*type == typeid(Reflection::Struct)) { + const Reflection::Struct *const child = reinterpret_cast(get(key)); + stream << child->description(); + return; + } +} + std::string Reflection::Struct::description() const { std::ostringstream stream; @@ -150,47 +194,20 @@ std::string Reflection::Struct::description() const { is_first = false; stream << key << ": "; + const auto count = count_of(key); const auto type = type_of(key); - // Output Bools as yes/no. - if(*type == typeid(bool)) { - stream << ::Reflection::get(*this, key); - continue; + if(count != 1) { + stream << "["; } - // Output Ints of all sizes as hex. -#define OutputIntC(int_type, cast_type) if(*type == typeid(int_type)) { stream << std::setfill('0') << std::setw(sizeof(int_type)*2) << std::hex << cast_type(::Reflection::get(*this, key)); continue; } -#define OutputInt(int_type) OutputIntC(int_type, int_type) - OutputIntC(int8_t, int16_t); - OutputIntC(uint8_t, uint16_t); - OutputInt(int16_t); - OutputInt(uint16_t); - OutputInt(int32_t); - OutputInt(uint32_t); - OutputInt(int64_t); - OutputInt(uint64_t); -#undef OutputInt - - // Output floats and strings natively. -#define OutputNative(val_type) if(*type == typeid(val_type)) { stream << ::Reflection::get(*this, key); continue; } - OutputNative(float); - OutputNative(double); - OutputNative(char *); - OutputNative(std::string); -#undef OutputNAtive - - // Output the current value of any enums. - if(!Enum::name(*type).empty()) { - const int value = ::Reflection::get(*this, key); - stream << Enum::to_string(*type, value); - continue; + for(size_t index = 0; index < count; ++index) { + append(stream, key, type, index); + if(index != count-1) stream << ", "; } - // Recurse to deal with embedded objects. - if(*type == typeid(Reflection::Struct)) { - const Reflection::Struct *const child = reinterpret_cast(get(key)); - stream << child->description(); - continue; + if(count != 1) { + stream << "]"; } } diff --git a/Reflection/Struct.hpp b/Reflection/Struct.hpp index 1e4e01c3d..833fe8d76 100644 --- a/Reflection/Struct.hpp +++ b/Reflection/Struct.hpp @@ -38,6 +38,9 @@ struct Struct { sufficiently formed for a formal language parser, etc. */ std::string description() const; + + private: + void append(std::ostringstream &stream, const std::string &key, const std::type_info *type, size_t offset) const; }; /*! @@ -94,14 +97,14 @@ bool fuzzy_set(Struct &target, const std::string &name, const std::string &value @returns @c true if the property was successfully read; @c false otherwise. */ -template bool get(const Struct &target, const std::string &name, Type &value); +template bool get(const Struct &target, const std::string &name, Type &value, size_t offset = 0); /*! Attempts to get the property @c name to @c value ; will perform limited type conversions. @returns @c true if the property was successfully read; a default-constructed instance of Type otherwise. */ -template Type get(const Struct &target, const std::string &name); +template Type get(const Struct &target, const std::string &name, size_t offset = 0); // TODO: move this elsewhere. It's just a sketch anyway. @@ -225,7 +228,7 @@ template class StructImpl: public Struct { // If the declared item is an array, record it as a pointer to the // first element plus a size. if constexpr (std::is_array()) { - declare_emplace(&t[0], name, sizeof(*t) / sizeof(*t[0])); + declare_emplace(&(*t)[0], name, sizeof(*t) / sizeof(*t[0])); return; }