1 // Copyright 2017 The Chromium Authors
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 BASE_CONTAINERS_SPAN_H_
6 #define BASE_CONTAINERS_SPAN_H_
7
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <array>
12 #include <concepts>
13 #include <iterator>
14 #include <limits>
15 #include <memory>
16 #include <type_traits>
17 #include <utility>
18
19 #include "base/check.h"
20 #include "base/compiler_specific.h"
21 #include "base/containers/checked_iterators.h"
22 #include "base/numerics/safe_conversions.h"
23 #include "base/template_util.h"
24
25 namespace base {
26
27 // [views.constants]
28 constexpr size_t dynamic_extent = std::numeric_limits<size_t>::max();
29
30 template <typename T,
31 size_t Extent = dynamic_extent,
32 typename InternalPtrType = T*>
33 class span;
34
35 namespace internal {
36
37 template <typename From, typename To>
38 concept LegalDataConversion =
39 std::convertible_to<std::remove_reference_t<From> (*)[],
40 std::remove_reference_t<To> (*)[]>;
41
42 template <typename T, typename It>
43 concept CompatibleIter = std::contiguous_iterator<It> &&
44 LegalDataConversion<std::iter_reference_t<It>, T>;
45
46 template <typename T, typename R>
47 concept CompatibleRange =
48 std::ranges::contiguous_range<R> && std::ranges::sized_range<R> &&
49 LegalDataConversion<std::ranges::range_reference_t<R>, T> &&
50 (std::ranges::borrowed_range<R> || std::is_const_v<T>);
51
52 // NOTE: Ideally we'd just use `CompatibleRange`, however this currently breaks
53 // code that was written prior to C++20 being standardized and assumes providing
54 // .data() and .size() is sufficient.
55 // TODO: https://crbug.com/1504998 - Remove in favor of CompatibleRange and fix
56 // callsites.
57 template <typename T, typename R>
requires(R & r)58 concept LegacyCompatibleRange = requires(R& r) {
59 { *std::ranges::data(r) } -> LegalDataConversion<T>;
60 std::ranges::size(r);
61 };
62
63 template <size_t I>
64 using size_constant = std::integral_constant<size_t, I>;
65
66 template <typename T>
67 struct ExtentImpl : size_constant<dynamic_extent> {};
68
69 template <typename T, size_t N>
70 struct ExtentImpl<T[N]> : size_constant<N> {};
71
72 template <typename T, size_t N>
73 struct ExtentImpl<std::array<T, N>> : size_constant<N> {};
74
75 template <typename T, size_t N>
76 struct ExtentImpl<base::span<T, N>> : size_constant<N> {};
77
78 template <typename T>
79 using Extent = ExtentImpl<std::remove_cvref_t<T>>;
80
81 template <typename T>
82 inline constexpr size_t ExtentV = Extent<T>::value;
83
84 // must_not_be_dynamic_extent prevents |dynamic_extent| from being returned in a
85 // constexpr context.
86 template <size_t kExtent>
87 constexpr size_t must_not_be_dynamic_extent() {
88 static_assert(
89 kExtent != dynamic_extent,
90 "EXTENT should only be used for containers with a static extent.");
91 return kExtent;
92 }
93
94 } // namespace internal
95
96 // A span is a value type that represents an array of elements of type T. Since
97 // it only consists of a pointer to memory with an associated size, it is very
98 // light-weight. It is cheap to construct, copy, move and use spans, so that
99 // users are encouraged to use it as a pass-by-value parameter. A span does not
100 // own the underlying memory, so care must be taken to ensure that a span does
101 // not outlive the backing store.
102 //
103 // span is somewhat analogous to std::string_view, but with arbitrary element
104 // types, allowing mutation if T is non-const.
105 //
106 // span is implicitly convertible from C++ arrays, as well as most [1]
107 // container-like types that provide a data() and size() method (such as
108 // std::vector<T>). A mutable span<T> can also be implicitly converted to an
109 // immutable span<const T>.
110 //
111 // Consider using a span for functions that take a data pointer and size
112 // parameter: it allows the function to still act on an array-like type, while
113 // allowing the caller code to be a bit more concise.
114 //
115 // For read-only data access pass a span<const T>: the caller can supply either
116 // a span<const T> or a span<T>, while the callee will have a read-only view.
117 // For read-write access a mutable span<T> is required.
118 //
119 // Without span:
120 // Read-Only:
121 // // std::string HexEncode(const uint8_t* data, size_t size);
122 // std::vector<uint8_t> data_buffer = GenerateData();
123 // std::string r = HexEncode(data_buffer.data(), data_buffer.size());
124 //
125 // Mutable:
126 // // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...);
127 // char str_buffer[100];
128 // SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14);
129 //
130 // With span:
131 // Read-Only:
132 // // std::string HexEncode(base::span<const uint8_t> data);
133 // std::vector<uint8_t> data_buffer = GenerateData();
134 // std::string r = HexEncode(data_buffer);
135 //
136 // Mutable:
137 // // ssize_t SafeSNPrintf(base::span<char>, const char* fmt, Args...);
138 // char str_buffer[100];
139 // SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14);
140 //
141 // Spans with "const" and pointers
142 // -------------------------------
143 //
144 // Const and pointers can get confusing. Here are vectors of pointers and their
145 // corresponding spans:
146 //
147 // const std::vector<int*> => base::span<int* const>
148 // std::vector<const int*> => base::span<const int*>
149 // const std::vector<const int*> => base::span<const int* const>
150 //
151 // Differences from the C++ standard
152 // ---------------------------------
153 //
154 // http://eel.is/c++draft/views.span contains the latest C++ draft of std::span.
155 // Chromium tries to follow the draft as close as possible. Differences between
156 // the draft and the implementation are documented in subsections below.
157 //
158 // Differences from [span.overview]:
159 // - Dynamic spans are implemented as a partial specialization of the regular
160 // class template. This leads to significantly simpler checks involving the
161 // extent, at the expense of some duplicated code. The same strategy is used
162 // by libc++.
163 //
164 // Differences from [span.objectrep]:
165 // - as_bytes() and as_writable_bytes() return spans of uint8_t instead of
166 // std::byte.
167 //
168 // Differences from [span.cons]:
169 // - The constructors from a contiguous range apart from a C array are folded
170 // into a single one, using a construct similarly to the one proposed
171 // (but not standardized) in https://wg21.link/P1419.
172 // The C array constructor is kept so that a span can be constructed from
173 // an init list like {{1, 2, 3}}.
174 // TODO: https://crbug.com/828324 - Consider adding C++26's constructor from
175 // a std::initializer_list instead.
176 // - The conversion constructors from a contiguous range into a dynamic span
177 // don't check for the range concept, but rather whether std::ranges::data
178 // and std::ranges::size are well formed. This is due to legacy reasons and
179 // should be fixed.
180 //
181 // Differences from [span.deduct]:
182 // - The deduction guides from a contiguous range are folded into a single one,
183 // and treat borrowed ranges correctly.
184 //
185 // Additions beyond the C++ standard draft
186 // - as_byte_span() function.
187 //
188 // Furthermore, all constructors and methods are marked noexcept due to the lack
189 // of exceptions in Chromium.
190 //
191 // Due to the lack of class template argument deduction guides in C++14
192 // appropriate make_span() utility functions are provided for historic reasons.
193
194 // [span], class template span
195 template <typename T, size_t N, typename InternalPtrType>
196 class GSL_POINTER span {
197 public:
198 using element_type = T;
199 using value_type = std::remove_cv_t<T>;
200 using size_type = size_t;
201 using difference_type = ptrdiff_t;
202 using pointer = T*;
203 using const_pointer = const T*;
204 using reference = T&;
205 using const_reference = const T&;
206 using iterator = CheckedContiguousIterator<T>;
207 using reverse_iterator = std::reverse_iterator<iterator>;
208 static constexpr size_t extent = N;
209
210 // [span.cons], span constructors, copy, assignment, and destructor
211 constexpr span() noexcept
212 requires(N == 0)
213 = default;
214
215 template <typename It>
216 requires(internal::CompatibleIter<T, It>)
217 explicit constexpr span(It first, StrictNumeric<size_t> count) noexcept
218 : // The use of to_address() here is to handle the case where the
219 // iterator `first` is pointing to the container's `end()`. In that
220 // case we can not use the address returned from the iterator, or
221 // dereference it through the iterator's `operator*`, but we can store
222 // it. We must assume in this case that `count` is 0, since the
223 // iterator does not point to valid data. Future hardening of iterators
224 // may disallow pulling the address from `end()`, as demonstrated by
225 // asserts() in libstdc++:
226 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93960.
227 //
228 // The span API dictates that the `data()` is accessible when size is
229 // 0, since the pointer may be valid, so we cannot prevent storing and
230 // giving out an invalid pointer here without breaking API
231 // compatibility and our unit tests. Thus protecting against this can
232 // likely only be successful from inside iterators themselves, where
233 // the context about the pointer is known.
234 //
235 // We can not protect here generally against an invalid iterator/count
236 // being passed in, since we have no context to determine if the
237 // iterator or count are valid.
238 data_(std::to_address(first)) {
239 CHECK(N == count);
240 }
241
242 template <typename It, typename End>
243 requires(internal::CompatibleIter<T, It> &&
244 std::sized_sentinel_for<End, It> &&
245 !std::convertible_to<End, size_t>)
246 explicit constexpr span(It begin, End end) noexcept
247 : span(begin, static_cast<size_t>(end - begin)) {}
248
249 // NOLINTNEXTLINE(google-explicit-constructor)
250 constexpr span(T (&arr)[N]) noexcept
251 : span(std::ranges::data(arr), std::ranges::size(arr)) {}
252
253 template <typename R, size_t X = internal::ExtentV<R>>
254 requires(internal::CompatibleRange<T, R> && (X == N || X == dynamic_extent))
255 // NOLINTNEXTLINE(google-explicit-constructor)
256 explicit(X == dynamic_extent) constexpr span(R&& range) noexcept
257 : span(std::ranges::data(range), std::ranges::size(range)) {}
258
259 // [span.sub], span subviews
260 template <size_t Count>
261 constexpr span<T, Count> first() const noexcept
262 requires(Count <= N)
263 {
264 return span<T, Count>(data(), Count);
265 }
266
267 template <size_t Count>
268 constexpr span<T, Count> last() const noexcept
269 requires(Count <= N)
270 {
271 return span<T, Count>(data() + (size() - Count), Count);
272 }
273
274 template <size_t Offset, size_t Count = dynamic_extent>
275 constexpr auto subspan() const noexcept
276 requires(Offset <= N && (Count == dynamic_extent || Count <= N - Offset))
277 {
278 constexpr size_t kExtent = Count != dynamic_extent ? Count : N - Offset;
279 return span<T, kExtent>(data() + Offset, kExtent);
280 }
281
282 constexpr span<T, dynamic_extent> first(size_t count) const noexcept {
283 CHECK_LE(count, size());
284 return {data(), count};
285 }
286
287 constexpr span<T, dynamic_extent> last(size_t count) const noexcept {
288 CHECK_LE(count, size());
289 return {data() + (size() - count), count};
290 }
291
292 constexpr span<T, dynamic_extent> subspan(
293 size_t offset,
294 size_t count = dynamic_extent) const noexcept {
295 CHECK_LE(offset, size());
296 CHECK(count == dynamic_extent || count <= size() - offset);
297 return {data() + offset, count != dynamic_extent ? count : size() - offset};
298 }
299
300 // [span.obs], span observers
301 constexpr size_t size() const noexcept { return N; }
302 constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); }
303 [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
304
305 // [span.elem], span element access
306 constexpr T& operator[](size_t idx) const noexcept {
307 CHECK_LT(idx, size());
308 return data()[idx];
309 }
310
311 constexpr T& front() const noexcept
312 requires(N > 0)
313 {
314 return data()[0];
315 }
316
317 constexpr T& back() const noexcept
318 requires(N > 0)
319 {
320 return data()[size() - 1];
321 }
322
323 constexpr T* data() const noexcept { return data_; }
324
325 // [span.iter], span iterator support
326 constexpr iterator begin() const noexcept {
327 return iterator(data(), data() + size());
328 }
329
330 constexpr iterator end() const noexcept {
331 return iterator(data(), data() + size(), data() + size());
332 }
333
334 constexpr reverse_iterator rbegin() const noexcept {
335 return reverse_iterator(end());
336 }
337
338 constexpr reverse_iterator rend() const noexcept {
339 return reverse_iterator(begin());
340 }
341
342 private:
343 // This field is not a raw_ptr<> because it was filtered by the rewriter
344 // for: #constexpr-ctor-field-initializer, #global-scope, #union
345 InternalPtrType data_ = nullptr;
346 };
347
348 // [span], class template span
349 template <typename T, typename InternalPtrType>
350 class GSL_POINTER span<T, dynamic_extent, InternalPtrType> {
351 public:
352 using element_type = T;
353 using value_type = std::remove_cv_t<T>;
354 using size_type = size_t;
355 using difference_type = ptrdiff_t;
356 using pointer = T*;
357 using const_pointer = const T*;
358 using reference = T&;
359 using const_reference = const T&;
360 using iterator = CheckedContiguousIterator<T>;
361 using reverse_iterator = std::reverse_iterator<iterator>;
362 static constexpr size_t extent = dynamic_extent;
363
364 constexpr span() noexcept = default;
365
366 template <typename It>
367 requires(internal::CompatibleIter<T, It>)
368 constexpr span(It first, StrictNumeric<size_t> count) noexcept
369 // The use of to_address() here is to handle the case where the iterator
370 // `first` is pointing to the container's `end()`. In that case we can
371 // not use the address returned from the iterator, or dereference it
372 // through the iterator's `operator*`, but we can store it. We must
373 // assume in this case that `count` is 0, since the iterator does not
374 // point to valid data. Future hardening of iterators may disallow
375 // pulling the address from `end()`, as demonstrated by asserts() in
376 // libstdc++: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93960.
377 //
378 // The span API dictates that the `data()` is accessible when size is 0,
379 // since the pointer may be valid, so we cannot prevent storing and
380 // giving out an invalid pointer here without breaking API compatibility
381 // and our unit tests. Thus protecting against this can likely only be
382 // successful from inside iterators themselves, where the context about
383 // the pointer is known.
384 //
385 // We can not protect here generally against an invalid iterator/count
386 // being passed in, since we have no context to determine if the
387 // iterator or count are valid.
388 : data_(std::to_address(first)), size_(count) {}
389
390 template <typename It, typename End>
391 requires(internal::CompatibleIter<T, It> &&
392 std::sized_sentinel_for<End, It> &&
393 !std::convertible_to<End, size_t>)
394 constexpr span(It begin, End end) noexcept
395 // Subtracting two iterators gives a ptrdiff_t, but the result should be
396 // non-negative: see CHECK below.
397 : span(begin, static_cast<size_t>(end - begin)) {
398 CHECK(begin <= end);
399 }
400
401 template <size_t N>
402 // NOLINTNEXTLINE(google-explicit-constructor)
403 constexpr span(T (&arr)[N]) noexcept
404 : span(std::ranges::data(arr), std::ranges::size(arr)) {}
405
406 template <typename R>
407 requires(internal::LegacyCompatibleRange<T, R>)
408 // NOLINTNEXTLINE(google-explicit-constructor)
409 constexpr span(R&& range) noexcept
410 : span(std::ranges::data(range), std::ranges::size(range)) {}
411
412 // [span.sub], span subviews
413 template <size_t Count>
414 constexpr span<T, Count> first() const noexcept {
415 CHECK_LE(Count, size());
416 return span<T, Count>(data(), Count);
417 }
418
419 template <size_t Count>
420 constexpr span<T, Count> last() const noexcept {
421 CHECK_LE(Count, size());
422 return span<T, Count>(data() + (size() - Count), Count);
423 }
424
425 template <size_t Offset, size_t Count = dynamic_extent>
426 constexpr span<T, Count> subspan() const noexcept {
427 CHECK_LE(Offset, size());
428 CHECK(Count == dynamic_extent || Count <= size() - Offset);
429 return span<T, Count>(data() + Offset,
430 Count != dynamic_extent ? Count : size() - Offset);
431 }
432
433 constexpr span<T, dynamic_extent> first(size_t count) const noexcept {
434 CHECK_LE(count, size());
435 return {data(), count};
436 }
437
438 constexpr span<T, dynamic_extent> last(size_t count) const noexcept {
439 CHECK_LE(count, size());
440 return {data() + (size() - count), count};
441 }
442
443 constexpr span<T, dynamic_extent> subspan(
444 size_t offset,
445 size_t count = dynamic_extent) const noexcept {
446 CHECK_LE(offset, size());
447 CHECK(count == dynamic_extent || count <= size() - offset);
448 return {data() + offset, count != dynamic_extent ? count : size() - offset};
449 }
450
451 // [span.obs], span observers
452 constexpr size_t size() const noexcept { return size_; }
453 constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); }
454 [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
455
456 // [span.elem], span element access
457 constexpr T& operator[](size_t idx) const noexcept {
458 CHECK_LT(idx, size());
459 return data()[idx];
460 }
461
462 constexpr T& front() const noexcept {
463 CHECK(!empty());
464 return data()[0];
465 }
466
467 constexpr T& back() const noexcept {
468 CHECK(!empty());
469 return data()[size() - 1];
470 }
471
472 constexpr T* data() const noexcept { return data_; }
473
474 // [span.iter], span iterator support
475 constexpr iterator begin() const noexcept {
476 return iterator(data(), data() + size());
477 }
478
479 constexpr iterator end() const noexcept {
480 return iterator(data(), data() + size(), data() + size());
481 }
482
483 constexpr reverse_iterator rbegin() const noexcept {
484 return reverse_iterator(end());
485 }
486
487 constexpr reverse_iterator rend() const noexcept {
488 return reverse_iterator(begin());
489 }
490
491 private:
492 // This field is not a raw_ptr<> because it was filtered by the rewriter
493 // for: #constexpr-ctor-field-initializer, #global-scope, #union
494 InternalPtrType data_ = nullptr;
495 size_t size_ = 0;
496 };
497
498 // [span.deduct], deduction guides.
499 template <typename It, typename EndOrSize>
500 requires(std::contiguous_iterator<It>)
501 span(It, EndOrSize) -> span<std::remove_reference_t<std::iter_reference_t<It>>>;
502
503 template <
504 typename R,
505 typename T = std::remove_reference_t<std::ranges::range_reference_t<R>>>
506 requires(std::ranges::contiguous_range<R>)
507 span(R&&)
508 -> span<std::conditional_t<std::ranges::borrowed_range<R>, T, const T>,
509 internal::ExtentV<R>>;
510
511 // [span.objectrep], views of object representation
512 template <typename T, size_t X>
513 auto as_bytes(span<T, X> s) noexcept {
514 constexpr size_t N = X == dynamic_extent ? dynamic_extent : sizeof(T) * X;
515 return span<const uint8_t, N>(reinterpret_cast<const uint8_t*>(s.data()),
516 s.size_bytes());
517 }
518
519 template <typename T, size_t X>
520 requires(!std::is_const_v<T>)
521 auto as_writable_bytes(span<T, X> s) noexcept {
522 constexpr size_t N = X == dynamic_extent ? dynamic_extent : sizeof(T) * X;
523 return span<uint8_t, N>(reinterpret_cast<uint8_t*>(s.data()), s.size_bytes());
524 }
525
526 // Type-deducing helpers for constructing a span.
527 template <int&... ExplicitArgumentBarrier, typename It>
528 constexpr auto make_span(It it, StrictNumeric<size_t> size) noexcept {
529 using T = std::remove_reference_t<iter_reference_t<It>>;
530 return span<T>(it, size);
531 }
532
533 template <int&... ExplicitArgumentBarrier,
534 typename It,
535 typename End,
536 typename = std::enable_if_t<!std::is_convertible_v<End, size_t>>>
537 constexpr auto make_span(It it, End end) noexcept {
538 using T = std::remove_reference_t<iter_reference_t<It>>;
539 return span<T>(it, end);
540 }
541
542 // make_span utility function that deduces both the span's value_type and extent
543 // from the passed in argument.
544 //
545 // Usage: auto span = base::make_span(...);
546 template <int&... ExplicitArgumentBarrier, typename Container>
547 constexpr auto make_span(Container&& container) noexcept {
548 using T =
549 std::remove_pointer_t<decltype(std::data(std::declval<Container>()))>;
550 using Extent = internal::Extent<Container>;
551 return span<T, Extent::value>(std::forward<Container>(container));
552 }
553
554 // make_span utility functions that allow callers to explicit specify the span's
555 // extent, the value_type is deduced automatically. This is useful when passing
556 // a dynamically sized container to a method expecting static spans, when the
557 // container is known to have the correct size.
558 //
559 // Note: This will CHECK that N indeed matches size(container).
560 //
561 // Usage: auto static_span = base::make_span<N>(...);
562 template <size_t N, int&... ExplicitArgumentBarrier, typename It>
563 constexpr auto make_span(It it, StrictNumeric<size_t> size) noexcept {
564 using T = std::remove_reference_t<iter_reference_t<It>>;
565 return span<T, N>(it, size);
566 }
567
568 template <size_t N,
569 int&... ExplicitArgumentBarrier,
570 typename It,
571 typename End,
572 typename = std::enable_if_t<!std::is_convertible_v<End, size_t>>>
573 constexpr auto make_span(It it, End end) noexcept {
574 using T = std::remove_reference_t<iter_reference_t<It>>;
575 return span<T, N>(it, end);
576 }
577
578 template <size_t N, int&... ExplicitArgumentBarrier, typename Container>
579 constexpr auto make_span(Container&& container) noexcept {
580 using T =
581 std::remove_pointer_t<decltype(std::data(std::declval<Container>()))>;
582 return span<T, N>(std::data(container), std::size(container));
583 }
584
585 // Convenience function for converting an object which is itself convertible
586 // to span into a span of bytes (i.e. span of const uint8_t). Typically used
587 // to convert std::string or string-objects holding chars, or std::vector
588 // or vector-like objects holding other scalar types, prior to passing them
589 // into an API that requires byte spans.
590 template <typename T>
591 span<const uint8_t> as_byte_span(const T& arg) {
592 return as_bytes(make_span(arg));
593 }
594
595 } // namespace base
596
597 template <typename T, size_t N, typename Ptr>
598 inline constexpr bool
599 std::ranges::enable_borrowed_range<base::span<T, N, Ptr>> = true;
600
601 template <typename T, size_t N, typename Ptr>
602 inline constexpr bool std::ranges::enable_view<base::span<T, N, Ptr>> = true;
603
604 // EXTENT returns the size of any type that can be converted to a |base::span|
605 // with definite extent, i.e. everything that is a contiguous storage of some
606 // sort with static size. Specifically, this works for std::array in a constexpr
607 // context. Note:
608 // * |std::size| should be preferred for plain arrays.
609 // * In run-time contexts, functions such as |std::array::size| should be
610 // preferred.
611 #define EXTENT(x) \
612 ::base::internal::must_not_be_dynamic_extent<decltype( \
613 ::base::make_span(x))::extent>()
614
615 #endif // BASE_CONTAINERS_SPAN_H_
616