#ifndef V8_ZONE_ZONE_CONTAINERS_H_
#define V8_ZONE_ZONE_CONTAINERS_H_
#include <deque>
#include <forward_list>
#include <initializer_list>
#include <iterator>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include "absl/container/btree_map.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "src/base/hashing.h"
#include "src/base/intrusive-set.h"
#include "src/base/small-map.h"
#include "src/base/small-vector.h"
#include "src/zone/zone-allocator.h"
namespace v8 {
namespace internal {
template <typename T>
class ZoneVector {
public:
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<T*>;
using const_reverse_iterator = std::reverse_iterator<const T*>;
using value_type = T;
using reference = T&;
using const_reference = const T&;
using size_type = size_t;
explicit ZoneVector(Zone* zone) : zone_(zone) {}
ZoneVector(size_t size, Zone* zone) : zone_(zone) {
data_ = size > 0 ? zone->AllocateArray<T>(size) : nullptr;
end_ = capacity_ = data_ + size;
for (T* p = data_; p < end_; p++) emplace_at(p);
}
ZoneVector(size_t size, T def, Zone* zone) : zone_(zone) {
data_ = size > 0 ? zone->AllocateArray<T>(size) : nullptr;
end_ = capacity_ = data_ + size;
for (T* p = data_; p < end_; p++) emplace_at(p, def);
}
ZoneVector(std::initializer_list<T> list, Zone* zone) : zone_(zone) {
size_t size = list.size();
if (size > 0) {
data_ = zone->AllocateArray<T>(size);
CopyToNewStorage(data_, list.begin(), list.end());
} else {
data_ = nullptr;
}
end_ = capacity_ = data_ + size;
}
template <class It,
typename = typename std::iterator_traits<It>::iterator_category>
ZoneVector(It first, It last, Zone* zone) : zone_(zone) {
if constexpr (std::is_base_of_v<
std::random_access_iterator_tag,
typename std::iterator_traits<It>::iterator_category>) {
size_t size = last - first;
data_ = size > 0 ? zone->AllocateArray<T>(size) : nullptr;
end_ = capacity_ = data_ + size;
for (T* p = data_; p < end_; p++) emplace_at(p, *first++);
} else {
while (first != last) push_back(*first++);
}
DCHECK_EQ(first, last);
}
ZoneVector(const ZoneVector& other) V8_NOEXCEPT : zone_(other.zone_) {
*this = other;
}
ZoneVector(ZoneVector&& other) V8_NOEXCEPT { *this = std::move(other); }
~ZoneVector() {
for (T* p = data_; p < end_; p++) p->~T();
if (data_) zone_->DeleteArray(data_, capacity());
}
ZoneVector& operator=(const ZoneVector& other) V8_NOEXCEPT {
DCHECK_NE(this, &other);
T* src = other.data_;
if (capacity() >= other.size() && zone_ == other.zone_) {
T* dst = data_;
if constexpr (std::is_trivially_copyable_v<T>) {
size_t size = other.size();
if (size) base::MemCopy(dst, src, size * sizeof(T));
end_ = dst + size;
} else if constexpr (std::is_copy_assignable_v<T>) {
while (dst < end_ && src < other.end_) *dst++ = *src++;
while (src < other.end_) emplace_at(dst++, *src++);
T* old_end = end_;
end_ = dst;
for (T* p = end_; p < old_end; p++) p->~T();
} else {
for (T* p = data_; p < end_; p++) p->~T();
while (src < other.end_) emplace_at(dst++, *src++);
end_ = dst;
}
} else {
for (T* p = data_; p < end_; p++) p->~T();
if (data_) zone_->DeleteArray(data_, capacity());
size_t new_cap = other.capacity();
if (new_cap > 0) {
data_ = zone_->AllocateArray<T>(new_cap);
CopyToNewStorage(data_, other.data_, other.end_);
} else {
data_ = nullptr;
}
capacity_ = data_ + new_cap;
end_ = data_ + other.size();
}
return *this;
}
ZoneVector& operator=(ZoneVector&& other) V8_NOEXCEPT {
DCHECK_NE(this, &other);
if (zone_ == nullptr) {
zone_ = other.zone_;
} else {
DCHECK_EQ(zone_, other.zone_);
}
for (T* p = data_; p < end_; p++) p->~T();
if (data_) zone_->DeleteArray(data_, capacity());
data_ = other.data_;
end_ = other.end_;
capacity_ = other.capacity_;
other.data_ = other.end_ = other.capacity_ = nullptr;
return *this;
}
ZoneVector& operator=(std::initializer_list<T> ilist) {
clear();
EnsureCapacity(ilist.size());
CopyToNewStorage(data_, ilist.begin(), ilist.end());
end_ = data_ + ilist.size();
return *this;
}
base::Vector<T> Release() && {
base::Vector<T> ret = base::VectorOf(*this);
data_ = end_ = capacity_ = nullptr;
return ret;
}
void swap(ZoneVector<T>& other) noexcept {
DCHECK_EQ(zone_, other.zone_);
std::swap(data_, other.data_);
std::swap(end_, other.end_);
std::swap(capacity_, other.capacity_);
}
void resize(size_t new_size) {
EnsureCapacity(new_size);
T* new_end = data_ + new_size;
for (T* p = end_; p < new_end; p++) emplace_at(p);
for (T* p = new_end; p < end_; p++) p->~T();
end_ = new_end;
}
void resize(size_t new_size, const T& value) {
EnsureCapacity(new_size);
T* new_end = data_ + new_size;
for (T* p = end_; p < new_end; p++) emplace_at(p, value);
for (T* p = new_end; p < end_; p++) p->~T();
end_ = new_end;
}
void assign(size_t new_size, const T& value) {
if (capacity() >= new_size) {
T* new_end = data_ + new_size;
T* assignable = data_ + std::min(size(), new_size);
for (T* p = data_; p < assignable; p++) CopyingOverwrite(p, &value);
for (T* p = assignable; p < new_end; p++) CopyToNewStorage(p, &value);
for (T* p = new_end; p < end_; p++) p->~T();
end_ = new_end;
} else {
clear();
EnsureCapacity(new_size);
T* new_end = data_ + new_size;
for (T* p = data_; p < new_end; p++) emplace_at(p, value);
end_ = new_end;
}
}
void clear() {
for (T* p = data_; p < end_; p++) p->~T();
end_ = data_;
}
size_t size() const { return end_ - data_; }
bool empty() const { return end_ == data_; }
size_t capacity() const { return capacity_ - data_; }
void reserve(size_t new_cap) { EnsureCapacity(new_cap); }
T* data() { return data_; }
const T* data() const { return data_; }
Zone* zone() const { return zone_; }
T& at(size_t pos) {
DCHECK_LT(pos, size());
return data_[pos];
}
const T& at(size_t pos) const {
DCHECK_LT(pos, size());
return data_[pos];
}
T& operator[](size_t pos) { return at(pos); }
const T& operator[](size_t pos) const { return at(pos); }
T& front() {
DCHECK_GT(end_, data_);
return *data_;
}
const T& front() const {
DCHECK_GT(end_, data_);
return *data_;
}
T& back() {
DCHECK_GT(end_, data_);
return *(end_ - 1);
}
const T& back() const {
DCHECK_GT(end_, data_);
return *(end_ - 1);
}
T* begin() V8_NOEXCEPT { return data_; }
const T* begin() const V8_NOEXCEPT { return data_; }
const T* cbegin() const V8_NOEXCEPT { return data_; }
T* end() V8_NOEXCEPT { return end_; }
const T* end() const V8_NOEXCEPT { return end_; }
const T* cend() const V8_NOEXCEPT { return end_; }
reverse_iterator rbegin() V8_NOEXCEPT {
return std::make_reverse_iterator(end());
}
const_reverse_iterator rbegin() const V8_NOEXCEPT {
return std::make_reverse_iterator(end());
}
const_reverse_iterator crbegin() const V8_NOEXCEPT {
return std::make_reverse_iterator(cend());
}
reverse_iterator rend() V8_NOEXCEPT {
return std::make_reverse_iterator(begin());
}
const_reverse_iterator rend() const V8_NOEXCEPT {
return std::make_reverse_iterator(begin());
}
const_reverse_iterator crend() const V8_NOEXCEPT {
return std::make_reverse_iterator(cbegin());
}
void push_back(const T& value) {
EnsureOneMoreCapacity();
emplace_at(end_++, value);
}
void push_back(T&& value) { emplace_back(std::move(value)); }
void pop_back() {
DCHECK_GT(end_, data_);
(--end_)->~T();
}
template <typename... Args>
T& emplace_back(Args&&... args) {
EnsureOneMoreCapacity();
T* ptr = end_++;
new (ptr) T(std::forward<Args>(args)...);
return *ptr;
}
template <class It,
typename = typename std::iterator_traits<It>::iterator_category>
T* insert(const T* pos, It first, It last) {
T* position;
if constexpr (std::is_base_of_v<
std::random_access_iterator_tag,
typename std::iterator_traits<It>::iterator_category>) {
DCHECK_LE(0, last - first);
size_t count = last - first;
size_t assignable;
position = PrepareForInsertion(pos, count, &assignable);
if (!base::TryTrivialCopy(first, first + count, position)) {
CopyingOverwrite(position, first, first + assignable);
CopyToNewStorage(position + assignable, first + assignable, last);
}
} else if (pos == end()) {
position = end_;
while (first != last) {
EnsureOneMoreCapacity();
emplace_at(end_++, *first++);
}
} else {
UNIMPLEMENTED();
}
return position;
}
T* insert(const T* pos, size_t count, const T& value) {
size_t assignable;
T* position = PrepareForInsertion(pos, count, &assignable);
T* dst = position;
T* stop = dst + assignable;
while (dst < stop) {
CopyingOverwrite(dst++, &value);
}
stop = position + count;
while (dst < stop) emplace_at(dst++, value);
return position;
}
template <typename... Args>
T* emplace(const T* pos, Args&&... args) {
size_t assignable;
T* dst = PrepareForInsertion(pos, 1, &assignable);
if (assignable == 1) {
dst->~T();
}
emplace_at(dst, args...);
return dst;
}
T* erase(const T* pos) {
DCHECK(data_ <= pos && pos <= end());
if (pos == end()) return const_cast<T*>(pos);
return erase(pos, 1);
}
T* erase(const T* first, const T* last) {
DCHECK(data_ <= first && first <= last && last <= end());
if (first == last) return const_cast<T*>(first);
return erase(first, last - first);
}
private:
static constexpr size_t kMinCapacity = 2;
size_t NewCapacity(size_t minimum) {
size_t new_capacity = data_ == capacity_ ? kMinCapacity : capacity() * 2;
return new_capacity < minimum ? minimum : new_capacity;
}
V8_INLINE void EnsureOneMoreCapacity() {
if (V8_LIKELY(end_ < capacity_)) return;
Grow(capacity() + 1);
}
V8_INLINE void EnsureCapacity(size_t minimum) {
if (V8_LIKELY(minimum <= capacity())) return;
Grow(minimum);
}
V8_INLINE void CopyToNewStorage(T* dst, const T* src) {
emplace_at(dst, *src);
}
V8_INLINE void MoveToNewStorage(T* dst, T* src) {
if constexpr (std::is_move_constructible_v<T>) {
emplace_at(dst, std::move(*src));
} else {
CopyToNewStorage(dst, src);
}
}
V8_INLINE void CopyingOverwrite(T* dst, const T* src) {
if constexpr (std::is_copy_assignable_v<T>) {
*dst = *src;
} else {
dst->~T();
CopyToNewStorage(dst, src);
}
}
V8_INLINE void MovingOverwrite(T* dst, T* src) {
if constexpr (std::is_move_assignable_v<T>) {
*dst = std::move(*src);
} else {
CopyingOverwrite(dst, src);
}
}
V8_INLINE void CopyToNewStorage(T* dst, const T* src, const T* src_end) {
if (base::TryTrivialCopy(src, src_end, dst)) {
return;
}
for (; src < src_end; dst++, src++) {
CopyToNewStorage(dst, src);
}
}
V8_INLINE void MoveToNewStorage(T* dst, T* src, const T* src_end) {
if (base::TryTrivialCopy(src, src_end, dst)) {
return;
}
for (; src < src_end; dst++, src++) {
MoveToNewStorage(dst, src);
src->~T();
}
}
V8_INLINE void CopyingOverwrite(T* dst, const T* src, const T* src_end) {
if (base::TryTrivialMove(src, src_end, dst)) {
return;
}
for (; src < src_end; dst++, src++) {
CopyingOverwrite(dst, src);
}
}
V8_INLINE void MovingOverwrite(T* dst, T* src, const T* src_end) {
if (base::TryTrivialMove(src, src_end, dst)) {
return;
}
for (; src < src_end; dst++, src++) {
MovingOverwrite(dst, src);
}
}
V8_NOINLINE V8_PRESERVE_MOST void Grow(size_t minimum) {
T* old_data = data_;
T* old_end = end_;
size_t old_size = size();
size_t new_capacity = NewCapacity(minimum);
data_ = zone_->AllocateArray<T>(new_capacity);
end_ = data_ + old_size;
if (old_data) {
MoveToNewStorage(data_, old_data, old_end);
zone_->DeleteArray(old_data, capacity_ - old_data);
}
capacity_ = data_ + new_capacity;
}
T* PrepareForInsertion(const T* pos, size_t count, size_t* assignable) {
DCHECK(data_ <= pos && pos <= end_);
CHECK(std::numeric_limits<size_t>::max() - size() >= count);
size_t index = pos - data_;
size_t to_shift = end() - pos;
DCHECK_EQ(index + to_shift, size());
if (capacity() < size() + count) {
*assignable = 0;
T* old_data = data_;
T* old_end = end_;
size_t old_size = size();
size_t new_capacity = NewCapacity(old_size + count);
data_ = zone_->AllocateArray<T>(new_capacity);
end_ = data_ + old_size + count;
if (old_data) {
MoveToNewStorage(data_, old_data, pos);
MoveToNewStorage(data_ + index + count, const_cast<T*>(pos), old_end);
zone_->DeleteArray(old_data, capacity_ - old_data);
}
capacity_ = data_ + new_capacity;
} else {
size_t assignable_slots = std::min(to_shift, count);
*assignable = assignable_slots;
if constexpr (std::is_trivially_copyable_v<T>) {
if (to_shift > 0) {
V8_ASSUME(pos != nullptr);
memmove(const_cast<T*>(pos + count), pos, to_shift * sizeof(T));
}
end_ += count;
return data_ + index;
}
T* dst = end_ + count;
T* src = end_;
for (T* stop = dst - assignable_slots; dst > stop;) {
MoveToNewStorage(--dst, --src);
}
DCHECK_EQ(src > pos, to_shift > count);
DCHECK_IMPLIES(src > pos, dst == end_);
while (src > pos) MovingOverwrite(--dst, --src);
end_ += count;
}
return data_ + index;
}
T* erase(const T* first, size_t count) {
DCHECK(data_ <= first && first <= end());
DCHECK_LE(count, end() - first);
T* position = const_cast<T*>(first);
MovingOverwrite(position, position + count, end());
T* old_end = end();
end_ -= count;
for (T* p = end_; p < old_end; p++) p->~T();
return position;
}
template <typename... Args>
void emplace_at(T* target, Args&&... args) {
new (target) T(std::forward<Args>(args)...);
}
Zone* zone_{nullptr};
T* data_{nullptr};
T* end_{nullptr};
T* capacity_{nullptr};
};
template <class T>
bool operator==(const ZoneVector<T>& lhs, const ZoneVector<T>& rhs) {
return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}
template <class T>
bool operator!=(const ZoneVector<T>& lhs, const ZoneVector<T>& rhs) {
return !(lhs == rhs);
}
template <class T>
bool operator<(const ZoneVector<T>& lhs, const ZoneVector<T>& rhs) {
return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(),
rhs.end());
}
template <class T, class GetIntrusiveSetIndex>
class ZoneIntrusiveSet
: public base::IntrusiveSet<T, GetIntrusiveSetIndex, ZoneVector<T>> {
public:
explicit ZoneIntrusiveSet(Zone* zone, GetIntrusiveSetIndex index_functor = {})
: base::IntrusiveSet<T, GetIntrusiveSetIndex, ZoneVector<T>>(
ZoneVector<T>(zone), std::move(index_functor)) {}
};
using base::IntrusiveSetIndex;
template <typename T>
class ZoneDeque : public std::deque<T, RecyclingZoneAllocator<T>> {
public:
explicit ZoneDeque(Zone* zone)
: std::deque<T, RecyclingZoneAllocator<T>>(
RecyclingZoneAllocator<T>(zone)) {}
};
template <typename T>
class ZoneLinkedList : public std::list<T, ZoneAllocator<T>> {
public:
explicit ZoneLinkedList(Zone* zone)
: std::list<T, ZoneAllocator<T>>(ZoneAllocator<T>(zone)) {}
};
template <typename T>
class ZoneForwardList : public std::forward_list<T, ZoneAllocator<T>> {
public:
explicit ZoneForwardList(Zone* zone)
: std::forward_list<T, ZoneAllocator<T>>(ZoneAllocator<T>(zone)) {}
};
template <typename T, typename Compare = std::less<T>>
class ZonePriorityQueue
: public std::priority_queue<T, ZoneVector<T>, Compare> {
public:
explicit ZonePriorityQueue(Zone* zone)
: std::priority_queue<T, ZoneVector<T>, Compare>(Compare(),
ZoneVector<T>(zone)) {}
};
template <typename T>
class ZoneQueue : public std::queue<T, ZoneDeque<T>> {
public:
explicit ZoneQueue(Zone* zone)
: std::queue<T, ZoneDeque<T>>(ZoneDeque<T>(zone)) {}
};
template <typename T>
class ZoneStack : public std::stack<T, ZoneDeque<T>> {
public:
explicit ZoneStack(Zone* zone)
: std::stack<T, ZoneDeque<T>>(ZoneDeque<T>(zone)) {}
};
template <typename K, typename Compare = std::less<K>>
class ZoneSet : public std::set<K, Compare, ZoneAllocator<K>> {
public:
explicit ZoneSet(Zone* zone)
: std::set<K, Compare, ZoneAllocator<K>>(Compare(),
ZoneAllocator<K>(zone)) {}
};
template <typename K, typename Compare = std::less<K>>
class ZoneMultiset : public std::multiset<K, Compare, ZoneAllocator<K>> {
public:
explicit ZoneMultiset(Zone* zone)
: std::multiset<K, Compare, ZoneAllocator<K>>(Compare(),
ZoneAllocator<K>(zone)) {}
};
template <typename K, typename V, typename Compare = std::less<K>>
class ZoneMap
: public std::map<K, V, Compare, ZoneAllocator<std::pair<const K, V>>> {
public:
explicit ZoneMap(Zone* zone)
: std::map<K, V, Compare, ZoneAllocator<std::pair<const K, V>>>(
Compare(), ZoneAllocator<std::pair<const K, V>>(zone)) {}
};
template <typename K, typename V, typename Hash = base::hash<K>,
typename KeyEqual = std::equal_to<K>>
class ZoneUnorderedMap
: public std::unordered_map<K, V, Hash, KeyEqual,
ZoneAllocator<std::pair<const K, V>>> {
public:
explicit ZoneUnorderedMap(Zone* zone, size_t bucket_count = 0)
: std::unordered_map<K, V, Hash, KeyEqual,
ZoneAllocator<std::pair<const K, V>>>(
bucket_count, Hash(), KeyEqual(),
ZoneAllocator<std::pair<const K, V>>(zone)) {}
};
template <typename K, typename Hash = base::hash<K>,
typename KeyEqual = std::equal_to<K>>
class ZoneUnorderedSet
: public std::unordered_set<K, Hash, KeyEqual, ZoneAllocator<K>> {
public:
explicit ZoneUnorderedSet(Zone* zone, size_t bucket_count = 0)
: std::unordered_set<K, Hash, KeyEqual, ZoneAllocator<K>>(
bucket_count, Hash(), KeyEqual(), ZoneAllocator<K>(zone)) {}
};
template <typename K, typename V, typename Compare = std::less<K>>
class ZoneMultimap
: public std::multimap<K, V, Compare,
ZoneAllocator<std::pair<const K, V>>> {
public:
explicit ZoneMultimap(Zone* zone)
: std::multimap<K, V, Compare, ZoneAllocator<std::pair<const K, V>>>(
Compare(), ZoneAllocator<std::pair<const K, V>>(zone)) {}
};
template <typename T, size_t kSize>
class SmallZoneVector : public base::SmallVector<T, kSize, ZoneAllocator<T>> {
public:
explicit SmallZoneVector(Zone* zone)
: base::SmallVector<T, kSize, ZoneAllocator<T>>(ZoneAllocator<T>(zone)) {}
explicit SmallZoneVector(size_t size, Zone* zone)
: base::SmallVector<T, kSize, ZoneAllocator<T>>(
size, ZoneAllocator<T>(ZoneAllocator<T>(zone))) {}
};
template <typename ZoneMap>
class ZoneMapInit {
public:
explicit ZoneMapInit(Zone* zone) : zone_(zone) {}
void operator()(ZoneMap* map) const { new (map) ZoneMap(zone_); }
private:
Zone* zone_;
};
template <typename K, typename V, size_t kArraySize,
typename Compare = std::less<K>, typename KeyEqual = std::equal_to<K>>
class SmallZoneMap
: public base::SmallMap<ZoneMap<K, V, Compare>, kArraySize, KeyEqual,
ZoneMapInit<ZoneMap<K, V, Compare>>> {
public:
explicit SmallZoneMap(Zone* zone)
: base::SmallMap<ZoneMap<K, V, Compare>, kArraySize, KeyEqual,
ZoneMapInit<ZoneMap<K, V, Compare>>>(
ZoneMapInit<ZoneMap<K, V, Compare>>(zone)) {}
};
template <typename K, typename V,
typename Hash = typename absl::flat_hash_map<K, V>::hasher,
typename KeyEqual =
typename absl::flat_hash_map<K, V, Hash>::key_equal>
class ZoneAbslFlatHashMap
: public absl::flat_hash_map<K, V, Hash, KeyEqual,
ZoneAllocator<std::pair<const K, V>>> {
public:
explicit ZoneAbslFlatHashMap(Zone* zone, size_t bucket_count = 0)
: absl::flat_hash_map<K, V, Hash, KeyEqual,
ZoneAllocator<std::pair<const K, V>>>(
bucket_count, Hash(), KeyEqual(),
ZoneAllocator<std::pair<const K, V>>(zone)) {}
};
template <typename K, typename Hash = typename absl::flat_hash_set<K>::hasher,
typename KeyEqual = typename absl::flat_hash_set<K, Hash>::key_equal>
class ZoneAbslFlatHashSet
: public absl::flat_hash_set<K, Hash, KeyEqual, ZoneAllocator<K>> {
public:
explicit ZoneAbslFlatHashSet(Zone* zone, size_t bucket_count = 0)
: absl::flat_hash_set<K, Hash, KeyEqual, ZoneAllocator<K>>(
bucket_count, Hash(), KeyEqual(), ZoneAllocator<K>(zone)) {}
};
template <typename K, typename V, typename Compare = std::less<K>>
class ZoneAbslBTreeMap
: public absl::btree_map<K, V, Compare,
ZoneAllocator<std::pair<const K, V>>> {
public:
explicit ZoneAbslBTreeMap(Zone* zone)
: absl::btree_map<K, V, Compare, ZoneAllocator<std::pair<const K, V>>>(
ZoneAllocator<std::pair<const K, V>>(zone)) {}
};
using IntVector = ZoneVector<int>;
}
}
#endif