1 // Copyright 2014 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_BASE_VECTOR_H_
6 #define V8_BASE_VECTOR_H_
7
8 #include <algorithm>
9 #include <cstring>
10 #include <iterator>
11 #include <limits>
12 #include <memory>
13 #include <type_traits>
14
15 #include "src/base/logging.h"
16 #include "src/base/macros.h"
17
18 namespace v8 {
19 namespace base {
20
21 template <typename T>
22 class Vector {
23 public:
24 using value_type = T;
25 using iterator = T*;
26 using const_iterator = const T*;
27
Vector()28 constexpr Vector() : start_(nullptr), length_(0) {}
29
Vector(T * data,size_t length)30 constexpr Vector(T* data, size_t length) : start_(data), length_(length) {
31 DCHECK(length == 0 || data != nullptr);
32 }
33
New(size_t length)34 static Vector<T> New(size_t length) {
35 return Vector<T>(new T[length], length);
36 }
37
38 // Returns a vector using the same backing storage as this one,
39 // spanning from and including 'from', to but not including 'to'.
SubVector(size_t from,size_t to)40 Vector<T> SubVector(size_t from, size_t to) const {
41 DCHECK_LE(from, to);
42 DCHECK_LE(to, length_);
43 return Vector<T>(begin() + from, to - from);
44 }
45
46 // Returns the length of the vector. Only use this if you really need an
47 // integer return value. Use {size()} otherwise.
length()48 int length() const {
49 DCHECK_GE(std::numeric_limits<int>::max(), length_);
50 return static_cast<int>(length_);
51 }
52
53 // Returns the length of the vector as a size_t.
size()54 constexpr size_t size() const { return length_; }
55
56 // Returns whether or not the vector is empty.
empty()57 constexpr bool empty() const { return length_ == 0; }
58
59 // Access individual vector elements - checks bounds in debug mode.
60 T& operator[](size_t index) const {
61 DCHECK_LT(index, length_);
62 return start_[index];
63 }
64
at(size_t index)65 const T& at(size_t index) const { return operator[](index); }
66
first()67 T& first() { return start_[0]; }
68
last()69 T& last() {
70 DCHECK_LT(0, length_);
71 return start_[length_ - 1];
72 }
73
74 // Returns a pointer to the start of the data in the vector.
begin()75 constexpr T* begin() const { return start_; }
76
77 // For consistency with other containers, do also provide a {data} accessor.
data()78 constexpr T* data() const { return start_; }
79
80 // Returns a pointer past the end of the data in the vector.
end()81 constexpr T* end() const { return start_ + length_; }
82
83 // Returns a clone of this vector with a new backing store.
Clone()84 Vector<T> Clone() const {
85 T* result = new T[length_];
86 for (size_t i = 0; i < length_; i++) result[i] = start_[i];
87 return Vector<T>(result, length_);
88 }
89
Truncate(size_t length)90 void Truncate(size_t length) {
91 DCHECK(length <= length_);
92 length_ = length;
93 }
94
95 // Releases the array underlying this vector. Once disposed the
96 // vector is empty.
Dispose()97 void Dispose() {
98 delete[] start_;
99 start_ = nullptr;
100 length_ = 0;
101 }
102
103 Vector<T> operator+(size_t offset) {
104 DCHECK_LE(offset, length_);
105 return Vector<T>(start_ + offset, length_ - offset);
106 }
107
108 Vector<T> operator+=(size_t offset) {
109 DCHECK_LE(offset, length_);
110 start_ += offset;
111 length_ -= offset;
112 return *this;
113 }
114
115 // Implicit conversion from Vector<T> to Vector<const T>.
116 operator Vector<const T>() const { return {start_, length_}; }
117
118 template <typename S>
cast(Vector<S> input)119 static Vector<T> cast(Vector<S> input) {
120 // Casting is potentially dangerous, so be really restrictive here. This
121 // might be lifted once we have use cases for that.
122 STATIC_ASSERT(std::is_pod<S>::value);
123 STATIC_ASSERT(std::is_pod<T>::value);
124 DCHECK_EQ(0, (input.size() * sizeof(S)) % sizeof(T));
125 DCHECK_EQ(0, reinterpret_cast<uintptr_t>(input.begin()) % alignof(T));
126 return Vector<T>(reinterpret_cast<T*>(input.begin()),
127 input.size() * sizeof(S) / sizeof(T));
128 }
129
130 bool operator==(const Vector<const T> other) const {
131 return std::equal(begin(), end(), other.begin(), other.end());
132 }
133
134 bool operator!=(const Vector<const T> other) const {
135 return !operator==(other);
136 }
137
138 private:
139 T* start_;
140 size_t length_;
141 };
142
143 template <typename T>
144 class V8_NODISCARD ScopedVector : public Vector<T> {
145 public:
ScopedVector(size_t length)146 explicit ScopedVector(size_t length) : Vector<T>(new T[length], length) {}
~ScopedVector()147 ~ScopedVector() { delete[] this->begin(); }
148
149 private:
150 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedVector);
151 };
152
153 template <typename T>
154 class OwnedVector {
155 public:
156 MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(OwnedVector);
OwnedVector(std::unique_ptr<T[]> data,size_t length)157 OwnedVector(std::unique_ptr<T[]> data, size_t length)
158 : data_(std::move(data)), length_(length) {
159 DCHECK_IMPLIES(length_ > 0, data_ != nullptr);
160 }
161
162 // Implicit conversion from {OwnedVector<U>} to {OwnedVector<T>}, instantiable
163 // if {std::unique_ptr<U>} can be converted to {std::unique_ptr<T>}.
164 // Can be used to convert {OwnedVector<T>} to {OwnedVector<const T>}.
165 template <typename U,
166 typename = typename std::enable_if<std::is_convertible<
167 std::unique_ptr<U>, std::unique_ptr<T>>::value>::type>
OwnedVector(OwnedVector<U> && other)168 OwnedVector(OwnedVector<U>&& other)
169 : data_(std::move(other.data_)), length_(other.length_) {
170 STATIC_ASSERT(sizeof(U) == sizeof(T));
171 other.length_ = 0;
172 }
173
174 // Returns the length of the vector as a size_t.
size()175 constexpr size_t size() const { return length_; }
176
177 // Returns whether or not the vector is empty.
empty()178 constexpr bool empty() const { return length_ == 0; }
179
180 // Returns the pointer to the start of the data in the vector.
start()181 T* start() const {
182 DCHECK_IMPLIES(length_ > 0, data_ != nullptr);
183 return data_.get();
184 }
185
begin()186 constexpr T* begin() const { return start(); }
end()187 constexpr T* end() const { return start() + size(); }
188
189 // Access individual vector elements - checks bounds in debug mode.
190 T& operator[](size_t index) const {
191 DCHECK_LT(index, length_);
192 return data_[index];
193 }
194
195 // Returns a {Vector<T>} view of the data in this vector.
as_vector()196 Vector<T> as_vector() const { return Vector<T>(start(), size()); }
197
198 // Releases the backing data from this vector and transfers ownership to the
199 // caller. This vector will be empty afterwards.
ReleaseData()200 std::unique_ptr<T[]> ReleaseData() {
201 length_ = 0;
202 return std::move(data_);
203 }
204
205 // Allocates a new vector of the specified size via the default allocator.
206 // Elements in the new vector are value-initialized.
New(size_t size)207 static OwnedVector<T> New(size_t size) {
208 if (size == 0) return {};
209 return OwnedVector<T>(std::make_unique<T[]>(size), size);
210 }
211
212 // Allocates a new vector of the specified size via the default allocator.
213 // Elements in the new vector are default-initialized.
NewForOverwrite(size_t size)214 static OwnedVector<T> NewForOverwrite(size_t size) {
215 if (size == 0) return {};
216 // TODO(v8): Use {std::make_unique_for_overwrite} once we allow C++20.
217 return OwnedVector<T>(std::unique_ptr<T[]>(new T[size]), size);
218 }
219
220 // Allocates a new vector containing the specified collection of values.
221 // {Iterator} is the common type of {std::begin} and {std::end} called on a
222 // {const U&}. This function is only instantiable if that type exists.
223 template <typename U, typename Iterator = typename std::common_type<
224 decltype(std::begin(std::declval<const U&>())),
225 decltype(std::end(std::declval<const U&>()))>::type>
Of(const U & collection)226 static OwnedVector<T> Of(const U& collection) {
227 Iterator begin = std::begin(collection);
228 Iterator end = std::end(collection);
229 using non_const_t = typename std::remove_const<T>::type;
230 auto vec =
231 OwnedVector<non_const_t>::NewForOverwrite(std::distance(begin, end));
232 std::copy(begin, end, vec.start());
233 return vec;
234 }
235
236 bool operator==(std::nullptr_t) const { return data_ == nullptr; }
237 bool operator!=(std::nullptr_t) const { return data_ != nullptr; }
238
239 private:
240 template <typename U>
241 friend class OwnedVector;
242
243 std::unique_ptr<T[]> data_;
244 size_t length_ = 0;
245 };
246
247 // The vectors returned by {StaticCharVector}, {CStrVector}, or {OneByteVector}
248 // do not contain a null-termination byte. If you want the null byte, use
249 // {ArrayVector}.
250
251 // Known length, constexpr.
252 template <size_t N>
StaticCharVector(const char (& array)[N])253 constexpr Vector<const char> StaticCharVector(const char (&array)[N]) {
254 return {array, N - 1};
255 }
256
257 // Unknown length, not constexpr.
CStrVector(const char * data)258 inline Vector<const char> CStrVector(const char* data) {
259 return {data, strlen(data)};
260 }
261
262 // OneByteVector is never constexpr because the data pointer is
263 // {reinterpret_cast}ed.
OneByteVector(const char * data,size_t length)264 inline Vector<const uint8_t> OneByteVector(const char* data, size_t length) {
265 return {reinterpret_cast<const uint8_t*>(data), length};
266 }
267
OneByteVector(const char * data)268 inline Vector<const uint8_t> OneByteVector(const char* data) {
269 return OneByteVector(data, strlen(data));
270 }
271
272 template <size_t N>
StaticOneByteVector(const char (& array)[N])273 Vector<const uint8_t> StaticOneByteVector(const char (&array)[N]) {
274 return OneByteVector(array, N - 1);
275 }
276
277 // For string literals, ArrayVector("foo") returns a vector ['f', 'o', 'o', \0]
278 // with length 4 and null-termination.
279 // If you want ['f', 'o', 'o'], use CStrVector("foo").
280 template <typename T, size_t N>
ArrayVector(T (& arr)[N])281 inline constexpr Vector<T> ArrayVector(T (&arr)[N]) {
282 return {arr, N};
283 }
284
285 // Construct a Vector from a start pointer and a size.
286 template <typename T>
VectorOf(T * start,size_t size)287 inline constexpr Vector<T> VectorOf(T* start, size_t size) {
288 return {start, size};
289 }
290
291 // Construct a Vector from anything providing a {data()} and {size()} accessor.
292 template <typename Container>
293 inline constexpr auto VectorOf(Container&& c)
294 -> decltype(VectorOf(c.data(), c.size())) {
295 return VectorOf(c.data(), c.size());
296 }
297
298 // Construct a Vector from an initializer list. The vector can obviously only be
299 // used as long as the initializer list is live. Valid uses include direct use
300 // in parameter lists: F(VectorOf({1, 2, 3}));
301 template <typename T>
VectorOf(std::initializer_list<T> list)302 inline constexpr Vector<const T> VectorOf(std::initializer_list<T> list) {
303 return VectorOf(list.begin(), list.size());
304 }
305
306 template <typename T, size_t kSize>
307 class EmbeddedVector : public Vector<T> {
308 public:
EmbeddedVector()309 EmbeddedVector() : Vector<T>(buffer_, kSize) {}
EmbeddedVector(const T & initial_value)310 explicit EmbeddedVector(const T& initial_value) : Vector<T>(buffer_, kSize) {
311 std::fill_n(buffer_, kSize, initial_value);
312 }
313 EmbeddedVector(const EmbeddedVector&) = delete;
314 EmbeddedVector& operator=(const EmbeddedVector&) = delete;
315
316 private:
317 T buffer_[kSize];
318 };
319
320 } // namespace base
321 } // namespace v8
322
323 #endif // V8_BASE_VECTOR_H_
324