/* 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/. */
#ifndef mozilla_dom_FastFrontRemovableArray_h
#define mozilla_dom_FastFrontRemovableArray_h
// An nsTArray of pointers where removing from the front is amortized constant
// time.
#include "mozilla/Span.h"
#include "nsTArray.h"
namespace mozilla::dom {
template <typename T, size_t InlineCapacity =
0>
class FastFrontRemovableArray {
using InternalList = AutoTArray<T, InlineCapacity>;
public:
static const size_t NoIndex = InternalList::NoIndex;
operator Span<
const T>()
const {
return AsSpan(); }
operator Span<T>() {
return AsSpan(); }
Span<
const T> AsSpan()
const {
return Span<
const T>(mList).From(mIndexOfFirstElement);
}
Span<T> AsSpan() {
return Span<T>(mList).From(mIndexOfFirstElement); }
size_t Length()
const {
return mList.Length() - mIndexOfFirstElement; }
bool IsEmpty()
const {
return Length() ==
0; }
void RemoveElementAt(size_t aIndex) {
if (aIndex ==
0) {
mList[mIndexOfFirstElement++] = nullptr;
if (mIndexOfFirstElement > std::max(size_t(
4), mList.Length() /
4)) {
// Compact the list if it gets too big. This shifts all the elements,
// which is expensive, so only do it if we have more than 4 elements
// wasted at the front, and more than a quarter of the list is wasted
// space in the front.
mList.RemoveElementsAt(
0, mIndexOfFirstElement);
mIndexOfFirstElement =
0;
}
return;
}
mList.RemoveElementAt(aIndex + mIndexOfFirstElement);
if (IsEmpty()) {
Clear();
}
}
template <typename U>
void InsertElementAt(size_t aIndex, U* aElem) {
if (mIndexOfFirstElement && aIndex ==
0) {
mList[--mIndexOfFirstElement] = aElem;
return;
}
mList.InsertElementAt(aIndex + mIndexOfFirstElement, aElem);
}
T&
operator[](size_t aIndex) {
return mList[aIndex + mIndexOfFirstElement]; }
const T&
operator[](size_t aIndex)
const {
return mList[aIndex + mIndexOfFirstElement];
}
T& ElementAt(size_t aIndex) {
return mList[aIndex + mIndexOfFirstElement]; }
const T& ElementAt(size_t aIndex)
const {
return mList[aIndex + mIndexOfFirstElement];
}
T& SafeElementAt(size_t aIndex, T& aDef) {
return mList.SafeElementAt(aIndex + mIndexOfFirstElement, aDef);
}
const T& SafeElementAt(size_t aIndex,
const T& aDef)
const {
return mList.SafeElementAt(aIndex + mIndexOfFirstElement, aDef);
}
const T& FirstElement()
const {
return ElementAt(
0); }
const T& LastElement()
const {
return mList.LastElement(); }
T& FirstElement() {
return ElementAt(
0); }
T& LastElement() {
return mList.LastElement(); }
template <typename U>
void AppendElement(U* aElem) {
mList.AppendElement(aElem);
}
template <typename Item>
bool RemoveElement(
const Item& aItem) {
auto i = IndexOf(aItem);
if (i == NoIndex) {
return false;
}
RemoveElementAt(i);
return true;
}
template <typename Item>
bool Contains(
const Item& aItem)
const {
return IndexOf(aItem) != NoIndex;
}
void Clear() {
mList.Clear();
mIndexOfFirstElement =
0;
}
template <typename Item>
size_t IndexOf(
const Item& aItem)
const {
auto index = mList.IndexOf(aItem, mIndexOfFirstElement);
if (index == NoIndex || mIndexOfFirstElement ==
0) {
return index;
}
return index - mIndexOfFirstElement;
}
private:
AutoTArray<T, InlineCapacity> mList;
size_t mIndexOfFirstElement =
0;
};
template <typename T, size_t InlineCap>
inline void ImplCycleCollectionUnlink(
FastFrontRemovableArray<T, InlineCap>& aField) {
aField.Clear();
}
template <typename T, size_t InlineCap, typename Callback>
inline void ImplCycleCollectionIndexedContainer(
FastFrontRemovableArray<T, InlineCap>& aField, Callback&& aCallback) {
for (
auto& value : aField.AsSpan()) {
aCallback(value);
}
}
}
// namespace mozilla::dom
#endif