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