Add iterators to ring_buffer

Change-Id: Id3185b94240da595925fc4878f068b673ea98dd9
diff --git a/aos/containers/ring_buffer.h b/aos/containers/ring_buffer.h
index d4cd92a..cd7872e 100644
--- a/aos/containers/ring_buffer.h
+++ b/aos/containers/ring_buffer.h
@@ -55,6 +55,74 @@
   // Clears all the data out of the buffer.
   void Reset() { size_ = 0; }
 
+  class iterator {
+   public:
+    using iterator_category = ::std::forward_iterator_tag;
+    using value_type = Data;
+    using difference_type = ::std::ptrdiff_t;
+    using pointer = Data *;
+    using reference = Data &;
+
+    explicit iterator(RingBuffer *buffer, size_t index)
+        : buffer_(buffer), index_(index) {}
+
+    iterator &operator++() {
+      ++index_;
+      return *this;
+    }
+    iterator operator++(int) {
+      iterator retval = *this;
+      ++(*this);
+      return retval;
+    }
+    bool operator==(iterator other) const {
+      return buffer_ == other.buffer_ && index_ == other.index_;
+    }
+    bool operator!=(iterator other) const { return !(*this == other); }
+    reference operator*() const { return (*buffer_)[index_]; }
+
+   private:
+    RingBuffer *buffer_;
+    size_t index_;
+  };
+
+  class const_iterator {
+   public:
+    using iterator_category = ::std::forward_iterator_tag;
+    using value_type = Data;
+    using difference_type = ::std::ptrdiff_t;
+    using pointer = Data *;
+    using reference = Data &;
+
+    explicit const_iterator(const RingBuffer *buffer, size_t index)
+        : buffer_(buffer), index_(index) {}
+
+    const_iterator &operator++() {
+      ++index_;
+      return *this;
+    }
+    const_iterator operator++(int) {
+      const_iterator retval = *this;
+      ++(*this);
+      return retval;
+    }
+    bool operator==(const_iterator other) const {
+      return buffer_ == other.buffer_ && index_ == other.index_;
+    }
+    bool operator!=(const_iterator other) const { return !(*this == other); }
+    const Data &operator*() const { return (*buffer_)[index_]; }
+
+   private:
+    const RingBuffer *buffer_;
+    size_t index_;
+  };
+
+  iterator begin() { return iterator(this, 0); }
+  iterator end() { return iterator(this, size()); }
+
+  const_iterator begin() const { return const_iterator(this, 0); }
+  const_iterator end() const { return const_iterator(this, size()); }
+
  private:
   ::std::array<Data, buffer_size> data_;
 
diff --git a/aos/containers/ring_buffer_test.cc b/aos/containers/ring_buffer_test.cc
index 5fb2331..01e057f 100644
--- a/aos/containers/ring_buffer_test.cc
+++ b/aos/containers/ring_buffer_test.cc
@@ -118,5 +118,41 @@
   }
 }
 
+// Test that an iterator over the buffer works.
+TEST_F(RingBufferTest, Iterator) {
+  // Over fill it, and then clear it out.
+  ASSERT_TRUE(buffer_.empty());
+
+  for (int i = 0; i < 12; ++i) {
+    buffer_.Push(i);
+  }
+
+  int i = 0;
+  for (int element : buffer_) {
+    EXPECT_EQ(i + 2, element);
+    ++i;
+  }
+  EXPECT_EQ(i, buffer_.size());
+}
+
+// Test that a const iterator over the buffer works.
+TEST_F(RingBufferTest, CIterator) {
+  // Over fill it, and then clear it out.
+  ASSERT_TRUE(buffer_.empty());
+
+  for (int i = 0; i < 12; ++i) {
+    buffer_.Push(i);
+  }
+
+  const RingBuffer<int, 10> &cbuffer = buffer_;
+
+  int i = 0;
+  for (const int element : cbuffer) {
+    EXPECT_EQ(i + 2, element);
+    ++i;
+  }
+  EXPECT_EQ(i, buffer_.size());
+}
+
 }  // namespace testing
 }  // namespace aos