// 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>
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
private:
size_t _M_extent_value;
};
-
} // namespace __detail
template<typename _Type, size_t _Extent = dynamic_extent>
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
{
__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
{
__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)
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());
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>;
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