diff --git a/src/data/StructLayout.cpp b/src/data/StructLayout.cpp index 8fe3682a..3cf30a4f 100644 --- a/src/data/StructLayout.cpp +++ b/src/data/StructLayout.cpp @@ -2,7 +2,6 @@ #include #include -#include #include #include "util/data_io.hpp" @@ -36,6 +35,35 @@ StructLayout StructLayout::create(const std::vector& fields) { offset, std::move(builtFields), std::move(indices)); } +static inline constexpr bool is_integer_type(FieldType type) { + return (type >= FieldType::I8 && type <= FieldType::I64) || + type == FieldType::CHAR; +} + +static inline constexpr bool is_floating_point_type(FieldType type) { + return type == FieldType::F32 || type == FieldType::F64; +} + +static inline constexpr bool is_numeric_type(FieldType type) { + return is_floating_point_type(type) || is_integer_type(type); +} + +void StructLayout::convert( + const StructLayout& srcLayout, + const ubyte* src, + ubyte* dst, + bool allowDataLoss +) const { + for (const Field& field : fields) { + auto srcField = srcLayout.getField(field.name); + if (srcField == nullptr) { + std::memset(dst + field.offset, 0, field.size); + continue; + } + // TODO: implement + } +} + const Field& StructLayout::requreField(const std::string& name) const { auto found = indices.find(name); if (found == indices.end()) { @@ -54,7 +82,7 @@ static void set_int(ubyte* dst, integer_t value) { void StructLayout::setInteger( ubyte* dst, integer_t value, const std::string& name, int index -) { +) const { const auto& field = requreField(name); if (index < 0 || index >= field.elements) { throw std::out_of_range( @@ -78,7 +106,7 @@ void StructLayout::setInteger( void StructLayout::setNumber( ubyte* dst, number_t value, const std::string& name, int index -) { +) const { const auto& field = requreField(name); if (index < 0 || index >= field.elements) { throw std::out_of_range( @@ -107,7 +135,7 @@ void StructLayout::setNumber( size_t StructLayout::setChars( ubyte* dst, std::string_view value, const std::string& name -) { +) const { const auto& field = requreField(name); if (field.type != FieldType::CHAR) { throw std::runtime_error("'char' field type required"); @@ -120,7 +148,7 @@ size_t StructLayout::setChars( size_t StructLayout::setUnicode( ubyte* dst, std::string_view value, const std::string& name -) { +) const { const auto& field = requreField(name); if (field.type != FieldType::CHAR) { throw std::runtime_error("'char' field type required"); diff --git a/src/data/StructLayout.hpp b/src/data/StructLayout.hpp index 22d255ab..e3f819af 100644 --- a/src/data/StructLayout.hpp +++ b/src/data/StructLayout.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include "typedefs.hpp" @@ -19,6 +20,11 @@ namespace data { return sizes[static_cast(type)]; } + class dataloss_error : public std::runtime_error { + public: + dataloss_error(const std::string& message) : std::runtime_error(message) {} + }; + struct Field { FieldType type; std::string name; @@ -99,7 +105,7 @@ namespace data { /// @param value value /// @param name field name /// @param index array index - void setInteger(ubyte* dst, integer_t value, const std::string& name, int index=0); + void setInteger(ubyte* dst, integer_t value, const std::string& name, int index=0) const; /// @brief Set field numeric value. /// Types: (f32, f64) @@ -109,7 +115,7 @@ namespace data { /// @param value value /// @param name field name /// @param index array index - void setNumber(ubyte* dst, number_t value, const std::string& name, int index=0); + void setNumber(ubyte* dst, number_t value, const std::string& name, int index=0) const; /// @brief Replace chars array to given ASCII string /// @throws std::runtime_exception - field not found @@ -118,7 +124,7 @@ namespace data { /// @param value ASCII string /// @param name field name /// @return number of written string chars - size_t setChars(ubyte* dst, std::string_view value, const std::string& name); + size_t setChars(ubyte* dst, std::string_view value, const std::string& name) const; /// @brief Unicode-safe version of setChars /// @throws std::runtime_exception - field not found @@ -126,23 +132,31 @@ namespace data { /// @param value utf-8 string /// @param name field name /// @return number of written string chars - size_t setUnicode(ubyte* dst, std::string_view value, const std::string& name); + size_t setUnicode(ubyte* dst, std::string_view value, const std::string& name) const; /// @return total structure size (bytes) [[nodiscard]] size_t size() const { return totalSize; } + /// @brief Convert structure data from srcLayout to this layout. + /// @param srcLayout source structure layout + /// @param src source data + /// @param dst destination buffer + /// (size must be enough to store converted structure) + /// @param allowDataLoss allow to drop fields that are not present in + /// this layout or have incompatible types + /// @throws data::dataloss_error - data loss detected and allowDataLoss + /// is set to false + void convert( + const StructLayout& srcLayout, + const ubyte* src, + ubyte* dst, + bool allowDataLoss) const; + + /// TODO: add checkCompatibility method + [[nodiscard]] static StructLayout create(const std::vector& fields); }; - - class StructAccess { - const StructLayout& mapping; - uint8_t* buffer; - public: - StructAccess(const StructLayout& mapping, uint8_t* buffer) - : mapping(mapping), buffer(buffer) { - } - }; } diff --git a/test/data/StructLayout.cpp b/test/data/StructLayout.cpp index c948d030..ae5ea1d3 100644 --- a/test/data/StructLayout.cpp +++ b/test/data/StructLayout.cpp @@ -39,3 +39,7 @@ TEST(StructLayout, Unicode) { layout.setUnicode(buffer, u8"пример", "text"); EXPECT_EQ(layout.getChars(buffer, "text"), std::string(u8"пр")); } + +TEST(StructLayout, Convert) { + +}