From patchwork Fri Apr 14 04:00:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1768762 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=TA7ylj4A; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PyN6J4mVBz1yXv for ; Fri, 14 Apr 2023 14:01:10 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E48673856962 for ; Fri, 14 Apr 2023 04:01:08 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E48673856962 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1681444868; bh=3q234YHJ6R6x7OQl7LxdtXR3Jj+PrwznrT3sVNPNYC8=; h=To:Cc:Subject:Date:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=TA7ylj4AmG/Jkm8eRK4eNHseIFKlMSVtl0QaW2S7GmVTB5tj3p2TcCO6kaVLmKjTy m6tsczhOQvxPaNG2WpeH06VLziRdop1JyKRokEMhoj0oqFmIrX+q/ONtnMsu3YwmC+ eTUrUFoCA/MGfBFxZCYfRTqwIeFBBf8Bo1Hq+2ZE= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 7F51B3858D39 for ; Fri, 14 Apr 2023 04:00:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7F51B3858D39 Received: from mail-qv1-f69.google.com (mail-qv1-f69.google.com [209.85.219.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-624-CiHjknR7PMCK6hiU4an6Sw-1; Fri, 14 Apr 2023 00:00:46 -0400 X-MC-Unique: CiHjknR7PMCK6hiU4an6Sw-1 Received: by mail-qv1-f69.google.com with SMTP id o14-20020a0cc38e000000b005e62747d93aso10941069qvi.11 for ; Thu, 13 Apr 2023 21:00:46 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681444845; x=1684036845; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=3q234YHJ6R6x7OQl7LxdtXR3Jj+PrwznrT3sVNPNYC8=; b=L+nt9e3kpuEZbnkJwiP02M0tpSCyPMTSBA/tLNxIyraZL9OINjzCd4kWXFl12ew4H5 mmb6y6cxk6WeHM7CcoF8SP6jvxecNU/s9gpXlY9GFarzPVwJOE7zydx+fTTOfUIAi57N W6bFPeLSC5ypr5aFGAlekdc77Yuk9Gd9/OeRnATkdGxRVoa1h1kqE7FjfZBqFB+10J2m 1sJq7CG/I6iuf58x1/soixbgWaiw9X6X3G/mgTi2/PZJSZbnnb3yUHPC7q+oJZdDuD2P B9d3aw6fgmWhE6H5RlAVAW+U2wObPf3CtdQ826kXJP94u8iHZxVRQxgxCL494KIHJEge yQZg== X-Gm-Message-State: AAQBX9eKEab1oy256rOcy8kIAEzy4uscirOBVrKPu3D19gNr/m/N74nV 57iQPZjn9UzobAFfgDTy5Vw+S3cbmqMSp2UaSMkWWGuqEFQXH4n9XQYZrIAfn4C81UeJnYAEbAe cUzVw0rhby5KmQ37h/QT3C0ftV1UymIT4GKEaxkTemd0mZtykdrSSSomei1YWdtrTbYNAwziWGn o= X-Received: by 2002:a05:6214:1c86:b0:5ef:4435:f1cd with SMTP id ib6-20020a0562141c8600b005ef4435f1cdmr1006733qvb.27.1681444845062; Thu, 13 Apr 2023 21:00:45 -0700 (PDT) X-Google-Smtp-Source: AKy350ZBHNg4jyttTX6i4k4ITg5dwP0QojfRBS6qYpTuwyv3RE8WdjTPyke4loM0dDOKpQDB5BzERg== X-Received: by 2002:a05:6214:1c86:b0:5ef:4435:f1cd with SMTP id ib6-20020a0562141c8600b005ef4435f1cdmr1006709qvb.27.1681444844687; Thu, 13 Apr 2023 21:00:44 -0700 (PDT) Received: from localhost.localdomain (ool-457670bb.dyn.optonline.net. [69.118.112.187]) by smtp.gmail.com with ESMTPSA id dp20-20020a05621409d400b005dd8b9345d6sm871169qvb.110.2023.04.13.21.00.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Apr 2023 21:00:44 -0700 (PDT) To: gcc-patches@gcc.gnu.org Cc: libstdc++@gcc.gnu.org, Patrick Palka Subject: [PATCH 1/2] libstdc++: Move down definitions of ranges::cbegin/cend/cetc Date: Fri, 14 Apr 2023 00:00:41 -0400 Message-ID: <20230414040042.1498825-1-ppalka@redhat.com> X-Mailer: git-send-email 2.40.0.335.g9857273be0 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Patrick Palka via Gcc-patches From: Patrick Palka Reply-To: Patrick Palka Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This moves down the definitions of the const range access CPOs to after the definition of input_range in preparation for implementing P2287R4 which redefines these CPOs in a way that indirectly uses input_range. tested on x86_64-pc-linux-gnu, does this look OK for trunk? libstdc++-v3/ChangeLog: * include/bits/ranges_base.h (__cust_access::__as_const) (__cust_access::_CBegin, __cust::cbegin) (__cust_access::_CEnd, __cust::cend) (__cust_access::_CRBegin, __cust::crbegin) (__cust_access::_CREnd, __cust::crend) (__cust_access::_CData, __cust::cdata): Move down definitions to shortly after the definition of input_range. --- libstdc++-v3/include/bits/ranges_base.h | 174 +++++++++++++----------- 1 file changed, 91 insertions(+), 83 deletions(-) diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index 86952b34096..c89cb3e976a 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -177,45 +177,6 @@ namespace ranges } }; - // If _To is an lvalue-reference, return const _Tp&, otherwise const _Tp&&. - template - constexpr decltype(auto) - __as_const(_Tp& __t) noexcept - { - static_assert(std::is_same_v<_To&, _Tp&>); - - if constexpr (is_lvalue_reference_v<_To>) - return const_cast(__t); - else - return static_cast(__t); - } - - struct _CBegin - { - template - [[nodiscard]] - constexpr auto - operator()(_Tp&& __e) const - noexcept(noexcept(_Begin{}(__cust_access::__as_const<_Tp>(__e)))) - requires requires { _Begin{}(__cust_access::__as_const<_Tp>(__e)); } - { - return _Begin{}(__cust_access::__as_const<_Tp>(__e)); - } - }; - - struct _CEnd final - { - template - [[nodiscard]] - constexpr auto - operator()(_Tp&& __e) const - noexcept(noexcept(_End{}(__cust_access::__as_const<_Tp>(__e)))) - requires requires { _End{}(__cust_access::__as_const<_Tp>(__e)); } - { - return _End{}(__cust_access::__as_const<_Tp>(__e)); - } - }; - template concept __member_rbegin = requires(_Tp& __t) { @@ -337,32 +298,6 @@ namespace ranges } }; - struct _CRBegin - { - template - [[nodiscard]] - constexpr auto - operator()(_Tp&& __e) const - noexcept(noexcept(_RBegin{}(__cust_access::__as_const<_Tp>(__e)))) - requires requires { _RBegin{}(__cust_access::__as_const<_Tp>(__e)); } - { - return _RBegin{}(__cust_access::__as_const<_Tp>(__e)); - } - }; - - struct _CREnd - { - template - [[nodiscard]] - constexpr auto - operator()(_Tp&& __e) const - noexcept(noexcept(_REnd{}(__cust_access::__as_const<_Tp>(__e)))) - requires requires { _REnd{}(__cust_access::__as_const<_Tp>(__e)); } - { - return _REnd{}(__cust_access::__as_const<_Tp>(__e)); - } - }; - template concept __member_size = !disable_sized_range> && requires(_Tp& __t) @@ -547,36 +482,18 @@ namespace ranges } }; - struct _CData - { - template - [[nodiscard]] - constexpr auto - operator()(_Tp&& __e) const - noexcept(noexcept(_Data{}(__cust_access::__as_const<_Tp>(__e)))) - requires requires { _Data{}(__cust_access::__as_const<_Tp>(__e)); } - { - return _Data{}(__cust_access::__as_const<_Tp>(__e)); - } - }; - } // namespace __cust_access inline namespace __cust { inline constexpr __cust_access::_Begin begin{}; inline constexpr __cust_access::_End end{}; - inline constexpr __cust_access::_CBegin cbegin{}; - inline constexpr __cust_access::_CEnd cend{}; inline constexpr __cust_access::_RBegin rbegin{}; inline constexpr __cust_access::_REnd rend{}; - inline constexpr __cust_access::_CRBegin crbegin{}; - inline constexpr __cust_access::_CREnd crend{}; inline constexpr __cust_access::_Size size{}; inline constexpr __cust_access::_SSize ssize{}; inline constexpr __cust_access::_Empty empty{}; inline constexpr __cust_access::_Data data{}; - inline constexpr __cust_access::_CData cdata{}; } /// [range.range] The range concept. @@ -690,6 +607,97 @@ namespace ranges concept common_range = range<_Tp> && same_as, sentinel_t<_Tp>>; + namespace __cust_access + { + // If _To is an lvalue-reference, return const _Tp&, otherwise const _Tp&&. + template + constexpr decltype(auto) + __as_const(_Tp& __t) noexcept + { + static_assert(std::is_same_v<_To&, _Tp&>); + + if constexpr (is_lvalue_reference_v<_To>) + return const_cast(__t); + else + return static_cast(__t); + } + + struct _CBegin + { + template + [[nodiscard]] + constexpr auto + operator()(_Tp&& __e) const + noexcept(noexcept(_Begin{}(__cust_access::__as_const<_Tp>(__e)))) + requires requires { _Begin{}(__cust_access::__as_const<_Tp>(__e)); } + { + return _Begin{}(__cust_access::__as_const<_Tp>(__e)); + } + }; + + struct _CEnd final + { + template + [[nodiscard]] + constexpr auto + operator()(_Tp&& __e) const + noexcept(noexcept(_End{}(__cust_access::__as_const<_Tp>(__e)))) + requires requires { _End{}(__cust_access::__as_const<_Tp>(__e)); } + { + return _End{}(__cust_access::__as_const<_Tp>(__e)); + } + }; + + struct _CRBegin + { + template + [[nodiscard]] + constexpr auto + operator()(_Tp&& __e) const + noexcept(noexcept(_RBegin{}(__cust_access::__as_const<_Tp>(__e)))) + requires requires { _RBegin{}(__cust_access::__as_const<_Tp>(__e)); } + { + return _RBegin{}(__cust_access::__as_const<_Tp>(__e)); + } + }; + + struct _CREnd + { + template + [[nodiscard]] + constexpr auto + operator()(_Tp&& __e) const + noexcept(noexcept(_REnd{}(__cust_access::__as_const<_Tp>(__e)))) + requires requires { _REnd{}(__cust_access::__as_const<_Tp>(__e)); } + { + return _REnd{}(__cust_access::__as_const<_Tp>(__e)); + } + }; + + struct _CData + { + template + [[nodiscard]] + constexpr auto + operator()(_Tp&& __e) const + noexcept(noexcept(_Data{}(__cust_access::__as_const<_Tp>(__e)))) + requires requires { _Data{}(__cust_access::__as_const<_Tp>(__e)); } + { + return _Data{}(__cust_access::__as_const<_Tp>(__e)); + } + }; + + } // namespace __cust_access + + inline namespace __cust + { + inline constexpr __cust_access::_CBegin cbegin{}; + inline constexpr __cust_access::_CEnd cend{}; + inline constexpr __cust_access::_CRBegin crbegin{}; + inline constexpr __cust_access::_CREnd crend{}; + inline constexpr __cust_access::_CData cdata{}; + } + namespace __detail { template From patchwork Fri Apr 14 04:00:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1768764 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=wX/KAWqC; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4PyN6b4rHfz1yXv for ; Fri, 14 Apr 2023 14:01:27 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 33714385380A for ; Fri, 14 Apr 2023 04:01:25 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 33714385380A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1681444885; bh=KsSXilyYGK8Yp0BC1Oijk1vAJk4A5B25uVYnoKgt3xM=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=wX/KAWqC1r5R2zQFVoW8wX0mhubs9R5Lj0Fuw8P5xliQ2O8VqeVxXyE1wJ4p+oUyg TRMUxAnHl4Xd0J9quhkfBW3O3lnzDrUjWHJvd6nkZeJSKZPcqTeCsTbkgL/jSyDm8H SaBumLGRVD/3tJgWRXAKtwaUjOUJjHCs+U1Mm6hU= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id EC1313858C30 for ; Fri, 14 Apr 2023 04:00:49 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org EC1313858C30 Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-596-K25for8vNwewqwXfaUZS5g-1; Fri, 14 Apr 2023 00:00:48 -0400 X-MC-Unique: K25for8vNwewqwXfaUZS5g-1 Received: by mail-qt1-f198.google.com with SMTP id e8-20020a05622a110800b003e4e915a164so7985837qty.4 for ; Thu, 13 Apr 2023 21:00:48 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681444847; x=1684036847; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=KsSXilyYGK8Yp0BC1Oijk1vAJk4A5B25uVYnoKgt3xM=; b=GM8UC7Joq/etgQZGOguvwtH+e+c/IPVNjOHVaHw200Yn8kFRHw6KCez1b1ir8XfJfc dIjPcDAitRicEI2Z4oN/qKZSzfUpFOi59zppJv78ULZ0ZwLWI8gQoBG0kgvlga6+/1Cd V/8KgS6oc87WeIN+udbkc4sLq2YKEl/cgmGIhaf2V0eTwXpMCOnSgkw5HCIVfkoaNDz/ +gduC4Cw6ehnT02u8K+Lmf/jZFa77JZVjEslzdxigam17ajgJIH2W95sKW2Xq26GwKYA hyhyDcNifQ5+9WuJQF6GuoCiNO9V4rHec7XtJVV+HAW6u/mtEWbdgPewAiIEJQgmx5Ts ePYA== X-Gm-Message-State: AAQBX9eui7EBhW/nMKDH7wOa7YRhdsEDl5THZu7l29j+81xqX4OV2dyQ o7yUeowTjcG73oxMk1LgGKdprPLOpjP+iKkaOU26ja4CGhUcMcZH8fPOAFmyhkd5hCUnUkDGG8h ZGvxyT7Bi9GOiWoc6zzQlhSF52Xba/d8INJY9wZIBLp6Ihigj7gOrvRNKVg6RQFXlZyH0NoSnNW Y= X-Received: by 2002:a05:6214:cab:b0:56f:820:6703 with SMTP id s11-20020a0562140cab00b0056f08206703mr1481924qvs.43.1681444846992; Thu, 13 Apr 2023 21:00:46 -0700 (PDT) X-Google-Smtp-Source: AKy350bOb+E9vxCVrGRthwceQpzvNMUssw4Y+wo0DTPowqc5UxaMNNzEXiZixAM8lkJjQZ1dB1WG5A== X-Received: by 2002:a05:6214:cab:b0:56f:820:6703 with SMTP id s11-20020a0562140cab00b0056f08206703mr1481873qvs.43.1681444846345; Thu, 13 Apr 2023 21:00:46 -0700 (PDT) Received: from localhost.localdomain (ool-457670bb.dyn.optonline.net. [69.118.112.187]) by smtp.gmail.com with ESMTPSA id dp20-20020a05621409d400b005dd8b9345d6sm871169qvb.110.2023.04.13.21.00.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 13 Apr 2023 21:00:45 -0700 (PDT) To: gcc-patches@gcc.gnu.org Cc: libstdc++@gcc.gnu.org, Patrick Palka Subject: [PATCH 2/2] libstdc++: Implement P2278R4 "cbegin should always return a constant iterator" Date: Fri, 14 Apr 2023 00:00:42 -0400 Message-ID: <20230414040042.1498825-2-ppalka@redhat.com> X-Mailer: git-send-email 2.40.0.335.g9857273be0 In-Reply-To: <20230414040042.1498825-1-ppalka@redhat.com> References: <20230414040042.1498825-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-14.0 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Patrick Palka via Gcc-patches From: Patrick Palka Reply-To: Patrick Palka Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" This also implements the approved follow-up LWG issues 3765, 3766, 3769, 3770, 3811, 3850, 3853, 3862 and 3872. Tested on x86_64-pc-linux-gnu, does this look OK for trunk? libstdc++-v3/ChangeLog: * include/bits/ranges_base.h (const_iterator_t): Define for C++23. (const_sentinel_t): Likewise. (range_const_reference_t): Likewise. (constant_range): Likewise. (__cust_access::__possibly_const_range): Likewise, replacing ... (__cust_access::__as_const): ... this. (__cust_access::_CBegin::operator()): Redefine for C++23 as per P2278R4. (__cust_access::_CEnd::operator()): Likewise. (__cust_access::_CRBegin::operator()): Likewise. (__cust_access::_CREnd::operator()): Likewise. (__cust_access::_CData::operator()): Likewise. (__cust_access::_CData::__as_const_pointer): Define for C++23 * include/bits/ranges_util.h (ranges::__detail::__different_from): Make it an alias of std::__detail::__different_from. (view_interface::cbegin): Define for C++23. (view_interface::cend): Likewise. * include/bits/stl_iterator.h (__detail::__different_from): Define. (iter_const_reference_t): Define for C++23. (__detail::__constant_iterator): Likewise. (__detail::__is_const_iterator): Likewise. (__detail::__not_a_const_iterator: Likewise. (__detail::__iter_const_rvalue_reference_t): Likewise. (__detail::__basic_const_iter_cat):: Likewise. (const_iterator): Likewise. (__detail::__const_sentinel): Likewise. (const_sentinel): Likewise. (basic_const_iterator): Likewise. (common_type, _Up>): Likewise. (common_type<_Up, basic_const_iterator<_Tp>>): Likewise. (common_type, basic_const_iterator>): Likewise. (make_const_iterator): Define for C++23. (make_const_sentinel): Likewise. * include/std/ranges (__cpp_lib_ranges_as_const): Likewise. (as_const_view): Likewise. (enable_borrowed_range): Likewise. (views::__detail::__is_ref_view): Likewise. (views::__detail::__can_is_const_view): Likewise. (views::_AsConst, views::as_const): Likewise. * include/std/span (span::const_iterator): Likewise. (span::const_reverse_iterator): Likewise. (span::cbegin): Likewise. (span::cend): Likewise. (span::crbegin): Likewise. (span::crend): Likewise. * include/std/version (__cpp_lib_ranges_as_const): Likewise. * testsuite/std/ranges/adaptors/join.cc (test06): Adjust to behave independently of C++20 vs C++23. * testsuite/std/ranges/version_c++23.cc: Verify value of __cpp_lib_ranges_as_const macro. * testsuite/24_iterators/const_iterator/1.cc: New test. * testsuite/std/ranges/adaptors/as_const/1.cc: New test. --- libstdc++-v3/include/bits/ranges_base.h | 99 +++++ libstdc++-v3/include/bits/ranges_util.h | 22 +- libstdc++-v3/include/bits/stl_iterator.h | 366 ++++++++++++++++++ libstdc++-v3/include/std/ranges | 106 +++++ libstdc++-v3/include/std/span | 22 ++ libstdc++-v3/include/std/version | 1 + .../24_iterators/const_iterator/1.cc | 140 +++++++ .../std/ranges/adaptors/as_const/1.cc | 64 +++ .../testsuite/std/ranges/adaptors/join.cc | 5 +- .../testsuite/std/ranges/version_c++23.cc | 4 + 10 files changed, 824 insertions(+), 5 deletions(-) create mode 100644 libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h index c89cb3e976a..b3144bbae4d 100644 --- a/libstdc++-v3/include/bits/ranges_base.h +++ b/libstdc++-v3/include/bits/ranges_base.h @@ -515,6 +515,17 @@ namespace ranges template using sentinel_t = decltype(ranges::end(std::declval<_Range&>())); +#if __cplusplus > 202002L + template + using const_iterator_t = const_iterator>; + + template + using const_sentinel_t = const_sentinel>; + + template + using range_const_reference_t = iter_const_reference_t>; +#endif + template using range_difference_t = iter_difference_t>; @@ -607,8 +618,25 @@ namespace ranges concept common_range = range<_Tp> && same_as, sentinel_t<_Tp>>; +#if __cplusplus > 202002L + template + concept constant_range + = input_range<_Tp> && std::__detail::__constant_iterator>; +#endif + namespace __cust_access { +#if __cplusplus > 202020L + template + constexpr auto& + __possibly_const_range(_Range& __r) noexcept + { + if constexpr (constant_range && !constant_range<_Range>) + return const_cast(__r); + else + return __r; + } +#else // If _To is an lvalue-reference, return const _Tp&, otherwise const _Tp&&. template constexpr decltype(auto) @@ -621,9 +649,23 @@ namespace ranges else return static_cast(__t); } +#endif struct _CBegin { +#if __cplusplus > 202002L + template<__maybe_borrowed_range _Tp> + constexpr auto + operator() [[nodiscard]] (_Tp&& __t) const + noexcept(noexcept(std::make_const_iterator + (ranges::begin(__cust_access::__possibly_const_range(__t))))) + requires requires { std::make_const_iterator + (ranges::begin(__cust_access::__possibly_const_range(__t))); } + { + auto& __r = __cust_access::__possibly_const_range(__t); + return const_iterator_t(ranges::begin(__r)); + } +#else template [[nodiscard]] constexpr auto @@ -633,10 +675,24 @@ namespace ranges { return _Begin{}(__cust_access::__as_const<_Tp>(__e)); } +#endif }; struct _CEnd final { +#if __cplusplus > 202002L + template<__maybe_borrowed_range _Tp> + constexpr auto + operator() [[nodiscard]] (_Tp&& __t) const + noexcept(noexcept(std::make_const_sentinel + (ranges::end(__cust_access::__possibly_const_range(__t))))) + requires requires { std::make_const_sentinel + (ranges::end(__cust_access::__possibly_const_range(__t))); } + { + auto& __r = __cust_access::__possibly_const_range(__t); + return const_sentinel_t(ranges::end(__r)); + } +#else template [[nodiscard]] constexpr auto @@ -646,10 +702,24 @@ namespace ranges { return _End{}(__cust_access::__as_const<_Tp>(__e)); } +#endif }; struct _CRBegin { +#if __cplusplus > 202002L + template<__maybe_borrowed_range _Tp> + constexpr auto + operator() [[nodiscard]] (_Tp&& __t) const + noexcept(noexcept(std::make_const_iterator + (ranges::rbegin(__cust_access::__possibly_const_range(__t))))) + requires requires { std::make_const_iterator + (ranges::rbegin(__cust_access::__possibly_const_range(__t))); } + { + auto& __r = __cust_access::__possibly_const_range(__t); + return const_iterator(ranges::rbegin(__r)); + } +#else template [[nodiscard]] constexpr auto @@ -659,10 +729,24 @@ namespace ranges { return _RBegin{}(__cust_access::__as_const<_Tp>(__e)); } +#endif }; struct _CREnd { +#if __cplusplus > 202002L + template<__maybe_borrowed_range _Tp> + constexpr auto + operator() [[nodiscard]] (_Tp&& __t) const + noexcept(noexcept(std::make_const_sentinel + (ranges::rend(__cust_access::__possibly_const_range(__t))))) + requires requires { std::make_const_sentinel + (ranges::rend(__cust_access::__possibly_const_range(__t))); } + { + auto& __r = __cust_access::__possibly_const_range(__t); + return const_sentinel(ranges::rend(__r)); + } +#else template [[nodiscard]] constexpr auto @@ -672,10 +756,24 @@ namespace ranges { return _REnd{}(__cust_access::__as_const<_Tp>(__e)); } +#endif }; struct _CData { +#if __cplusplus > 202002L + template + static constexpr auto + __as_const_pointer(const _Tp* __p) noexcept + { return __p; } + + template<__maybe_borrowed_range _Tp> + constexpr auto + operator() [[nodiscard]] (_Tp&& __t) const + noexcept(noexcept(ranges::data(__cust_access::__possibly_const_range(__t)))) + requires requires { ranges::data(__cust_access::__possibly_const_range(__t)); } + { return __as_const_pointer(ranges::data(__cust_access::__possibly_const_range(__t))); } +#else template [[nodiscard]] constexpr auto @@ -685,6 +783,7 @@ namespace ranges { return _Data{}(__cust_access::__as_const<_Tp>(__e)); } +#endif }; } // namespace __cust_access diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h index 880a0ce0143..f7e3538af97 100644 --- a/libstdc++-v3/include/bits/ranges_util.h +++ b/libstdc++-v3/include/bits/ranges_util.h @@ -53,9 +53,7 @@ namespace ranges concept __has_arrow = input_iterator<_It> && (is_pointer_v<_It> || requires(_It __it) { __it.operator->(); }); - template - concept __different_from - = !same_as, remove_cvref_t<_Up>>; + using std::__detail::__different_from; } // namespace __detail /// The ranges::view_interface class template @@ -192,6 +190,24 @@ namespace ranges constexpr decltype(auto) operator[](range_difference_t<_Range> __n) const { return ranges::begin(_M_derived())[__n]; } + +#if __cplusplus > 202002L + constexpr auto + cbegin() requires input_range<_Derived> + { return ranges::cbegin(_M_derived()); } + + constexpr auto + cbegin() const requires input_range + { return ranges::cbegin(_M_derived()); } + + constexpr auto + cend() requires input_range<_Derived> + { return ranges::cend(_M_derived()); } + + constexpr auto + cend() const requires input_range + { return ranges::cend(_M_derived()); } +#endif }; namespace __detail diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index a6a09dbac16..0974d735328 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -102,6 +102,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template using __clamp_iter_cat = __conditional_t, _Limit, _Otherwise>; + + template + concept __different_from + = !same_as, remove_cvref_t<_Up>>; } #endif @@ -2578,6 +2582,368 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION add_pointer_t>, void>; }; + +#if __cplusplus > 202020L + template + using iter_const_reference_t + = common_reference_t&&, iter_reference_t<_It>>; + + template class basic_const_iterator; + + namespace __detail + { + template + concept __constant_iterator = input_iterator<_It> + && same_as, iter_reference_t<_It>>; + + template + inline constexpr bool __is_const_iterator = false; + + template + inline constexpr bool __is_const_iterator> = true; + + template + concept __not_a_const_iterator = !__is_const_iterator<_Tp>; + + template + using __iter_const_rvalue_reference_t + = common_reference_t&&, iter_rvalue_reference_t<_It>>; + + template + struct __basic_const_iterator_iter_cat + { }; + + template + struct __basic_const_iterator_iter_cat<_It> + { using iterator_category = iterator_traits<_It>::iterator_category; }; + } // namespace detail + + template + using const_iterator + = __conditional_t<__detail::__constant_iterator<_It>, _It, basic_const_iterator<_It>>; + + namespace __detail + { + template + struct __const_sentinel + { using type = _Sent; }; + + template + struct __const_sentinel<_Sent> + { using type = const_iterator<_Sent>; }; + } // namespace __detail + + template + using const_sentinel = typename __detail::__const_sentinel<_Sent>::type; + + template + class basic_const_iterator : public __detail::__basic_const_iterator_iter_cat<_It> + { + _It _M_current = _It(); + using __reference = iter_const_reference_t<_It>; + using __rvalue_reference = __detail::__iter_const_rvalue_reference_t<_It>; + + static auto + _S_iter_concept() + { + if constexpr (contiguous_iterator<_It>) + return contiguous_iterator_tag{}; + else if constexpr (random_access_iterator<_It>) + return random_access_iterator_tag{}; + else if constexpr (bidirectional_iterator<_It>) + return bidirectional_iterator_tag{}; + else if constexpr (forward_iterator<_It>) + return forward_iterator_tag{}; + else + return input_iterator_tag{}; + } + + template friend class basic_const_iterator; + + public: + using iterator_concept = decltype(_S_iter_concept()); + using value_type = iter_value_t<_It>; + using difference_type = iter_difference_t<_It>; + + basic_const_iterator() requires default_initializable<_It> = default; + + constexpr + basic_const_iterator(_It __current) + noexcept(is_nothrow_move_constructible_v<_It>) + : _M_current(std::move(__current)) + { } + + template _It2> + constexpr + basic_const_iterator(basic_const_iterator<_It2> __current) + noexcept(is_nothrow_constructible_v<_It, _It2>) + : _M_current(std::move(__current._M_current)) + { } + + template<__detail::__different_from _Tp> + requires convertible_to<_Tp, _It> + constexpr + basic_const_iterator(_Tp&& __current) + noexcept(is_nothrow_constructible_v<_It, _Tp>) + : _M_current(std::forward<_Tp>(__current)) + { } + + constexpr const _It& + base() const & noexcept + { return _M_current; } + + constexpr _It + base() && + noexcept(is_nothrow_move_constructible_v<_It>) + { return std::move(_M_current); } + + constexpr __reference + operator*() const + noexcept(noexcept(static_cast<__reference>(*_M_current))) + { return static_cast<__reference>(*_M_current); } + + constexpr const auto* + operator->() const + noexcept(contiguous_iterator<_It> || noexcept(*_M_current)) + requires is_lvalue_reference_v> + && same_as>, value_type> + { + if constexpr (contiguous_iterator<_It>) + return std::to_address(_M_current); + else + return std::__addressof(*_M_current); + } + + constexpr basic_const_iterator& + operator++() + noexcept(noexcept(++_M_current)) + { + ++_M_current; + return *this; + } + + constexpr void + operator++(int) + noexcept(noexcept(++_M_current)) + { ++_M_current; } + + constexpr basic_const_iterator + operator++(int) + noexcept(noexcept(++*this) && is_nothrow_copy_constructible_v) + requires forward_iterator<_It> + { + auto __tmp = *this; + ++*this; + return __tmp; + } + + constexpr basic_const_iterator& + operator--() + noexcept(noexcept(--_M_current)) + requires bidirectional_iterator<_It> + { + --_M_current; + return *this; + } + + constexpr basic_const_iterator + operator--(int) + noexcept(noexcept(--*this) && is_nothrow_copy_constructible_v) + requires bidirectional_iterator<_It> + { + auto __tmp = *this; + --*this; + return __tmp; + } + + constexpr basic_const_iterator& + operator+=(difference_type __n) + noexcept(noexcept(_M_current += __n)) + requires random_access_iterator<_It> + { + _M_current += __n; + return *this; + } + + constexpr basic_const_iterator& + operator-=(difference_type __n) + noexcept(noexcept(_M_current -= __n)) + requires random_access_iterator<_It> + { + _M_current -= __n; + return *this; + } + + constexpr __reference + operator[](difference_type __n) const + noexcept(noexcept(static_cast<__reference>(_M_current[__n]))) + requires random_access_iterator<_It> + { return static_cast<__reference>(_M_current[__n]); } + + template _Sent> + constexpr bool + operator==(const _Sent& __s) const + noexcept(noexcept(_M_current == __s)) + { return _M_current == __s; } + + constexpr bool + operator<(const basic_const_iterator& __y) const + noexcept(noexcept(_M_current < __y._M_current)) + requires random_access_iterator<_It> + { return _M_current < __y._M_current; } + + constexpr bool + operator>(const basic_const_iterator& __y) const + noexcept(noexcept(_M_current > __y._M_current)) + requires random_access_iterator<_It> + { return _M_current > __y._M_current; } + + constexpr bool + operator<=(const basic_const_iterator& __y) const + noexcept(noexcept(_M_current <= __y._M_current)) + requires random_access_iterator<_It> + { return _M_current <= __y._M_current; } + + constexpr bool + operator>=(const basic_const_iterator& __y) const + noexcept(noexcept(_M_current >= __y._M_current)) + requires random_access_iterator<_It> + { return _M_current >= __y._M_current; } + + constexpr auto + operator<=>(const basic_const_iterator& __y) const + noexcept(noexcept(_M_current <=> __y._M_current)) + requires random_access_iterator<_It> && three_way_comparable<_It> + { return _M_current <=> __y._M_current; } + + template<__detail::__different_from _It2> + constexpr bool + operator<(const _It2& __y) const + noexcept(noexcept(_M_current < __y)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return _M_current < __y; } + + template<__detail::__different_from _It2> + constexpr bool + operator>(const _It2& __y) const + noexcept(noexcept(_M_current > __y)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return _M_current > __y; } + + template<__detail::__different_from _It2> + constexpr bool + operator<=(const _It2& __y) const + noexcept(noexcept(_M_current <= __y)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return _M_current <= __y; } + + template<__detail::__different_from _It2> + constexpr bool + operator>=(const _It2& __y) const + noexcept(noexcept(_M_current >= __y)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return _M_current >= __y; } + + template<__detail::__different_from _It2> + constexpr auto + operator<=>(const _It2& __y) const + noexcept(noexcept(_M_current <=> __y)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + && three_way_comparable_with<_It, _It2> + { return _M_current <=> __y; } + + template<__detail::__not_a_const_iterator _It2> + friend constexpr bool + operator<(const _It2& __x, const basic_const_iterator& __y) + noexcept(noexcept(__x < __y._M_current)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return __x < __y._M_current; } + + template<__detail::__not_a_const_iterator _It2> + friend constexpr bool + operator>(const _It2& __x, const basic_const_iterator& __y) + noexcept(noexcept(__x > __y._M_current)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return __x > __y._M_current; } + + template<__detail::__not_a_const_iterator _It2> + friend constexpr bool + operator<=(const _It2& __x, const basic_const_iterator& __y) + noexcept(noexcept(__x <= __y._M_current)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return __x <= __y._M_current; } + + template<__detail::__not_a_const_iterator _It2> + friend constexpr bool + operator>=(const _It2& __x, const basic_const_iterator& __y) + noexcept(noexcept(__x >= __y._M_current)) + requires random_access_iterator<_It> && totally_ordered_with<_It, _It2> + { return __x >= __y._M_current; } + + friend constexpr basic_const_iterator + operator+(const basic_const_iterator& __i, difference_type __n) + noexcept(noexcept(basic_const_iterator(__i._M_current + __n))) + requires random_access_iterator<_It> + { return basic_const_iterator(__i._M_current + __n); } + + friend constexpr basic_const_iterator + operator+(difference_type __n, const basic_const_iterator& __i) + noexcept(noexcept(basic_const_iterator(__i._M_current + __n))) + requires random_access_iterator<_It> + { return basic_const_iterator(__i._M_current + __n); } + + friend constexpr basic_const_iterator + operator-(const basic_const_iterator& __i, difference_type __n) + noexcept(noexcept(basic_const_iterator(__i._M_current - __n))) + requires random_access_iterator<_It> + { return basic_const_iterator(__i._M_current - __n); } + + template _Sent> + constexpr difference_type + operator-(const _Sent& __y) const + noexcept(noexcept(_M_current - __y)) + { return _M_current - __y; } + + template<__detail::__not_a_const_iterator _Sent> + requires sized_sentinel_for<_Sent, _It> + friend constexpr difference_type + operator-(const _Sent& __x, const basic_const_iterator& __y) + noexcept(noexcept(__x - __y._M_current)) + { return __x - __y._M_current; } + + friend constexpr __rvalue_reference + iter_move(const basic_const_iterator& __i) + noexcept(noexcept(static_cast<__rvalue_reference>(ranges::iter_move(__i._M_current)))) + { return static_cast<__rvalue_reference>(ranges::iter_move(__i._M_current)); } + }; + + template _Up> + requires input_iterator> + struct common_type, _Up> + { using type = basic_const_iterator>; }; + + template _Up> + requires input_iterator> + struct common_type<_Up, basic_const_iterator<_Tp>> + { using type = basic_const_iterator>; }; + + template _Up> + requires input_iterator> + struct common_type, basic_const_iterator<_Up>> + { using type = basic_const_iterator>; }; + + template + constexpr const_iterator<_It> + make_const_iterator(_It __it) + noexcept(is_nothrow_convertible_v<_It, const_iterator<_It>>) + { return __it; } + + template + constexpr const_sentinel<_Sent> + make_const_sentinel(_Sent __s) + noexcept(is_nothrow_convertible_v<_Sent, const_sentinel<_Sent>>) + { return __s; } +#endif // C++23 #endif // C++20 /// @} group iterators diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 3f6ff505617..283d757faa4 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -8929,6 +8929,112 @@ namespace views::__adaptor inline constexpr _Enumerate enumerate; } + +#define __cpp_lib_ranges_as_const 202207L + + template + requires input_range<_Vp> + class as_const_view : public view_interface> + { + _Vp _M_base = _Vp(); + + public: + as_const_view() requires default_initializable<_Vp> = default; + + constexpr explicit + as_const_view(_Vp __base) + noexcept(is_nothrow_move_constructible_v<_Vp>) + : _M_base(std::move(__base)) + { } + + constexpr _Vp + base() const & + noexcept(is_nothrow_copy_constructible_v<_Vp>) + requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + noexcept(is_nothrow_move_constructible_v<_Vp>) + { return std::move(_M_base); } + + constexpr auto + begin() requires (!__detail::__simple_view<_Vp>) + { return ranges::cbegin(_M_base); } + + constexpr auto + begin() const requires range + { return ranges::cbegin(_M_base); } + + constexpr auto + end() requires (!__detail::__simple_view<_Vp>) + { return ranges::cend(_M_base); } + + constexpr auto + end() const requires range + { return ranges::cend(_M_base); } + + constexpr auto + size() requires sized_range<_Vp> + { return ranges::size(_M_base); } + + constexpr auto + size() const requires sized_range + { return ranges::size(_M_base); } + }; + + template + as_const_view(_Range&&) -> as_const_view>; + + template + inline constexpr bool enable_borrowed_range> + = enable_borrowed_range<_Tp>; + + namespace views + { + namespace __detail + { + template + inline constexpr bool __is_ref_view = false; + + template + inline constexpr bool __is_ref_view> = true; + + template + concept __can_as_const_view = requires { as_const_view(std::declval<_Range>()); }; + } + + struct _AsConst : __adaptor::_RangeAdaptorClosure + { + template + constexpr auto + operator()(_Range&& __r) const + noexcept(noexcept(as_const_view(std::declval<_Range>()))) + requires __detail::__can_as_const_view<_Range> + { + using _Tp = remove_cvref_t<_Range>; + using element_type = remove_reference_t>; + if constexpr (constant_range>) + return views::all(std::forward<_Range>(__r)); + else if constexpr (__detail::__is_empty_view<_Tp>) + return views::empty; + else if constexpr (std::__detail::__is_span<_Tp>) + return span(std::forward<_Range>(__r)); + else if constexpr (__detail::__is_ref_view<_Tp> + && constant_range) + return ref_view(static_cast + (std::forward<_Range>(__r).base())); + else if constexpr (is_lvalue_reference_v<_Range> + && constant_range<_Tp> + && !view<_Tp>) + return ref_view(static_cast(__r)); + else + return as_const_view(std::forward<_Range>(__r)); + } + }; + + inline constexpr _AsConst as_const; + } #endif // C++23 } // namespace ranges diff --git a/libstdc++-v3/include/std/span b/libstdc++-v3/include/std/span index 06d5c185880..67633899665 100644 --- a/libstdc++-v3/include/std/span +++ b/libstdc++-v3/include/std/span @@ -137,6 +137,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using const_reference = const element_type&; using iterator = __gnu_cxx::__normal_iterator; using reverse_iterator = std::reverse_iterator; +#if __cplusplus > 202002L + using const_iterator = std::const_iterator; + using const_reverse_iterator = std::const_iterator; +#endif // member constants static constexpr size_t extent = _Extent; @@ -301,6 +305,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION rend() const noexcept { return reverse_iterator(this->begin()); } +#if __cplusplus > 202002L + constexpr const_iterator + cbegin() const noexcept + { return begin(); } + + constexpr const_iterator + cend() const noexcept + { return end(); } + + constexpr const_reverse_iterator + crbegin() const noexcept + { return rbegin(); } + + constexpr const_reverse_iterator + crend() const noexcept + { return rend(); } +#endif + // subviews template diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version index d233b037d1a..9f31f25f1e9 100644 --- a/libstdc++-v3/include/std/version +++ b/libstdc++-v3/include/std/version @@ -339,6 +339,7 @@ #define __cpp_lib_ranges_stride 202207L #define __cpp_lib_ranges_cartesian_product 202207L #define __cpp_lib_ranges_as_rvalue 202207L +#define __cpp_lib_ranges_as_const 202207L #define __cpp_lib_ranges_enumerate 202302L #define __cpp_lib_fold 202207L #if __cpp_constexpr_dynamic_alloc diff --git a/libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc b/libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc new file mode 100644 index 00000000000..51befd29541 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/const_iterator/1.cc @@ -0,0 +1,140 @@ +// { dg-options "-std=gnu++23" } +// { dg-do run { target c++23 } } + +#include +#include +#include +#include +#include +#include + +using __gnu_test::test_input_range; +using __gnu_test::test_forward_range; +using __gnu_test::test_bidirectional_range; +using __gnu_test::test_random_access_range; + +namespace ranges = std::ranges; + +template +void +test01() +{ + if constexpr (Const) + { + static_assert( std::same_as, Iter> ); + static_assert( std::same_as, Iter> ); + static_assert( std::same_as, + std::iter_reference_t> ); + } + else + { + using Wrapped = std::basic_const_iterator; + + static_assert( std::same_as, Wrapped> ); + static_assert( std::same_as, Wrapped> ); + static_assert( std::same_as, + std::iter_reference_t> ); + + static_assert( std::input_iterator == std::input_iterator ); + static_assert( std::forward_iterator == std::forward_iterator ); + static_assert( std::bidirectional_iterator == std::bidirectional_iterator ); + static_assert( std::random_access_iterator == std::random_access_iterator ); + } +} + +template +void +test02() +{ + if constexpr (Const) + { + static_assert( ranges::constant_range ); + static_assert( std::same_as, ranges::iterator_t> ); + static_assert( std::same_as, ranges::sentinel_t> ); + static_assert( std::same_as, + ranges::range_reference_t> ); + + static_assert( std::same_as())), + decltype(ranges::begin(std::declval()))> ); + static_assert( std::same_as())), + decltype(ranges::end(std::declval()))> ); + } + else + { + static_assert( !ranges::constant_range ); + using Wrapped = std::basic_const_iterator>; + + static_assert( std::same_as, Wrapped> ); + if constexpr (ranges::common_range) + static_assert( std::same_as, Wrapped> ); + static_assert( std::same_as, + std::iter_reference_t> ); + + static_assert( ranges::input_range == std::input_iterator ); + static_assert( ranges::forward_range == std::forward_iterator ); + static_assert( ranges::bidirectional_range == std::bidirectional_iterator ); + static_assert( ranges::random_access_range == std::random_access_iterator ); + + if constexpr (ranges::constant_range) + { + static_assert( std::same_as())), + decltype(ranges::begin(std::declval()))> ); + static_assert( std::same_as())), + decltype(ranges::end(std::declval()))> ); + } + else + { + static_assert( std::same_as())), Wrapped> ); + if constexpr (ranges::common_range) + static_assert( std::same_as())), Wrapped> ); + } + } +} + +void +test03() +{ + static_assert( std::same_as, + std::unreachable_sentinel_t> ); +} + +int +main() +{ + test01(); + test01>, false>(); + test01>, false>(); + test01>, false>(); + test01>, false>(); + test01::iterator, false>(); + test01::iterator, false>(); + + test01(); + test01>, true>(); + test01>, true>(); + test01>, true>(); + test01>, true>(); + test01::iterator, true>(); + test01(); + test01::const_iterator, true>(); + + test02(); + test02, false>(); + test02, false>(); + test02, false>(); + test02, false>(); + test02, false>(); + test02, false>(); + + test02(); + test02, true>(); + test02, true>(); + test02, true>(); + test02, true>(); + test02, true>(); + test02, true>(); + test02(); + test02, true>(); + + test03(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc new file mode 100644 index 00000000000..d04645f047e --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/as_const/1.cc @@ -0,0 +1,64 @@ +// { dg-options "-std=gnu++23" } +// { dg-do run { target c++23 } } + +#include +#include +#include +#include +#include +#include + +#if __cpp_lib_ranges_as_const != 202207L +# error "Feature-test macro __cpp_lib_ranges_as_const has wrong value in " +#endif + +namespace ranges = std::ranges; +namespace views = std::views; + +constexpr bool +test01() +{ + int x[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; + auto v = x | views::filter([](int x) { return (x % 2) == 0; }) | views::as_const; + + using ty = decltype(v); + static_assert(ranges::constant_range); + static_assert(!ranges::constant_range); + static_assert(std::same_as, const int&>); + static_assert(std::same_as, int&>); + + VERIFY( ranges::equal(v, (int[]){2, 4, 6, 8, 10}) ); + VERIFY( ranges::equal(v | views::reverse, (int[]){10, 8, 6, 4, 2}) ); + + return true; +} + +constexpr bool +test02() +{ + std::same_as> auto v1 + = views::empty | views::as_const; + + int x[] = {1, 2, 3}; + std::same_as>> auto v2 + = x | views::as_const; + std::same_as> auto v3 + = std::as_const(x) | views::as_const; + std::same_as> auto v4 + = std::as_const(x) | views::all | views::as_const; + std::same_as> auto v5 + = std::span{x, x+3} | views::as_const; + + std::same_as>>> auto v6 + = x | views::chunk(2) | views::as_const; + VERIFY( v6.size() == 2 ); + + return true; +} + +int +main() +{ + static_assert(test01()); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc index e5ae9b7be20..cda2cbfc577 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -120,8 +121,8 @@ test06() // Verify that _Sentinel is implicitly convertible to _Sentinel. static_assert(!ranges::common_range); static_assert(!std::same_as); - auto b = ranges::cend(v); + decltype(std::as_const(v).end())>); + auto b = std::as_const(v).end(); b = ranges::end(v); } diff --git a/libstdc++-v3/testsuite/std/ranges/version_c++23.cc b/libstdc++-v3/testsuite/std/ranges/version_c++23.cc index fa010bf166b..e2c14edc8ef 100644 --- a/libstdc++-v3/testsuite/std/ranges/version_c++23.cc +++ b/libstdc++-v3/testsuite/std/ranges/version_c++23.cc @@ -45,6 +45,10 @@ # error "Feature-test macro __cpp_lib_ranges_as_rvalue has wrong value in " #endif +#if __cpp_lib_ranges_as_const != 202207L +# error "Feature-test macro __cpp_lib_ranges_as_const has wrong value in " +#endif + #if __cpp_lib_ranges_enumerate != 202302L # error "Feature-test macro __cpp_lib_ranges_enumerate has wrong value in " #endif