Thank you for the review! - I moved the concepts back into the class and changed them to template aliases because class local concepts aren't a thing that works. + They are not inline constexpr bools because that ICE's GCC pretty hard, as you explained to me earlier, so we use ::value in some places rather than _v - I named the alias __is_array_convertible, to match what the intent is, and named the template parameters very explicitly. + I moved it into type_traits, but I didn't change bits/unique_ptr.h or shared_ptr yet because I'm not confident I can do that quickly in one go. + (And it should probably be a different patch anyways, but it should be in the right place when we introduce it here.)
--------- 2019-11-21 JeanHeyd "ThePhD" Meneide <phdoftheho...@gmail.com> * include/std/span: Use concepts and ranges:: calls instead of enable_if and friends. * include/std/ranges: tear basic concepts out and put in range_access.h for "ranges lite" internal header. * include/std/type_traits: __is_array_convertible trait. Is common to unique/shared_ptr as well (preparation for changing unique/shared_ptr soon). * include/bits/range_access.h: Remove __adl_* versions of access functions.
diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h index de074460c16..c0891c2f235 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 <typename _Container> - constexpr auto - __adl_begin(_Container& __cont) noexcept(noexcept(begin(__cont))) - { return begin(__cont); } - - template <typename _Container> - constexpr auto - __adl_data(_Container& __cont) noexcept(noexcept(data(__cont))) - { return data(__cont); } - #ifdef __cpp_lib_concepts namespace ranges { @@ -869,10 +856,70 @@ namespace ranges template<typename _Tp> concept range = __detail::__range_impl<_Tp&>; + template<range _Range> + using sentinel_t = decltype(ranges::end(std::declval<_Range&>())); + + template<range _Range> + using iterator_t = decltype(ranges::begin(std::declval<_Range&>())); + + template<range _Range> + using range_value_t = iter_value_t<iterator_t<_Range>>; + + template<range _Range> + using range_reference_t = iter_reference_t<iterator_t<_Range>>; + + template<range _Range> + using range_rvalue_reference_t + = iter_rvalue_reference_t<iterator_t<_Range>>; + + template<range _Range> + using range_difference_t = iter_difference_t<iterator_t<_Range>>; + + namespace __detail + { + template<typename _Tp> + concept __forwarding_range = range<_Tp> && __range_impl<_Tp>; + } // namespace __detail + /// [range.sized] The sized_range concept. template<typename _Tp> concept sized_range = range<_Tp> && requires(_Tp& __t) { ranges::size(__t); }; + + template<typename> + inline constexpr bool disable_sized_range = false; + + // [range.refinements] + template<typename _Range, typename _Tp> + concept output_range + = range<_Range> && output_iterator<iterator_t<_Range>, _Tp>; + + template<typename _Tp> + concept input_range = range<_Tp> && input_iterator<iterator_t<_Tp>>; + + template<typename _Tp> + concept forward_range + = input_range<_Tp> && forward_iterator<iterator_t<_Tp>>; + + template<typename _Tp> + concept bidirectional_range + = forward_range<_Tp> && bidirectional_iterator<iterator_t<_Tp>>; + + template<typename _Tp> + concept random_access_range + = bidirectional_range<_Tp> && random_access_iterator<iterator_t<_Tp>>; + + template<typename _Tp> + concept contiguous_range + = random_access_range<_Tp> && contiguous_iterator<iterator_t<_Tp>> + && requires(_Tp& __t) + { + { ranges::data(__t) } -> same_as<add_pointer_t<range_reference_t<_Tp>>>; + }; + + template<typename _Tp> + concept common_range + = range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp>>; // [range.iter.ops] range iterator operations @@ -1008,12 +1055,6 @@ namespace ranges } } - template<range _Range> - using iterator_t = decltype(ranges::begin(std::declval<_Range&>())); - - template<range _Range> - using range_difference_t = iter_difference_t<iterator_t<_Range>>; - template<range _Range> 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 <bits/range_iterator.h> - // template<typename> concept range; - - template<range _Range> - using sentinel_t = decltype(ranges::end(std::declval<_Range&>())); - - template<range _Range> - using range_value_t = iter_value_t<iterator_t<_Range>>; - - template<range _Range> - using range_reference_t = iter_reference_t<iterator_t<_Range>>; - - template<range _Range> - using range_rvalue_reference_t - = iter_rvalue_reference_t<iterator_t<_Range>>; - - namespace __detail - { - template<typename _Tp> - concept __forwarding_range = range<_Tp> && __range_impl<_Tp>; - } // namespace __detail - // [range.sized] The sized_range concept. - // Defined in <bits/range_iterator.h> - // template<typename> concept sized_range; + // Defined in <bits/range_access.h> // [range.refinements] - - template<typename _Range, typename _Tp> - concept output_range - = range<_Range> && output_iterator<iterator_t<_Range>, _Tp>; - - template<typename _Tp> - concept input_range = range<_Tp> && input_iterator<iterator_t<_Tp>>; - - template<typename _Tp> - concept forward_range - = input_range<_Tp> && forward_iterator<iterator_t<_Tp>>; - - template<typename _Tp> - concept bidirectional_range - = forward_range<_Tp> && bidirectional_iterator<iterator_t<_Tp>>; - - template<typename _Tp> - concept random_access_range - = bidirectional_range<_Tp> && random_access_iterator<iterator_t<_Tp>>; - - template<typename _Tp> - concept contiguous_range - = random_access_range<_Tp> && contiguous_iterator<iterator_t<_Tp>> - && requires(_Tp& __t) - { - { ranges::data(__t) } -> same_as<add_pointer_t<range_reference_t<_Tp>>>; - }; - - template<typename _Tp> - concept common_range - = range<_Tp> && same_as<iterator_t<_Tp>, sentinel_t<_Tp>>; + // Defined in <bits/range_access.h> struct view_base { }; diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index fcec22a6c57..2717645c406 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -104,7 +104,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: size_t _M_extent_value; }; - } // namespace __detail template<typename _Type, size_t _Extent = dynamic_extent> @@ -122,21 +121,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return dynamic_extent; } - template<typename _Tp> - using __is_compatible = is_convertible<_Tp(*)[], _Type(*)[]>; - // _GLIBCXX_RESOLVE_LIB_DEFECTS // 3255. span's array constructor is too strict - template<typename _Tp, size_t _ArrayExtent, - typename = enable_if_t<_Extent == dynamic_extent - || _ArrayExtent == _Extent>> - using __is_compatible_array = __is_compatible<_Tp>; + template<typename _Tp, size_t _ArrayExtent> + using __is_compatible_array = __and_< + bool_constant<(_Extent == dynamic_extent || _ArrayExtent == _Extent)>, + __is_array_convertible<_Type, _Tp>>; + + template<typename _Iter> + using __is_compatible_iterator = __and_< + bool_constant<contiguous_iterator<_Iter>>, + is_lvalue_reference<iter_reference_t<_Iter>>, + is_same<iter_value_t<_Iter>, remove_cvref_t<iter_reference_t<_Iter>>>, + __is_array_convertible<_Type, remove_reference_t<iter_reference_t<_Iter>>>>; + + template<typename _Range> + using __is_compatible_range + = __is_compatible_iterator<ranges::iterator_t<_Range>>; 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*; @@ -156,160 +163,74 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // constructors - template<bool _DefaultConstructible = (_Extent + 1u) <= 1u, - enable_if_t<_DefaultConstructible>* = 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<typename _Tp, size_t _ArrayExtent, - typename = _Require<__is_compatible_array<_Tp, _ArrayExtent>>> + template<typename _Tp, size_t _ArrayExtent> + requires (__is_compatible_array<_Tp, _ArrayExtent>::value) constexpr span(_Tp (&__arr)[_ArrayExtent]) noexcept : span(static_cast<pointer>(__arr), _ArrayExtent) { } - template<typename _Tp, size_t _ArrayExtent, - typename = _Require<__is_compatible_array<_Tp, _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, - typename = _Require<__is_compatible_array<_Tp, _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) { } - // 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<typename _Iterator> - 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 _Rng, - typename _Rng2 = remove_cvref_t<_Rng>, - typename = enable_if_t<!__detail::__is_std_span<_Rng2>::value>> - using iterator_t = decltype(std::__adl_begin(std::declval<_Rng&>())); - // FIXME: use std::iter_value_t - template<typename _Iter> - using iter_value_t = typename iterator_traits<_Iter>::value_type; - // FIXME: use std::derived_from concept - template<typename _Derived, typename _Base> - using derived_from - = __and_<is_base_of<_Base, _Derived>, - is_convertible<const volatile _Derived*, const volatile _Base*>>; - // FIXME: require contiguous_iterator<_Iterator> - template<typename _Iter, - typename _Ref = iter_reference_t<_Iter>, - typename _Traits = iterator_traits<_Iter>, - typename _Tag = typename _Traits::iterator_category> - using __is_compatible_iterator - = __and_<derived_from<_Tag, random_access_iterator_tag>, - is_lvalue_reference<_Ref>, - is_same<iter_value_t<_Iter>, remove_cvref_t<_Ref>>, - __is_compatible<remove_reference_t<_Ref>>>; - - template<typename _Range> - using __is_compatible_range - = __is_compatible_iterator<iterator_t<_Range>>; - public: - template<typename _Range, typename = _Require< - bool_constant<_Extent == dynamic_extent>, - __not_<__detail::__is_std_span<remove_cvref_t<_Range>>>, - __not_<__detail::__is_std_array<remove_cvref_t<_Range>>>, - __not_<is_array<remove_reference_t<_Range>>>, - __is_compatible_range<_Range>>, - typename = decltype(std::__adl_data(std::declval<_Range&>()))> + template<ranges::contiguous_range _Range> + requires (_Extent == dynamic_extent) + && (!__detail::__is_std_span<remove_cvref_t<_Range>>::value) + && (!__detail::__is_std_array<remove_cvref_t<_Range>>::value) + && (!is_array_v<remove_reference_t<_Range>>) + && (__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<typename _ContiguousIterator, typename _Sentinel, typename - = _Require<__not_<is_convertible<_Sentinel, index_type>>, - __is_compatible_iterator<_ContiguousIterator>>> + template<contiguous_iterator _ContiguousIterator, + sized_sentinel_for<_ContiguousIterator> _Sentinel> + requires (__is_compatible_iterator<_ContiguousIterator>::value) + && (!is_convertible_v<_Sentinel, size_type>) constexpr span(_ContiguousIterator __first, _Sentinel __last) - : _M_extent(static_cast<index_type>(__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); } - template<typename _ContiguousIterator, typename - = _Require<__is_compatible_iterator<_ContiguousIterator>>> + template<contiguous_iterator _ContiguousIterator> + 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 _Container, - typename _DataT = decltype(std::data(std::declval<_Container&>())), - typename _SizeT = decltype(std::size(std::declval<_Container&>()))> - using __is_compatible_container - = __is_compatible<remove_pointer_t<_DataT>>; - public: - template<typename _Container, typename = _Require< - bool_constant<_Extent == dynamic_extent>, - __not_<__detail::__is_std_span<remove_cv_t<_Container>>>, - __not_<__detail::__is_std_array<remove_cv_t<_Container>>>, - __not_<is_array<_Container>>, - __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<typename _Container, typename = _Require< - bool_constant<_Extent == dynamic_extent>, - __not_<__detail::__is_std_span<remove_cv_t<_Container>>>, - __not_<__detail::__is_std_array<remove_cv_t<_Container>>>, - __not_<is_array<_Container>>, - __is_compatible_container<const _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<index_type>(__last - __first)) - { } -#endif // P1394 - - template<typename _OType, size_t _OExtent, typename = _Require< - __bool_constant<_Extent == dynamic_extent || _Extent == _OExtent>, - is_convertible<_OType(*)[], _Type(*)[]>>> + template<typename _OType, size_t _OExtent> + 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 +243,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 +274,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 +333,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } constexpr span<element_type, dynamic_extent> - first(index_type __count) const noexcept + first(size_type __count) const noexcept { __glibcxx_assert(__count <= size()); return { this->data(), __count }; @@ -430,7 +351,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } constexpr span<element_type, dynamic_extent> - 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 +386,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } constexpr span<element_type, dynamic_extent> - 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 +426,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION span(const array<_Type, _ArrayExtent>&) -> span<const _Type, _ArrayExtent>; -#ifdef _GLIBCXX_P1394 - - template<typename _ContiguousIterator, typename _Sentinel> + template<contiguous_iterator _ContiguousIterator, typename _Sentinel> span(_ContiguousIterator, _Sentinel) - -> span<remove_reference_t< - typename iterator_traits<_ContiguousIterator>::reference>>; + -> span<remove_reference_t<ranges::range_reference_t<_ContiguousIterator>>>; template<typename _Range> span(_Range &&) - -> span<remove_reference_t<typename iterator_traits< - decltype(std::__adl_begin(::std::declval<_Range&>()))>::reference>>; - -#else - - template<typename _Container> - span(_Container&) -> span<typename _Container::value_type>; - - template<typename _Container> - span(const _Container&) -> span<const typename _Container::value_type>; - -#endif // P1394 + -> span<remove_reference_t<ranges::range_reference_t<_Range&>>>; template<typename _Type, size_t _Extent> inline 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<T[]>, shared_ptr<T[]>, and span<T, N> + template<typename _ToElementType, typename _FromElementType> + using __is_array_convertible + = is_convertible<_FromElementType(*)[], _ToElementType(*)[]>; + // is_nothrow_convertible for C++11 template<typename _From, typename _To> struct __is_nothrow_convertible