xref: /third_party/node/deps/v8/src/base/vector.h (revision 1cb0ef41)
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
18namespace v8 {
19namespace base {
20
21template <typename T>
22class Vector {
23 public:
24  using value_type = T;
25  using iterator = T*;
26  using const_iterator = const T*;
27
28  constexpr Vector() : start_(nullptr), length_(0) {}
29
30  constexpr Vector(T* data, size_t length) : start_(data), length_(length) {
31    DCHECK(length == 0 || data != nullptr);
32  }
33
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'.
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.
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.
54  constexpr size_t size() const { return length_; }
55
56  // Returns whether or not the vector is 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
65  const T& at(size_t index) const { return operator[](index); }
66
67  T& first() { return start_[0]; }
68
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.
75  constexpr T* begin() const { return start_; }
76
77  // For consistency with other containers, do also provide a {data} accessor.
78  constexpr T* data() const { return start_; }
79
80  // Returns a pointer past the end of the data in the vector.
81  constexpr T* end() const { return start_ + length_; }
82
83  // Returns a clone of this vector with a new backing store.
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
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.
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>
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
143template <typename T>
144class V8_NODISCARD ScopedVector : public Vector<T> {
145 public:
146  explicit ScopedVector(size_t length) : Vector<T>(new T[length], length) {}
147  ~ScopedVector() { delete[] this->begin(); }
148
149 private:
150  DISALLOW_IMPLICIT_CONSTRUCTORS(ScopedVector);
151};
152
153template <typename T>
154class OwnedVector {
155 public:
156  MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(OwnedVector);
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>
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.
175  constexpr size_t size() const { return length_; }
176
177  // Returns whether or not the vector is empty.
178  constexpr bool empty() const { return length_ == 0; }
179
180  // Returns the pointer to the start of the data in the vector.
181  T* start() const {
182    DCHECK_IMPLIES(length_ > 0, data_ != nullptr);
183    return data_.get();
184  }
185
186  constexpr T* begin() const { return start(); }
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.
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.
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.
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.
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>
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.
252template <size_t N>
253constexpr Vector<const char> StaticCharVector(const char (&array)[N]) {
254  return {array, N - 1};
255}
256
257// Unknown length, not constexpr.
258inline 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.
264inline Vector<const uint8_t> OneByteVector(const char* data, size_t length) {
265  return {reinterpret_cast<const uint8_t*>(data), length};
266}
267
268inline Vector<const uint8_t> OneByteVector(const char* data) {
269  return OneByteVector(data, strlen(data));
270}
271
272template <size_t N>
273Vector<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").
280template <typename T, size_t N>
281inline constexpr Vector<T> ArrayVector(T (&arr)[N]) {
282  return {arr, N};
283}
284
285// Construct a Vector from a start pointer and a size.
286template <typename T>
287inline 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.
292template <typename Container>
293inline 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}));
301template <typename T>
302inline constexpr Vector<const T> VectorOf(std::initializer_list<T> list) {
303  return VectorOf(list.begin(), list.size());
304}
305
306template <typename T, size_t kSize>
307class EmbeddedVector : public Vector<T> {
308 public:
309  EmbeddedVector() : Vector<T>(buffer_, kSize) {}
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