mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
For a span with statically empty extent, we currently model the preconditions of front(), back(), and operator[] as if they are mandates, by using a static_assert to verify that extent != 0. This causes us to reject valid programs that would instantiate these member functions and at runtime never call them. Since they are already followed by more general runtime asserts, this patch just removes these static_asserts altogether, libstdc++-v3/ChangeLog: * include/std/span (span::front): Remove static_assert. (span::back): Likewise. (span::operator[]): Likewise. * testsuite/23_containers/span/back_neg.cc: Rewrite to verify that we check the preconditions of back() only when it's called. * testsuite/23_containers/span/front_neg.cc: Likewise for front(). * testsuite/23_containers/span/index_op_neg.cc: Likewise for operator[].
463 lines
13 KiB
C++
463 lines
13 KiB
C++
// Components for manipulating non-owning sequences of objects -*- C++ -*-
|
|
|
|
// Copyright (C) 2019-2020 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 <type_traits>
|
|
#include <array>
|
|
#include <bits/stl_iterator.h>
|
|
#include <bits/range_access.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>
|
|
struct __is_std_span : false_type { };
|
|
|
|
template<typename _Tp, size_t _Num>
|
|
struct __is_std_span<span<_Tp, _Num>> : true_type { };
|
|
|
|
template<typename _Tp>
|
|
struct __is_std_array : false_type { };
|
|
|
|
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
|
|
|
|
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_extent(0), _M_ptr(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_extent(__count), _M_ptr(std::to_address(__first))
|
|
{
|
|
if constexpr (_Extent != dynamic_extent)
|
|
{
|
|
__glibcxx_assert(__count == _Extent);
|
|
}
|
|
}
|
|
|
|
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_extent(static_cast<size_type>(__last - __first)),
|
|
_M_ptr(std::to_address(__first))
|
|
{
|
|
if constexpr (_Extent != dynamic_extent)
|
|
{
|
|
__glibcxx_assert((__last - __first) == _Extent);
|
|
}
|
|
}
|
|
|
|
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 ranges::contiguous_range<_Range> && ranges::sized_range<_Range>
|
|
&& (ranges::borrowed_range<_Range> || is_const_v<element_type>)
|
|
&& (!__detail::__is_std_span<remove_cvref_t<_Range>>::value)
|
|
&& (!__detail::__is_std_array<remove_cvref_t<_Range>>::value)
|
|
&& (!is_array_v<remove_cvref_t<_Range>>)
|
|
&& __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:
|
|
[[no_unique_address]] __detail::__extent_storage<extent> _M_extent;
|
|
pointer _M_ptr;
|
|
};
|
|
|
|
// 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<typename _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>
|
|
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>>
|
|
= _Extent == 0 || _Extent == dynamic_extent;
|
|
}
|
|
_GLIBCXX_END_NAMESPACE_VERSION
|
|
} // namespace std
|
|
#endif // concepts
|
|
#endif // C++20
|
|
#endif // _GLIBCXX_SPAN
|