From patchwork Tue Aug 23 01:34:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 666 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:ecc5:0:0:0:0:0 with SMTP id s5csp747415wro; Mon, 22 Aug 2022 18:36:53 -0700 (PDT) X-Google-Smtp-Source: AA6agR7zpEkNBJSxNS6zFPWwTPu8wgfX4NJbHZLvEW6W0uPYnYE93nHstwZZGR0UMtcxF1Fv/nDo X-Received: by 2002:a05:6402:44c:b0:445:f2f1:4add with SMTP id p12-20020a056402044c00b00445f2f14addmr1544869edw.257.1661218612882; Mon, 22 Aug 2022 18:36:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1661218612; cv=none; d=google.com; s=arc-20160816; b=Ea6WlazI73SLO4gnm7LXIc3JdeojdWfEC7tID4nw2UgoRQOHUjD2ThiyX09U5m2O4t NSfJ6yisyynTTM0tSZJF1n160qGyCCu48MRN1gOAIDkTEIozbYgo60Sp7q2yZdQZr2Fd qg3CYGFOxRGsnmsWmRU5Bj4kTrBMVjNbDtoETnciGdsYw+egWeMkL/gh70zqg1h0PXD0 glMBacRbJ4aW90aJJYthLHGFlkLrlLnCWmA+a9lPaBOz9jKrUZGhNjs1HNmZk/MmKCRi P5NmJTVXLc5LNtUmlVAuUktfPh4sSXW75dI4bJb6uWangcTHUyTGR1Fawu0qIKSFIUJe xcRA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:reply-to:from:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence :content-transfer-encoding:mime-version:message-id:date:subject:to :dmarc-filter:delivered-to:dkim-signature:dkim-filter; bh=xwJga+iKr7YMPjR2NLqP6/50JDlQiXx2+7MRt68EoOY=; b=ylcSgrGPgXrohIX0lMjE0WFK/ZoDiyj24EyFPpLNiSlhgTSeSXVLq0qpX/HZGY6YOE JB8vXB4AdfFLmaHgjsoWa8qfN7tMb5PTrltFefVFjKAdKZ2e9RAVkM58xNRbPu+smw/m ydGo7FCHzqxiM43H2Ts0fTGP3dc4iTSAxihN0Tnsn97/qqAteQD5Uk5cyOvQS//hLdIZ UKJn788Dysy+P9KatboQtHTTtCNFPLgnVnw9J1MN/RUm6Aviex9FyThzW7qpkBJQ2gL+ 08o73y8JNf8WMGJePYov8n2+nS9S8kpR9QCSm+JgmVNR1Qx3k8nMkgIuWBK4fCOtsrSo 4odg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=O4qEiJ8n; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id hq4-20020a1709073f0400b00726b8d2fbc6si11555137ejc.504.2022.08.22.18.36.52 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Aug 2022 18:36:52 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=O4qEiJ8n; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 511C1385085B for ; Tue, 23 Aug 2022 01:35:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 511C1385085B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1661218549; bh=xwJga+iKr7YMPjR2NLqP6/50JDlQiXx2+7MRt68EoOY=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=O4qEiJ8nstPrgqcrYDxF5gYmElduZxrQx+RQYhoTb4jV75a82BFmLsa3zcH5CK44c +fEMHlybtscw8mr1Vu4NB/penPRLjbzNDGbgcuiKQiN+2TXORGSk62rpOSQ5Tic/Jk pYUESWX+wo7tYPR+CULP4h56b1wI8nFyEy22lYZU= 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 B1DF03858D3C for ; Tue, 23 Aug 2022 01:35:05 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org B1DF03858D3C Received: from mail-qv1-f70.google.com (mail-qv1-f70.google.com [209.85.219.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-418-FZ4Y4yc6PWyDfVouYcHcGA-1; Mon, 22 Aug 2022 21:35:04 -0400 X-MC-Unique: FZ4Y4yc6PWyDfVouYcHcGA-1 Received: by mail-qv1-f70.google.com with SMTP id ea4-20020ad458a4000000b0049682af0ca8so6600138qvb.21 for ; Mon, 22 Aug 2022 18:35:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc; bh=xwJga+iKr7YMPjR2NLqP6/50JDlQiXx2+7MRt68EoOY=; b=qo7SNJvOGFgMExIJLsk8EOgyxyHTf/9UoAFauBoDQIMPuxc8nwYEID1Bfu98JLbcZw WOldMaoAcOQcMxKstp5mESXKCWsqldhT+KGngkz5+NGFeIHcOf24R5DdYgFC8QOM4aAr hq8l9ghzl/WCe24IhZM/AWdQn11dVopQ0O8fKLw9UcvONzTML4JoXv0MPEIFOZQa7EIK ZSTkFMvMDsBuaSJdOYxazgHKbmGcpujbqdSuc3y96ft8MV1f7ZV9ocKFW01dDU+/z2k7 1kBWr6Vj/GmBzXfkNiCob14ZYRow8dT/LPmUIlEn8COQq3S1bqpBx2q+/vTC4v0rXOrK S3LQ== X-Gm-Message-State: ACgBeo1Qigro+yGUdgg8y+woZc8rfywuA3ng6gAMZSsBEMvkUWND2cF1 ihSug23KVobdiJ50CQCv0sWO4nqUNrH/GpKKh03Q9ApCI8VuUxGv/9YKKqeLyaup7FEwMt6J2Xx L0qrtVd/4zlRJnIKdzGvSfbQz+zFcsnZkRt1sgMi40gwFVSAduFEnTRgaup6IAJ0Cyf4= X-Received: by 2002:a05:622a:3d0:b0:343:58db:d5c7 with SMTP id k16-20020a05622a03d000b0034358dbd5c7mr17364584qtx.21.1661218503700; Mon, 22 Aug 2022 18:35:03 -0700 (PDT) X-Received: by 2002:a05:622a:3d0:b0:343:58db:d5c7 with SMTP id k16-20020a05622a03d000b0034358dbd5c7mr17364566qtx.21.1661218503403; Mon, 22 Aug 2022 18:35:03 -0700 (PDT) Received: from localhost.localdomain (ool-457670bb.dyn.optonline.net. [69.118.112.187]) by smtp.gmail.com with ESMTPSA id p11-20020ac8740b000000b00342fcdc2d46sm9816942qtq.56.2022.08.22.18.35.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Aug 2022 18:35:03 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH 1/3] libstdc++: Separate construct/convertibility tests for std::tuple Date: Mon, 22 Aug 2022 21:34:58 -0400 Message-Id: <20220823013500.1756466-1-ppalka@redhat.com> X-Mailer: git-send-email 2.37.2.382.g795ea8776b 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, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE 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 Cc: libstdc++@gcc.gnu.org Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1741913968550540636?= X-GMAIL-MSGID: =?utf-8?q?1741913968550540636?= P2321R2 adds new conditionally explicit constructors to std::tuple which we'll concisely implement in a subsequent patch using explicit(bool), like in our C++20 std::pair implementation. But before we can do that, this patch first adds members to _TupleConstraints that test for constructibility and convertibility separately; we'll use the first in the new constructors' constraints, and the second in their explicit specifier. In passing, this patch also redefines the existing predicates __is_ex/implicitly_constructible in terms of these new members. This seems to reduce compile time and memory usage by about 10% for large tuples when using the relevant constructors constrained by _Explicit/_ImplicitCtor (since we no longer have to redundantly expand and process is_constructible<_Types, _UTypes>... twice for each pair of such constructors). In order to retain maximal short circuiting, do this only when constexpr if is available. Tested on x86_64-pc-linux-gnu, does this look OK for trunk? libstdc++-v3/ChangeLog: * include/std/tuple (_TupleConstraints::__convertible): Define for C++17. (_TupleConstraints::__constructible): Likewise. (_TupleConstraints::__is_explicitly_constructible): For C++17 define this in terms of __convertible and __constructible using constexpr if. (_TupleConstraints::__is_implicitly_constructible): Likewise. --- libstdc++-v3/include/std/tuple | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index 6d0060a191c..d0c168fd7e2 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -553,15 +553,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct _TupleConstraints { +#if __cplusplus >= 201703L + template + static constexpr bool __constructible + = __and_v...>; + + template + static constexpr bool __convertible + = __and_v...>; +#endif + // Constraint for a non-explicit constructor. // True iff each Ti in _Types... can be constructed from Ui in _UTypes... // and every Ui is implicitly convertible to Ti. template static constexpr bool __is_implicitly_constructible() { +#if __cplusplus >= 201703L + if constexpr (__constructible<_UTypes...>) + return __convertible<_UTypes...>; + return false; +#else return __and_..., is_convertible<_UTypes, _Types>... >::value; +#endif } // Constraint for a non-explicit constructor. @@ -570,9 +586,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template static constexpr bool __is_explicitly_constructible() { +#if __cplusplus >= 201703L + if constexpr (__constructible<_UTypes...>) + return !__convertible<_UTypes...>; + return false; +#else return __and_..., __not_<__and_...>> >::value; +#endif } static constexpr bool __is_implicitly_default_constructible() From patchwork Tue Aug 23 01:34:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 668 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:ecc5:0:0:0:0:0 with SMTP id s5csp747492wro; Mon, 22 Aug 2022 18:37:10 -0700 (PDT) X-Google-Smtp-Source: AA6agR6XO6IIgtY0LUaZcnpaGseJPPGTZ3Z5Uk+Vor23Lc3f2XPPIMg6Iz431IWQVVuIYLKoHNB5 X-Received: by 2002:a17:906:8467:b0:73d:8873:841b with SMTP id hx7-20020a170906846700b0073d8873841bmr3537265ejc.418.1661218629886; Mon, 22 Aug 2022 18:37:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1661218629; cv=none; d=google.com; s=arc-20160816; b=Mv41H6iFrtiyZ4sF5vud5kGPpMj2oQvFjQGJb3YJlYMjO3MTh1iBSzovwjyXd+pDte orZtdyTs/catKRCN9qLpOouOc16Yphyk1Lii38n9d8Ats6Q4Nf7gh/xEhHPR1LbuQrvh UadWGdJbp6XYRqhz0Vv3U1tvqHbYZldzRpgMXj39rWNz5VIyo1SrFrvRvdWkRYc2veVB 7pZe4vW7zXq4Wmxc7Huq6KVyIk8Ly7UnUQmMHhPrEhI/vjKkU+atWrCEGMUo7dIGPVsf b5i7Bqr4PC3EDthEv/Q0uX6hmI3Ffp8s5cXDyVSAHTr33jn7rm2glc8NsrKMzYIL+rTS YgOQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:reply-to:from:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence :content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:dmarc-filter:delivered-to:dkim-signature :dkim-filter; bh=AuINIqY5DB3JSAR7pGlThWQrz8bZqSMi4NmPZ/k0APc=; b=k/Y8g7f6VKeZkAeNdyhcletikStrDmOIWySUBTZi/zieQQcN6SKTvqQO16XCAOqadF R1Rat07+B8NvCMEOSwb7CzHonFmQdryPk5JV7dZCqiN4+3DAgic0YeKCb+J1BL06h6p1 m7hkYF9YbCUAxcdeIAOkju5hi8zbrr3uxzmwnZHAsdnoWqOYmFxFvB/us1R/IDDZYSfq 8K1p9xVvk3mEdgTgWS5shIggeIUyHiEbTQcm7YYRE9m6eL1kiS6Jv91Ripcdl/5VSPmS +iJ5DoDsnbPBrTWx+K/3QCoYadY6qwPoZ+sgsDo6rkK7GUOptTEP3xqR02sa/RNTwWTh Tf3A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=K2V18Xz6; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id z21-20020a056402275500b00442edebe687si863883edd.633.2022.08.22.18.37.09 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Aug 2022 18:37:09 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=K2V18Xz6; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 09E3A3850230 for ; Tue, 23 Aug 2022 01:35:58 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 09E3A3850230 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1661218558; bh=AuINIqY5DB3JSAR7pGlThWQrz8bZqSMi4NmPZ/k0APc=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=K2V18Xz6PBr4abN5kCg2MYp+1YPFf5unU8TQ3moTk7tZ2N+nbc8cnZGeeO7kz3/9s N6XY7cMkD//cVuJ+mYW5hW70GKFAWSwaC2FLEv7VBlmWfHi7gN+8CKUMHUDsQMsq2c EWHIHl7wySbmfp+sXA2vAQzUe3FjonMY+Gq1Lmgs= 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 45B593858C39 for ; Tue, 23 Aug 2022 01:35:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 45B593858C39 Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-438-zsyjymXtNRmUL7bf3LEvMQ-1; Mon, 22 Aug 2022 21:35:07 -0400 X-MC-Unique: zsyjymXtNRmUL7bf3LEvMQ-1 Received: by mail-qt1-f199.google.com with SMTP id s2-20020ac85cc2000000b00342f8ad1f40so9561926qta.12 for ; Mon, 22 Aug 2022 18:35:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=AuINIqY5DB3JSAR7pGlThWQrz8bZqSMi4NmPZ/k0APc=; b=ruE1dC2G4rQRgpulMliruuwlcfxrTZan5UjO84Cac+5qyXDpsVxXVG1LxKc6jDq3b0 RZbRvrJ3kJlY5QMDHeOLYTS2+aO8O6zSbioHcsNRpLCr1nMKokcnVGN0iZiMxk5Pm2DI XENMeHd6sHoMfNZbF/FudB1bQXh9HtYHv/gJEJanfqFyK/nWPZx4iE2E86uEs1MCdhhg dCCzsad20EfnU2FPzWpPa1dYaBJzsEh176lcNgKW85gzHtv4I9yHieQcxFhZUwuZ3Ivy z8FpPW/uezwQknpBxUO+uY4ioM2U3GLbA26gFi0MlJImB9yYA+mtSSxn4u5pspNA9eSt Audw== X-Gm-Message-State: ACgBeo2NQC66XDDWyoqxnlBO0NkVN4YW8xzoXNwwY1sLPBVpi1D8rRP3 W9pJK6PucIoCeIVxj/QgMqrzUWh9qiLWP95Fy93s5JZmhLTAuw4UpKIJlS0YKdaWentL/OL07ap OFY/TcRNhR3zHzvpGYrYPAVQAsfpNvl1xi6uOsdO92TS9RZycHtiRGMvNKokhSWIkUHc= X-Received: by 2002:a37:b702:0:b0:6b8:d9ec:3196 with SMTP id h2-20020a37b702000000b006b8d9ec3196mr14215362qkf.660.1661218505718; Mon, 22 Aug 2022 18:35:05 -0700 (PDT) X-Received: by 2002:a37:b702:0:b0:6b8:d9ec:3196 with SMTP id h2-20020a37b702000000b006b8d9ec3196mr14215335qkf.660.1661218504676; Mon, 22 Aug 2022 18:35:04 -0700 (PDT) Received: from localhost.localdomain (ool-457670bb.dyn.optonline.net. [69.118.112.187]) by smtp.gmail.com with ESMTPSA id p11-20020ac8740b000000b00342fcdc2d46sm9816942qtq.56.2022.08.22.18.35.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Aug 2022 18:35:04 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH 2/3] libstdc++: Implement std::pair/tuple/misc enhancements from P2321R2 Date: Mon, 22 Aug 2022 21:34:59 -0400 Message-Id: <20220823013500.1756466-2-ppalka@redhat.com> X-Mailer: git-send-email 2.37.2.382.g795ea8776b In-Reply-To: <20220823013500.1756466-1-ppalka@redhat.com> References: <20220823013500.1756466-1-ppalka@redhat.com> 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, KAM_NUMSUBJECT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE 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 Cc: libstdc++@gcc.gnu.org Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1741913986126580084?= X-GMAIL-MSGID: =?utf-8?q?1741913986126580084?= This implements the non- changes from P2321R2, which primarily consist of new converting constructors, assignment operator and swap overloads for std::pair and std::tuple. Tested on x86_64-pc-linux-gnu, does this look OK for trunk? libstdc++-v3/ChangeLog: * include/bits/stl_bvector.h (_Bit_reference::operator=): Define const overload for C++23 as per P2321R2. * include/bits/stl_pair.h (pair::swap): Likewise. (pair::pair): Define additional converting constructors for C++23 as per P2321R2. (pair::operator=): Define const overloads for C++23 as per P2321R2. (swap): Define overload taking const pair& for C++23 as per P2321R2. (basic_common_reference): Define partial specialization for pair for C++23 as per P2321R2. (common_type): Likewise. * include/bits/uses_allocator_args.h (uses_allocator_construction_args): Define additional pair overloads for C++23 as per P2321R2. * include/std/tuple (_Tuple_impl::_Tuple_impl): Define additional converting constructors for C++23 as per P2321R2. (_Tuple_impl::_M_assign): Define const overloads for C++23 as per P2321R2. (_Tuple_impl::_M_swap): Likewise. (tuple::__constructible): Define as a convenient renaming of _TCC::__constructible. (tuple::__convertible): As above but for _TCC::__convertible. (tuple::tuple): Define additional converting constructors for C++23 as per P2321R2. (tuple::operator=): Define const overloads for C++23 as per P2321R2. (tuple::swap): Likewise. (basic_common_reference): Define partial specialization for tuple for C++23 as per P2321R2. (common_type): Likewise. * testsuite/20_util/pair/p2321.cc: New test. * testsuite/20_util/tuple/p2321.cc: New test. * testsuite/23_containers/vector/bool/element_access/1.cc: New test. --- libstdc++-v3/include/bits/stl_bvector.h | 12 + libstdc++-v3/include/bits/stl_pair.h | 118 +++- .../include/bits/uses_allocator_args.h | 41 ++ libstdc++-v3/include/std/tuple | 416 +++++++++++ libstdc++-v3/testsuite/20_util/pair/p2321.cc | 208 ++++++ libstdc++-v3/testsuite/20_util/tuple/p2321.cc | 664 ++++++++++++++++++ .../vector/bool/element_access/1.cc | 26 + 7 files changed, 1480 insertions(+), 5 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/pair/p2321.cc create mode 100644 libstdc++-v3/testsuite/20_util/tuple/p2321.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/element_access/1.cc diff --git a/libstdc++-v3/include/bits/stl_bvector.h b/libstdc++-v3/include/bits/stl_bvector.h index d256af40f40..c5fd19e7309 100644 --- a/libstdc++-v3/include/bits/stl_bvector.h +++ b/libstdc++-v3/include/bits/stl_bvector.h @@ -106,6 +106,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return *this; } +#if __cplusplus > 202002L + constexpr const _Bit_reference& + operator=(bool __x) const noexcept + { + if (__x) + *_M_p |= _M_mask; + else + *_M_p &= ~_M_mask; + return *this; + } +#endif + _GLIBCXX20_CONSTEXPR _Bit_reference& operator=(const _Bit_reference& __x) _GLIBCXX_NOEXCEPT diff --git a/libstdc++-v3/include/bits/stl_pair.h b/libstdc++-v3/include/bits/stl_pair.h index 831e770d54b..d0efba635bc 100644 --- a/libstdc++-v3/include/bits/stl_pair.h +++ b/libstdc++-v3/include/bits/stl_pair.h @@ -212,6 +212,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION swap(second, __p.second); } +#if __cplusplus > 202002L + /// Swap the first members and then the second members. + constexpr void + swap(const pair& __p) const + noexcept(__and_<__is_nothrow_swappable, + __is_nothrow_swappable>::value) + { + using std::swap; + swap(first, __p.first); + swap(second, __p.second); + } +#endif // C++23 + private: template @@ -283,7 +296,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : first(std::forward<_U1>(__x)), second(std::forward<_U2>(__y)) { } - /// Converting constructor from a `pair` lvalue + /// Converting constructor from a const `pair` lvalue template requires (_S_constructible()) constexpr explicit(!_S_convertible()) @@ -292,7 +305,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : first(__p.first), second(__p.second) { } - /// Converting constructor from a `pair` rvalue + /// Converting constructor from a non-const `pair` rvalue template requires (_S_constructible<_U1, _U2>()) constexpr explicit(!_S_convertible<_U1, _U2>()) @@ -302,6 +315,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION second(std::forward<_U2>(__p.second)) { } +#if __cplusplus > 202002L + /// Converting constructor from a non-const `pair` lvalue + template + requires (_S_constructible<_U1&, _U2&>()) + constexpr explicit(!_S_convertible<_U1&, _U2&>()) + pair(pair<_U1, _U2>& __p) + noexcept(_S_nothrow_constructible<_U1&, _U2&>()) + : first(__p.first), second(__p.second) + { } + + /// Converting constructor from a const `pair` rvalue + template + requires (_S_constructible()) + constexpr explicit(!_S_convertible()) + pair(const pair<_U1, _U2>&& __p) + noexcept(_S_nothrow_constructible()) + : first(std::forward(__p.first)), + second(std::forward(__p.second)) + { } +#endif + private: /// @cond undocumented template @@ -349,7 +383,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - /// Converting assignment from a `pair` lvalue + /// Converting assignment from a const `pair` lvalue template constexpr pair& operator=(const pair<_U1, _U2>& __p) @@ -361,7 +395,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } - /// Converting assignment from a `pair` rvalue + /// Converting assignment from a non-const `pair` rvalue template constexpr pair& operator=(pair<_U1, _U2>&& __p) @@ -372,7 +406,55 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION second = std::forward<_U2>(__p.second); return *this; } -#else + +#if __cplusplus > 202002L + /// Copy assignment operator + constexpr const pair& + operator=(const pair& __p) const + requires is_copy_assignable_v + && is_copy_assignable_v + { + first = __p.first; + second = __p.second; + return *this; + } + + /// Move assignment operator + constexpr const pair& + operator=(pair&& __p) const + requires is_assignable_v + && is_assignable_v + { + first = std::forward(__p.first); + second = std::forward(__p.second); + return *this; + } + + /// Converting assignment from a const `pair` lvalue + template + constexpr const pair& + operator=(const pair<_U1, _U2>& __p) const + requires is_assignable_v + && is_assignable_v + { + first = __p.first; + second = __p.second; + return *this; + } + + /// Converting assignment from a non-const `pair` rvalue + template + constexpr const pair& + operator=(pair<_U1, _U2>&& __p) const + requires is_assignable_v + && is_assignable_v + { + first = std::forward<_U1>(__p.first); + second = std::forward<_U2>(__p.second); + return *this; + } +#endif // C++23 +#else // !__cpp_lib_concepts // C++11/14/17 implementation using enable_if, partially constexpr. /** The default constructor creates @c first and @c second using their @@ -710,6 +792,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(noexcept(__x.swap(__y))) { __x.swap(__y); } +#if __cplusplus > 202002L + template + requires is_swappable::value && is_swappable::value + constexpr void + swap(const pair<_T1, _T2>& __x, const pair<_T1, _T2>& __y) + noexcept(noexcept(__x.swap(__y))) + { __x.swap(__y); } +#endif // C++23 + #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 template typename enable_if, @@ -918,6 +1009,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION get(const pair<_Up, _Tp>&& __p) noexcept { return std::move(__p.second); } +#if __cplusplus > 202002L + template class _TQual, template class _UQual> + requires requires { typename pair, _UQual<_U1>>, + common_reference_t<_TQual<_T2>, _UQual<_U2>>>; } + struct basic_common_reference, pair<_U1, _U2>, _TQual, _UQual> + { + using type = pair, _UQual<_U1>>, + common_reference_t<_TQual<_T2>, _UQual<_U2>>>; + }; + + template + requires requires { typename pair, common_type_t<_T2, _U2>>; } + struct common_type, pair<_U1, _U2>> + { using type = pair, common_type_t<_T2, _U2>>; }; +#endif + #endif // C++14 /// @} #endif // C++11 diff --git a/libstdc++-v3/include/bits/uses_allocator_args.h b/libstdc++-v3/include/bits/uses_allocator_args.h index 09cdbf1aaa8..3528e4cc4fa 100644 --- a/libstdc++-v3/include/bits/uses_allocator_args.h +++ b/libstdc++-v3/include/bits/uses_allocator_args.h @@ -107,6 +107,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION constexpr auto uses_allocator_construction_args(const _Alloc&, pair<_Up, _Vp>&&) noexcept; +#if __cplusplus > 202002L + template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc&, + pair<_Up, _Vp>&) noexcept; + + template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc&, const pair<_Up, _Vp>&&) noexcept; +#endif + template<_Std_pair _Tp, typename _Alloc, typename _Tuple1, typename _Tuple2> constexpr auto uses_allocator_construction_args(const _Alloc& __a, piecewise_construct_t, @@ -181,6 +192,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::move(__pr).second)); } +#if __cplusplus > 202002L + template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, + pair<_Up, _Vp>& __pr) noexcept + { + using _Tp1 = typename _Tp::first_type; + using _Tp2 = typename _Tp::second_type; + + return std::make_tuple(piecewise_construct, + std::uses_allocator_construction_args<_Tp1>(__a, __pr.first), + std::uses_allocator_construction_args<_Tp2>(__a, __pr.second)); + } + + template<_Std_pair _Tp, typename _Alloc, typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, + const pair<_Up, _Vp>&& __pr) noexcept + { + using _Tp1 = typename _Tp::first_type; + using _Tp2 = typename _Tp::second_type; + + return std::make_tuple(piecewise_construct, + std::uses_allocator_construction_args<_Tp1>(__a, + std::move(__pr).first), + std::uses_allocator_construction_args<_Tp2>(__a, + std::move(__pr).second)); + } +#endif + template constexpr _Tp make_obj_using_allocator(const _Alloc& __a, _Args&&... __args) diff --git a/libstdc++-v3/include/std/tuple b/libstdc++-v3/include/std/tuple index d0c168fd7e2..812e70d17be 100644 --- a/libstdc++-v3/include/std/tuple +++ b/libstdc++-v3/include/std/tuple @@ -316,6 +316,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { } +#if __cplusplus > 202002L + template + constexpr + _Tuple_impl(_Tuple_impl<_Idx, _UElements...>& __in) + : _Inherited(_Tuple_impl<_Idx, _UElements...>::_M_tail(__in)), + _Base(_Tuple_impl<_Idx, _UElements...>::_M_head(__in)) + { } + + template + constexpr + _Tuple_impl(const _Tuple_impl<_Idx, _UHead, _UTails...>&& __in) + : _Inherited(std::move + (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))), + _Base(std::forward + (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) + { } +#endif + template _GLIBCXX20_CONSTEXPR _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) @@ -379,6 +397,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) { } +#if __cplusplus > 202002L + template + constexpr + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl<_Idx, _UHead, _UTails...>& __in) + : _Inherited(__tag, __a, + _Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in)), + _Base(__use_alloc<_Head, _Alloc, _UHead&>(__a), + _Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in)) + { } + + template + constexpr + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Tuple_impl<_Idx, _UHead, _UTails...>&& __in) + : _Inherited(__tag, __a, std::move + (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))), + _Base(__use_alloc<_Head, _Alloc, const _UHead>(__a), + std::forward + (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in))) + { } +#endif + template _GLIBCXX20_CONSTEXPR void @@ -400,6 +441,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::move(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))); } +#if __cplusplus > 202002L + template + constexpr void + _M_assign(const _Tuple_impl<_Idx, _UElements...>& __in) const + { + _M_head(*this) = _Tuple_impl<_Idx, _UElements...>::_M_head(__in); + _M_tail(*this)._M_assign( + _Tuple_impl<_Idx, _UElements...>::_M_tail(__in)); + } + + template + constexpr void + _M_assign(_Tuple_impl<_Idx, _UHead, _UTails...>&& __in) const + { + _M_head(*this) = std::forward<_UHead> + (_Tuple_impl<_Idx, _UHead, _UTails...>::_M_head(__in)); + _M_tail(*this)._M_assign( + std::move(_Tuple_impl<_Idx, _UHead, _UTails...>::_M_tail(__in))); + } +#endif + protected: _GLIBCXX20_CONSTEXPR void @@ -409,6 +471,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION swap(_M_head(*this), _M_head(__in)); _Inherited::_M_swap(_M_tail(__in)); } + +#if __cplusplus > 202002L + constexpr void + _M_swap(const _Tuple_impl& __in) const + { + using std::swap; + swap(_M_head(*this), _M_head(__in)); + _Inherited::_M_swap(_M_tail(__in)); + } +#endif }; // Basis case of inheritance recursion. @@ -469,6 +541,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _Base(std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) { } +#if __cplusplus > 202002L + template + constexpr + _Tuple_impl(_Tuple_impl<_Idx, _UHead>& __in) + : _Base(_Tuple_impl<_Idx, _UHead>::_M_head(__in)) + { } + + template + constexpr + _Tuple_impl(const _Tuple_impl<_Idx, _UHead>&& __in) + : _Base(std::forward(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) + { } +#endif + template _GLIBCXX20_CONSTEXPR _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a) @@ -521,6 +607,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) { } +#if __cplusplus > 202002L + template + constexpr + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + _Tuple_impl<_Idx, _UHead>& __in) + : _Base(__use_alloc<_Head, _Alloc, _UHead&>(__a), + _Tuple_impl<_Idx, _UHead>::_M_head(__in)) + { } + + template + constexpr + _Tuple_impl(allocator_arg_t __tag, const _Alloc& __a, + const _Tuple_impl<_Idx, _UHead>&& __in) + : _Base(__use_alloc<_Head, _Alloc, const _UHead>(__a), + std::forward(_Tuple_impl<_Idx, _UHead>::_M_head(__in))) + { } +#endif + template _GLIBCXX20_CONSTEXPR void @@ -538,6 +642,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION = std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)); } +#if __cplusplus > 202002L + template + constexpr void + _M_assign(const _Tuple_impl<_Idx, _UHead>& __in) const + { + _M_head(*this) = _Tuple_impl<_Idx, _UHead>::_M_head(__in); + } + + template + constexpr void + _M_assign(_Tuple_impl<_Idx, _UHead>&& __in) const + { + _M_head(*this) + = std::forward<_UHead>(_Tuple_impl<_Idx, _UHead>::_M_head(__in)); + } +#endif + protected: _GLIBCXX20_CONSTEXPR void @@ -546,6 +667,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using std::swap; swap(_M_head(*this), _M_head(__in)); } + +#if __cplusplus > 202002L + constexpr void + _M_swap(const _Tuple_impl& __in) const + { + using std::swap; + swap(_M_head(*this), _M_head(__in)); + } +#endif }; // Concept utility functions, reused in conditionally-explicit @@ -728,6 +858,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static constexpr bool __use_other_ctor() { return _UseOtherCtor<_Tuple>::value; } +#if __cplusplus > 202002L + template + static constexpr bool __constructible + = _TCC::template __constructible<_Args...>; + + template + static constexpr bool __convertible + = _TCC::template __convertible<_Args...>; +#endif + public: template::value> = true> @@ -815,6 +955,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(__nothrow_constructible<_UElements...>()) : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&&>(__in)) { } +#if __cplusplus > 202002L + template + requires (sizeof...(_Elements) == sizeof...(_UElements)) + && (!__use_other_ctor&>()) + && __constructible<_UElements&...> + explicit(!__convertible<_UElements&...>) + constexpr + tuple(tuple<_UElements...>& __in) + noexcept(__nothrow_constructible<_UElements&...>()) + : _Inherited(static_cast<_Tuple_impl<0, _UElements...>&>(__in)) + { } + + template + requires (sizeof...(_Elements) == sizeof...(_UElements)) + && (!__use_other_ctor&&>()) + && __constructible + explicit(!__convertible) + constexpr + tuple(const tuple<_UElements...>&& __in) + noexcept(__nothrow_constructible()) + : _Inherited(static_cast&&>(__in)) { } +#endif + // Allocator-extended constructors. template&&>(__in)) { } +#if __cplusplus > 202002L + template + requires (sizeof...(_Elements) == sizeof...(_UElements)) + && (!__use_other_ctor&>()) + && __constructible<_UElements&...> + explicit(!__convertible<_UElements&...>) + constexpr + tuple(allocator_arg_t __tag, const _Alloc& __a, + tuple<_UElements...>& __in) + : _Inherited(__tag, __a, + static_cast<_Tuple_impl<0, _UElements...>&>(__in)) + { } + + template + requires (sizeof...(_Elements) == sizeof...(_UElements)) + && (!__use_other_ctor>()) + && __constructible + explicit(!__convertible) + constexpr + tuple(allocator_arg_t __tag, const _Alloc& __a, + const tuple<_UElements...>&& __in) + : _Inherited(__tag, __a, + static_cast&&>(__in)) + { } +#endif + // tuple assignment _GLIBCXX20_CONSTEXPR @@ -957,12 +1146,57 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } +#if __cplusplus > 202002L + constexpr const tuple& + operator=(const tuple& __in) const + requires (is_copy_assignable_v && ...) + { + this->_M_assign(__in); + return *this; + } + + constexpr const tuple& + operator=(tuple&& __in) const + requires (is_assignable_v && ...) + { + this->_M_assign(std::move(__in)); + return *this; + } + + template + constexpr const tuple& + operator=(const tuple<_UElements...>& __in) const + requires (sizeof...(_Elements) == sizeof...(_UElements)) + && (is_assignable_v && ...) + { + this->_M_assign(__in); + return *this; + } + + template + constexpr const tuple& + operator=(tuple<_UElements...>&& __in) const + requires (sizeof...(_Elements) == sizeof...(_UElements)) + && (is_assignable_v && ...) + { + this->_M_assign(std::move(__in)); + return *this; + } +#endif + // tuple swap _GLIBCXX20_CONSTEXPR void swap(tuple& __in) noexcept(__and_<__is_nothrow_swappable<_Elements>...>::value) { _Inherited::_M_swap(__in); } + +#if __cplusplus > 202002L + constexpr void + swap(const tuple& __in) const + noexcept(__and_<__is_nothrow_swappable...>::value) + { _Inherited::_M_swap(__in); } +#endif }; #if __cpp_deduction_guides >= 201606 @@ -985,6 +1219,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION public: _GLIBCXX20_CONSTEXPR void swap(tuple&) noexcept { /* no-op */ } +#if __cplusplus > 202002L + constexpr void swap(const tuple&) const noexcept { /* no-op */ } +#endif // We need the default since we're going to define no-op // allocator constructors. tuple() = default; @@ -1064,6 +1301,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static constexpr bool __is_alloc_arg() { return is_same<__remove_cvref_t<_U1>, allocator_arg_t>::value; } +#if __cplusplus > 202002L + template + static constexpr bool __constructible + = _TCC::template __constructible<_U1, _U2>; + + template + static constexpr bool __convertible + = _TCC::template __convertible<_U1, _U2>; +#endif + public: template = true> @@ -1139,6 +1386,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(__nothrow_constructible<_U1, _U2>()) : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&&>(__in)) { } +#if __cplusplus > 202002L + template + requires __constructible<_U1&, _U2&> + explicit(!__convertible<_U1&, _U2&>) + constexpr + tuple(tuple<_U1, _U2>& __in) + noexcept(__nothrow_constructible<_U1&, _U2&>()) + : _Inherited(static_cast<_Tuple_impl<0, _U1, _U2>&>(__in)) { } + + template + requires __constructible + explicit(!__convertible) + constexpr + tuple(const tuple<_U1, _U2>&& __in) + noexcept(__nothrow_constructible()) + : _Inherited(static_cast&&>(__in)) { } +#endif + template = true> constexpr @@ -1169,6 +1434,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _Inherited(std::forward<_U1>(__in.first), std::forward<_U2>(__in.second)) { } +#if __cplusplus > 202002L + template + requires __constructible<_U1&, _U2&> + explicit(!__convertible<_U1&, _U2&>) + constexpr + tuple(pair<_U1, _U2>& __in) + noexcept(__nothrow_constructible<_U1&, _U2&>()) + : _Inherited(__in.first, __in.second) { } + + template + requires __constructible + explicit(!__convertible) + constexpr + tuple(const pair<_U1, _U2>&& __in) + noexcept(__nothrow_constructible()) + : _Inherited(std::forward(__in.first), + std::forward(__in.second)) { } +#endif + // Allocator-extended constructors. template&&>(__in)) { } +#if __cplusplus > 202002L + template + requires __constructible<_U1&, _U2&> + explicit(!__convertible<_U1&, _U2&>) + constexpr + tuple(allocator_arg_t __tag, const _Alloc& __a, + tuple<_U1, _U2>& __in) + : _Inherited(__tag, __a, + static_cast<_Tuple_impl<0, _U1, _U2>&>(__in)) + { } + + template + requires __constructible + explicit(!__convertible) + constexpr + tuple(allocator_arg_t __tag, const _Alloc& __a, + const tuple<_U1, _U2>&& __in) + : _Inherited(__tag, __a, + static_cast&&>(__in)) + { } +#endif + template = true> _GLIBCXX20_CONSTEXPR @@ -1282,6 +1588,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _Inherited(__tag, __a, std::forward<_U1>(__in.first), std::forward<_U2>(__in.second)) { } +#if __cplusplus > 202002L + template + requires __constructible<_U1&, _U2&> + explicit(!__convertible<_U1&, _U2&>) + constexpr + tuple(allocator_arg_t __tag, const _Alloc& __a, + pair<_U1, _U2>& __in) + : _Inherited(__tag, __a, __in.first, __in.second) { } + + template + requires __constructible + explicit(!__convertible) + constexpr + tuple(allocator_arg_t __tag, const _Alloc& __a, const pair<_U1, _U2>&& __in) + : _Inherited(__tag, __a, std::forward(__in.first), + std::forward(__in.second)) { } +#endif + // Tuple assignment. _GLIBCXX20_CONSTEXPR @@ -1326,6 +1650,44 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } +#if __cplusplus > 202002L + constexpr const tuple& + operator=(const tuple& __in) const + requires is_copy_assignable_v && is_copy_assignable_v + { + this->_M_assign(__in); + return *this; + } + + constexpr const tuple& + operator=(tuple&& __in) const + requires is_assignable_v && is_assignable_v + { + this->_M_assign(std::move(__in)); + return *this; + } + + template + constexpr const tuple& + operator=(const tuple<_U1, _U2>& __in) const + requires is_assignable_v + && is_assignable_v + { + this->_M_assign(__in); + return *this; + } + + template + constexpr const tuple& + operator=(tuple<_U1, _U2>&& __in) const + requires is_assignable_v + && is_assignable_v + { + this->_M_assign(std::move(__in)); + return *this; + } +#endif + template _GLIBCXX20_CONSTEXPR __enable_if_t<__assignable(), tuple&> @@ -1348,12 +1710,44 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return *this; } +#if __cplusplus > 202002L + template + constexpr const tuple& + operator=(const pair<_U1, _U2>& __in) const + requires is_assignable_v + && is_assignable_v + { + this->_M_head(*this) = __in.first; + this->_M_tail(*this)._M_head(*this) = __in.second; + return *this; + } + + template + constexpr const tuple& + operator=(pair<_U1, _U2>&& __in) const + requires is_assignable_v + && is_assignable_v + { + this->_M_head(*this) = std::forward<_U1>(__in.first); + this->_M_tail(*this)._M_head(*this) = std::forward<_U2>(__in.second); + return *this; + } +#endif + _GLIBCXX20_CONSTEXPR void swap(tuple& __in) noexcept(__and_<__is_nothrow_swappable<_T1>, __is_nothrow_swappable<_T2>>::value) { _Inherited::_M_swap(__in); } + +#if __cplusplus > 202002L + constexpr void + swap(const tuple& __in) const + noexcept(__and_<__is_nothrow_swappable, + __is_nothrow_swappable>::value) + { _Inherited::_M_swap(__in); } +#endif }; @@ -1781,6 +2175,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION noexcept(noexcept(__x.swap(__y))) { __x.swap(__y); } +#if __cplusplus > 202002L + template + requires (__is_swappable::value && ...) + constexpr void + swap(const tuple<_Elements...>& __x, const tuple<_Elements...>& __y) + noexcept(noexcept(__x.swap(__y))) + { __x.swap(__y); } +#endif + #if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++11 template _GLIBCXX20_CONSTEXPR @@ -1905,6 +2308,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } #endif // C++17 +#if __cplusplus > 202002L + template class TQual, template class UQual> + requires requires { typename tuple, UQual<_UTypes>>...>; } + struct basic_common_reference, tuple<_UTypes...>, TQual, UQual> + { using type = tuple, UQual<_UTypes>>...>; }; + + template + requires requires { typename tuple...>; } + struct common_type, tuple<_UTypes...>> + { using type = tuple...>; }; +#endif + /// @} _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/testsuite/20_util/pair/p2321.cc b/libstdc++-v3/testsuite/20_util/pair/p2321.cc new file mode 100644 index 00000000000..4f436ee03d6 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/pair/p2321.cc @@ -0,0 +1,208 @@ +// Verify P2321R2 "zip" enhancements to std::pair. +// { dg-options "-std=gnu++23" } +// { dg-do run { target c++23 } } + +#include +#include + +using std::pair; + +struct A { }; + +constexpr bool +test01() +{ + struct B { bool v; constexpr B(A&) : v(true) { } }; + + // template + // constexpr explicit(false) pair(pair&); + + pair p2a0; + pair p2b0 = p2a0; + VERIFY( std::get<0>(p2b0).v ); + + pair p2a1; + pair p2b1 = p2a1; + VERIFY( std::get<1>(p2b1).v ); + + return true; +} + +constexpr bool +test02() +{ + struct B { bool v; explicit constexpr B(A&) : v(true) { } }; + + // template + // constexpr explicit(true) pair(pair&); + + static_assert(!std::is_convertible_v&, pair>); + static_assert(!std::is_convertible_v&, pair>); + + pair p2a0; + pair p2b0(p2a0); + VERIFY( std::get<0>(p2b0).v ); + + pair p2a1; + pair p2b1(p2a1); + VERIFY( std::get<1>(p2b1).v ); + + return true; +} + +constexpr bool +test03() +{ + struct B { bool v; constexpr B(const A&&) : v(true) { } }; + + // template + // constexpr explicit(false) pair(const pair&&); + + const pair p2a0; + pair p2b0 = std::move(p2a0); + VERIFY( std::get<0>(p2b0).v ); + + const pair p2a1; + pair p2b1 = std::move(p2a1); + VERIFY( std::get<1>(p2b1).v ); + + return true; +} + +constexpr bool +test04() +{ + struct B { bool v; explicit constexpr B(const A&&) : v(true) { } }; + + // template + // constexpr explicit(true) pair(const pair&&); + + static_assert(!std::is_convertible_v&&, pair>); + static_assert(!std::is_convertible_v&&, pair>); + + const pair p2a0; + pair p2b0(std::move(p2a0)); + VERIFY( std::get<0>(p2b0).v ); + + const pair p2a1; + pair p2b1(std::move(p2a1)); + VERIFY( std::get<1>(p2b1).v ); + + return true; +} + +constexpr bool +test05() +{ + struct B + { + mutable bool v; + constexpr const B& operator=(const A&) const { v = true; return *this; } + }; + + // template + // constexpr const pair& operator=(const pair&) const; + + const pair p2a; + const pair p2b; + p2b = p2a; + + return true; +} + +constexpr bool +test06() +{ + struct B + { + mutable bool v; + constexpr const B& operator=(A&&) const { v = true; return *this; } + }; + + // template + // constexpr const pair& operator=(pair&&) const; + + pair p2a; + const pair p2b; + p2b = std::move(p2a); + + return true; +} + +constexpr bool +test07() +{ + struct B + { + mutable bool v; + constexpr const B& operator=(const B&) const { v = true; return *this; } + }; + + // constexpr const pair& operator=(const pair&) const; + + const pair t2a; + const pair t2b; + t2b = t2a; + VERIFY( std::get<0>(t2b).v ); + VERIFY( std::get<1>(t2b).v ); + + return true; +} + +constexpr bool +test08() +{ + struct B + { + mutable bool v; + constexpr const B& operator=(B&&) const { v = true; return *this; } + }; + + // constexpr const pair& operator=(pair&&) const; + + pair t2a; + const pair t2b; + t2b = std::move(t2a); + VERIFY( std::get<0>(t2b).v ); + VERIFY( std::get<1>(t2b).v ); + + return true; +} + +struct S +{ + mutable int v = 0; + friend constexpr void swap(S&& x, S&& y) = delete; + friend constexpr void swap(const S& x, const S& y) { ++x.v; ++y.v; } +}; + +constexpr bool +test09() +{ + const pair t2, u2; + std::swap(t2, u2); + VERIFY( std::get<0>(t2).v == 1 ); + VERIFY( std::get<0>(u2).v == 1 ); + VERIFY( std::get<1>(t2).v == 1 ); + VERIFY( std::get<1>(u2).v == 1 ); + + static_assert(!std::is_swappable_v&>); + static_assert(!std::is_swappable_v&>); + + return true; +} + +int +main() +{ + static_assert(test01()); + static_assert(test02()); + static_assert(test03()); + static_assert(test04()); + // FIXME: G++ doesn't support reading mutable members during constexpr (PR c++/92505). + test05(); + test06(); + test07(); + test08(); + test09(); +} diff --git a/libstdc++-v3/testsuite/20_util/tuple/p2321.cc b/libstdc++-v3/testsuite/20_util/tuple/p2321.cc new file mode 100644 index 00000000000..80fc23cf9d4 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/tuple/p2321.cc @@ -0,0 +1,664 @@ +// Verify P2321R2 "zip" enhancements to std::tuple. +// { dg-options "-std=gnu++23" } +// { dg-do run { target c++23 } } + +#include +#include +#include + +using std::tuple; +using std::pair; +using std::allocator; +using std::allocator_arg_t; +using std::allocator_arg; + +namespace alloc { + struct B01; + struct B02; + struct B03; + struct B04; +} + +template<> struct std::uses_allocator> : std::true_type { }; +template<> struct std::uses_allocator> : std::true_type { }; +template<> struct std::uses_allocator> : std::true_type { }; +template<> struct std::uses_allocator> : std::true_type { }; + +struct A { }; + +constexpr bool +test01() +{ + struct B { bool v; constexpr B(A&) : v(true) { } }; + + // template + // constexpr explicit(false) tuple(tuple&); + + tuple t1a; + tuple t1b = t1a; + VERIFY( std::get<0>(t1b).v ); + + tuple t2a0; + tuple t2b0 = t2a0; + VERIFY( std::get<0>(t2b0).v ); + + tuple t2a1; + tuple t2b1 = t2a1; + VERIFY( std::get<1>(t2b1).v ); + + tuple t3a0; + tuple t3b0 = t3a0; + VERIFY( std::get<0>(t3b0).v ); + + tuple t3a1; + tuple t3b1 = t3a1; + VERIFY( std::get<1>(t3b1).v ); + + tuple t3a2; + tuple t3b2 = t3a2; + VERIFY( std::get<2>(t3b2).v ); + + // template + // constexpr explicit(false) tuple(pair&); + + pair p2a0; + tuple p2b0 = p2a0; + VERIFY( std::get<0>(p2b0).v ); + + pair p2a1; + tuple p2b1 = p2a1; + VERIFY( std::get<1>(p2b1).v ); + + return true; +} + +namespace alloc +{ + struct B01 + { + bool v; + B01(A&); + constexpr B01(allocator_arg_t, allocator, A&) : v(true) { } + }; + + constexpr bool + test01() + { + using B = B01; + + // template + // constexpr explicit(false) + // tuple(allocator_arg_t, const Alloc& a, tuple&); + + tuple t1a; + tuple t1b = {allocator_arg, allocator{}, t1a}; + VERIFY( std::get<0>(t1b).v ); + + tuple t2a0; + tuple t2b0 = {allocator_arg, allocator{}, t2a0}; + VERIFY( std::get<0>(t2b0).v ); + + tuple t2a1; + tuple t2b1 = {allocator_arg, allocator{}, t2a1}; + VERIFY( std::get<1>(t2b1).v ); + + tuple t3a0; + tuple t3b0 = {allocator_arg, allocator{}, t3a0}; + VERIFY( std::get<0>(t3b0).v ); + + tuple t3a1; + tuple t3b1 = {allocator_arg, allocator{}, t3a1}; + VERIFY( std::get<1>(t3b1).v ); + + tuple t3a2; + tuple t3b2 = {allocator_arg, allocator{}, t3a2}; + VERIFY( std::get<2>(t3b2).v ); + + // template + // constexpr explicit(false) + // tuple(allocator_arg_t, const Alloc& a, pair&); + + pair p2a0; + tuple p2b0 = {allocator_arg, allocator{}, p2a0}; + VERIFY( std::get<0>(p2b0).v ); + + pair p2a1; + tuple p2b1 = {allocator_arg, allocator{}, p2a1}; + VERIFY( std::get<1>(p2b1).v ); + + return true; + } +} + +constexpr bool +test02() +{ + struct B { bool v; explicit constexpr B(A&) : v(true) { } }; + + // template + // constexpr explicit(true) tuple(tuple&); + + static_assert(!std::is_convertible_v&, tuple>); + + tuple t1a; + tuple t1b(t1a); + VERIFY( std::get<0>(t1b).v ); + + static_assert(!std::is_convertible_v&, tuple>); + static_assert(!std::is_convertible_v&, tuple>); + + tuple t2a0; + tuple t2b0(t2a0); + VERIFY( std::get<0>(t2b0).v ); + + tuple t2a1; + tuple t2b1(t2a1); + VERIFY( std::get<1>(t2b1).v ); + + static_assert(!std::is_convertible_v&, tuple>); + static_assert(!std::is_convertible_v&, tuple>); + static_assert(!std::is_convertible_v&, tuple>); + + tuple t3a0; + tuple t3b0(t3a0); + VERIFY( std::get<0>(t3b0).v ); + + tuple t3a1; + tuple t3b1(t3a1); + VERIFY( std::get<1>(t3b1).v ); + + tuple t3a2; + tuple t3b2(t3a2); + VERIFY( std::get<2>(t3b2).v ); + + // template + // constexpr explicit(true) tuple(pair&); + + static_assert(!std::is_convertible_v&, tuple>); + static_assert(!std::is_convertible_v&, tuple>); + + pair p2a0; + tuple p2b0(p2a0); + VERIFY( std::get<0>(p2b0).v ); + + pair p2a1; + tuple p2b1(p2a1); + VERIFY( std::get<1>(p2b1).v ); + + return true; +} + +namespace alloc +{ + struct B02 + { + bool v; + explicit B02(A&); + explicit constexpr B02(allocator_arg_t, allocator, A&) : v(true) { } + }; + + constexpr bool + test02() + { + using B = B02; + + // template + // constexpr explicit(true) + // tuple(allocator_arg_t, const Alloc& a, tuple&); + + tuple t1a; + tuple t1b(allocator_arg, allocator{}, t1a); + VERIFY( std::get<0>(t1b).v ); + + tuple t2a0; + tuple t2b0(allocator_arg, allocator{}, t2a0); + VERIFY( std::get<0>(t2b0).v ); + + tuple t2a1; + tuple t2b1(allocator_arg, allocator{}, t2a1); + VERIFY( std::get<1>(t2b1).v ); + + tuple t3a0; + tuple t3b0(allocator_arg, allocator{}, t3a0); + VERIFY( std::get<0>(t3b0).v ); + + tuple t3a1; + tuple t3b1(allocator_arg, allocator{}, t3a1); + VERIFY( std::get<1>(t3b1).v ); + + tuple t3a2; + tuple t3b2(allocator_arg, allocator{}, t3a2); + VERIFY( std::get<2>(t3b2).v ); + + // template + // constexpr explicit(true) + // tuple(allocator_arg_t, const Alloc& a, pair&); + + pair p2a0; + tuple p2b0(allocator_arg, allocator{}, p2a0); + VERIFY( std::get<0>(p2b0).v ); + + pair p2a1; + tuple p2b1(allocator_arg, allocator{}, p2a1); + VERIFY( std::get<1>(p2b1).v ); + + return true; + } +} // namespace alloc + +constexpr bool +test03() +{ + struct B { bool v; constexpr B(const A&&) : v(true) { } }; + + // template + // constexpr explicit(false) tuple(const tuple&&); + + const tuple t1a; + tuple t1b = std::move(t1a); + VERIFY( std::get<0>(t1b).v ); + + const tuple t2a0; + tuple t2b0 = std::move(t2a0); + VERIFY( std::get<0>(t2b0).v ); + + const tuple t2a1; + tuple t2b1 = std::move(t2a1); + VERIFY( std::get<1>(t2b1).v ); + + const tuple t3a0; + tuple t3b0 = std::move(t3a0); + VERIFY( std::get<0>(t3b0).v ); + + const tuple t3a1; + tuple t3b1 = std::move(t3a1); + VERIFY( std::get<1>(t3b1).v ); + + const tuple t3a2; + tuple t3b2 = std::move(t3a2); + VERIFY( std::get<2>(t3b2).v ); + + // template + // constexpr explicit(false) tuple(const pair&&); + + const pair p2a0; + tuple p2b0 = std::move(p2a0); + VERIFY( std::get<0>(p2b0).v ); + + const pair p2a1; + tuple p2b1 = std::move(p2a1); + VERIFY( std::get<1>(p2b1).v ); + + return true; +} + +namespace alloc +{ + struct B03 + { + bool v; + B03(const A&&); + constexpr B03(allocator_arg_t, allocator, const A&&) : v(true) { } + }; + + constexpr bool + test03() + { + using B = B03; + + // template + // constexpr explicit(false) + // tuple(allocator_arg_t, const Alloc& a, const tuple&&); + + const tuple t1a; + tuple t1b = {allocator_arg, allocator{}, std::move(t1a)}; + VERIFY( std::get<0>(t1b).v ); + + const tuple t2a0; + tuple t2b0 = {allocator_arg, allocator{}, std::move(t2a0)}; + VERIFY( std::get<0>(t2b0).v ); + + const tuple t2a1; + tuple t2b1 = {allocator_arg, allocator{}, std::move(t2a1)}; + VERIFY( std::get<1>(t2b1).v ); + + const tuple t3a0; + tuple t3b0 = {allocator_arg, allocator{}, std::move(t3a0)}; + VERIFY( std::get<0>(t3b0).v ); + + const tuple t3a1; + tuple t3b1 = {allocator_arg, allocator{}, std::move(t3a1)}; + VERIFY( std::get<1>(t3b1).v ); + + const tuple t3a2; + tuple t3b2 = {allocator_arg, allocator{}, std::move(t3a2)}; + VERIFY( std::get<2>(t3b2).v ); + + // template + // constexpr explicit(false) + // tuple(allocator_arg_t, const Alloc& a, const pair&&); + + const pair p2a0; + tuple p2b0 = {allocator_arg, allocator{}, std::move(p2a0)}; + VERIFY( std::get<0>(p2b0).v ); + + const pair p2a1; + tuple p2b1 = {allocator_arg, allocator{}, std::move(p2a1)}; + VERIFY( std::get<1>(p2b1).v ); + + return true; + } +}; + +constexpr bool +test04() +{ + struct B { bool v; explicit constexpr B(const A&&) : v(true) { } }; + + // template + // constexpr explicit(true) tuple(const tuple&&); + + static_assert(!std::is_convertible_v&, tuple>); + + const tuple t1a; + tuple t1b(std::move(t1a)); + VERIFY( std::get<0>(t1b).v ); + + static_assert(!std::is_convertible_v&, tuple>); + static_assert(!std::is_convertible_v&, tuple>); + + const tuple t2a0; + tuple t2b0(std::move(t2a0)); + VERIFY( std::get<0>(t2b0).v ); + + const tuple t2a1; + tuple t2b1(std::move(t2a1)); + VERIFY( std::get<1>(t2b1).v ); + + static_assert(!std::is_convertible_v&, tuple>); + static_assert(!std::is_convertible_v&, tuple>); + static_assert(!std::is_convertible_v&, tuple>); + + const tuple t3a0; + tuple t3b0(std::move(t3a0)); + VERIFY( std::get<0>(t3b0).v ); + + const tuple t3a1; + tuple t3b1(std::move(t3a1)); + VERIFY( std::get<1>(t3b1).v ); + + const tuple t3a2; + tuple t3b2(std::move(t3a2)); + VERIFY( std::get<2>(t3b2).v ); + + // template + // constexpr explicit(true) tuple(const pair&&); + + static_assert(!std::is_convertible_v&, tuple>); + static_assert(!std::is_convertible_v&, tuple>); + + const pair p2a0; + tuple p2b0(std::move(p2a0)); + VERIFY( std::get<0>(p2b0).v ); + + const pair p2a1; + tuple p2b1(std::move(p2a1)); + VERIFY( std::get<1>(p2b1).v ); + + return true; +} + +namespace alloc +{ + struct B04 + { + bool v; + explicit B04(const A&&); + explicit constexpr B04(allocator_arg_t, allocator, const A&&) : v(true) { } + }; + + constexpr bool + test04() + { + using B = B04; + + // template + // constexpr explicit(true) + // tuple(allocator_arg_t, const Alloc& a, const tuple&&); + + const tuple t1a; + tuple t1b(allocator_arg, allocator{}, std::move(t1a)); + VERIFY( std::get<0>(t1b).v ); + + const tuple t2a0; + tuple t2b0(allocator_arg, allocator{}, std::move(t2a0)); + VERIFY( std::get<0>(t2b0).v ); + + const tuple t2a1; + tuple t2b1(allocator_arg, allocator{}, std::move(t2a1)); + VERIFY( std::get<1>(t2b1).v ); + + const tuple t3a0; + tuple t3b0(allocator_arg, allocator{}, std::move(t3a0)); + VERIFY( std::get<0>(t3b0).v ); + + const tuple t3a1; + tuple t3b1(allocator_arg, allocator{}, std::move(t3a1)); + VERIFY( std::get<1>(t3b1).v ); + + const tuple t3a2; + tuple t3b2(allocator_arg, allocator{}, std::move(t3a2)); + VERIFY( std::get<2>(t3b2).v ); + + // template + // constexpr explicit(true) + // tuple(allocator_arg_t, const Alloc& a, const pair&&); + + tuple p2b0(allocator_arg, allocator{}, std::move(t2a0)); + VERIFY( std::get<0>(p2b0).v ); + + tuple p2b1(allocator_arg, allocator{}, std::move(t2a1)); + VERIFY( std::get<1>(p2b1).v ); + + return true; + } +}; + +constexpr bool +test05() +{ + struct B + { + mutable bool v; + constexpr const B& operator=(const A&) const { v = true; return *this; } + }; + + // template + // constexpr const tuple& operator=(const tuple&) const; + + const tuple t1a; + const tuple t1b; + t1b = t1a; + VERIFY( std::get<0>(t1b).v ); + + const tuple t2a; + const tuple t2b; + t2b = t2a; + VERIFY( std::get<0>(t2b).v ); + VERIFY( std::get<1>(t2b).v ); + + const tuple t3a; + const tuple t3b; + t3b = t3a; + VERIFY( std::get<0>(t3b).v ); + VERIFY( std::get<1>(t3b).v ); + VERIFY( std::get<2>(t3b).v ); + + // template + // constexpr const tuple& operator=(const pair&) const; + + const pair p2a; + const tuple p2b; + p2b = p2a; + + return true; +} + +constexpr bool +test06() +{ + struct B + { + mutable bool v; + constexpr const B& operator=(A&&) const { v = true; return *this; } + }; + + // template + // constexpr const tuple& operator=(tuple&&) const; + + tuple t1a; + const tuple t1b; + t1b = std::move(t1a); + VERIFY( std::get<0>(t1b).v ); + + tuple t2a; + const tuple t2b; + t2b = std::move(t2a); + VERIFY( std::get<0>(t2b).v ); + VERIFY( std::get<1>(t2b).v ); + + tuple t3a; + const tuple t3b; + t3b = std::move(t3a); + VERIFY( std::get<0>(t3b).v ); + VERIFY( std::get<1>(t3b).v ); + VERIFY( std::get<2>(t3b).v ); + + // template + // constexpr const tuple& operator=(pair&&) const; + + pair p2a; + const tuple p2b; + p2b = std::move(p2a); + + return true; +} + +constexpr bool +test07() +{ + struct B + { + mutable bool v; + constexpr const B& operator=(const B&) const { v = true; return *this; } + }; + + // constexpr const tuple& operator=(const tuple&) const; + + const tuple t1a; + const tuple t1b; + t1b = t1a; + VERIFY( std::get<0>(t1b).v ); + + const tuple t2a; + const tuple t2b; + t2b = t2a; + VERIFY( std::get<0>(t2b).v ); + VERIFY( std::get<1>(t2b).v ); + + const tuple t3a; + const tuple t3b; + t3b = t3a; + VERIFY( std::get<0>(t3b).v ); + VERIFY( std::get<1>(t3b).v ); + VERIFY( std::get<2>(t3b).v ); + + return true; +} + +constexpr bool +test08() +{ + struct B + { + mutable bool v; + constexpr const B& operator=(B&&) const { v = true; return *this; } + }; + + // constexpr const tuple& operator=(tuple&&) const; + + tuple t1a; + const tuple t1b; + t1b = std::move(t1a); + VERIFY( std::get<0>(t1b).v ); + + tuple t2a; + const tuple t2b; + t2b = std::move(t2a); + VERIFY( std::get<0>(t2b).v ); + VERIFY( std::get<1>(t2b).v ); + + tuple t3a; + const tuple t3b; + t3b = std::move(t3a); + VERIFY( std::get<0>(t3b).v ); + VERIFY( std::get<1>(t3b).v ); + VERIFY( std::get<2>(t3b).v ); + + return true; +} + +struct S +{ + mutable int v = 0; + friend constexpr void swap(S&& x, S&& y) = delete; + friend constexpr void swap(const S& x, const S& y) { ++x.v; ++y.v; } +}; + +constexpr bool +test09() +{ + const tuple t1, u1; + std::swap(t1, u1); + VERIFY( std::get<0>(t1).v == 1 ); + VERIFY( std::get<0>(u1).v == 1 ); + + const tuple t2, u2; + std::swap(t2, u2); + VERIFY( std::get<0>(t2).v == 1 ); + VERIFY( std::get<0>(u2).v == 1 ); + VERIFY( std::get<1>(t2).v == 1 ); + VERIFY( std::get<1>(u2).v == 1 ); + + const tuple t3, u3; + std::swap(t3, u3); + VERIFY( std::get<0>(t3).v == 1 ); + VERIFY( std::get<0>(u3).v == 1 ); + VERIFY( std::get<1>(t3).v == 1 ); + VERIFY( std::get<1>(u3).v == 1 ); + VERIFY( std::get<2>(t3).v == 1 ); + VERIFY( std::get<2>(u3).v == 1 ); + + static_assert(!std::is_swappable_v&>); + + return true; +} + +int +main() +{ + static_assert(test01()); + static_assert(alloc::test01()); + static_assert(test02()); + static_assert(alloc::test02()); + static_assert(test03()); + static_assert(alloc::test03()); + static_assert(test04()); + static_assert(alloc::test04()); + // FIXME: G++ doesn't support reading mutable members during constexpr (PR c++/92505). + test05(); + test06(); + test07(); + test08(); + test09(); +} diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/1.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/1.cc new file mode 100644 index 00000000000..9016c026b33 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/1.cc @@ -0,0 +1,26 @@ +// { dg-options "-std=gnu++23" } +// { dg-do compile { target c++23 } } +// { dg-xfail-if "not supported" { debug_mode } } + +#include +#include + +constexpr bool +test01() +{ + // P2321R2 + // constexpr const reference& vector::operator=(bool x) const noexcept; + + std::vector v(1); + const auto e = v[0]; + e = true; + VERIFY( v[0] ); + + return true; +} + +int +main() +{ + static_assert(test01()); +} From patchwork Tue Aug 23 01:35:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 667 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:adf:ecc5:0:0:0:0:0 with SMTP id s5csp747483wro; Mon, 22 Aug 2022 18:37:08 -0700 (PDT) X-Google-Smtp-Source: AA6agR7cXWXX034NH1CPi/V2aREJOueCysgpBk4YBNHeMJCAQP1P3q1Eii/1pHusBee6rs2ktE0y X-Received: by 2002:a05:6402:51cb:b0:43e:8f40:858d with SMTP id r11-20020a05640251cb00b0043e8f40858dmr1463586edd.391.1661218628266; Mon, 22 Aug 2022 18:37:08 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1661218628; cv=none; d=google.com; s=arc-20160816; b=yL3JczDUfMrsfA8/0XwQosekruhim8VC9NpxVKROCQTfw3ljSVkHd0LmFV2m+RLkDC VQiGCjhWIYbV9/dQiOqNXFDLlCxlh7UBexec0D3pE96D1pmq7Ncy9cT8VJ3+bPkcKPX3 z3nubeC/c+LTBwzKTMeo5cyMvKjU2QMTq/5+IQurfXH92pUPsIcqt7/UQBpTa3NavCAL scNeQWhgaPh/JD2PAscDnecKolybwVFBZAwJTGjDlqcRbCtSqjZH5Z69ZK5pCtxX7FaU BuoJBRWTgsVPGpdOehZpb8Gx3zS2ifeoEsJtbL2OXts5p9GWJhKt8+Fq5yzn8JQnhjl/ T3uA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:cc:reply-to:from:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence :content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:dmarc-filter:delivered-to:dkim-signature :dkim-filter; bh=jh6iULO3RrFkPQ7YkNMP9Aqms5+GfKMleOi4cMsAkJU=; b=JRzDXS3ABf7V9olmlr2Ek+4EM7dqN/PqZCeWcrU6R0hBkhoHmyUyoqN/WqAlEpVwJV QWToH6ynCrlIlWM0n4xKMAiqrQ4ULh4DuKOyP1qI1SKFyPnQjsV+nOzniyRQniY6MURi PHmjDLyBVMyb9U62u3XMTB37FzH9Gsap0jBugBu1aDCjMtapHEuwuduuLD6J4znOWvZN JNacjCPNwQrdwfUL3JTyYPdsFWIbXsftTl4rTr7vS1Kn0moDr3CMRcfp1cz/GfEVVi9n i4OmIDi2xGe8PKdqoU8KkIA2zU6K8rrgVE9JBSbMUabnh6FcbiIMBuL4qnXho9jwXpRC qkHw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=Qeu3pJzN; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id ga7-20020a1709070c0700b0073d866e5d4dsi3559862ejc.98.2022.08.22.18.37.07 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Aug 2022 18:37:08 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@gcc.gnu.org header.s=default header.b=Qeu3pJzN; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org"; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=gnu.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 48DDE3853838 for ; Tue, 23 Aug 2022 01:35:57 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 48DDE3853838 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1661218557; bh=jh6iULO3RrFkPQ7YkNMP9Aqms5+GfKMleOi4cMsAkJU=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To:Cc: From; b=Qeu3pJzNmFZeLkiNODG+6/kl3ul0QPNNvTzcdI8uJ6wkSge9+e319elmx7cUIJbGJ X7bn0G9dWJmfCpMQKnXV+0aA5RZgxFXolCwUVEhFLtZUb1PLvxnOcz6JHT2bOKvLUt N/D1qRSafNhiMriVi7eDg0SkXLN2RlnLGmTmncQc= 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.129.124]) by sourceware.org (Postfix) with ESMTPS id 66E8B3857C69 for ; Tue, 23 Aug 2022 01:35:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 66E8B3857C69 Received: from mail-qv1-f70.google.com (mail-qv1-f70.google.com [209.85.219.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-635-k-0C-o5aPEuGbgeYNhGbDA-1; Mon, 22 Aug 2022 21:35:07 -0400 X-MC-Unique: k-0C-o5aPEuGbgeYNhGbDA-1 Received: by mail-qv1-f70.google.com with SMTP id dh19-20020ad458d3000000b00496bf7e4a72so5851813qvb.0 for ; Mon, 22 Aug 2022 18:35:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc; bh=jh6iULO3RrFkPQ7YkNMP9Aqms5+GfKMleOi4cMsAkJU=; b=C0zozyReAvdE7/9pDeSFj31IkkMnSdKF2V2pDTcYUDnAVabgUiPh5rZEQlj/aIKrHO Fgc4o4MLjxGX4FAsVLWJTxvqG73GIEYPY7HUGWgtbF/ziD1q9BJmSqOkXXs7ZVZEB0Ek 1upPQsNkGjqeKemtYMSGZejt+DnyfG2A4g4tX3NXfD0rMOh0AlR5Y/vSFdhclPOj1BFk 5tiYo2F9tzwspu1RNr8O0mkpUe6QItp97F/0hIB1CYcv61M7caqSeQdC8WxjtCy7kYtE 8EOyOwsle+5zMNUs1MX7DOE89/MLer+VpUWTbE4ejsMCLOYGbfGfxfc0OT+bmahQ8niu IkTQ== X-Gm-Message-State: ACgBeo2DDdLi8YLZ9Hc1l+2X8xIfBv0rdEz79R1hQvHTVlCIMzt38DjN p5dYjgcBN1tRcRAxaVta6nCvxBKJsS8A/Q/nL+vmEpI7rzRdIBXdHuM6EknhZqGeU1h/+WcYaCc 68Vx7oqWRB0nsyi/ESzRrKPD0xrHF3WNdw32J9+WoKrJLILo8fsOE5Ocajsr4F1y11hI= X-Received: by 2002:a05:622a:11c5:b0:344:8dac:6552 with SMTP id n5-20020a05622a11c500b003448dac6552mr17554325qtk.660.1661218506185; Mon, 22 Aug 2022 18:35:06 -0700 (PDT) X-Received: by 2002:a05:622a:11c5:b0:344:8dac:6552 with SMTP id n5-20020a05622a11c500b003448dac6552mr17554301qtk.660.1661218505680; Mon, 22 Aug 2022 18:35:05 -0700 (PDT) Received: from localhost.localdomain (ool-457670bb.dyn.optonline.net. [69.118.112.187]) by smtp.gmail.com with ESMTPSA id p11-20020ac8740b000000b00342fcdc2d46sm9816942qtq.56.2022.08.22.18.35.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 22 Aug 2022 18:35:05 -0700 (PDT) To: gcc-patches@gcc.gnu.org Subject: [PATCH 3/3] libstdc++: Implement ranges::zip_view from P2321R2 Date: Mon, 22 Aug 2022 21:35:00 -0400 Message-Id: <20220823013500.1756466-3-ppalka@redhat.com> X-Mailer: git-send-email 2.37.2.382.g795ea8776b In-Reply-To: <20220823013500.1756466-1-ppalka@redhat.com> References: <20220823013500.1756466-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-14.1 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE 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 Cc: libstdc++@gcc.gnu.org Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1741913984312936437?= X-GMAIL-MSGID: =?utf-8?q?1741913984312936437?= Tested on 86_64-pc-linux-gnu, does this look OK for trunk? libstdc++-v3/ChangeLog: * include/bits/ranges_algo.h (__min_fn, min): Move to ... * include/bits/ranges_util.h: ... here in order to avoid including all of ranges_algo.h from . * include/std/ranges (__detail::__zip_is_common): Define for C++23 as per P2321R2. (__detail::__tuple_or_pair): Likewise. (__detail::__tuple_or_pair_t): Likewise. (__detail::__tuple_transform): Likewise. (__detail::__tuple_for_each): Likewise. (zip_view): Likewise. (enable_borrowed_range): Likewise. (__detail::__all_random_access): Likewise. (__detail::__all_bidirectional): Likewise. (__detail::__all_forward): Likewise. (__detail::__zip_view_iter_cat): Likewise. (zip_view::iterator): Likewise. (zip_view::sentinel): Likewise. (testsuite/std/ranges/zip/1.cc): New test. --- libstdc++-v3/include/bits/ranges_algo.h | 54 +-- libstdc++-v3/include/bits/ranges_util.h | 55 +++ libstdc++-v3/include/std/ranges | 445 +++++++++++++++++++++ libstdc++-v3/testsuite/std/ranges/zip/1.cc | 101 +++++ 4 files changed, 602 insertions(+), 53 deletions(-) create mode 100644 libstdc++-v3/testsuite/std/ranges/zip/1.cc diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h index 3d30fb1428c..2a116361a67 100644 --- a/libstdc++-v3/include/bits/ranges_algo.h +++ b/libstdc++-v3/include/bits/ranges_algo.h @@ -2902,59 +2902,7 @@ namespace ranges inline constexpr __set_symmetric_difference_fn set_symmetric_difference{}; - struct __min_fn - { - template> - _Comp = ranges::less> - constexpr const _Tp& - operator()(const _Tp& __a, const _Tp& __b, - _Comp __comp = {}, _Proj __proj = {}) const - { - if (std::__invoke(__comp, - std::__invoke(__proj, __b), - std::__invoke(__proj, __a))) - return __b; - else - return __a; - } - - template, _Proj>> - _Comp = ranges::less> - requires indirectly_copyable_storable, - range_value_t<_Range>*> - constexpr range_value_t<_Range> - operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const - { - auto __first = ranges::begin(__r); - auto __last = ranges::end(__r); - __glibcxx_assert(__first != __last); - auto __result = *__first; - while (++__first != __last) - { - auto __tmp = *__first; - if (std::__invoke(__comp, - std::__invoke(__proj, __tmp), - std::__invoke(__proj, __result))) - __result = std::move(__tmp); - } - return __result; - } - - template> - _Comp = ranges::less> - constexpr _Tp - operator()(initializer_list<_Tp> __r, - _Comp __comp = {}, _Proj __proj = {}) const - { - return (*this)(ranges::subrange(__r), - std::move(__comp), std::move(__proj)); - } - }; - - inline constexpr __min_fn min{}; + // min is defined in . struct __max_fn { diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h index 37d7bc862f9..bb56deee01b 100644 --- a/libstdc++-v3/include/bits/ranges_util.h +++ b/libstdc++-v3/include/bits/ranges_util.h @@ -649,6 +649,61 @@ namespace ranges }; inline constexpr __search_fn search{}; + + struct __min_fn + { + template> + _Comp = ranges::less> + constexpr const _Tp& + operator()(const _Tp& __a, const _Tp& __b, + _Comp __comp = {}, _Proj __proj = {}) const + { + if (std::__invoke(__comp, + std::__invoke(__proj, __b), + std::__invoke(__proj, __a))) + return __b; + else + return __a; + } + + template, _Proj>> + _Comp = ranges::less> + requires indirectly_copyable_storable, + range_value_t<_Range>*> + constexpr range_value_t<_Range> + operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const + { + auto __first = ranges::begin(__r); + auto __last = ranges::end(__r); + __glibcxx_assert(__first != __last); + auto __result = *__first; + while (++__first != __last) + { + auto __tmp = *__first; + if (std::__invoke(__comp, + std::__invoke(__proj, __tmp), + std::__invoke(__proj, __result))) + __result = std::move(__tmp); + } + return __result; + } + + template> + _Comp = ranges::less> + constexpr _Tp + operator()(initializer_list<_Tp> __r, + _Comp __comp = {}, _Proj __proj = {}) const + { + return (*this)(ranges::subrange(__r), + std::move(__comp), std::move(__proj)); + } + }; + + inline constexpr __min_fn min{}; + } // namespace ranges using ranges::get; diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 3e71ecb32b7..8d0c2a52b40 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -39,6 +39,7 @@ #if __cpp_lib_concepts #include +#include #include #include #include @@ -4352,6 +4353,450 @@ namespace views::__adaptor inline constexpr auto values = elements<1>; } // namespace views +#if __cplusplus > 202002L + namespace __detail + { + template + concept __zip_is_common = (sizeof...(_Rs) == 1 && (common_range<_Rs> && ...)) + || (!(bidirectional_range<_Rs> && ...) && (common_range<_Rs> && ...)) + || ((random_access_range<_Rs> && ...) && (sized_range<_Rs> && ...)); + + template + struct __tuple_or_pair + { using type = std::tuple<_Ts...>; }; + + template + struct __tuple_or_pair<_Tp, _Up> + { using type = pair<_Tp, _Up>; }; + + template + using __tuple_or_pair_t = typename __tuple_or_pair<_Ts...>::type; + + template + constexpr auto + __tuple_transform(_Fp&& __f, _Tuple&& __tuple) + { + return std::apply([&](_Ts&&... __elts) { + return __tuple_or_pair_t...> + (std::__invoke(__f, std::forward<_Ts>(__elts))...); + }, std::forward<_Tuple>(__tuple)); + } + + template + constexpr void + __tuple_for_each(_Fp&& __f, _Tuple&& __tuple) + { + std::apply([&](_Ts&&... __elts) { + (std::__invoke(__f, std::forward<_Ts>(__elts)), ...); + }, std::forward<_Tuple>(__tuple)); + } + } // namespace __detail + + template + requires (view<_Vs> && ...) && (sizeof...(_Vs) > 0) + class zip_view : public view_interface> + { + tuple<_Vs...> _M_views; + + template class iterator; + template class sentinel; + + public: + zip_view() = default; + + constexpr explicit + zip_view(_Vs... views) + : _M_views(std::move(views)...) + { } + + constexpr auto + begin() requires (!(__detail::__simple_view<_Vs> && ...)) + { return iterator(__detail::__tuple_transform(ranges::begin, _M_views)); } + + constexpr auto + begin() const requires (range && ...) + { return iterator(__detail::__tuple_transform(ranges::begin, _M_views)); } + + constexpr auto + end() requires (!(__detail::__simple_view<_Vs> && ...)) + { + if constexpr (!__detail::__zip_is_common<_Vs...>) + return sentinel(__detail::__tuple_transform(ranges::end, _M_views)); + else if constexpr ((random_access_range<_Vs> && ...)) + return begin() + iter_difference_t>(size()); + else + return iterator(__detail::__tuple_transform(ranges::end, _M_views)); + } + + constexpr auto + end() const requires (range && ...) + { + if constexpr (!__detail::__zip_is_common) + return sentinel(__detail::__tuple_transform(ranges::end, _M_views)); + else if constexpr ((random_access_range && ...)) + return begin() + iter_difference_t>(size()); + else + return iterator(__detail::__tuple_transform(ranges::end, _M_views)); + } + + constexpr auto + size() requires (sized_range<_Vs> && ...) + { + return std::apply([](auto... sizes) { + using _CT = __detail::__make_unsigned_like_t>; + return ranges::min({_CT(sizes)...}); + }, __detail::__tuple_transform(ranges::size, _M_views)); + } + + constexpr auto + size() const requires (sized_range && ...) + { + return std::apply([](auto... sizes) { + using _CT = __detail::__make_unsigned_like_t>; + return ranges::min({_CT(sizes)...}); + }, __detail::__tuple_transform(ranges::size, _M_views)); + } + }; + + template + zip_view(_Rs&&...) -> zip_view...>; + + template + inline constexpr bool enable_borrowed_range> + = (enable_borrowed_range<_Views> && ...); + + namespace __detail + { + template + concept __all_random_access + = (random_access_range<__maybe_const_t<_Const, _Vs>> && ...); + + template + concept __all_bidirectional + = (bidirectional_range<__maybe_const_t<_Const, _Vs>> && ...); + + template + concept __all_forward + = (forward_range<__maybe_const_t<_Const, _Vs>> && ...); + + template + struct __zip_view_iter_cat + { }; + + template + requires __all_forward<_Const, _Views...> + struct __zip_view_iter_cat<_Const, _Views...> + { using iterator_category = input_iterator_tag; }; + } // namespace __detail + + template + requires (view<_Vs> && ...) && (sizeof...(_Vs) > 0) + template + class zip_view<_Vs...>::iterator + : public __detail::__zip_view_iter_cat<_Const, _Vs...> + { + __detail::__tuple_or_pair_t>...> _M_current; + + constexpr explicit + iterator(decltype(_M_current) __current) + : _M_current(std::move(__current)) + { } + + static auto + _S_iter_concept() + { + if constexpr (__detail::__all_random_access<_Const, _Vs...>) + return random_access_iterator_tag{}; + else if constexpr (__detail::__all_bidirectional<_Const, _Vs...>) + return bidirectional_iterator_tag{}; + else if constexpr (__detail::__all_forward<_Const, _Vs...>) + return forward_iterator_tag{}; + else + return input_iterator_tag{}; + } + + public: + // iterator_category defined in __zip_view_iter_cat + using iterator_concept = decltype(_S_iter_concept()); + using value_type + = __detail::__tuple_or_pair_t>...>; + using difference_type + = common_type_t>...>; + + iterator() = default; + + constexpr + iterator(iterator __i) + requires _Const + && (convertible_to, + iterator_t<__detail::__maybe_const_t<_Const, _Vs>>> && ...) + : _M_current(std::move(__i._M_current)) + { } + + constexpr auto + operator*() const + { + auto __f = [](auto& __i) -> decltype(auto) { + return *__i; + }; + return __detail::__tuple_transform(__f, _M_current); + } + + constexpr iterator& + operator++() + { + __detail::__tuple_for_each([](auto& __i) { ++__i; }, _M_current); + return *this; + } + + constexpr void + operator++(int) + { ++*this; } + + constexpr iterator + operator++(int) + requires __detail::__all_forward<_Const, _Vs...> + { + auto __tmp = *this; + ++*this; + return __tmp; + } + + constexpr iterator& + operator--() + requires __detail::__all_bidirectional<_Const, _Vs...> + { + __detail::__tuple_for_each([](auto& __i) { --__i; }, _M_current); + return *this; + } + + constexpr iterator + operator--(int) + requires __detail::__all_bidirectional<_Const, _Vs...> + { + auto __tmp = *this; + --*this; + return __tmp; + } + + constexpr iterator& + operator+=(difference_type __x) + requires __detail::__all_random_access<_Const, _Vs...> + { + auto __f = [&](_It& __i) { + __i += iter_difference_t<_It>(__x); + }; + __detail::__tuple_for_each(__f, _M_current); + return *this; + } + + constexpr iterator& + operator-=(difference_type __x) + requires __detail::__all_random_access<_Const, _Vs...> + { + auto __f = [&](_It& __i) { + __i -= iter_difference_t<_It>(__x); + }; + __detail::__tuple_for_each(__f, _M_current); + return *this; + } + + constexpr auto + operator[](difference_type __n) const + requires __detail::__all_random_access<_Const, _Vs...> + { + auto __f = [&](_It& __i) -> decltype(auto) { + return __i[iter_difference_t<_It>(__n)]; + }; + return __detail::__tuple_transform(__f, _M_current); + } + + friend constexpr bool + operator==(const iterator& __x, const iterator& __y) + requires (equality_comparable>> && ...) + { + if constexpr (__detail::__all_bidirectional<_Const, _Vs...>) + return __x._M_current == __y._M_current; + else + return [&](index_sequence<_Is...>) { + return ((std::get<_Is>(__x._M_current) == std::get<_Is>(__y._M_current)) || ...); + }(make_index_sequence{}); + } + + friend constexpr bool + operator<(const iterator& __x, const iterator& __y) + requires __detail::__all_random_access<_Const, _Vs...> + { return __x._M_current < __y._M_current; } + + friend constexpr bool + operator>(const iterator& __x, const iterator& __y) + requires __detail::__all_random_access<_Const, _Vs...> + { return __y < __x; } + + friend constexpr bool + operator<=(const iterator& __x, const iterator& __y) + requires __detail::__all_random_access<_Const, _Vs...> + { return !(__y < __x); } + + friend constexpr bool + operator>=(const iterator& __x, const iterator& __y) + requires __detail::__all_random_access<_Const, _Vs...> + { return !(__x < __y); } + + friend constexpr auto + operator<=>(const iterator& __x, const iterator& __y) + requires __detail::__all_random_access<_Const, _Vs...> + && (three_way_comparable>> && ...) + { return __x._M_current <=> __y._M_current; } + + friend constexpr iterator + operator+(const iterator& __i, difference_type __n) + requires __detail::__all_random_access<_Const, _Vs...> + { + auto __r = __i; + __r += __n; + return __r; + } + + friend constexpr iterator + operator+(difference_type __n, const iterator& __i) + requires __detail::__all_random_access<_Const, _Vs...> + { + auto __r = __i; + __r += __n; + return __r; + } + + friend constexpr iterator + operator-(const iterator& __i, difference_type __n) + requires __detail::__all_random_access<_Const, _Vs...> + { + auto __r = __i; + __r -= __n; + return __r; + } + + friend constexpr difference_type + operator-(const iterator& __x, const iterator& __y) + requires (sized_sentinel_for>, + iterator_t<__detail::__maybe_const_t<_Const, _Vs>>> && ...) + { + return [&](index_sequence<_Is...>) { + return ranges::min({difference_type(std::get<_Is>(__x._M_current) + - std::get<_Is>(__y._M_current))...}, + ranges::less{}, + [](difference_type __i) -> make_unsigned_t { + // TODO: use constexpr std::abs from P0533R9 once implemented + return __i < 0 ? -__i : __i; + }); + }(make_index_sequence{}); + } + + friend constexpr auto + iter_move(const iterator& __i) + { return __detail::__tuple_transform(ranges::iter_move, __i._M_current); } + + friend constexpr void + iter_swap(const iterator& __l, const iterator& __r) + requires (indirectly_swappable>> && ...) + { + [&](index_sequence<_Is...>) { + (ranges::iter_swap(std::get<_Is>(__l._M_current), std::get<_Is>(__r._M_current)), ...); + }(make_index_sequence{}); + } + + friend class zip_view; + }; + + template + requires (view<_Vs> && ...) && (sizeof...(_Vs) > 0) + template + class zip_view<_Vs...>::sentinel + { + __detail::__tuple_or_pair_t>...> _M_end; + + constexpr explicit + sentinel(decltype(_M_end) __end) + : _M_end(__end) + { } + + friend class zip_view; + + public: + sentinel() = default; + + constexpr + sentinel(sentinel __i) + requires _Const + && (convertible_to, + sentinel_t<__detail::__maybe_const_t<_Const, _Vs>>> && ...) + : _M_end(std::move(__i._M_end)) + { } + + template + requires (sentinel_for>, + iterator_t<__detail::__maybe_const_t<_OtherConst, _Vs>>> && ...) + friend constexpr bool + operator==(const iterator<_OtherConst>& __x, const sentinel& __y) + { + return [&](index_sequence<_Is...>) { + return ((std::get<_Is>(__x._M_current) == std::get<_Is>(__y._M_end)) || ...); + }(make_index_sequence{}); + } + + template + requires (sized_sentinel_for>, + iterator_t<__detail::__maybe_const_t<_OtherConst, _Vs>>> && ...) + friend constexpr auto + operator-(const iterator<_OtherConst>& __x, const sentinel& __y) + { + using _Ret + = common_type_t>...>; + return [&](index_sequence<_Is...>) { + return ranges::min({_Ret(std::get<_Is>(__x._M_current) - std::get<_Is>(__y._M_end))...}, + ranges::less{}, + [](_Ret __i) -> make_unsigned_t<_Ret> { + // TODO: use constexpr std::abs from P0533R9 once implemented + return __i < 0 ? -__i : __i; + }); + }(make_index_sequence{}); + } + + template + requires (sized_sentinel_for>, + iterator_t<__detail::__maybe_const_t<_OtherConst, _Vs>>> && ...) + friend constexpr auto + operator-(const sentinel& __y, const iterator<_OtherConst>& __x) + { return -(__x - __y); } + }; + + namespace views + { + namespace __detail + { + template + concept __can_zip_view + = requires { zip_view...>(std::declval<_Ts>()...); }; + } + + struct _Zip + { + template + requires (sizeof...(_Ts) == 0 || __detail::__can_zip_view<_Ts...>) + [[nodiscard]] + constexpr auto + operator()(_Ts&&... __ts) const + { + if constexpr (sizeof...(_Ts) == 0) + return views::empty>; + else + return zip_view...>(std::forward<_Ts>(__ts)...); + } + }; + + inline constexpr _Zip zip; + } +#endif // C++23 } // namespace ranges namespace views = ranges::views; diff --git a/libstdc++-v3/testsuite/std/ranges/zip/1.cc b/libstdc++-v3/testsuite/std/ranges/zip/1.cc new file mode 100644 index 00000000000..4d5835829dd --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/zip/1.cc @@ -0,0 +1,101 @@ +// { dg-options "-std=gnu++23" } +// { dg-do run { target c++23 } } + +#include +#include +#include +#include +#include +#include + +namespace ranges = std::ranges; +namespace views = std::views; + +constexpr bool +test01() +{ + static_assert(ranges::empty(views::zip())); + static_assert(ranges::empty(views::empty)); + + auto z1 = views::zip(std::array{1, 2}); + const auto i0 = z1.begin(), i1 = z1.begin() + 1; + VERIFY( i0 + 1 - 1 == i0 ); + VERIFY( i0 < i1 ); + VERIFY( i1 < z1.end() ); + VERIFY( i1 - i0 == 1 ); + VERIFY( i0 - i1 == -1 ); + VERIFY( z1.end() - i1 == 1 ); + VERIFY( i1 - z1.end() == -1 ); + ranges::iter_swap(i0, i1); + VERIFY( ranges::equal(std::move(z1) | views::keys, (int[]){2, 1}) ); + + auto z2 = views::zip(std::array{1, 2}, std::array{3, 4, 5}); + VERIFY( ranges::size(z2) == 2 ); + VERIFY( ranges::size(std::as_const(z2)) == 2 ); + VERIFY( z2[0].first == 1 && z2[0].second == 3 ); + VERIFY( z2[1].first == 2 && z2[1].second == 4 ); + for (const auto [x, y] : z2) + { + VERIFY( y - x == 2 ); + std::swap(x, y); + } + + int x[2] = {1, 2}, y[2] = {3, 4}, z[2] = {5, 6}; + const auto z3 = views::zip(x, y, z); + VERIFY( ranges::size(z3) == 2 ); + for (int i = 0; i < ranges::size(x); i++) + { + VERIFY( &std::get<0>(z3[i]) == &x[i] ); + VERIFY( &std::get<1>(z3[i]) == &y[i] ); + VERIFY( &std::get<2>(z3[i]) == &z[i] ); + } + + return true; +} + +constexpr bool +test02() +{ + using __gnu_test::test_input_range; + using __gnu_test::test_forward_range; + using __gnu_test::test_random_access_range; + + using ty1 = ranges::zip_view>, + views::all_t>>; + static_assert(ranges::forward_range); + static_assert(!ranges::random_access_range); + static_assert(!ranges::sized_range); + + using ty2 = ranges::zip_view>, + views::all_t>, + views::all_t>>; + static_assert(ranges::input_range); + static_assert(!ranges::forward_range); + static_assert(!ranges::sized_range); + + return true; +} + +constexpr bool +test03() +{ + int u[] = {1, 2, 3, 4}, v[] = {4, 5, 6}, w[] = {7, 8, 9, 10}; + auto z = views::zip(u | views::filter([](auto) { return true; }), v, w); + using ty = decltype(z); + static_assert(ranges::forward_range); + static_assert(!ranges::common_range); + static_assert(!ranges::sized_range); + VERIFY( z.begin() == z.begin() ); + VERIFY( z.begin() != z.end() ); + VERIFY( ranges::next(z.begin(), 3) == z.end() ); + + return true; +} + +int +main() +{ + static_assert(test01()); + static_assert(test02()); + static_assert(test03()); +}