/* -*- 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 #include namespace mozilla { namespace detail { template struct AddInnerConst; template struct AddInnerConst { using Type = const T&; }; template struct AddInnerConst { using Type = const T*; }; template using AddInnerConstT = typename AddInnerConst::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 ArrayIterator { public: typedef ArrayType array_type; typedef ArrayIterator iterator_type; typedef typename array_type::index_type index_type; typedef std::remove_reference_t 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, 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(&mArray->ElementAt(mIndex)); } Element operator*() const { return const_cast(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(mIndex) - static_cast(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