gecko-dev/xpcom/ds/ArrayIterator.h

138 строки
4.1 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 "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