[vector] Allow to iterate with mutables (#7586)

Co-authored-by: ArnaudD-FR <arnaud.desmier@gmail.com>
Co-authored-by: Derek Bailey <derekbailey@google.com>
diff --git a/include/flatbuffers/array.h b/include/flatbuffers/array.h
index d4b73fc..ec34dee 100644
--- a/include/flatbuffers/array.h
+++ b/include/flatbuffers/array.h
@@ -35,7 +35,7 @@
  public:
   typedef uint16_t size_type;
   typedef typename IndirectHelper<IndirectHelperType>::return_type return_type;
-  typedef VectorIterator<T, return_type> const_iterator;
+  typedef VectorConstIterator<T, return_type> const_iterator;
   typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
 
   // If T is a LE-scalar or a struct (!scalar_tag::value).
diff --git a/include/flatbuffers/buffer.h b/include/flatbuffers/buffer.h
index ca005f7..96ae538 100644
--- a/include/flatbuffers/buffer.h
+++ b/include/flatbuffers/buffer.h
@@ -76,6 +76,9 @@
   static return_type Read(const uint8_t *p, uoffset_t i) {
     return EndianScalar((reinterpret_cast<const T *>(p))[i]);
   }
+  static return_type Read(uint8_t *p, uoffset_t i) {
+    return Read(const_cast<const uint8_t *>(p), i);
+  }
 };
 template<typename T> struct IndirectHelper<Offset<T>> {
   typedef const T *return_type;
@@ -85,13 +88,20 @@
     p += i * sizeof(uoffset_t);
     return reinterpret_cast<return_type>(p + ReadScalar<uoffset_t>(p));
   }
+  static mutable_return_type Read(uint8_t *p, uoffset_t i) {
+    p += i * sizeof(uoffset_t);
+    return reinterpret_cast<mutable_return_type>(p + ReadScalar<uoffset_t>(p));
+  }
 };
 template<typename T> struct IndirectHelper<const T *> {
   typedef const T *return_type;
   typedef T *mutable_return_type;
   static const size_t element_stride = sizeof(T);
   static return_type Read(const uint8_t *p, uoffset_t i) {
-    return reinterpret_cast<const T *>(p + i * sizeof(T));
+    return reinterpret_cast<return_type>(p + i * sizeof(T));
+  }
+  static mutable_return_type Read(uint8_t *p, uoffset_t i) {
+    return reinterpret_cast<mutable_return_type>(p + i * sizeof(T));
   }
 };
 
diff --git a/include/flatbuffers/vector.h b/include/flatbuffers/vector.h
index 6bcdfe2..9cb6a2d 100644
--- a/include/flatbuffers/vector.h
+++ b/include/flatbuffers/vector.h
@@ -27,14 +27,15 @@
 
 // An STL compatible iterator implementation for Vector below, effectively
 // calling Get() for every element.
-template<typename T, typename IT> struct VectorIterator {
+template<typename T, typename IT, typename Data = uint8_t *>
+struct VectorIterator {
   typedef std::random_access_iterator_tag iterator_category;
   typedef IT value_type;
   typedef ptrdiff_t difference_type;
   typedef IT *pointer;
   typedef IT &reference;
 
-  VectorIterator(const uint8_t *data, uoffset_t i)
+  VectorIterator(Data data, uoffset_t i)
       : data_(data + IndirectHelper<T>::element_stride * i) {}
   VectorIterator(const VectorIterator &other) : data_(other.data_) {}
   VectorIterator() : data_(nullptr) {}
@@ -116,9 +117,12 @@
   }
 
  private:
-  const uint8_t *data_;
+  Data data_;
 };
 
+template<typename T, typename IT>
+using VectorConstIterator = VectorIterator<T, IT, const uint8_t *>;
+
 template<typename Iterator>
 struct VectorReverseIterator : public std::reverse_iterator<Iterator> {
   explicit VectorReverseIterator(Iterator iter)
@@ -145,7 +149,7 @@
  public:
   typedef VectorIterator<T, typename IndirectHelper<T>::mutable_return_type>
       iterator;
-  typedef VectorIterator<T, typename IndirectHelper<T>::return_type>
+  typedef VectorConstIterator<T, typename IndirectHelper<T>::return_type>
       const_iterator;
   typedef VectorReverseIterator<iterator> reverse_iterator;
   typedef VectorReverseIterator<const_iterator> const_reverse_iterator;
diff --git a/tests/monster_test.cpp b/tests/monster_test.cpp
index 4fc9e14..6e810dd 100644
--- a/tests/monster_test.cpp
+++ b/tests/monster_test.cpp
@@ -439,6 +439,16 @@
   TEST_EQ(first->hp(), 0);
   first->mutate_hp(1000);
 
+  // Test for each loop over mutable entries
+  for (auto item: *tables)
+  {
+    TEST_EQ(item->hp(), 1000);
+    item->mutate_hp(0);
+    TEST_EQ(item->hp(), 0);
+    item->mutate_hp(1000);
+    break; // one iteration is enough, just testing compilation
+  }
+
   // Mutate via LookupByKey
   TEST_NOTNULL(tables->MutableLookupByKey("Barney"));
   TEST_EQ(static_cast<Monster *>(nullptr),