| // Copyright 2024 The PDFium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| // This is Chromium's span.h with the following modificiations: |
| // - namespace changed to pdfium |
| // - include paths changed for check.h, compiler_specific.h, |
| // integral_constant_like.h, and safe_conversions.h. |
| // - include removed for checked_iterators.h, cstring_view.h, to_string.h, |
| // and to_address.h. |
| // - span_forward_internal.h contents inlined in this file. |
| // - iterator types changed from checked iterators to ordinary pointers, |
| // and adjusted begin(), end() |
| // - removed to_address() calls as iterators are now pointers. |
| // - removed operator<<() that pretty-prints to std::stream. |
| // - removed any references to std::string_view. |
| // - removed any references to base::cstring_view<>. |
| // - Added reinterpret_span() helper. |
| // - Added make_span() helper method to ease conversion to CTAD. |
| // - DCHECK() verbose logging message not supported and removed. |
| // - Kept EnableIfSpanCompatibleContainer as in prior versions. |
| |
| // This file intentionally uses the `CHECK()` macro instead of the `CHECK_op()` |
| // macros, as `CHECK()` generates significantly less code and is more likely to |
| // optimize reasonably, even in non-official release builds. Please do not |
| // change the `CHECK()` calls back to `CHECK_op()` calls. |
| |
| #ifndef BASE_CONTAINERS_SPAN_H_ |
| #define BASE_CONTAINERS_SPAN_H_ |
| |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <string.h> |
| |
| #include <algorithm> |
| #include <array> |
| #include <concepts> |
| #include <functional> |
| #include <initializer_list> |
| #include <iosfwd> |
| #include <iterator> |
| #include <limits> |
| #include <memory> |
| #include <optional> |
| #include <ranges> |
| #include <span> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
| |
| #include "core/fxcrt/check.h" |
| #include "core/fxcrt/compiler_specific.h" |
| #include "core/fxcrt/numerics/integral_constant_like.h" |
| #include "core/fxcrt/numerics/safe_conversions.h" |
| |
| // A span is a view of contiguous elements that can be accessed like an array, |
| // intended for use as a parameter or local. Unlike direct use of pointers and |
| // sizes, it enforces safe usage (and simplifies callers); unlike container |
| // refs, it is agnostic to the element container, expressing only "access to |
| // some sequence of elements". It is similar to `std::string_view`, but for |
| // arbitrary elements instead of just characters, and additionally allowing |
| // mutation if the element type is non-`const`. |
| // |
| // Spans can be constructed from arrays, range-like objects (generally, objects |
| // which expose `begin()`, `end()`, `data()`, and `size()`), and initializer |
| // lists. As with all view types, spans do not own the underlying memory, so |
| // users must ensure they do not outlive their backing stores; storing a span as |
| // a member object is usually incorrect. (For the rare case this is useful, |
| // prefer `raw_span<>` so the underlying storage pointer will be protected by |
| // MiraclePtr.) |
| // |
| // Since spans only consist of a pointer and (for dynamic-extent spans) a size, |
| // they are lightweight; constructing and copying spans is cheap and they should |
| // be passed by value. |
| // |
| // Scopes which only need read access to the underlying data should use |
| // `span<const T>`, which can be implicitly constructed from `span<T>`. |
| // Habitually using `span<const T>` also avoids confusing compile errors when |
| // trying to construct spans from compile-time constants or non-borrowed ranges, |
| // which won't convert to `span<T>`. |
| // |
| // Without span: |
| // ``` |
| // /* Read-only usage */ |
| // |
| // // Implementation must avoid OOB reads. |
| // std::string HexEncode(const uint8_t* data, size_t size) { ... } |
| // |
| // // Must use a separate variable to avoid repeated generation calls below. |
| // std::vector<uint8_t> data_buffer = GenerateData(); |
| // // Prone to accidentally passing the wrong size. |
| // std::string r = HexEncode(data_buffer.data(), data_buffer.size()); |
| // |
| // /* Mutable usage */ |
| // |
| // // Same concerns apply in this example. |
| // ssize_t SafeSNPrintf(char* buf, size_t N, const char* fmt, Args...) { ... } |
| // |
| // char str_buffer[100]; |
| // SafeSNPrintf(str_buffer, sizeof(str_buffer), "Pi ~= %lf", 3.14); |
| // ``` |
| // |
| // With span: |
| // ``` |
| // /* Read-only usage */ |
| // |
| // // Automatically `CHECK()`s on attempted OOB accesses. |
| // std::string HexEncode(span<const uint8_t> data) { ... } |
| // |
| // // Can pass return value directly, since it lives until the end of the full |
| // // expression, outlasting the function call. Can't pass wrong size. |
| // std::string r = HexEncode(GenerateData()); |
| // |
| // /* Mutable usage */ |
| // |
| // // Can write to `buf`, but only within bounds. |
| // ssize_t SafeSNPrintf(span<char> buf, const char* fmt, Args...) { ... } |
| // |
| // char str_buffer[100]; |
| // // Automatically infers span size as array size (i.e. 100). |
| // SafeSNPrintf(str_buffer, "Pi ~= %lf", 3.14); |
| // ``` |
| // |
| // Dynamic-extent vs. fixed-extent spans |
| // ------------------------------------- |
| // By default spans have dynamic extent, which means that the size is available |
| // at runtime via `size()`, a la other containers and views. By using a second |
| // template parameter or passing a `std::integral_constant` to the second (size) |
| // constructor arg, a span's extent can be fixed at compile time; this can move |
| // some constraint checks to compile time and slightly improve codegen, at the |
| // cost of verbosity and more template instantiations. Methods like `first()` or |
| // `subspan()` also provide templated overloads that produce fixed-extent spans; |
| // these are preferred when the size is known at compile time, in part because |
| // e.g. `first(1)` is a compile-error (the `int` arg is not compatible with the |
| // `StrictNumeric<size_t>` param; use `first(1u)` instead), but `first<1>()` is |
| // not. |
| // |
| // A fixed-extent span implicitly converts to a dynamic-extent span (e.g. |
| // `span<int, 6>` is implicitly convertible to `span<int>`), so most code that |
| // operates on spans of arbitrary length can just accept a `span<T>`; there is |
| // no need to add an additional overload for specially handling the `span<T, N>` |
| // case. |
| // |
| // There are several ways to go from a dynamic-extent span to a fixed-extent |
| // span: |
| // - Explicit construction of `span<T, N>`, which `CHECK()`s if the size doesn't |
| // match. |
| // - Construction of `span(T*, fixed_extent<N>)`, which is equivalent to the |
| // above. |
| // - `to_fixed_extent<N>()`, which returns `std::nullopt` if the size doesn't |
| // match. |
| // - `first<N>()`, `last<N>()`, and `subspan<Index, N>()`, which `CHECK()` if |
| // the size is insufficient. |
| // |
| // Spans, `const`, and pointer-type element types |
| // ---------------------------------------------- |
| // Pointer-type elements can make translating `const` from container types to |
| // spans confusing. Fundamentally, if you analogize types this way: |
| // `std::vector<T>` => `span<T>` |
| // Then this would be const version: |
| // `const std::vector<T>` => `span<const T>` |
| // (or, more verbosely:) => `span<std::add_const_t<T>>` |
| // |
| // However, note that if `T` is `int*`, then `const T` is `int* const`. So: |
| // `const std::vector<int*>` => `span<int* const>` |
| // `std::vector<const int*>` => `span<const int*>` |
| // `const std::vector<const int*>` => `span<const int* const>` |
| // |
| // (N.B. There is no entry above for `std::vector<int* const>`, since per the |
| // C++ standard, `std::vector`'s element type must be non-const.) |
| // |
| // Byte spans, `std::has_unique_object_representations_v<>`, and conversions |
| // ------------------------------------------------------------------------- |
| // Because byte spans are often used to copy and hash objects, the byte span |
| // conversion functions (e.g. `as_bytes()`, `as_byte_span()`) require the |
| // element type to meet `std::has_unique_object_representations_v<>`. For types |
| // which do not meet this requirement but need conversion to a byte span, there |
| // are two workarounds: |
| // 1. If the type is safe to convert to a byte span in general, specialize |
| // `kCanSafelyConvertToByteSpan<T>` to be true for it. For example, Blink's |
| // `AtomicString` is not trivially copyable, but it is interned, so hashing |
| // and comparing the hashed values is safe. |
| // 2. If the type is not safe in general but is safe for a particular use |
| // case, pass `base::allow_nonunique_obj` as the first arg to the byte span |
| // conversion functions. For example, floating-point values are not unique |
| // (among other reasons, because `+0` and `-0` are distinct but compare |
| // equal), but they are trivially copyable, so serializing them to disk and |
| // then deserializing is OK. |
| // |
| // Spans using `raw_ptr<T>` for internal storage |
| // --------------------------------------------- |
| // Provided via the type alias `raw_span<T[, N]>` (see base/memory/raw_span.h). |
| // Use only for the uncommon case when a span should be a data member of an |
| // object; for locals and params, use `span` (similarly to where you'd use a |
| // `raw_ptr<T>` vs. a `T*`). |
| // |
| // Beware the risk of dangling pointers! The object owning the member span must |
| // not access that span's data after the backing storage's lifetime ends. This |
| // is the same risk as with all spans, but members tend to be longer-lived than |
| // params/locals, and thus more prone to dangerous use. |
| // |
| // Differences from `std::span` |
| // ---------------------------- |
| // https://eel.is/c++draft/views contains the latest C++ draft of `std::span` |
| // and related utilities. Chromium aims to follow the draft except where noted |
| // below; please report other divergences you find. |
| // |
| // Differences from [span.syn]: |
| // - For convenience, provides `fixed_extent<N>` as an alias to |
| // `std::integral_constant<size_t, N>`, to aid in constructing fixed-extent |
| // spans from pointers. |
| // |
| // Differences from [span.overview]: |
| // - `span` takes an optional third template argument that can be used to |
| // customize the underlying storage pointer type. This allows implementing |
| // `raw_span` as a specialization. |
| // |
| // Differences from [span.cons]: |
| // - The constructor which takes an iterator and a count uses |
| // `StrictNumeric<size_type>` instead of `size_type` to prevent unsafe type |
| // conversions. |
| // - Omits constructors from `std::array`, since separating these from the range |
| // constructor is only useful to mark them `noexcept`, and Chromium doesn't |
| // care about that. |
| // - Fixed-extent constructor from range is only `explicit` for ranges whose |
| // extent cannot be statically computed. This matches the spirit of |
| // `std::span`, which handles these (so far as it is aware) via other |
| // overloads. Without this, we would not only need the dedicated constructors |
| // from `std::array`, we would also need dedicated constructors from |
| // fixed-extent `std::span`. |
| // - Adds move construction and assignment. These can avoid refcount churn when |
| // the storage pointer is not `T*`. Not necessary for `std::span` since it |
| // does not allow customizing the storage pointer type. |
| // - Provides implicit conversion in both directions between fixed-extent `span` |
| // and `std::span`. The general-purpose range constructors that would |
| // otherwise handle these cases are explicit for both fixed-extent span types. |
| // - For convenience, provides `span::copy_from[_nonoverlapping]()` as wrappers |
| // around `std::ranges::copy()` that enforce equal-size spans. |
| // - For convenience, provides `span::copy_prefix_from()` to allow copying into |
| // the beginning of the current span. |
| // |
| // Differences from [span.deduct]: |
| // - The deduction guide from a range creates fixed-extent spans if the source |
| // extent is available at compile time. |
| // |
| // Differences from [span.sub]: |
| // - As in [span.cons], `size_t` parameters are changed to |
| // `StrictNumeric<size_type>`. |
| // - There are separate overloads for one-arg and two-arg forms of subspan, |
| // and the two-arg form does not accept dynamic_extent as a count. |
| // - For convenience, provides `span::split_at()` to split a single span into |
| // two at a given offset. |
| // - For convenience, provides `span::take_first[_elem]()` to remove the first |
| // portion of a dynamic-extent span and return it. |
| // |
| // Differences from [span.obs]: |
| // - For convenience, provides `span::operator==()` to check whether two spans |
| // refer to equal-sized ranges of equal objects. This was intentionally |
| // removed from `std::span` because it makes the type non-Regular; see |
| // http://wg21.link/p1085 for details. |
| // - Similarly, provides `span::operator<=>()`, which performs lexicographic |
| // comparison between spans. |
| // |
| // Differences from [span.elem]: |
| // - Because Chromium does not use exceptions, `span::at()` behaves identically |
| // to `span::operator[]()` (i.e. it `CHECK()`s on out-of-range indexes rather |
| // than throwing). |
| // - For convenience, provides `span::get_at()` to return a pointer (rather than |
| // reference) to an element. This is necessary if the backing memory may be |
| // uninitialized, since forming a reference would be UB. |
| // |
| // Differences from [span.objectrep]: |
| // - For convenience, provides `span::to_fixed_extent<N>()` to attempt |
| // conversion to a fixed-extent span, and return null on failure. |
| // - Because Chromium bans `std::byte`, `as_[writable_]bytes()` use `uint8_t` |
| // instead of `std::byte` as the returned element type. |
| // - For convenience, provides `as_[writable_]chars()` and `as_string_view()` |
| // to convert to other "view of bytes"-like objects. |
| // - For convenience, provides an `operator<<()` overload that accepts a span |
| // and prints a byte representation. Also provides a `PrintTo()` overload to |
| // convince GoogleTest to use this operator to print. |
| // - For convenience, provides `[byte_]span_from_ref()` to convert single |
| // (non-range) objects to spans. |
| // - For convenience, provides `[byte_]span_[with_nul_]from_cstring()` to |
| // convert `const char[]` literals to spans. |
| // - For convenience, provides `[byte_]span_with_nul_from_cstring_view()` to |
| // convert `basic_cstring_view<T>` to spans, preserving the null terminator. |
| // - For convenience, provides `as_[writable_]byte_span()` to convert |
| // spanifiable objects directly to byte spans. |
| // - For safety, bans types which do not meet |
| // `std::has_unique_object_representations_v<>` from all byte span conversion |
| // functions by default. See more detailed comments above for workarounds. |
| |
| namespace pdfium { |
| |
| // [span.syn]: Constants |
| inline constexpr size_t dynamic_extent = std::numeric_limits<size_t>::max(); |
| |
| // [views.span]: class template `span<>` |
| template <typename ElementType, |
| size_t Extent = dynamic_extent, |
| // Storage pointer customization. By default this is not a |
| // `raw_ptr<>`, since `span` is mostly used for stack variables. Use |
| // `raw_span` instead for class fields, which sets this to |
| // `raw_ptr<T>`. |
| typename InternalPtrType = ElementType*> |
| class span; |
| |
| // Provides a compile-time fixed extent to the `count` argument of the span |
| // constructor. |
| // |
| // (Not in `std::`.) |
| template <size_t N> |
| using fixed_extent = std::integral_constant<size_t, N>; |
| |
| } // namespace pdfium |
| |
| // Mark `span` as satisfying the `view` and `borrowed_range` concepts. This |
| // should be done before the definition of `span`, so that any inlined calls to |
| // range functionality use the correct specializations. |
| template <typename ElementType, size_t Extent, typename InternalPtrType> |
| inline constexpr bool std::ranges::enable_view< |
| pdfium::span<ElementType, Extent, InternalPtrType>> = true; |
| template <typename ElementType, size_t Extent, typename InternalPtrType> |
| inline constexpr bool std::ranges::enable_borrowed_range< |
| pdfium::span<ElementType, Extent, InternalPtrType>> = true; |
| |
| namespace pdfium { |
| |
| // Allows global use of a type for conversion to byte spans. |
| template <typename T> |
| inline constexpr bool kCanSafelyConvertToByteSpan = |
| std::has_unique_object_representations_v<T>; |
| template <typename T, typename U> |
| inline constexpr bool kCanSafelyConvertToByteSpan<std::pair<T, U>> = |
| kCanSafelyConvertToByteSpan<std::remove_cvref_t<T>> && |
| kCanSafelyConvertToByteSpan<std::remove_cvref_t<U>>; |
| |
| // Type tag to provide to byte span conversion functions to bypass |
| // `std::has_unique_object_representations_v<>` check. |
| struct allow_nonunique_obj_t { |
| explicit allow_nonunique_obj_t() = default; |
| }; |
| inline constexpr allow_nonunique_obj_t allow_nonunique_obj{}; |
| |
| namespace internal { |
| |
| template <typename T> |
| struct IsSpanImpl : std::false_type {}; |
| |
| template <typename T> |
| struct IsSpanImpl<span<T>> : std::true_type {}; |
| |
| template <typename T> |
| using IsSpan = IsSpanImpl<typename std::decay<T>::type>; |
| |
| template <typename T> |
| struct IsStdArrayImpl : std::false_type {}; |
| |
| template <typename T, size_t N> |
| struct IsStdArrayImpl<std::array<T, N>> : std::true_type {}; |
| |
| template <typename T> |
| using IsStdArray = IsStdArrayImpl<typename std::decay<T>::type>; |
| |
| template <typename From, typename To> |
| using IsLegalSpanConversion = std::is_convertible<From*, To*>; |
| |
| template <typename Container, typename T> |
| using ContainerHasConvertibleData = |
| IsLegalSpanConversion<typename std::remove_pointer< |
| decltype(std::declval<Container>().data())>::type, |
| T>; |
| template <typename Container> |
| using ContainerHasIntegralSize = |
| std::is_integral<decltype(std::declval<Container>().size())>; |
| |
| template <typename From, typename To> |
| using EnableIfLegalSpanConversion = |
| typename std::enable_if<IsLegalSpanConversion<From, To>::value>::type; |
| |
| // SFINAE check if Container can be converted to a span<T>. Note that the |
| // implementation details of this check differ slightly from the requirements in |
| // the working group proposal: in particular, the proposal also requires that |
| // the container conversion constructor participate in overload resolution only |
| // if two additional conditions are true: |
| // |
| // 1. Container implements operator[]. |
| // 2. Container::value_type matches remove_const_t<element_type>. |
| // |
| // The requirements are relaxed slightly here: in particular, not requiring (2) |
| // means that an immutable span can be easily constructed from a mutable |
| // container. |
| template <typename Container, typename T> |
| using EnableIfSpanCompatibleContainer = |
| typename std::enable_if<!internal::IsSpan<Container>::value && |
| !internal::IsStdArray<Container>::value && |
| ContainerHasConvertibleData<Container, T>::value && |
| ContainerHasIntegralSize<Container>::value>::type; |
| |
| template <typename Container, typename T> |
| using EnableIfConstSpanCompatibleContainer = |
| typename std::enable_if<std::is_const<T>::value && |
| !internal::IsSpan<Container>::value && |
| !internal::IsStdArray<Container>::value && |
| ContainerHasConvertibleData<Container, T>::value && |
| ContainerHasIntegralSize<Container>::value>::type; |
| |
| // Exposition-only concept from [span.syn] |
| template <typename T> |
| inline constexpr size_t MaybeStaticExt = dynamic_extent; |
| template <typename T> |
| requires IntegralConstantLike<T> |
| inline constexpr size_t MaybeStaticExt<T> = {T::value}; |
| |
| template <typename From, typename To> |
| concept LegalDataConversion = std::is_convertible_v<From (*)[], To (*)[]>; |
| |
| // Akin to `std::constructible_from<span, T>`, but meant to be used in a |
| // type-deducing context where we don't know what args would be deduced; |
| // `std::constructible_from` can't be directly used in such a case since the |
| // type parameters must be fully-specified (e.g. `span<int>`), requiring us to |
| // have that knowledge already. |
| template <typename T> |
| concept SpanConstructibleFrom = requires(T&& t) { span(std::forward<T>(t)); }; |
| |
| // Returns the element type of `span(T)`. |
| template <typename T> |
| requires SpanConstructibleFrom<T> |
| using ElementTypeOfSpanConstructedFrom = |
| typename decltype(span(std::declval<T>()))::element_type; |
| |
| template <typename T, typename It> |
| concept CompatibleIter = |
| std::contiguous_iterator<It> && |
| LegalDataConversion<std::remove_reference_t<std::iter_reference_t<It>>, T>; |
| |
| // True when `T` is a `span`. |
| template <typename T> |
| inline constexpr bool kIsSpan = false; |
| template <typename ElementType, size_t Extent, typename InternalPtrType> |
| inline constexpr bool kIsSpan<span<ElementType, Extent, InternalPtrType>> = |
| true; |
| |
| template <typename T, typename R> |
| concept CompatibleRange = |
| std::ranges::contiguous_range<R> && std::ranges::sized_range<R> && |
| (std::ranges::borrowed_range<R> || (std::is_const_v<T>)) && |
| // `span`s should go through the copy constructor. |
| (!kIsSpan<std::remove_cvref_t<R>> && |
| // Arrays should go through the array constructors. |
| (!std::is_array_v<std::remove_cvref_t<R>>)) && |
| LegalDataConversion< |
| std::remove_reference_t<std::ranges::range_reference_t<R>>, |
| T>; |
| |
| // Whether source object extent `X` will work to create a span of fixed extent |
| // `N`. This is not intended for use in dynamic-extent spans. |
| template <size_t N, size_t X> |
| concept FixedExtentConstructibleFromExtent = X == N || X == dynamic_extent; |
| |
| // Computes a fixed extent if possible from a source container type `T`. |
| template <typename T> |
| inline constexpr size_t kComputedExtentImpl = dynamic_extent; |
| template <typename T> |
| requires requires { std::tuple_size<T>(); } |
| inline constexpr size_t kComputedExtentImpl<T> = std::tuple_size_v<T>; |
| template <typename T, size_t N> |
| inline constexpr size_t kComputedExtentImpl<T[N]> = N; |
| template <typename T, size_t N> |
| inline constexpr size_t kComputedExtentImpl<std::span<T, N>> = N; |
| template <typename T, size_t N, typename InternalPtrType> |
| inline constexpr size_t kComputedExtentImpl<span<T, N, InternalPtrType>> = N; |
| template <typename T> |
| inline constexpr size_t kComputedExtent = |
| kComputedExtentImpl<std::remove_cvref_t<T>>; |
| |
| template <typename T> |
| concept CanSafelyConvertToByteSpan = |
| kCanSafelyConvertToByteSpan<std::remove_cvref_t<T>>; |
| |
| template <typename T> |
| concept ByteSpanConstructibleFrom = |
| SpanConstructibleFrom<T> && |
| CanSafelyConvertToByteSpan<ElementTypeOfSpanConstructedFrom<T>>; |
| |
| // Allows one-off use of a type that wouldn't normally convert to a byte span. |
| template <typename T> |
| concept CanSafelyConvertNonUniqueToByteSpan = |
| // Non-trivially-copyable elements usually aren't safe even to serialize; |
| // when they are that's normally unconditionally true and can be handled |
| // using `kCanSafelyConvertToByteSpan`. |
| std::is_trivially_copyable_v<T> && |
| // If this fails, `allow_nonunique_obj` wasn't necessary. |
| !std::has_unique_object_representations_v<T>; |
| |
| template <typename T> |
| concept ByteSpanConstructibleFromNonUnique = |
| SpanConstructibleFrom<T> && |
| CanSafelyConvertNonUniqueToByteSpan<ElementTypeOfSpanConstructedFrom<T>>; |
| |
| template <typename ByteType, |
| typename ElementType, |
| size_t Extent, |
| typename InternalPtrType> |
| requires((std::same_as<std::remove_const_t<ByteType>, char> || |
| std::same_as<std::remove_const_t<ByteType>, unsigned char>) && |
| (std::is_const_v<ByteType> || !std::is_const_v<ElementType>)) |
| constexpr auto as_byte_span( |
| span<ElementType, Extent, InternalPtrType> s) noexcept { |
| constexpr size_t kByteExtent = |
| Extent == dynamic_extent ? dynamic_extent : sizeof(ElementType) * Extent; |
| // SAFETY: `s.data()` points to at least `s.size_bytes()` bytes' worth of |
| // valid elements, so the size computed below must only contain valid |
| // elements. Since `ByteType` is an alias to a character type, it has a size |
| // of 1 byte, the resulting pointer has no alignment concerns, and it is not |
| // UB to access memory contents inside the allocation through it. |
| return UNSAFE_BUFFERS(span<ByteType, kByteExtent>( |
| reinterpret_cast<ByteType*>(s.data()), s.size_bytes())); |
| } |
| |
| } // namespace internal |
| |
| // [span]: class `span` (non-dynamic `Extent`s) |
| template <typename ElementType, size_t Extent, typename InternalPtrType> |
| class GSL_POINTER span { |
| public: |
| using element_type = ElementType; |
| using value_type = std::remove_cv_t<element_type>; |
| using size_type = size_t; |
| using difference_type = ptrdiff_t; |
| using pointer = element_type*; |
| using const_pointer = const element_type*; |
| using reference = element_type&; |
| using const_reference = const element_type&; |
| using iterator = element_type*; |
| using const_iterator = const element_type*; |
| using reverse_iterator = std::reverse_iterator<iterator>; |
| // TODO(C++23): When `std::const_iterator<>` is available, switch to |
| // `std::const_iterator<reverse_iterator>` as the standard specifies. |
| using const_reverse_iterator = std::reverse_iterator<const_iterator>; |
| static constexpr size_type extent = Extent; |
| |
| // [span.cons]: Constructors, copy, and assignment |
| // Default constructor. |
| constexpr span() noexcept |
| requires(extent == 0) |
| = default; |
| |
| // Iterator + count. |
| template <typename It> |
| requires(internal::CompatibleIter<element_type, It>) |
| // SAFETY: `first` must point to the first of at least `count` contiguous |
| // valid elements, or the span will allow access to invalid elements, |
| // resulting in UB. |
| UNSAFE_BUFFER_USAGE constexpr explicit span(It first, |
| StrictNumeric<size_type> count) |
| : data_(first) { |
| CHECK(size_type{count} == extent); |
| |
| // Non-zero `count` implies non-null `data_`. Use `SpanOrSize<T>` to |
| // represent a size that might not be accompanied by the actual data. |
| DCHECK(count == 0 || !!data_); |
| } |
| |
| // Iterator + sentinel. |
| template <typename It, typename End> |
| requires(internal::CompatibleIter<element_type, It> && |
| std::sized_sentinel_for<End, It> && |
| !std::is_convertible_v<End, size_t>) |
| // SAFETY: `first` and `last` must be for the same allocation and all elements |
| // in the range [first, last) must be valid, or the span will allow access to |
| // invalid elements, resulting in UB. |
| UNSAFE_BUFFER_USAGE constexpr explicit span(It first, End last) |
| // SAFETY: The caller must guarantee that `first` and `last` point into |
| // the same allocation. In this case, the extent will be the number of |
| // elements between the iterators and thus a valid size for the pointer to |
| // the element at `first`. |
| // |
| // It is safe to check for underflow after subtraction because the |
| // underflow itself is not UB and `size_` is not converted to an invalid |
| // pointer (which would be UB) before the check. |
| : UNSAFE_BUFFERS(span(first, static_cast<size_type>(last - first))) { |
| // Verify `last - first` did not underflow. |
| CHECK(first <= last); |
| } |
| |
| // Array of size `extent`. |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| constexpr span( |
| std::type_identity_t<element_type> (&arr LIFETIME_BOUND)[extent]) noexcept |
| // SAFETY: The type signature guarantees `arr` contains `extent` elements. |
| : UNSAFE_BUFFERS(span(arr, extent)) {} |
| |
| // Range. |
| template <typename R, size_t N = internal::kComputedExtent<R>> |
| requires(internal::CompatibleRange<element_type, R> && |
| internal::FixedExtentConstructibleFromExtent<extent, N>) |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| constexpr explicit(N != extent) span(R&& range LIFETIME_BOUND) |
| // SAFETY: `std::ranges::size()` returns the number of elements |
| // `std::ranges::data()` will point to, so accessing those elements will |
| // be safe. |
| : UNSAFE_BUFFERS( |
| span(std::ranges::data(range), std::ranges::size(range))) {} |
| template <typename R, size_t N = internal::kComputedExtent<R>> |
| requires(internal::CompatibleRange<element_type, R> && |
| internal::FixedExtentConstructibleFromExtent<extent, N> && |
| std::ranges::borrowed_range<R>) |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| constexpr explicit span(R&& range) |
| // SAFETY: `std::ranges::size()` returns the number of elements |
| // `std::ranges::data()` will point to, so accessing those elements will |
| // be safe. |
| : UNSAFE_BUFFERS( |
| span(std::ranges::data(range), std::ranges::size(range))) {} |
| |
| // Initializer list. |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| constexpr explicit span(std::initializer_list<value_type> il LIFETIME_BOUND) |
| requires(std::is_const_v<element_type>) |
| // SAFETY: `size()` is exactly the number of elements in the initializer |
| // list, so accessing that many will be safe. |
| : UNSAFE_BUFFERS(span(il.begin(), il.size())) {} |
| |
| // Copy and move. |
| constexpr span(const span& other) noexcept = default; |
| template <typename OtherElementType, |
| size_t OtherExtent, |
| typename OtherInternalPtrType> |
| requires((OtherExtent == dynamic_extent || extent == OtherExtent) && |
| internal::LegalDataConversion<OtherElementType, element_type>) |
| constexpr explicit(OtherExtent == dynamic_extent) |
| span(const span<OtherElementType, OtherExtent, OtherInternalPtrType>& |
| other) noexcept |
| // SAFETY: `size()` is the number of elements that can be safely accessed |
| // at `data()`. |
| : UNSAFE_BUFFERS(span(other.data(), other.size())) {} |
| constexpr span(span&& other) noexcept = default; |
| |
| // Copy and move assignment. |
| constexpr span& operator=(const span& other) noexcept = default; |
| constexpr span& operator=(span&& other) noexcept = default; |
| |
| // Performs a deep copy of the elements referenced by `other` to those |
| // referenced by `this`. The spans must be the same size. |
| // |
| // If it's known the spans can not overlap, `copy_from_nonoverlapping()` |
| // provides an unsafe alternative that avoids intermediate copies. |
| // |
| // (Not in `std::`; inspired by Rust's `slice::copy_from_slice()`.) |
| constexpr void copy_from(span<const element_type, extent> other) |
| requires(!std::is_const_v<element_type>) |
| { |
| if (std::is_constant_evaluated()) { |
| // Comparing pointers to different objects at compile time yields |
| // unspecified behavior, which would halt compilation. Instead, |
| // unconditionally use a separate buffer in the constexpr context. This |
| // would be inefficient at runtime, but that's irrelevant. |
| std::vector<element_type> vec(other.begin(), other.end()); |
| std::ranges::copy(vec, begin()); |
| } else { |
| // Using `<=` to compare pointers to different allocations is UB, but |
| // using `std::less_equal` is well-defined ([comparisons.general]). |
| if (std::less_equal{}(begin(), other.begin())) { |
| std::ranges::copy(other, begin()); |
| } else { |
| std::ranges::copy_backward(other, end()); |
| } |
| } |
| } |
| template <typename R, size_t N = internal::kComputedExtent<R>> |
| requires(!std::is_const_v<element_type> && |
| // Fixed-extent ranges should implicitly convert to use the |
| // overload above; if they don't, it's because the extent doesn't |
| // match. Rejecting this here improves the resulting errors. |
| N == dynamic_extent && |
| std::convertible_to<R &&, span<const element_type>>) |
| constexpr void copy_from(R&& other) { |
| // Note: The constructor `CHECK()`s that a dynamic-extent `other` has the |
| // right size. |
| copy_from(span<const element_type, extent>(std::forward<R>(other))); |
| } |
| |
| // Like `copy_from()`, but may be more performant; however, the caller must |
| // guarantee the spans do not overlap, or this will invoke UB. |
| // |
| // (Not in `std::`; inspired by Rust's `slice::copy_from_slice()`.) |
| constexpr void copy_from_nonoverlapping( |
| span<const element_type, extent> other) |
| requires(!std::is_const_v<element_type>) |
| { |
| // Comparing pointers to different objects at compile time yields |
| // unspecified behavior, which would halt compilation. Instead implement in |
| // terms of the guaranteed-safe behavior; performance is irrelevant in the |
| // constexpr context. |
| if (std::is_constant_evaluated()) { |
| copy_from(other); |
| return; |
| } |
| |
| // See comments in `copy_from()` re: use of templated comparison objects. |
| DCHECK(std::less_equal{}(end(), other.begin()) || |
| std::greater_equal{}(begin(), other.end())); |
| std::ranges::copy(other, begin()); |
| } |
| template <typename R, size_t N = internal::kComputedExtent<R>> |
| requires(!std::is_const_v<element_type> && N == dynamic_extent && |
| std::convertible_to<R &&, span<const element_type>>) |
| constexpr void copy_from_nonoverlapping(R&& other) { |
| // Note: The constructor `CHECK()`s that a dynamic-extent `other` has the |
| // right size. |
| copy_from_nonoverlapping( |
| span<const element_type, extent>(std::forward<R>(other))); |
| } |
| |
| // Like `copy_from()`, but allows the source to be smaller than this span, and |
| // will only copy as far as the source size, leaving the remaining elements of |
| // this span unwritten. |
| // |
| // (Not in `std::`; allows caller code to elide repeated size information and |
| // makes it easier to preserve fixed-extent spans in the process.) |
| template <typename R, size_t N = internal::kComputedExtent<R>> |
| requires(!std::is_const_v<element_type> && |
| (N <= extent || N == dynamic_extent) && |
| std::convertible_to<R &&, span<const element_type>>) |
| constexpr void copy_prefix_from(R&& other) { |
| if constexpr (N == dynamic_extent) { |
| return first(other.size()).copy_from(other); |
| } else { |
| return first<N>().copy_from(other); |
| } |
| } |
| |
| // Implicit conversion to fixed-extent `std::span<>`. (The fixed-extent |
| // `std::span` range constructor is explicit.) |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| operator std::span<element_type, extent>() const { |
| return std::span<element_type, extent>(*this); |
| } |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| operator std::span<const element_type, extent>() const |
| requires(!std::is_const_v<element_type>) |
| { |
| return std::span<const element_type, extent>(*this); |
| } |
| |
| // [span.sub]: Subviews |
| // First `count` elements. |
| template <size_t Count> |
| constexpr auto first() const |
| requires(Count <= extent) |
| { |
| // SAFETY: `data()` points to at least `extent` elements, so the new data |
| // scope is a strict subset of the old. |
| return UNSAFE_BUFFERS(span<element_type, Count>(data(), Count)); |
| } |
| constexpr auto first(StrictNumeric<size_type> count) const { |
| CHECK(size_type{count} <= extent); |
| // SAFETY: `data()` points to at least `extent` elements, so the new data |
| // scope is a strict subset of the old. |
| return UNSAFE_BUFFERS(span<element_type>(data(), count)); |
| } |
| |
| // Last `count` elements. |
| template <size_t Count> |
| constexpr auto last() const |
| requires(Count <= extent) |
| { |
| // SAFETY: `data()` points to at least `extent` elements, so the new data |
| // scope is a strict subset of the old. |
| return UNSAFE_BUFFERS( |
| span<element_type, Count>(data() + (extent - Count), Count)); |
| } |
| constexpr auto last(StrictNumeric<size_type> count) const { |
| CHECK(size_type{count} <= extent); |
| // SAFETY: `data()` points to at least `extent` elements, so the new data |
| // scope is a strict subset of the old. |
| return UNSAFE_BUFFERS( |
| span<element_type>(data() + (extent - size_type{count}), count)); |
| } |
| |
| // `count` elements beginning at `offset`. |
| template <size_t Offset, size_t Count = dynamic_extent> |
| constexpr auto subspan() const |
| requires(Offset <= extent && |
| (Count == dynamic_extent || Count <= extent - Offset)) |
| { |
| if constexpr (Count == dynamic_extent) { |
| constexpr size_t kRemaining = extent - Offset; |
| // SAFETY: `data()` points to at least `extent` elements, so `Offset` |
| // specifies a valid element index or the past-the-end index, and |
| // `kRemaining` cannot index past-the-end elements. |
| return UNSAFE_BUFFERS( |
| span<element_type, kRemaining>(data() + Offset, kRemaining)); |
| } else { |
| // SAFETY: `data()` points to at least `extent` elements, so `Offset` |
| // specifies a valid element index or the past-the-end index, and `Count` |
| // is no larger than the number of remaining valid elements. |
| return UNSAFE_BUFFERS(span<element_type, Count>(data() + Offset, Count)); |
| } |
| } |
| constexpr auto subspan(StrictNumeric<size_type> offset) const { |
| CHECK(size_type{offset} <= extent); |
| const size_type remaining = extent - size_type{offset}; |
| // SAFETY: `data()` points to at least `extent` elements, so `offset` |
| // specifies a valid element index or the past-the-end index, and |
| // `remaining` cannot index past-the-end elements. |
| return UNSAFE_BUFFERS( |
| span<element_type>(data() + size_type{offset}, remaining)); |
| } |
| constexpr auto subspan(StrictNumeric<size_type> offset, |
| StrictNumeric<size_type> count) const { |
| // PDFium does not allow dynamic_extent in two-arg subspan() |
| DCHECK(size_type{count} != dynamic_extent); |
| // Deliberately combine tests to minimize code size. |
| CHECK(size_type{offset} <= size() && |
| size_type{count} <= size() - size_type{offset}); |
| // SAFETY: `data()` points to at least `extent` elements, so `offset` |
| // specifies a valid element index or the past-the-end index, and `count` is |
| // no larger than the number of remaining valid elements. |
| return UNSAFE_BUFFERS( |
| span<element_type>(data() + size_type{offset}, count)); |
| } |
| |
| // Splits a span a given offset, returning a pair of spans that cover the |
| // ranges strictly before the offset and starting at the offset, respectively. |
| // |
| // (Not in `std::span`; inspired by Rust's `slice::split_at()` and |
| // `split_at_mut()`.) |
| template <size_t Offset> |
| requires(Offset <= extent) |
| constexpr auto split_at() const { |
| return std::pair(first<Offset>(), subspan<Offset, extent - Offset>()); |
| } |
| constexpr auto split_at(StrictNumeric<size_type> offset) const { |
| return std::pair(first(offset), subspan(offset)); |
| } |
| |
| // [span.obs]: Observers |
| // Size. |
| constexpr size_type size() const noexcept { return extent; } |
| constexpr size_type size_bytes() const noexcept { |
| return extent * sizeof(element_type); |
| } |
| |
| // Empty. |
| [[nodiscard]] constexpr bool empty() const noexcept { return extent == 0; } |
| |
| // Returns true if `lhs` and `rhs` are equal-sized and are per-element equal. |
| // |
| // (Not in `std::span`; improves both ergonomics and safety.) |
| // |
| // NOTE: Using non-members here intentionally allows comparing types that |
| // implicitly convert to `span`. |
| friend constexpr bool operator==(span lhs, span rhs) |
| requires(std::is_const_v<element_type> && |
| std::equality_comparable<const element_type>) |
| { |
| return std::ranges::equal(span<const element_type, extent>(lhs), |
| span<const element_type, extent>(rhs)); |
| } |
| friend constexpr bool operator==(span lhs, |
| span<const element_type, extent> rhs) |
| requires(!std::is_const_v<element_type> && |
| std::equality_comparable<const element_type>) |
| { |
| return std::ranges::equal(span<const element_type, extent>(lhs), rhs); |
| } |
| template <typename OtherElementType, |
| size_t OtherExtent, |
| typename OtherInternalPtrType> |
| requires((OtherExtent == dynamic_extent || extent == OtherExtent) && |
| std::equality_comparable_with<const element_type, |
| const OtherElementType>) |
| friend constexpr bool operator==( |
| span lhs, |
| span<OtherElementType, OtherExtent, OtherInternalPtrType> rhs) { |
| return std::ranges::equal(span<const element_type, extent>(lhs), |
| span<const OtherElementType, OtherExtent>(rhs)); |
| } |
| |
| // Performs lexicographical comparison of `lhs` and `rhs`. |
| // |
| // (Not in `std::span`; improves both ergonomics and safety.) |
| // |
| // NOTE: Using non-members here intentionally allows comparing types that |
| // implicitly convert to `span`. |
| friend constexpr auto operator<=>(span lhs, span rhs) |
| requires(std::is_const_v<element_type> && |
| std::three_way_comparable<const element_type>) |
| { |
| const auto const_lhs = span<const element_type>(lhs); |
| const auto const_rhs = span<const element_type>(rhs); |
| return std::lexicographical_compare_three_way( |
| const_lhs.begin(), const_lhs.end(), const_rhs.begin(), const_rhs.end()); |
| } |
| friend constexpr auto operator<=>(span lhs, |
| span<const element_type, extent> rhs) |
| requires(!std::is_const_v<element_type> && |
| std::three_way_comparable<const element_type>) |
| { |
| return span<const element_type>(lhs) <=> rhs; |
| } |
| template <typename OtherElementType, |
| size_t OtherExtent, |
| typename OtherInternalPtrType> |
| requires((OtherExtent == dynamic_extent || extent == OtherExtent) && |
| std::three_way_comparable_with<const element_type, |
| const OtherElementType>) |
| friend constexpr auto operator<=>( |
| span lhs, |
| span<OtherElementType, OtherExtent, OtherInternalPtrType> rhs) { |
| const auto const_lhs = span<const element_type>(lhs); |
| const auto const_rhs = span<const OtherElementType, OtherExtent>(rhs); |
| return std::lexicographical_compare_three_way( |
| const_lhs.begin(), const_lhs.end(), const_rhs.begin(), const_rhs.end()); |
| } |
| |
| // [span.elem]: Element access |
| // Reference to specific element. |
| // When `idx` is outside the span, the underlying call will `CHECK()`. |
| // |
| // Intentionally does not take `StrictNumeric<size_t>`, unlike all other APIs. |
| // There are far too many false positives on integer literals (e.g. `s[0]`), |
| // and while `ENABLE_IF_ATTR` can be used to work around those for Clang, that |
| // would leave the gcc build broken. The consequence of not upgrading this is |
| // that some errors will only be detected at runtime instead of compile time. |
| constexpr reference operator[](size_type idx) const |
| requires(extent > 0) |
| { |
| return at(idx); |
| } |
| // When `idx` is outside the span, the underlying call will `CHECK()`. |
| constexpr reference at(StrictNumeric<size_type> idx) const |
| requires(extent > 0) |
| { |
| return *get_at(idx); |
| } |
| |
| // Returns a pointer to an element in the span. |
| // |
| // (Not in `std::`; necessary when underlying memory is not yet initialized.) |
| constexpr pointer get_at(StrictNumeric<size_type> idx) const |
| requires(extent > 0) |
| { |
| CHECK(size_type{idx} < extent); |
| // SAFETY: `data()` points to at least `extent` elements, so `idx` must be |
| // the index of a valid element. |
| return UNSAFE_BUFFERS(data() + size_type{idx}); |
| } |
| |
| // Reference to first/last elements. |
| // When `empty()`, the underlying call will `CHECK()`. |
| constexpr reference front() const |
| requires(extent > 0) |
| { |
| return operator[](0); |
| } |
| // When `empty()`, the underlying call will `CHECK()`. |
| constexpr reference back() const |
| requires(extent > 0) |
| { |
| return operator[](size() - 1); |
| } |
| |
| // Underlying memory. |
| constexpr pointer data() const noexcept { return data_; } |
| |
| // [span.iter]: Iterator support |
| // Forward iterators. |
| constexpr iterator begin() const noexcept { return iterator(data()); } |
| constexpr const_iterator cbegin() const noexcept { |
| return const_iterator(begin()); |
| } |
| constexpr iterator end() const noexcept { |
| // SAFETY: `data()` points to at least `extent` elements, so `data() + |
| // extent` is no larger than just past the end of the corresponding |
| // allocation, which is a legal pointer to construct and compare to (though |
| // not dereference). |
| return UNSAFE_BUFFERS(iterator(data() + extent)); |
| } |
| constexpr const_iterator cend() const noexcept { |
| return const_iterator(end()); |
| } |
| |
| // Reverse iterators. |
| constexpr reverse_iterator rbegin() const noexcept { |
| return reverse_iterator(end()); |
| } |
| constexpr const_reverse_iterator crbegin() const noexcept { |
| return const_iterator(rbegin()); |
| } |
| constexpr reverse_iterator rend() const noexcept { |
| return reverse_iterator(begin()); |
| } |
| constexpr const_reverse_iterator crend() const noexcept { |
| return const_iterator(rend()); |
| } |
| |
| private: |
| InternalPtrType data_ = nullptr; |
| }; |
| |
| // [span]: class <span> (dynamic `Extent`) |
| template <typename ElementType, typename InternalPtrType> |
| class GSL_POINTER span<ElementType, dynamic_extent, InternalPtrType> { |
| public: |
| using element_type = ElementType; |
| using value_type = std::remove_cv_t<element_type>; |
| using size_type = size_t; |
| using difference_type = ptrdiff_t; |
| using pointer = element_type*; |
| using const_pointer = const element_type*; |
| using reference = element_type&; |
| using const_reference = const element_type&; |
| using iterator = element_type*; |
| using const_iterator = const element_type*; |
| using reverse_iterator = std::reverse_iterator<iterator>; |
| // TODO(C++23): When `std::const_iterator<>` is available, switch to |
| // `std::const_iterator<reverse_iterator>` as the standard specifies. |
| using const_reverse_iterator = std::reverse_iterator<const_iterator>; |
| static constexpr size_type extent = dynamic_extent; |
| |
| // [span.cons]: Constructors, copy, and assignment |
| // Default constructor. |
| constexpr span() noexcept = default; |
| |
| // Iterator + count. |
| template <typename It> |
| requires(internal::CompatibleIter<element_type, It>) |
| // SAFETY: `first` must point to the first of at least `count` contiguous |
| // valid elements, or the span will allow access to invalid elements, |
| // resulting in UB. |
| UNSAFE_BUFFER_USAGE constexpr span(It first, StrictNumeric<size_type> count) |
| : data_(first), size_(count) { |
| // Non-zero `count` implies non-null `data_`. Use `SpanOrSize<T>` to |
| // represent a size that might not be accompanied by the actual data. |
| DCHECK(count == 0 || !!data_); |
| } |
| |
| // Iterator + sentinel. |
| template <typename It, typename End> |
| requires(internal::CompatibleIter<element_type, It> && |
| std::sized_sentinel_for<End, It> && |
| !std::is_convertible_v<End, size_t>) |
| // SAFETY: `first` and `last` must be for the same allocation and all elements |
| // in the range [first, last) must be valid, or the span will allow access to |
| // invalid elements, resulting in UB. |
| UNSAFE_BUFFER_USAGE constexpr span(It first, End last) |
| // SAFETY: The caller must guarantee that `first` and `last` point into |
| // the same allocation. In this case, `size_` will be the number of |
| // elements between the iterators and thus a valid size for the pointer to |
| // the element at `first`. |
| // |
| // It is safe to check for underflow after subtraction because the |
| // underflow itself is not UB and `size_` is not converted to an invalid |
| // pointer (which would be UB) before the check. |
| : UNSAFE_BUFFERS(span(first, static_cast<size_type>(last - first))) { |
| // Verify `last - first` did not underflow. |
| CHECK(first <= last); |
| } |
| |
| // Array of size N. |
| template <size_t N> |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| constexpr span( |
| std::type_identity_t<element_type> (&arr LIFETIME_BOUND)[N]) noexcept |
| // SAFETY: The type signature guarantees `arr` contains `N` elements. |
| : UNSAFE_BUFFERS(span(arr, N)) {} |
| |
| // Range. |
| template <typename R> |
| requires(internal::CompatibleRange<element_type, R>) |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| constexpr span(R&& range LIFETIME_BOUND) |
| // SAFETY: `std::ranges::size()` returns the number of elements |
| // `std::ranges::data()` will point to, so accessing those elements will |
| // be safe. |
| : UNSAFE_BUFFERS( |
| span(std::ranges::data(range), std::ranges::size(range))) {} |
| template <typename R> |
| requires(internal::CompatibleRange<element_type, R> && |
| std::ranges::borrowed_range<R>) |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| constexpr span(R&& range) |
| // SAFETY: `std::ranges::size()` returns the number of elements |
| // `std::ranges::data()` will point to, so accessing those elements will |
| // be safe. |
| : UNSAFE_BUFFERS( |
| span(std::ranges::data(range), std::ranges::size(range))) {} |
| |
| // Initializer list. |
| constexpr span(std::initializer_list<value_type> il LIFETIME_BOUND) |
| requires(std::is_const_v<element_type>) |
| // SAFETY: `size()` is exactly the number of elements in the initializer |
| // list, so accessing that many will be safe. |
| : UNSAFE_BUFFERS(span(il.begin(), il.size())) {} |
| |
| // Copy and move. |
| constexpr span(const span& other) noexcept = default; |
| template <typename OtherElementType, |
| size_t OtherExtent, |
| typename OtherInternalPtrType> |
| requires(internal::LegalDataConversion<OtherElementType, element_type>) |
| // NOLINTNEXTLINE(google-explicit-constructor) |
| constexpr span( |
| const span<OtherElementType, OtherExtent, OtherInternalPtrType>& |
| other) noexcept |
| : data_(other.data()), size_(other.size()) {} |
| constexpr span(span&& other) noexcept = default; |
| |
| // Copy and move assignment. |
| constexpr span& operator=(const span& other) noexcept = default; |
| constexpr span& operator=(span&& other) noexcept = default; |
| |
| // Performs a deep copy of the elements referenced by `other` to those |
| // referenced by `this`. The spans must be the same size. |
| // |
| // If it's known the spans can not overlap, `copy_from_nonoverlapping()` |
| // provides an unsafe alternative that avoids intermediate copies. |
| // |
| // (Not in `std::`; inspired by Rust's `slice::copy_from_slice()`.) |
| constexpr void copy_from(span<const element_type> other) |
| requires(!std::is_const_v<element_type>) |
| { |
| CHECK(size() == other.size()); |
| if (std::is_constant_evaluated()) { |
| // Comparing pointers to different objects at compile time yields |
| // unspecified behavior, which would halt compilation. Instead, |
| // unconditionally use a separate buffer in the constexpr context. This |
| // would be inefficient at runtime, but that's irrelevant. |
| std::vector<element_type> vec(other.begin(), other.end()); |
| std::ranges::copy(vec, begin()); |
| } else { |
| // Using `<=` to compare pointers to different allocations is UB, but |
| // using `std::less_equal` is well-defined ([comparisons.general]). |
| if (std::less_equal{}(begin(), other.begin())) { |
| std::ranges::copy(other, begin()); |
| } else { |
| std::ranges::copy_backward(other, end()); |
| } |
| } |
| } |
| |
| // Like `copy_from()`, but may be more performant; however, the caller must |
| // guarantee the spans do not overlap, or this will invoke UB. |
| // |
| // (Not in `std::`; inspired by Rust's `slice::copy_from_slice()`.) |
| constexpr void copy_from_nonoverlapping(span<const element_type> other) |
| requires(!std::is_const_v<element_type>) |
| { |
| // Comparing pointers to different objects at compile time yields |
| // unspecified behavior, which would halt compilation. Instead implement in |
| // terms of the guaranteed-safe behavior; performance is irrelevant in the |
| // constexpr context. |
| if (std::is_constant_evaluated()) { |
| copy_from(other); |
| return; |
| } |
| |
| CHECK(size() == other.size()); |
| // See comments in `copy_from()` re: use of templated comparison objects. |
| DCHECK(std::less_equal{}(end(), other.begin()) || |
| std::greater_equal{}(begin(), other.end())); |
| std::ranges::copy(other, begin()); |
| } |
| |
| // Like `copy_from()`, but allows the source to be smaller than this span, and |
| // will only copy as far as the source size, leaving the remaining elements of |
| // this span unwritten. |
| // |
| // (Not in `std::`; allows caller code to elide repeated size information and |
| // makes it easier to preserve fixed-extent spans in the process.) |
| constexpr void copy_prefix_from(span<const element_type> other) |
| requires(!std::is_const_v<element_type>) |
| { |
| return first(other.size()).copy_from(other); |
| } |
| |
| // [span.sub]: Subviews |
| // First `count` elements. |
| template <size_t Count> |
| constexpr auto first() const { |
| CHECK(Count <= size()); |
| // SAFETY: `data()` points to at least `size()` elements, so the new data |
| // scope is a strict subset of the old. |
| return UNSAFE_BUFFERS(span<element_type, Count>(data(), Count)); |
| } |
| constexpr auto first(StrictNumeric<size_t> count) const { |
| CHECK(size_type{count} <= size()); |
| // SAFETY: `data()` points to at least `size()` elements, so the new data |
| // scope is a strict subset of the old. |
| return UNSAFE_BUFFERS(span<element_type>(data(), count)); |
| } |
| |
| // Last `count` elements. |
| template <size_t Count> |
| constexpr auto last() const { |
| CHECK(Count <= size()); |
| // SAFETY: `data()` points to at least `size()` elements, so the new data |
| // scope is a strict subset of the old. |
| return UNSAFE_BUFFERS( |
| span<element_type, Count>(data() + (size() - Count), Count)); |
| } |
| constexpr auto last(StrictNumeric<size_type> count) const { |
| CHECK(size_type{count} <= size()); |
| // SAFETY: `data()` points to at least `size()` elements, so the new data |
| // scope is a strict subset of the old. |
| return UNSAFE_BUFFERS( |
| span<element_type>(data() + (size() - size_type{count}), count)); |
| } |
| |
| // `count` elements beginning at `offset`. |
| template <size_t Offset, size_t Count = dynamic_extent> |
| constexpr auto subspan() const { |
| CHECK(Offset <= size()); |
| const size_type remaining = size() - Offset; |
| if constexpr (Count == dynamic_extent) { |
| // SAFETY: `data()` points to at least `size()` elements, so `Offset` |
| // specifies a valid element index or the past-the-end index, and |
| // `remaining` cannot index past-the-end elements. |
| return UNSAFE_BUFFERS( |
| span<element_type, Count>(data() + Offset, remaining)); |
| } |
| CHECK(Count <= remaining); |
| // SAFETY: `data()` points to at least `size()` elements, so `Offset` |
| // specifies a valid element index or the past-the-end index, and `Count` is |
| // no larger than the number of remaining valid elements. |
| return UNSAFE_BUFFERS(span<element_type, Count>(data() + Offset, Count)); |
| } |
| constexpr auto subspan(StrictNumeric<size_type> offset) const { |
| CHECK(size_type{offset} <= size()); |
| const size_type remaining = size() - size_type{offset}; |
| // SAFETY: `data()` points to at least `size()` elements, so `offset` |
| // specifies a valid element index or the past-the-end index, and |
| // `remaining` cannot index past-the-end elements. |
| return UNSAFE_BUFFERS( |
| span<element_type>(data() + size_type{offset}, remaining)); |
| } |
| constexpr auto subspan(StrictNumeric<size_type> offset, |
| StrictNumeric<size_type> count) const { |
| // PDFium does not allow dynamic_extent in two-arg subspan() |
| DCHECK(size_type{count} != dynamic_extent); |
| // Deliberately combine tests to minimize code size. |
| CHECK(size_type{offset} <= size() && |
| size_type{count} <= size() - size_type{offset}); |
| // SAFETY: `data()` points to at least `size()` elements, so `offset` |
| // specifies a valid element index or the past-the-end index, and `count` is |
| // no larger than the number of remaining valid elements. |
| return UNSAFE_BUFFERS( |
| span<element_type>(data() + size_type{offset}, count)); |
| } |
| |
| // Splits a span a given offset, returning a pair of spans that cover the |
| // ranges strictly before the offset and starting at the offset, respectively. |
| // |
| // (Not in `std::span`; inspired by Rust's `slice::split_at()` and |
| // `split_at_mut()`.) |
| template <size_t Offset> |
| constexpr auto split_at() const { |
| CHECK(Offset <= size()); |
| return std::pair(first<Offset>(), subspan<Offset>()); |
| } |
| constexpr auto split_at(StrictNumeric<size_type> offset) const { |
| return std::pair(first(offset), subspan(offset)); |
| } |
| |
| // Returns a span of the first N elements, removing them. |
| // When `Offset` is outside the span, the underlying call will `CHECK()`. For |
| // a non-fatal alternative, consider `SpanReader`. |
| // |
| // (Not in `std::span`; convenient for processing a stream of disparate |
| // objects or looping over elements.) |
| template <size_t Offset> |
| constexpr auto take_first() { |
| const auto [first, rest] = split_at<Offset>(); |
| *this = rest; |
| return first; |
| } |
| // When `offset` is outside the span, the underlying call will `CHECK()`. |
| constexpr auto take_first(StrictNumeric<size_type> offset) { |
| const auto [first, rest] = split_at(offset); |
| *this = rest; |
| return first; |
| } |
| |
| // Returns the first element, removing it. |
| // When `empty()`, the underlying call will `CHECK()`. For a non-fatal |
| // alternative, consider `SpanReader`. |
| // |
| // (Not in `std::span`; convenient for processing a stream of disparate |
| // objects or looping over elements.) |
| constexpr auto take_first_elem() { return take_first<1>().front(); } |
| |
| // [span.obs]: Observers |
| // Size. |
| constexpr size_type size() const noexcept { return size_; } |
| constexpr size_type size_bytes() const noexcept { |
| return size() * sizeof(element_type); |
| } |
| |
| // Empty. |
| [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } |
| |
| // Returns true if `lhs` and `rhs` are equal-sized and are per-element equal. |
| // |
| // (Not in `std::span`; improves both ergonomics and safety.) |
| // |
| // NOTE: Using non-members here intentionally allows comparing types that |
| // implicitly convert to `span`. |
| friend constexpr bool operator==(span lhs, span rhs) |
| requires(std::is_const_v<element_type> && |
| std::equality_comparable<const element_type>) |
| { |
| return std::ranges::equal(span<const element_type>(lhs), |
| span<const element_type>(rhs)); |
| } |
| friend constexpr bool operator==(span lhs, |
| span<const element_type, extent> rhs) |
| requires(!std::is_const_v<element_type> && |
| std::equality_comparable<const element_type>) |
| { |
| return std::ranges::equal(span<const element_type>(lhs), rhs); |
| } |
| template <typename OtherElementType, |
| size_t OtherExtent, |
| typename OtherInternalPtrType> |
| requires(std::equality_comparable_with<const element_type, |
| const OtherElementType>) |
| friend constexpr bool operator==( |
| span lhs, |
| span<OtherElementType, OtherExtent, OtherInternalPtrType> rhs) { |
| return std::ranges::equal(span<const element_type>(lhs), |
| span<const OtherElementType, OtherExtent>(rhs)); |
| } |
| |
| // Performs lexicographical comparison of `lhs` and `rhs`. |
| // |
| // (Not in `std::span`; improves both ergonomics and safety.) |
| // |
| // NOTE: Using non-members here intentionally allows comparing types that |
| // implicitly convert to `span`. |
| friend constexpr auto operator<=>(span lhs, span rhs) |
| requires(std::is_const_v<element_type> && |
| std::three_way_comparable<const element_type>) |
| { |
| const auto const_lhs = span<const element_type>(lhs); |
| const auto const_rhs = span<const element_type>(rhs); |
| return std::lexicographical_compare_three_way( |
| const_lhs.begin(), const_lhs.end(), const_rhs.begin(), const_rhs.end()); |
| } |
| friend constexpr auto operator<=>(span lhs, |
| span<const element_type, extent> rhs) |
| requires(!std::is_const_v<element_type> && |
| std::three_way_comparable<const element_type>) |
| { |
| return span<const element_type>(lhs) <=> rhs; |
| } |
| template <typename OtherElementType, |
| size_t OtherExtent, |
| typename OtherInternalPtrType> |
| requires(std::three_way_comparable_with<const element_type, |
| const OtherElementType>) |
| friend constexpr auto operator<=>( |
| span lhs, |
| span<OtherElementType, OtherExtent, OtherInternalPtrType> rhs) { |
| const auto const_lhs = span<const element_type>(lhs); |
| const auto const_rhs = span<const OtherElementType, OtherExtent>(rhs); |
| return std::lexicographical_compare_three_way( |
| const_lhs.begin(), const_lhs.end(), const_rhs.begin(), const_rhs.end()); |
| } |
| |
| // [span.elem]: Element access |
| // Reference to a specific element. |
| // When `idx` is outside the span, the underlying call will `CHECK()`. |
| // |
| // Intentionally does not take `StrictNumeric<size_type>`; see comments on |
| // fixed-extent version for rationale. |
| constexpr reference operator[](size_type idx) const { return at(idx); } |
| |
| // When `idx` is outside the span, the underlying call will `CHECK()`. |
| constexpr reference at(StrictNumeric<size_type> idx) const { |
| return *get_at(idx); |
| } |
| |
| // Returns a pointer to an element in the span. |
| // |
| // (Not in `std::`; necessary when underlying memory is not yet initialized.) |
| constexpr pointer get_at(StrictNumeric<size_type> idx) const { |
| CHECK(size_type{idx} < size()); |
| // SAFETY: `data()` points to at least `size()` elements, so `idx` must be |
| // the index of a valid element. |
| return UNSAFE_BUFFERS(data() + size_type{idx}); |
| } |
| |
| // Reference to first/last elements. |
| // When `empty()`, the underlying call will `CHECK()`. |
| constexpr reference front() const { return operator[](0); } |
| // When `empty()`, the underlying call will `CHECK()`. |
| constexpr reference back() const { return operator[](size() - 1); } |
| |
| // Underlying memory. |
| constexpr pointer data() const noexcept { return data_; } |
| |
| // [span.iter]: Iterator support |
| // Forward iterators. |
| constexpr iterator begin() const noexcept { return iterator(data()); } |
| constexpr const_iterator cbegin() const noexcept { |
| return const_iterator(begin()); |
| } |
| constexpr iterator end() const noexcept { |
| // SAFETY: `data()` points to at least `size()` elements, so `data() + |
| // size()` is no larger than just past the end of the corresponding |
| // allocation, which is a legal pointer to construct and compare to (though |
| // not dereference). |
| return UNSAFE_BUFFERS(data() + size()); |
| } |
| constexpr const_iterator cend() const noexcept { |
| return const_iterator(end()); |
| } |
| |
| // Reverse iterators. |
| constexpr reverse_iterator rbegin() const noexcept { |
| return reverse_iterator(end()); |
| } |
| constexpr const_reverse_iterator crbegin() const noexcept { |
| return const_iterator(rbegin()); |
| } |
| constexpr reverse_iterator rend() const noexcept { |
| return reverse_iterator(begin()); |
| } |
| constexpr const_reverse_iterator crend() const noexcept { |
| return const_iterator(rend()); |
| } |
| |
| // [span.objectrep]: Views of object representation |
| // Converts a dynamic-extent span to a fixed-extent span. Returns a |
| // `span<element_type, Extent>` iff `size() == Extent`; otherwise, returns |
| // `std::nullopt`. |
| // |
| // (Not in `std::`; provides a conditional conversion path.) |
| template <size_t Extent> |
| constexpr std::optional<span<element_type, Extent>> to_fixed_extent() const { |
| return size() == Extent ? std::optional(span<element_type, Extent>(*this)) |
| : std::nullopt; |
| } |
| |
| private: |
| InternalPtrType data_ = nullptr; |
| size_t size_ = 0; |
| }; |
| |
| // [span.deduct]: Deduction guides |
| template <typename It, typename EndOrSize> |
| requires(std::contiguous_iterator<It>) |
| span(It, EndOrSize) -> span<std::remove_reference_t<std::iter_reference_t<It>>, |
| internal::MaybeStaticExt<EndOrSize>>; |
| |
| template <typename T, size_t N> |
| span(T (&)[N]) -> span<T, N>; |
| |
| template <typename R> |
| requires(std::ranges::contiguous_range<R>) |
| span(R&&) -> span<std::remove_reference_t<std::ranges::range_reference_t<R>>, |
| internal::kComputedExtent<R>>; |
| |
| // [span.objectrep]: Views of object representation |
| template <typename ElementType, size_t Extent, typename InternalPtrType> |
| requires(internal::CanSafelyConvertToByteSpan<ElementType>) |
| constexpr auto as_bytes(span<ElementType, Extent, InternalPtrType> s) { |
| return internal::as_byte_span<const uint8_t>(s); |
| } |
| template <typename ElementType, size_t Extent, typename InternalPtrType> |
| requires(internal::CanSafelyConvertNonUniqueToByteSpan<ElementType>) |
| constexpr auto as_bytes(allow_nonunique_obj_t, |
| span<ElementType, Extent, InternalPtrType> s) { |
| return internal::as_byte_span<const uint8_t>(s); |
| } |
| template <typename ElementType, size_t Extent, typename InternalPtrType> |
| requires(internal::CanSafelyConvertToByteSpan<ElementType> && |
| !std::is_const_v<ElementType>) |
| constexpr auto as_writable_bytes(span<ElementType, Extent, InternalPtrType> s) { |
| return internal::as_byte_span<uint8_t>(s); |
| } |
| template <typename ElementType, size_t Extent, typename InternalPtrType> |
| requires(internal::CanSafelyConvertNonUniqueToByteSpan<ElementType> && |
| !std::is_const_v<ElementType>) |
| constexpr auto as_writable_bytes(allow_nonunique_obj_t, |
| span<ElementType, Extent, InternalPtrType> s) { |
| return internal::as_byte_span<uint8_t>(s); |
| } |
| |
| // Like `as_[writable_]bytes()`, but uses `[const] char` rather than `[const] |
| // uint8_t`. |
| // |
| // (Not in `std::`; eases span adoption in Chromium, which uses `char` in many |
| // cases that rightfully should be `uint8_t`.) |
| template <typename ElementType, size_t Extent, typename InternalPtrType> |
| requires(internal::CanSafelyConvertToByteSpan<ElementType>) |
| constexpr auto as_chars(span<ElementType, Extent, InternalPtrType> s) { |
| return internal::as_byte_span<const char>(s); |
| } |
| template <typename ElementType, size_t Extent, typename InternalPtrType> |
| requires(internal::CanSafelyConvertNonUniqueToByteSpan<ElementType>) |
| constexpr auto as_chars(allow_nonunique_obj_t, |
| span<ElementType, Extent, InternalPtrType> s) { |
| return internal::as_byte_span<const char>(s); |
| } |
| template <typename ElementType, size_t Extent, typename InternalPtrType> |
| requires(internal::CanSafelyConvertToByteSpan<ElementType> && |
| !std::is_const_v<ElementType>) |
| constexpr auto as_writable_chars(span<ElementType, Extent, InternalPtrType> s) { |
| return internal::as_byte_span<char>(s); |
| } |
| template <typename ElementType, size_t Extent, typename InternalPtrType> |
| requires(internal::CanSafelyConvertNonUniqueToByteSpan<ElementType> && |
| !std::is_const_v<ElementType>) |
| constexpr auto as_writable_chars(allow_nonunique_obj_t, |
| span<ElementType, Extent, InternalPtrType> s) { |
| return internal::as_byte_span<char>(s); |
| } |
| |
| // Converts a `T&` to a `span<T, 1>`. |
| // |
| // (Not in `std::`; inspired by Rust's `slice::from_ref()`.) |
| template <typename T> |
| constexpr auto span_from_ref(const T& t LIFETIME_BOUND) { |
| // SAFETY: It's safe to read the memory at `t`'s address as long as the |
| // provided reference is valid. |
| return UNSAFE_BUFFERS(span<const T, 1>(std::addressof(t), 1u)); |
| } |
| template <typename T> |
| constexpr auto span_from_ref(T& t LIFETIME_BOUND) { |
| // SAFETY: It's safe to read the memory at `t`'s address as long as the |
| // provided reference is valid. |
| return UNSAFE_BUFFERS(span<T, 1>(std::addressof(t), 1u)); |
| } |
| |
| // Converts a `T&` to a `span<[const] uint8_t, sizeof(T)>`. |
| // |
| // (Not in `std::`.) |
| template <typename T> |
| requires(internal::CanSafelyConvertToByteSpan<T>) |
| constexpr auto byte_span_from_ref(const T& t LIFETIME_BOUND) { |
| return as_bytes(span_from_ref(t)); |
| } |
| template <typename T> |
| requires(internal::CanSafelyConvertNonUniqueToByteSpan<T>) |
| constexpr auto byte_span_from_ref(allow_nonunique_obj_t, |
| const T& t LIFETIME_BOUND) { |
| return as_bytes(allow_nonunique_obj, span_from_ref(t)); |
| } |
| template <typename T> |
| requires(internal::CanSafelyConvertToByteSpan<T>) |
| constexpr auto byte_span_from_ref(T& t LIFETIME_BOUND) { |
| return as_writable_bytes(span_from_ref(t)); |
| } |
| template <typename T> |
| requires(internal::CanSafelyConvertNonUniqueToByteSpan<T>) |
| constexpr auto byte_span_from_ref(allow_nonunique_obj_t, T& t LIFETIME_BOUND) { |
| return as_writable_bytes(allow_nonunique_obj, span_from_ref(t)); |
| } |
| |
| // Converts a `const CharT[]` literal to a `span<const CharT>`, omitting the |
| // trailing '\0' (internal '\0's, if any, are preserved). For comparison: |
| // `span("hi")` => `span<const char, 3>({'h', 'i', '\0'})` |
| // `span(std::string_view("hi")) => `span<const char>({'h', 'i'})` |
| // `span_from_cstring("hi")` => `span<const char, 2>({'h', 'i'})` |
| // |
| // (Not in `std::`; useful when reading and writing character subsequences in |
| // larger files.) |
| template <typename CharT, size_t Extent> |
| constexpr auto span_from_cstring(const CharT (&str LIFETIME_BOUND)[Extent]) |
| ENABLE_IF_ATTR(str[Extent - 1u] == CharT{0}, |
| "requires string literal as input") { |
| return span(str).template first<Extent - 1>(); |
| } |
| |
| // Converts a `const CharT[]` literal to a `span<const CharT>`, preserving the |
| // trailing '\0'. |
| // |
| // (Not in `std::`; identical to constructor behavior, but more explicit.) |
| template <typename CharT, size_t Extent> |
| constexpr auto span_with_nul_from_cstring( |
| const CharT (&str LIFETIME_BOUND)[Extent]) |
| ENABLE_IF_ATTR(str[Extent - 1u] == CharT{0}, |
| "requires string literal as input") { |
| return span(str); |
| } |
| |
| // Converts an object which can already explicitly convert to some kind of span |
| // directly into a byte span. |
| // |
| // (Not in `std::`.) |
| template <int&... ExplicitArgumentBarrier, typename T> |
| requires(internal::ByteSpanConstructibleFrom<const T&>) |
| constexpr auto as_byte_span(const T& t LIFETIME_BOUND) { |
| return as_bytes(span(t)); |
| } |
| template <int&... ExplicitArgumentBarrier, typename T> |
| requires(internal::ByteSpanConstructibleFromNonUnique<const T&>) |
| constexpr auto as_byte_span(allow_nonunique_obj_t, const T& t LIFETIME_BOUND) { |
| return as_bytes(allow_nonunique_obj, span(t)); |
| } |
| template <int&... ExplicitArgumentBarrier, typename T> |
| requires(internal::ByteSpanConstructibleFrom<const T&> && |
| std::ranges::borrowed_range<T>) |
| constexpr auto as_byte_span(const T& t) { |
| return as_bytes(span(t)); |
| } |
| template <int&... ExplicitArgumentBarrier, typename T> |
| requires(internal::ByteSpanConstructibleFromNonUnique<const T&> && |
| std::ranges::borrowed_range<T>) |
| constexpr auto as_byte_span(allow_nonunique_obj_t, const T& t) { |
| return as_bytes(allow_nonunique_obj, span(t)); |
| } |
| // Array arguments require dedicated specializations because if only the |
| // generalized functions are available, the compiler cannot deduce the template |
| // parameter. |
| template <int&... ExplicitArgumentBarrier, typename ElementType, size_t Extent> |
| requires(internal::CanSafelyConvertToByteSpan<ElementType>) |
| constexpr auto as_byte_span(const ElementType (&arr LIFETIME_BOUND)[Extent]) { |
| return as_bytes(span<const ElementType, Extent>(arr)); |
| } |
| template <int&... ExplicitArgumentBarrier, typename ElementType, size_t Extent> |
| requires(internal::CanSafelyConvertNonUniqueToByteSpan<ElementType>) |
| constexpr auto as_byte_span(allow_nonunique_obj_t, |
| const ElementType (&arr LIFETIME_BOUND)[Extent]) { |
| return as_bytes(allow_nonunique_obj, span<const ElementType, Extent>(arr)); |
| } |
| template <int&... ExplicitArgumentBarrier, typename T> |
| requires(internal::ByteSpanConstructibleFrom<T &&> && |
| !std::is_const_v<internal::ElementTypeOfSpanConstructedFrom<T>>) |
| // NOTE: `t` is not marked as lifetimebound because the "non-const |
| // `element_type`" requirement above will in turn require `T` to be a borrowed |
| // range. |
| constexpr auto as_writable_byte_span(T&& t) { |
| return as_writable_bytes(span(t)); |
| } |
| template <int&... ExplicitArgumentBarrier, typename T> |
| requires(internal::ByteSpanConstructibleFromNonUnique<T &&> && |
| !std::is_const_v<internal::ElementTypeOfSpanConstructedFrom<T>>) |
| constexpr auto as_writable_byte_span(allow_nonunique_obj_t, T&& t) { |
| return as_writable_bytes(allow_nonunique_obj, span(t)); |
| } |
| template <int&... ExplicitArgumentBarrier, typename ElementType, size_t Extent> |
| requires(internal::CanSafelyConvertToByteSpan<ElementType> && |
| !std::is_const_v<ElementType>) |
| constexpr auto as_writable_byte_span( |
| ElementType (&arr LIFETIME_BOUND)[Extent]) { |
| return as_writable_bytes(span<ElementType, Extent>(arr)); |
| } |
| template <int&... ExplicitArgumentBarrier, typename ElementType, size_t Extent> |
| requires(internal::CanSafelyConvertNonUniqueToByteSpan<ElementType> && |
| !std::is_const_v<ElementType>) |
| constexpr auto as_writable_byte_span( |
| allow_nonunique_obj_t, |
| ElementType (&arr LIFETIME_BOUND)[Extent]) { |
| return as_writable_bytes(allow_nonunique_obj, span<ElementType, Extent>(arr)); |
| } |
| |
| // Type-deducing helpers for constructing a span. |
| template <typename T> |
| UNSAFE_BUFFER_USAGE constexpr span<T> make_span(T* data, size_t size) noexcept { |
| return UNSAFE_BUFFERS(span<T>(data, size)); |
| } |
| |
| template <typename T, size_t N> |
| constexpr span<T> make_span(T (&array)[N]) noexcept { |
| return span<T>(array); |
| } |
| |
| template <typename T, size_t N> |
| constexpr span<T> make_span(std::array<T, N>& array) noexcept { |
| return span<T>(array); |
| } |
| |
| template <typename T, size_t N> |
| constexpr span<const T> make_span(const std::array<T, N>& array) noexcept { |
| return span<const T>(const_cast<std::array<T, N>&>(array)); |
| } |
| |
| template <typename Container, |
| typename T = typename Container::value_type, |
| typename = internal::EnableIfSpanCompatibleContainer<Container, T>> |
| constexpr span<T> make_span(Container& container) { |
| return span<T>(container); |
| } |
| |
| template < |
| typename Container, |
| typename T = typename std::add_const<typename Container::value_type>::type, |
| typename = internal::EnableIfConstSpanCompatibleContainer<Container, T>> |
| constexpr span<T> make_span(const Container& container) { |
| return span<T>(container); |
| } |
| |
| } // namespace pdfium |
| |
| #endif // BASE_CONTAINERS_SPAN_H_ |