Bug 1342303 part 1 - Make nsTArrayIterator an independent class. r=erahm
☠☠ backed out by b0b40ce3dfe5 ☠ ☠
authorXidorn Quan <me@upsuper.org>
Fri, 24 Feb 2017 16:14:06 +1100
changeset 394655 b5de1dfff82f40c9cfdba333b7380861f1f373ce
parent 394654 e8a2f3d55415f5be5abb3b0e6a4ff76e08e4d39a
child 394656 5c6042dee665597e1e21697e0a1de7a2aab60d55
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerserahm
bugs1342303
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1342303 part 1 - Make nsTArrayIterator an independent class. r=erahm MozReview-Commit-ID: LbkIGEH0Irl
xpcom/ds/ArrayIterator.h
xpcom/ds/moz.build
xpcom/ds/nsTArray.h
new file mode 100644
--- /dev/null
+++ b/xpcom/ds/ArrayIterator.h
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Common iterator implementation for array classes e.g. nsTArray.
+
+#ifndef mozilla_ArrayIterator_h
+#define mozilla_ArrayIterator_h
+
+#include <iterator>
+
+#include "mozilla/TypeTraits.h"
+
+namespace mozilla {
+
+// We have implemented a custom iterator class for array rather than using
+// raw pointers into the backing storage to improve the safety of C++11-style
+// range based iteration in the presence of array mutation, or script execution
+// (bug 1299489).
+//
+// Mutating an array which is being iterated is still wrong, and will either
+// cause elements to be missed or firefox to crash, but will not trigger memory
+// safety problems due to the release-mode bounds checking found in ElementAt.
+//
+// Dereferencing this iterator returns type Element. When Element is a reference
+// type, this iterator implements the full standard random access iterator spec,
+// and can be treated in many ways as though it is a pointer. Otherwise, it is
+// just enough to be used in range-based for loop.
+template<class Element, class ArrayType>
+class ArrayIterator
+{
+public:
+  typedef ArrayType                               array_type;
+  typedef ArrayIterator<Element, ArrayType>       iterator_type;
+  typedef typename array_type::index_type         index_type;
+  typedef typename RemoveReference<Element>::Type value_type;
+  typedef ptrdiff_t                               difference_type;
+  typedef value_type*                             pointer;
+  typedef value_type&                             reference;
+  typedef std::random_access_iterator_tag         iterator_category;
+
+private:
+  const array_type* mArray;
+  index_type mIndex;
+
+public:
+  ArrayIterator() : mArray(nullptr), mIndex(0) {}
+  ArrayIterator(const iterator_type& aOther)
+    : mArray(aOther.mArray), mIndex(aOther.mIndex) {}
+  ArrayIterator(const array_type& aArray, index_type aIndex)
+    : mArray(&aArray), mIndex(aIndex) {}
+
+  iterator_type& operator=(const iterator_type& aOther) {
+    mArray = aOther.mArray;
+    mIndex = aOther.mIndex;
+    return *this;
+  }
+
+  bool operator==(const iterator_type& aRhs) const {
+    return mIndex == aRhs.mIndex;
+  }
+  bool operator!=(const iterator_type& aRhs) const {
+    return !(*this == aRhs);
+  }
+  bool operator<(const iterator_type& aRhs) const {
+    return mIndex < aRhs.mIndex;
+  }
+  bool operator>(const iterator_type& aRhs) const {
+    return mIndex > aRhs.mIndex;
+  }
+  bool operator<=(const iterator_type& aRhs) const {
+    return mIndex <= aRhs.mIndex;
+  }
+  bool operator>=(const iterator_type& aRhs) const {
+    return mIndex >= aRhs.mIndex;
+  }
+
+  // These operators depend on the release mode bounds checks in
+  // ArrayIterator::ElementAt for safety.
+  value_type* operator->() const {
+    return const_cast<value_type*>(&mArray->ElementAt(mIndex));
+  }
+  Element operator*() const {
+    return const_cast<Element>(mArray->ElementAt(mIndex));
+  }
+
+  iterator_type& operator++() {
+    ++mIndex;
+    return *this;
+  }
+  iterator_type operator++(int) {
+    iterator_type it = *this;
+    ++*this;
+    return it;
+  }
+  iterator_type& operator--() {
+    --mIndex;
+    return *this;
+  }
+  iterator_type operator--(int) {
+    iterator_type it = *this;
+    --*this;
+    return it;
+  }
+
+  iterator_type& operator+=(difference_type aDiff) {
+    mIndex += aDiff;
+    return *this;
+  }
+  iterator_type& operator-=(difference_type aDiff) {
+    mIndex -= aDiff;
+    return *this;
+  }
+
+  iterator_type operator+(difference_type aDiff) const {
+    iterator_type it = *this;
+    it += aDiff;
+    return it;
+  }
+  iterator_type operator-(difference_type aDiff) const {
+    iterator_type it = *this;
+    it -= aDiff;
+    return it;
+  }
+
+  difference_type operator-(const iterator_type& aOther) const {
+    return static_cast<difference_type>(mIndex) -
+      static_cast<difference_type>(aOther.mIndex);
+  }
+
+  Element operator[](difference_type aIndex) const {
+    return *this->operator+(aIndex);
+  }
+};
+
+} // namespace mozilla
+
+#endif // mozilla_ArrayIterator_h
--- a/xpcom/ds/moz.build
+++ b/xpcom/ds/moz.build
@@ -78,16 +78,17 @@ EXPORTS += [
     'nsTObserverArray.h',
     'nsTPriorityQueue.h',
     'nsVariant.h',
     'nsWhitespaceTokenizer.h',
     'PLDHashTable.h',
 ]
 
 EXPORTS.mozilla += [
+    'ArrayIterator.h',
     'IncrementalTokenizer.h',
     'Observer.h',
     'StickyTimeDuration.h',
     'Tokenizer.h',
 ]
 
 UNIFIED_SOURCES += [
     'IncrementalTokenizer.cpp',
--- a/xpcom/ds/nsTArray.h
+++ b/xpcom/ds/nsTArray.h
@@ -4,16 +4,17 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsTArray_h__
 #define nsTArray_h__
 
 #include "nsTArrayForwardDeclare.h"
 #include "mozilla/Alignment.h"
+#include "mozilla/ArrayIterator.h"
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/BinarySearch.h"
 #include "mozilla/fallible.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/Move.h"
 #include "mozilla/ReverseIterator.h"
@@ -26,17 +27,16 @@
 #include "nscore.h"
 #include "nsQuickSort.h"
 #include "nsDebug.h"
 #include "nsISupportsImpl.h"
 #include "nsRegionFwd.h"
 #include <functional>
 #include <initializer_list>
 #include <new>
-#include <iterator>
 
 namespace JS {
 template<class T>
 class Heap;
 } /* namespace JS */
 
 class nsRegion;
 namespace mozilla {
@@ -352,134 +352,16 @@ struct nsTArray_SafeElementAtHelper<mozi
   {
     if (aIndex < static_cast<const Derived*>(this)->Length()) {
       return static_cast<const Derived*>(this)->ElementAt(aIndex);
     }
     return nullptr;
   }
 };
 
-// We have implemented a custom iterator class for nsTArray rather than using
-// raw pointers into the backing storage to improve the safety of C++11-style
-// range based iteration in the presence of array mutation, or script execution
-// (bug 1299489).
-//
-// Mutating an array which is being iterated is still wrong, and will either
-// cause elements to be missed or firefox to crash, but will not trigger memory
-// safety problems due to the release-mode bounds checking found in ElementAt.
-//
-// This iterator implements the full standard random access iterator spec, and
-// can be treated in may ways as though it is a pointer.
-template<class Element>
-class nsTArrayIterator
-{
-public:
-  typedef nsTArray<typename mozilla::RemoveConst<Element>::Type> array_type;
-  typedef nsTArrayIterator<Element>       iterator_type;
-  typedef typename array_type::index_type index_type;
-  typedef Element                         value_type;
-  typedef ptrdiff_t                       difference_type;
-  typedef value_type*                     pointer;
-  typedef value_type&                     reference;
-  typedef std::random_access_iterator_tag iterator_category;
-
-private:
-  const array_type* mArray;
-  index_type mIndex;
-
-public:
-  nsTArrayIterator() : mArray(nullptr), mIndex(0) {}
-  nsTArrayIterator(const iterator_type& aOther)
-    : mArray(aOther.mArray), mIndex(aOther.mIndex) {}
-  nsTArrayIterator(const array_type& aArray, index_type aIndex)
-    : mArray(&aArray), mIndex(aIndex) {}
-
-  iterator_type& operator=(const iterator_type& aOther) {
-    mArray = aOther.mArray;
-    mIndex = aOther.mIndex;
-    return *this;
-  }
-
-  bool operator==(const iterator_type& aRhs) const {
-    return mIndex == aRhs.mIndex;
-  }
-  bool operator!=(const iterator_type& aRhs) const {
-    return !(*this == aRhs);
-  }
-  bool operator<(const iterator_type& aRhs) const {
-    return mIndex < aRhs.mIndex;
-  }
-  bool operator>(const iterator_type& aRhs) const {
-    return mIndex > aRhs.mIndex;
-  }
-  bool operator<=(const iterator_type& aRhs) const {
-    return mIndex <= aRhs.mIndex;
-  }
-  bool operator>=(const iterator_type& aRhs) const {
-    return mIndex >= aRhs.mIndex;
-  }
-
-  // These operators depend on the release mode bounds checks in
-  // nsTArray::ElementAt for safety.
-  value_type* operator->() const {
-    return const_cast<value_type*>(&(*mArray)[mIndex]);
-  }
-  value_type& operator*() const {
-    return const_cast<value_type&>((*mArray)[mIndex]);
-  }
-
-  iterator_type& operator++() {
-    ++mIndex;
-    return *this;
-  }
-  iterator_type operator++(int) {
-    iterator_type it = *this;
-    ++*this;
-    return it;
-  }
-  iterator_type& operator--() {
-    --mIndex;
-    return *this;
-  }
-  iterator_type operator--(int) {
-    iterator_type it = *this;
-    --*this;
-    return it;
-  }
-
-  iterator_type& operator+=(difference_type aDiff) {
-    mIndex += aDiff;
-    return *this;
-  }
-  iterator_type& operator-=(difference_type aDiff) {
-    mIndex -= aDiff;
-    return *this;
-  }
-
-  iterator_type operator+(difference_type aDiff) const {
-    iterator_type it = *this;
-    it += aDiff;
-    return it;
-  }
-  iterator_type operator-(difference_type aDiff) const {
-    iterator_type it = *this;
-    it -= aDiff;
-    return it;
-  }
-
-  difference_type operator-(const iterator_type& aOther) const {
-    return static_cast<difference_type>(mIndex) -
-      static_cast<difference_type>(aOther.mIndex);
-  }
-
-  value_type& operator[](difference_type aIndex) const {
-    return *this->operator+(aIndex);
-  }
-};
-
 // Servo bindings.
 extern "C" void Gecko_EnsureTArrayCapacity(void* aArray,
                                            size_t aCapacity,
                                            size_t aElementSize);
 extern "C" void Gecko_ClearPODTArray(void* aArray,
                                      size_t aElementSize,
                                      size_t aElementAlign);
 
@@ -973,18 +855,18 @@ public:
   typedef typename nsTArray_CopyChooser<E>::Type     copy_type;
   typedef nsTArray_base<Alloc, copy_type>            base_type;
   typedef typename base_type::size_type              size_type;
   typedef typename base_type::index_type             index_type;
   typedef E                                          elem_type;
   typedef nsTArray_Impl<E, Alloc>                    self_type;
   typedef nsTArrayElementTraits<E>                   elem_traits;
   typedef nsTArray_SafeElementAtHelper<E, self_type> safeelementat_helper_type;
-  typedef nsTArrayIterator<elem_type>                iterator;
-  typedef nsTArrayIterator<const elem_type>          const_iterator;
+  typedef mozilla::ArrayIterator<elem_type&, nsTArray<E>>       iterator;
+  typedef mozilla::ArrayIterator<const elem_type&, nsTArray<E>> const_iterator;
   typedef mozilla::ReverseIterator<iterator>         reverse_iterator;
   typedef mozilla::ReverseIterator<const_iterator>   const_reverse_iterator;
 
   using safeelementat_helper_type::SafeElementAt;
   using base_type::EmptyHdr;
 
   // A special value that is used to indicate an invalid or unknown index
   // into the array.