Coverage Report

Created: 2025-12-30 08:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/deps/v8/include/v8-memory-span.h
Line
Count
Source
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 <compare>
12
#include <cstddef>
13
#include <iterator>
14
#include <ranges>
15
#include <type_traits>
16
17
#include "v8config.h"  // NOLINT(build/include_directory)
18
19
namespace v8 {
20
21
template <typename T>
22
class V8_EXPORT MemorySpan;
23
24
}  // namespace v8
25
26
// Mark `MemorySpan` as satisfying the `view` and `borrowed_range` concepts.
27
// This should be done before the definition of `MemorySpan`, so that any
28
// inlined calls to range functionality use the correct specializations.
29
template <typename T>
30
inline constexpr bool std::ranges::enable_view<v8::MemorySpan<T>> = true;
31
template <typename T>
32
inline constexpr bool std::ranges::enable_borrowed_range<v8::MemorySpan<T>> =
33
    true;
34
35
namespace v8 {
36
37
/**
38
 * Points to an unowned contiguous buffer holding a known number of elements.
39
 *
40
 * This is similar to std::span (under consideration for C++20), but does not
41
 * require advanced C++ support. In the (far) future, this may be replaced with
42
 * or aliased to std::span.
43
 *
44
 * To facilitate future migration, this class exposes a subset of the interface
45
 * implemented by std::span.
46
 */
47
template <typename T>
48
class V8_EXPORT MemorySpan {
49
 private:
50
  /** Some C++ machinery, brought from the future. */
51
  template <typename From, typename To>
52
  using is_array_convertible = std::is_convertible<From (*)[], To (*)[]>;
53
  template <typename From, typename To>
54
  static constexpr bool is_array_convertible_v =
55
      is_array_convertible<From, To>::value;
56
57
  template <typename It>
58
  using iter_reference_t = decltype(*std::declval<It&>());
59
60
  template <typename It, typename = void>
61
  struct is_compatible_iterator : std::false_type {};
62
  template <typename It>
63
  struct is_compatible_iterator<
64
      It,
65
      std::void_t<
66
          std::is_base_of<std::random_access_iterator_tag,
67
                          typename std::iterator_traits<It>::iterator_category>,
68
          is_array_convertible<std::remove_reference_t<iter_reference_t<It>>,
69
                               T>>> : std::true_type {};
70
  template <typename It>
71
  static constexpr bool is_compatible_iterator_v =
72
      is_compatible_iterator<It>::value;
73
74
  // SFINAE-compatible wrapper for `std::to_address()`.
75
  // Adapted from "base/types/to_address.h" in chromium.
76
  template <typename U>
77
    requires(!std::is_function_v<U>)
78
35
  [[nodiscard]] static constexpr U* to_address(U* p) noexcept {
79
35
    return p;
80
35
  }
Unexecuted instantiation: _ZN2v810MemorySpanIKhE10to_addressIS1_Qntsr3stdE13is_function_vITL0__EEEPT_S6_
_ZN2v810MemorySpanIKNS_9CFunctionEE10to_addressIS1_Qntsr3stdE13is_function_vITL0__EEEPT_S7_
Line
Count
Source
78
35
  [[nodiscard]] static constexpr U* to_address(U* p) noexcept {
79
35
    return p;
80
35
  }
81
82
  template <typename It>
83
    requires(
84
        requires(const It& it) { std::pointer_traits<It>::to_address(it); } ||
85
        requires(const It& it) { it.operator->(); })
86
0
  [[nodiscard]] static constexpr auto to_address(const It& it) noexcept {
87
0
    return std::to_address(it);
88
0
  }
89
90
 public:
91
  /** The default constructor creates an empty span. */
92
  constexpr MemorySpan() = default;
93
94
  /** Constructor from nullptr and count, for backwards compatibility.
95
   * This is not compatible with C++20 std::span.
96
   */
97
  constexpr MemorySpan(std::nullptr_t, size_t) {}
98
99
  /** Constructor from "iterator" and count. */
100
  template <typename Iterator,
101
            std::enable_if_t<is_compatible_iterator_v<Iterator>, bool> = true>
102
  constexpr MemorySpan(Iterator first,
103
                       size_t count)  // NOLINT(runtime/explicit)
104
35
      : data_(to_address(first)), size_(count) {}
Unexecuted instantiation: _ZN2v810MemorySpanIKNS_5LocalINS_6StringEEEEC2INS_8internal15WrappedIteratorINSt3__111__wrap_iterIPNS7_14LocalUncheckedIS2_EEEES3_EETnNS9_9enable_ifIX24is_compatible_iterator_vIT_EEbE4typeELb1EEESH_m
_ZN2v810MemorySpanIKNS_9CFunctionEEC2IPS1_TnNSt3__19enable_ifIX24is_compatible_iterator_vIT_EEbE4typeELb1EEES8_m
Line
Count
Source
104
35
      : data_(to_address(first)), size_(count) {}
105
106
  /** Constructor from two "iterators". */
107
  template <typename Iterator,
108
            std::enable_if_t<is_compatible_iterator_v<Iterator> &&
109
                                 !std::is_convertible_v<Iterator, size_t>,
110
                             bool> = true>
111
  constexpr MemorySpan(Iterator first,
112
                       Iterator last)  // NOLINT(runtime/explicit)
113
      : data_(to_address(first)), size_(last - first) {}
114
115
  /** Implicit conversion from C-style array. */
116
  template <size_t N>
117
  constexpr MemorySpan(T (&a)[N]) noexcept  // NOLINT(runtime/explicit)
118
70
      : data_(a), size_(N) {}
Unexecuted instantiation: v8::MemorySpan<std::__1::basic_string_view<char, std::__1::char_traits<char> > const>::MemorySpan<6ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> > const (&) [6ul])
Unexecuted instantiation: v8::MemorySpan<v8::MaybeLocal<v8::Value> >::MemorySpan<6ul>(v8::MaybeLocal<v8::Value> (&) [6ul])
v8::MemorySpan<std::__1::basic_string_view<char, std::__1::char_traits<char> > const>::MemorySpan<5ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> > const (&) [5ul])
Line
Count
Source
118
35
      : data_(a), size_(N) {}
v8::MemorySpan<v8::MaybeLocal<v8::Value> >::MemorySpan<5ul>(v8::MaybeLocal<v8::Value> (&) [5ul])
Line
Count
Source
118
35
      : data_(a), size_(N) {}
Unexecuted instantiation: v8::MemorySpan<std::__1::basic_string_view<char, std::__1::char_traits<char> > const>::MemorySpan<3ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> > const (&) [3ul])
Unexecuted instantiation: v8::MemorySpan<std::__1::basic_string_view<char, std::__1::char_traits<char> > const>::MemorySpan<2ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> > const (&) [2ul])
Unexecuted instantiation: v8::MemorySpan<v8::MaybeLocal<v8::Value> >::MemorySpan<2ul>(v8::MaybeLocal<v8::Value> (&) [2ul])
Unexecuted instantiation: v8::MemorySpan<v8::MaybeLocal<v8::Value> >::MemorySpan<3ul>(v8::MaybeLocal<v8::Value> (&) [3ul])
Unexecuted instantiation: v8::MemorySpan<std::__1::basic_string_view<char, std::__1::char_traits<char> > const>::MemorySpan<9ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> > const (&) [9ul])
Unexecuted instantiation: v8::MemorySpan<v8::MaybeLocal<v8::Value> >::MemorySpan<9ul>(v8::MaybeLocal<v8::Value> (&) [9ul])
Unexecuted instantiation: v8::MemorySpan<std::__1::basic_string_view<char, std::__1::char_traits<char> > const>::MemorySpan<4ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> > const (&) [4ul])
Unexecuted instantiation: v8::MemorySpan<v8::MaybeLocal<v8::Value> >::MemorySpan<4ul>(v8::MaybeLocal<v8::Value> (&) [4ul])
Unexecuted instantiation: v8::MemorySpan<std::__1::basic_string_view<char, std::__1::char_traits<char> > const>::MemorySpan<15ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> > const (&) [15ul])
Unexecuted instantiation: v8::MemorySpan<v8::MaybeLocal<v8::Value> >::MemorySpan<15ul>(v8::MaybeLocal<v8::Value> (&) [15ul])
Unexecuted instantiation: v8::MemorySpan<std::__1::basic_string_view<char, std::__1::char_traits<char> > const>::MemorySpan<19ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> > const (&) [19ul])
Unexecuted instantiation: v8::MemorySpan<v8::MaybeLocal<v8::Value> >::MemorySpan<19ul>(v8::MaybeLocal<v8::Value> (&) [19ul])
Unexecuted instantiation: v8::MemorySpan<std::__1::basic_string_view<char, std::__1::char_traits<char> > const>::MemorySpan<7ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> > const (&) [7ul])
Unexecuted instantiation: v8::MemorySpan<v8::MaybeLocal<v8::Value> >::MemorySpan<7ul>(v8::MaybeLocal<v8::Value> (&) [7ul])
Unexecuted instantiation: v8::MemorySpan<std::__1::basic_string_view<char, std::__1::char_traits<char> > const>::MemorySpan<8ul>(std::__1::basic_string_view<char, std::__1::char_traits<char> > const (&) [8ul])
Unexecuted instantiation: v8::MemorySpan<v8::MaybeLocal<v8::Value> >::MemorySpan<8ul>(v8::MaybeLocal<v8::Value> (&) [8ul])
119
120
  /** Implicit conversion from std::array. */
121
  template <typename U, size_t N,
122
            std::enable_if_t<is_array_convertible_v<U, T>, bool> = true>
123
  constexpr MemorySpan(
124
      std::array<U, N>& a) noexcept  // NOLINT(runtime/explicit)
125
      : data_(a.data()), size_{N} {}
126
127
  /** Implicit conversion from const std::array. */
128
  template <typename U, size_t N,
129
            std::enable_if_t<is_array_convertible_v<const U, T>, bool> = true>
130
  constexpr MemorySpan(
131
      const std::array<U, N>& a) noexcept  // NOLINT(runtime/explicit)
132
      : data_(a.data()), size_{N} {}
133
134
  /** Returns a pointer to the beginning of the buffer. */
135
  [[nodiscard]] constexpr T* data() const { return data_; }
136
  /** Returns the number of elements that the buffer holds. */
137
0
  [[nodiscard]] constexpr size_t size() const { return size_; }
138
139
  [[nodiscard]] constexpr T& operator[](size_t i) const { return data_[i]; }
140
141
  /** Returns true if the buffer is empty. */
142
0
  [[nodiscard]] constexpr bool empty() const { return size() == 0; }
143
144
  class Iterator {
145
   public:
146
    using difference_type = std::ptrdiff_t;
147
    using value_type = T;
148
    using pointer = value_type*;
149
    using reference = value_type&;
150
    using iterator_category = std::random_access_iterator_tag;
151
    using iterator_concept = std::contiguous_iterator_tag;
152
153
    // Required to satisfy `std::semiregular<>`.
154
    constexpr Iterator() = default;
155
156
210
    [[nodiscard]] constexpr bool operator==(const Iterator&) const = default;
157
    [[nodiscard]] constexpr auto operator<=>(const Iterator&) const = default;
158
159
175
    constexpr Iterator& operator++() {
160
175
      ++ptr_;
161
175
      return *this;
162
175
    }
163
164
    constexpr Iterator operator++(int) {
165
      Iterator temp = *this;
166
      ++*this;
167
      return temp;
168
    }
169
170
    constexpr Iterator& operator--() {
171
      --ptr_;
172
      return *this;
173
    }
174
175
    constexpr Iterator operator--(int) {
176
      Iterator temp = *this;
177
      --*this;
178
      return temp;
179
    }
180
181
    constexpr Iterator& operator+=(difference_type rhs) {
182
      ptr_ += rhs;
183
      return *this;
184
    }
185
186
    [[nodiscard]] friend constexpr Iterator operator+(Iterator lhs,
187
                                                      difference_type rhs) {
188
      lhs += rhs;
189
      return lhs;
190
    }
191
192
    [[nodiscard]] friend constexpr Iterator operator+(difference_type lhs,
193
                                                      const Iterator& rhs) {
194
      return rhs + lhs;
195
    }
196
197
    constexpr Iterator& operator-=(difference_type rhs) {
198
      ptr_ -= rhs;
199
      return *this;
200
    }
201
202
    [[nodiscard]] friend constexpr Iterator operator-(Iterator lhs,
203
                                                      difference_type rhs) {
204
      lhs -= rhs;
205
      return lhs;
206
    }
207
208
    [[nodiscard]] friend constexpr difference_type operator-(
209
        const Iterator& lhs, const Iterator& rhs) {
210
      return lhs.ptr_ - rhs.ptr_;
211
    }
212
213
175
    [[nodiscard]] constexpr reference operator*() const { return *ptr_; }
214
    [[nodiscard]] constexpr pointer operator->() const { return ptr_; }
215
    [[nodiscard]] constexpr reference operator[](size_t offset) const {
216
      return ptr_[offset];
217
    }
218
219
   private:
220
    friend class MemorySpan<T>;
221
222
70
    constexpr explicit Iterator(T* ptr) : ptr_(ptr) {}
223
224
    T* ptr_ = nullptr;
225
  };
226
227
35
  [[nodiscard]] Iterator begin() const { return Iterator(data_); }
228
35
  [[nodiscard]] Iterator end() const { return Iterator(data_ + size_); }
229
230
 private:
231
  T* data_ = nullptr;
232
  size_t size_ = 0;
233
};
234
235
/**
236
 * Helper function template to create an array of fixed length, initialized by
237
 * the provided initializer list, without explicitly specifying the array size,
238
 * e.g.
239
 *
240
 *   auto arr = v8::to_array<Local<String>>({v8_str("one"), v8_str("two")});
241
 *
242
 * In the future, this may be replaced with or aliased to std::to_array (under
243
 * consideration for C++20).
244
 */
245
246
namespace detail {
247
template <class T, std::size_t N, std::size_t... I>
248
[[nodiscard]] constexpr std::array<std::remove_cv_t<T>, N> to_array_lvalue_impl(
249
    T (&a)[N], std::index_sequence<I...>) {
250
  return {{a[I]...}};
251
}
252
253
template <class T, std::size_t N, std::size_t... I>
254
[[nodiscard]] constexpr std::array<std::remove_cv_t<T>, N> to_array_rvalue_impl(
255
    T (&&a)[N], std::index_sequence<I...>) {
256
  return {{std::move(a[I])...}};
257
}
258
}  // namespace detail
259
260
template <class T, std::size_t N>
261
[[nodiscard]] constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N]) {
262
  return detail::to_array_lvalue_impl(a, std::make_index_sequence<N>{});
263
}
264
265
template <class T, std::size_t N>
266
[[nodiscard]] constexpr std::array<std::remove_cv_t<T>, N> to_array(
267
    T (&&a)[N]) {
268
  return detail::to_array_rvalue_impl(std::move(a),
269
                                      std::make_index_sequence<N>{});
270
}
271
272
}  // namespace v8
273
#endif  // INCLUDE_V8_MEMORY_SPAN_H_