09bc98098e
In PR libstdc++/103013 Tim Song pointed out that we could reorder the constraints of this constructor. That's worth doing just to reduce the work the compiler has to do during overload resolution, even if it isn't needed to make the code in the PR work. libstdc++-v3/ChangeLog: * include/std/span (span(Range&&)): Reorder constraints.
460 lines
13 KiB
C++
460 lines
13 KiB
C++
// Components for manipulating non-owning sequences of objects -*- C++ -*-
|
|
|
|
// Copyright (C) 2019-2021 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
|
|
// terms of the GNU General Public License as published by the
|
|
// Free Software Foundation; either version 3, or (at your option)
|
|
// any later version.
|
|
|
|
// This library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// Under Section 7 of GPL version 3, you are granted additional
|
|
// permissions described in the GCC Runtime Library Exception, version
|
|
// 3.1, as published by the Free Software Foundation.
|
|
|
|
// You should have received a copy of the GNU General Public License and
|
|
// a copy of the GCC Runtime Library Exception along with this program;
|
|
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
// <http://www.gnu.org/licenses/>.
|
|
|
|
/** @file span
|
|
* This is a Standard C++ Library header.
|
|
*/
|
|
|
|
//
|
|
// P0122 span library
|
|
// Contributed by ThePhD
|
|
//
|
|
|
|
#ifndef _GLIBCXX_SPAN
|
|
#define _GLIBCXX_SPAN 1
|
|
|
|
#pragma GCC system_header
|
|
|
|
#if __cplusplus > 201703L
|
|
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <bits/stl_iterator.h>
|
|
#include <bits/ranges_base.h>
|
|
|
|
#if __cpp_lib_concepts
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
#define __cpp_lib_span 202002L
|
|
|
|
inline constexpr size_t dynamic_extent = static_cast<size_t>(-1);
|
|
|
|
template<typename _Type, size_t _Extent>
|
|
class span;
|
|
|
|
namespace __detail
|
|
{
|
|
template<typename _Tp>
|
|
inline constexpr bool __is_span = false;
|
|
|
|
template<typename _Tp, size_t _Num>
|
|
inline constexpr bool __is_span<span<_Tp, _Num>> = true;
|
|
|
|
template<typename _Tp>
|
|
inline constexpr bool __is_std_array = false;
|
|
|
|
template<typename _Tp, size_t _Num>
|
|
inline constexpr bool __is_std_array<std::array<_Tp, _Num>> = true;
|
|
|
|
template<size_t _Extent>
|
|
class __extent_storage
|
|
{
|
|
public:
|
|
constexpr
|
|
__extent_storage(size_t) noexcept
|
|
{ }
|
|
|
|
static constexpr size_t
|
|
_M_extent() noexcept
|
|
{ return _Extent; }
|
|
};
|
|
|
|
template<>
|
|
class __extent_storage<dynamic_extent>
|
|
{
|
|
public:
|
|
constexpr
|
|
__extent_storage(size_t __extent) noexcept
|
|
: _M_extent_value(__extent)
|
|
{ }
|
|
|
|
constexpr size_t
|
|
_M_extent() const noexcept
|
|
{ return this->_M_extent_value; }
|
|
|
|
private:
|
|
size_t _M_extent_value;
|
|
};
|
|
} // namespace __detail
|
|
|
|
template<typename _Type, size_t _Extent = dynamic_extent>
|
|
class span
|
|
{
|
|
template<size_t _Offset, size_t _Count>
|
|
static constexpr size_t
|
|
_S_subspan_extent()
|
|
{
|
|
if constexpr (_Count != dynamic_extent)
|
|
return _Count;
|
|
else if constexpr (extent != dynamic_extent)
|
|
return _Extent - _Offset;
|
|
else
|
|
return dynamic_extent;
|
|
}
|
|
|
|
// _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 element_type = _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 reference = element_type&;
|
|
using const_reference = const element_type&;
|
|
using iterator = __gnu_cxx::__normal_iterator<pointer, span>;
|
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
|
|
|
// member constants
|
|
static constexpr size_t extent = _Extent;
|
|
|
|
// constructors, copy and assignment
|
|
|
|
constexpr
|
|
span() noexcept
|
|
requires ((_Extent + 1u) <= 1u)
|
|
: _M_ptr(nullptr), _M_extent(0)
|
|
{ }
|
|
|
|
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(type_identity_t<element_type> (&__arr)[_ArrayExtent]) noexcept
|
|
: span(static_cast<pointer>(__arr), _ArrayExtent)
|
|
{ }
|
|
|
|
template<typename _Tp, size_t _ArrayExtent>
|
|
requires __is_compatible_array<_Tp, _ArrayExtent>::value
|
|
constexpr
|
|
span(array<_Tp, _ArrayExtent>& __arr) noexcept
|
|
: span(static_cast<pointer>(__arr.data()), _ArrayExtent)
|
|
{ }
|
|
|
|
template<typename _Tp, size_t _ArrayExtent>
|
|
requires __is_compatible_array<const _Tp, _ArrayExtent>::value
|
|
constexpr
|
|
span(const array<_Tp, _ArrayExtent>& __arr) noexcept
|
|
: span(static_cast<pointer>(__arr.data()), _ArrayExtent)
|
|
{ }
|
|
|
|
template<typename _Range>
|
|
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(ranges::data(__range))
|
|
&& noexcept(ranges::size(__range)))
|
|
: span(ranges::data(__range), ranges::size(__range))
|
|
{
|
|
if constexpr (extent != dynamic_extent)
|
|
{
|
|
__glibcxx_assert(ranges::size(__range) == extent);
|
|
}
|
|
}
|
|
|
|
constexpr
|
|
span(const span&) noexcept = default;
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
~span() noexcept = default;
|
|
|
|
constexpr span&
|
|
operator=(const span&) noexcept = default;
|
|
|
|
// observers
|
|
|
|
constexpr size_type
|
|
size() const noexcept
|
|
{ return this->_M_extent._M_extent(); }
|
|
|
|
constexpr size_type
|
|
size_bytes() const noexcept
|
|
{ return this->_M_extent._M_extent() * sizeof(element_type); }
|
|
|
|
[[nodiscard]] constexpr bool
|
|
empty() const noexcept
|
|
{ return size() == 0; }
|
|
|
|
// element access
|
|
|
|
constexpr reference
|
|
front() const noexcept
|
|
{
|
|
__glibcxx_assert(!empty());
|
|
return *this->_M_ptr;
|
|
}
|
|
|
|
constexpr reference
|
|
back() const noexcept
|
|
{
|
|
__glibcxx_assert(!empty());
|
|
return *(this->_M_ptr + (size() - 1));
|
|
}
|
|
|
|
constexpr reference
|
|
operator[](size_type __idx) const noexcept
|
|
{
|
|
__glibcxx_assert(__idx < size());
|
|
return *(this->_M_ptr + __idx);
|
|
}
|
|
|
|
constexpr pointer
|
|
data() const noexcept
|
|
{ return this->_M_ptr; }
|
|
|
|
// iterator support
|
|
|
|
constexpr iterator
|
|
begin() const noexcept
|
|
{ return iterator(this->_M_ptr); }
|
|
|
|
constexpr iterator
|
|
end() const noexcept
|
|
{ return iterator(this->_M_ptr + this->size()); }
|
|
|
|
constexpr reverse_iterator
|
|
rbegin() const noexcept
|
|
{ return reverse_iterator(this->end()); }
|
|
|
|
constexpr reverse_iterator
|
|
rend() const noexcept
|
|
{ return reverse_iterator(this->begin()); }
|
|
|
|
// subviews
|
|
|
|
template<size_t _Count>
|
|
constexpr span<element_type, _Count>
|
|
first() const noexcept
|
|
{
|
|
if constexpr (_Extent == dynamic_extent)
|
|
__glibcxx_assert(_Count <= size());
|
|
else
|
|
static_assert(_Count <= extent);
|
|
using _Sp = span<element_type, _Count>;
|
|
return _Sp{ this->data(), _Count };
|
|
}
|
|
|
|
constexpr span<element_type, dynamic_extent>
|
|
first(size_type __count) const noexcept
|
|
{
|
|
__glibcxx_assert(__count <= size());
|
|
return { this->data(), __count };
|
|
}
|
|
|
|
template<size_t _Count>
|
|
constexpr span<element_type, _Count>
|
|
last() const noexcept
|
|
{
|
|
if constexpr (_Extent == dynamic_extent)
|
|
__glibcxx_assert(_Count <= size());
|
|
else
|
|
static_assert(_Count <= extent);
|
|
using _Sp = span<element_type, _Count>;
|
|
return _Sp{ this->data() + (this->size() - _Count), _Count };
|
|
}
|
|
|
|
constexpr span<element_type, dynamic_extent>
|
|
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>
|
|
constexpr auto
|
|
subspan() const noexcept
|
|
-> span<element_type, _S_subspan_extent<_Offset, _Count>()>
|
|
{
|
|
if constexpr (_Extent == dynamic_extent)
|
|
{
|
|
__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 _Sp{ this->data() + _Offset, this->size() - _Offset };
|
|
else
|
|
{
|
|
if constexpr (_Extent == dynamic_extent)
|
|
{
|
|
__glibcxx_assert(_Count <= size());
|
|
__glibcxx_assert(_Count <= (size() - _Offset));
|
|
}
|
|
else
|
|
{
|
|
static_assert(_Count <= extent);
|
|
static_assert(_Count <= (extent - _Offset));
|
|
}
|
|
return _Sp{ this->data() + _Offset, _Count };
|
|
}
|
|
}
|
|
|
|
constexpr span<element_type, dynamic_extent>
|
|
subspan(size_type __offset, size_type __count = dynamic_extent) const
|
|
noexcept
|
|
{
|
|
__glibcxx_assert(__offset <= size());
|
|
if (__count == dynamic_extent)
|
|
__count = this->size() - __offset;
|
|
else
|
|
{
|
|
__glibcxx_assert(__count <= size());
|
|
__glibcxx_assert(__offset + __count <= size());
|
|
}
|
|
return {this->data() + __offset, __count};
|
|
}
|
|
|
|
private:
|
|
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>;
|
|
|
|
template<typename _Type, size_t _ArrayExtent>
|
|
span(array<_Type, _ArrayExtent>&) -> span<_Type, _ArrayExtent>;
|
|
|
|
template<typename _Type, size_t _ArrayExtent>
|
|
span(const array<_Type, _ArrayExtent>&)
|
|
-> span<const _Type, _ArrayExtent>;
|
|
|
|
template<contiguous_iterator _Iter, typename _End>
|
|
span(_Iter, _End)
|
|
-> span<remove_reference_t<iter_reference_t<_Iter>>>;
|
|
|
|
template<ranges::contiguous_range _Range>
|
|
span(_Range &&)
|
|
-> span<remove_reference_t<ranges::range_reference_t<_Range&>>>;
|
|
|
|
template<typename _Type, size_t _Extent>
|
|
inline
|
|
span<const byte, _Extent == dynamic_extent
|
|
? dynamic_extent : _Extent * sizeof(_Type)>
|
|
as_bytes(span<_Type, _Extent> __sp) noexcept
|
|
{
|
|
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
|
|
{
|
|
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};
|
|
}
|
|
|
|
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 // concepts
|
|
#endif // C++20
|
|
#endif // _GLIBCXX_SPAN
|