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>
37class V8_EXPORT MemorySpan;
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
63template <typename T>
65 private:
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 =
71 is_array_convertible<From, To>::value;
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>
79 struct is_compatible_iterator<
80 It,
81 std::void_t<
82 std::is_base_of<std::random_access_iterator_tag,
83 typename std::iterator_traits<It>::iterator_category>,
84 is_array_convertible<std::remove_reference_t<iter_reference_t<It>>,
85 T>>> : std::true_type {};
86 template <typename It>
87 static constexpr bool is_compatible_iterator_v =
88 is_compatible_iterator<It>::value;
89
90 template <typename U>
91 [[nodiscard]] static constexpr U* to_address(U* p) noexcept {
92 return p;
93 }
94
95 template <typename It,
96 typename = std::void_t<decltype(std::declval<It&>().operator->())>>
97 [[nodiscard]] static constexpr auto to_address(It it) noexcept {
98 return it.operator->();
99 }
100
101 public:
103 constexpr MemorySpan() = default;
104
108 constexpr MemorySpan(std::nullptr_t, size_t) {}
109
111 template <typename Iterator,
112 std::enable_if_t<is_compatible_iterator_v<Iterator>, bool> = true>
113 constexpr MemorySpan(Iterator first,
114 size_t count) // NOLINT(runtime/explicit)
115 : data_(to_address(first)), size_(count) {}
116
118 template <typename Iterator,
119 std::enable_if_t<is_compatible_iterator_v<Iterator> &&
120 !std::is_convertible_v<Iterator, size_t>,
121 bool> = true>
122 constexpr MemorySpan(Iterator first,
123 Iterator last) // NOLINT(runtime/explicit)
124 : data_(to_address(first)), size_(last - first) {}
125
127 template <size_t N>
128 constexpr MemorySpan(T (&a)[N]) noexcept // NOLINT(runtime/explicit)
129 : data_(a), size_(N) {}
130
132 template <typename U, size_t N,
133 std::enable_if_t<is_array_convertible_v<U, T>, bool> = true>
134 constexpr MemorySpan(
135 std::array<U, N>& a) noexcept // NOLINT(runtime/explicit)
136 : data_(a.data()), size_{N} {}
137
139 template <typename U, size_t N,
140 std::enable_if_t<is_array_convertible_v<const U, T>, bool> = true>
141 constexpr MemorySpan(
142 const std::array<U, N>& a) noexcept // NOLINT(runtime/explicit)
143 : data_(a.data()), size_{N} {}
144
146 [[nodiscard]] constexpr T* data() const { return data_; }
148 [[nodiscard]] constexpr size_t size() const { return size_; }
149
150 [[nodiscard]] constexpr T& operator[](size_t i) const { return data_[i]; }
151
153 [[nodiscard]] constexpr bool empty() const { return size() == 0; }
154
155 class Iterator {
156 public:
157 using difference_type = std::ptrdiff_t;
158 using value_type = T;
161 using iterator_category = std::random_access_iterator_tag;
162 // There seems to be no feature-test macro covering this, so use the
163 // presence of `<ranges>` as a crude proxy, since it was added to the
164 // standard as part of the Ranges papers.
165 // TODO(pkasting): Add this unconditionally after dropping support for old
166 // libstdc++ versions.
167#if __has_include(<ranges>)
168 using iterator_concept = std::contiguous_iterator_tag;
169#endif
170
171 // Required to satisfy `std::semiregular<>`.
172 constexpr Iterator() = default;
173
174 [[nodiscard]] friend constexpr bool operator==(const Iterator& a,
175 const Iterator& b) {
176 // TODO(pkasting): Replace this body with `= default` after dropping
177 // support for old gcc versions.
178 return a.ptr_ == b.ptr_;
179 }
180#if V8_HAVE_SPACESHIP_OPERATOR
181 [[nodiscard]] friend constexpr auto operator<=>(const Iterator&,
182 const Iterator&) = default;
183#else
184 // Assume that if spaceship isn't present, operator rewriting might not be
185 // either.
186 [[nodiscard]] friend constexpr bool operator!=(const Iterator& a,
187 const Iterator& b) {
188 return a.ptr_ != b.ptr_;
189 }
190
191 [[nodiscard]] friend constexpr bool operator<(const Iterator& a,
192 const Iterator& b) {
193 return a.ptr_ < b.ptr_;
194 }
195 [[nodiscard]] friend constexpr bool operator<=(const Iterator& a,
196 const Iterator& b) {
197 return a.ptr_ <= b.ptr_;
198 }
199 [[nodiscard]] friend constexpr bool operator>(const Iterator& a,
200 const Iterator& b) {
201 return a.ptr_ > b.ptr_;
202 }
203 [[nodiscard]] friend constexpr bool operator>=(const Iterator& a,
204 const Iterator& b) {
205 return a.ptr_ >= b.ptr_;
206 }
207#endif
208
209 constexpr Iterator& operator++() {
210 ++ptr_;
211 return *this;
212 }
213
214 constexpr Iterator operator++(int) {
215 Iterator temp = *this;
216 ++*this;
217 return temp;
218 }
219
220 constexpr Iterator& operator--() {
221 --ptr_;
222 return *this;
223 }
224
225 constexpr Iterator operator--(int) {
226 Iterator temp = *this;
227 --*this;
228 return temp;
229 }
230
232 ptr_ += rhs;
233 return *this;
234 }
235
236 [[nodiscard]] friend constexpr Iterator operator+(Iterator lhs,
237 difference_type rhs) {
238 lhs += rhs;
239 return lhs;
240 }
241
242 [[nodiscard]] friend constexpr Iterator operator+(difference_type lhs,
243 const Iterator& rhs) {
244 return rhs + lhs;
245 }
246
248 ptr_ -= rhs;
249 return *this;
250 }
251
252 [[nodiscard]] friend constexpr Iterator operator-(Iterator lhs,
253 difference_type rhs) {
254 lhs -= rhs;
255 return lhs;
256 }
257
258 [[nodiscard]] friend constexpr difference_type operator-(
259 const Iterator& lhs, const Iterator& rhs) {
260 return lhs.ptr_ - rhs.ptr_;
261 }
262
263 [[nodiscard]] constexpr reference operator*() const { return *ptr_; }
264 [[nodiscard]] constexpr pointer operator->() const { return ptr_; }
265 [[nodiscard]] constexpr reference operator[](size_t offset) const {
266 return ptr_[offset];
267 }
268
269 private:
270 friend class MemorySpan<T>;
271
272 constexpr explicit Iterator(T* ptr) : ptr_(ptr) {}
273
274 T* ptr_ = nullptr;
275 };
276
277 [[nodiscard]] Iterator begin() const { return Iterator(data_); }
278 [[nodiscard]] Iterator end() const { return Iterator(data_ + size_); }
279
280 private:
281 T* data_ = nullptr;
282 size_t size_ = 0;
283};
284
296namespace detail {
297template <class T, std::size_t N, std::size_t... I>
298[[nodiscard]] constexpr std::array<std::remove_cv_t<T>, N> to_array_lvalue_impl(
299 T (&a)[N], std::index_sequence<I...>) {
300 return {{a[I]...}};
301}
302
303template <class T, std::size_t N, std::size_t... I>
304[[nodiscard]] constexpr std::array<std::remove_cv_t<T>, N> to_array_rvalue_impl(
305 T (&&a)[N], std::index_sequence<I...>) {
306 return {{std::move(a[I])...}};
307}
308} // namespace detail
309
310template <class T, std::size_t N>
311[[nodiscard]] constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N]) {
312 return detail::to_array_lvalue_impl(a, std::make_index_sequence<N>{});
313}
314
315template <class T, std::size_t N>
316[[nodiscard]] constexpr std::array<std::remove_cv_t<T>, N> to_array(
317 T (&&a)[N]) {
318 return detail::to_array_rvalue_impl(std::move(a),
319 std::make_index_sequence<N>{});
320}
321
322} // namespace v8
323#endif // INCLUDE_V8_MEMORY_SPAN_H_
Definition: v8-memory-span.h:155
std::ptrdiff_t difference_type
Definition: v8-memory-span.h:157
friend constexpr bool operator>(const Iterator &a, const Iterator &b)
Definition: v8-memory-span.h:199
friend constexpr difference_type operator-(const Iterator &lhs, const Iterator &rhs)
Definition: v8-memory-span.h:258
constexpr Iterator & operator+=(difference_type rhs)
Definition: v8-memory-span.h:231
friend constexpr Iterator operator+(Iterator lhs, difference_type rhs)
Definition: v8-memory-span.h:236
constexpr Iterator & operator++()
Definition: v8-memory-span.h:209
friend constexpr bool operator>=(const Iterator &a, const Iterator &b)
Definition: v8-memory-span.h:203
friend constexpr bool operator==(const Iterator &a, const Iterator &b)
Definition: v8-memory-span.h:174
std::random_access_iterator_tag iterator_category
Definition: v8-memory-span.h:161
T value_type
Definition: v8-memory-span.h:158
constexpr Iterator()=default
friend constexpr bool operator!=(const Iterator &a, const Iterator &b)
Definition: v8-memory-span.h:186
value_type & reference
Definition: v8-memory-span.h:160
constexpr reference operator*() const
Definition: v8-memory-span.h:263
friend constexpr Iterator operator+(difference_type lhs, const Iterator &rhs)
Definition: v8-memory-span.h:242
constexpr Iterator operator--(int)
Definition: v8-memory-span.h:225
constexpr Iterator operator++(int)
Definition: v8-memory-span.h:214
value_type * pointer
Definition: v8-memory-span.h:159
friend constexpr bool operator<(const Iterator &a, const Iterator &b)
Definition: v8-memory-span.h:191
constexpr Iterator & operator-=(difference_type rhs)
Definition: v8-memory-span.h:247
friend constexpr Iterator operator-(Iterator lhs, difference_type rhs)
Definition: v8-memory-span.h:252
friend constexpr bool operator<=(const Iterator &a, const Iterator &b)
Definition: v8-memory-span.h:195
constexpr Iterator & operator--()
Definition: v8-memory-span.h:220
constexpr pointer operator->() const
Definition: v8-memory-span.h:264
Definition: v8-memory-span.h:64
constexpr MemorySpan(std::nullptr_t, size_t)
Definition: v8-memory-span.h:108
Iterator end() const
Definition: v8-memory-span.h:278
constexpr MemorySpan(std::array< U, N > &a) noexcept
Definition: v8-memory-span.h:134
constexpr MemorySpan()=default
constexpr T & operator[](size_t i) const
Definition: v8-memory-span.h:150
constexpr MemorySpan(const std::array< U, N > &a) noexcept
Definition: v8-memory-span.h:141
constexpr MemorySpan(Iterator first, size_t count)
Definition: v8-memory-span.h:113
constexpr MemorySpan(T(&a)[N]) noexcept
Definition: v8-memory-span.h:128
constexpr T * data() const
Definition: v8-memory-span.h:146
constexpr MemorySpan(Iterator first, Iterator last)
Definition: v8-memory-span.h:122
constexpr bool empty() const
Definition: v8-memory-span.h:153
Iterator begin() const
Definition: v8-memory-span.h:277
constexpr size_t size() const
Definition: v8-memory-span.h:148
constexpr std::array< std::remove_cv_t< T >, N > to_array_rvalue_impl(T(&&a)[N], std::index_sequence< I... >)
Definition: v8-memory-span.h:304
constexpr std::array< std::remove_cv_t< T >, N > to_array_lvalue_impl(T(&a)[N], std::index_sequence< I... >)
Definition: v8-memory-span.h:298
Definition: libplatform.h:15
constexpr std::array< std::remove_cv_t< T >, N > to_array(T(&a)[N])
Definition: v8-memory-span.h:311
#define V8_EXPORT
Definition: v8config.h:793