add StructMapping::setUnicode
This commit is contained in:
parent
4343e81e00
commit
77229b8d9a
@ -1,10 +1,12 @@
|
|||||||
#include "StructMapper.hpp"
|
#include "StructMapper.hpp"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <string.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "util/data_io.hpp"
|
#include "util/data_io.hpp"
|
||||||
|
#include "util/stringutil.hpp"
|
||||||
|
|
||||||
using namespace data;
|
using namespace data;
|
||||||
|
|
||||||
@ -55,7 +57,7 @@ void StructMapping::setInteger(
|
|||||||
) {
|
) {
|
||||||
const auto& field = requreField(name);
|
const auto& field = requreField(name);
|
||||||
if (index < 0 || index >= field.elements) {
|
if (index < 0 || index >= field.elements) {
|
||||||
throw std::runtime_error(
|
throw std::out_of_range(
|
||||||
"index out of bounds [0, "+std::to_string(field.elements)+"]");
|
"index out of bounds [0, "+std::to_string(field.elements)+"]");
|
||||||
}
|
}
|
||||||
auto ptr = dst + field.offset + index * sizeof_type(field.type);
|
auto ptr = dst + field.offset + index * sizeof_type(field.type);
|
||||||
@ -79,7 +81,7 @@ void StructMapping::setNumber(
|
|||||||
) {
|
) {
|
||||||
const auto& field = requreField(name);
|
const auto& field = requreField(name);
|
||||||
if (index < 0 || index >= field.elements) {
|
if (index < 0 || index >= field.elements) {
|
||||||
throw std::runtime_error(
|
throw std::out_of_range(
|
||||||
"index out of bounds [0, "+std::to_string(field.elements)+"]");
|
"index out of bounds [0, "+std::to_string(field.elements)+"]");
|
||||||
}
|
}
|
||||||
auto ptr = dst + field.offset + index * sizeof_type(field.type);
|
auto ptr = dst + field.offset + index * sizeof_type(field.type);
|
||||||
@ -103,7 +105,7 @@ void StructMapping::setNumber(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StructMapping::setChars(
|
size_t StructMapping::setChars(
|
||||||
ubyte* dst, std::string_view value, const std::string& name
|
ubyte* dst, std::string_view value, const std::string& name
|
||||||
) {
|
) {
|
||||||
const auto& field = requreField(name);
|
const auto& field = requreField(name);
|
||||||
@ -111,8 +113,23 @@ void StructMapping::setChars(
|
|||||||
throw std::runtime_error("'char' field type required");
|
throw std::runtime_error("'char' field type required");
|
||||||
}
|
}
|
||||||
auto ptr = reinterpret_cast<char*>(dst + field.offset);
|
auto ptr = reinterpret_cast<char*>(dst + field.offset);
|
||||||
std::memcpy(ptr, value.data(),
|
auto size = std::min(value.size(), static_cast<std::size_t>(field.elements));
|
||||||
std::min(value.size(), static_cast<std::size_t>(field.elements)));
|
std::memcpy(ptr, value.data(), size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t StructMapping::setUnicode(
|
||||||
|
ubyte* dst, std::string_view value, const std::string& name
|
||||||
|
) {
|
||||||
|
const auto& field = requreField(name);
|
||||||
|
if (field.type != FieldType::CHAR) {
|
||||||
|
throw std::runtime_error("'char' field type required");
|
||||||
|
}
|
||||||
|
auto text = std::string_view(value.data(), value.size());
|
||||||
|
size_t size = util::crop_utf8(text, field.elements);
|
||||||
|
auto ptr = reinterpret_cast<char*>(dst + field.offset);
|
||||||
|
std::memcpy(ptr, value.data(), size);
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@ -125,7 +142,7 @@ integer_t StructMapping::getInteger(
|
|||||||
) const {
|
) const {
|
||||||
const auto& field = requreField(name);
|
const auto& field = requreField(name);
|
||||||
if (index < 0 || index >= field.elements) {
|
if (index < 0 || index >= field.elements) {
|
||||||
throw std::runtime_error(
|
throw std::out_of_range(
|
||||||
"index out of bounds [0, "+std::to_string(field.elements)+"]");
|
"index out of bounds [0, "+std::to_string(field.elements)+"]");
|
||||||
}
|
}
|
||||||
auto ptr = src + field.offset + index * sizeof_type(field.type);
|
auto ptr = src + field.offset + index * sizeof_type(field.type);
|
||||||
@ -145,7 +162,7 @@ number_t StructMapping::getNumber(
|
|||||||
) const {
|
) const {
|
||||||
const auto& field = requreField(name);
|
const auto& field = requreField(name);
|
||||||
if (index < 0 || index >= field.elements) {
|
if (index < 0 || index >= field.elements) {
|
||||||
throw std::runtime_error(
|
throw std::out_of_range(
|
||||||
"index out of bounds [0, "+std::to_string(field.elements)+"]");
|
"index out of bounds [0, "+std::to_string(field.elements)+"]");
|
||||||
}
|
}
|
||||||
auto ptr = src + field.offset + index * sizeof_type(field.type);
|
auto ptr = src + field.offset + index * sizeof_type(field.type);
|
||||||
@ -180,6 +197,6 @@ std::string_view StructMapping::getChars(
|
|||||||
if (field.type != FieldType::CHAR) {
|
if (field.type != FieldType::CHAR) {
|
||||||
throw std::runtime_error("'char' field type required");
|
throw std::runtime_error("'char' field type required");
|
||||||
}
|
}
|
||||||
auto ptr = src + field.offset;
|
auto ptr = reinterpret_cast<const char*>(src + field.offset);
|
||||||
return std::string_view(reinterpret_cast<const char*>(ptr), field.elements);
|
return std::string_view(ptr, strnlen(ptr, field.elements));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,6 +44,9 @@ namespace data {
|
|||||||
indices(std::move(indices))
|
indices(std::move(indices))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
/// @brief Get field by name. Returns nullptr if field not found.
|
||||||
|
/// @param name field name
|
||||||
|
/// @return nullable field pointer
|
||||||
const Field* getField(const std::string& name) const {
|
const Field* getField(const std::string& name) const {
|
||||||
auto found = indices.find(name);
|
auto found = indices.find(name);
|
||||||
if (found == indices.end()) {
|
if (found == indices.end()) {
|
||||||
@ -53,16 +56,78 @@ namespace data {
|
|||||||
return &fields.at(found->second);
|
return &fields.at(found->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Get field by name
|
||||||
|
/// @throws std::runtime_exception - field not found
|
||||||
|
/// @param name field name
|
||||||
|
/// @return read-only field reference
|
||||||
const Field& requreField(const std::string& name) const;
|
const Field& requreField(const std::string& name) const;
|
||||||
|
|
||||||
|
/// @brief Get integer from specified field.
|
||||||
|
/// Types: (i8, i16, i32, i64, char)
|
||||||
|
/// @throws std::runtime_exception - field not found
|
||||||
|
/// @throws std::out_of_range - index is out of range [0, elements-1]
|
||||||
|
/// @param src source buffer
|
||||||
|
/// @param name field name
|
||||||
|
/// @param index array index
|
||||||
|
/// @return field value
|
||||||
|
[[nodiscard]]
|
||||||
integer_t getInteger(const ubyte* src, const std::string& name, int index=0) const;
|
integer_t getInteger(const ubyte* src, const std::string& name, int index=0) const;
|
||||||
|
|
||||||
|
/// @brief Get floating-point number from specified field.
|
||||||
|
/// Types: (f32, f64, i8, i16, i32, i64, char)
|
||||||
|
/// @throws std::runtime_exception - field not found
|
||||||
|
/// @throws std::out_of_range - index is out of range [0, elements-1]
|
||||||
|
/// @param src source buffer
|
||||||
|
/// @param name field name
|
||||||
|
/// @param index array index
|
||||||
|
/// @return field value
|
||||||
|
[[nodiscard]]
|
||||||
number_t getNumber(const ubyte* src, const std::string& name, int index=0) const;
|
number_t getNumber(const ubyte* src, const std::string& name, int index=0) const;
|
||||||
|
|
||||||
|
/// @brief Get read-only chars array as string_view.
|
||||||
|
/// @param src source buffer
|
||||||
|
/// @param name field name
|
||||||
|
[[nodiscard]]
|
||||||
std::string_view getChars(const ubyte* src, const std::string& name) const;
|
std::string_view getChars(const ubyte* src, const std::string& name) const;
|
||||||
|
|
||||||
|
/// @brief Set field integer value.
|
||||||
|
/// Types: (i8, i16, i32, i64, f32, f64, char)
|
||||||
|
/// @throws std::runtime_exception - field not found
|
||||||
|
/// @throws std::out_of_range - index is out of range [0, elements-1]
|
||||||
|
/// @param dst destination buffer
|
||||||
|
/// @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);
|
||||||
void setNumber(ubyte* dst, number_t value, const std::string& name, int index=0);
|
|
||||||
void setChars(ubyte* dst, std::string_view value, const std::string& name);
|
|
||||||
|
|
||||||
|
/// @brief Set field numeric value.
|
||||||
|
/// Types: (f32, f64)
|
||||||
|
/// @throws std::runtime_exception - field not found
|
||||||
|
/// @throws std::out_of_range - index is out of range [0, elements-1]
|
||||||
|
/// @param dst destination buffer
|
||||||
|
/// @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);
|
||||||
|
|
||||||
|
/// @brief Replace chars array to given ASCII string
|
||||||
|
/// @throws std::runtime_exception - field not found
|
||||||
|
/// @see StructMapper::setUnicode - utf-8 version of setChars
|
||||||
|
/// @param dst destination buffer
|
||||||
|
/// @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);
|
||||||
|
|
||||||
|
/// @brief Unicode-safe version of setChars
|
||||||
|
/// @throws std::runtime_exception - field not found
|
||||||
|
/// @param dst destination buffer
|
||||||
|
/// @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);
|
||||||
|
|
||||||
|
/// @return total structure size (bytes)
|
||||||
int size() const {
|
int size() const {
|
||||||
return totalSize;
|
return totalSize;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,3 +24,18 @@ TEST(StructMapper, ReadWrite) {
|
|||||||
mapping.setChars(buffer, "hello", "s");
|
mapping.setChars(buffer, "hello", "s");
|
||||||
EXPECT_EQ(mapping.getChars(buffer, "s"), "hell");
|
EXPECT_EQ(mapping.getChars(buffer, "s"), "hell");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(StructMapper, Unicode) {
|
||||||
|
ubyte buffer[8] {};
|
||||||
|
std::vector<Field> fields {
|
||||||
|
Field {FieldType::CHAR, "text", 5},
|
||||||
|
};
|
||||||
|
auto mapping = StructMapping::create(fields);
|
||||||
|
EXPECT_EQ(mapping.size(), 5);
|
||||||
|
|
||||||
|
mapping.setUnicode(buffer, u8"テキストデモ", "text");
|
||||||
|
EXPECT_EQ(mapping.getChars(buffer, "text"), std::string(u8"テ"));
|
||||||
|
|
||||||
|
mapping.setUnicode(buffer, u8"пример", "text");
|
||||||
|
EXPECT_EQ(mapping.getChars(buffer, "text"), std::string(u8"пр"));
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user