From 0b3bb36188bc6bffdfaafacafaa81e31eac65125 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Wed, 4 Sep 2024 15:41:51 +0300 Subject: [PATCH] update byte_utils --- src/coders/byte_utils.cpp | 90 ++++++++++++++++---------------------- src/coders/byte_utils.hpp | 26 +++++------ src/util/Buffer.hpp | 2 +- src/util/data_io.hpp | 18 ++++++++ test/coders/byte_utils.cpp | 20 +++++++++ 5 files changed, 88 insertions(+), 68 deletions(-) create mode 100644 test/coders/byte_utils.cpp diff --git a/src/coders/byte_utils.cpp b/src/coders/byte_utils.cpp index d28e31ce..50c08563 100644 --- a/src/coders/byte_utils.cpp +++ b/src/coders/byte_utils.cpp @@ -4,6 +4,8 @@ #include #include +#include "util/data_io.hpp" + void ByteBuilder::put(ubyte b) { buffer.push_back(b); } @@ -30,28 +32,24 @@ void ByteBuilder::put(const ubyte* arr, size_t size) { } void ByteBuilder::putInt16(int16_t val) { - buffer.push_back(static_cast(val >> 0 & 255)); - buffer.push_back(static_cast(val >> 8 & 255)); + size_t size = buffer.size(); + buffer.resize(buffer.size() + sizeof(int16_t)); + val = dataio::h2le(val); + std::memcpy(buffer.data()+size, &val, sizeof(int16_t)); } void ByteBuilder::putInt32(int32_t val) { - buffer.reserve(buffer.size() + 4); - buffer.push_back(static_cast(val >> 0 & 255)); - buffer.push_back(static_cast(val >> 8 & 255)); - buffer.push_back(static_cast(val >> 16 & 255)); - buffer.push_back(static_cast(val >> 24 & 255)); + size_t size = buffer.size(); + buffer.resize(buffer.size() + sizeof(int32_t)); + val = dataio::h2le(val); + std::memcpy(buffer.data()+size, &val, sizeof(int32_t)); } void ByteBuilder::putInt64(int64_t val) { - buffer.reserve(buffer.size() + 8); - buffer.push_back(static_cast(val >> 0 & 255)); - buffer.push_back(static_cast(val >> 8 & 255)); - buffer.push_back(static_cast(val >> 16 & 255)); - buffer.push_back(static_cast(val >> 24 & 255)); - buffer.push_back(static_cast(val >> 32 & 255)); - buffer.push_back(static_cast(val >> 40 & 255)); - buffer.push_back(static_cast(val >> 48 & 255)); - buffer.push_back(static_cast(val >> 56 & 255)); + size_t size = buffer.size(); + buffer.resize(buffer.size() + sizeof(int64_t)); + val = dataio::h2le(val); + std::memcpy(buffer.data()+size, &val, sizeof(int64_t)); } void ByteBuilder::putFloat32(float val) { @@ -71,27 +69,18 @@ void ByteBuilder::set(size_t position, ubyte val) { } void ByteBuilder::setInt16(size_t position, int16_t val) { - buffer[position++] = val >> 0 & 255; - buffer[position] = val >> 8 & 255; + val = dataio::h2le(val); + std::memcpy(buffer.data()+position, &val, sizeof(int16_t)); } void ByteBuilder::setInt32(size_t position, int32_t val) { - buffer[position++] = val >> 0 & 255; - buffer[position++] = val >> 8 & 255; - buffer[position++] = val >> 16 & 255; - buffer[position] = val >> 24 & 255; + val = dataio::h2le(val); + std::memcpy(buffer.data()+position, &val, sizeof(int32_t)); } void ByteBuilder::setInt64(size_t position, int64_t val) { - buffer[position++] = val >> 0 & 255; - buffer[position++] = val >> 8 & 255; - buffer[position++] = val >> 16 & 255; - buffer[position++] = val >> 24 & 255; - - buffer[position++] = val >> 32 & 255; - buffer[position++] = val >> 40 & 255; - buffer[position++] = val >> 48 & 255; - buffer[position] = val >> 56 & 255; + val = dataio::h2le(val); + std::memcpy(buffer.data()+position, &val, sizeof(int64_t)); } std::vector ByteBuilder::build() { @@ -111,7 +100,7 @@ void ByteReader::checkMagic(const char* data, size_t size) { throw std::runtime_error("invalid magic number"); } for (size_t i = 0; i < size; i++) { - if (this->data[pos + i] != (ubyte)data[i]) { + if (this->data[pos + i] != static_cast(data[i])) { throw std::runtime_error("invalid magic number"); } } @@ -133,38 +122,33 @@ ubyte ByteReader::peek() { } int16_t ByteReader::getInt16() { - if (pos + 2 > size) { + if (pos + sizeof(int16_t) > size) { throw std::runtime_error("buffer underflow"); } - pos += 2; - return (static_cast(data[pos - 1]) << 8) | - (static_cast(data[pos - 2])); + int16_t value; + std::memcpy(&value, data + pos, sizeof(int16_t)); + pos += sizeof(int16_t); + return dataio::le2h(value); } int32_t ByteReader::getInt32() { - if (pos + 4 > size) { + if (pos + sizeof(int32_t) > size) { throw std::runtime_error("buffer underflow"); } - pos += 4; - return (static_cast(data[pos - 1]) << 24) | - (static_cast(data[pos - 2]) << 16) | - (static_cast(data[pos - 3]) << 8) | - (static_cast(data[pos - 4])); + int32_t value; + std::memcpy(&value, data + pos, sizeof(int32_t)); + pos += sizeof(int32_t); + return dataio::le2h(value); } int64_t ByteReader::getInt64() { - if (pos + 8 > size) { + if (pos + sizeof(int64_t) > size) { throw std::runtime_error("buffer underflow"); } - pos += 8; - return (static_cast(data[pos - 1]) << 56) | - (static_cast(data[pos - 2]) << 48) | - (static_cast(data[pos - 3]) << 40) | - (static_cast(data[pos - 4]) << 32) | - (static_cast(data[pos - 5]) << 24) | - (static_cast(data[pos - 6]) << 16) | - (static_cast(data[pos - 7]) << 8) | - (static_cast(data[pos - 8])); + int64_t value; + std::memcpy(&value, data + pos, sizeof(int64_t)); + pos += sizeof(int64_t); + return dataio::le2h(value); } float ByteReader::getFloat32() { @@ -183,7 +167,7 @@ double ByteReader::getFloat64() { const char* ByteReader::getCString() { const char* cstr = reinterpret_cast(data + pos); - pos += strlen(cstr) + 1; + pos += std::strlen(cstr) + 1; return cstr; } diff --git a/src/coders/byte_utils.hpp b/src/coders/byte_utils.hpp index 20c5d150..855ebaec 100644 --- a/src/coders/byte_utils.hpp +++ b/src/coders/byte_utils.hpp @@ -5,28 +5,27 @@ #include "typedefs.hpp" -/* byteorder: little-endian */ class ByteBuilder { std::vector buffer; public: - /* Write one byte (8 bit unsigned integer) */ + /// @brief Write one byte (8 bit unsigned integer) void put(ubyte b); - /* Write c-string (bytes array terminated with '\00') */ + /// @brief Write c-string (bytes array terminated with '\00') void putCStr(const char* str); - /* Write signed 16 bit integer */ + /// @brief Write signed 16 bit little-endian integer void putInt16(int16_t val); - /* Write signed 32 bit integer */ + /// @brief Write signed 32 bit integer void putInt32(int32_t val); - /* Write signed 64 bit integer */ + /// @brief Write signed 64 bit integer void putInt64(int64_t val); - /* Write 32 bit floating-point number */ + /// @brief Write 32 bit floating-point number void putFloat32(float val); - /* Write 64 bit floating-point number */ + /// @brief Write 64 bit floating-point number void putFloat64(double val); - /* Write string (uint32 length + bytes) */ + /// @brief Write string (uint32 length + bytes) void put(const std::string& s); - /* Write sequence of bytes without any header */ + /// @brief Write sequence of bytes without any header void put(const ubyte* arr, size_t size); void set(size_t position, ubyte val); @@ -44,7 +43,6 @@ public: std::vector build(); }; -/// byteorder: little-endian class ByteReader { const ubyte* data; size_t size; @@ -58,11 +56,11 @@ public: ubyte get(); /// @brief Read one byte (unsigned 8 bit integer) without pointer move ubyte peek(); - /// @brief Read signed 16 bit integer + /// @brief Read signed 16 bit little-endian integer int16_t getInt16(); - /// @brief Read signed 32 bit integer + /// @brief Read signed 32 bit little-endian integer int32_t getInt32(); - /// @brief Read signed 64 bit integer + /// @brief Read signed 64 bit little-endian integer int64_t getInt64(); /// @brief Read 32 bit floating-point number float getFloat32(); diff --git a/src/util/Buffer.hpp b/src/util/Buffer.hpp index 7ff0ca8a..4787d2ed 100644 --- a/src/util/Buffer.hpp +++ b/src/util/Buffer.hpp @@ -18,7 +18,7 @@ namespace util { Buffer(const T* src, size_t length) : ptr(std::make_unique(length)), length(length) { - std::memcpy(ptr, src, length); + std::memcpy(ptr.get(), src, length); } T& operator[](long long index) { diff --git a/src/util/data_io.hpp b/src/util/data_io.hpp index 93022f7d..4d2d69ab 100644 --- a/src/util/data_io.hpp +++ b/src/util/data_io.hpp @@ -41,6 +41,15 @@ namespace dataio { } } + /// @brief Convert hardware byte-order to big-endian + /// @tparam T value type + /// @param value source integer + /// @return big-endian integer + template + T h2be(T value){ + return be2h(value); + } + /// @brief Convert little-endian to hardware byte-order /// @tparam T value type /// @param value source integer @@ -54,6 +63,15 @@ namespace dataio { } } + /// @brief Convert hardware byte-order to little-endian + /// @tparam T value type + /// @param value source integer + /// @return little-endian integer + template + T h2le(T value){ + return le2h(value); + } + /// @brief Read big-endian 16 bit signed integer from bytes inline int16_t read_int16_big(const ubyte* src, size_t offset) { return (src[offset] << 8) | (src[offset + 1]); diff --git a/test/coders/byte_utils.cpp b/test/coders/byte_utils.cpp new file mode 100644 index 00000000..6b0be61d --- /dev/null +++ b/test/coders/byte_utils.cpp @@ -0,0 +1,20 @@ +#include + +#include "coders/byte_utils.hpp" + +TEST(byte_utils, BytesBuildAndRead) { + ByteBuilder builder; + builder.putCStr("MAGIC.#"); + builder.put(50); + builder.putInt16(1980); + builder.putInt32(123456789); + builder.putInt64(98765432123456789LL); + auto data = builder.build(); + + ByteReader reader(data.data(), data.size()); + reader.checkMagic("MAGIC.#", 8); + EXPECT_EQ(reader.get(), 50); + EXPECT_EQ(reader.getInt16(), 1980); + EXPECT_EQ(reader.getInt32(), 123456789); + EXPECT_EQ(reader.getInt64(), 98765432123456789LL); +}