From a7922ddf481b048c0aaa5fae9d836d656e08d850 Mon Sep 17 00:00:00 2001 From: "JeanHeyd \"ThePhD\" Meneide" Date: Thu, 5 Dec 2019 13:50:01 +0000 Subject: [PATCH] libstdc++: Implement P1872R0 and P1394R0 for std::span This also fixes a bug in the implementation of LWG 3255, which causes: FAIL: 23_containers/span/lwg3255.cc (test for excess errors) That's because the test was wrong and verified the buggy behaviour. That will be fixed in the following commit. 2019-12-05 JeanHeyd "ThePhD" Meneide Implement P1872R0 and P1394R0 for std::span * include/bits/range_access.h (__adl_begin, __adl_end): Remove. (sentinel_t, range_value_t, range_reference_t) (range_rvalue_reference_t, __forwarding_range, disable_sized_range) (output_range, input_range, forward_range, bidirectional_range) (random_access_range, contiguous_range, common_range): Move here from , to make this the "ranges lite" internal header. * include/std/ranges: Move basic aliases and concepts to . * include/std/span: Use concepts and ranges:: calls instead of enable_if and friends. * include/std/type_traits: Add __is_array_convertible trait. From-SVN: r279000 --- libstdc++-v3/ChangeLog | 15 ++ libstdc++-v3/include/bits/range_access.h | 79 +++++++-- libstdc++-v3/include/std/ranges | 57 +----- libstdc++-v3/include/std/span | 212 +++++++---------------- libstdc++-v3/include/std/type_traits | 5 + 5 files changed, 141 insertions(+), 227 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index a5ed14528df..82cb5a99400 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,18 @@ +2019-12-05 JeanHeyd "ThePhD" Meneide + + Implement P1872R0 and P1394R0 for std::span + * include/bits/range_access.h (__adl_begin, __adl_end): Remove. + (sentinel_t, range_value_t, range_reference_t) + (range_rvalue_reference_t, __forwarding_range, disable_sized_range) + (output_range, input_range, forward_range, bidirectional_range) + (random_access_range, contiguous_range, common_range): Move here from + , to make this the "ranges lite" internal header. + * include/std/ranges: Move basic aliases and concepts to + . + * include/std/span: Use concepts and ranges:: calls instead of + enable_if and friends. + * include/std/type_traits: Add __is_array_convertible trait. + 2019-12-05 Jonathan Wakely * include/bits/stl_algobase.h (lexicographical_compare_three_way): diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h index de074460c16..c94e965afb4 100644 --- a/libstdc++-v3/include/bits/range_access.h +++ b/libstdc++-v3/include/bits/range_access.h @@ -336,19 +336,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ssize(const _Tp (&)[_Num]) noexcept { return _Num; } - // "why are these in namespace std:: and not __gnu_cxx:: ?" - // because if we don't put them here it's impossible to - // have implicit ADL with "using std::begin/end/size/data;". - template - constexpr auto - __adl_begin(_Container& __cont) noexcept(noexcept(begin(__cont))) - { return begin(__cont); } - - template - constexpr auto - __adl_data(_Container& __cont) noexcept(noexcept(data(__cont))) - { return data(__cont); } - #ifdef __cpp_lib_concepts namespace ranges { @@ -869,11 +856,71 @@ namespace ranges template concept range = __detail::__range_impl<_Tp&>; + template + using sentinel_t = decltype(ranges::end(std::declval<_Range&>())); + + template + using iterator_t = decltype(ranges::begin(std::declval<_Range&>())); + + template + using range_value_t = iter_value_t>; + + template + using range_reference_t = iter_reference_t>; + + template + using range_rvalue_reference_t + = iter_rvalue_reference_t>; + + template + using range_difference_t = iter_difference_t>; + + namespace __detail + { + template + concept __forwarding_range = range<_Tp> && __range_impl<_Tp>; + } // namespace __detail + /// [range.sized] The sized_range concept. template concept sized_range = range<_Tp> && requires(_Tp& __t) { ranges::size(__t); }; + template + inline constexpr bool disable_sized_range = false; + + // [range.refinements] + template + concept output_range + = range<_Range> && output_iterator, _Tp>; + + template + concept input_range = range<_Tp> && input_iterator>; + + template + concept forward_range + = input_range<_Tp> && forward_iterator>; + + template + concept bidirectional_range + = forward_range<_Tp> && bidirectional_iterator>; + + template + concept random_access_range + = bidirectional_range<_Tp> && random_access_iterator>; + + template + concept contiguous_range + = random_access_range<_Tp> && contiguous_iterator> + && requires(_Tp& __t) + { + { ranges::data(__t) } -> same_as>>; + }; + + template + concept common_range + = range<_Tp> && same_as, sentinel_t<_Tp>>; + // [range.iter.ops] range iterator operations template @@ -1008,12 +1055,6 @@ namespace ranges } } - template - using iterator_t = decltype(ranges::begin(std::declval<_Range&>())); - - template - using range_difference_t = iter_difference_t>; - template constexpr range_difference_t<_Range> distance(_Range&& __r) diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 333d110b67e..e1bf6eec5d0 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -56,64 +56,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION namespace ranges { // [range.range] The range concept. - // Defined in - // template concept range; - - template - using sentinel_t = decltype(ranges::end(std::declval<_Range&>())); - - template - using range_value_t = iter_value_t>; - - template - using range_reference_t = iter_reference_t>; - - template - using range_rvalue_reference_t - = iter_rvalue_reference_t>; - - namespace __detail - { - template - concept __forwarding_range = range<_Tp> && __range_impl<_Tp>; - } // namespace __detail - // [range.sized] The sized_range concept. - // Defined in - // template concept sized_range; + // Defined in // [range.refinements] - - template - concept output_range - = range<_Range> && output_iterator, _Tp>; - - template - concept input_range = range<_Tp> && input_iterator>; - - template - concept forward_range - = input_range<_Tp> && forward_iterator>; - - template - concept bidirectional_range - = forward_range<_Tp> && bidirectional_iterator>; - - template - concept random_access_range - = bidirectional_range<_Tp> && random_access_iterator>; - - template - concept contiguous_range - = random_access_range<_Tp> && contiguous_iterator> - && requires(_Tp& __t) - { - { ranges::data(__t) } -> same_as>>; - }; - - template - concept common_range - = range<_Tp> && same_as, sentinel_t<_Tp>>; + // Defined in struct view_base { }; diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index fcec22a6c57..c71f8bc3f89 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -45,6 +45,7 @@ #include #include +#if __cpp_lib_concepts namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION @@ -104,7 +105,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: size_t _M_extent_value; }; - } // namespace __detail template @@ -122,21 +122,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return dynamic_extent; } - template - using __is_compatible = is_convertible<_Tp(*)[], _Type(*)[]>; - // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3255. span's array constructor is too strict - template> - using __is_compatible_array = __is_compatible<_Tp>; + template + using __is_compatible_array = __and_< + bool_constant<(_Extent == dynamic_extent || _ArrayExtent == _Extent)>, + __is_array_convertible<_Type, _Tp>>; + + template> + using __is_compatible_iterator = __and_< + bool_constant>, + is_lvalue_reference>, + is_same, remove_cvref_t<_Ref>>, + __is_array_convertible<_Type, remove_reference_t<_Ref>>>; + + template + using __is_compatible_range + = __is_compatible_iterator>; public: // member types using value_type = remove_cv_t<_Type>; using element_type = _Type; - using index_type = size_t; + using size_type = size_t; using reference = element_type&; using const_reference = const element_type&; using pointer = _Type*; @@ -148,168 +156,80 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; using difference_type = ptrdiff_t; - // Official wording has no size_type -- why?? - // using size_type = size_t; // member constants static inline constexpr size_t extent = _Extent; // constructors - template* = nullptr> - constexpr - span() noexcept : _M_extent(0), _M_ptr(nullptr) - { } + constexpr + span() noexcept + requires ((_Extent + 1u) <= 1u) + : _M_extent(0), _M_ptr(nullptr) + { } constexpr span(const span&) noexcept = default; - template>> + template + requires (__is_compatible_array<_Tp, _ArrayExtent>::value) constexpr span(_Tp (&__arr)[_ArrayExtent]) noexcept : span(static_cast(__arr), _ArrayExtent) { } - template>> + template + requires (__is_compatible_array<_Tp, _ArrayExtent>::value) constexpr span(array<_Tp, _ArrayExtent>& __arr) noexcept : span(static_cast(__arr.data()), _ArrayExtent) { } - template>> + template + requires (__is_compatible_array::value) constexpr span(const array<_Tp, _ArrayExtent>& __arr) noexcept : span(static_cast(__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 - 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 = enable_if_t::value>> - using iterator_t = decltype(std::__adl_begin(std::declval<_Rng&>())); - // FIXME: use std::iter_value_t - template - using iter_value_t = typename iterator_traits<_Iter>::value_type; - // FIXME: use std::derived_from concept - template - using derived_from - = __and_, - is_convertible>; - // FIXME: require contiguous_iterator<_Iterator> - template, - typename _Traits = iterator_traits<_Iter>, - typename _Tag = typename _Traits::iterator_category> - using __is_compatible_iterator - = __and_, - is_lvalue_reference<_Ref>, - is_same, remove_cvref_t<_Ref>>, - __is_compatible>>; - - template - using __is_compatible_range - = __is_compatible_iterator>; - public: - template, - __not_<__detail::__is_std_span>>, - __not_<__detail::__is_std_array>>, - __not_>>, - __is_compatible_range<_Range>>, - typename = decltype(std::__adl_data(std::declval<_Range&>()))> + template + requires (_Extent == dynamic_extent) + && (!__detail::__is_std_span>::value) + && (!__detail::__is_std_array>::value) + && (!is_array_v>) + && (__is_compatible_range<_Range>::value) constexpr span(_Range&& __range) - noexcept(noexcept(::std::__adl_data(__range)) - && noexcept(::std::__adl_size(__range))) - : span(::std::__adl_data(__range), ::std::__adl_size(__range)) + noexcept(noexcept(ranges::data(__range)) + && noexcept(ranges::size(__range))) + : span(ranges::data(__range), ranges::size(__range)) { } - template>, - __is_compatible_iterator<_ContiguousIterator>>> + template _Sentinel> + requires (__is_compatible_iterator<_ContiguousIterator>::value) + && (!is_convertible_v<_Sentinel, size_type>) constexpr span(_ContiguousIterator __first, _Sentinel __last) - : _M_extent(static_cast(__last - __first)), + : _M_extent(static_cast(__last - __first)), _M_ptr(std::to_address(__first)) { if (_Extent != dynamic_extent) __glibcxx_assert((__last - __first) == _Extent); } - template>> + template + requires (__is_compatible_iterator<_ContiguousIterator>::value) constexpr - span(_ContiguousIterator __first, index_type __count) + span(_ContiguousIterator __first, size_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 _SizeT = decltype(std::size(std::declval<_Container&>()))> - using __is_compatible_container - = __is_compatible>; - public: - template, - __not_<__detail::__is_std_span>>, - __not_<__detail::__is_std_array>>, - __not_>, - __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, - __not_<__detail::__is_std_span>>, - __not_<__detail::__is_std_array>>, - __not_>, - __is_compatible_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(__last - __first)) - { } -#endif // P1394 - - template, - is_convertible<_OType(*)[], _Type(*)[]>>> + template + requires (_Extent == dynamic_extent || _Extent == _OExtent) + && (__is_array_convertible<_Type, _OType>::value) constexpr span(const span<_OType, _OExtent>& __s) noexcept : _M_extent(__s.size()), _M_ptr(__s.data()) @@ -322,11 +242,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // observers - constexpr index_type + constexpr size_type size() const noexcept { return this->_M_extent._M_extent(); } - constexpr index_type + constexpr size_type size_bytes() const noexcept { return this->_M_extent._M_extent() * sizeof(element_type); } @@ -353,7 +273,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } constexpr reference - operator[](index_type __idx) const noexcept + operator[](size_type __idx) const noexcept { static_assert(extent != 0); __glibcxx_assert(__idx < size()); @@ -412,7 +332,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } constexpr span - first(index_type __count) const noexcept + first(size_type __count) const noexcept { __glibcxx_assert(__count <= size()); return { this->data(), __count }; @@ -430,7 +350,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } constexpr span - last(index_type __count) const noexcept + last(size_type __count) const noexcept { __glibcxx_assert(__count <= size()); return { this->data() + (this->size() - __count), __count }; @@ -465,7 +385,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } constexpr span - 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()); @@ -505,27 +425,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION span(const array<_Type, _ArrayExtent>&) -> span; -#ifdef _GLIBCXX_P1394 - - template - span(_ContiguousIterator, _Sentinel) - -> span::reference>>; + template + span(_Iter, _Sentinel) + -> span>>; template span(_Range &&) - -> span()))>::reference>>; - -#else - - template - span(_Container&) -> span; - - template - span(const _Container&) -> span; - -#endif // P1394 + -> span>>; template inline @@ -574,6 +480,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_END_NAMESPACE_VERSION } // namespace std - +#endif // concepts #endif // C++20 #endif // _GLIBCXX_SPAN diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits index 8e787a994c3..28981d84e76 100644 --- a/libstdc++-v3/include/std/type_traits +++ b/libstdc++-v3/include/std/type_traits @@ -1475,6 +1475,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION }; #pragma GCC diagnostic pop + // helper trait for unique_ptr, shared_ptr, and span + template + using __is_array_convertible + = is_convertible<_FromElementType(*)[], _ToElementType(*)[]>; + // is_nothrow_convertible for C++11 template struct __is_nothrow_convertible -- 2.30.2