• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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