mirror of
https://github.com/gcc-mirror/gcc.git
synced 2026-05-06 14:59:39 +02:00
All std::span member functions are pure functions that have no side effects. They are only useful for their return value, so they should all warn if that value is not used. libstdc++-v3/ChangeLog: * include/std/span (span, as_bytes, as_writable_bytes): Add [[nodiscard]] attribute on all non-void functions. * testsuite/23_containers/span/back_assert_neg.cc: Suppress nodiscard warning. * testsuite/23_containers/span/back_neg.cc: Likewise. * testsuite/23_containers/span/first_2_assert_neg.cc: Likewise. * testsuite/23_containers/span/first_assert_neg.cc: Likewise. * testsuite/23_containers/span/first_neg.cc: Likewise. * testsuite/23_containers/span/front_assert_neg.cc: Likewise. * testsuite/23_containers/span/front_neg.cc: Likewise. * testsuite/23_containers/span/index_op_assert_neg.cc: Likewise. * testsuite/23_containers/span/index_op_neg.cc: Likewise. * testsuite/23_containers/span/last_2_assert_neg.cc: Likewise. * testsuite/23_containers/span/last_assert_neg.cc: Likewise. * testsuite/23_containers/span/last_neg.cc: Likewise. * testsuite/23_containers/span/subspan_2_assert_neg.cc: Likewise. * testsuite/23_containers/span/subspan_3_assert_neg.cc: Likewise. * testsuite/23_containers/span/subspan_4_assert_neg.cc: Likewise. * testsuite/23_containers/span/subspan_5_assert_neg.cc: Likewise. * testsuite/23_containers/span/subspan_6_assert_neg.cc: Likewise. * testsuite/23_containers/span/subspan_assert_neg.cc: Likewise. * testsuite/23_containers/span/subspan_neg.cc: Likewise. * testsuite/23_containers/span/nodiscard.cc: New test.
501 lines
14 KiB
C++
501 lines
14 KiB
C++
// Components for manipulating non-owning sequences of objects -*- C++ -*-
|
|
|
|
// Copyright (C) 2019-2023 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
|
|
|
|
#define __glibcxx_want_span
|
|
#include <bits/version.h>
|
|
|
|
#ifdef __cpp_lib_span // C++ >= 20 && concepts
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <bits/stl_iterator.h>
|
|
#include <bits/ranges_base.h>
|
|
namespace std _GLIBCXX_VISIBILITY(default)
|
|
{
|
|
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|
|
|
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>;
|
|
#if __cplusplus > 202002L
|
|
using const_iterator = std::const_iterator<iterator>;
|
|
using const_reverse_iterator = std::const_iterator<reverse_iterator>;
|
|
#endif
|
|
|
|
// member constants
|
|
static constexpr size_t extent = _Extent;
|
|
|
|
// constructors, copy and assignment
|
|
|
|
constexpr
|
|
span() noexcept
|
|
requires (_Extent == dynamic_extent || _Extent == 0)
|
|
: _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
|
|
|
|
[[nodiscard]]
|
|
constexpr size_type
|
|
size() const noexcept
|
|
{ return this->_M_extent._M_extent(); }
|
|
|
|
[[nodiscard]]
|
|
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
|
|
|
|
[[nodiscard]]
|
|
constexpr reference
|
|
front() const noexcept
|
|
{
|
|
__glibcxx_assert(!empty());
|
|
return *this->_M_ptr;
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr reference
|
|
back() const noexcept
|
|
{
|
|
__glibcxx_assert(!empty());
|
|
return *(this->_M_ptr + (size() - 1));
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr reference
|
|
operator[](size_type __idx) const noexcept
|
|
{
|
|
__glibcxx_assert(__idx < 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); }
|
|
|
|
[[nodiscard]]
|
|
constexpr iterator
|
|
end() const noexcept
|
|
{ return iterator(this->_M_ptr + this->size()); }
|
|
|
|
[[nodiscard]]
|
|
constexpr reverse_iterator
|
|
rbegin() const noexcept
|
|
{ return reverse_iterator(this->end()); }
|
|
|
|
[[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 rend(); }
|
|
#endif
|
|
|
|
// subviews
|
|
|
|
template<size_t _Count>
|
|
[[nodiscard]]
|
|
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 };
|
|
}
|
|
|
|
[[nodiscard]]
|
|
constexpr span<element_type, dynamic_extent>
|
|
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
|
|
{
|
|
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 };
|
|
}
|
|
|
|
[[nodiscard]]
|
|
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>
|
|
[[nodiscard]]
|
|
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 };
|
|
}
|
|
}
|
|
|
|
[[nodiscard]]
|
|
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>
|
|
[[nodiscard]]
|
|
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 [[nodiscard]] (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 // __cpp_lib_span
|
|
#endif // _GLIBCXX_SPAN
|