From 27dada7d06926cc7ef6293fbbf0629f523b49e48 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Mon, 9 Sep 2019 12:12:38 +0100 Subject: [PATCH] Improve constraints for std::span constructors This patch simplifies the constraints on the constructors from arrays by removing the redundant checks that element_type and value_type are convertible to element_type. The incorrect uses of __adl_data in those constructors are removed as well (they should use std::data not std::ranges::data, and the former doesn't use ADL). The range/container constructors are now constrained to exclude all specializations of std::span, not just the current instantiation. The range constructor now also checks s subset of the contiguous_range requirements. All relevant constructor constraints now use the _Require helper in order to short circuit and avoid unnecessary instantiations after the first failed constraint. A new constructor supports initialization from different specializations of std::span, as specified in the C++20 draft. * include/bits/range_access.h (__adl_to_address): Remove. * include/std/span (__is_base_derived_safe_convertible_v): Replace with span::__is_compatible. (__is_std_array_v): Replace with __is_std_array class template and partial specializations. (__is_std_array, __is_std_span): New class templates and partial specializations. (span::__is_compatible): New alias template for SFINAE constraints. (span::span(element_type (&)[N])): Remove redundant constraints. Do not use __adl_data to obtain a pointer. (span::span(array&)): Likewise. (span::span(const array&)): Likewise. [_GLIBCXX_P1394] (span::iter_reference_t, span::iterator_t) (span::iter_value_t, span::derived_from): New alias templates for SFINAE constraints, until the equivalents are supported in and . [_GLIBCXX_P1394] (span::__is_compatible_iterator): New alias template for SFINAE constraints. [_GLIBCXX_P1394] (span::is_compatible_range): New class template for SFINAE constraints. [_GLIBCXX_P1394] (span::span(Range&&)): Improve constraints. [_GLIBCXX_P1394] (span::span(ContiguousIterator, Sentinel)): Likewise. Use std::to_address instead of __adl_to_address. [_GLIBCXX_P1394] (span::span(ContiguousIterator, size_type)): Likewise. [!_GLIBCXX_P1394] (span::__is_compatible_container): New alias template for SFINAE constraints. [!_GLIBCXX_P1394] (span::span(Container&)) (span::span(const Container&)): Improve constraints. [!_GLIBCXX_P1394] (span::span(pointer, size_type)) (span::span(pointer, pointer)): Remove redundant cast of pointer. (span(const span&)): New constructor. From-SVN: r275513 --- libstdc++-v3/ChangeLog | 34 ++++ libstdc++-v3/include/bits/range_access.h | 7 - libstdc++-v3/include/std/span | 214 +++++++++++++---------- 3 files changed, 155 insertions(+), 100 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index e135e850594..0aff148effb 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,37 @@ +2019-09-09 Jonathan Wakely + + * include/bits/range_access.h (__adl_to_address): Remove. + * include/std/span (__is_base_derived_safe_convertible_v): Replace + with span::__is_compatible. + (__is_std_array_v): Replace with __is_std_array class template and + partial specializations. + (__is_std_array, __is_std_span): New class templates and partial + specializations. + (span::__is_compatible): New alias template for SFINAE constraints. + (span::span(element_type (&)[N])): Remove redundant constraints. Do + not use __adl_data to obtain a pointer. + (span::span(array&)): Likewise. + (span::span(const array&)): Likewise. + [_GLIBCXX_P1394] (span::iter_reference_t, span::iterator_t) + (span::iter_value_t, span::derived_from): New alias templates for + SFINAE constraints, until the equivalents are supported in + and . + [_GLIBCXX_P1394] (span::__is_compatible_iterator): New alias template + for SFINAE constraints. + [_GLIBCXX_P1394] (span::is_compatible_range): New class template for + SFINAE constraints. + [_GLIBCXX_P1394] (span::span(Range&&)): Improve constraints. + [_GLIBCXX_P1394] (span::span(ContiguousIterator, Sentinel)): Likewise. + Use std::to_address instead of __adl_to_address. + [_GLIBCXX_P1394] (span::span(ContiguousIterator, size_type)): Likewise. + [!_GLIBCXX_P1394] (span::__is_compatible_container): New alias + template for SFINAE constraints. + [!_GLIBCXX_P1394] (span::span(Container&)) + (span::span(const Container&)): Improve constraints. + [!_GLIBCXX_P1394] (span::span(pointer, size_type)) + (span::span(pointer, pointer)): Remove redundant cast of pointer. + (span(const span&)): New constructor. + 2019-09-06 Jonathan Wakely * include/bits/range_access.h (ssize): Define for C++20. diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h index c5744145590..bc137d7396e 100644 --- a/libstdc++-v3/include/bits/range_access.h +++ b/libstdc++-v3/include/bits/range_access.h @@ -396,13 +396,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto __adl_empty(_Container& __cont) noexcept(noexcept(empty(__cont))) { return empty(__cont); } - -#if defined(_GLIBCXX_P1394) && _GLIBCXX_P1394 - template - constexpr auto - __adl_to_address(_Container& __cont) noexcept(noexcept(to_address(__cont))) - { return to_address(__cont); } -#endif // P1394 and new contiguous_iterator requirements [iterator.concept.contiguous] #endif // C++20 _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index 95d778b104b..1a0d61c1947 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -53,24 +53,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION inline constexpr size_t dynamic_extent = static_cast(-1); + template + class span; + namespace __detail { - template - static constexpr inline bool __is_base_derived_safe_convertible_v - = is_convertible_v<_Element (*)[], _ToElement (*)[]>; + template + struct __is_std_span : false_type { }; + + template + struct __is_std_span> : true_type { }; template - inline constexpr bool __is_std_array_v = false; + struct __is_std_array : false_type { }; template - inline constexpr bool - __is_std_array_v<_GLIBCXX_STD_C::array<_Tp, _Num>> = true; + struct __is_std_array<_GLIBCXX_STD_C::array<_Tp, _Num>> : true_type { }; #ifdef _GLIBCXX_DEBUG template - inline constexpr bool - __is_std_array_v> = true; -#endif // debug/array + struct __is_std_array<__debug::array<_Tp, _Num>> : true_type { }; +#endif template class __extent_storage @@ -119,6 +122,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return dynamic_extent; } + template + using __is_compatible = is_convertible<_Tp(*)[], _Type(*)[]>; + public: // member types using value_type = remove_cv_t<_Type>; @@ -154,41 +160,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION span(const span&) noexcept = default; template()))>, - element_type>>* = nullptr> - constexpr span(element_type (&__arr)[_ArrayExtent]) - noexcept(noexcept(::std::__adl_data(__arr))) - : span(::std::__adl_data(__arr), _ArrayExtent) + enable_if_t<_Extent == dynamic_extent || _ArrayExtent == _Extent>* + = nullptr> + constexpr + span(element_type (&__arr)[_ArrayExtent]) noexcept + : span(static_cast(__arr), _ArrayExtent) { } template&>()))>, - element_type>>* = nullptr> + enable_if_t<_Extent == dynamic_extent || _ArrayExtent == _Extent>* + = nullptr> constexpr - span(array& __arr) - noexcept(noexcept(::std::__adl_data(__arr))) - : span(::std::__adl_data(__arr), _ArrayExtent) + span(array& __arr) noexcept + : span(__arr.data(), _ArrayExtent) { } template&>()))>, - element_type>>* = nullptr> + enable_if_t<_Extent == dynamic_extent || _ArrayExtent == _Extent>* + = nullptr> constexpr - span(const array& __arr) - noexcept(noexcept(::std::__adl_data(__arr))) - : span(::std::__adl_data(__arr), _ArrayExtent) + span(const array& __arr) noexcept + : span(__arr.data(), _ArrayExtent) { } // NOTE: when the time comes, and P1394 - @@ -199,18 +191,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // and keep the crappy #else block // and then cry that NB comments failed C++20... // but maybe for C++23? -#if defined(_GLIBCXX_P1394) && _GLIBCXX_P1394 - template, span> - && !__detail::__is_std_array_v> - && !is_array_v> - && __detail::__is_base_derived_safe_convertible_v< - remove_pointer_t()) - + ::std::__adl_size(::std::declval<_Range&>()))>, - element_type>>* = nullptr> +#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&>()))> constexpr span(_Range&& __range) noexcept(noexcept(::std::__adl_data(__range)) @@ -218,72 +241,77 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : span(::std::__adl_data(__range), ::std::__adl_size(__range)) { } - template - && __detail::__is_base_derived_safe_convertible_v< - remove_reference_t::reference>, - element_type>>* = nullptr> + template>, + __is_compatible_iterator<_ContiguousIterator>>> constexpr span(_ContiguousIterator __first, _Sentinel __last) - : span(::std::move(__first), 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>> constexpr span(_ContiguousIterator __first, index_type __count) - noexcept(noexcept(::std::__adl_to_address(__first))) - : _M_extent(__count), _M_ptr(::std::__adl_to_address(__first)) + 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, span> - && !__detail::__is_std_array_v> - && !is_array_v> - && __detail::__is_base_derived_safe_convertible_v< - remove_pointer_t()) - + ::std::__adl_size(::std::declval<_Container&>()))>, - element_type>>* = nullptr> + typename _DataT = decltype(std::data(std::declval<_Container&>())), + typename _SizeT = decltype(std::size(std::declval<_Container&>()))> + using __is_compatible_container + = __is_compatible>; + + public: + template, + __not_<__detail::__is_std_span<_Container>>, + __not_<__detail::__is_std_array<_Container>>, + __not_>, + __is_compatible_container<_Container>>> constexpr - span(_Container& __range) - noexcept(noexcept(::std::__adl_data(__range)) - && noexcept(::std::__adl_size(__range))) - : span(::std::__adl_data(__range), ::std::__adl_size(__range)) + span(_Container& __cont) + noexcept(noexcept(std::data(__cont)) && noexcept(std::size(__cont))) + : _M_extent(std::size(__cont)), _M_ptr(std::data(__cont)) { } - template, span> - && !__detail::__is_std_array_v> - && !is_array_v> - && __detail::__is_base_derived_safe_convertible_v< - remove_pointer_t()) - + ::std::__adl_size(::std::declval<_Container&>()))>, - element_type>>* = nullptr> - constexpr span(const _Container& __range) - noexcept(noexcept(::std::__adl_data(__range)) - && noexcept(::std::__adl_size(__range))) - : span(::std::__adl_data(__range), ::std::__adl_size(__range)) + template, + __not_<__detail::__is_std_span<_Container>>, + __not_<__detail::__is_std_array<_Container>>, + __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(static_cast(__first)) + : _M_extent(__count), _M_ptr(__first) { __glibcxx_assert(_Extent == dynamic_extent || __count == _Extent); } constexpr span(pointer __first, pointer __last) noexcept - : span(::std::move(__first), static_cast(__last - __first)) + : span(__first, static_cast(__last - __first)) { } #endif // P1394 + template, + is_convertible<_OType(*)[], _Type(*)[]>>> + constexpr + span(const span<_OType, _OExtent>& __s) noexcept + : _M_extent(__s.size()), _M_ptr(__s.data()) + { } + // assignment constexpr span& @@ -474,7 +502,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION span(const array<_Type, _ArrayExtent>&) -> span; -#if defined(_GLIBCXX_P1394) && _GLIBCXX_P1394 +#ifdef _GLIBCXX_P1394 template span(_ContiguousIterator, _Sentinel) -- 2.30.2