1 // Copyright 2020 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef V8_ZONE_ZONE_LIST_H_ 6 #define V8_ZONE_ZONE_LIST_H_ 7 8 #include "src/base/logging.h" 9 #include "src/zone/zone.h" 10 11 namespace v8 { 12 namespace internal { 13 14 template <typename T> 15 class Vector; 16 17 // ZoneLists are growable lists with constant-time access to the elements. 18 // The list itself and all its elements are supposed to be allocated in zone 19 // memory. Unlike ZoneVector container, the ZoneList instance has minimal 20 // possible size which makes it a good candidate for embedding into other 21 // often-allocated zone objects. 22 // 23 // Note, ZoneLists' elements cannot be deleted individually and the destructor 24 // intentionally does not free the backing store. Because of the latter, the 25 // ZoneList must not be used outsize of zone memory. Consider using ZoneVector 26 // or other containers instead. 27 template <typename T> 28 class ZoneList final : public ZoneObject { 29 public: 30 // Construct a new ZoneList with the given capacity; the length is 31 // always zero. The capacity must be non-negative. ZoneList(int capacity,Zone * zone)32 ZoneList(int capacity, Zone* zone) : capacity_(capacity) { 33 DCHECK_GE(capacity, 0); 34 data_ = (capacity_ > 0) ? zone->NewArray<T>(capacity_) : nullptr; 35 } 36 37 // Construct a new ZoneList by copying the elements of the given ZoneList. ZoneList(const ZoneList<T> & other,Zone * zone)38 ZoneList(const ZoneList<T>& other, Zone* zone) 39 : ZoneList(other.length(), zone) { 40 AddAll(other, zone); 41 } 42 43 // Construct a new ZoneList by copying the elements of the given vector. ZoneList(const Vector<const T> & other,Zone * zone)44 ZoneList(const Vector<const T>& other, Zone* zone) 45 : ZoneList(other.length(), zone) { 46 AddAll(other, zone); 47 } 48 ZoneList(ZoneList<T> && other)49 ZoneList(ZoneList<T>&& other) V8_NOEXCEPT { *this = std::move(other); } 50 51 // The ZoneList objects are usually allocated as a fields in other 52 // zone-allocated objects for which destructors are not called anyway, so 53 // we are not going to clear the memory here as well. 54 ~ZoneList() = default; 55 56 ZoneList& operator=(ZoneList&& other) V8_NOEXCEPT { 57 // We don't have a Zone object, so we'll have to drop the data_ array. 58 // If this assert ever fails, consider calling Clear(Zone*) or 59 // DropAndClear() before the move assignment to make it explicit what's 60 // happenning with the lvalue. 61 DCHECK_NULL(data_); 62 data_ = other.data_; 63 capacity_ = other.capacity_; 64 length_ = other.length_; 65 other.DropAndClear(); 66 return *this; 67 } 68 69 // Returns a reference to the element at index i. This reference is not safe 70 // to use after operations that can change the list's backing store 71 // (e.g. Add). 72 inline T& operator[](int i) const { 73 DCHECK_LE(0, i); 74 DCHECK_GT(static_cast<unsigned>(length_), static_cast<unsigned>(i)); 75 return data_[i]; 76 } at(int i)77 inline T& at(int i) const { return operator[](i); } last()78 inline T& last() const { return at(length_ - 1); } first()79 inline T& first() const { return at(0); } 80 81 using iterator = T*; begin()82 inline iterator begin() { return &data_[0]; } end()83 inline iterator end() { return &data_[length_]; } 84 85 using const_iterator = const T*; begin()86 inline const_iterator begin() const { return &data_[0]; } end()87 inline const_iterator end() const { return &data_[length_]; } 88 is_empty()89 V8_INLINE bool is_empty() const { return length_ == 0; } length()90 V8_INLINE int length() const { return length_; } capacity()91 V8_INLINE int capacity() const { return capacity_; } 92 ToVector()93 Vector<T> ToVector() const { return Vector<T>(data_, length_); } ToVector(int start,int length)94 Vector<T> ToVector(int start, int length) const { 95 DCHECK_LE(start, length_); 96 return Vector<T>(&data_[start], std::min(length_ - start, length)); 97 } 98 ToConstVector()99 Vector<const T> ToConstVector() const { 100 return Vector<const T>(data_, length_); 101 } 102 103 // Adds a copy of the given 'element' to the end of the list, 104 // expanding the list if necessary. 105 void Add(const T& element, Zone* zone); 106 // Add all the elements from the argument list to this list. 107 void AddAll(const ZoneList<T>& other, Zone* zone); 108 // Add all the elements from the vector to this list. 109 void AddAll(const Vector<const T>& other, Zone* zone); 110 // Inserts the element at the specific index. 111 void InsertAt(int index, const T& element, Zone* zone); 112 113 // Added 'count' elements with the value 'value' and returns a 114 // vector that allows access to the elements. The vector is valid 115 // until the next change is made to this list. 116 Vector<T> AddBlock(T value, int count, Zone* zone); 117 118 // Overwrites the element at the specific index. 119 void Set(int index, const T& element); 120 121 // Removes the i'th element without deleting it even if T is a 122 // pointer type; moves all elements above i "down". Returns the 123 // removed element. This function's complexity is linear in the 124 // size of the list. 125 T Remove(int i); 126 127 // Removes the last element without deleting it even if T is a 128 // pointer type. Returns the removed element. RemoveLast()129 V8_INLINE T RemoveLast() { return Remove(length_ - 1); } 130 131 // Clears the list by freeing the storage memory. If you want to keep the 132 // memory, use Rewind(0) instead. Be aware, that even if T is a 133 // pointer type, clearing the list doesn't delete the entries. 134 V8_INLINE void Clear(Zone* zone); 135 136 // Clears the list but unlike Clear(), it doesn't free the storage memory. 137 // It's useful when the whole zone containing the backing store will be 138 // released but the list will be used further. DropAndClear()139 V8_INLINE void DropAndClear() { 140 data_ = nullptr; 141 capacity_ = 0; 142 length_ = 0; 143 } 144 145 // Drops all but the first 'pos' elements from the list. 146 V8_INLINE void Rewind(int pos); 147 Contains(const T & elm)148 inline bool Contains(const T& elm) const { 149 for (int i = 0; i < length_; i++) { 150 if (data_[i] == elm) return true; 151 } 152 return false; 153 } 154 155 // Iterate through all list entries, starting at index 0. 156 template <class Visitor> 157 void Iterate(Visitor* visitor); 158 159 // Sort all list entries (using QuickSort) 160 template <typename CompareFunction> 161 void Sort(CompareFunction cmp); 162 template <typename CompareFunction> 163 void StableSort(CompareFunction cmp, size_t start, size_t length); 164 165 private: 166 T* data_ = nullptr; 167 int capacity_ = 0; 168 int length_ = 0; 169 170 // Increase the capacity of a full list, and add an element. 171 // List must be full already. 172 void ResizeAdd(const T& element, Zone* zone); 173 174 // Inlined implementation of ResizeAdd, shared by inlined and 175 // non-inlined versions of ResizeAdd. 176 void ResizeAddInternal(const T& element, Zone* zone); 177 178 // Resize the list. 179 void Resize(int new_capacity, Zone* zone); 180 181 DISALLOW_COPY_AND_ASSIGN(ZoneList); 182 }; 183 184 } // namespace internal 185 } // namespace v8 186 187 #endif // V8_ZONE_ZONE_LIST_H_ 188