VectorShim.h (6578B)
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_UTIL_VECTOR_H_ 6 #define V8_UTIL_VECTOR_H_ 7 8 #include <cstring> 9 10 #include "js/AllocPolicy.h" 11 #include "js/Utility.h" 12 #include "js/Vector.h" 13 14 namespace v8 { 15 namespace internal { 16 17 ////////////////////////////////////////////////// 18 19 // Adapted from: 20 // https://github.com/v8/v8/blob/5f69bbc233c2d1baf149faf869a7901603929914/src/utils/allocation.h#L36-L58 21 22 template <typename T> 23 T* NewArray(size_t size) { 24 static_assert(std::is_trivially_copyable_v<T>); 25 js::AutoEnterOOMUnsafeRegion oomUnsafe; 26 T* result = js_pod_malloc<T>(size); 27 if (!result) { 28 oomUnsafe.crash("Irregexp NewArray"); 29 } 30 return result; 31 } 32 33 template <typename T> 34 void DeleteArray(T* array) { 35 static_assert(std::is_trivially_destructible_v<T>); 36 js_free(array); 37 } 38 39 } // namespace internal 40 41 namespace base { 42 43 ////////////////////////////////////////////////// 44 45 // A non-resizable vector containing a pointer and a length. 46 // The Vector may or may not own the pointer, depending on context. 47 // Origin: 48 // https://github.com/v8/v8/blob/5f69bbc233c2d1baf149faf869a7901603929914/src/utils/vector.h#L20-L134 49 50 template <typename T> 51 class Vector { 52 public: 53 constexpr Vector() : start_(nullptr), length_(0) {} 54 55 constexpr Vector(T* data, size_t length) : start_(data), length_(length) { 56 MOZ_ASSERT_IF(length != 0, data != nullptr); 57 } 58 59 static Vector<T> New(size_t length) { 60 return Vector<T>(v8::internal::NewArray<T>(length), length); 61 } 62 63 // Returns a vector using the same backing storage as this one, 64 // spanning from and including 'from', to but not including 'to'. 65 Vector<T> SubVector(size_t from, size_t to) const { 66 MOZ_ASSERT(from <= to); 67 MOZ_ASSERT(to <= length_); 68 return Vector<T>(begin() + from, to - from); 69 } 70 71 // Returns the length of the vector. Only use this if you really need an 72 // integer return value. Use {size()} otherwise. 73 int length() const { 74 MOZ_ASSERT(length_ <= static_cast<size_t>(std::numeric_limits<int>::max())); 75 return static_cast<int>(length_); 76 } 77 78 // Returns the length of the vector as a size_t. 79 constexpr size_t size() const { return length_; } 80 81 // Returns whether or not the vector is empty. 82 constexpr bool empty() const { return length_ == 0; } 83 84 // Access individual vector elements - checks bounds in debug mode. 85 T& operator[](size_t index) const { 86 MOZ_ASSERT(index < length_); 87 return start_[index]; 88 } 89 90 const T& at(size_t index) const { return operator[](index); } 91 92 T& first() { return start_[0]; } 93 94 T& last() { 95 MOZ_ASSERT(length_ > 0); 96 return start_[length_ - 1]; 97 } 98 99 // Returns a pointer to the start of the data in the vector. 100 constexpr T* begin() const { return start_; } 101 102 // Returns a pointer past the end of the data in the vector. 103 constexpr T* end() const { return start_ + length_; } 104 105 // Returns a clone of this vector with a new backing store. 106 Vector<T> Clone() const { 107 T* result = v8::internal::NewArray<T>(length_); 108 for (size_t i = 0; i < length_; i++) result[i] = start_[i]; 109 return Vector<T>(result, length_); 110 } 111 112 void Truncate(size_t length) { 113 MOZ_ASSERT(length <= length_); 114 length_ = length; 115 } 116 117 // Releases the array underlying this vector. Once disposed the 118 // vector is empty. 119 void Dispose() { 120 DeleteArray(start_); 121 start_ = nullptr; 122 length_ = 0; 123 } 124 125 Vector<T> operator+(size_t offset) const { 126 MOZ_ASSERT(offset <= length_); 127 return Vector<T>(start_ + offset, length_ - offset); 128 } 129 130 Vector<T> operator+=(size_t offset) { 131 MOZ_ASSERT(offset <= length_); 132 start_ += offset; 133 length_ -= offset; 134 return *this; 135 } 136 137 // Implicit conversion from Vector<T> to Vector<const T>. 138 inline operator Vector<const T>() const { 139 return Vector<const T>::cast(*this); 140 } 141 142 template <typename S> 143 static constexpr Vector<T> cast(Vector<S> input) { 144 return Vector<T>(reinterpret_cast<T*>(input.begin()), 145 input.length() * sizeof(S) / sizeof(T)); 146 } 147 148 bool operator==(const Vector<const T> other) const { 149 if (length_ != other.length_) return false; 150 if (start_ == other.start_) return true; 151 for (size_t i = 0; i < length_; ++i) { 152 if (start_[i] != other.start_[i]) { 153 return false; 154 } 155 } 156 return true; 157 } 158 159 private: 160 T* start_; 161 size_t length_; 162 }; 163 164 // The resulting vector does not contain a null-termination byte. If you want 165 // the null byte, use ArrayVector("foo"). 166 inline Vector<const char> CStrVector(const char* data) { 167 return Vector<const char>(data, strlen(data)); 168 } 169 170 // Construct a Vector from a start pointer and a size. 171 template <typename T> 172 inline constexpr Vector<T> VectorOf(T* start, size_t size) { 173 return {start, size}; 174 } 175 176 class DefaultAllocator { 177 public: 178 using Policy = js::SystemAllocPolicy; 179 Policy policy() const { return js::SystemAllocPolicy(); } 180 }; 181 182 // SmallVector uses inline storage first, and reallocates when full. 183 // It is basically equivalent to js::Vector, and is implemented 184 // as a thin wrapper. 185 // V8's implementation: 186 // https://github.com/v8/v8/blob/main/src/base/small-vector.h 187 template <typename T, size_t kSize, typename Allocator = DefaultAllocator> 188 class SmallVector { 189 public: 190 explicit SmallVector(const Allocator& allocator = DefaultAllocator()) 191 : inner_(allocator.policy()) {} 192 SmallVector(size_t size) { resize(size); } 193 194 inline bool empty() const { return inner_.empty(); } 195 inline const T& back() const { return inner_.back(); } 196 inline void pop_back() { inner_.popBack(); }; 197 template <typename... Args> 198 inline void emplace_back(Args&&... args) { 199 js::AutoEnterOOMUnsafeRegion oomUnsafe; 200 if (!inner_.emplaceBack(args...)) { 201 oomUnsafe.crash("Irregexp SmallVector emplace_back"); 202 } 203 }; 204 inline size_t size() const { return inner_.length(); } 205 inline const T& at(size_t index) const { return inner_[index]; } 206 T* data() { return inner_.begin(); } 207 T* begin() { return inner_.begin(); } 208 209 T& operator[](size_t index) { return inner_[index]; } 210 const T& operator[](size_t index) const { return inner_[index]; } 211 212 inline void clear() { inner_.clear(); } 213 214 void resize(size_t new_size) { 215 js::AutoEnterOOMUnsafeRegion oomUnsafe; 216 if (!inner_.resize(new_size)) { 217 oomUnsafe.crash("Irregexp SmallVector resize"); 218 } 219 } 220 221 private: 222 js::Vector<T, kSize, typename Allocator::Policy> inner_; 223 }; 224 225 } // namespace base 226 227 } // namespace v8 228 229 #endif // V8_UTIL_VECTOR_H_