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 345709 6de42abcf2c71e8d74312a6587b181ba52fdeca1
parent 345708 81d219527dbe7143c71cbce2fc3c1ecca41a0f5d
child 345710 b1df335e52e42cf261e5dcb5c9f6aeb735875f9d
push id31443
push usercbook@mozilla.com
push dateFri, 03 Mar 2017 12:01:25 +0000
treeherdermozilla-central@31c09bb63b69 [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.