blob: 66112fafecf72dcc16cd12609272061123a3f03a [file] [log] [blame]
// 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_UTILS_SCOPED_LIST_H_
#define V8_UTILS_SCOPED_LIST_H_
#include <type_traits>
#include <vector>
#include "src/base/logging.h"
namespace v8 {
namespace internal {
template <typename T>
class Vector;
template <typename T>
class ZoneList;
// ScopedList is a scope-lifetime list with a std::vector backing that can be
// re-used between ScopedLists. Note that a ScopedList in an outer scope cannot
// add any entries if there is a ScopedList with the same backing in an inner
// scope.
template <typename T, typename TBacking = T>
class ScopedList final {
// The backing can either be the same type as the list type, or, for pointers,
// we additionally allow a void* backing store.
static_assert((std::is_same<TBacking, T>::value) ||
(std::is_same<TBacking, void*>::value &&
std::is_pointer<T>::value),
"Incompatible combination of T and TBacking types");
public:
explicit ScopedList(std::vector<TBacking>* buffer)
: buffer_(*buffer), start_(buffer->size()), end_(buffer->size()) {}
~ScopedList() { Rewind(); }
void Rewind() {
DCHECK_EQ(buffer_.size(), end_);
buffer_.resize(start_);
end_ = start_;
}
void MergeInto(ScopedList* parent) {
DCHECK_EQ(parent->end_, start_);
parent->end_ = end_;
start_ = end_;
DCHECK_EQ(0, length());
}
int length() const { return static_cast<int>(end_ - start_); }
const T& at(int i) const {
size_t index = start_ + i;
DCHECK_LE(start_, index);
DCHECK_LT(index, buffer_.size());
return *reinterpret_cast<T*>(&buffer_[index]);
}
T& at(int i) {
size_t index = start_ + i;
DCHECK_LE(start_, index);
DCHECK_LT(index, buffer_.size());
return *reinterpret_cast<T*>(&buffer_[index]);
}
Vector<const T> ToConstVector() const {
T* data = reinterpret_cast<T*>(buffer_.data() + start_);
return Vector<const T>(data, length());
}
void Add(const T& value) {
DCHECK_EQ(buffer_.size(), end_);
buffer_.push_back(value);
++end_;
}
void AddAll(const Vector<const T>& list) {
DCHECK_EQ(buffer_.size(), end_);
buffer_.reserve(buffer_.size() + list.length());
for (int i = 0; i < list.length(); i++) {
buffer_.push_back(list.at(i));
}
end_ += list.length();
}
using iterator = T*;
using const_iterator = const T*;
inline iterator begin() {
return reinterpret_cast<T*>(buffer_.data() + start_);
}
inline const_iterator begin() const {
return reinterpret_cast<T*>(buffer_.data() + start_);
}
inline iterator end() { return reinterpret_cast<T*>(buffer_.data() + end_); }
inline const_iterator end() const {
return reinterpret_cast<T*>(buffer_.data() + end_);
}
private:
std::vector<TBacking>& buffer_;
size_t start_;
size_t end_;
};
template <typename T>
using ScopedPtrList = ScopedList<T*, void*>;
} // namespace internal
} // namespace v8
#endif // V8_UTILS_SCOPED_LIST_H_