Bug 1342303 part 1 - Make nsTArrayIterator an independent class. r=erahm
authorXidorn Quan <me@upsuper.org>
Fri, 24 Feb 2017 16:14:06 +1100
changeset 374736 6de42abcf2c71e8d74312a6587b181ba52fdeca1
parent 374735 81d219527dbe7143c71cbce2fc3c1ecca41a0f5d
child 374737 b1df335e52e42cf261e5dcb5c9f6aeb735875f9d
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerserahm
bugs1342303
milestone54.0a1
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.