FastFrontRemovableArray.h (4200B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_FastFrontRemovableArray_h 8 #define mozilla_dom_FastFrontRemovableArray_h 9 10 // An nsTArray of pointers where removing from the front is amortized constant 11 // time. 12 13 #include "mozilla/Span.h" 14 #include "nsTArray.h" 15 16 namespace mozilla::dom { 17 18 template <typename T, size_t InlineCapacity = 0> 19 class FastFrontRemovableArray { 20 using InternalList = AutoTArray<T, InlineCapacity>; 21 22 public: 23 static const size_t NoIndex = InternalList::NoIndex; 24 25 operator Span<const T>() const { return AsSpan(); } 26 operator Span<T>() { return AsSpan(); } 27 28 Span<const T> AsSpan() const { 29 return Span<const T>(mList).From(mIndexOfFirstElement); 30 } 31 Span<T> AsSpan() { return Span<T>(mList).From(mIndexOfFirstElement); } 32 33 size_t Length() const { return mList.Length() - mIndexOfFirstElement; } 34 35 bool IsEmpty() const { return Length() == 0; } 36 37 void RemoveElementAt(size_t aIndex) { 38 if (aIndex == 0) { 39 mList[mIndexOfFirstElement++] = nullptr; 40 if (mIndexOfFirstElement > std::max(size_t(4), mList.Length() / 4)) { 41 // Compact the list if it gets too big. This shifts all the elements, 42 // which is expensive, so only do it if we have more than 4 elements 43 // wasted at the front, and more than a quarter of the list is wasted 44 // space in the front. 45 mList.RemoveElementsAt(0, mIndexOfFirstElement); 46 mIndexOfFirstElement = 0; 47 } 48 return; 49 } 50 mList.RemoveElementAt(aIndex + mIndexOfFirstElement); 51 if (IsEmpty()) { 52 Clear(); 53 } 54 } 55 56 template <typename U> 57 void InsertElementAt(size_t aIndex, U* aElem) { 58 if (mIndexOfFirstElement && aIndex == 0) { 59 mList[--mIndexOfFirstElement] = aElem; 60 return; 61 } 62 mList.InsertElementAt(aIndex + mIndexOfFirstElement, aElem); 63 } 64 65 T& operator[](size_t aIndex) { return mList[aIndex + mIndexOfFirstElement]; } 66 67 const T& operator[](size_t aIndex) const { 68 return mList[aIndex + mIndexOfFirstElement]; 69 } 70 T& ElementAt(size_t aIndex) { return mList[aIndex + mIndexOfFirstElement]; } 71 const T& ElementAt(size_t aIndex) const { 72 return mList[aIndex + mIndexOfFirstElement]; 73 } 74 75 T& SafeElementAt(size_t aIndex, T& aDef) { 76 return mList.SafeElementAt(aIndex + mIndexOfFirstElement, aDef); 77 } 78 79 const T& SafeElementAt(size_t aIndex, const T& aDef) const { 80 return mList.SafeElementAt(aIndex + mIndexOfFirstElement, aDef); 81 } 82 83 const T& FirstElement() const { return ElementAt(0); } 84 const T& LastElement() const { return mList.LastElement(); } 85 T& FirstElement() { return ElementAt(0); } 86 T& LastElement() { return mList.LastElement(); } 87 88 template <typename U> 89 void AppendElement(U* aElem) { 90 mList.AppendElement(aElem); 91 } 92 93 template <typename Item> 94 bool RemoveElement(const Item& aItem) { 95 auto i = IndexOf(aItem); 96 if (i == NoIndex) { 97 return false; 98 } 99 RemoveElementAt(i); 100 return true; 101 } 102 103 template <typename Item> 104 bool Contains(const Item& aItem) const { 105 return IndexOf(aItem) != NoIndex; 106 } 107 108 void Clear() { 109 mList.Clear(); 110 mIndexOfFirstElement = 0; 111 } 112 113 template <typename Item> 114 size_t IndexOf(const Item& aItem) const { 115 auto index = mList.IndexOf(aItem, mIndexOfFirstElement); 116 if (index == NoIndex || mIndexOfFirstElement == 0) { 117 return index; 118 } 119 return index - mIndexOfFirstElement; 120 } 121 122 private: 123 AutoTArray<T, InlineCapacity> mList; 124 size_t mIndexOfFirstElement = 0; 125 }; 126 127 template <typename T, size_t InlineCap> 128 inline void ImplCycleCollectionUnlink( 129 FastFrontRemovableArray<T, InlineCap>& aField) { 130 aField.Clear(); 131 } 132 133 template <typename T, size_t InlineCap, typename Callback> 134 inline void ImplCycleCollectionIndexedContainer( 135 FastFrontRemovableArray<T, InlineCap>& aField, Callback&& aCallback) { 136 for (auto& value : aField.AsSpan()) { 137 aCallback(value); 138 } 139 } 140 141 } // namespace mozilla::dom 142 143 #endif