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));