/src/node/deps/v8/include/v8-memory-span.h
Line | Count | Source (jump to first uncovered line) |
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 <iterator> |
12 | | #include <type_traits> |
13 | | |
14 | | #include "v8config.h" // NOLINT(build/include_directory) |
15 | | |
16 | | namespace v8 { |
17 | | |
18 | | /** |
19 | | * Points to an unowned contiguous buffer holding a known number of elements. |
20 | | * |
21 | | * This is similar to std::span (under consideration for C++20), but does not |
22 | | * require advanced C++ support. In the (far) future, this may be replaced with |
23 | | * or aliased to std::span. |
24 | | * |
25 | | * To facilitate future migration, this class exposes a subset of the interface |
26 | | * implemented by std::span. |
27 | | */ |
28 | | template <typename T> |
29 | | class V8_EXPORT MemorySpan { |
30 | | private: |
31 | | /** Some C++ machinery, brought from the future. */ |
32 | | template <typename From, typename To> |
33 | | using is_array_convertible = std::is_convertible<From (*)[], To (*)[]>; |
34 | | template <typename From, typename To> |
35 | | static constexpr bool is_array_convertible_v = |
36 | | is_array_convertible<From, To>::value; |
37 | | |
38 | | template <typename It> |
39 | | using iter_reference_t = decltype(*std::declval<It&>()); |
40 | | |
41 | | template <typename It, typename = void> |
42 | | struct is_compatible_iterator : std::false_type {}; |
43 | | template <typename It> |
44 | | struct is_compatible_iterator< |
45 | | It, |
46 | | std::void_t< |
47 | | std::is_base_of<std::random_access_iterator_tag, |
48 | | typename std::iterator_traits<It>::iterator_category>, |
49 | | is_array_convertible<std::remove_reference_t<iter_reference_t<It>>, |
50 | | T>>> : std::true_type {}; |
51 | | template <typename It> |
52 | | static constexpr bool is_compatible_iterator_v = |
53 | | is_compatible_iterator<It>::value; |
54 | | |
55 | | template <typename U> |
56 | 134k | static constexpr U* to_address(U* p) noexcept { |
57 | 134k | return p; |
58 | 134k | } |
59 | | |
60 | | template <typename It, |
61 | | typename = std::void_t<decltype(std::declval<It&>().operator->())>> |
62 | 0 | static constexpr auto to_address(It it) noexcept { |
63 | 0 | return it.operator->(); |
64 | 0 | } |
65 | | |
66 | | public: |
67 | | /** The default constructor creates an empty span. */ |
68 | | constexpr MemorySpan() = default; |
69 | | |
70 | | /** Constructor from nullptr and count, for backwards compatibility. |
71 | | * This is not compatible with C++20 std::span. |
72 | | */ |
73 | | constexpr MemorySpan(std::nullptr_t, size_t) {} |
74 | | |
75 | | /** Constructor from "iterator" and count. */ |
76 | | template <typename Iterator, |
77 | | std::enable_if_t<is_compatible_iterator_v<Iterator>, bool> = true> |
78 | | constexpr MemorySpan(Iterator first, |
79 | | size_t count) // NOLINT(runtime/explicit) |
80 | 134k | : data_(to_address(first)), size_(count) {} Unexecuted instantiation: _ZN2v810MemorySpanIKNS_5LocalINS_6StringEEEEC2INSt3__111__wrap_iterIPS3_EETnNS7_9enable_ifIX24is_compatible_iterator_vIT_EEbE4typeELb1EEESC_m _ZN2v810MemorySpanIKNS_9CFunctionEEC2IPS1_TnNSt3__19enable_ifIX24is_compatible_iterator_vIT_EEbE4typeELb1EEES8_m Line | Count | Source | 80 | 134k | : data_(to_address(first)), size_(count) {} |
|
81 | | |
82 | | /** Constructor from two "iterators". */ |
83 | | template <typename Iterator, |
84 | | std::enable_if_t<is_compatible_iterator_v<Iterator> && |
85 | | !std::is_convertible_v<Iterator, size_t>, |
86 | | bool> = true> |
87 | | constexpr MemorySpan(Iterator first, |
88 | | Iterator last) // NOLINT(runtime/explicit) |
89 | | : data_(to_address(first)), size_(last - first) {} |
90 | | |
91 | | /** Implicit conversion from C-style array. */ |
92 | | template <size_t N> |
93 | | constexpr MemorySpan(T (&a)[N]) noexcept // NOLINT(runtime/explicit) |
94 | | : data_(a), size_(N) {} |
95 | | |
96 | | /** Implicit conversion from std::array. */ |
97 | | template <typename U, size_t N, |
98 | | std::enable_if_t<is_array_convertible_v<U, T>, bool> = true> |
99 | | constexpr MemorySpan( |
100 | | std::array<U, N>& a) noexcept // NOLINT(runtime/explicit) |
101 | | : data_(a.data()), size_{N} {} |
102 | | |
103 | | /** Implicit conversion from const std::array. */ |
104 | | template <typename U, size_t N, |
105 | | std::enable_if_t<is_array_convertible_v<const U, T>, bool> = true> |
106 | | constexpr MemorySpan( |
107 | | const std::array<U, N>& a) noexcept // NOLINT(runtime/explicit) |
108 | | : data_(a.data()), size_{N} {} |
109 | | |
110 | | /** Returns a pointer to the beginning of the buffer. */ |
111 | | constexpr T* data() const { return data_; } |
112 | | /** Returns the number of elements that the buffer holds. */ |
113 | | constexpr size_t size() const { return size_; } |
114 | | |
115 | | constexpr T& operator[](size_t i) const { return data_[i]; } |
116 | | |
117 | | /** Returns true if the buffer is empty. */ |
118 | | constexpr bool empty() const { return size() == 0; } |
119 | | |
120 | | class Iterator { |
121 | | public: |
122 | | using iterator_category = std::forward_iterator_tag; |
123 | | using value_type = T; |
124 | | using difference_type = std::ptrdiff_t; |
125 | | using pointer = value_type*; |
126 | | using reference = value_type&; |
127 | | |
128 | | T& operator*() const { return *ptr_; } |
129 | | T* operator->() const { return ptr_; } |
130 | | |
131 | | bool operator==(Iterator other) const { return ptr_ == other.ptr_; } |
132 | | bool operator!=(Iterator other) const { return !(*this == other); } |
133 | | |
134 | | Iterator& operator++() { |
135 | | ++ptr_; |
136 | | return *this; |
137 | | } |
138 | | |
139 | | Iterator operator++(int) { |
140 | | Iterator temp(*this); |
141 | | ++(*this); |
142 | | return temp; |
143 | | } |
144 | | |
145 | | private: |
146 | | friend class MemorySpan<T>; |
147 | | |
148 | | explicit Iterator(T* ptr) : ptr_(ptr) {} |
149 | | |
150 | | T* ptr_ = nullptr; |
151 | | }; |
152 | | |
153 | | Iterator begin() const { return Iterator(data_); } |
154 | | Iterator end() const { return Iterator(data_ + size_); } |
155 | | |
156 | | private: |
157 | | T* data_ = nullptr; |
158 | | size_t size_ = 0; |
159 | | }; |
160 | | |
161 | | /** |
162 | | * Helper function template to create an array of fixed length, initialized by |
163 | | * the provided initializer list, without explicitly specifying the array size, |
164 | | * e.g. |
165 | | * |
166 | | * auto arr = v8::to_array<Local<String>>({v8_str("one"), v8_str("two")}); |
167 | | * |
168 | | * In the future, this may be replaced with or aliased to std::to_array (under |
169 | | * consideration for C++20). |
170 | | */ |
171 | | |
172 | | namespace detail { |
173 | | template <class T, std::size_t N, std::size_t... I> |
174 | | constexpr std::array<std::remove_cv_t<T>, N> to_array_lvalue_impl( |
175 | | T (&a)[N], std::index_sequence<I...>) { |
176 | | return {{a[I]...}}; |
177 | | } |
178 | | |
179 | | template <class T, std::size_t N, std::size_t... I> |
180 | | constexpr std::array<std::remove_cv_t<T>, N> to_array_rvalue_impl( |
181 | | T (&&a)[N], std::index_sequence<I...>) { |
182 | | return {{std::move(a[I])...}}; |
183 | | } |
184 | | } // namespace detail |
185 | | |
186 | | template <class T, std::size_t N> |
187 | | constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N]) { |
188 | | return detail::to_array_lvalue_impl(a, std::make_index_sequence<N>{}); |
189 | | } |
190 | | |
191 | | template <class T, std::size_t N> |
192 | | constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&&a)[N]) { |
193 | | return detail::to_array_rvalue_impl(std::move(a), |
194 | | std::make_index_sequence<N>{}); |
195 | | } |
196 | | |
197 | | } // namespace v8 |
198 | | #endif // INCLUDE_V8_MEMORY_SPAN_H_ |