// Copyright 2026 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // // ----------------------------------------------------------------------------- // File: any_span.h // ----------------------------------------------------------------------------- // // AnySpan provides a view of a random access container, much like absl::Span // (go/totw/93). See also go/totw/145#gtlanyspan for an introduction of AnySpan. // // The primary differences from absl::Span are: // * AnySpan works with any random access container, whereas Span only works if // elements are contiguous in memory -- both will work with std::vector, but // only AnySpan will work with std::deque. // * AnySpan performs a variety of transformations, such as dereferencing // containers of pointers, or accessing specific members from a collection of // structs, whereas Span does not offer such capability. For example, // AnySpan can handle both std::vector and // std::vector. Safe implicit conversions for a container's // value type (such as up-casting from child classes, or converting // reference_wrapper to const T&) will happen implicitly. // * AnySpan's generality has some small runtime cost, usually only a // conditional branch per element access, or a function-pointer call in the // worst case. Span may be preferable when the inputs are likely to be // contiguous and performance is critical. // // AnySpan is a mutable view to the elements and AnySpan is a // read-only view to the elements, similar to absl::Span. // // AnySpan only requires containers to provide a size() and an operator[] that // returns a reference. It will use data() if it returns a pointer to the type // returned by operator[], which allows it to perform some internal // optimizations (this should apply to many well behaved random access // containers that use arrays internally, but notably // RepeatedPtrField::data() returns T** instead of T*). // // Using AnySpan as an input parameter: // // To write a function that can accept vector, // vector>, or RepeatedPtrField as inputs, you // can use AnySpan as the input to the function. AnySpan should be passed by // value and it is trivially copyable so it does not need to be moved: // // void MyFunction(AnySpan messages); // // You can invoke MyFunction with a vector or deque: // // std::vector messages = ...; // MyFunction(messages); // // Or a container of smart pointers: // // std::deque> message_ptrs = ...; // MyFunction(AnySpan( // message_ptrs, any_span_transform::Deref())); // // Or, you can call the same function with a repeated proto field of type // MyMessage: // // OtherMessage proto_message = ...; // MyFunction(proto_message.repeated_field()); // // // Using AnySpan as an output parameter: // // To write a function that allows mutation of a fixed-size container of // objects, you can use AnySpan with a non-const value type. // // void MyMutatingFunction(AnySpan messages); // // To bind a mutable AnySpan to a container, callers must construct it // explicitly around an lvalue: // // std::vector messages = ...; // MyMutatingFunction(AnySpan(messages)); // // Or use one of the "Make" functions: // // std::vector message_ptrs = ...; // MyMutatingFunction(MakeDerefAnySpan(message_ptrs)); // // Or, if you are already dealing with a mutable view-like object, construction // can usually be implicit: // // absl::Span mutable_span = ...; // MyMutatingFunction(mutable_span); // // Transforming Spans: // // A set of useful transformation functors are provided (see the // any_span_transform namespace), but you can provide your own transforms as // well. // // Transforms work for both mutable and const values. When a transform is used // for a mutable AnySpan, it will usually have to accept its argument as a // mutable reference. // // Transforms can be any object supported by std::invoke, such as // callable objects, function pointers, member function pointers, and even data // members. Invoking a transform must return a reference to T or a reference to // a compatible object such as a std::reference_wrapper or a child class. // Transforms that return value types will not compile and would return // dangling references if they did. // // struct MyStruct { // int member; // } // // std::vector structs = ...; // // // Create an AnySpan that accesses the members of 'structs': // auto mem_ptr = &MyStruct::member; // AnySpan members(structs, mem_ptr); // // // Or, using a lambda: // auto get_member = [](const MyStruct& s) -> const int& { // return s.member; // }; // AnySpan members_from_lambda(structs, get_member); // // Transforms must outlive the spans that use them (even member/method pointers, // but not function pointer). Callable transforms must provide a const call // operator that takes a single argument and returns a reference. Transforms // will be executed every time an element is accessed, so complex transforms may // have significant performance consequences. // // Factory Functions: // // A set of useful functions for constructing common types of AnySpans are // provided. Factories with "Const" in the name produce AnySpans of const // elements. Factories with "Deref" in the name will dereference elements of the // container or array: // // AnySpan MakeAnySpan(Container& c); // AnySpan MakeDerefAnySpan(Container& c); // AnySpan MakeAnySpan(T* ptr, std::size_t size); // AnySpan MakeConstAnySpan(const Container& c); // AnySpan MakeConstDerefAnySpan(const Container& c); // AnySpan MakeConstAnySpan(const T* ptr, std::size_t size); // // Lifetime Gotchas: // // Take care when constructing spans as named variables! AnySpan captures all // arguments by reference, even if it's a pointer: // // AnySpan span(v, &MyClass::SomeMethod); // Dangling reference! // // // Also bad! The lambda is destroyed before the span. // AnySpan span(v, [](U& u) { return SomeFunction(u); }); // // Free functions are ok: // // AnySpan span(v, SomeFunction); // This is OK. // AnySpan span(v, &SomeFunction); // This is OK too. // // In all other cases, you must ensure that the object used as a transform // outlives the span, even if that object is a pointer type. // // AnySpan is also capable of capturing another AnySpan, so watch out for // implicit conversions between types of AnySpans: // // // MakeDerefAnySpan() returns an AnySpan, leaving 's' pointing to // // a temporary! // vector v; // AnySpan s = MakeDerefAnySpan(v); // // Adapting Spans: // // Since AnySpan only expects operator[] and size(), it is relatively simple to // write light-weight adaptor classes that can behave like containers. See the // any_span_adaptor namespace for a utility class that does this for iterators // and views. // // Adapters are more powerful than transforms, since they allow you to change // the value type and element order of a container, but transforms will // generally perform better and leave code with fewer object lifetime concerns. // // // Note about RepeatedPtrField performance: // // AnySpan will use data() when it returns a pointer to the same type returned // by operator[], however RepeatedPtrField's operator[] returns T& and its // data() returns a T**. Because of this, AnySpan will fall back to a less // efficient version of type-erasure. If you have a performance critical use of // RepeatedPtrField, you might find this pattern to have better performance: // // MyFunction(AnySpan( // proto_message.repeated_field().data(), // proto_message.repeated_field().size(), // any_span_transform::Deref())); // #ifndef ABSL_TYPES_ANY_SPAN_H_ #define ABSL_TYPES_ANY_SPAN_H_ #include #include #include #include #include #include #include #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/internal/hardening.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" #include "absl/base/nullability.h" #include "absl/base/optimization.h" #include "absl/base/throw_delegate.h" #include "absl/meta/type_traits.h" #include "absl/types/internal/any_span.h" namespace absl { ABSL_NAMESPACE_BEGIN // The accessors in the 'any_span_transform' namespace return references to // Transform functors that may be passed to AnySpan. Generally you should // prefer to use these functors whenever possible, as they may trigger internal // optimizations that are otherwise not possible, and they are valid for the // duration of the program, so you do not have to worry about their lifetime. namespace any_span_transform { // // Identity() returns a functor that returns whatever is passed to it. Generally // you should prefer to use AnySpan's implicit constructor directly, but this // may be useful if you are writing templates on top of AnySpan. // // Returns a const reference so that callers don't have to worry about // lifetime of the functor. // struct IdentityT { template T& operator()(T& v) const { // NOLINT(runtime/references) return v; } }; inline const IdentityT& Identity() { static const IdentityT f = {}; return f; } struct DerefT { template auto operator()(Ptr& ptr) const // NOLINT(runtime/references) -> decltype(*ptr) { ABSL_RAW_DCHECK(ptr, "Cannot dereference null pointer"); return *ptr; } }; // Deref() returns a functor that dereferences whatever is passed to it. It // works for smart and raw pointers, as well as std::optional. Do not use this // with containers that may contain elements that cannot be dereferenced, such // as null pointers. // // Returns a const reference so that callers don't have to worry about lifetime // of the functor. inline const DerefT& Deref() { static const DerefT f = {}; return f; } } // namespace any_span_transform // Utilities for adapting things to look like the interface that AnySpan // expects. For the most part this is based on iterators and views, and is // intended to be composed with absl/types/iterator_adaptors.h. namespace any_span_adaptor { // Adapts a pair of iterators into a container-like object that AnySpan can // wrap. This is useful if you are faced with a range or view of random access // iterators. Iter must be a valid random access iterator. template class Range { public: static_assert( std::is_same::iterator_category, std::random_access_iterator_tag>::value, "Iter must be a random access iterator."); Range(Iter begin, Iter end) { absl::base_internal::HardeningAssertLE(begin, end); begin_ = begin; end_ = end; } std::size_t size() const { return end_ - begin_; } decltype(std::declval()[0]) operator[](std::size_t i) const { absl::base_internal::HardeningAssertLT(i, size()); return begin_[i]; } private: Iter begin_; Iter end_; }; // Returns a Range adaptor that wraps the given pair of iterators. The return // value of this function must outlive any spans that use it. Iter must be a // valid random access iterator. template Range MakeAdaptorFromRange(Iter begin, Iter end) { return Range(begin, end); } // Returns a Range adaptor that wraps the given view. The begin() and end() // functions of the given view must return valid random access iterators. The // return value of this function must outlive any spans that use it. template auto MakeAdaptorFromView(View& view) // NOLINT(runtime/references) -> Range { return Range(view.begin(), view.end()); } } // namespace any_span_adaptor template class AnySpan; template class ABSL_ATTRIBUTE_VIEW AnySpan { private: template class IteratorBase; template using EnableIfMutable = std::enable_if_t::value, U>; template using EnableIfConst = std::enable_if_t::value, U>; static std::true_type CreatesATemporaryImpl(std::decay_t&&); static std::false_type CreatesATemporaryImpl(const T&); template ()))> struct CreatesATemporary : B {}; // Enable if invoke(transform, element) is valid and if a reference to T can // bind to its output. This prevents situations where the constructor may be // ambiguous. // We also verify that the conversion from TransformResult to T& does not // create a temporary. Otherwise, we would get a false positive in the // enabler where `const char*` looks like can be converted to // `const std::string&`. template (), std::declval()))> using EnableIfTransformIsValid = std::enable_if_t && !CreatesATemporary::value>; // Enable if Container appears to be a valid container. Just checks for size() // and makes sure the class is not an AnySpan for now. template using EnableIfContainer = std::enable_if_t::value && !any_span_internal::IsAnySpan::value>; template using EnableIfDifferentElementType = std::enable_if_t::value && !std::is_same::value>; template using EnableIfTransformIsByCopy = std::enable_if_t, bool>; template using EnableIfTransformIsByRef = std::enable_if_t, bool>; public: using element_type = T; using value_type = typename std::remove_const::type; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using absl_internal_is_view = std::true_type; static const size_type npos = static_cast(-1); // NOLINT using reference = T&; using const_reference = typename std::add_const::type&; using pointer = T*; using const_pointer = typename std::add_const::type*; // Note that iterator will be const if T is const. class iterator; class const_iterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; // Null and empty by default. AnySpan() = default; // Creates a span that wraps an initializer list. This makes it possible to // pass a brace-enclosed initializer list to a function expecting an AnySpan. // // Example: // // void Process(AnySpan x); // Process({1, 2, 3}); // // The initializer_list must outlive this AnySpan. constexpr AnySpan( // NOLINT(google-explicit-constructor) std::initializer_list l ABSL_ATTRIBUTE_LIFETIME_BOUND) : AnySpan(l.begin(), l.size()) {} // Creates a span that wraps an initializer list of a type other than // value_type, or with an explicit transform. Applies the optional transform // to elements before returning them. // // Example: // // struct Base {}; // struct Derived : Base {}; // // void Process(AnySpan x); // Process({Derived(a), Derived(b), Derived(c)}); // // where the default identity transform would apply an implicit // derived-to-base conversion. // // The initializer_list must outlive this AnySpan. template , EnableIfTransformIsByCopy = true> constexpr AnySpan(std::initializer_list l ABSL_ATTRIBUTE_LIFETIME_BOUND, const Transform& transform) : AnySpan(l.begin(), l.size(), transform) {} template , EnableIfTransformIsByRef = true> constexpr AnySpan(std::initializer_list l ABSL_ATTRIBUTE_LIFETIME_BOUND, const Transform& transform ABSL_ATTRIBUTE_LIFETIME_BOUND = any_span_transform::Identity()) : AnySpan(l.begin(), l.size(), transform) {} // Creates a span that wraps an array. Applies the optional transform to // elements before returning them. // // Transform must be a function object with a const operator() that takes // Element as an argument and return a reference to T or compatible object. // // Both the transform and array must outlive this span. template , EnableIfTransformIsByCopy = true> constexpr AnySpan(const Element* absl_nullable ptr ABSL_ATTRIBUTE_LIFETIME_BOUND, size_type size, const Transform& transform) : AnySpan(any_span_internal::MakeArrayGetter(ptr, transform), size) {} template , EnableIfTransformIsByRef = true> constexpr AnySpan(const Element* absl_nullable ptr ABSL_ATTRIBUTE_LIFETIME_BOUND, size_type size, const Transform& transform ABSL_ATTRIBUTE_LIFETIME_BOUND = any_span_transform::Identity()) : AnySpan(any_span_internal::MakeArrayGetter(ptr, transform), size) {} // Creates a span that wraps an array of fixed size. Applies the optional // transform to elements before returning them. // // Transform must be a function object with a const operator() that takes // Element as an argument and return a reference to T or compatible object. // // Both the transform and array must outlive this span. template , EnableIfTransformIsByCopy = true> constexpr AnySpan( // NOLINT(google-explicit-constructor) const Element (&array ABSL_ATTRIBUTE_LIFETIME_BOUND)[N], const Transform& transform) : AnySpan(array, N, transform) {} template , EnableIfTransformIsByRef = true> constexpr AnySpan( // NOLINT(google-explicit-constructor) const Element (&array ABSL_ATTRIBUTE_LIFETIME_BOUND)[N], const Transform& transform ABSL_ATTRIBUTE_LIFETIME_BOUND = any_span_transform::Identity()) : AnySpan(array, N, transform) {} // Creates a span that wraps a const container. Applies the optional transform // to elements before returning them. // // This constructor is enabled even for mutable spans, since some // container-like objects provide mutable element access even when the object // itself is const (such as absl::Span) // // Transform must be a function object with a const operator() that takes the // value type of Container as an argument and return a reference to T or // compatible object. // // The transform, container, and the container's underlying storage must // outlive this span. Any operation that may reallocate the container's // storage or change its size will invalidate the span. template , typename = EnableIfTransformIsValid< Transform, decltype(std::declval()[0])>, EnableIfTransformIsByCopy::value, Transform>> = true> constexpr AnySpan( // NOLINT(google-explicit-constructor) const Container& container, const Transform& transform) : AnySpan(any_span_internal::MakeContainerGetter(container, transform), container.size()) {} template , typename = EnableIfTransformIsValid< Transform, decltype(std::declval()[0])>, EnableIfTransformIsByCopy::value, Transform>> = true> constexpr AnySpan( // NOLINT(google-explicit-constructor) const Container& container ABSL_ATTRIBUTE_LIFETIME_BOUND, const Transform& transform) : AnySpan(any_span_internal::MakeContainerGetter(container, transform), container.size()) {} template < typename Container, typename Transform = any_span_transform::IdentityT, typename = EnableIfContainer, typename = EnableIfTransformIsValid< Transform, decltype(std::declval()[0])>, EnableIfTransformIsByRef< std::enable_if_t::value, Transform>> = true> constexpr AnySpan( // NOLINT(google-explicit-constructor) const Container& container, const Transform& transform ABSL_ATTRIBUTE_LIFETIME_BOUND = any_span_transform::Identity()) : AnySpan(any_span_internal::MakeContainerGetter(container, transform), container.size()) {} template , typename = EnableIfTransformIsValid< Transform, decltype(std::declval()[0])>, EnableIfTransformIsByRef::value, Transform>> = true> constexpr AnySpan( // NOLINT(google-explicit-constructor) const Container& container ABSL_ATTRIBUTE_LIFETIME_BOUND, const Transform& transform ABSL_ATTRIBUTE_LIFETIME_BOUND = any_span_transform::Identity()) : AnySpan(any_span_internal::MakeContainerGetter(container, transform), container.size()) {} // Creates a span that wraps a mutable array. Applies the optional transform // to elements before returning them. // // Transform must be a function object with a const operator() that takes // Element as an argument and return a reference to T or compatible object. // // Both the transform and array must outlive this span. template , typename = EnableIfTransformIsValid, EnableIfTransformIsByCopy = true> constexpr AnySpan(Element* absl_nullable ptr ABSL_ATTRIBUTE_LIFETIME_BOUND, size_type size, const Transform& transform) : AnySpan(any_span_internal::MakeArrayGetter(ptr, transform), size) {} template , typename = EnableIfTransformIsValid, EnableIfTransformIsByRef = true> constexpr AnySpan(Element* absl_nullable ptr ABSL_ATTRIBUTE_LIFETIME_BOUND, size_type size, const Transform& transform ABSL_ATTRIBUTE_LIFETIME_BOUND = any_span_transform::Identity()) : AnySpan(any_span_internal::MakeArrayGetter(ptr, transform), size) {} // Creates a span that wraps a mutable array of fixed size. Applies the // optional transform to elements before returning them. // // Transform must be a function object with a const operator() that takes // Element as an argument and return a reference to T or compatible object. // // Both the transform and array must outlive this span. template , typename = EnableIfTransformIsValid, EnableIfTransformIsByCopy = true> constexpr AnySpan( // NOLINT(google-explicit-constructor) Element (&array ABSL_ATTRIBUTE_LIFETIME_BOUND)[N], const Transform& transform) : AnySpan(array, N, transform) {} template , typename = EnableIfTransformIsValid, EnableIfTransformIsByRef = true> constexpr AnySpan( // NOLINT(google-explicit-constructor) Element (&array ABSL_ATTRIBUTE_LIFETIME_BOUND)[N], const Transform& transform ABSL_ATTRIBUTE_LIFETIME_BOUND = any_span_transform::Identity()) : AnySpan(array, N, transform) {} // Creates a span that wraps a mutable container. Only enabled if T is // mutable. Applies the optional transform to elements before returning them. // // Transform must be a function object with a const operator() that takes the // value type of Container as an argument and return a reference to T or // compatible object. // // The transform, container, and the container's underlying storage must // outlive this span. Any operation that may reallocate the container's // storage or change its size will invalidate the span. template , typename = EnableIfContainer, typename = EnableIfTransformIsValid< Transform, decltype(std::declval()[0])>, EnableIfTransformIsByCopy = true> constexpr explicit AnySpan( // NOLINT(google-explicit-constructor) Container& container ABSL_ATTRIBUTE_LIFETIME_BOUND, const Transform& transform) : AnySpan(any_span_internal::MakeContainerGetter(container, transform), container.size()) {} template , typename = EnableIfContainer, typename = EnableIfTransformIsValid< Transform, decltype(std::declval()[0])>, EnableIfTransformIsByRef = true> constexpr explicit AnySpan( // NOLINT(google-explicit-constructor) Container& container ABSL_ATTRIBUTE_LIFETIME_BOUND, const Transform& transform ABSL_ATTRIBUTE_LIFETIME_BOUND = any_span_transform::Identity()) : AnySpan(any_span_internal::MakeContainerGetter(container, transform), container.size()) {} // Converts a mutable span to a const span by copying the internal state // (rather than wrapping the other span). // TODO(b/179783710): add ABSL_ATTRIBUTE_LIFETIME_BOUND. template > constexpr AnySpan( // NOLINT(google-explicit-constructor) const AnySpan::type>& other) : getter_(other.getter_), size_(other.size()) {} // Creates a span that wraps around another span of different type. // // This has performance and lifetime consequences, and can easily happen by // mistake. We make such conversions explicit here. template , typename = EnableIfTransformIsValid> constexpr explicit AnySpan( const AnySpan& other ABSL_ATTRIBUTE_LIFETIME_BOUND) : AnySpan(any_span_internal::MakeContainerGetter( other, any_span_transform::Identity()), other.size()) {} // Creates a span that wraps around another span. Applies the non-optional // transform to elements before returning them. // // This has lifetime consequences, and may happen by mistake. We make it // explicit here. template , EnableIfTransformIsByCopy = true> constexpr explicit AnySpan(const AnySpan& other ABSL_ATTRIBUTE_LIFETIME_BOUND, const Transform& transform) : AnySpan(any_span_internal::MakeContainerGetter(other, transform), other.size()) {} template , EnableIfTransformIsByRef = true> constexpr explicit AnySpan( const AnySpan& other ABSL_ATTRIBUTE_LIFETIME_BOUND, const Transform& transform ABSL_ATTRIBUTE_LIFETIME_BOUND) : AnySpan(any_span_internal::MakeContainerGetter(other, transform), other.size()) {} // Returns a subspan of this span. This span may become invalid before the // subspan, but both the container and transform must remain valid. // pos must be non-negative and <= size(). // len must be non-negative and <= size() - pos, or equal to npos. // If len == npos, the subspan continues till the end of this span. constexpr AnySpan subspan(size_type pos, size_type len) const { const size_t this_size = size(); if (len == AnySpan::npos) { len = this_size - pos; } absl::base_internal::HardeningAssertLE(pos, this_size); absl::base_internal::HardeningAssertLE(len, static_cast(this_size - pos)); return AnySpan(getter_.Offset(pos), len); } constexpr AnySpan subspan(size_type pos) const { absl::base_internal::HardeningAssertLE(pos, size()); return AnySpan(getter_.Offset(pos), size() - pos); } // Returns a `AnySpan` containing first `len` elements. Parameter `len` // must be non-negative and <= size(). constexpr AnySpan first(size_type len) const { absl::base_internal::HardeningAssert(len != AnySpan::npos); return subspan(0, len); } // Returns a `AnySpan` containing last `len` elements. Parameter `len` must be // non-negative and <= size(). constexpr AnySpan last(size_type len) const { return subspan(size() - len); } // Size operations. constexpr size_type size() const { return size_; } constexpr bool empty() const { return size() == 0; } // Element access. constexpr reference operator[](size_type index) const { absl::base_internal::HardeningAssertLT(index, size()); return getter_.Get(index); } constexpr reference at(size_type index) const { if (ABSL_PREDICT_FALSE(index >= size())) { absl::ThrowStdOutOfRange("AnySpan::at failed bounds check"); } return getter_.Get(index); } constexpr reference front() const { absl::base_internal::HardeningAssertGT(size(), size_type{0}); return (*this)[0]; } constexpr reference back() const { absl::base_internal::HardeningAssertGT(size(), size_type{0}); return (*this)[size() - 1]; } // Iterator accessors. constexpr iterator begin() const { return iterator(this, 0); } constexpr iterator end() const { return iterator(this, size_); } constexpr reverse_iterator rbegin() const { return reverse_iterator(end()); } constexpr reverse_iterator rend() const { return reverse_iterator(begin()); } constexpr const_iterator cbegin() const { return const_iterator(this, 0); } constexpr const_iterator cend() const { return const_iterator(this, size_); } constexpr const_reverse_iterator crbegin() const { return rbegin(); } constexpr const_reverse_iterator crend() const { return rend(); } // Constructs from a getter and size. Not for external use. AnySpan(any_span_internal::Getter getter, size_type size) : getter_(getter), size_(size) {} // Support for absl::Hash. template friend constexpr H AbslHashValue(H state, AnySpan any_span) { for (const auto& v : any_span) { state = H::combine(std::move(state), v); } return H::combine(std::move(state), any_span.size()); } private: template friend class AnySpan; template friend bool any_span_internal::IsCheap(AnySpan s); // Getter to access elements. any_span_internal::Getter getter_; // The size of this span. size_type size_ = 0; #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnon-template-friend" #endif // The technical reasons we need to declare these friends in this manner are // quite subtle and confusing, but they're necessary on some toolchains to // allow all mutable/const combinations with this & other range types while // avoiding symbol collisions or ODR violations. friend bool operator==(AnySpan a, AnySpan b); friend bool operator!=(AnySpan a, AnySpan b); #if defined(__GNUC__) && !defined(__clang__) #pragma GCC diagnostic pop #endif // operator== friend bool operator==(AnySpan a, AnySpan b) { return any_span_internal::EqualImpl(a, b); } friend bool operator!=(AnySpan a, AnySpan b) { return !(a == b); } }; // Constructs an AnySpan from a container or array. template > std::enable_if_t< absl::type_traits_internal::IsView>::value, AnySpan> MakeAnySpan(Container& c) { return AnySpan(c); } template > std::enable_if_t< !absl::type_traits_internal::IsView>::value, AnySpan> MakeAnySpan(Container& c ABSL_ATTRIBUTE_LIFETIME_BOUND) { return AnySpan(c); } // Constructs an AnySpan that dereferences a container or array of pointers. template > std::enable_if_t< absl::type_traits_internal::IsView>::value, AnySpan> MakeDerefAnySpan(Container& c) { return AnySpan(c, any_span_transform::Deref()); } template > std::enable_if_t< !absl::type_traits_internal::IsView>::value, AnySpan> MakeDerefAnySpan(Container& c ABSL_ATTRIBUTE_LIFETIME_BOUND) { return AnySpan(c, any_span_transform::Deref()); } // Constructs an AnySpan from a pointer and size. template AnySpan MakeAnySpan(T* absl_nullable ptr ABSL_ATTRIBUTE_LIFETIME_BOUND, std::size_t size) { return AnySpan(ptr, size); } // Constructs a const AnySpan from a container or array. template > std::enable_if_t::value, AnySpan> MakeConstAnySpan(const Container& c) { return AnySpan(c); } template > std::enable_if_t::value, AnySpan> MakeConstAnySpan(const Container& c ABSL_ATTRIBUTE_LIFETIME_BOUND) { return AnySpan(c); } // Constructs a const AnySpan that dereferences a container or array of // pointers. template > std::enable_if_t::value, AnySpan> MakeConstDerefAnySpan(const Container& c) { return AnySpan(c, any_span_transform::Deref()); } template > std::enable_if_t::value, AnySpan> MakeConstDerefAnySpan(const Container& c ABSL_ATTRIBUTE_LIFETIME_BOUND) { return AnySpan(c, any_span_transform::Deref()); } // Constructs an AnySpan from a pointer and size. template AnySpan MakeConstAnySpan(const T* absl_nullable ptr, std::size_t size) { return AnySpan(ptr, size); } // // Implementation details follow. // template const typename AnySpan::size_type AnySpan::npos; // Iterator base class. Uses CRTP (Iter should be the child class). Constness of // the iterator is determined by the constness of Value. template template class ABSL_ATTRIBUTE_VIEW AnySpan::IteratorBase { private: // Returns a reference to this as the child class. const Iter& self() const { return static_cast(*this); } Iter& self() { return static_cast(*this); } public: using iterator_category = std::random_access_iterator_tag; using value_type = typename std::remove_const::type; using difference_type = std::ptrdiff_t; using reference = Value&; using pointer = Value*; // Constructs an invalid iterator. IteratorBase() = default; reference operator*() const { return (*container_)[index_]; } pointer absl_nonnull operator->() const { return &(*container_)[index_]; } reference operator[](difference_type i) const { return (*container_)[index_ + i]; } Iter& operator+=(difference_type d) { index_ += d; return self(); } Iter& operator-=(difference_type d) { return self() += -d; } Iter& operator++() { self() += 1; return self(); } Iter operator++(int) { Iter copy(self()); ++self(); return copy; } Iter& operator--() { self() -= 1; return self(); } Iter operator--(int) { Iter copy(self()); --self(); return copy; } Iter operator+(difference_type d) const { Iter tmp = self(); tmp += d; return tmp; } friend Iter operator+(difference_type d, Iter i) { return i + d; } Iter operator-(difference_type d) const { return self() + (-d); } difference_type operator-(const Iter& other) const { return index_ - other.index_; } friend bool operator==(const Iter& a, const Iter& b) { return a.index_ == b.index_; } friend bool operator!=(const Iter& a, const Iter& b) { return a.index_ != b.index_; } friend bool operator<(const Iter& a, const Iter& b) { return a.index_ < b.index_; } friend bool operator<=(const Iter& a, const Iter& b) { return a.index_ <= b.index_; } friend bool operator>(const Iter& a, const Iter& b) { return a.index_ > b.index_; } friend bool operator>=(const Iter& a, const Iter& b) { return a.index_ >= b.index_; } protected: // Constructs an iterator that points to the given index of the given span. IteratorBase(const AnySpan* absl_nullable container, size_type index) : container_(container), index_(index) {} const AnySpan* absl_nullable container_ = nullptr; size_type index_ = 0; }; // iterator implementation. This mostly just forwards to IteratorBase. template class ABSL_ATTRIBUTE_VIEW AnySpan::iterator : public IteratorBase { private: using Base = IteratorBase; public: using typename Base::difference_type; using typename Base::iterator_category; using typename Base::pointer; using typename Base::reference; using typename Base::value_type; iterator() = default; private: // Only let AnySpan construct valid instances. friend class AnySpan; iterator(const AnySpan* absl_nullable container, size_type index) : Base(container, index) {} }; // const_iterator implementation. This mostly just forwards to IteratorBase, // but also provides conversion from MutableIterator. template class AnySpan::const_iterator : public IteratorBase::type> { private: using Base = IteratorBase::type>; public: using typename Base::difference_type; using typename Base::iterator_category; using typename Base::pointer; using typename Base::reference; using typename Base::value_type; const_iterator() = default; // Support conversion from mutable iterators. // NOLINTNEXTLINE(google-explicit-constructor) const_iterator(const iterator& other) // NOLINT(runtime/explicit) : Base(other.container_, other.index_) {} private: // Only let AnySpan construct valid instances. friend class AnySpan; const_iterator(const AnySpan* absl_nullable container, size_type index) : Base(container, index) {} }; ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_TYPES_ANY_SPAN_H_