libstdc++: P1976R2 Fixed-size span construction from dynamic range
This includes fixes for first, last, as_bytes and as_writable_bytes which were missing from the paper. * include/std/span (__cpp_lib_span): Update value. (span(It, size_type), span(It, End)): Make conditionally explicit. Add assertion. (span(R&&), span(const span<OType, OExtent>&)): Likewise and relax constraints. (span::first<Count>(), span::last<Count>()): Use explicit type in return statement. (as_bytes, as_writable_bytes): Likewise. * include/std/version (__cpp_lib_span): Update value. * testsuite/23_containers/span/1.cc: Check new value. * testsuite/23_containers/span/2.cc: Check new value. * testsuite/23_containers/span/explicit.cc: New test.
This commit is contained in:
parent
d6c9e37237
commit
9b8e2dea78
6 changed files with 116 additions and 22 deletions
|
@ -1,5 +1,19 @@
|
|||
2020-02-18 Jonathan Wakely <jwakely@redhat.com>
|
||||
|
||||
P1976R2 Fixed-size span construction from dynamic range
|
||||
* include/std/span (__cpp_lib_span): Update value.
|
||||
(span(It, size_type), span(It, End)): Make conditionally explicit. Add
|
||||
assertion.
|
||||
(span(R&&), span(const span<OType, OExtent>&)): Likewise and relax
|
||||
constraints.
|
||||
(span::first<Count>(), span::last<Count>()): Use explicit type in
|
||||
return statement.
|
||||
(as_bytes, as_writable_bytes): Likewise.
|
||||
* include/std/version (__cpp_lib_span): Update value.
|
||||
* testsuite/23_containers/span/1.cc: Check new value.
|
||||
* testsuite/23_containers/span/2.cc: Check new value.
|
||||
* testsuite/23_containers/span/explicit.cc: New test.
|
||||
|
||||
* include/std/span (span::__is_compatible_array): Simplify alias
|
||||
template by using requires-clause.
|
||||
(span::__is_compatible_ref): New alias template for constraining
|
||||
|
|
|
@ -48,7 +48,7 @@ namespace std _GLIBCXX_VISIBILITY(default)
|
|||
{
|
||||
_GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
#define __cpp_lib_span 201902L
|
||||
#define __cpp_lib_span 202002L
|
||||
|
||||
inline constexpr size_t dynamic_extent = static_cast<size_t>(-1);
|
||||
|
||||
|
@ -158,23 +158,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
|
||||
template<contiguous_iterator _It>
|
||||
requires __is_compatible_ref<iter_reference_t<_It>>::value
|
||||
constexpr
|
||||
constexpr explicit(extent != dynamic_extent)
|
||||
span(_It __first, size_type __count)
|
||||
noexcept
|
||||
: _M_extent(__count), _M_ptr(std::to_address(__first))
|
||||
{ __glibcxx_assert(_Extent == dynamic_extent || __count == _Extent); }
|
||||
{
|
||||
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
|
||||
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 (_Extent != dynamic_extent)
|
||||
__glibcxx_assert((__last - __first) == _Extent);
|
||||
if constexpr (_Extent != dynamic_extent)
|
||||
{
|
||||
__glibcxx_assert((__last - __first) == _Extent);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename _Tp, size_t _ArrayExtent>
|
||||
|
@ -199,30 +206,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
{ }
|
||||
|
||||
template<typename _Range>
|
||||
requires (_Extent == dynamic_extent)
|
||||
&& ranges::contiguous_range<_Range> && ranges::sized_range<_Range>
|
||||
requires ranges::contiguous_range<_Range> && ranges::sized_range<_Range>
|
||||
&& (ranges::safe_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
|
||||
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 || _Extent == _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;
|
||||
|
||||
|
@ -317,7 +335,8 @@ _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 };
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent>
|
||||
|
@ -335,7 +354,8 @@ _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 };
|
||||
}
|
||||
|
||||
constexpr span<element_type, dynamic_extent>
|
||||
|
@ -351,12 +371,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
-> 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)
|
||||
|
@ -369,7 +393,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
static_assert(_Count <= extent);
|
||||
static_assert(_Count <= (extent - _Offset));
|
||||
}
|
||||
return { this->data() + _Offset, _Count };
|
||||
return _Sp{ this->data() + _Offset, _Count };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,7 +443,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
? 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>
|
||||
|
@ -428,7 +456,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
|||
? dynamic_extent : _Extent * sizeof(_Type)>
|
||||
as_writable_bytes(span<_Type, _Extent> __sp) noexcept
|
||||
{
|
||||
return {reinterpret_cast<byte*>(__sp.data()), __sp.size_bytes()};
|
||||
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
|
||||
|
|
|
@ -193,7 +193,7 @@
|
|||
#endif
|
||||
#define __cpp_lib_list_remove_return_type 201806L
|
||||
#define __cpp_lib_math_constants 201907L
|
||||
#define __cpp_lib_span 201902L
|
||||
#define __cpp_lib_span 202002L
|
||||
#if __cpp_impl_three_way_comparison >= 201907L && __cpp_lib_concepts
|
||||
# define __cpp_lib_three_way_comparison 201711L
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,6 @@
|
|||
|
||||
#ifndef __cpp_lib_span
|
||||
# error "Feature-test macro for span missing in <span>"
|
||||
#elif __cpp_lib_span != 201902L
|
||||
#elif __cpp_lib_span != 202002L
|
||||
# error "Feature-test macro for span has wrong value in <span>"
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,6 @@
|
|||
|
||||
#ifndef __cpp_lib_span
|
||||
# error "Feature-test macro for span missing in <version>"
|
||||
#elif __cpp_lib_span != 201902L
|
||||
#elif __cpp_lib_span != 202002L
|
||||
# error "Feature-test macro for span has wrong value in <version>"
|
||||
#endif
|
||||
|
|
48
libstdc++-v3/testsuite/23_containers/span/explicit.cc
Normal file
48
libstdc++-v3/testsuite/23_containers/span/explicit.cc
Normal file
|
@ -0,0 +1,48 @@
|
|||
// Copyright (C) 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.
|
||||
|
||||
// You should have received a copy of the GNU General Public License along
|
||||
// with this library; see the file COPYING3. If not see
|
||||
// <http://www.gnu.org/licenses/>.
|
||||
|
||||
// { dg-options "-std=gnu++2a" }
|
||||
// { dg-do compile { target c++2a } }
|
||||
|
||||
#include <span>
|
||||
|
||||
struct Range
|
||||
{
|
||||
int* begin();
|
||||
int* end();
|
||||
unsigned size() const;
|
||||
} r;
|
||||
|
||||
auto first = std::begin(r), last = std::end(r);
|
||||
|
||||
// span(It, size_type)
|
||||
std::span<int> s1 = {first, 2};
|
||||
std::span<int, 2> s2 = {first, 2}; // { dg-error "could not convert" }
|
||||
|
||||
// span(It, End)
|
||||
std::span<int> s3 = {first, last};
|
||||
std::span<int, 2> s4 = {first, last}; // { dg-error "could not convert" }
|
||||
|
||||
// span(R&&)
|
||||
std::span<int> s5 = r;
|
||||
std::span<int, 2> s6 = r; // { dg-error "conversion from" }
|
||||
|
||||
// span(const span<OtherElement, OtherExtent>&)
|
||||
std::span<const int> s7 = s5;
|
||||
std::span<const int> s8 = s6;
|
||||
std::span<const int, 1> s9 = s5.first(1); // { dg-error "conversion from" }
|
||||
std::span<const int, 1> s10 = s7.first(1); // { dg-error "conversion from" }
|
Loading…
Add table
Reference in a new issue