// Copyright 2014 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_UTIL_VECTOR_H_ #define V8_UTIL_VECTOR_H_ #include #include #include #include #include "js/AllocPolicy.h" #include "js/Utility.h" #include "js/Vector.h" namespace v8 { namespace internal { ////////////////////////////////////////////////// // Adapted from: // https://github.com/v8/v8/blob/5f69bbc233c2d1baf149faf869a7901603929914/src/utils/allocation.h#L36-L58 template T* NewArray(size_t size) { static_assert(std::is_pod::value, ""); js::AutoEnterOOMUnsafeRegion oomUnsafe; T* result = static_cast(js_malloc(size * sizeof(T))); if (!result) { oomUnsafe.crash("Irregexp NewArray"); } return result; } template void DeleteArray(T* array) { js_free(array); } ////////////////////////////////////////////////// // A non-resizable vector containing a pointer and a length. // The Vector may or may not own the pointer, depending on context. // Origin: // https://github.com/v8/v8/blob/5f69bbc233c2d1baf149faf869a7901603929914/src/utils/vector.h#L20-L134 template class Vector { public: constexpr Vector() : start_(nullptr), length_(0) {} constexpr Vector(T* data, size_t length) : start_(data), length_(length) { MOZ_ASSERT_IF(length != 0, data != nullptr); } static Vector New(size_t length) { return Vector(NewArray(length), length); } // Returns a vector using the same backing storage as this one, // spanning from and including 'from', to but not including 'to'. Vector SubVector(size_t from, size_t to) const { MOZ_ASSERT(from <= to); MOZ_ASSERT(to <= length_); return Vector(begin() + from, to - from); } // Returns the length of the vector. Only use this if you really need an // integer return value. Use {size()} otherwise. int length() const { MOZ_ASSERT(length_ <= static_cast(std::numeric_limits::max())); return static_cast(length_); } // Returns the length of the vector as a size_t. constexpr size_t size() const { return length_; } // Returns whether or not the vector is empty. constexpr bool empty() const { return length_ == 0; } // Access individual vector elements - checks bounds in debug mode. T& operator[](size_t index) const { MOZ_ASSERT(index < length_); return start_[index]; } const T& at(size_t index) const { return operator[](index); } T& first() { return start_[0]; } T& last() { MOZ_ASSERT(length_ > 0); return start_[length_ - 1]; } // Returns a pointer to the start of the data in the vector. constexpr T* begin() const { return start_; } // Returns a pointer past the end of the data in the vector. constexpr T* end() const { return start_ + length_; } // Returns a clone of this vector with a new backing store. Vector Clone() const { T* result = NewArray(length_); for (size_t i = 0; i < length_; i++) result[i] = start_[i]; return Vector(result, length_); } void Truncate(size_t length) { MOZ_ASSERT(length <= length_); length_ = length; } // Releases the array underlying this vector. Once disposed the // vector is empty. void Dispose() { DeleteArray(start_); start_ = nullptr; length_ = 0; } Vector operator+(size_t offset) { MOZ_ASSERT(offset <= length_); return Vector(start_ + offset, length_ - offset); } Vector operator+=(size_t offset) { MOZ_ASSERT(offset <= length_); start_ += offset; length_ -= offset; return *this; } // Implicit conversion from Vector to Vector. inline operator Vector() const { return Vector::cast(*this); } template static constexpr Vector cast(Vector input) { return Vector(reinterpret_cast(input.begin()), input.length() * sizeof(S) / sizeof(T)); } bool operator==(const Vector other) const { if (length_ != other.length_) return false; if (start_ == other.start_) return true; for (size_t i = 0; i < length_; ++i) { if (start_[i] != other.start_[i]) { return false; } } return true; } private: T* start_; size_t length_; }; // The resulting vector does not contain a null-termination byte. If you want // the null byte, use ArrayVector("foo"). inline Vector CStrVector(const char* data) { return Vector(data, strlen(data)); } } // namespace internal namespace base { // SmallVector uses inline storage first, and reallocates when full. // It is basically equivalent to js::Vector, and is implemented // as a thin wrapper. // V8's implementation: // https://github.com/v8/v8/blob/master/src/base/small-vector.h template class SmallVector { public: SmallVector() = default; SmallVector(size_t size) { resize_no_init(size); } inline bool empty() const { return inner_.empty(); } inline const T& back() const { return inner_.back(); } inline void pop_back() { inner_.popBack(); }; template inline void emplace_back(Args&&... args) { js::AutoEnterOOMUnsafeRegion oomUnsafe; if (!inner_.emplaceBack(args...)) { oomUnsafe.crash("Irregexp SmallVector emplace_back"); } }; inline size_t size() const { return inner_.length(); } inline const T& at(size_t index) const { return inner_[index]; } T* data() { return inner_.begin(); } T& operator[](size_t index) { return inner_[index]; } const T& operator[](size_t index) const { return inner_[index]; } void resize_no_init(size_t new_size) { js::AutoEnterOOMUnsafeRegion oomUnsafe; if (!inner_.resizeUninitialized(new_size)) { oomUnsafe.crash("Irregexp SmallVector resize"); } } private: js::Vector inner_; }; } // namespace base } // namespace v8 #endif // V8_UTIL_VECTOR_H_