add StructLayout::convert (WIP)

This commit is contained in:
MihailRis 2024-08-30 06:16:41 +03:00
parent 5afbad1bd6
commit caa5e1b03b
3 changed files with 64 additions and 18 deletions

View File

@ -2,7 +2,6 @@
#include <cstring>
#include <string.h>
#include <stdexcept>
#include <algorithm>
#include "util/data_io.hpp"
@ -36,6 +35,35 @@ StructLayout StructLayout::create(const std::vector<Field>& 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");

View File

@ -2,6 +2,7 @@
#include <vector>
#include <string>
#include <stdexcept>
#include <unordered_map>
#include "typedefs.hpp"
@ -19,6 +20,11 @@ namespace data {
return sizes[static_cast<int>(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<Field>& fields);
};
class StructAccess {
const StructLayout& mapping;
uint8_t* buffer;
public:
StructAccess(const StructLayout& mapping, uint8_t* buffer)
: mapping(mapping), buffer(buffer) {
}
};
}

View File

@ -39,3 +39,7 @@ TEST(StructLayout, Unicode) {
layout.setUnicode(buffer, u8"пример", "text");
EXPECT_EQ(layout.getChars(buffer, "text"), std::string(u8"пр"));
}
TEST(StructLayout, Convert) {
}