// Copyright 2020 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_ZONE_ZONE_LIST_H_ #define V8_ZONE_ZONE_LIST_H_ #include "src/base/logging.h" #include "src/zone/zone.h" namespace v8 { namespace internal { template <typename T> class Vector; // ZoneLists are growable lists with constant-time access to the elements. // The list itself and all its elements are supposed to be allocated in zone // memory. Unlike ZoneVector container, the ZoneList instance has minimal // possible size which makes it a good candidate for embedding into other // often-allocated zone objects. // // Note, ZoneLists' elements cannot be deleted individually and the destructor // intentionally does not free the backing store. Because of the latter, the // ZoneList must not be used outsize of zone memory. Consider using ZoneVector // or other containers instead. template <typename T> class ZoneList final : public ZoneObject { public: // Construct a new ZoneList with the given capacity; the length is // always zero. The capacity must be non-negative. ZoneList(int capacity, Zone* zone) : capacity_(capacity) { DCHECK_GE(capacity, 0); data_ = (capacity_ > 0) ? zone->NewArray<T>(capacity_) : nullptr; } // Construct a new ZoneList by copying the elements of the given ZoneList. ZoneList(const ZoneList<T>& other, Zone* zone) : ZoneList(other.length(), zone) { AddAll(other, zone); } // Construct a new ZoneList by copying the elements of the given vector. ZoneList(const Vector<const T>& other, Zone* zone) : ZoneList(other.length(), zone) { AddAll(other, zone); } ZoneList(ZoneList<T>&& other) V8_NOEXCEPT { *this = std::move(other); } // The ZoneList objects are usually allocated as a fields in other // zone-allocated objects for which destructors are not called anyway, so // we are not going to clear the memory here as well. ~ZoneList() = default; ZoneList& operator=(ZoneList&& other) V8_NOEXCEPT { // We don't have a Zone object, so we'll have to drop the data_ array. // If this assert ever fails, consider calling Clear(Zone*) or // DropAndClear() before the move assignment to make it explicit what's // happenning with the lvalue. DCHECK_NULL(data_); data_ = other.data_; capacity_ = other.capacity_; length_ = other.length_; other.DropAndClear(); return *this; } // Returns a reference to the element at index i. This reference is not safe // to use after operations that can change the list's backing store // (e.g. Add). inline T& operator[](int i) const { DCHECK_LE(0, i); DCHECK_GT(static_cast<unsigned>(length_), static_cast<unsigned>(i)); return data_[i]; } inline T& at(int i) const { return operator[](i); } inline T& last() const { return at(length_ - 1); } inline T& first() const { return at(0); } using iterator = T*; inline iterator begin() { return &data_[0]; } inline iterator end() { return &data_[length_]; } using const_iterator = const T*; inline const_iterator begin() const { return &data_[0]; } inline const_iterator end() const { return &data_[length_]; } V8_INLINE bool is_empty() const { return length_ == 0; } V8_INLINE int length() const { return length_; } V8_INLINE int capacity() const { return capacity_; } Vector<T> ToVector() const { return Vector<T>(data_, length_); } Vector<T> ToVector(int start, int length) const { DCHECK_LE(start, length_); return Vector<T>(&data_[start], std::min(length_ - start, length)); } Vector<const T> ToConstVector() const { return Vector<const T>(data_, length_); } // Adds a copy of the given 'element' to the end of the list, // expanding the list if necessary. void Add(const T& element, Zone* zone); // Add all the elements from the argument list to this list. void AddAll(const ZoneList<T>& other, Zone* zone); // Add all the elements from the vector to this list. void AddAll(const Vector<const T>& other, Zone* zone); // Inserts the element at the specific index. void InsertAt(int index, const T& element, Zone* zone); // Added 'count' elements with the value 'value' and returns a // vector that allows access to the elements. The vector is valid // until the next change is made to this list. Vector<T> AddBlock(T value, int count, Zone* zone); // Overwrites the element at the specific index. void Set(int index, const T& element); // Removes the i'th element without deleting it even if T is a // pointer type; moves all elements above i "down". Returns the // removed element. This function's complexity is linear in the // size of the list. T Remove(int i); // Removes the last element without deleting it even if T is a // pointer type. Returns the removed element. V8_INLINE T RemoveLast() { return Remove(length_ - 1); } // Clears the list by freeing the storage memory. If you want to keep the // memory, use Rewind(0) instead. Be aware, that even if T is a // pointer type, clearing the list doesn't delete the entries. V8_INLINE void Clear(Zone* zone); // Clears the list but unlike Clear(), it doesn't free the storage memory. // It's useful when the whole zone containing the backing store will be // released but the list will be used further. V8_INLINE void DropAndClear() { data_ = nullptr; capacity_ = 0; length_ = 0; } // Drops all but the first 'pos' elements from the list. V8_INLINE void Rewind(int pos); inline bool Contains(const T& elm) const { for (int i = 0; i < length_; i++) { if (data_[i] == elm) return true; } return false; } // Iterate through all list entries, starting at index 0. template <class Visitor> void Iterate(Visitor* visitor); // Sort all list entries (using QuickSort) template <typename CompareFunction> void Sort(CompareFunction cmp); template <typename CompareFunction> void StableSort(CompareFunction cmp, size_t start, size_t length); private: T* data_ = nullptr; int capacity_ = 0; int length_ = 0; // Increase the capacity of a full list, and add an element. // List must be full already. void ResizeAdd(const T& element, Zone* zone); // Inlined implementation of ResizeAdd, shared by inlined and // non-inlined versions of ResizeAdd. void ResizeAddInternal(const T& element, Zone* zone); // Resize the list. void Resize(int new_capacity, Zone* zone); DISALLOW_COPY_AND_ASSIGN(ZoneList); }; } // namespace internal } // namespace v8 #endif // V8_ZONE_ZONE_LIST_H_