From patchwork Thu Nov 21 18:33:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: JeanHeyd Meneide X-Patchwork-Id: 1199101 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-514347-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="UMYkOtSv"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ZjaxmRNy"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47Jp9L4SBDz9sPc for ; Fri, 22 Nov 2019 05:33:41 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=XqwSIg/6BPZ8QnD9AqJ8zOuRpKEoIutqdQeiSNF96Ig868 lH9AozdH2AgfY4R2aQbTbe2P4EPYnTgkZ3zM2GMTGcNCM9hRL7begOF+foetmvNQ F6lOyPFbjdFPa6sgaRkci5VYSv3VP4KxBcePEOuOhDj2tN7ASOeMEG9qPl5Tk= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=n8hCFR7R2fX4Wx4Jrq+P9txkeB4=; b=UMYkOtSvCMzzqbvW91az fJ5gpJVyPR3Tn0lYclhEV7EO8y0swXF/T0wsn4b1Ds2v+og0Qa3nHg3YfNqNGXqm F6G64kkdTikpt4jJVGY2h/41jYOjkdCIcoWDhedn2oVVXRkjkdZ1x+Uhbap/1fTC BxBRpRuWsoK83QhcbzOjIg0= Received: (qmail 27882 invoked by alias); 21 Nov 2019 18:33:33 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 27864 invoked by uid 89); 21 Nov 2019 18:33:33 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-24.8 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.1 spammy=sk:forward, is_same, sk:de07446, range_access.h X-HELO: mail-il1-f180.google.com Received: from mail-il1-f180.google.com (HELO mail-il1-f180.google.com) (209.85.166.180) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 21 Nov 2019 18:33:30 +0000 Received: by mail-il1-f180.google.com with SMTP id r9so4254647ilq.10; Thu, 21 Nov 2019 10:33:30 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:from:date:message-id:subject:to; bh=LwtvLPi6+0Y547TE+iBKfZqXuQaFIykEdM/kzbyG3m8=; b=ZjaxmRNyJ+sD+MwBF5ZjirQzrY8uFi9AVhmi3rnYp2Pr5kQn6HDaEpK0j8fDsIoh/3 w7XRQM2Q/bfuEPrhwJEENXccmeOfjIVHpN9W1QN6TYkH6UVA9MX6DNRe7JTNSpNIk0bh UU/K3vSajRzsG7vJI3TG1QQeAvNiB6vuPgBFEsvwO3Oz6lw5SZngKVxi4psGraq1DzLp VKMGEDlpVMnNSfDFxiUH5xQxdxcXIJaG73YjJeCTRoR0/xoMdW6rTURn9w9jmo6U63af W8Oq6qob31KRBShWWE5x3SUQg6XSVXB7zaat7WJeObJ9S+WCdZiR55ZNADnyxgPNC911 CkCg== MIME-Version: 1.0 From: JeanHeyd Meneide Date: Thu, 21 Nov 2019 13:33:16 -0500 Message-ID: Subject: [PATCH] [RFC] span-v2: using concepts, constraints and ranges:: instead of enable_if To: gcc-patches@gcc.gnu.org, "libstdc++" X-IsSubscribed: yes This is an attempt to use concepts and constraints rather than ranges::. It builds and run the tests I ran on x86_64 Linux decently (albeit I'm still new at doing this). I wanted to get a feel for whether or not this had been done right: Thoughts? diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 6300de9e96d..7f7035ca64e 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -156,6 +156,7 @@ bits_headers = \ ${bits_srcdir}/random.tcc \ ${bits_srcdir}/range_access.h \ ${bits_srcdir}/range_cmp.h \ + ${bits_srcdir}/range_concepts.h \ ${bits_srcdir}/refwrap.h \ ${bits_srcdir}/regex.h \ ${bits_srcdir}/regex.tcc \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index ae4a493ea65..475106ee69b 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -500,6 +500,7 @@ bits_headers = \ ${bits_srcdir}/random.tcc \ ${bits_srcdir}/range_access.h \ ${bits_srcdir}/range_cmp.h \ + ${bits_srcdir}/range_concepts.h \ ${bits_srcdir}/refwrap.h \ ${bits_srcdir}/regex.h \ ${bits_srcdir}/regex.tcc \ diff --git a/libstdc++-v3/include/bits/iterator_concepts.h b/libstdc++-v3/include/bits/iterator_concepts.h index 3843ba5d57f..c4a4e92fed0 100644 --- a/libstdc++-v3/include/bits/iterator_concepts.h +++ b/libstdc++-v3/include/bits/iterator_concepts.h @@ -71,6 +71,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { *__t } -> __can_reference; }; + template + concept __is_compatible_pointer = is_convertible<_RightType(*)[], _LeftType(*)[]>::value; + // FIXME: needed due to PR c++/67704 template<__detail::__dereferenceable _Tp> struct __iter_ref diff --git a/libstdc++-v3/include/bits/range_access.h b/libstdc++-v3/include/bits/range_access.h index de074460c16..66697ffc354 100644 --- a/libstdc++-v3/include/bits/range_access.h +++ b/libstdc++-v3/include/bits/range_access.h @@ -34,6 +34,7 @@ #if __cplusplus >= 201103L #include +#include #include namespace std _GLIBCXX_VISIBILITY(default) @@ -336,19 +337,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,10 +857,68 @@ 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); }; + && 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 @@ -1008,12 +1054,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..a8b27764419 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -43,6 +43,7 @@ #include #include #include +#include /** * @defgroup ranges Ranges @@ -55,66 +56,6 @@ namespace std _GLIBCXX_VISIBILITY(default) _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; - - // [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>>; - struct view_base { }; namespace __detail diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index fcec22a6c57..09864dc8e13 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -105,6 +106,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION size_t _M_extent_value; }; + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3255. span's array constructor is too strict + template + concept __is_compatible_array + = (_Extent == dynamic_extent || _ArrayExtent == _Extent) + && __is_compatible_pointer<_Type, _Tp>; + + template + concept __is_compatible_iterator + = contiguous_iterator<_Iter> + && is_lvalue_reference_v> + && same_as, remove_cvref_t>> + && __is_compatible_pointer<_Type, remove_reference_t>>; + + template + concept __is_compatible_range + = __is_compatible_iterator<_Type, ranges::iterator_t<_Range>>; } // namespace __detail template @@ -122,21 +140,11 @@ _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>; - 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 +164,74 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 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 __detail::__is_compatible_array<_Type, _Extent, _Tp, _ArrayExtent> constexpr span(_Tp (&__arr)[_ArrayExtent]) noexcept : span(static_cast(__arr), _ArrayExtent) { } - template>> + template + requires __detail::__is_compatible_array<_Type, _Extent, _Tp, _ArrayExtent> constexpr span(array<_Tp, _ArrayExtent>& __arr) noexcept : span(static_cast(__arr.data()), _ArrayExtent) { } - template>> + template + requires __detail::__is_compatible_array<_Type, _Extent, const _Tp, _ArrayExtent> 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>::value) + && __detail::__is_compatible_range<_Type, _Range> 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 __detail::__is_compatible_iterator<_Type, _ContiguousIterator> + && (!is_convertible<_Sentinel, size_type>::value) 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 __detail::__is_compatible_iterator<_Type, _ContiguousIterator> 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) + && __detail::__is_compatible_pointer<_Type, _OType> constexpr span(const span<_OType, _OExtent>& __s) noexcept : _M_extent(__s.size()), _M_ptr(__s.data()) @@ -322,11 +244,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 +275,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 +334,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 +352,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 +387,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 +427,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION span(const array<_Type, _ArrayExtent>&) -> span; -#ifdef _GLIBCXX_P1394 - template span(_ContiguousIterator, _Sentinel) - -> span::reference>>; + -> span>>; template span(_Range &&) - -> span()))>::reference>>; - -#else - - template - span(_Container&) -> span; - - template - span(const _Container&) -> span; - -#endif // P1394 + -> span>>; template inline