/* -*- 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/. */ #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 class FastFrontRemovableArray { using InternalList = AutoTArray; public: static const size_t NoIndex = InternalList::NoIndex; operator Span() const { return AsSpan(); } operator Span() { return AsSpan(); } Span AsSpan() const { return Span(mList).From(mIndexOfFirstElement); } Span AsSpan() { return Span(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 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 void AppendElement(U* aElem) { mList.AppendElement(aElem); } template bool RemoveElement(const Item& aItem) { auto i = IndexOf(aItem); if (i == NoIndex) { return false; } RemoveElementAt(i); return true; } template bool Contains(const Item& aItem) const { return IndexOf(aItem) != NoIndex; } void Clear() { mList.Clear(); mIndexOfFirstElement = 0; } template 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 mList; size_t mIndexOfFirstElement = 0; }; template inline void ImplCycleCollectionUnlink( FastFrontRemovableArray& aField) { aField.Clear(); } template inline void ImplCycleCollectionIndexedContainer( FastFrontRemovableArray& aField, Callback&& aCallback) { for (auto& value : aField.AsSpan()) { aCallback(value); } } } // namespace mozilla::dom #endif