pw_bytes: Added iterator value-retrieval methods
Added 'peek' and 'read' functionality that enables ordered retreival
(Little/Big Endian) of the inserted integer values, and adjusts the
position of the iterator accordingly.
Change-Id: I418f7bd3ed5a1b627a80a0eaa190c2d26fed032c
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/12960
Reviewed-by: Wyatt Hepler <hepler@google.com>
Commit-Queue: Shane Gomindes <shaneajg@google.com>
diff --git a/pw_bytes/byte_builder_test.cc b/pw_bytes/byte_builder_test.cc
index ab4dba9..1fa6a32 100644
--- a/pw_bytes/byte_builder_test.cc
+++ b/pw_bytes/byte_builder_test.cc
@@ -57,9 +57,9 @@
ByteBuilder bb(ByteSpan{});
EXPECT_TRUE(bb.empty());
- auto bytesTestLiteral = MakeBytes(0x04, 0x05);
+ constexpr auto kBytesTestLiteral = MakeBytes(0x04, 0x05);
- EXPECT_FALSE(bb.append(bytesTestLiteral.data(), 2).ok());
+ EXPECT_FALSE(bb.append(kBytesTestLiteral.data(), 2).ok());
EXPECT_EQ(0u, bb.size());
EXPECT_EQ(0u, bb.max_size());
}
@@ -69,9 +69,9 @@
ByteBuilder bb(buffer);
EXPECT_TRUE(bb.empty());
- auto bytesTestLiteral = MakeBytes(0x04, 0x05);
+ constexpr auto kBytesTestLiteral = MakeBytes(0x04, 0x05);
- EXPECT_TRUE(bb.append(bytesTestLiteral.data(), 2).ok());
+ EXPECT_TRUE(bb.append(kBytesTestLiteral.data(), 2).ok());
EXPECT_EQ(byte{0x04}, bb.data()[0]);
EXPECT_EQ(byte{0x05}, bb.data()[1]);
}
@@ -82,9 +82,9 @@
EXPECT_TRUE(bb.empty());
- auto bytesTestLiteral = MakeBytes(0x04, 0x05, 0x06, 0x07);
+ constexpr auto kBytesTestLiteral = MakeBytes(0x04, 0x05, 0x06, 0x07);
- EXPECT_TRUE(bb.append(bytesTestLiteral.data(), 3).ok());
+ EXPECT_TRUE(bb.append(kBytesTestLiteral.data(), 3).ok());
EXPECT_EQ(byte{0x04}, bb.data()[0]);
EXPECT_EQ(byte{0x05}, bb.data()[1]);
EXPECT_EQ(byte{0x06}, bb.data()[2]);
@@ -96,9 +96,9 @@
EXPECT_TRUE(bb.empty());
- auto bytesTestLiteral = MakeBytes(0x04, 0x05, 0x06, 0x07);
+ constexpr auto kBytesTestLiteral = MakeBytes(0x04, 0x05, 0x06, 0x07);
- EXPECT_FALSE(bb.append(bytesTestLiteral.data(), 4).ok());
+ EXPECT_FALSE(bb.append(kBytesTestLiteral.data(), 4).ok());
EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.status());
EXPECT_EQ(0u, bb.size());
}
@@ -290,9 +290,9 @@
EXPECT_EQ(byte{0x02}, two.data()[1]);
EXPECT_EQ(byte{0x03}, two.data()[2]);
- auto bytesTestLiteral = MakeBytes(0x04, 0x05, 0x06, 0x07);
- one.append(bytesTestLiteral.data(), 2);
- two.append(bytesTestLiteral.data(), 4);
+ constexpr auto kBytesTestLiteral = MakeBytes(0x04, 0x05, 0x06, 0x07);
+ one.append(kBytesTestLiteral.data(), 2);
+ two.append(kBytesTestLiteral.data(), 4);
EXPECT_EQ(5u, one.size());
EXPECT_EQ(7u, two.size());
EXPECT_EQ(byte{0x04}, one.data()[3]);
@@ -774,5 +774,93 @@
EXPECT_EQ(it[2], byte{0x03});
}
+TEST(ByteBuffer, Iterator_PeekValues_1Byte) {
+ ByteBuffer<3> bb;
+ bb.PutInt8(0xF2);
+ bb.PutUint8(0xE5);
+ bb.PutInt8(0x5F);
+
+ auto it = bb.begin();
+ EXPECT_EQ(it.PeekInt8(), int8_t(0xF2));
+ it = it + 1;
+ EXPECT_EQ(it.PeekUint8(), uint8_t(0xE5));
+ it = it + 1;
+ EXPECT_EQ(it.PeekInt8(), int8_t(0x5F));
+}
+
+TEST(ByteBuffer, Iterator_PeekValues_2Bytes) {
+ ByteBuffer<4> bb;
+ bb.PutInt16(0xA7F1);
+ bb.PutUint16(0xF929, ByteOrder::kBigEndian);
+
+ auto it = bb.begin();
+ EXPECT_EQ(it.PeekInt16(), int16_t(0xA7F1));
+ it = it + 2;
+ EXPECT_EQ(it.PeekUint16(ByteOrder::kBigEndian), uint16_t(0xF929));
+}
+
+TEST(ByteBuffer, Iterator_PeekValues_4Bytes) {
+ ByteBuffer<8> bb;
+ bb.PutInt32(0xFFFFFFF1);
+ bb.PutUint32(0xF92927B2, ByteOrder::kBigEndian);
+
+ auto it = bb.begin();
+ EXPECT_EQ(it.PeekInt32(), int32_t(0xFFFFFFF1));
+ it = it + 4;
+ EXPECT_EQ(it.PeekUint32(ByteOrder::kBigEndian), uint32_t(0xF92927B2));
+}
+
+TEST(ByteBuffer, Iterator_PeekValues_8Bytes) {
+ ByteBuffer<16> bb;
+ bb.PutUint64(0x000001E8A7A0D569);
+ bb.PutInt64(0xFFFFFE17585F2A97, ByteOrder::kBigEndian);
+
+ auto it = bb.begin();
+ EXPECT_EQ(it.PeekUint64(), uint64_t(0x000001E8A7A0D569));
+ it = it + 8;
+ EXPECT_EQ(it.PeekInt64(ByteOrder::kBigEndian), int64_t(0xFFFFFE17585F2A97));
+}
+
+TEST(ByteBuffer, Iterator_ReadValues_1Byte) {
+ ByteBuffer<3> bb;
+ bb.PutInt8(0xF2);
+ bb.PutUint8(0xE5);
+ bb.PutInt8(0x5F);
+
+ auto it = bb.begin();
+ EXPECT_EQ(it.ReadInt8(), int8_t(0xF2));
+ EXPECT_EQ(it.ReadUint8(), uint8_t(0xE5));
+ EXPECT_EQ(it.ReadInt8(), int8_t(0x5F));
+}
+
+TEST(ByteBuffer, Iterator_ReadValues_2Bytes) {
+ ByteBuffer<4> bb;
+ bb.PutInt16(0xA7F1);
+ bb.PutUint16(0xF929, ByteOrder::kBigEndian);
+
+ auto it = bb.begin();
+ EXPECT_EQ(it.ReadInt16(), int16_t(0xA7F1));
+ EXPECT_EQ(it.ReadUint16(ByteOrder::kBigEndian), uint16_t(0xF929));
+}
+
+TEST(ByteBuffer, Iterator_ReadValues_4Bytes) {
+ ByteBuffer<8> bb;
+ bb.PutInt32(0xFFFFFFF1);
+ bb.PutUint32(0xF92927B2, ByteOrder::kBigEndian);
+
+ auto it = bb.begin();
+ EXPECT_EQ(it.ReadInt32(), int32_t(0xFFFFFFF1));
+ EXPECT_EQ(it.ReadUint32(ByteOrder::kBigEndian), uint32_t(0xF92927B2));
+}
+
+TEST(ByteBuffer, Iterator_ReadValues_8Bytes) {
+ ByteBuffer<16> bb;
+ bb.PutUint64(0x000001E8A7A0D569);
+ bb.PutInt64(0xFFFFFE17585F2A97, ByteOrder::kBigEndian);
+
+ auto it = bb.begin();
+ EXPECT_EQ(it.ReadUint64(), uint64_t(0x000001E8A7A0D569));
+ EXPECT_EQ(it.ReadInt64(ByteOrder::kBigEndian), int64_t(0xFFFFFE17585F2A97));
+}
} // namespace
} // namespace pw
diff --git a/pw_bytes/public/pw_bytes/byte_builder.h b/pw_bytes/public/pw_bytes/byte_builder.h
index 49af984..79b609e 100644
--- a/pw_bytes/public/pw_bytes/byte_builder.h
+++ b/pw_bytes/public/pw_bytes/byte_builder.h
@@ -122,7 +122,96 @@
return byte_[index];
}
+ // The Peek methods will retreive ordered (Little/Big Endian) values
+ // located at the iterator position without moving the iterator forward.
+ int8_t PeekInt8() const { return static_cast<int8_t>(PeekUint8()); }
+
+ uint8_t PeekUint8() const { return GetInteger<uint8_t>(); }
+
+ int16_t PeekInt16(ByteOrder order = ByteOrder::kLittleEndian) const {
+ return static_cast<int16_t>(PeekUint16(order));
+ }
+
+ uint16_t PeekUint16(ByteOrder order = ByteOrder::kLittleEndian) const {
+ return GetInteger<uint16_t>(order);
+ }
+
+ int32_t PeekInt32(ByteOrder order = ByteOrder::kLittleEndian) const {
+ return static_cast<int32_t>(PeekUint32(order));
+ }
+
+ uint32_t PeekUint32(ByteOrder order = ByteOrder::kLittleEndian) const {
+ return GetInteger<uint32_t>(order);
+ }
+
+ int64_t PeekInt64(ByteOrder order = ByteOrder::kLittleEndian) const {
+ return static_cast<int64_t>(PeekUint64(order));
+ }
+
+ uint64_t PeekUint64(ByteOrder order = ByteOrder::kLittleEndian) const {
+ return GetInteger<uint64_t>(order);
+ }
+
+ // The Read methods will retreive ordered (Little/Big Endian) values
+ // located at the iterator position and move the iterator forward by
+ // sizeof(value) positions forward.
+ int8_t ReadInt8() { return static_cast<int8_t>(ReadUint8()); }
+
+ uint8_t ReadUint8() {
+ uint8_t value = GetInteger<uint8_t>();
+ byte_ += 1;
+ return value;
+ }
+
+ int16_t ReadInt16(ByteOrder order = ByteOrder::kLittleEndian) {
+ return static_cast<int16_t>(ReadUint16(order));
+ }
+
+ uint16_t ReadUint16(ByteOrder order = ByteOrder::kLittleEndian) {
+ uint16_t value = GetInteger<uint16_t>(order);
+ byte_ += 2;
+ return value;
+ }
+
+ int32_t ReadInt32(ByteOrder order = ByteOrder::kLittleEndian) {
+ return static_cast<int32_t>(ReadUint32(order));
+ }
+
+ uint32_t ReadUint32(ByteOrder order = ByteOrder::kLittleEndian) {
+ uint32_t value = GetInteger<uint32_t>(order);
+ byte_ += 4;
+ return value;
+ }
+
+ int64_t ReadInt64(ByteOrder order = ByteOrder::kLittleEndian) {
+ return static_cast<int64_t>(ReadUint64(order));
+ }
+
+ uint64_t ReadUint64(ByteOrder order = ByteOrder::kLittleEndian) {
+ int64_t value = GetInteger<int64_t>(order);
+ byte_ += 8;
+ return value;
+ }
+
private:
+ template <typename T>
+ T GetInteger(ByteOrder order = ByteOrder::kLittleEndian) const {
+ T value;
+ std::memcpy(&value, byte_, sizeof(T));
+ if (kSystemEndianness != order) {
+ if constexpr (sizeof(T) == 1) {
+ return value;
+ } else if constexpr (sizeof(T) == 2) {
+ return Reverse2Bytes(value);
+ } else if constexpr (sizeof(T) == 4) {
+ return Reverse4Bytes(value);
+ } else if constexpr (sizeof(T) == 8) {
+ return Reverse8Bytes(value);
+ }
+ }
+ return value;
+ }
+
const std::byte* byte_;
};
@@ -230,7 +319,7 @@
ByteBuilder& PutUint16(uint16_t value,
ByteOrder order = ByteOrder::kLittleEndian) {
if (kSystemEndianness != order) {
- value = ((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8);
+ value = Reverse2Bytes(value);
}
return WriteInOrder(value);
}
@@ -244,10 +333,7 @@
ByteBuilder& PutUint32(uint32_t value,
ByteOrder order = ByteOrder::kLittleEndian) {
if (kSystemEndianness != order) {
- value = ((value & 0x000000FF) << 3 * 8) | //
- ((value & 0x0000FF00) << 1 * 8) | //
- ((value & 0x00FF0000) >> 1 * 8) | //
- ((value & 0xFF000000) >> 3 * 8);
+ value = Reverse4Bytes(value);
}
return WriteInOrder(value);
}
@@ -261,14 +347,7 @@
ByteBuilder& PutUint64(uint64_t value,
ByteOrder order = ByteOrder::kLittleEndian) {
if (kSystemEndianness != order) {
- value = ((value & 0x00000000000000FF) << 7 * 8) | //
- ((value & 0x000000000000FF00) << 5 * 8) | //
- ((value & 0x0000000000FF0000) << 3 * 8) | //
- ((value & 0x00000000FF000000) << 1 * 8) | //
- ((value & 0x000000FF00000000) >> 1 * 8) | //
- ((value & 0x0000FF0000000000) >> 3 * 8) | //
- ((value & 0x00FF000000000000) >> 5 * 8) | //
- ((value & 0xFF00000000000000) >> 7 * 8);
+ value = Reverse8Bytes(value);
}
return WriteInOrder(value);
}
@@ -289,6 +368,28 @@
};
private:
+ static constexpr uint16_t Reverse2Bytes(uint16_t value) {
+ return uint16_t(((value & 0x00FF) << 8) | ((value & 0xFF00) >> 8));
+ }
+
+ static constexpr uint32_t Reverse4Bytes(uint32_t value) {
+ return uint32_t(((value & 0x000000FF) << 3 * 8) | //
+ ((value & 0x0000FF00) << 1 * 8) | //
+ ((value & 0x00FF0000) >> 1 * 8) | //
+ ((value & 0xFF000000) >> 3 * 8));
+ }
+
+ static constexpr uint64_t Reverse8Bytes(uint64_t value) {
+ return uint64_t(((value & 0x00000000000000FF) << 7 * 8) | //
+ ((value & 0x000000000000FF00) << 5 * 8) | //
+ ((value & 0x0000000000FF0000) << 3 * 8) | //
+ ((value & 0x00000000FF000000) << 1 * 8) | //
+ ((value & 0x000000FF00000000) >> 1 * 8) | //
+ ((value & 0x0000FF0000000000) >> 3 * 8) | //
+ ((value & 0x00FF000000000000) >> 5 * 8) | //
+ ((value & 0xFF00000000000000) >> 7 * 8));
+ }
+
template <typename T>
ByteBuilder& WriteInOrder(T value) {
return append(&value, sizeof(value));