Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions native/V2StyxLib/modules/l5/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.22)
if(BUILD_MODULE_L5)
add_library(module_l5 STATIC
src/BufferWriterImpl.cpp
src/BufferReaderImpl.cpp
src/StyxMessage.cpp
)
target_include_directories(module_l5 PUBLIC
Expand All @@ -12,6 +13,7 @@ if(BUILD_MODULE_L5)

add_executable(module_l5_tests
test/test_BufferWriterImpl.cpp
test/test_BufferReaderImpl.cpp
)
target_include_directories(module_l5_tests PRIVATE ./include/)
target_link_libraries(module_l5_tests PRIVATE Catch2::Catch2WithMain module_l5)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#pragma once
#include "serialization/IBufferReader.h"

class BufferReaderImpl : public IBufferReader {
private:
const StyxBuffer buffer;
Styx::Size position;
Styx::Size limit;
public:
BufferReaderImpl(const StyxBuffer &buf, Styx::Size size);
virtual ~BufferReaderImpl();

Copilot AI Jun 22, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The destructor is empty; you can simplify by defaulting it (~BufferReaderImpl() override = default;) to reduce boilerplate.

Suggested change
virtual ~BufferReaderImpl();
~BufferReaderImpl() override = default;

Copilot uses AI. Check for mistakes.
uint8_t readUInt8() override;
uint16_t readUInt16() override;
uint32_t readUInt32() override;
uint64_t readUInt64() override;
StyxString readUTFString() override;
Styx::Size read(uint8_t* data, Styx::Size count) override;
};
14 changes: 14 additions & 0 deletions native/V2StyxLib/modules/l5/include/serialization/IBufferReader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
#include "data.h"

class IBufferReader {
public:
virtual ~IBufferReader() = default;
virtual uint8_t readUInt8() = 0;
virtual uint16_t readUInt16() = 0;
virtual uint32_t readUInt32() = 0;
virtual uint64_t readUInt64() = 0;
virtual StyxString readUTFString() = 0;
virtual Styx::Size read(uint8_t* data, Styx::Size count) = 0;
};
92 changes: 92 additions & 0 deletions native/V2StyxLib/modules/l5/src/BufferReaderImpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
#include "serialization/BufferReaderImpl.h"
#include <stdexcept>

BufferReaderImpl::BufferReaderImpl(const StyxBuffer &buf, Styx::Size size)
: buffer(buf), position(0), limit(size)
{
if (buf == nullptr) {
throw std::invalid_argument("Buffer cannot be null");
}
}

BufferReaderImpl::~BufferReaderImpl()
{

}

uint8_t BufferReaderImpl::readUInt8()
{
if (position + sizeof(uint8_t) > limit) {
throw std::out_of_range("Buffer overflow");
}
return buffer[position++];
}

uint16_t BufferReaderImpl::readUInt16()
{
if (position + sizeof(uint16_t) > limit) {
throw std::out_of_range("Buffer overflow");
}
uint16_t value = static_cast<uint16_t>(buffer[position]) |
(static_cast<uint16_t>(buffer[position + 1]) << 8);
position += sizeof(uint16_t);
return value;
}

uint32_t BufferReaderImpl::readUInt32()
{
if (position + sizeof(uint32_t) > limit) {
throw std::out_of_range("Buffer overflow");
}
uint32_t value = static_cast<uint32_t>(buffer[position]) |
(static_cast<uint32_t>(buffer[position + 1]) << 8) |
(static_cast<uint32_t>(buffer[position + 2]) << 16) |
(static_cast<uint32_t>(buffer[position + 3]) << 24);
position += sizeof(uint32_t);
return value;
}

uint64_t BufferReaderImpl::readUInt64()
{
if (position + sizeof(uint64_t) > limit) {
throw std::out_of_range("Buffer overflow");
}
uint64_t value = static_cast<uint64_t>(buffer[position]) |
(static_cast<uint64_t>(buffer[position + 1]) << 8) |
(static_cast<uint64_t>(buffer[position + 2]) << 16) |
(static_cast<uint64_t>(buffer[position + 3]) << 24) |
(static_cast<uint64_t>(buffer[position + 4]) << 32) |
(static_cast<uint64_t>(buffer[position + 5]) << 40) |
(static_cast<uint64_t>(buffer[position + 6]) << 48) |
(static_cast<uint64_t>(buffer[position + 7]) << 56);
position += sizeof(uint64_t);
return value;
}

StyxString BufferReaderImpl::readUTFString()
{
if (position + sizeof(uint16_t) > limit) {
throw std::out_of_range("Buffer overflow");
}
uint16_t length = readUInt16();
if (position + length > limit) {
throw std::out_of_range("Buffer overflow");
}
StyxString result;
result.reserve(length);
for (uint16_t i = 0; i < length; ++i) {
result += static_cast<char>(buffer[position++]);
}
return result;
}

Styx::Size BufferReaderImpl::read(uint8_t* data, Styx::Size count)
{
if (position + count > limit) {
throw std::out_of_range("Buffer overflow");
}
for (Styx::Size i = 0; i < count; ++i) {
data[i] = buffer[position++];
}
Comment on lines +88 to +90

Copilot AI Jun 22, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For bulk reads, prefer std::memcpy(data, buffer + position, count); position += count; to avoid the per-byte loop and improve performance.

Suggested change
for (Styx::Size i = 0; i < count; ++i) {
data[i] = buffer[position++];
}
std::memcpy(data, buffer + position, count);
position += count;

Copilot uses AI. Check for mistakes.
return count;
}
37 changes: 37 additions & 0 deletions native/V2StyxLib/modules/l5/test/test_BufferReaderImpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <catch2/catch_test_macros.hpp>
#include "serialization/BufferReaderImpl.h"

TEST_CASE("readUTFString", "[BufferReaderImpl]") {
uint8_t testData[] = {0x05, 0x00, 'A', 'B', 'C', 'D', 'E', 'F', 'G'};
BufferReaderImpl impl(testData, sizeof(testData));
REQUIRE("ABCDE" == impl.readUTFString());
}

TEST_CASE("readUInt8", "[BufferReaderImpl]") {
uint8_t testData[] = {0x05, 0x06};
BufferReaderImpl impl(testData, sizeof(testData));
REQUIRE(0x05 == impl.readUInt8());
REQUIRE(0x06 == impl.readUInt8());
}

TEST_CASE("readUInt16", "[BufferReaderImpl]") {
uint8_t testData[] = {0x05, 0x06, 0x07, 0x08};
BufferReaderImpl impl(testData, sizeof(testData));
REQUIRE(0x0605 == impl.readUInt16());
REQUIRE(0x0807 == impl.readUInt16());
}

TEST_CASE("readUInt32", "[BufferReaderImpl]") {
uint8_t testData[] = {0x05, 0x06, 0x07, 0x08, 0x10, 0x11, 0x12, 0x13};
BufferReaderImpl impl(testData, sizeof(testData));
REQUIRE(0x08070605 == impl.readUInt32());
REQUIRE(0x13121110 == impl.readUInt32());
}

TEST_CASE("readUInt64", "[BufferReaderImpl]") {
uint8_t testData[] = {0x05, 0x06, 0x07, 0x08, 0x10, 0x11, 0x12, 0x13,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27};
BufferReaderImpl impl(testData, sizeof(testData));
REQUIRE(0x1312111008070605ULL == impl.readUInt64());
REQUIRE(0x2726252423222120ULL == impl.readUInt64());
}
Loading