v8 14.1.146 (node 25.0.0)
V8 is Google's open source JavaScript engine
Loading...
Searching...
No Matches
v8-memory-span.h
Go to the documentation of this file.
1// Copyright 2021 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 INCLUDE_V8_MEMORY_SPAN_H_
6#define INCLUDE_V8_MEMORY_SPAN_H_
7
8#include <stddef.h>
9
10#include <array>
11#include <cstddef>
12#include <iterator>
13#include <type_traits>
14
15#include "v8config.h" // NOLINT(build/include_directory)
16
17// TODO(pkasting): Use <compare>/spaceship unconditionally after dropping
18// support for old libstdc++ versions.
19#if __has_include(<version>)
20#include <version>
21#endif
22#if defined(__cpp_lib_three_way_comparison) &&
23 __cpp_lib_three_way_comparison >= 201711L
24#define V8_HAVE_SPACESHIP_OPERATOR 1
25#else
26#define V8_HAVE_SPACESHIP_OPERATOR 0
27#endif
28
29// TODO(pkasting): Make this block unconditional after dropping support for old
30// libstdc++ versions.
31#if __has_include(<ranges>)
32#include <ranges>
33
34namespace v8 {
35
36template <typename T>
38
39} // namespace v8
40
41// Mark `MemorySpan` as satisfying the `view` and `borrowed_range` concepts.
42// This should be done before the definition of `MemorySpan`, so that any
43// inlined calls to range functionality use the correct specializations.
44template <typename T>
45inline constexpr bool std::ranges::enable_view<v8::MemorySpan<T>> = true;
46template <typename T>
47inline constexpr bool std::ranges::enable_borrowed_range<v8::MemorySpan<T>> =
48 true;
49#endif
50
51namespace v8 {
52
53/**
54 * Points to an unowned contiguous buffer holding a known number of elements.
55 *
56 * This is similar to std::span (under consideration for C++20), but does not
57 * require advanced C++ support. In the (far) future, this may be replaced with
58 * or aliased to std::span.
59 *
60 * To facilitate future migration, this class exposes a subset of the interface
61 * implemented by std::span.
62 */
63template <typename T>
65 private:
66 /** Some C++ machinery, brought from the future. */
67 template <typename From, typename To>
68 using is_array_convertible = std::is_convertible<From (*)[], To (*)[]>;
69 template <typename From, typename To>
70 static constexpr bool is_array_convertible_v =
72
73 template <typename It>
74 using iter_reference_t = decltype(*std::declval<It&>());
75
76 template <typename It, typename = void>
77 struct is_compatible_iterator : std::false_type {};
78 template <typename It>
80 It,
81 std::void_t<
85 T>>> : std::true_type {};
86 template <typename It>
87 static constexpr bool is_compatible_iterator_v =
89
90 // SFINAE-compatible wrapper for `std::to_address()`.
91 // Adapted from "base/types/to_address.h" in chromium.
92 template <typename U>
93 requires(!std::is_function_v<U>)
94 [[nodiscard]] static constexpr U* to_address(U* p) noexcept {
95 return p;
96 }
97
98 template <typename It>
100 requires(const It& it) { std::pointer_traits<It>::to_address(it); } ||
101 requires(const It& it) { it.operator->(); })
102 [[nodiscard]] static constexpr auto to_address(const It& it) noexcept {
103 return std::to_address(it);
104 }
105
106 public:
107 /** The default constructor creates an empty span. */
108 constexpr MemorySpan() = default;
109
110 /** Constructor from nullptr and count, for backwards compatibility.
111 * This is not compatible with C++20 std::span.
112 */
113 constexpr MemorySpan(std::nullptr_t, size_t) {}
114
115 /** Constructor from "iterator" and count. */
116 template <typename Iterator,
117 std::enable_if_t<is_compatible_iterator_v<Iterator>, bool> = true>
118 constexpr MemorySpan(Iterator first,
119 size_t count) // NOLINT(runtime/explicit)
120 : data_(to_address(first)), size_(count) {}
121
122 /** Constructor from two "iterators". */
123 template <typename Iterator,
124 std::enable_if_t<is_compatible_iterator_v<Iterator> &&
125 !std::is_convertible_v<Iterator, size_t>,
126 bool> = true>
127 constexpr MemorySpan(Iterator first,
128 Iterator last) // NOLINT(runtime/explicit)
129 : data_(to_address(first)), size_(last - first) {}
130
131 /** Implicit conversion from C-style array. */
132 template <size_t N>
133 constexpr MemorySpan(T (&a)[N]) noexcept // NOLINT(runtime/explicit)
134 : data_(a), size_(N) {}
135
136 /** Implicit conversion from std::array. */
137 template <typename U, size_t N,
138 std::enable_if_t<is_array_convertible_v<U, T>, bool> = true>
139 constexpr MemorySpan(
140 std::array<U, N>& a) noexcept // NOLINT(runtime/explicit)
141 : data_(a.data()), size_{N} {}
142
143 /** Implicit conversion from const std::array. */
144 template <typename U, size_t N,
145 std::enable_if_t<is_array_convertible_v<const U, T>, bool> = true>
146 constexpr MemorySpan(
147 const std::array<U, N>& a) noexcept // NOLINT(runtime/explicit)
148 : data_(a.data()), size_{N} {}
149
150 /** Returns a pointer to the beginning of the buffer. */
151 [[nodiscard]] constexpr T* data() const { return data_; }
152 /** Returns the number of elements that the buffer holds. */
153 [[nodiscard]] constexpr size_t size() const { return size_; }
154
155 [[nodiscard]] constexpr T& operator[](size_t i) const { return data_[i]; }
156
157 /** Returns true if the buffer is empty. */
158 [[nodiscard]] constexpr bool empty() const { return size() == 0; }
159
160 class Iterator {
161 public:
162 using difference_type = std::ptrdiff_t;
163 using value_type = T;
164 using pointer = value_type*;
165 using reference = value_type&;
166 using iterator_category = std::random_access_iterator_tag;
167 // There seems to be no feature-test macro covering this, so use the
168 // presence of `<ranges>` as a crude proxy, since it was added to the
169 // standard as part of the Ranges papers.
170 // TODO(pkasting): Add this unconditionally after dropping support for old
171 // libstdc++ versions.
172#if __has_include(<ranges>)
174#endif
175
176 // Required to satisfy `std::semiregular<>`.
177 constexpr Iterator() = default;
178
179 [[nodiscard]] friend constexpr bool operator==(const Iterator& a,
180 const Iterator& b) {
181 // TODO(pkasting): Replace this body with `= default` after dropping
182 // support for old gcc versions.
183 return a.ptr_ == b.ptr_;
184 }
186 [[nodiscard]] friend constexpr auto operator<=>(const Iterator&,
187 const Iterator&) = default;
188#else
189 // Assume that if spaceship isn't present, operator rewriting might not be
190 // either.
191 [[nodiscard]] friend constexpr bool operator!=(const Iterator& a,
192 const Iterator& b) {
193 return a.ptr_ != b.ptr_;
194 }
195
196 [[nodiscard]] friend constexpr bool operator<(const Iterator& a,
197 const Iterator& b) {
198 return a.ptr_ < b.ptr_;
199 }
200 [[nodiscard]] friend constexpr bool operator<=(const Iterator& a,
201 const Iterator& b) {
202 return a.ptr_ <= b.ptr_;
203 }
204 [[nodiscard]] friend constexpr bool operator>(const Iterator& a,
205 const Iterator& b) {
206 return a.ptr_ > b.ptr_;
207 }
208 [[nodiscard]] friend constexpr bool operator>=(const Iterator& a,
209 const Iterator& b) {
210 return a.ptr_ >= b.ptr_;
211 }
212#endif
213
214 constexpr Iterator& operator++() {
215 ++ptr_;
216 return *this;
217 }
218
219 constexpr Iterator operator++(int) {
220 Iterator temp = *this;
221 ++*this;
222 return temp;
223 }
224
225 constexpr Iterator& operator--() {
226 --ptr_;
227 return *this;
228 }
229
230 constexpr Iterator operator--(int) {
231 Iterator temp = *this;
232 --*this;
233 return temp;
234 }
235
236 constexpr Iterator& operator+=(difference_type rhs) {
237 ptr_ += rhs;
238 return *this;
239 }
240
241 [[nodiscard]] friend constexpr Iterator operator+(Iterator lhs,
242 difference_type rhs) {
243 lhs += rhs;
244 return lhs;
245 }
246
247 [[nodiscard]] friend constexpr Iterator operator+(difference_type lhs,
248 const Iterator& rhs) {
249 return rhs + lhs;
250 }
251
252 constexpr Iterator& operator-=(difference_type rhs) {
253 ptr_ -= rhs;
254 return *this;
255 }
256
257 [[nodiscard]] friend constexpr Iterator operator-(Iterator lhs,
258 difference_type rhs) {
259 lhs -= rhs;
260 return lhs;
261 }
262
263 [[nodiscard]] friend constexpr difference_type operator-(
264 const Iterator& lhs, const Iterator& rhs) {
265 return lhs.ptr_ - rhs.ptr_;
266 }
267
268 [[nodiscard]] constexpr reference operator*() const { return *ptr_; }
269 [[nodiscard]] constexpr pointer operator->() const { return ptr_; }
270 [[nodiscard]] constexpr reference operator[](size_t offset) const {
271 return ptr_[offset];
272 }
273
274 private:
275 friend class MemorySpan<T>;
276
277 constexpr explicit Iterator(T* ptr) : ptr_(ptr) {}
278
279 T* ptr_ = nullptr;
280 };
281
282 [[nodiscard]] Iterator begin() const { return Iterator(data_); }
283 [[nodiscard]] Iterator end() const { return Iterator(data_ + size_); }
284
285 private:
286 T* data_ = nullptr;
287 size_t size_ = 0;
288};
289
290/**
291 * Helper function template to create an array of fixed length, initialized by
292 * the provided initializer list, without explicitly specifying the array size,
293 * e.g.
294 *
295 * auto arr = v8::to_array<Local<String>>({v8_str("one"), v8_str("two")});
296 *
297 * In the future, this may be replaced with or aliased to std::to_array (under
298 * consideration for C++20).
299 */
300
301namespace detail {
302template <class T, std::size_t N, std::size_t... I>
303[[nodiscard]] constexpr std::array<std::remove_cv_t<T>, N> to_array_lvalue_impl(
304 T (&a)[N], std::index_sequence<I...>) {
305 return {{a[I]...}};
306}
307
308template <class T, std::size_t N, std::size_t... I>
309[[nodiscard]] constexpr std::array<std::remove_cv_t<T>, N> to_array_rvalue_impl(
310 T (&&a)[N], std::index_sequence<I...>) {
311 return {{std::move(a[I])...}};
312}
313} // namespace detail
314
315template <class T, std::size_t N>
316[[nodiscard]] constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N]) {
317 return detail::to_array_lvalue_impl(a, std::make_index_sequence<N>{});
318}
319
320template <class T, std::size_t N>
321[[nodiscard]] constexpr std::array<std::remove_cv_t<T>, N> to_array(
322 T (&&a)[N]) {
323 return detail::to_array_rvalue_impl(std::move(a),
324 std::make_index_sequence<N>{});
325}
326
327} // namespace v8
328#endif // INCLUDE_V8_MEMORY_SPAN_H_
constexpr Iterator operator--(int)
friend constexpr bool operator>(const Iterator &a, const Iterator &b)
friend constexpr difference_type operator-(const Iterator &lhs, const Iterator &rhs)
friend constexpr Iterator operator+(Iterator lhs, difference_type rhs)
friend constexpr bool operator>=(const Iterator &a, const Iterator &b)
friend constexpr bool operator==(const Iterator &a, const Iterator &b)
constexpr Iterator operator++(int)
constexpr Iterator & operator--()
friend constexpr bool operator!=(const Iterator &a, const Iterator &b)
constexpr reference operator[](size_t offset) const
friend constexpr Iterator operator+(difference_type lhs, const Iterator &rhs)
constexpr Iterator & operator++()
friend constexpr bool operator<(const Iterator &a, const Iterator &b)
friend constexpr Iterator operator-(Iterator lhs, difference_type rhs)
constexpr reference operator*() const
constexpr Iterator()=default
friend constexpr bool operator<=(const Iterator &a, const Iterator &b)
constexpr pointer operator->() const
constexpr Iterator & operator+=(difference_type rhs)
constexpr Iterator & operator-=(difference_type rhs)
Iterator begin() const
constexpr T * data() const
constexpr T & operator[](size_t i) const
constexpr MemorySpan(std::array< U, N > &a) noexcept
Iterator end() const
constexpr MemorySpan(std::nullptr_t, size_t)
constexpr MemorySpan(const std::array< U, N > &a) noexcept
constexpr MemorySpan(T(&a)[N]) noexcept
constexpr size_t size() const
constexpr MemorySpan(Iterator first, size_t count)
constexpr MemorySpan(Iterator first, Iterator last)
constexpr bool empty() const
constexpr std::array< std::remove_cv_t< T >, N > to_array(T(&a)[N])
constexpr std::array< std::remove_cv_t< T >, N > to_array(T(&&a)[N])
#define V8_HAVE_SPACESHIP_OPERATOR
Definition v8-internal.h:34
#define V8_EXPORT
Definition v8config.h:860