зеркало из https://github.com/mozilla/gecko-dev.git
166 строки
4.7 KiB
C++
166 строки
4.7 KiB
C++
/* -*- 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 <type_traits>
|
|
|
|
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 std::remove_reference_t<Element> 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
|