xref: /aosp_15_r20/external/pdfium/third_party/base/containers/span.h (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1 // Copyright 2017 The Chromium 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 THIRD_PARTY_BASE_CONTAINERS_SPAN_H_
6 #define THIRD_PARTY_BASE_CONTAINERS_SPAN_H_
7 
8 #include <stddef.h>
9 
10 #include <algorithm>
11 #include <array>
12 #include <iterator>
13 #include <type_traits>
14 #include <utility>
15 
16 #include "core/fxcrt/unowned_ptr.h"
17 #include "third_party/base/check.h"
18 #include "third_party/base/compiler_specific.h"
19 
20 namespace pdfium {
21 
22 constexpr size_t dynamic_extent = static_cast<size_t>(-1);
23 
24 template <typename T>
25 class span;
26 
27 namespace internal {
28 
29 template <typename T>
30 struct IsSpanImpl : std::false_type {};
31 
32 template <typename T>
33 struct IsSpanImpl<span<T>> : std::true_type {};
34 
35 template <typename T>
36 using IsSpan = IsSpanImpl<typename std::decay<T>::type>;
37 
38 template <typename T>
39 struct IsStdArrayImpl : std::false_type {};
40 
41 template <typename T, size_t N>
42 struct IsStdArrayImpl<std::array<T, N>> : std::true_type {};
43 
44 template <typename T>
45 using IsStdArray = IsStdArrayImpl<typename std::decay<T>::type>;
46 
47 template <typename From, typename To>
48 using IsLegalSpanConversion = std::is_convertible<From*, To*>;
49 
50 template <typename Container, typename T>
51 using ContainerHasConvertibleData =
52     IsLegalSpanConversion<typename std::remove_pointer<decltype(
53                               std::declval<Container>().data())>::type,
54                           T>;
55 template <typename Container>
56 using ContainerHasIntegralSize =
57     std::is_integral<decltype(std::declval<Container>().size())>;
58 
59 template <typename From, typename To>
60 using EnableIfLegalSpanConversion =
61     typename std::enable_if<IsLegalSpanConversion<From, To>::value>::type;
62 
63 // SFINAE check if Container can be converted to a span<T>. Note that the
64 // implementation details of this check differ slightly from the requirements in
65 // the working group proposal: in particular, the proposal also requires that
66 // the container conversion constructor participate in overload resolution only
67 // if two additional conditions are true:
68 //
69 //   1. Container implements operator[].
70 //   2. Container::value_type matches remove_const_t<element_type>.
71 //
72 // The requirements are relaxed slightly here: in particular, not requiring (2)
73 // means that an immutable span can be easily constructed from a mutable
74 // container.
75 template <typename Container, typename T>
76 using EnableIfSpanCompatibleContainer =
77     typename std::enable_if<!internal::IsSpan<Container>::value &&
78                             !internal::IsStdArray<Container>::value &&
79                             ContainerHasConvertibleData<Container, T>::value &&
80                             ContainerHasIntegralSize<Container>::value>::type;
81 
82 template <typename Container, typename T>
83 using EnableIfConstSpanCompatibleContainer =
84     typename std::enable_if<std::is_const<T>::value &&
85                             !internal::IsSpan<Container>::value &&
86                             !internal::IsStdArray<Container>::value &&
87                             ContainerHasConvertibleData<Container, T>::value &&
88                             ContainerHasIntegralSize<Container>::value>::type;
89 
90 }  // namespace internal
91 
92 // A span is a value type that represents an array of elements of type T. Since
93 // it only consists of a pointer to memory with an associated size, it is very
94 // light-weight. It is cheap to construct, copy, move and use spans, so that
95 // users are encouraged to use it as a pass-by-value parameter. A span does not
96 // own the underlying memory, so care must be taken to ensure that a span does
97 // not outlive the backing store.
98 //
99 // span is somewhat analogous to StringPiece, but with arbitrary element types,
100 // allowing mutation if T is non-const.
101 //
102 // span is implicitly convertible from C++ arrays, as well as most [1]
103 // container-like types that provide a data() and size() method (such as
104 // std::vector<T>). A mutable span<T> can also be implicitly converted to an
105 // immutable span<const T>.
106 //
107 // Consider using a span for functions that take a data pointer and size
108 // parameter: it allows the function to still act on an array-like type, while
109 // allowing the caller code to be a bit more concise.
110 //
111 // For read-only data access pass a span<const T>: the caller can supply either
112 // a span<const T> or a span<T>, while the callee will have a read-only view.
113 // For read-write access a mutable span<T> is required.
114 //
115 // Without span:
116 //   Read-Only:
117 //     // std::string HexEncode(const uint8_t* data, size_t size);
118 //     std::vector<uint8_t> data_buffer = GenerateData();
119 //     std::string r = HexEncode(data_buffer.data(), data_buffer.size());
120 //
121 //  Mutable:
122 //     // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...);
123 //     char str_buffer[100];
124 //     SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14);
125 //
126 // With span:
127 //   Read-Only:
128 //     // std::string HexEncode(base::span<const uint8_t> data);
129 //     std::vector<uint8_t> data_buffer = GenerateData();
130 //     std::string r = HexEncode(data_buffer);
131 //
132 //  Mutable:
133 //     // ssize_t SafeSNPrintf(base::span<char>, const char* fmt, Args...);
134 //     char str_buffer[100];
135 //     SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14);
136 //
137 // Spans with "const" and pointers
138 // -------------------------------
139 //
140 // Const and pointers can get confusing. Here are vectors of pointers and their
141 // corresponding spans (you can always make the span "more const" too):
142 //
143 //   const std::vector<int*>        =>  base::span<int* const>
144 //   std::vector<const int*>        =>  base::span<const int*>
145 //   const std::vector<const int*>  =>  base::span<const int* const>
146 //
147 // Differences from the working group proposal
148 // -------------------------------------------
149 //
150 // https://wg21.link/P0122 is the latest working group proposal, Chromium
151 // currently implements R6. The biggest difference is span does not support a
152 // static extent template parameter. Other differences are documented in
153 // subsections below.
154 //
155 // Differences in constants and types:
156 // - no element_type type alias
157 // - no index_type type alias
158 // - no different_type type alias
159 // - no extent constant
160 //
161 // Differences from [span.cons]:
162 // - no constructor from a pointer range
163 //
164 // Differences from [span.sub]:
165 // - no templated first()
166 // - no templated last()
167 // - no templated subspan()
168 // - using size_t instead of ptrdiff_t for indexing
169 //
170 // Differences from [span.obs]:
171 // - using size_t instead of ptrdiff_t to represent size()
172 //
173 // Differences from [span.elem]:
174 // - no operator ()()
175 // - using size_t instead of ptrdiff_t for indexing
176 
177 // [span], class template span
178 template <typename T>
179 class TRIVIAL_ABI GSL_POINTER span {
180  public:
181   using value_type = typename std::remove_cv<T>::type;
182   using pointer = T*;
183   using reference = T&;
184   using iterator = T*;
185   using const_iterator = const T*;
186   using reverse_iterator = std::reverse_iterator<iterator>;
187   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
188 
189   // [span.cons], span constructors, copy, assignment, and destructor
190   constexpr span() noexcept : data_(nullptr), size_(0) {}
191   constexpr span(T* data, size_t size) noexcept : data_(data), size_(size) {
192     DCHECK(data_ || size_ == 0);
193   }
194 
195   // TODO(dcheng): Implement construction from a |begin| and |end| pointer.
196   template <size_t N>
197   constexpr span(T (&array)[N]) noexcept : span(array, N) {}
198 
199   template <size_t N>
200   constexpr span(std::array<T, N>& array) noexcept : span(array.data(), N) {}
201 
202   // Conversion from a container that provides |T* data()| and |integral_type
203   // size()|. Note that |data()| may not return nullptr for some empty
204   // containers, which can lead to container overflow errors when probing
205   // unowned ptrs.
206 #if defined(ADDRESS_SANITIZER) && defined(UNOWNED_PTR_IS_BASE_RAW_PTR)
207   template <typename Container,
208             typename = internal::EnableIfSpanCompatibleContainer<Container, T>>
209   constexpr span(Container& container)
210       : span(container.size() ? container.data() : nullptr, container.size()) {}
211 #else
212   template <typename Container,
213             typename = internal::EnableIfSpanCompatibleContainer<Container, T>>
214   constexpr span(Container& container)
215       : span(container.data(), container.size()) {}
216 #endif
217 
218   template <
219       typename Container,
220       typename = internal::EnableIfConstSpanCompatibleContainer<Container, T>>
221   span(const Container& container) : span(container.data(), container.size()) {}
222 
223   constexpr span(const span& other) noexcept = default;
224 
225   // Conversions from spans of compatible types: this allows a span<T> to be
226   // seamlessly used as a span<const T>, but not the other way around.
227   template <typename U, typename = internal::EnableIfLegalSpanConversion<U, T>>
228   constexpr span(const span<U>& other) : span(other.data(), other.size()) {}
229   span& operator=(const span& other) noexcept {
230     if (this != &other) {
231       ReleaseEmptySpan();
232       data_ = other.data_;
233       size_ = other.size_;
234     }
235     return *this;
236   }
237   ~span() noexcept { ReleaseEmptySpan(); }
238 
239   // [span.sub], span subviews
240   const span first(size_t count) const {
241     CHECK(count <= size_);
242     return span(static_cast<T*>(data_), count);
243   }
244 
245   const span last(size_t count) const {
246     CHECK(count <= size_);
247     return span(static_cast<T*>(data_) + (size_ - count), count);
248   }
249 
250   const span subspan(size_t pos, size_t count = dynamic_extent) const {
251     CHECK(pos <= size_);
252     CHECK(count == dynamic_extent || count <= size_ - pos);
253     return span(static_cast<T*>(data_) + pos,
254                 count == dynamic_extent ? size_ - pos : count);
255   }
256 
257   // [span.obs], span observers
258   constexpr size_t size() const noexcept { return size_; }
259   constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); }
260   constexpr bool empty() const noexcept { return size_ == 0; }
261 
262   // [span.elem], span element access
263   T& operator[](size_t index) const noexcept {
264     CHECK(index < size_);
265     return static_cast<T*>(data_)[index];
266   }
267 
268   constexpr T& front() const noexcept {
269     CHECK(!empty());
270     return *data();
271   }
272 
273   constexpr T& back() const noexcept {
274     CHECK(!empty());
275     return *(data() + size() - 1);
276   }
277 
278   constexpr T* data() const noexcept { return static_cast<T*>(data_); }
279 
280   // [span.iter], span iterator support
281   constexpr iterator begin() const noexcept { return static_cast<T*>(data_); }
282   constexpr iterator end() const noexcept { return begin() + size_; }
283 
284   constexpr const_iterator cbegin() const noexcept { return begin(); }
285   constexpr const_iterator cend() const noexcept { return end(); }
286 
287   constexpr reverse_iterator rbegin() const noexcept {
288     return reverse_iterator(end());
289   }
290   constexpr reverse_iterator rend() const noexcept {
291     return reverse_iterator(begin());
292   }
293 
294   constexpr const_reverse_iterator crbegin() const noexcept {
295     return const_reverse_iterator(cend());
296   }
297   constexpr const_reverse_iterator crend() const noexcept {
298     return const_reverse_iterator(cbegin());
299   }
300 
301  private:
302   void ReleaseEmptySpan() noexcept {
303 #if defined(ADDRESS_SANITIZER) && !defined(UNOWNED_PTR_IS_BASE_RAW_PTR)
304     // Empty spans might point to byte N+1 of a N-byte object, legal for
305     // C pointers but not UnownedPtrs.
306     if (!size_)
307       data_.ReleaseBadPointer();
308 #endif
309   }
310 
311 #if defined(UNOWNED_PTR_IS_BASE_RAW_PTR)
312   raw_ptr<T, AllowPtrArithmetic> data_ = nullptr;
313 #else
314   UnownedPtr<T> data_;
315 #endif
316   size_t size_;
317 };
318 
319 // [span.comparison], span comparison operators
320 // Relational operators. Equality is a element-wise comparison.
321 template <typename T>
322 constexpr bool operator==(span<T> lhs, span<T> rhs) noexcept {
323   return lhs.size() == rhs.size() &&
324          std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin());
325 }
326 
327 template <typename T>
328 constexpr bool operator!=(span<T> lhs, span<T> rhs) noexcept {
329   return !(lhs == rhs);
330 }
331 
332 template <typename T>
333 constexpr bool operator<(span<T> lhs, span<T> rhs) noexcept {
334   return std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(),
335                                       rhs.cend());
336 }
337 
338 template <typename T>
339 constexpr bool operator<=(span<T> lhs, span<T> rhs) noexcept {
340   return !(rhs < lhs);
341 }
342 
343 template <typename T>
344 constexpr bool operator>(span<T> lhs, span<T> rhs) noexcept {
345   return rhs < lhs;
346 }
347 
348 template <typename T>
349 constexpr bool operator>=(span<T> lhs, span<T> rhs) noexcept {
350   return !(lhs < rhs);
351 }
352 
353 // [span.objectrep], views of object representation
354 template <typename T>
355 span<const uint8_t> as_bytes(span<T> s) noexcept {
356   return {reinterpret_cast<const uint8_t*>(s.data()), s.size_bytes()};
357 }
358 
359 template <typename T,
360           typename U = typename std::enable_if<!std::is_const<T>::value>::type>
361 span<uint8_t> as_writable_bytes(span<T> s) noexcept {
362   return {reinterpret_cast<uint8_t*>(s.data()), s.size_bytes()};
363 }
364 
365 // Type-deducing helpers for constructing a span.
366 template <typename T>
367 constexpr span<T> make_span(T* data, size_t size) noexcept {
368   return span<T>(data, size);
369 }
370 
371 template <typename T, size_t N>
372 constexpr span<T> make_span(T (&array)[N]) noexcept {
373   return span<T>(array);
374 }
375 
376 template <typename T, size_t N>
377 constexpr span<T> make_span(std::array<T, N>& array) noexcept {
378   return span<T>(array);
379 }
380 
381 template <typename Container,
382           typename T = typename Container::value_type,
383           typename = internal::EnableIfSpanCompatibleContainer<Container, T>>
384 constexpr span<T> make_span(Container& container) {
385   return span<T>(container);
386 }
387 
388 template <
389     typename Container,
390     typename T = typename std::add_const<typename Container::value_type>::type,
391     typename = internal::EnableIfConstSpanCompatibleContainer<Container, T>>
392 constexpr span<T> make_span(const Container& container) {
393   return span<T>(container);
394 }
395 
396 }  // namespace pdfium
397 
398 #endif  // THIRD_PARTY_BASE_CONTAINERS_SPAN_H_
399