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_UTILS_VECTOR_H_
6 #define V8_UTILS_VECTOR_H_
7
8 #include <algorithm>
9 #include <cstring>
10 #include <iterator>
11 #include <memory>
12 #include <type_traits>
13
14 #include "src/common/checks.h"
15 #include "src/common/globals.h"
16 #include "src/utils/allocation.h"
17
18 namespace v8 {
19 namespace internal {
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 CONSTEXPR_DCHECK(length == 0 || data != nullptr);
32 }
33
New(size_t length)34 static Vector<T> New(size_t length) {
35 return Vector<T>(NewArray<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 = NewArray<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 DeleteArray(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 ScopedVector : public Vector<T> {
145 public:
ScopedVector(size_t length)146 explicit ScopedVector(size_t length)
147 : Vector<T>(NewArray<T>(length), length) {}
~ScopedVector()148 ~ScopedVector() { DeleteArray(this->begin()); }
149
150 private:
151 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedVector);
152 };
153
154 template <typename T>
155 class OwnedVector {
156 public:
157 MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(OwnedVector);
OwnedVector(std::unique_ptr<T[]> data,size_t length)158 OwnedVector(std::unique_ptr<T[]> data, size_t length)
159 : data_(std::move(data)), length_(length) {
160 DCHECK_IMPLIES(length_ > 0, data_ != nullptr);
161 }
162
163 // Implicit conversion from {OwnedVector<U>} to {OwnedVector<T>}, instantiable
164 // if {std::unique_ptr<U>} can be converted to {std::unique_ptr<T>}.
165 // Can be used to convert {OwnedVector<T>} to {OwnedVector<const T>}.
166 template <typename U,
167 typename = typename std::enable_if<std::is_convertible<
168 std::unique_ptr<U>, std::unique_ptr<T>>::value>::type>
OwnedVector(OwnedVector<U> && other)169 OwnedVector(OwnedVector<U>&& other)
170 : data_(std::move(other.data_)), length_(other.length_) {
171 STATIC_ASSERT(sizeof(U) == sizeof(T));
172 other.length_ = 0;
173 }
174
175 // Returns the length of the vector as a size_t.
size()176 constexpr size_t size() const { return length_; }
177
178 // Returns whether or not the vector is empty.
empty()179 constexpr bool empty() const { return length_ == 0; }
180
181 // Returns the pointer to the start of the data in the vector.
start()182 T* start() const {
183 DCHECK_IMPLIES(length_ > 0, data_ != nullptr);
184 return data_.get();
185 }
186
begin()187 constexpr T* begin() const { return start(); }
end()188 constexpr T* end() const { return start() + size(); }
189
190 // Access individual vector elements - checks bounds in debug mode.
191 T& operator[](size_t index) const {
192 DCHECK_LT(index, length_);
193 return data_[index];
194 }
195
196 // Returns a {Vector<T>} view of the data in this vector.
as_vector()197 Vector<T> as_vector() const { return Vector<T>(start(), size()); }
198
199 // Releases the backing data from this vector and transfers ownership to the
200 // caller. This vector will be empty afterwards.
ReleaseData()201 std::unique_ptr<T[]> ReleaseData() {
202 length_ = 0;
203 return std::move(data_);
204 }
205
206 // Allocates a new vector of the specified size via the default allocator.
207 // Elements in the new vector are value-initialized.
New(size_t size)208 static OwnedVector<T> New(size_t size) {
209 if (size == 0) return {};
210 return OwnedVector<T>(std::make_unique<T[]>(size), size);
211 }
212
213 // Allocates a new vector of the specified size via the default allocator.
214 // Elements in the new vector are default-initialized.
NewForOverwrite(size_t size)215 static OwnedVector<T> NewForOverwrite(size_t size) {
216 if (size == 0) return {};
217 // TODO(v8): Use {std::make_unique_for_overwrite} once we allow C++20.
218 return OwnedVector<T>(std::unique_ptr<T[]>(new T[size]), size);
219 }
220
221 // Allocates a new vector containing the specified collection of values.
222 // {Iterator} is the common type of {std::begin} and {std::end} called on a
223 // {const U&}. This function is only instantiable if that type exists.
224 template <typename U, typename Iterator = typename std::common_type<
225 decltype(std::begin(std::declval<const U&>())),
226 decltype(std::end(std::declval<const U&>()))>::type>
Of(const U & collection)227 static OwnedVector<T> Of(const U& collection) {
228 Iterator begin = std::begin(collection);
229 Iterator end = std::end(collection);
230 using non_const_t = typename std::remove_const<T>::type;
231 auto vec =
232 OwnedVector<non_const_t>::NewForOverwrite(std::distance(begin, end));
233 std::copy(begin, end, vec.start());
234 return vec;
235 }
236
237 bool operator==(std::nullptr_t) const { return data_ == nullptr; }
238 bool operator!=(std::nullptr_t) const { return data_ != nullptr; }
239
240 private:
241 template <typename U>
242 friend class OwnedVector;
243
244 std::unique_ptr<T[]> data_;
245 size_t length_ = 0;
246 };
247
248 // The vectors returned by {StaticCharVector}, {CStrVector}, or {OneByteVector}
249 // do not contain a null-termination byte. If you want the null byte, use
250 // {ArrayVector}.
251
252 // Known length, constexpr.
253 template <size_t N>
StaticCharVector(const char (& array)[N])254 constexpr Vector<const char> StaticCharVector(const char (&array)[N]) {
255 return {array, N - 1};
256 }
257
258 // Unknown length, not constexpr.
CStrVector(const char * data)259 inline Vector<const char> CStrVector(const char* data) {
260 return {data, strlen(data)};
261 }
262
263 // OneByteVector is never constexpr because the data pointer is
264 // {reinterpret_cast}ed.
OneByteVector(const char * data,size_t length)265 inline Vector<const uint8_t> OneByteVector(const char* data, size_t length) {
266 return {reinterpret_cast<const uint8_t*>(data), length};
267 }
268
OneByteVector(const char * data)269 inline Vector<const uint8_t> OneByteVector(const char* data) {
270 return OneByteVector(data, strlen(data));
271 }
272
273 template <size_t N>
StaticOneByteVector(const char (& array)[N])274 Vector<const uint8_t> StaticOneByteVector(const char (&array)[N]) {
275 return OneByteVector(array, N - 1);
276 }
277
278 // For string literals, ArrayVector("foo") returns a vector ['f', 'o', 'o', \0]
279 // with length 4 and null-termination.
280 // If you want ['f', 'o', 'o'], use CStrVector("foo").
281 template <typename T, size_t N>
ArrayVector(T (& arr)[N])282 inline constexpr Vector<T> ArrayVector(T (&arr)[N]) {
283 return {arr, N};
284 }
285
286 // Construct a Vector from a start pointer and a size.
287 template <typename T>
VectorOf(T * start,size_t size)288 inline constexpr Vector<T> VectorOf(T* start, size_t size) {
289 return {start, size};
290 }
291
292 // Construct a Vector from anything providing a {data()} and {size()} accessor.
293 template <typename Container>
294 inline constexpr auto VectorOf(Container&& c)
295 -> decltype(VectorOf(c.data(), c.size())) {
296 return VectorOf(c.data(), c.size());
297 }
298
299 // Construct a Vector from an initializer list. The vector can obviously only be
300 // used as long as the initializer list is live. Valid uses include direct use
301 // in parameter lists: F(VectorOf({1, 2, 3}));
302 template <typename T>
VectorOf(std::initializer_list<T> list)303 inline constexpr Vector<const T> VectorOf(std::initializer_list<T> list) {
304 return VectorOf(list.begin(), list.size());
305 }
306
307 template <typename T, size_t kSize>
308 class EmbeddedVector : public Vector<T> {
309 public:
EmbeddedVector()310 EmbeddedVector() : Vector<T>(buffer_, kSize) {}
311
EmbeddedVector(const T & initial_value)312 explicit EmbeddedVector(const T& initial_value) : Vector<T>(buffer_, kSize) {
313 std::fill_n(buffer_, kSize, initial_value);
314 }
315
316 private:
317 T buffer_[kSize];
318
319 DISALLOW_COPY_AND_ASSIGN(EmbeddedVector);
320 };
321
322 } // namespace internal
323 } // namespace v8
324
325 #endif // V8_UTILS_VECTOR_H_
326