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 <algorithm>
12 #include <array>
13 #include <concepts>
14 #include <iterator>
15 #include <limits>
16 #include <memory>
17 #include <span>
18 #include <type_traits>
19 #include <utility>
20
21 #include "base/check.h"
22 #include "base/compiler_specific.h"
23 #include "base/containers/checked_iterators.h"
24 #include "base/containers/dynamic_extent.h"
25 #include "base/numerics/safe_conversions.h"
26 #include "base/template_util.h"
27 #include "base/types/to_address.h"
28 #include "third_party/abseil-cpp/absl/base/attributes.h"
29
30 namespace base {
31
32 template <typename T,
33 size_t Extent = dynamic_extent,
34 typename InternalPtrType = T*>
35 class span;
36
37 namespace internal {
38
39 template <typename From, typename To>
40 concept LegalDataConversion =
41 std::convertible_to<std::remove_reference_t<From> (*)[],
42 std::remove_reference_t<To> (*)[]>;
43
44 template <typename T, typename It>
45 concept CompatibleIter = std::contiguous_iterator<It> &&
46 LegalDataConversion<std::iter_reference_t<It>, T>;
47
48 template <typename T, typename R>
49 concept CompatibleRange =
50 std::ranges::contiguous_range<R> && std::ranges::sized_range<R> &&
51 LegalDataConversion<std::ranges::range_reference_t<R>, T> &&
52 (std::ranges::borrowed_range<R> || std::is_const_v<T>);
53
54 template <typename T>
55 concept LegacyRangeDataIsPointer = std::is_pointer_v<T>;
56
57 template <typename R>
requires(R & r)58 concept LegacyRange = requires(R& r) {
59 { std::ranges::data(r) } -> LegacyRangeDataIsPointer;
60 { std::ranges::size(r) } -> std::convertible_to<size_t>;
61 };
62
63 // NOTE: Ideally we'd just use `CompatibleRange`, however this currently breaks
64 // code that was written prior to C++20 being standardized and assumes providing
65 // .data() and .size() is sufficient.
66 // TODO: https://crbug.com/1504998 - Remove in favor of CompatibleRange and fix
67 // callsites.
68 template <typename T, typename R>
requires(R & r)69 concept LegacyCompatibleRange = LegacyRange<R> && requires(R& r) {
70 { *std::ranges::data(r) } -> LegalDataConversion<T>;
71 };
72
73 template <size_t I>
74 using size_constant = std::integral_constant<size_t, I>;
75
76 template <typename T>
77 struct ExtentImpl : size_constant<dynamic_extent> {};
78
79 template <typename T, size_t N>
80 struct ExtentImpl<T[N]> : size_constant<N> {};
81
82 template <typename T, size_t N>
83 struct ExtentImpl<std::array<T, N>> : size_constant<N> {};
84
85 template <typename T, size_t N>
86 struct ExtentImpl<base::span<T, N>> : size_constant<N> {};
87
88 template <typename T>
89 using Extent = ExtentImpl<std::remove_cvref_t<T>>;
90
91 template <typename T>
92 inline constexpr size_t ExtentV = Extent<T>::value;
93
94 // must_not_be_dynamic_extent prevents |dynamic_extent| from being returned in a
95 // constexpr context.
96 template <size_t kExtent>
97 constexpr size_t must_not_be_dynamic_extent() {
98 static_assert(
99 kExtent != dynamic_extent,
100 "EXTENT should only be used for containers with a static extent.");
101 return kExtent;
102 }
103
104 template <class T, class U, size_t N, size_t M>
105 requires((N == M || N == dynamic_extent || M == dynamic_extent) &&
106 std::equality_comparable_with<T, U>)
107 constexpr bool span_cmp(span<T, N> l, span<U, M> r);
108
109 } // namespace internal
110
111 // A span is a value type that represents an array of elements of type T. Since
112 // it only consists of a pointer to memory with an associated size, it is very
113 // light-weight. It is cheap to construct, copy, move and use spans, so that
114 // users are encouraged to use it as a pass-by-value parameter. A span does not
115 // own the underlying memory, so care must be taken to ensure that a span does
116 // not outlive the backing store.
117 //
118 // span is somewhat analogous to std::string_view, but with arbitrary element
119 // types, allowing mutation if T is non-const.
120 //
121 // span is implicitly convertible from C++ arrays, as well as most [1]
122 // container-like types that provide a data() and size() method (such as
123 // std::vector<T>). A mutable span<T> can also be implicitly converted to an
124 // immutable span<const T>.
125 //
126 // Consider using a span for functions that take a data pointer and size
127 // parameter: it allows the function to still act on an array-like type, while
128 // allowing the caller code to be a bit more concise.
129 //
130 // For read-only data access pass a span<const T>: the caller can supply either
131 // a span<const T> or a span<T>, while the callee will have a read-only view.
132 // For read-write access a mutable span<T> is required.
133 //
134 // Without span:
135 // Read-Only:
136 // // std::string HexEncode(const uint8_t* data, size_t size);
137 // std::vector<uint8_t> data_buffer = GenerateData();
138 // std::string r = HexEncode(data_buffer.data(), data_buffer.size());
139 //
140 // Mutable:
141 // // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...);
142 // char str_buffer[100];
143 // SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14);
144 //
145 // With span:
146 // Read-Only:
147 // // std::string HexEncode(base::span<const uint8_t> data);
148 // std::vector<uint8_t> data_buffer = GenerateData();
149 // std::string r = HexEncode(data_buffer);
150 //
151 // Mutable:
152 // // ssize_t SafeSNPrintf(base::span<char>, const char* fmt, Args...);
153 // char str_buffer[100];
154 // SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14);
155 //
156 // Dynamic vs Fixed size spans
157 // ---------------------------
158 //
159 // Normally spans have a dynamic size, which is represented as a type as
160 // `span<T>`. However it is possible to encode the size of the span into the
161 // type as a second parameter such as `span<T, N>`. When working with fixed-size
162 // spans, the compiler will check the size of operations and prevent compilation
163 // when an invalid size is used for an operation such as assignment or
164 // `copy_from()`. However operations that produce a new span will make a
165 // dynamic-sized span by default. See below for how to prevent that.
166 //
167 // Fixed-size spans implicitly convert to a dynamic-size span, throwing away the
168 // compile-time size information from the type signature. So most code should
169 // work with dynamic-sized `span<T>` types and not worry about the existence of
170 // fixed-size spans.
171 //
172 // It is possible to convert from a dynamic-size to a fixed-size span (or to
173 // move from a fixed-size span to another fixed-size span) but it requires
174 // writing an the size explicitly in the code. Methods like `first` can be
175 // passed a size as a template argument, such as `first<N>()` to generate a
176 // fixed-size span. And the `make_span` function can be given a compile-time
177 // size in a similar way with `make_span<N>()`.
178 //
179 // Spans with "const" and pointers
180 // -------------------------------
181 //
182 // Const and pointers can get confusing. Here are vectors of pointers and their
183 // corresponding spans:
184 //
185 // const std::vector<int*> => base::span<int* const>
186 // std::vector<const int*> => base::span<const int*>
187 // const std::vector<const int*> => base::span<const int* const>
188 //
189 // Differences from the C++ standard
190 // ---------------------------------
191 //
192 // http://eel.is/c++draft/views.span contains the latest C++ draft of std::span.
193 // Chromium tries to follow the draft as close as possible. Differences between
194 // the draft and the implementation are documented in subsections below.
195 //
196 // Differences from [span.overview]:
197 // - Dynamic spans are implemented as a partial specialization of the regular
198 // class template. This leads to significantly simpler checks involving the
199 // extent, at the expense of some duplicated code. The same strategy is used
200 // by libc++.
201 //
202 // Differences from [span.objectrep]:
203 // - as_bytes() and as_writable_bytes() return spans of uint8_t instead of
204 // std::byte.
205 //
206 // Differences from [span.cons]:
207 // - The constructors from a contiguous range apart from a C array are folded
208 // into a single one, using a construct similarly to the one proposed
209 // (but not standardized) in https://wg21.link/P1419.
210 // The C array constructor is kept so that a span can be constructed from
211 // an init list like {{1, 2, 3}}.
212 // TODO: https://crbug.com/828324 - Consider adding C++26's constructor from
213 // a std::initializer_list instead.
214 // - The conversion constructors from a contiguous range into a dynamic span
215 // don't check for the range concept, but rather whether std::ranges::data
216 // and std::ranges::size are well formed. This is due to legacy reasons and
217 // should be fixed.
218 //
219 // Differences from [span.deduct]:
220 // - The deduction guides from a contiguous range are folded into a single one,
221 // and treat borrowed ranges correctly.
222 // - Add deduction guide from rvalue array.
223 //
224 // Other differences:
225 // - Using StrictNumeric<size_t> instead of size_t where possible.
226 //
227 // Additions beyond the C++ standard draft
228 // - as_chars() function.
229 // - as_writable_chars() function.
230 // - as_byte_span() function.
231 // - as_writable_byte_span() function.
232 // - copy_from() method.
233 // - span_from_ref() function.
234 // - byte_span_from_ref() function.
235 // - span_from_cstring() function.
236 // - byte_span_from_cstring() function.
237 // - split_at() method.
238 // - operator==() comparator function.
239 //
240 // Furthermore, all constructors and methods are marked noexcept due to the lack
241 // of exceptions in Chromium.
242 //
243 // Due to the lack of class template argument deduction guides in C++14
244 // appropriate make_span() utility functions are provided for historic reasons.
245
246 // [span], class template span
247 template <typename T, size_t N, typename InternalPtrType>
248 class GSL_POINTER span {
249 public:
250 using element_type = T;
251 using value_type = std::remove_cv_t<T>;
252 using size_type = size_t;
253 using difference_type = ptrdiff_t;
254 using pointer = T*;
255 using const_pointer = const T*;
256 using reference = T&;
257 using const_reference = const T&;
258 using iterator = CheckedContiguousIterator<T>;
259 using reverse_iterator = std::reverse_iterator<iterator>;
260 static constexpr size_t extent = N;
261
262 // [span.cons], span constructors, copy, assignment, and destructor
263 constexpr span() noexcept
264 requires(N == 0)
265 = default;
266
267 // Constructs a span from a contiguous iterator and a size.
268 //
269 // # Checks
270 // The function CHECKs that `count` matches the template parameter `N` and
271 // will terminate otherwise.
272 //
273 // # Safety
274 // The iterator must point to the first of at least `count` many elements, or
275 // Undefined Behaviour can result as the span will allow access beyond the
276 // valid range of the collection pointed to by the iterator.
277 template <typename It>
278 requires(internal::CompatibleIter<T, It>)
279 UNSAFE_BUFFER_USAGE explicit constexpr span(
280 It first,
281 StrictNumeric<size_t> count) noexcept
282 : // The use of to_address() here is to handle the case where the
283 // iterator `first` is pointing to the container's `end()`. In that
284 // case we can not use the address returned from the iterator, or
285 // dereference it through the iterator's `operator*`, but we can store
286 // it. We must assume in this case that `count` is 0, since the
287 // iterator does not point to valid data. Future hardening of iterators
288 // may disallow pulling the address from `end()`, as demonstrated by
289 // asserts() in libstdc++:
290 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93960.
291 //
292 // The span API dictates that the `data()` is accessible when size is
293 // 0, since the pointer may be valid, so we cannot prevent storing and
294 // giving out an invalid pointer here without breaking API
295 // compatibility and our unit tests. Thus protecting against this can
296 // likely only be successful from inside iterators themselves, where
297 // the context about the pointer is known.
298 //
299 // We can not protect here generally against an invalid iterator/count
300 // being passed in, since we have no context to determine if the
301 // iterator or count are valid.
302 data_(base::to_address(first)) {
303 // Guarantees that the N in the type signature is correct.
304 CHECK(N == count);
305 }
306
307 // Constructs a span from a contiguous iterator and a size.
308 //
309 // # Checks
310 // The function CHECKs that `it <= end` and will terminate otherwise.
311 //
312 // # Safety
313 // The begin and end iterators must be for the same allocation or Undefined
314 // Behaviour can result as the span will allow access beyond the valid range
315 // of the collection pointed to by `begin`.
316 template <typename It, typename End>
317 requires(internal::CompatibleIter<T, It> &&
318 std::sized_sentinel_for<End, It> &&
319 !std::convertible_to<End, size_t>)
320 UNSAFE_BUFFER_USAGE explicit constexpr span(It begin, End end) noexcept
321 // SAFETY: The caller must guarantee that the iterator and end sentinel
322 // are part of the same allocation, in which case it is the number of
323 // elements between the iterators and thus a valid size for the pointer to
324 // the element at `begin`.
325 //
326 // We CHECK that `end - begin` did not underflow below. Normally checking
327 // correctness afterward is flawed, however underflow is not UB and the
328 // size is not converted to an invalid pointer (which would be UB) before
329 // we CHECK for underflow.
330 : UNSAFE_BUFFERS(span(begin, static_cast<size_t>(end - begin))) {
331 // Verify `end - begin` did not underflow.
332 CHECK(begin <= end);
333 }
334
335 // NOLINTNEXTLINE(google-explicit-constructor)
336 constexpr span(T (&arr)[N]) noexcept
337 // SAFETY: The std::ranges::size() function gives the number of elements
338 // pointed to by the std::ranges::data() function, which meets the
339 // requirement of span.
340 : UNSAFE_BUFFERS(span(std::ranges::data(arr), std::ranges::size(arr))) {}
341
342 template <typename R, size_t X = internal::ExtentV<R>>
343 requires(internal::CompatibleRange<T, R> && (X == N || X == dynamic_extent))
344 // NOLINTNEXTLINE(google-explicit-constructor)
345 explicit(X == dynamic_extent) constexpr span(R&& range) noexcept
346 // SAFETY: The std::ranges::size() function gives the number of elements
347 // pointed to by the std::ranges::data() function, which meets the
348 // requirement of span.
349 : UNSAFE_BUFFERS(
350 span(std::ranges::data(range), std::ranges::size(range))) {}
351
352 // [span.sub], span subviews
353 template <size_t Count>
354 constexpr span<T, Count> first() const noexcept
355 requires(Count <= N)
356 {
357 // SAFETY: span provides that data() points to at least `N` many elements.
358 // `Count` is non-negative by its type and `Count <= N` from the requires
359 // condition. So `Count` is a valid new size for `data()`.
360 return UNSAFE_BUFFERS(span<T, Count>(data(), Count));
361 }
362
363 template <size_t Count>
364 constexpr span<T, Count> last() const noexcept
365 requires(Count <= N)
366 {
367 // SAFETY: span provides that data() points to at least `N` many elements.
368 // `Count` is non-negative by its type and `Count <= N` from the requires
369 // condition. So `0 <= N - Count <= N`, meaning `N - Count` is a valid new
370 // size for `data()` and it will point to `Count` many elements.`
371 return UNSAFE_BUFFERS(span<T, Count>(data() + (N - Count), Count));
372 }
373
374 // Returns a span over the first `count` elements.
375 //
376 // # Checks
377 // The function CHECKs that the span contains at least `count` elements and
378 // will terminate otherwise.
379 constexpr span<T> first(StrictNumeric<size_t> count) const noexcept {
380 CHECK_LE(size_t{count}, size());
381 // SAFETY: span provides that data() points to at least `N` many elements.
382 // `count` is non-negative by its type and `count <= N` from the CHECK
383 // above. So `count` is a valid new size for `data()`.
384 return UNSAFE_BUFFERS({data(), count});
385 }
386
387 // Returns a span over the last `count` elements.
388 //
389 // # Checks
390 // The function CHECKs that the span contains at least `count` elements and
391 // will terminate otherwise.
392 constexpr span<T> last(StrictNumeric<size_t> count) const noexcept {
393 CHECK_LE(size_t{count}, N);
394 // SAFETY: span provides that data() points to at least `N` many elements.
395 // `count` is non-negative by its type and `count <= N` from the CHECK
396 // above. So `0 <= N - count <= N`, meaning `N - count` is a valid new size
397 // for `data()` and it will point to `count` many elements.
398 return UNSAFE_BUFFERS({data() + (N - size_t{count}), count});
399 }
400
401 template <size_t Offset, size_t Count = dynamic_extent>
402 constexpr auto subspan() const noexcept
403 requires(Offset <= N && (Count == dynamic_extent || Count <= N - Offset))
404 {
405 constexpr size_t kExtent = Count != dynamic_extent ? Count : N - Offset;
406 // SAFETY: span provides that data() points to at least `N` many elements.
407 //
408 // If Count is dynamic_extent, kExtent becomes `N - Offset`. Since `Offset
409 // <= N` from the requires condition, then `Offset` is a valid offset for
410 // data(), and `Offset + kExtent = Offset + N - Offset = N >= Offset` is
411 // also a valid offset that is not before `Offset`. This makes a span at
412 // `Offset` with size `kExtent` valid.
413 //
414 // Otherwise `Count <= N - Offset` and `0 <= Offset <= N` by the requires
415 // condition, so `Offset <= N - Count` and `N - Count` can not underflow.
416 // Then `Offset` is a valid offset for data() and `kExtent` is `Count <= N -
417 // Offset`, so `Offset + kExtent <= Offset + N - Offset = N` which makes
418 // both `Offset` and `Offset + kExtent` valid offsets for data(), and since
419 // `kExtent` is non-negative, `Offset + kExtent` is not before `Offset` so
420 // `kExtent` is a valid size for the span at `data() + Offset`.
421 return UNSAFE_BUFFERS(span<T, kExtent>(data() + Offset, kExtent));
422 }
423
424 // Returns a span over the first `count` elements starting at the given
425 // `offset` from the start of the span.
426 //
427 // # Checks
428 // The function CHECKs that the span contains at least `offset + count`
429 // elements, or at least `offset` elements if `count` is not specified, and
430 // will terminate otherwise.
431 constexpr span<T> subspan(size_t offset,
432 size_t count = dynamic_extent) const noexcept {
433 CHECK_LE(offset, N);
434 CHECK(count == dynamic_extent || count <= N - offset);
435 const size_t new_extent = count != dynamic_extent ? count : N - offset;
436 // SAFETY: span provides that data() points to at least `N` many elements.
437 //
438 // If Count is dynamic_extent, `new_extent` becomes `N - offset`. Since
439 // `offset <= N` from the requires condition, then `offset` is a valid
440 // offset for data(), and `offset + new_extent = offset + N - offset = N >=
441 // offset` is also a valid offset that is not before `offset`. This makes a
442 // span at `offset` with size `new_extent` valid.
443 //
444 // Otherwise `count <= N - offset` and `0 <= offset <= N` by the requires
445 // condition, so `offset <= N - count` and `N - count` can not underflow.
446 // Then `offset` is a valid offset for data() and `new_extent` is `count <=
447 // N - offset`, so `offset + new_extent <= offset + N - offset = N` which
448 // makes both `offset` and `offset + new_extent` valid offsets for data(),
449 // and since `new_extent` is non-negative, `offset + new_extent` is not
450 // before `offset` so `new_extent` is a valid size for the span at `data() +
451 // offset`.
452 return UNSAFE_BUFFERS({data() + offset, new_extent});
453 }
454
455 // Splits a span into two at the given `offset`, returning two spans that
456 // cover the full range of the original span.
457 //
458 // Similar to calling subspan() with the `offset` as the length on the first
459 // call, and then the `offset` as the offset in the second.
460 //
461 // The split_at<N>() overload allows construction of a fixed-size span from a
462 // compile-time constant. If the input span is fixed-size, both output output
463 // spans will be. Otherwise, the first will be fixed-size and the second will
464 // be dynamic-size.
465 //
466 // This is a non-std extension that is inspired by the Rust slice::split_at()
467 // and split_at_mut() methods.
468 //
469 // # Checks
470 // The function CHECKs that the span contains at least `offset` elements and
471 // will terminate otherwise.
472 constexpr std::pair<span<T>, span<T>> split_at(size_t offset) const noexcept {
473 return {first(offset), subspan(offset)};
474 }
475
476 template <size_t Offset>
477 requires(Offset <= N)
478 constexpr std::pair<span<T, Offset>, span<T, N - Offset>> split_at()
479 const noexcept {
480 return {first<Offset>(), subspan<Offset, N - Offset>()};
481 }
482
483 // [span.obs], span observers
484 constexpr size_t size() const noexcept { return N; }
485 constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); }
486 [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
487
488 // [span.elem], span element access
489 //
490 // # Checks
491 // The function CHECKs that the `idx` is inside the span and will terminate
492 // otherwise.
493 constexpr T& operator[](size_t idx) const noexcept {
494 CHECK_LT(idx, size());
495 // SAFETY: Since data() always points to at least `N` elements, the check
496 // above ensures `idx < N` and is thus in range for data().
497 return UNSAFE_BUFFERS(data()[idx]);
498 }
499
500 constexpr T& front() const noexcept
501 requires(N > 0)
502 {
503 // SAFETY: Since data() always points to at least `N` elements, the requires
504 // constraint above ensures `0 < N` and is thus in range for data().
505 return UNSAFE_BUFFERS(data()[0]);
506 }
507
508 constexpr T& back() const noexcept
509 requires(N > 0)
510 {
511 // SAFETY: Since data() always points to at least `N` elements, the requires
512 // constraint above ensures `N > 0` and thus `N - 1` does not underflow and
513 // is in range for data().
514 return UNSAFE_BUFFERS(data()[N - 1]);
515 }
516
517 // Returns a pointer to the first element in the span. If the span is empty
518 // (`size()` is 0), the returned pointer may or may not be null, and it must
519 // not be dereferenced.
520 //
521 // It is always valid to add `size()` to the the pointer in C++ code, though
522 // it may be invalid in C code when the span is empty.
523 constexpr T* data() const noexcept { return data_; }
524
525 // [span.iter], span iterator support
526 constexpr iterator begin() const noexcept {
527 // SAFETY: span provides that data() points to at least `size()` many
528 // elements, and size() is non-negative. So data() + size() is a valid
529 // pointer for the data() allocation.
530 return UNSAFE_BUFFERS(iterator(data(), data() + size()));
531 }
532
533 constexpr iterator end() const noexcept {
534 // SAFETY: span provides that data() points to at least `size()` many
535 // elements, and size() is non-negative. So data() + size() is a valid
536 // pointer for the data() allocation.
537 return UNSAFE_BUFFERS(iterator(data(), data() + size(), data() + size()));
538 }
539
540 constexpr reverse_iterator rbegin() const noexcept {
541 return reverse_iterator(end());
542 }
543
544 constexpr reverse_iterator rend() const noexcept {
545 return reverse_iterator(begin());
546 }
547
548 // Bounds-checked copy from a non-overlapping span. The spans must be the
549 // exact same size or a hard CHECK() occurs. If the two spans overlap,
550 // Undefined Behaviour occurs.
551 //
552 // This is a non-std extension that is inspired by the Rust
553 // slice::copy_from_slice() method.
554 //
555 // # Checks
556 // The function CHECKs that the `other` span has the same size as itself and
557 // will terminate otherwise.
558 constexpr void copy_from(span<const T, N> other)
559 requires(!std::is_const_v<T>)
560 {
561 CHECK_EQ(size_bytes(), other.size_bytes());
562 // Verify non-overlapping in developer builds.
563 //
564 // SAFETY: span provides that data() points to at least size() many
565 // elements, so adding size() to the data() pointer is well-defined.
566 DCHECK(UNSAFE_BUFFERS(data() + size()) <= other.data() ||
567 data() >= UNSAFE_BUFFERS(other.data() + other.size()));
568 // When compiling with -Oz, std::ranges::copy() does not get inlined, which
569 // makes copy_from() very expensive compared to memcpy for small sizes (up
570 // to around 4x slower). We observe that this is because ranges::copy() uses
571 // begin()/end() and span's iterators are checked iterators, not just
572 // pointers. This additional complexity prevents inlining and breaks the
573 // ability for the compiler to eliminate code.
574 //
575 // See also https://crbug.com/1396134.
576 //
577 // We also see std::copy() (with pointer arguments! not iterators) optimize
578 // and inline better than memcpy() since memcpy() needs to rely on
579 // size_bytes(), which while computable at compile time when `other` has a
580 // fixed size, the optimizer stumbles on with -Oz.
581 //
582 // SAFETY: The copy() here does not check bounds, but we have verified that
583 // `this` and `other` have the same bounds above (and are pointers of the
584 // same type), so `data()` and `other.data()` both have at least
585 // `other.size()` elements.
586 UNSAFE_BUFFERS(
587 std::copy(other.data(), other.data() + other.size(), data()));
588 }
589
590 // Implicit conversion from std::span<T, N> to base::span<T, N>.
591 //
592 // We get other conversions for free from std::span's constructors, but it
593 // does not deduce N on its range constructor.
594 span(std::span<std::remove_const_t<T>, N> other)
595 : // SAFETY: std::span contains a valid data pointer and size such
596 // that pointer+size remains valid.
597 UNSAFE_BUFFERS(
598 span(std::ranges::data(other), std::ranges::size(other))) {}
599 span(std::span<T, N> other)
600 requires(std::is_const_v<T>)
601 : // SAFETY: std::span contains a valid data pointer and size such
602 // that pointer+size remains valid.
603 UNSAFE_BUFFERS(
604 span(std::ranges::data(other), std::ranges::size(other))) {}
605
606 // Implicit conversion from base::span<T, N> to std::span<T, N>.
607 //
608 // We get other conversions for free from std::span's constructors, but it
609 // does not deduce N on its range constructor.
610 operator std::span<T, N>() const { return std::span<T, N>(*this); }
611 operator std::span<const T, N>() const
612 requires(!std::is_const_v<T>)
613 {
614 return std::span<const T, N>(*this);
615 }
616
617 // Compares two spans for equality by comparing the objects pointed to by the
618 // spans. The operation is defined for spans of different types as long as the
619 // types are themselves comparable.
620 //
621 // For primitive types, this replaces the less safe `memcmp` function, where
622 // `memcmp(a.data(), b.data(), a.size())` can be written as `a == b` and can
623 // no longer go outside the bounds of `b`. Otherwise, it replaced std::equal
624 // or std::ranges::equal when working with spans, and when no projection is
625 // needed.
626 //
627 // If the spans are of different sizes, they are not equal. If both spans are
628 // empty, they are always equal (even though their data pointers may differ).
629 //
630 // # Implementation note
631 // The non-template overloads allow implicit conversions to span for
632 // comparison.
633 friend constexpr bool operator==(span lhs, span rhs)
634 requires(std::equality_comparable<const T>)
635 {
636 return internal::span_cmp(span<const T, N>(lhs), span<const T, N>(rhs));
637 }
638 friend constexpr bool operator==(span lhs, span<const T, N> rhs)
639 requires(!std::is_const_v<T> && std::equality_comparable<const T>)
640 {
641 return internal::span_cmp(span<const T, N>(lhs), span<const T, N>(rhs));
642 }
643 template <class U, size_t M>
644 requires((N == M || M == dynamic_extent) &&
645 std::equality_comparable_with<const T, const U>)
646 friend constexpr bool operator==(span lhs, span<U, M> rhs) {
647 return internal::span_cmp(span<const T, N>(lhs), span<const U, M>(rhs));
648 }
649
650 private:
651 // This field is not a raw_ptr<> since span is mostly used for stack
652 // variables. Use `raw_span` instead for class fields, which does use
653 // raw_ptr<> internally.
654 InternalPtrType data_ = nullptr;
655 };
656
657 // [span], class template span
658 template <typename T, typename InternalPtrType>
659 class GSL_POINTER span<T, dynamic_extent, InternalPtrType> {
660 public:
661 using element_type = T;
662 using value_type = std::remove_cv_t<T>;
663 using size_type = size_t;
664 using difference_type = ptrdiff_t;
665 using pointer = T*;
666 using const_pointer = const T*;
667 using reference = T&;
668 using const_reference = const T&;
669 using iterator = CheckedContiguousIterator<T>;
670 using reverse_iterator = std::reverse_iterator<iterator>;
671 static constexpr size_t extent = dynamic_extent;
672
673 constexpr span() noexcept = default;
674
675 // Constructs a span from a contiguous iterator and a size.
676 //
677 // # Safety
678 // The iterator must point to the first of at least `count` many elements, or
679 // Undefined Behaviour can result as the span will allow access beyond the
680 // valid range of the collection pointed to by the iterator.
681 template <typename It>
682 requires(internal::CompatibleIter<T, It>)
683 UNSAFE_BUFFER_USAGE constexpr span(It first,
684 StrictNumeric<size_t> count) noexcept
685 // The use of to_address() here is to handle the case where the iterator
686 // `first` is pointing to the container's `end()`. In that case we can
687 // not use the address returned from the iterator, or dereference it
688 // through the iterator's `operator*`, but we can store it. We must
689 // assume in this case that `count` is 0, since the iterator does not
690 // point to valid data. Future hardening of iterators may disallow
691 // pulling the address from `end()`, as demonstrated by asserts() in
692 // libstdc++: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93960.
693 //
694 // The span API dictates that the `data()` is accessible when size is 0,
695 // since the pointer may be valid, so we cannot prevent storing and
696 // giving out an invalid pointer here without breaking API compatibility
697 // and our unit tests. Thus protecting against this can likely only be
698 // successful from inside iterators themselves, where the context about
699 // the pointer is known.
700 //
701 // We can not protect here generally against an invalid iterator/count
702 // being passed in, since we have no context to determine if the
703 // iterator or count are valid.
704 : data_(base::to_address(first)), size_(count) {}
705
706 // Constructs a span from a contiguous iterator and a size.
707 //
708 // # Safety
709 // The begin and end iterators must be for the same allocation, and `begin <=
710 // end` or Undefined Behaviour can result as the span will allow access beyond
711 // the valid range of the collection pointed to by `begin`.
712 template <typename It, typename End>
713 requires(internal::CompatibleIter<T, It> &&
714 std::sized_sentinel_for<End, It> &&
715 !std::convertible_to<End, size_t>)
716 UNSAFE_BUFFER_USAGE constexpr span(It begin, End end) noexcept
717 // SAFETY: The caller must guarantee that the iterator and end sentinel
718 // are part of the same allocation, in which case it is the number of
719 // elements between the iterators and thus a valid size for the pointer to
720 // the element at `begin`.
721 //
722 // We CHECK that `end - begin` did not underflow below. Normally checking
723 // correctness afterward is flawed, however underflow is not UB and the
724 // size is not converted to an invalid pointer (which would be UB) before
725 // we CHECK for underflow.
726 : UNSAFE_BUFFERS(span(begin, static_cast<size_t>(end - begin))) {
727 // Verify `end - begin` did not underflow.
728 CHECK(begin <= end);
729 }
730
731 template <size_t N>
732 // NOLINTNEXTLINE(google-explicit-constructor)
733 constexpr span(T (&arr)[N]) noexcept
734 // SAFETY: The std::ranges::size() function gives the number of elements
735 // pointed to by the std::ranges::data() function, which meets the
736 // requirement of span.
737 : UNSAFE_BUFFERS(span(std::ranges::data(arr), std::ranges::size(arr))) {}
738
739 template <typename R>
740 requires(internal::LegacyCompatibleRange<T, R>)
741 // NOLINTNEXTLINE(google-explicit-constructor)
742 constexpr span(R&& range) noexcept
743 // SAFETY: The std::ranges::size() function gives the number of elements
744 // pointed to by the std::ranges::data() function, which meets the
745 // requirement of span.
746 : UNSAFE_BUFFERS(
747 span(std::ranges::data(range), std::ranges::size(range))) {}
748
749 // [span.sub], span subviews
750 template <size_t Count>
751 constexpr span<T, Count> first() const noexcept {
752 CHECK_LE(Count, size());
753 // SAFETY: span provides that data() points to at least `size()` many
754 // elements. `Count` is non-negative by its type and `Count <= size()` from
755 // the CHECK above. So `Count` is a valid new size for `data()`.
756 return UNSAFE_BUFFERS(span<T, Count>(data(), Count));
757 }
758
759 template <size_t Count>
760 constexpr span<T, Count> last() const noexcept {
761 CHECK_LE(Count, size());
762 // SAFETY: span provides that data() points to at least `size()` many
763 // elements. `Count` is non-negative by its type and `Count <= size()` from
764 // the check above. So `0 <= size() - Count <= size()`, meaning
765 // `size() - Count` is a valid new size for `data()` and it will point to
766 // `Count` many elements.
767 return UNSAFE_BUFFERS(span<T, Count>(data() + (size() - Count), Count));
768 }
769
770 // Returns a span over the first `count` elements.
771 //
772 // # Checks
773 // The function CHECKs that the span contains at least `count` elements and
774 // will terminate otherwise.
775 constexpr span<T> first(StrictNumeric<size_t> count) const noexcept {
776 CHECK_LE(size_t{count}, size());
777 // SAFETY: span provides that data() points to at least `size()` many
778 // elements. `count` is non-negative by its type and `count <= size()` from
779 // the CHECK above. So `count` is a valid new size for `data()`.
780 return UNSAFE_BUFFERS({data(), count});
781 }
782
783 // Returns a span over the last `count` elements.
784 //
785 // # Checks
786 // The function CHECKs that the span contains at least `count` elements and
787 // will terminate otherwise.
788 constexpr span<T> last(StrictNumeric<size_t> count) const noexcept {
789 CHECK_LE(size_t{count}, size());
790 // SAFETY: span provides that data() points to at least `size()` many
791 // elements. `count` is non-negative by its type and `count <= size()` from
792 // the CHECK above. So `0 <= size() - count <= size()`, meaning
793 // `size() - count` is a valid new size for `data()` and it will point to
794 // `count` many elements.
795 return UNSAFE_BUFFERS({data() + (size() - size_t{count}), count});
796 }
797
798 template <size_t Offset, size_t Count = dynamic_extent>
799 constexpr span<T, Count> subspan() const noexcept {
800 CHECK_LE(Offset, size());
801 CHECK(Count == dynamic_extent || Count <= size() - Offset);
802 const size_t new_extent = Count != dynamic_extent ? Count : size() - Offset;
803 // SAFETY: span provides that data() points to at least `size()` many
804 // elements.
805 //
806 // If Count is dynamic_extent, `new_extent` becomes `size() - Offset`. Since
807 // `Offset <= size()` from the check above, then `Offset` is a valid offset
808 // for data(), and `Offset + new_extent = Offset + size() - Offset = size()
809 // >= Offset` is also a valid offset that is not before `Offset`. This makes
810 // a span at `Offset` with size `new_extent` valid.
811 //
812 // Otherwise `Count <= size() - Offset` and `0 <= Offset <= size()` by the
813 // check above, so `Offset <= size() - Count` and `size() - Count` can not
814 // underflow. Then `Offset` is a valid offset for data() and `new_extent` is
815 // `Count <= size() - Offset`, so `Offset + extent <= Offset + size() -
816 // Offset = size()` which makes both `Offset` and `Offset + new_extent`
817 // valid offsets for data(), and since `new_extent` is non-negative, `Offset
818 // + new_extent` is not before `Offset` so `new_extent` is a valid size for
819 // the span at `data() + Offset`.
820 return UNSAFE_BUFFERS(span<T, Count>(data() + Offset, new_extent));
821 }
822
823 // Returns a span over the first `count` elements starting at the given
824 // `offset` from the start of the span.
825 //
826 // # Checks
827 // The function CHECKs that the span contains at least `offset + count`
828 // elements, or at least `offset` elements if `count` is not specified, and
829 // will terminate otherwise.
830 constexpr span<T> subspan(size_t offset,
831 size_t count = dynamic_extent) const noexcept {
832 CHECK_LE(offset, size());
833 CHECK(count == dynamic_extent || count <= size() - offset);
834 const size_t new_extent = count != dynamic_extent ? count : size() - offset;
835 // SAFETY: span provides that data() points to at least `size()` many
836 // elements.
837 //
838 // If count is dynamic_extent, `new_extent` becomes `size() - offset`. Since
839 // `offset <= size()` from the check above, then `offset` is a valid offset
840 // for data(), and `offset + new_extent = offset + size() - offset = size()
841 // >= offset` is also a valid offset that is not before `offset`. This makes
842 // a span at `offset` with size `new_extent` valid.
843 //
844 // Otherwise `count <= size() - offset` and `0 <= offset <= size()` by the
845 // checks above, so `offset <= size() - count` and `size() - count` can not
846 // underflow. Then `offset` is a valid offset for data() and `new_extent` is
847 // `count <= size() - offset`, so `offset + new_extent <= offset + size() -
848 // offset = size()` which makes both `offset` and `offset + new_extent`
849 // valid offsets for data(), and since `new_extent` is non-negative, `offset
850 // + new_extent` is not before `offset` so `new_extent` is a valid size for
851 // the span at `data() + offset`.
852 return UNSAFE_BUFFERS({data() + offset, new_extent});
853 }
854
855 // Splits a span into two at the given `offset`, returning two spans that
856 // cover the full range of the original span.
857 //
858 // Similar to calling subspan() with the `offset` as the length on the first
859 // call, and then the `offset` as the offset in the second.
860 //
861 // The split_at<N>() overload allows construction of a fixed-size span from a
862 // compile-time constant. If the input span is fixed-size, both output output
863 // spans will be. Otherwise, the first will be fixed-size and the second will
864 // be dynamic-size.
865 //
866 // This is a non-std extension that is inspired by the Rust slice::split_at()
867 // and split_at_mut() methods.
868 //
869 // # Checks
870 // The function CHECKs that the span contains at least `offset` elements and
871 // will terminate otherwise.
872 constexpr std::pair<span<T>, span<T>> split_at(size_t offset) const noexcept {
873 return {first(offset), subspan(offset)};
874 }
875
876 // An overload of `split_at` which returns a fixed-size span.
877 //
878 // # Checks
879 // The function CHECKs that the span contains at least `Offset` elements and
880 // will terminate otherwise.
881 template <size_t Offset>
882 constexpr std::pair<span<T, Offset>, span<T>> split_at() const noexcept {
883 CHECK_LE(Offset, size());
884 return {first<Offset>(), subspan(Offset)};
885 }
886
887 // [span.obs], span observers
888 constexpr size_t size() const noexcept { return size_; }
889 constexpr size_t size_bytes() const noexcept { return size() * sizeof(T); }
890 [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; }
891
892 // [span.elem], span element access
893 //
894 // # Checks
895 // The function CHECKs that the `idx` is inside the span and will terminate
896 // otherwise.
897 constexpr T& operator[](size_t idx) const noexcept {
898 CHECK_LT(idx, size());
899 // SAFETY: Since data() always points to at least `size()` elements, the
900 // check above ensures `idx < size()` and is thus in range for data().
901 return UNSAFE_BUFFERS(data()[idx]);
902 }
903
904 // Returns a reference to the first element in the span.
905 //
906 // # Checks
907 // The function CHECKs that the span is not empty and will terminate
908 // otherwise.
909 constexpr T& front() const noexcept {
910 CHECK(!empty());
911 // SAFETY: Since data() always points to at least `size()` elements, the
912 // check above above ensures `0 < size()` and is thus in range for data().
913 return UNSAFE_BUFFERS(data()[0]);
914 }
915
916 // Returns a reference to the last element in the span.
917 //
918 // # Checks
919 // The function CHECKs that the span is not empty and will terminate
920 // otherwise.
921 constexpr T& back() const noexcept {
922 CHECK(!empty());
923 // SAFETY: Since data() always points to at least `size()` elements, the
924 // check above above ensures `size() > 0` and thus `size() - 1` does not
925 // underflow and is in range for data().
926 return UNSAFE_BUFFERS(data()[size() - 1]);
927 }
928
929 // Returns a pointer to the first element in the span. If the span is empty
930 // (`size()` is 0), the returned pointer may or may not be null, and it must
931 // not be dereferenced.
932 //
933 // It is always valid to add `size()` to the the pointer in C++ code, though
934 // it may be invalid in C code when the span is empty.
935 constexpr T* data() const noexcept { return data_; }
936
937 // [span.iter], span iterator support
938 constexpr iterator begin() const noexcept {
939 // SAFETY: span provides that data() points to at least `size()` many
940 // elements, and size() is non-negative. So data() + size() is a valid
941 // pointer for the data() allocation.
942 return UNSAFE_BUFFERS(iterator(data(), data() + size()));
943 }
944
945 constexpr iterator end() const noexcept {
946 // SAFETY: span provides that data() points to at least `size()` many
947 // elements, and size() is non-negative. So data() + size() is a valid
948 // pointer for the data() allocation.
949 return UNSAFE_BUFFERS(iterator(data(), data() + size(), data() + size()));
950 }
951
952 constexpr reverse_iterator rbegin() const noexcept {
953 return reverse_iterator(end());
954 }
955
956 constexpr reverse_iterator rend() const noexcept {
957 return reverse_iterator(begin());
958 }
959
960 // Bounds-checked copy from a non-overlapping span. The spans must be the
961 // exact same size or a hard CHECK() occurs. If the two spans overlap,
962 // Undefined Behaviour occurs.
963 //
964 // This is a non-std extension that is inspired by the Rust
965 // slice::copy_from_slice() method.
966 //
967 // # Checks
968 // The function CHECKs that the `other` span has the same size as itself and
969 // will terminate otherwise.
970 constexpr void copy_from(span<const T> other)
971 requires(!std::is_const_v<T>)
972 {
973 CHECK_EQ(size_bytes(), other.size_bytes());
974 // Verify non-overlapping in developer builds.
975 //
976 // SAFETY: span provides that data() points to at least size() many
977 // elements, so adding size() to the data() pointer is well-defined.
978 DCHECK(UNSAFE_BUFFERS(data() + size()) <= other.data() ||
979 data() >= UNSAFE_BUFFERS(other.data() + other.size()));
980 // When compiling with -Oz, std::ranges::copy() does not get inlined, which
981 // makes copy_from() very expensive compared to memcpy for small sizes (up
982 // to around 4x slower). We observe that this is because ranges::copy() uses
983 // begin()/end() and span's iterators are checked iterators, not just
984 // pointers. This additional complexity prevents inlining and breaks the
985 // ability for the compiler to eliminate code.
986 //
987 // See also https://crbug.com/1396134.
988 //
989 // We also see std::copy() (with pointer arguments! not iterators) optimize
990 // and inline better than memcpy() since memcpy() needs to rely on
991 // size_bytes(), which while computable at compile time when `other` has a
992 // fixed size, the optimizer stumbles on with -Oz.
993 //
994 // SAFETY: The copy() here does not check bounds, but we have verified that
995 // `this` and `other` have the same bounds above (and are pointers of the
996 // same type), so `data()` and `other.data()` both have at least
997 // `other.size()` elements.
998 UNSAFE_BUFFERS(
999 std::copy(other.data(), other.data() + other.size(), data()));
1000 }
1001
1002 // Compares two spans for equality by comparing the objects pointed to by the
1003 // spans. The operation is defined for spans of different types as long as the
1004 // types are themselves comparable.
1005 //
1006 // For primitive types, this replaces the less safe `memcmp` function, where
1007 // `memcmp(a.data(), b.data(), a.size())` can be written as `a == b` and can
1008 // no longer go outside the bounds of `b`. Otherwise, it replaced std::equal
1009 // or std::ranges::equal when working with spans, and when no projection is
1010 // needed.
1011 //
1012 // If the spans are of different sizes, they are not equal. If both spans are
1013 // empty, they are always equal (even though their data pointers may differ).
1014 //
1015 // # Implementation note
1016 // The non-template overloads allow implicit conversions to span for
1017 // comparison.
1018 friend constexpr bool operator==(span lhs, span rhs)
1019 requires(std::equality_comparable<const T>)
1020 {
1021 return internal::span_cmp(span<const T>(lhs), span<const T>(rhs));
1022 }
1023 friend constexpr bool operator==(span lhs, span<const T> rhs)
1024 requires(!std::is_const_v<T> && std::equality_comparable<const T>)
1025 {
1026 return internal::span_cmp(span<const T>(lhs), span<const T>(rhs));
1027 }
1028 template <class U, size_t M>
1029 requires(std::equality_comparable_with<const T, const U>)
1030 friend constexpr bool operator==(span lhs, span<U, M> rhs) {
1031 return internal::span_cmp(span<const T>(lhs), span<const U, M>(rhs));
1032 }
1033
1034 private:
1035 // This field is not a raw_ptr<> since span is mostly used for stack
1036 // variables. Use `raw_span` instead for class fields, which does use
1037 // raw_ptr<> internally.
1038 InternalPtrType data_ = nullptr;
1039 size_t size_ = 0;
1040 };
1041
1042 // [span.deduct], deduction guides.
1043 template <typename It, typename EndOrSize>
1044 requires(std::contiguous_iterator<It>)
1045 span(It, EndOrSize) -> span<std::remove_reference_t<std::iter_reference_t<It>>>;
1046
1047 template <
1048 typename R,
1049 typename T = std::remove_reference_t<std::ranges::range_reference_t<R>>>
1050 requires(std::ranges::contiguous_range<R>)
1051 span(R&&)
1052 -> span<std::conditional_t<std::ranges::borrowed_range<R>, T, const T>,
1053 internal::ExtentV<R>>;
1054
1055 // This guide prefers to let the contiguous_range guide match, since it can
1056 // produce a fixed-size span. Whereas, LegacyRange only produces a dynamic-sized
1057 // span.
1058 template <typename R>
1059 requires(!std::ranges::contiguous_range<R> && internal::LegacyRange<R>)
1060 span(R&& r) noexcept
1061 -> span<std::remove_reference_t<decltype(*std::ranges::data(r))>>;
1062
1063 template <typename T, size_t N>
1064 span(const T (&)[N]) -> span<const T, N>;
1065
1066 // [span.objectrep], views of object representation
1067 template <typename T, size_t X>
1068 constexpr auto as_bytes(span<T, X> s) noexcept {
1069 constexpr size_t N = X == dynamic_extent ? dynamic_extent : sizeof(T) * X;
1070 // SAFETY: span provides that data() points to at least size_bytes() many
1071 // bytes. So since `uint8_t` has a size of 1 byte, the size_bytes() value is
1072 // a valid size for a span at data() when viewed as `uint8_t*`.
1073 //
1074 // The reinterpret_cast is valid as the alignment of uint8_t (which is 1) is
1075 // always less-than or equal to the alignment of T.
1076 return UNSAFE_BUFFERS(span<const uint8_t, N>(
1077 reinterpret_cast<const uint8_t*>(s.data()), s.size_bytes()));
1078 }
1079
1080 template <typename T, size_t X>
1081 requires(!std::is_const_v<T>)
1082 constexpr auto as_writable_bytes(span<T, X> s) noexcept {
1083 constexpr size_t N = X == dynamic_extent ? dynamic_extent : sizeof(T) * X;
1084 // SAFETY: span provides that data() points to at least size_bytes() many
1085 // bytes. So since `uint8_t` has a size of 1 byte, the size_bytes() value is a
1086 // valid size for a span at data() when viewed as `uint8_t*`.
1087 //
1088 // The reinterpret_cast is valid as the alignment of uint8_t (which is 1) is
1089 // always less-than or equal to the alignment of T.
1090 return UNSAFE_BUFFERS(
1091 span<uint8_t, N>(reinterpret_cast<uint8_t*>(s.data()), s.size_bytes()));
1092 }
1093
1094 // as_chars() is the equivalent of as_bytes(), except that it returns a
1095 // span of const char rather than const uint8_t. This non-std function is
1096 // added since chrome still represents many things as char arrays which
1097 // rightfully should be uint8_t.
1098 template <typename T, size_t X>
1099 constexpr auto as_chars(span<T, X> s) noexcept {
1100 constexpr size_t N = X == dynamic_extent ? dynamic_extent : sizeof(T) * X;
1101 // SAFETY: span provides that data() points to at least size_bytes() many
1102 // bytes. So since `char` has a size of 1 byte, the size_bytes() value is a
1103 // valid size for a span at data() when viewed as `char*`.
1104 //
1105 // The reinterpret_cast is valid as the alignment of char (which is 1) is
1106 // always less-than or equal to the alignment of T.
1107 return UNSAFE_BUFFERS(span<const char, N>(
1108 reinterpret_cast<const char*>(s.data()), s.size_bytes()));
1109 }
1110
1111 // as_string_view() converts a span over byte-sized primitives (holding chars or
1112 // uint8_t) into a std::string_view, where each byte is represented as a char.
1113 // It also accepts any type that can implicitly convert to a span, such as
1114 // arrays.
1115 //
1116 // If you want to view an arbitrary span type as a string, first explicitly
1117 // convert it to bytes via `base::as_bytes()`.
1118 //
1119 // For spans over byte-sized primitives, this is sugar for:
1120 // ```
1121 // std::string_view(as_chars(span).begin(), as_chars(span).end())
1122 // ```
1123 constexpr std::string_view as_string_view(span<const char> s) noexcept {
1124 return std::string_view(s.begin(), s.end());
1125 }
1126 constexpr std::string_view as_string_view(
1127 span<const unsigned char> s) noexcept {
1128 const auto c = as_chars(s);
1129 return std::string_view(c.begin(), c.end());
1130 }
1131
1132 // as_writable_chars() is the equivalent of as_writable_bytes(), except that
1133 // it returns a span of char rather than uint8_t. This non-std function is
1134 // added since chrome still represents many things as char arrays which
1135 // rightfully should be uint8_t.
1136 template <typename T, size_t X>
1137 requires(!std::is_const_v<T>)
1138 auto as_writable_chars(span<T, X> s) noexcept {
1139 constexpr size_t N = X == dynamic_extent ? dynamic_extent : sizeof(T) * X;
1140 // SAFETY: span provides that data() points to at least size_bytes() many
1141 // bytes. So since `char` has a size of 1 byte, the size_bytes() value is
1142 // a valid size for a span at data() when viewed as `char*`.
1143 //
1144 // The reinterpret_cast is valid as the alignment of char (which is 1) is
1145 // always less-than or equal to the alignment of T.
1146 return UNSAFE_BUFFERS(
1147 span<char, N>(reinterpret_cast<char*>(s.data()), s.size_bytes()));
1148 }
1149
1150 // Type-deducing helper for constructing a span.
1151 //
1152 // # Safety
1153 // The contiguous iterator `it` must point to the first element of at least
1154 // `size` many elements or Undefined Behaviour may result as the span may give
1155 // access beyond the bounds of the collection pointed to by `it`.
1156 template <int&... ExplicitArgumentBarrier, typename It>
1157 UNSAFE_BUFFER_USAGE constexpr auto make_span(
1158 It it,
1159 StrictNumeric<size_t> size) noexcept {
1160 using T = std::remove_reference_t<std::iter_reference_t<It>>;
1161 // SAFETY: The caller guarantees that `it` is the first of at least `size`
1162 // many elements.
1163 return UNSAFE_BUFFERS(span<T>(it, size));
1164 }
1165
1166 // Type-deducing helper for constructing a span.
1167 //
1168 // # Checks
1169 // The function CHECKs that `it <= end` and will terminate otherwise.
1170 //
1171 // # Safety
1172 // The contiguous iterator `it` and its end sentinel `end` must be for the same
1173 // allocation or Undefined Behaviour may result as the span may give access
1174 // beyond the bounds of the collection pointed to by `it`.
1175 template <int&... ExplicitArgumentBarrier,
1176 typename It,
1177 typename End,
1178 typename = std::enable_if_t<!std::is_convertible_v<End, size_t>>>
1179 UNSAFE_BUFFER_USAGE constexpr auto make_span(It it, End end) noexcept {
1180 using T = std::remove_reference_t<std::iter_reference_t<It>>;
1181 // SAFETY: The caller guarantees that `it` and `end` are iterators of the
1182 // same allocation.
1183 return UNSAFE_BUFFERS(span<T>(it, end));
1184 }
1185
1186 // make_span utility function that deduces both the span's value_type and extent
1187 // from the passed in argument.
1188 //
1189 // Usage: auto span = base::make_span(...);
1190 template <int&... ExplicitArgumentBarrier, typename Container>
1191 constexpr auto make_span(Container&& container) noexcept {
1192 using T =
1193 std::remove_pointer_t<decltype(std::data(std::declval<Container>()))>;
1194 using Extent = internal::Extent<Container>;
1195 return span<T, Extent::value>(std::forward<Container>(container));
1196 }
1197
1198 // make_span utility function that allows callers to explicit specify the span's
1199 // extent, the value_type is deduced automatically. This is useful when passing
1200 // a dynamically sized container to a method expecting static spans, when the
1201 // container is known to have the correct size.
1202 //
1203 // Note: This will CHECK that N indeed matches size(container).
1204 //
1205 // # Usage
1206 // As this function is unsafe, the caller must guarantee that the size is
1207 // correct for the iterator, and will not allow the span to reach out of bounds.
1208 // ```
1209 // // SAFETY: <An explanation of how the size is checked/ensured to always be
1210 // // valid for the iterator>.
1211 // auto static_span = UNSAFE_BUFFERS(base::make_span<N>(it, size));
1212 // ```
1213 //
1214 // # Safety
1215 // The contiguous iterator `it` must point to the first element of at least
1216 // `size` many elements or Undefined Behaviour may result as the span may give
1217 // access beyond the bounds of the collection pointed to by `it`.
1218 template <size_t N, int&... ExplicitArgumentBarrier, typename It>
1219 UNSAFE_BUFFER_USAGE constexpr auto make_span(
1220 It it,
1221 StrictNumeric<size_t> size) noexcept {
1222 using T = std::remove_reference_t<std::iter_reference_t<It>>;
1223 // SAFETY: The caller guarantees that `it` is the first of at least `size`
1224 // many elements.
1225 return UNSAFE_BUFFERS(span<T, N>(it, size));
1226 }
1227
1228 // make_span utility function that allows callers to explicit specify the span's
1229 // extent, the value_type is deduced automatically. This is useful when passing
1230 // a dynamically sized container to a method expecting static spans, when the
1231 // container is known to have the correct size.
1232 //
1233 // Note: This will CHECK that N indeed matches size(container).
1234 //
1235 // # Usage
1236 // As this function is unsafe, the caller must guarantee that the `end` is from
1237 // the same allocation as the `it` iterator.
1238 // ```
1239 // // SAFETY: <An explanation if non-trivial how the iterators are not from
1240 // // different containers/allocations>.
1241 // auto static_span = UNSAFE_BUFFERS(base::make_span<N>(it, end));
1242 // ```
1243 //
1244 // # Checks
1245 // The function CHECKs that `it <= end` and will terminate otherwise.
1246 //
1247 // # Safety
1248 // The contiguous iterator `it` and its end sentinel `end` must be for the same
1249 // allocation or Undefined Behaviour may result as the span may give access
1250 // beyond the bounds of the collection pointed to by `it`.
1251 template <size_t N,
1252 int&... ExplicitArgumentBarrier,
1253 typename It,
1254 typename End,
1255 typename = std::enable_if_t<!std::is_convertible_v<End, size_t>>>
1256 UNSAFE_BUFFER_USAGE constexpr auto make_span(It it, End end) noexcept {
1257 using T = std::remove_reference_t<std::iter_reference_t<It>>;
1258 // SAFETY: The caller guarantees that `it` and `end` are iterators of the
1259 // same allocation.
1260 return UNSAFE_BUFFERS(span<T, N>(it, end));
1261 }
1262
1263 template <size_t N, int&... ExplicitArgumentBarrier, typename Container>
1264 constexpr auto make_span(Container&& container) noexcept {
1265 using T =
1266 std::remove_pointer_t<decltype(std::data(std::declval<Container>()))>;
1267 // SAFETY: The std::size() function gives the number of elements pointed to by
1268 // the std::data() function, which meets the requirement of span.
1269 return UNSAFE_BUFFERS(span<T, N>(std::data(container), std::size(container)));
1270 }
1271
1272 // `span_from_ref` converts a reference to T into a span of length 1. This is a
1273 // non-std helper that is inspired by the `std::slice::from_ref()` function from
1274 // Rust.
1275 template <typename T>
1276 constexpr span<T, 1u> span_from_ref(
1277 T& single_object ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
1278 // SAFETY: Given a valid reference to `single_object` the span of size 1 will
1279 // be a valid span that points to the `single_object`.
1280 return UNSAFE_BUFFERS(span<T, 1u>(std::addressof(single_object), 1u));
1281 }
1282
1283 // `byte_span_from_ref` converts a reference to T into a span of uint8_t of
1284 // length sizeof(T). This is a non-std helper that is a sugar for
1285 // `as_writable_bytes(span_from_ref(x))`.
1286 //
1287 // Const references are turned into a `span<const T, sizeof(T)>` while mutable
1288 // references are turned into a `span<T, sizeof(T)>`.
1289 template <typename T>
1290 constexpr span<const uint8_t, sizeof(T)> byte_span_from_ref(
1291 const T& single_object ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
1292 return as_bytes(span_from_ref(single_object));
1293 }
1294 template <typename T>
1295 constexpr span<uint8_t, sizeof(T)> byte_span_from_ref(
1296 T& single_object ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept {
1297 return as_writable_bytes(span_from_ref(single_object));
1298 }
1299
1300 // Converts a string literal (such as `"hello"`) to a span of `char` while
1301 // omitting the terminating NUL character. These two are equivalent:
1302 // ```
1303 // base::span<char, 5u> s1 = base::span_from_cstring("hello");
1304 // base::span<char, 5u> s2 = base::span(std::string_view("hello"));
1305 // ```
1306 //
1307 // If you want to include the NUL terminator, then use the span constructor
1308 // directly, such as:
1309 // ```
1310 // base::span<char, 6u> s = base::span("hello");
1311 // ```
1312 template <size_t N>
1313 constexpr span<const char, N - 1> span_from_cstring(
1314 const char (&lit ABSL_ATTRIBUTE_LIFETIME_BOUND)[N]) {
1315 return span(lit).template first<N - 1>();
1316 }
1317
1318 // Converts a string literal (such as `"hello"`) to a span of `uint8_t` while
1319 // omitting the terminating NUL character. These two are equivalent:
1320 // ```
1321 // base::span<uint8_t, 5u> s1 = base::byte_span_from_cstring("hello");
1322 // base::span<uint8_t, 5u> s2 = base::as_byte_span(std::string_view("hello"));
1323 // ```
1324 //
1325 // If you want to include the NUL terminator, then use the span constructor
1326 // directly, such as:
1327 // ```
1328 // base::span<uint8_t, 6u> s = base::as_bytes(base::span("hello"));
1329 // ```
1330 template <size_t N>
1331 constexpr span<const uint8_t, N - 1> byte_span_from_cstring(
1332 const char (&lit ABSL_ATTRIBUTE_LIFETIME_BOUND)[N]) {
1333 return as_bytes(span(lit).template first<N - 1>());
1334 }
1335
1336 // Convenience function for converting an object which is itself convertible
1337 // to span into a span of bytes (i.e. span of const uint8_t). Typically used
1338 // to convert std::string or string-objects holding chars, or std::vector
1339 // or vector-like objects holding other scalar types, prior to passing them
1340 // into an API that requires byte spans.
1341 template <typename T>
1342 requires requires(const T& arg) {
1343 requires !std::is_array_v<std::remove_reference_t<T>>;
1344 make_span(arg);
1345 }
1346 constexpr span<const uint8_t> as_byte_span(const T& arg) {
1347 return as_bytes(make_span(arg));
1348 }
1349
1350 // This overload for arrays preserves the compile-time size N of the array in
1351 // the span type signature span<uint8_t, N>.
1352 template <typename T, size_t N>
1353 constexpr span<const uint8_t, N * sizeof(T)> as_byte_span(
1354 const T (&arr ABSL_ATTRIBUTE_LIFETIME_BOUND)[N]) {
1355 return as_bytes(make_span<N>(arr));
1356 }
1357
1358 // Convenience function for converting an object which is itself convertible
1359 // to span into a span of mutable bytes (i.e. span of uint8_t). Typically used
1360 // to convert std::string or string-objects holding chars, or std::vector
1361 // or vector-like objects holding other scalar types, prior to passing them
1362 // into an API that requires mutable byte spans.
1363 template <typename T>
1364 requires requires(T&& arg) {
1365 requires !std::is_array_v<std::remove_reference_t<T>>;
1366 make_span(arg);
1367 requires !std::is_const_v<typename decltype(make_span(arg))::element_type>;
1368 }
1369 constexpr span<uint8_t> as_writable_byte_span(T&& arg) {
1370 return as_writable_bytes(make_span(arg));
1371 }
1372
1373 // This overload for arrays preserves the compile-time size N of the array in
1374 // the span type signature span<uint8_t, N>.
1375 template <typename T, size_t N>
1376 requires(!std::is_const_v<T>)
1377 constexpr span<uint8_t, N * sizeof(T)> as_writable_byte_span(
1378 T (&arr ABSL_ATTRIBUTE_LIFETIME_BOUND)[N]) {
1379 return as_writable_bytes(make_span<N>(arr));
1380 }
1381 template <typename T, size_t N>
1382 requires(!std::is_const_v<T>)
1383 constexpr span<uint8_t, N * sizeof(T)> as_writable_byte_span(
1384 T (&&arr ABSL_ATTRIBUTE_LIFETIME_BOUND)[N]) {
1385 return as_writable_bytes(make_span<N>(arr));
1386 }
1387
1388 namespace internal {
1389
1390 // Template helper for implementing operator==.
1391 template <class T, class U, size_t N, size_t M>
1392 requires((N == M || N == dynamic_extent || M == dynamic_extent) &&
1393 std::equality_comparable_with<T, U>)
1394 constexpr bool span_cmp(span<T, N> l, span<U, M> r) {
1395 return l.size() == r.size() && std::equal(l.begin(), l.end(), r.begin());
1396 }
1397
1398 } // namespace internal
1399
1400 } // namespace base
1401
1402 template <typename T, size_t N, typename Ptr>
1403 inline constexpr bool
1404 std::ranges::enable_borrowed_range<base::span<T, N, Ptr>> = true;
1405
1406 template <typename T, size_t N, typename Ptr>
1407 inline constexpr bool std::ranges::enable_view<base::span<T, N, Ptr>> = true;
1408
1409 // EXTENT returns the size of any type that can be converted to a |base::span|
1410 // with definite extent, i.e. everything that is a contiguous storage of some
1411 // sort with static size. Specifically, this works for std::array in a constexpr
1412 // context. Note:
1413 // * |std::size| should be preferred for plain arrays.
1414 // * In run-time contexts, functions such as |std::array::size| should be
1415 // preferred.
1416 #define EXTENT(x) \
1417 ::base::internal::must_not_be_dynamic_extent<decltype(::base::make_span( \
1418 x))::extent>()
1419
1420 #endif // BASE_CONTAINERS_SPAN_H_
1421