DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (01032a31b2e2)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166
/* -*- 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 {

namespace detail {
template <typename T>
struct AddInnerConst;

template <typename T>
struct AddInnerConst<T&> {
  using Type = const T&;
};

template <typename T>
struct AddInnerConst<T*> {
  using Type = const T*;
};

template <typename T>
using AddInnerConstT = typename AddInnerConst<T>::Type;
}  // namespace detail

// 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;
  typedef ArrayIterator<detail::AddInnerConstT<Element>, ArrayType>
      const_iterator_type;

 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;
  }

  constexpr operator const_iterator_type() const {
    return mArray ? const_iterator_type{*mArray, mIndex}
                  : const_iterator_type{};
  }

  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);
  }

  constexpr const array_type* GetArray() const { return mArray; }

  constexpr index_type GetIndex() const { return mIndex; }
};

}  // namespace mozilla

#endif  // mozilla_ArrayIterator_h