Merge pull request #96 from reventlov/fix_iterator_bug

Fix array iterators when the array view is a temporary object.
diff --git a/compiler/back_end/cpp/testcode/auto_array_size_test.cc b/compiler/back_end/cpp/testcode/auto_array_size_test.cc
index 8e03d40..eaae8ec 100644
--- a/compiler/back_end/cpp/testcode/auto_array_size_test.cc
+++ b/compiler/back_end/cpp/testcode/auto_array_size_test.cc
@@ -122,6 +122,22 @@
   });
 }
 
+TEST(AutoSizeView, ForEachWithTemporaries) {
+  auto view = MakeAutoSizeView(kAutoSize, sizeof kAutoSize);
+
+  int i = 0;
+  ::std::for_each(view.four_struct_array().begin(),
+                  view.four_struct_array().end(), [&](ElementView element) {
+                    ASSERT_TRUE(element.Equals(view.four_struct_array()[i++]));
+                  });
+
+  i = view.four_struct_array().ElementCount() - 1;
+  ::std::for_each(view.four_struct_array().rbegin(),
+                  view.four_struct_array().rend(), [&](ElementView element) {
+                    ASSERT_TRUE(element.Equals(view.four_struct_array()[i--]));
+                  });
+}
+
 TEST(AutoSizeView, Find) {
   auto view = MakeAutoSizeView(kAutoSize, sizeof kAutoSize).four_struct_array();
 
diff --git a/runtime/cpp/emboss_array_view.h b/runtime/cpp/emboss_array_view.h
index 79c6268..7287fce 100644
--- a/runtime/cpp/emboss_array_view.h
+++ b/runtime/cpp/emboss_array_view.h
@@ -50,9 +50,9 @@
   using pointer = typename ::std::add_pointer<value_type>::type;
   using reference = typename ::std::add_lvalue_reference<value_type>::type;
 
-  explicit ElementViewIterator(const GenericArrayView *array_view,
+  explicit ElementViewIterator(const GenericArrayView array_view,
                                ::std::ptrdiff_t index)
-      : array_view_(array_view), view_((*array_view)[index]), index_(index) {}
+      : array_view_(array_view), view_(array_view[index]), index_(index) {}
 
   ElementViewIterator() = default;
 
@@ -62,7 +62,7 @@
 
   ElementViewIterator &operator+=(difference_type d) {
     index_ += (kDirection == ElementViewIteratorDirection::kForward ? d : -d);
-    view_ = (*array_view_)[index_];
+    view_ = array_view_[index_];
     return *this;
   }
 
@@ -135,7 +135,7 @@
   }
 
  private:
-  const GenericArrayView *array_view_;
+  const GenericArrayView array_view_;
   typename GenericArrayView::ViewType view_;
   ::std::ptrdiff_t index_;
 };
@@ -179,12 +179,12 @@
                                                     index);
   }
 
-  ForwardIterator begin() const { return ForwardIterator(this, 0); }
-  ForwardIterator end() const { return ForwardIterator(this, ElementCount()); }
+  ForwardIterator begin() const { return ForwardIterator(*this, 0); }
+  ForwardIterator end() const { return ForwardIterator(*this, ElementCount()); }
   ReverseIterator rbegin() const {
-    return ReverseIterator(this, ElementCount() - 1);
+    return ReverseIterator(*this, ElementCount() - 1);
   }
-  ReverseIterator rend() const { return ReverseIterator(this, -1); }
+  ReverseIterator rend() const { return ReverseIterator(*this, -1); }
 
   // In order to selectively enable SizeInBytes and SizeInBits, it is
   // necessary to make them into templates.  Further, it is necessary for
@@ -262,6 +262,10 @@
     return BackingStorage().template ToString<String>();
   }
 
+  bool operator==(const GenericArrayView &other) const {
+    return parameters_ == other.parameters_ && buffer_ == other.buffer_;
+  }
+
  private:
   // This uses the same technique to select the correct definition of
   // SizeOfBuffer() as in the SizeInBits()/SizeInBytes() selection above.
diff --git a/runtime/cpp/emboss_memory_util.h b/runtime/cpp/emboss_memory_util.h
index 49f4287..4195e99 100644
--- a/runtime/cpp/emboss_memory_util.h
+++ b/runtime/cpp/emboss_memory_util.h
@@ -438,6 +438,35 @@
       : bytes_{reinterpret_cast<Byte *>(other.data())},
         size_{other.SizeInBytes()} {}
 
+  // Compare a ContiguousBuffers to another, compatible ContiguousBuffer.
+  template <typename OtherByte, ::std::size_t kOtherAlignment,
+            ::std::size_t kOtherOffset,
+            typename = typename ::std::enable_if<
+                kOtherAlignment % kAlignment == 0 &&
+                kOtherOffset % kAlignment ==
+                    kOffset && ::std::is_same<
+                        typename AddSourceCV<OtherByte, Byte>::Type,
+                        Byte>::value>::type>
+  bool operator==(const ContiguousBuffer<OtherByte, kOtherAlignment,
+                                         kOtherOffset> &other) const {
+    return bytes_ == reinterpret_cast<Byte *>(other.data()) &&
+           size_ == other.SizeInBytes();
+  }
+
+  // Compare a ContiguousBuffers to another, compatible ContiguousBuffer.
+  template <typename OtherByte, ::std::size_t kOtherAlignment,
+            ::std::size_t kOtherOffset,
+            typename = typename ::std::enable_if<
+                kOtherAlignment % kAlignment == 0 &&
+                kOtherOffset % kAlignment ==
+                    kOffset && ::std::is_same<
+                        typename AddSourceCV<OtherByte, Byte>::Type,
+                        Byte>::value>::type>
+  bool operator!=(const ContiguousBuffer<OtherByte, kOtherAlignment,
+                                         kOtherOffset> &other) const {
+    return !(*this == other);
+  }
+
   // Assignment from a compatible ContiguousBuffer.
   template <typename OtherByte, ::std::size_t kOtherAlignment,
             ::std::size_t kOtherOffset,
diff --git a/runtime/cpp/emboss_text_util.h b/runtime/cpp/emboss_text_util.h
index 500d828..ac2e1d9 100644
--- a/runtime/cpp/emboss_text_util.h
+++ b/runtime/cpp/emboss_text_util.h
@@ -19,6 +19,7 @@
 #include <array>
 #include <climits>
 #include <cmath>
+#include <cstdint>
 #include <cstdio>
 #include <cstring>
 #include <limits>