Skip to content

Commit 3d80f6b

Browse files
committed
- Dedup'ing logic on SplitWithLengthPrefix functions.
- Improvements from code review.
1 parent 3ddcf19 commit 3d80f6b

2 files changed

Lines changed: 40 additions & 54 deletions

File tree

src/common/bytes_utils.h

Lines changed: 34 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
#include <tcb/span.hpp>
2929
#include "exceptions.h"
3030

31+
inline constexpr size_t kSizePrefixBytes = sizeof(uint32_t);
32+
3133
// Utility functions for little-endian number reading and writing.
3234

3335
inline void append_u32_le(std::vector<uint8_t>& out, uint32_t v) {
@@ -88,12 +90,12 @@ inline uint32_t read_u32_le(tcb::span<const uint8_t> in, size_t offset) {
8890

8991
// Utility functions for splitting and joining byte vectors.
9092

91-
struct SplitBytesPair {
93+
struct BytesPair {
9294
std::vector<uint8_t> leading;
9395
std::vector<uint8_t> trailing;
9496
};
9597

96-
struct SplitSpansPair {
98+
struct SpansPair {
9799
tcb::span<const uint8_t> leading;
98100
tcb::span<const uint8_t> trailing;
99101
};
@@ -119,11 +121,11 @@ inline std::vector<uint8_t> Join(const std::vector<uint8_t>& leading, const std:
119121
*
120122
* @param bytes The bytes to split
121123
* @param index The index at which to split (bytes before index go to leading, bytes from index go to trailing)
122-
* @return SplitBytesPair structure with split bytes
124+
* @return BytesPair structure with split bytes
123125
* @throws InvalidInputException if index is invalid
124126
*/
125-
inline SplitBytesPair Split(const std::vector<uint8_t>& bytes, int index) {
126-
SplitBytesPair result;
127+
inline BytesPair Split(const std::vector<uint8_t>& bytes, int index) {
128+
BytesPair result;
127129

128130
if (index < 0 || index > static_cast<int>(bytes.size())) {
129131
throw InvalidInputException("Invalid index for splitting bytes: " + std::to_string(index));
@@ -139,15 +141,15 @@ inline SplitBytesPair Split(const std::vector<uint8_t>& bytes, int index) {
139141
*
140142
* @param bytes The span to split
141143
* @param index The index at which to split (bytes before index go to leading, bytes from index go to trailing)
142-
* @return SplitSpansPair structure with split spans
144+
* @return SpansPair structure with split spans
143145
* @throws InvalidInputException if index is invalid
144146
*/
145-
inline SplitSpansPair Split(tcb::span<const uint8_t> bytes, int index) {
147+
inline SpansPair Split(tcb::span<const uint8_t> bytes, int index) {
146148
if (index < 0 || index > static_cast<int>(bytes.size())) {
147149
throw InvalidInputException("Invalid index for splitting bytes: " + std::to_string(index));
148150
}
149151
const size_t split_index = static_cast<size_t>(index);
150-
return SplitSpansPair{
152+
return SpansPair{
151153
tcb::span<const uint8_t>(bytes.data(), split_index),
152154
tcb::span<const uint8_t>(bytes.data() + split_index, bytes.size() - split_index)};
153155
}
@@ -170,7 +172,7 @@ inline std::vector<uint8_t> JoinWithLengthPrefix(const std::vector<uint8_t>& lea
170172
// Calculate the length of the leading bytes
171173
uint32_t leading_length = static_cast<uint32_t>(leading.size());
172174
std::vector<uint8_t> result;
173-
result.reserve(4 + leading.size() + trailing.size());
175+
result.reserve(kSizePrefixBytes + leading.size() + trailing.size());
174176

175177
// Prepend 4-byte length
176178
append_u32_le(result, leading_length);
@@ -183,60 +185,44 @@ inline std::vector<uint8_t> JoinWithLengthPrefix(const std::vector<uint8_t>& lea
183185
}
184186

185187
/**
186-
* Parse a self-contained byte vector that was created with JoinWithLengthPrefix.
187-
* Extracts the leading and trailing parts based on the embedded length prefix.
188-
*
188+
* Parse a self-contained byte span that was created with JoinWithLengthPrefix.
189+
* Extracts leading and trailing span views based on the embedded length prefix.
190+
*
189191
* @param bytes The combined bytes with length prefix
190-
* @return SplitBytesPair structure with leading and trailing bytes
192+
* @return SpansPair structure with leading and trailing span views
191193
* @throws InvalidInputException if the data is invalid or malformed
192194
*/
193-
inline SplitBytesPair SplitWithLengthPrefix(const std::vector<uint8_t>& bytes) {
194-
if (bytes.size() < 4) {
195+
inline SpansPair SplitWithLengthPrefix(tcb::span<const uint8_t> bytes) {
196+
if (bytes.size() < kSizePrefixBytes) {
195197
throw InvalidInputException("Invalid length-prefixed data: insufficient bytes for length prefix");
196198
}
197-
198-
// Read 4-byte length
199+
199200
uint32_t leading_length = read_u32_le(bytes, 0);
200-
201-
if (bytes.size() < 4 + leading_length) {
201+
202+
if (bytes.size() < kSizePrefixBytes + leading_length) {
202203
throw InvalidInputException("Invalid length-prefixed data: insufficient bytes for leading data (expected " +
203-
std::to_string(4 + leading_length) + ", got " + std::to_string(bytes.size()) + ")");
204+
std::to_string(kSizePrefixBytes + leading_length) + ", got " + std::to_string(bytes.size()) + ")");
204205
}
205-
206-
SplitBytesPair result;
207-
208-
// Extract leading bytes (skip the 4-byte length prefix)
209-
result.leading = std::vector<uint8_t>(bytes.begin() + 4, bytes.begin() + 4 + leading_length);
210206

211-
// Extract trailing bytes (everything after leading)
212-
result.trailing = std::vector<uint8_t>(bytes.begin() + 4 + leading_length, bytes.end());
213-
214-
return result;
207+
auto payload = tcb::span<const uint8_t>(
208+
bytes.data() + kSizePrefixBytes,
209+
bytes.size() - kSizePrefixBytes);
210+
return Split(payload, static_cast<int>(leading_length));
215211
}
216212

217213
/**
218-
* Parse a self-contained byte span that was created with JoinWithLengthPrefix.
219-
* Extracts leading and trailing span views based on the embedded length prefix.
220-
*
214+
* Parse a self-contained byte vector that was created with JoinWithLengthPrefix.
215+
* Extracts the leading and trailing parts based on the embedded length prefix.
216+
*
221217
* @param bytes The combined bytes with length prefix
222-
* @return SplitSpansPair structure with leading and trailing span views
218+
* @return BytesPair structure with leading and trailing bytes
223219
* @throws InvalidInputException if the data is invalid or malformed
224220
*/
225-
inline SplitSpansPair SplitWithLengthPrefix(tcb::span<const uint8_t> bytes) {
226-
if (bytes.size() < 4) {
227-
throw InvalidInputException("Invalid length-prefixed data: insufficient bytes for length prefix");
228-
}
229-
230-
uint32_t leading_length = read_u32_le(bytes, 0);
231-
232-
if (bytes.size() < 4 + leading_length) {
233-
throw InvalidInputException("Invalid length-prefixed data: insufficient bytes for leading data (expected " +
234-
std::to_string(4 + leading_length) + ", got " + std::to_string(bytes.size()) + ")");
235-
}
236-
237-
return SplitSpansPair{
238-
tcb::span<const uint8_t>(bytes.data() + 4, leading_length),
239-
tcb::span<const uint8_t>(bytes.data() + 4 + leading_length, bytes.size() - 4 - leading_length)};
221+
inline BytesPair SplitWithLengthPrefix(const std::vector<uint8_t>& bytes) {
222+
const auto spans = SplitWithLengthPrefix(tcb::span<const uint8_t>(bytes));
223+
return BytesPair{
224+
std::vector<uint8_t>(spans.leading.begin(), spans.leading.end()),
225+
std::vector<uint8_t>(spans.trailing.begin(), spans.trailing.end())};
240226
}
241227

242228
// Utility functions for creating an AttributesMap

src/common/bytes_utils_test.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
TEST(BytesUtils, Split_Normal) {
2626
std::vector<uint8_t> bytes = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
27-
SplitBytesPair result = Split(bytes, 3);
27+
BytesPair result = Split(bytes, 3);
2828

2929
EXPECT_EQ(3, result.leading.size());
3030
EXPECT_EQ(3, result.trailing.size());
@@ -34,7 +34,7 @@ TEST(BytesUtils, Split_Normal) {
3434

3535
TEST(BytesUtils, Split_AtBeginning) {
3636
std::vector<uint8_t> bytes = {0x01, 0x02, 0x03};
37-
SplitBytesPair result = Split(bytes, 0);
37+
BytesPair result = Split(bytes, 0);
3838

3939
EXPECT_EQ(0, result.leading.size());
4040
EXPECT_EQ(3, result.trailing.size());
@@ -43,7 +43,7 @@ TEST(BytesUtils, Split_AtBeginning) {
4343

4444
TEST(BytesUtils, Split_AtEnd) {
4545
std::vector<uint8_t> bytes = {0x01, 0x02, 0x03};
46-
SplitBytesPair result = Split(bytes, 3);
46+
BytesPair result = Split(bytes, 3);
4747

4848
EXPECT_EQ(3, result.leading.size());
4949
EXPECT_EQ(0, result.trailing.size());
@@ -97,7 +97,7 @@ TEST(BytesUtils, Join_BothEmpty) {
9797

9898
TEST(BytesUtils, SplitAndJoin_RoundTrip) {
9999
std::vector<uint8_t> original = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
100-
SplitBytesPair split_result = Split(original, 3);
100+
BytesPair split_result = Split(original, 3);
101101
std::vector<uint8_t> joined = Join(split_result.leading, split_result.trailing);
102102

103103
EXPECT_EQ(original, joined);
@@ -168,7 +168,7 @@ TEST(BytesUtils, SplitWithLengthPrefix_Normal) {
168168
std::vector<uint8_t> leading = {0x01, 0x02, 0x03};
169169
std::vector<uint8_t> trailing = {0x04, 0x05, 0x06};
170170
std::vector<uint8_t> combined = JoinWithLengthPrefix(leading, trailing);
171-
SplitBytesPair result = SplitWithLengthPrefix(combined);
171+
BytesPair result = SplitWithLengthPrefix(combined);
172172

173173
EXPECT_EQ(leading, result.leading);
174174
EXPECT_EQ(trailing, result.trailing);
@@ -196,7 +196,7 @@ TEST(BytesUtils, JoinWithLengthPrefixAndSplit_RoundTrip) {
196196
std::vector<uint8_t> trailing = {0x10, 0x20, 0x30, 0x40, 0x50, 0x60};
197197

198198
std::vector<uint8_t> joined = JoinWithLengthPrefix(leading, trailing);
199-
SplitBytesPair parsed = SplitWithLengthPrefix(joined);
199+
BytesPair parsed = SplitWithLengthPrefix(joined);
200200

201201
EXPECT_EQ(leading, parsed.leading);
202202
EXPECT_EQ(trailing, parsed.trailing);

0 commit comments

Comments
 (0)