]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - libstdc++-v3/include/std/span
Update copyright years.
[thirdparty/gcc.git] / libstdc++-v3 / include / std / span
index 1a0d61c194772e3e9ced0137efe0605afca10ff4..43e9cf82a546764d2c71517331137b2218955fad 100644 (file)
@@ -1,6 +1,6 @@
 // Components for manipulating non-owning sequences of objects -*- C++ -*-
 
-// Copyright (C) 2019 Free Software Foundation, Inc.
+// Copyright (C) 2019-2024 Free Software Foundation, Inc.
 //
 // This file is part of the GNU ISO C++ Library.  This library is free
 // software; you can redistribute it and/or modify it under the
 
 #pragma GCC system_header
 
-#if __cplusplus > 201703L
+#define __glibcxx_want_span
+#include <bits/version.h>
 
-#include <type_traits>
-#include <tuple>
-#include <utility>
+#ifdef __cpp_lib_span // C++ >= 20 && concepts
 #include <array>
+#include <cstddef>
 #include <bits/stl_iterator.h>
-#include <bits/range_access.h>
-
+#include <bits/ranges_base.h>
 namespace std _GLIBCXX_VISIBILITY(default)
 {
 _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
-#define __cpp_lib_span 201902L
-
   inline constexpr size_t dynamic_extent = static_cast<size_t>(-1);
 
   template<typename _Type, size_t _Extent>
@@ -59,21 +56,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
   namespace __detail
   {
     template<typename _Tp>
-      struct __is_std_span : false_type { };
+      inline constexpr bool __is_span = false;
 
     template<typename _Tp, size_t _Num>
-      struct __is_std_span<span<_Tp, _Num>> : true_type { };
+      inline constexpr bool __is_span<span<_Tp, _Num>> = true;
 
     template<typename _Tp>
-      struct __is_std_array : false_type { };
+      inline constexpr bool __is_std_array = false;
 
     template<typename _Tp, size_t _Num>
-      struct __is_std_array<_GLIBCXX_STD_C::array<_Tp, _Num>> : true_type { };
-
-#ifdef _GLIBCXX_DEBUG
-    template<typename _Tp, size_t _Num>
-      struct __is_std_array<__debug::array<_Tp, _Num>> : true_type { };
-#endif
+      inline constexpr bool __is_std_array<std::array<_Tp, _Num>> = true;
 
     template<size_t _Extent>
       class __extent_storage
@@ -104,7 +96,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       private:
        size_t _M_extent_value;
       };
-
   } // namespace __detail
 
   template<typename _Type, size_t _Extent = dynamic_extent>
@@ -122,282 +113,243 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            return dynamic_extent;
        }
 
-      template<typename _Tp>
-       using __is_compatible = is_convertible<_Tp(*)[], _Type(*)[]>;
+      // _GLIBCXX_RESOLVE_LIB_DEFECTS
+      // 3255. span's array constructor is too strict
+      template<typename _Tp, size_t _ArrayExtent>
+       requires (_Extent == dynamic_extent || _ArrayExtent == _Extent)
+       using __is_compatible_array = __is_array_convertible<_Type, _Tp>;
+
+      template<typename _Ref>
+       using __is_compatible_ref
+         = __is_array_convertible<_Type, remove_reference_t<_Ref>>;
 
     public:
       // member types
-      using value_type             = remove_cv_t<_Type>;
       using element_type           = _Type;
-      using index_type             = size_t;
-      using reference              = element_type&;
-      using const_reference        = const element_type&;
+      using value_type             = remove_cv_t<_Type>;
+      using size_type              = size_t;
+      using difference_type        = ptrdiff_t;
       using pointer                = _Type*;
       using const_pointer          = const _Type*;
-      using iterator
-       = __gnu_cxx::__normal_iterator<pointer, span>;
-      using const_iterator
-       = __gnu_cxx::__normal_iterator<const_pointer, span>;
+      using reference              = element_type&;
+      using const_reference        = const element_type&;
+      using iterator = __gnu_cxx::__normal_iterator<pointer, span>;
       using reverse_iterator       = std::reverse_iterator<iterator>;
-      using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-      using difference_type        = ptrdiff_t;
-      // Official wording has no size_type -- why??
-      // using size_type = size_t;
+#if __cplusplus > 202002L
+      using const_iterator         = std::const_iterator<iterator>;
+      using const_reverse_iterator = std::const_iterator<reverse_iterator>;
+#endif
 
       // member constants
-      static inline constexpr size_t extent = _Extent;
+      static constexpr size_t extent = _Extent;
 
-      // constructors
-
-      template <typename _Dummy = _Type,
-               enable_if_t<is_same_v<_Dummy, _Type>
-                 && (_Extent == dynamic_extent || _Extent == 0)>* = nullptr>
-       constexpr
-       span() noexcept : _M_extent(0), _M_ptr(nullptr)
-       { }
+      // constructors, copy and assignment
 
       constexpr
-      span(const span&) noexcept = default;
+      span() noexcept
+      requires (_Extent == dynamic_extent || _Extent == 0)
+      : _M_ptr(nullptr), _M_extent(0)
+      { }
 
-      template<size_t _ArrayExtent,
-       enable_if_t<_Extent == dynamic_extent || _ArrayExtent == _Extent>*
-         = nullptr>
+      template<contiguous_iterator _It>
+       requires __is_compatible_ref<iter_reference_t<_It>>::value
+       constexpr explicit(extent != dynamic_extent)
+       span(_It __first, size_type __count)
+       noexcept
+       : _M_ptr(std::to_address(__first)), _M_extent(__count)
+       {
+         if constexpr (_Extent != dynamic_extent)
+           {
+             __glibcxx_assert(__count == _Extent);
+           }
+         __glibcxx_requires_valid_range(__first, __first + __count);
+       }
+
+      template<contiguous_iterator _It, sized_sentinel_for<_It> _End>
+       requires __is_compatible_ref<iter_reference_t<_It>>::value
+         && (!is_convertible_v<_End, size_type>)
+       constexpr explicit(extent != dynamic_extent)
+       span(_It __first, _End __last)
+       noexcept(noexcept(__last - __first))
+       : _M_ptr(std::to_address(__first)),
+         _M_extent(static_cast<size_type>(__last - __first))
+       {
+         if constexpr (_Extent != dynamic_extent)
+           {
+             __glibcxx_assert((__last - __first) == _Extent);
+           }
+         __glibcxx_requires_valid_range(__first, __last);
+       }
+
+      template<size_t _ArrayExtent>
+       requires (_Extent == dynamic_extent || _ArrayExtent == _Extent)
        constexpr
-       span(element_type (&__arr)[_ArrayExtent]) noexcept
+       span(type_identity_t<element_type> (&__arr)[_ArrayExtent]) noexcept
        : span(static_cast<pointer>(__arr), _ArrayExtent)
        { }
 
-      template<size_t _ArrayExtent,
-       enable_if_t<_Extent == dynamic_extent || _ArrayExtent == _Extent>*
-         = nullptr>
+      template<typename _Tp, size_t _ArrayExtent>
+       requires __is_compatible_array<_Tp, _ArrayExtent>::value
        constexpr
-       span(array<value_type, _ArrayExtent>& __arr) noexcept
-       : span(__arr.data(), _ArrayExtent)
+       span(array<_Tp, _ArrayExtent>& __arr) noexcept
+       : span(static_cast<pointer>(__arr.data()), _ArrayExtent)
        { }
 
-      template<size_t _ArrayExtent,
-       enable_if_t<_Extent == dynamic_extent || _ArrayExtent == _Extent>*
-         = nullptr>
+      template<typename _Tp, size_t _ArrayExtent>
+       requires __is_compatible_array<const _Tp, _ArrayExtent>::value
        constexpr
-       span(const array<value_type, _ArrayExtent>& __arr) noexcept
-       : span(__arr.data(), _ArrayExtent)
+       span(const array<_Tp, _ArrayExtent>& __arr) noexcept
+       : span(static_cast<pointer>(__arr.data()), _ArrayExtent)
        { }
 
-      // NOTE: when the time comes, and P1394 -
-      // range constructors for std::span - ships in
-      // the standard, delete the #else block and remove
-      // the conditional
-      // if the paper fails, delete #if block
-      // and keep the crappy #else block
-      // and then cry that NB comments failed C++20...
-      // but maybe for C++23?
-#ifdef _GLIBCXX_P1394
-    private:
-      // FIXME: use std::iter_reference_t
-      template<typename _Iterator>
-       using iter_reference_t = decltype(*std::declval<_Iterator&>());
-      // FIXME: use std::ranges::iterator_t
-      // N.B. constraint is needed to prevent a cycle when __adl_begin finds
-      // begin(span) which does overload resolution on span(Range&&).
-      template<typename _Rng,
-              typename _Rng2 = remove_cvref_t<_Rng>,
-              typename = enable_if_t<!__detail::__is_std_span<_Rng2>::value>>
-       using iterator_t = decltype(std::__adl_begin(std::declval<_Rng&>()));
-      // FIXME: use std::iter_value_t
-      template<typename _Iter>
-       using iter_value_t = typename iterator_traits<_Iter>::value_type;
-      // FIXME: use std::derived_from concept
-      template<typename _Derived, typename _Base>
-       using derived_from
-         = __and_<is_base_of<_Base, _Derived>,
-             is_convertible<const volatile _Derived*, const volatile _Base*>>;
-      // FIXME: require contiguous_iterator<_Iterator>
-      template<typename _Iter,
-              typename _Ref = iter_reference_t<_Iter>,
-              typename _Traits = iterator_traits<_Iter>,
-              typename _Tag = typename _Traits::iterator_category>
-       using __is_compatible_iterator
-         = __and_<derived_from<_Tag, random_access_iterator_tag>,
-                  is_lvalue_reference<_Ref>,
-                  is_same<iter_value_t<_Iter>, remove_cvref_t<_Ref>>,
-                  __is_compatible<remove_reference_t<_Ref>>>;
-
       template<typename _Range>
-       using __is_compatible_range
-         = __is_compatible_iterator<iterator_t<_Range>>;
-
-    public:
-      template<typename _Range, typename = _Require<
-         bool_constant<_Extent == dynamic_extent>,
-         __not_<__detail::__is_std_span<remove_cvref_t<_Range>>>,
-         __not_<__detail::__is_std_array<remove_cvref_t<_Range>>>,
-         __not_<is_array<remove_reference_t<_Range>>>,
-         __is_compatible_range<_Range>>,
-         typename = decltype(std::__adl_data(std::declval<_Range&>()))>
-       constexpr
+       requires (!__detail::__is_span<remove_cvref_t<_Range>>)
+         && (!__detail::__is_std_array<remove_cvref_t<_Range>>)
+         && (!is_array_v<remove_cvref_t<_Range>>)
+         && ranges::contiguous_range<_Range> && ranges::sized_range<_Range>
+         && (ranges::borrowed_range<_Range> || is_const_v<element_type>)
+         && __is_compatible_ref<ranges::range_reference_t<_Range>>::value
+       constexpr explicit(extent != dynamic_extent)
        span(_Range&& __range)
-       noexcept(noexcept(::std::__adl_data(__range))
-                 && noexcept(::std::__adl_size(__range)))
-       : span(::std::__adl_data(__range), ::std::__adl_size(__range))
-       { }
-
-      template<typename _ContiguousIterator, typename _Sentinel, typename
-               = _Require<__not_<is_convertible<_Sentinel, index_type>>,
-                          __is_compatible_iterator<_ContiguousIterator>>>
-       constexpr
-       span(_ContiguousIterator __first, _Sentinel __last)
-       : _M_extent(static_cast<index_type>(__last - __first)),
-         _M_ptr(std::to_address(__first))
+       noexcept(noexcept(ranges::data(__range))
+                 && noexcept(ranges::size(__range)))
+       : span(ranges::data(__range), ranges::size(__range))
        {
-         if (_Extent != dynamic_extent)
-           __glibcxx_assert((__last - __first) == _Extent);
+         if constexpr (extent != dynamic_extent)
+           {
+             __glibcxx_assert(ranges::size(__range) == extent);
+           }
        }
 
-      template<typename _ContiguousIterator, typename
-               = _Require<__is_compatible_iterator<_ContiguousIterator>>>
-       constexpr
-       span(_ContiguousIterator __first, index_type __count)
-       noexcept(noexcept(std::to_address(__first)))
-       : _M_extent(__count), _M_ptr(std::to_address(__first))
-       { __glibcxx_assert(_Extent == dynamic_extent || __count == _Extent); }
-#else
-    private:
-      template<typename _Container,
-         typename _DataT = decltype(std::data(std::declval<_Container&>())),
-         typename _SizeT = decltype(std::size(std::declval<_Container&>()))>
-       using __is_compatible_container
-         = __is_compatible<remove_pointer_t<_DataT>>;
-
-    public:
-      template<typename _Container, typename = _Require<
-               bool_constant<_Extent == dynamic_extent>,
-               __not_<__detail::__is_std_span<_Container>>,
-               __not_<__detail::__is_std_array<_Container>>,
-               __not_<is_array<_Container>>,
-               __is_compatible_container<_Container>>>
-       constexpr
-       span(_Container& __cont)
-       noexcept(noexcept(std::data(__cont)) && noexcept(std::size(__cont)))
-       : _M_extent(std::size(__cont)), _M_ptr(std::data(__cont))
-       { }
-
-      template<typename _Container, typename = _Require<
-               bool_constant<_Extent == dynamic_extent>,
-               __not_<__detail::__is_std_span<_Container>>,
-               __not_<__detail::__is_std_array<_Container>>,
-               __not_<is_array<_Container>>,
-               __is_compatible_container<const _Container>>>
-       constexpr
-       span(const _Container& __cont)
-       noexcept(noexcept(std::data(__cont)) && noexcept(std::size(__cont)))
-       : _M_extent(std::size(__cont)), _M_ptr(std::data(__cont))
-       { }
-
-      constexpr
-      span(pointer __first, index_type __count) noexcept
-      : _M_extent(__count), _M_ptr(__first)
-      { __glibcxx_assert(_Extent == dynamic_extent || __count == _Extent); }
-
       constexpr
-      span(pointer __first, pointer __last) noexcept
-      : span(__first, static_cast<index_type>(__last - __first))
-      { }
-#endif // P1394
+      span(const span&) noexcept = default;
 
-      template<typename _OType, size_t _OExtent, typename = _Require<
-         __bool_constant<_Extent == dynamic_extent || _Extent == _OExtent>,
-         is_convertible<_OType(*)[], _Type(*)[]>>>
+      template<typename _OType, size_t _OExtent>
+       requires (_Extent == dynamic_extent || _OExtent == dynamic_extent
+                 || _Extent == _OExtent)
+         && (__is_array_convertible<_Type, _OType>::value)
        constexpr
+       explicit(extent != dynamic_extent && _OExtent == dynamic_extent)
        span(const span<_OType, _OExtent>& __s) noexcept
        : _M_extent(__s.size()), _M_ptr(__s.data())
-       { }
+       {
+         if constexpr (extent != dynamic_extent)
+           {
+             __glibcxx_assert(__s.size() == extent);
+           }
+       }
 
-      // assignment
+      ~span() noexcept = default;
 
       constexpr span&
       operator=(const span&) noexcept = default;
 
       // observers
 
-      constexpr index_type
+      [[nodiscard]]
+      constexpr size_type
       size() const noexcept
       { return this->_M_extent._M_extent(); }
 
-      constexpr index_type
+      [[nodiscard]]
+      constexpr size_type
       size_bytes() const noexcept
       { return this->_M_extent._M_extent() * sizeof(element_type); }
 
-      [[nodiscard]] constexpr bool
+      [[nodiscard]]
+      constexpr bool
       empty() const noexcept
       { return size() == 0; }
 
       // element access
 
+      [[nodiscard]]
       constexpr reference
       front() const noexcept
       {
-       static_assert(extent != 0);
        __glibcxx_assert(!empty());
        return *this->_M_ptr;
       }
 
+      [[nodiscard]]
       constexpr reference
       back() const noexcept
       {
-       static_assert(extent != 0);
        __glibcxx_assert(!empty());
        return *(this->_M_ptr + (size() - 1));
       }
 
+      [[nodiscard]]
       constexpr reference
-      operator[](index_type __idx) const noexcept
+      operator[](size_type __idx) const noexcept
       {
-       static_assert(extent != 0);
        __glibcxx_assert(__idx < size());
        return *(this->_M_ptr + __idx);
       }
 
+      [[nodiscard]]
+      constexpr reference
+      at(size_type __idx) const
+      {
+       if (__idx >= size())
+         __throw_out_of_range_fmt(__N("span::at(%zu) out-of-range for span "
+                                      "of size %zu"), __idx, this->size());
+       return *(this->_M_ptr + __idx);
+      }
+
+      [[nodiscard]]
       constexpr pointer
       data() const noexcept
       { return this->_M_ptr; }
 
       // iterator support
 
+      [[nodiscard]]
       constexpr iterator
       begin() const noexcept
       { return iterator(this->_M_ptr); }
 
-      constexpr const_iterator
-      cbegin() const noexcept
-      { return const_iterator(this->_M_ptr); }
-
+      [[nodiscard]]
       constexpr iterator
       end() const noexcept
       { return iterator(this->_M_ptr + this->size()); }
 
-      constexpr const_iterator
-      cend() const noexcept
-      { return const_iterator(this->_M_ptr + this->size()); }
-
+      [[nodiscard]]
       constexpr reverse_iterator
       rbegin() const noexcept
       { return reverse_iterator(this->end()); }
 
-      constexpr const_reverse_iterator
-      crbegin() const noexcept
-      { return const_reverse_iterator(this->cend()); }
-
+      [[nodiscard]]
       constexpr reverse_iterator
       rend() const noexcept
       { return reverse_iterator(this->begin()); }
 
+#if __cplusplus > 202002L
+      [[nodiscard]]
+      constexpr const_iterator
+      cbegin() const noexcept
+      { return begin(); }
+
+      [[nodiscard]]
+      constexpr const_iterator
+      cend() const noexcept
+      { return end(); }
+
+      [[nodiscard]]
+      constexpr const_reverse_iterator
+      crbegin() const noexcept
+      { return rbegin(); }
+
+      [[nodiscard]]
       constexpr const_reverse_iterator
       crend() const noexcept
-      { return const_reverse_iterator(this->cbegin()); }
+      { return rend(); }
+#endif
 
       // subviews
 
       template<size_t _Count>
+       [[nodiscard]]
        constexpr span<element_type, _Count>
        first() const noexcept
        {
@@ -405,17 +357,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            __glibcxx_assert(_Count <= size());
          else
            static_assert(_Count <= extent);
-         return { this->data(), _Count };
+         using _Sp = span<element_type, _Count>;
+         return _Sp{ this->data(), _Count };
        }
 
+      [[nodiscard]]
       constexpr span<element_type, dynamic_extent>
-      first(index_type __count) const noexcept
+      first(size_type __count) const noexcept
       {
        __glibcxx_assert(__count <= size());
        return { this->data(), __count };
       }
 
       template<size_t _Count>
+       [[nodiscard]]
        constexpr span<element_type, _Count>
        last() const noexcept
        {
@@ -423,28 +378,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            __glibcxx_assert(_Count <= size());
          else
            static_assert(_Count <= extent);
-         return { this->data() + (this->size() - _Count), _Count };
+         using _Sp = span<element_type, _Count>;
+         return _Sp{ this->data() + (this->size() - _Count), _Count };
        }
 
+      [[nodiscard]]
       constexpr span<element_type, dynamic_extent>
-      last(index_type __count) const noexcept
+      last(size_type __count) const noexcept
       {
        __glibcxx_assert(__count <= size());
        return { this->data() + (this->size() - __count), __count };
       }
 
       template<size_t _Offset, size_t _Count = dynamic_extent>
+       [[nodiscard]]
        constexpr auto
        subspan() const noexcept
        -> span<element_type, _S_subspan_extent<_Offset, _Count>()>
        {
          if constexpr (_Extent == dynamic_extent)
-           __glibcxx_assert(_Offset <= size());
+           {
+             __glibcxx_assert(_Offset <= size());
+           }
          else
            static_assert(_Offset <= extent);
 
+         using _Sp = span<element_type, _S_subspan_extent<_Offset, _Count>()>;
+
          if constexpr (_Count == dynamic_extent)
-           return { this->data() + _Offset, this->size() - _Offset };
+           return _Sp{ this->data() + _Offset, this->size() - _Offset };
          else
            {
              if constexpr (_Extent == dynamic_extent)
@@ -457,12 +419,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
                  static_assert(_Count <= extent);
                  static_assert(_Count <= (extent - _Offset));
                }
-             return { this->data() + _Offset, _Count };
+             return _Sp{ this->data() + _Offset, _Count };
            }
        }
 
+      [[nodiscard]]
       constexpr span<element_type, dynamic_extent>
-      subspan(index_type __offset, index_type __count = dynamic_extent) const
+      subspan(size_type __offset, size_type __count = dynamic_extent) const
       noexcept
       {
        __glibcxx_assert(__offset <= size());
@@ -476,22 +439,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        return {this->data() + __offset, __count};
       }
 
-      // observers: range helpers
-
-      friend constexpr iterator
-      begin(span __sp) noexcept
-      { return __sp.begin(); }
-
-      friend constexpr iterator
-      end(span __sp) noexcept
-      { return __sp.end(); }
-
     private:
-      [[no_unique_address]] __detail::__extent_storage<extent> _M_extent;
       pointer _M_ptr;
+      [[no_unique_address]] __detail::__extent_storage<extent> _M_extent;
     };
 
   // deduction guides
+
   template<typename _Type, size_t _ArrayExtent>
     span(_Type(&)[_ArrayExtent]) -> span<_Type, _ArrayExtent>;
 
@@ -502,75 +456,55 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     span(const array<_Type, _ArrayExtent>&)
       -> span<const _Type, _ArrayExtent>;
 
-#ifdef _GLIBCXX_P1394
-
-  template<typename _ContiguousIterator, typename _Sentinel>
-    span(_ContiguousIterator, _Sentinel)
-      -> span<remove_reference_t<
-       typename iterator_traits<_ContiguousIterator>::reference>>;
+  template<contiguous_iterator _Iter, typename _End>
+    span(_Iter, _End)
+      -> span<remove_reference_t<iter_reference_t<_Iter>>>;
 
-  template<typename _Range>
+  template<ranges::contiguous_range _Range>
     span(_Range &&)
-      -> span<remove_reference_t<typename iterator_traits<
-         decltype(std::__adl_begin(::std::declval<_Range&>()))>::reference>>;
-
-#else
-
-  template<typename _Container>
-    span(_Container&) -> span<typename _Container::value_type>;
-
-  template<typename _Container>
-    span(const _Container&) -> span<const typename _Container::value_type>;
-
-#endif // P1394
+      -> span<remove_reference_t<ranges::range_reference_t<_Range&>>>;
 
   template<typename _Type, size_t _Extent>
+    [[nodiscard]]
     inline
     span<const byte, _Extent == dynamic_extent
        ? dynamic_extent : _Extent * sizeof(_Type)>
     as_bytes(span<_Type, _Extent> __sp) noexcept
     {
-      return {reinterpret_cast<const byte*>(__sp.data()), __sp.size_bytes()};
+      auto data = reinterpret_cast<const byte*>(__sp.data());
+      auto size = __sp.size_bytes();
+      constexpr auto extent = _Extent == dynamic_extent
+       ? dynamic_extent : _Extent * sizeof(_Type);
+      return span<const byte, extent>{data, size};
     }
 
   template<typename _Type, size_t _Extent>
+    requires (!is_const_v<_Type>)
     inline
     span<byte, _Extent == dynamic_extent
        ? dynamic_extent : _Extent * sizeof(_Type)>
-    as_writable_bytes(span<_Type, _Extent> __sp) noexcept
-    {
-      return {reinterpret_cast<byte*>(__sp.data()), __sp.size_bytes()};
-    }
-
-  // tuple helpers
-  template<size_t _Index, typename _Type, size_t _Extent>
-    constexpr _Type&
-    get(span<_Type, _Extent> __sp) noexcept
+    as_writable_bytes [[nodiscard]] (span<_Type, _Extent> __sp) noexcept
     {
-      static_assert(_Extent != dynamic_extent && _Index < _Extent,
-       "get<I> can only be used with a span of non-dynamic (fixed) extent");
-      return __sp[_Index];
+      auto data = reinterpret_cast<byte*>(__sp.data());
+      auto size = __sp.size_bytes();
+      constexpr auto extent = _Extent == dynamic_extent
+       ? dynamic_extent : _Extent * sizeof(_Type);
+      return span<byte, extent>{data, size};
     }
 
-  template<typename _Type, size_t _Extent>
-    struct tuple_size<span<_Type, _Extent>>
-    : public integral_constant<size_t, _Extent>
-    {
-      static_assert(_Extent != dynamic_extent, "tuple_size can only "
-       "be used with a span of non-dynamic (fixed) extent");
-    };
-
-  template<size_t _Index, typename _Type, size_t _Extent>
-    struct tuple_element<_Index, span<_Type, _Extent>>
-    {
-      static_assert(_Extent != dynamic_extent, "tuple_element can only "
-       "be used with a span of non-dynamic (fixed) extent");
-      static_assert(_Index < _Extent, "Index is less than Extent");
-      using type = _Type;
-    };
-
+  namespace ranges
+  {
+    // Opt-in to borrowed_range concept
+    template<typename _ElementType, size_t _Extent>
+      inline constexpr bool
+       enable_borrowed_range<span<_ElementType, _Extent>> = true;
+
+    // Opt-in to view concept
+    template<typename _ElementType, size_t _Extent>
+      inline constexpr bool
+       enable_view<span<_ElementType, _Extent>> = true;
+  }
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
-
-#endif // C++20
+#endif // __cpp_lib_span
 #endif // _GLIBCXX_SPAN