pw_bytes: Added an iterator class

Added an iterator class to the ByteBuilder class with functionality
based on C++'s Random access iterator that allows access to the
elements in the buffer.

Change-Id: I3d4c1de916137bb515635fab575b29efc4a8855f
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/12802
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 c649b20..7d8ce2d 100644
--- a/pw_bytes/byte_builder_test.cc
+++ b/pw_bytes/byte_builder_test.cc
@@ -163,7 +163,7 @@
   std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
   ByteBuffer<8> bb;
 
-  EXPECT_TRUE(bb.append(buffer.data(), 3).ok());
+  EXPECT_TRUE(bb.append(buffer).ok());
 
   bb.resize(1);
   EXPECT_TRUE(bb.ok());
@@ -175,7 +175,7 @@
   std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
   ByteBuffer<8> bb;
 
-  EXPECT_TRUE(bb.append(buffer.data(), 3).ok());
+  EXPECT_TRUE(bb.append(buffer).ok());
 
   bb.resize(0);
   EXPECT_TRUE(bb.ok());
@@ -187,7 +187,7 @@
   std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
   ByteBuffer<8> bb;
 
-  EXPECT_TRUE(bb.append(buffer.data(), 3).ok());
+  EXPECT_TRUE(bb.append(buffer).ok());
 
   EXPECT_EQ(3u, bb.size());
   bb.resize(5);
@@ -204,7 +204,7 @@
   std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
   ByteBuffer<2> bb;
 
-  EXPECT_FALSE(bb.append(buffer.data(), 3).ok());
+  EXPECT_FALSE(bb.append(buffer).ok());
   EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.status());
 
   bb.resize(4);
@@ -218,7 +218,7 @@
   std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
   ByteBuffer<2> bb;
 
-  EXPECT_FALSE(bb.append(buffer.data(), 3).ok());
+  EXPECT_FALSE(bb.append(buffer).ok());
   EXPECT_EQ(Status::RESOURCE_EXHAUSTED, bb.status());
 
   bb.clear_status();
@@ -345,7 +345,7 @@
   std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
   ByteBuffer<8> bb;
 
-  EXPECT_TRUE(bb.append(buffer.data(), 3).ok());
+  EXPECT_TRUE(bb.append(buffer).ok());
 
   EXPECT_EQ(3u, bb.size());
   bb.resize(5);
@@ -530,5 +530,249 @@
   EXPECT_EQ(Status::OK, bb.status());
 }
 
+TEST(ByteBuffer, Iterator) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+
+  auto it = bb.begin();
+  EXPECT_EQ(*it, byte{0x01});
+
+  ++it;
+  EXPECT_EQ(*it, byte{0x02});
+  EXPECT_EQ(it - bb.begin(), 1);
+
+  ++it;
+  EXPECT_EQ(*it, byte{0x03});
+  EXPECT_EQ(it - bb.begin(), 2);
+
+  ++it;
+  EXPECT_EQ(it, bb.end());
+  EXPECT_EQ(static_cast<size_t>(it - bb.begin()), bb.size());
+}
+
+TEST(ByteBuffer, Iterator_PreIncrement) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+
+  auto it = bb.begin();
+  EXPECT_EQ(*(++it), byte{0x02});
+}
+
+TEST(ByteBuffer, Iterator_PostIncrement) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+
+  auto it = bb.begin();
+  EXPECT_EQ(*(it++), byte{0x01});
+  EXPECT_EQ(*it, byte{0x02});
+  EXPECT_EQ(*(it++), byte{0x02});
+  EXPECT_EQ(*it, byte{0x03});
+}
+
+TEST(ByteBuffer, Iterator_PreDecrement) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+  auto it = bb.begin();
+
+  EXPECT_EQ(*it, byte{0x01});
+  ++it;
+  EXPECT_EQ(*it, byte{0x02});
+  ++it;
+  EXPECT_EQ(*it, byte{0x03});
+  ++it;
+  EXPECT_EQ(it, bb.end());
+
+  --it;
+  EXPECT_EQ(*it, byte{0x03});
+  --it;
+  EXPECT_EQ(*it, byte{0x02});
+  --it;
+  EXPECT_EQ(*it, byte{0x01});
+  EXPECT_EQ(it, bb.begin());
+}
+
+TEST(ByteBuffer, Iterator_PostDecrement) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+  auto it = bb.begin();
+
+  it += 2;
+  EXPECT_EQ(*it, byte{0x03});
+
+  EXPECT_EQ(*(it--), byte{0x03});
+  EXPECT_EQ(*it, byte{0x02});
+  EXPECT_EQ(*(it--), byte{0x02});
+  EXPECT_EQ(*it, byte{0x01});
+}
+
+TEST(ByteBuffer, Iterator_PlusEquals) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+  auto it = bb.begin();
+
+  it += 2;
+  EXPECT_EQ(*it, byte{0x03});
+
+  it += -1;
+  EXPECT_EQ(*it, byte{0x02});
+
+  it += 1;
+  EXPECT_EQ(*it, byte{0x03});
+
+  it += -2;
+  EXPECT_EQ(*it, byte{0x01});
+}
+
+TEST(ByteBuffer, Iterator_MinusEquals) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+  auto it = bb.begin();
+
+  it -= -2;
+  EXPECT_EQ(*it, byte{0x03});
+
+  it -= +1;
+  EXPECT_EQ(*it, byte{0x02});
+
+  it -= -1;
+  EXPECT_EQ(*it, byte{0x03});
+
+  it -= +2;
+  EXPECT_EQ(*it, byte{0x01});
+}
+
+TEST(ByteBuffer, Iterator_Plus) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+  auto it = bb.begin();
+
+  auto test = it + 2;
+  EXPECT_EQ(*test, byte{0x03});
+
+  test = test + -1;
+  EXPECT_EQ(*test, byte{0x02});
+
+  test = test + 1;
+  EXPECT_EQ(*test, byte{0x03});
+
+  test = test + (-2);
+  EXPECT_EQ(*test, byte{0x01});
+}
+
+TEST(ByteBuffer, Iterator_Minus) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+  auto it = bb.begin();
+
+  auto test = it - (-2);
+  EXPECT_EQ(*test, byte{0x03});
+
+  test = test - 1;
+  EXPECT_EQ(*test, byte{0x02});
+
+  test = test - (-1);
+  EXPECT_EQ(*test, byte{0x03});
+
+  test = test - 2;
+  EXPECT_EQ(*test, byte{0x01});
+}
+
+TEST(ByteBuffer, Iterator_LessThan) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+
+  auto it_1 = bb.begin();
+  auto it_2 = it_1 + 2;
+  EXPECT_EQ(*it_1, byte{0x01});
+  EXPECT_EQ(*it_2, byte{0x03});
+  EXPECT_TRUE(it_1 < it_2);
+
+  it_1++;
+  it_2--;
+  EXPECT_EQ(*it_1, byte{0x02});
+  EXPECT_EQ(*it_2, byte{0x02});
+  EXPECT_FALSE(it_1 < it_2);
+
+  it_1++;
+  it_2--;
+  EXPECT_EQ(*it_1, byte{0x03});
+  EXPECT_EQ(*it_2, byte{0x01});
+  EXPECT_FALSE(it_1 < it_2);
+  EXPECT_TRUE(it_2 < it_1);
+}
+
+TEST(ByteBuffer, Iterator_GreaterThan) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+
+  auto it_1 = bb.begin();
+  auto it_2 = it_1 + 2;
+  EXPECT_EQ(*it_1, byte{0x01});
+  EXPECT_EQ(*it_2, byte{0x03});
+  EXPECT_FALSE(it_1 > it_2);
+
+  it_1++;
+  it_2--;
+  EXPECT_EQ(*it_1, byte{0x02});
+  EXPECT_EQ(*it_2, byte{0x02});
+  EXPECT_FALSE(it_1 > it_2);
+
+  it_1++;
+  it_2--;
+  EXPECT_EQ(*it_1, byte{0x03});
+  EXPECT_EQ(*it_2, byte{0x01});
+  EXPECT_TRUE(it_1 > it_2);
+  EXPECT_FALSE(it_2 > it_1);
+}
+
+TEST(ByteBuffer, Iterator_LessThanEqual_GreaterThanEqual) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+
+  auto it_1 = bb.begin();
+  auto it_2 = it_1 + 2;
+  EXPECT_EQ(*it_1, byte{0x01});
+  EXPECT_EQ(*it_2, byte{0x03});
+  EXPECT_FALSE(it_1 >= it_2);
+  EXPECT_TRUE(it_1 <= it_2);
+
+  it_1++;
+  it_2--;
+  EXPECT_EQ(*it_1, byte{0x02});
+  EXPECT_EQ(*it_2, byte{0x02});
+  EXPECT_TRUE(it_1 >= it_2);
+  EXPECT_TRUE(it_1 <= it_2);
+
+  it_1++;
+  it_2--;
+  EXPECT_EQ(*it_1, byte{0x03});
+  EXPECT_EQ(*it_2, byte{0x01});
+  EXPECT_FALSE(it_1 <= it_2);
+  EXPECT_TRUE(it_1 >= it_2);
+}
+
+TEST(ByteBuffer, Iterator_Indexing) {
+  std::array<byte, 3> buffer = MakeBytes(0x01, 0x02, 0x03);
+  ByteBuffer<8> bb;
+  EXPECT_TRUE(bb.append(buffer).ok());
+
+  auto it = bb.begin();
+  EXPECT_EQ(it[0], byte{0x01});
+  EXPECT_EQ(it[1], byte{0x02});
+  EXPECT_EQ(it[2], byte{0x03});
+}
+
 }  // namespace
 }  // namespace pw
diff --git a/pw_bytes/public/pw_bytes/byte_builder.h b/pw_bytes/public/pw_bytes/byte_builder.h
index eade658..fb84347 100644
--- a/pw_bytes/public/pw_bytes/byte_builder.h
+++ b/pw_bytes/public/pw_bytes/byte_builder.h
@@ -42,6 +42,97 @@
 // allocates a buffer alongside a ByteBuilder.
 class ByteBuilder {
  public:
+  // iterator class will allow users of ByteBuilder and ByteBuffer to access
+  // the data stored in the buffer. It has the functionality of C++'s
+  // random access iterator.
+  class iterator {
+   public:
+    using difference_type = ptrdiff_t;
+    using value_type = std::byte;
+    using pointer = std::byte*;
+    using reference = std::byte&;
+    using iterator_category = std::random_access_iterator_tag;
+
+    explicit constexpr iterator(const std::byte* byte_ptr) : byte_(byte_ptr) {}
+
+    constexpr iterator& operator++() {
+      byte_ += 1;
+      return *this;
+    }
+
+    constexpr iterator operator++(int) {
+      iterator previous(byte_);
+      operator++();
+      return previous;
+    }
+
+    constexpr iterator& operator--() {
+      byte_ -= 1;
+      return *this;
+    }
+
+    constexpr iterator operator--(int) {
+      iterator previous(byte_);
+      operator--();
+      return previous;
+    }
+
+    constexpr iterator operator+=(int n) {
+      byte_ += n;
+      return *this;
+    }
+
+    constexpr iterator operator+(int n) const { return iterator(byte_ + n); }
+
+    constexpr iterator operator-=(int n) { return operator+=(-n); }
+
+    constexpr iterator operator-(int n) const { return iterator(byte_ - n); }
+
+    constexpr ptrdiff_t operator-(const iterator& rhs) const {
+      return byte_ - rhs.byte_;
+    }
+
+    constexpr bool operator==(const iterator& rhs) const {
+      return byte_ == rhs.byte_;
+    }
+
+    constexpr bool operator!=(const iterator& rhs) const {
+      return byte_ != rhs.byte_;
+    }
+
+    constexpr bool operator<(const iterator& rhs) const {
+      return byte_ < rhs.byte_;
+    }
+
+    constexpr bool operator>(const iterator& rhs) const {
+      return byte_ > rhs.byte_;
+    }
+
+    constexpr bool operator<=(const iterator& rhs) const {
+      return !operator>(rhs);
+    }
+
+    constexpr bool operator>=(const iterator& rhs) const {
+      return !operator<(rhs);
+    }
+
+    constexpr const std::byte& operator*() const { return *byte_; }
+
+    constexpr const std::byte& operator[](int index) const {
+      return byte_[index];
+    }
+
+   private:
+    const std::byte* byte_;
+  };
+
+  using element_type = const std::byte;
+  using value_type = std::byte;
+  using pointer = std::byte*;
+  using reference = std::byte&;
+  using iterator = iterator;
+  using const_iterator = iterator;
+
   // Creates an empty ByteBuilder.
   constexpr ByteBuilder(span<std::byte> buffer) : buffer_(buffer), size_(0) {}
 
@@ -101,6 +192,18 @@
     resize(size() - 1);
   }
 
+  // Root of bytebuffer wrapped in iterator type
+  const_iterator begin() const { return iterator(data()); }
+  const_iterator cbegin() const { return begin(); }
+
+  // End of bytebuffer wrapped in iterator type
+  const_iterator end() const { return iterator(data() + size()); }
+  const_iterator cend() const { return end(); }
+
+  // Front and Back C++ container functions
+  const std::byte& front() const { return buffer_[0]; }
+  const std::byte& back() const { return buffer_[size() - 1]; }
+
   // Appends the provided byte count times.
   ByteBuilder& append(size_t count, std::byte b);