From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) by sourceware.org (Postfix) with ESMTP id 5CC1A396E855 for ; Thu, 20 May 2021 16:07:47 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 5CC1A396E855 Received: from mail-qt1-f200.google.com (mail-qt1-f200.google.com [209.85.160.200]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-439-8QENMViVNgmW0zWPrgI_1Q-1; Thu, 20 May 2021 12:07:44 -0400 X-MC-Unique: 8QENMViVNgmW0zWPrgI_1Q-1 Received: by mail-qt1-f200.google.com with SMTP id h2-20020a05622a1702b02901b9123889b0so12616701qtk.10 for ; Thu, 20 May 2021 09:07:44 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:mime-version :content-transfer-encoding; bh=asSvW99y3bTZ7vTm4EiRW6PnRKxYC3xL6sBKY/JOyJA=; b=o1Vfjsbc0adEtBWY4BCKhXbT+mGn+s3HTAfD6k8R8z50/m4vN+BCz3HulPpPqyHQtJ qhZ0nhLMBmwOO3xcAA3DByKT8v0oLVDO8TqyFgCpLjqDFP8tEQrHGVjqWOuqRZVx6r4z kidCIib27vl/FdOuB5IZ0DlGO1fzAQqGwTyqAdkVaI88+vJu03wN6KzzXag4zT+f3GSf /ujpB3F2x7OCyBQFv0b+uJd2LotKkLC+0BkzAeFZFtYG9T8U0ZfjgnAhiK2NB6vcsKP6 s5nKn92gZSLgQiTm18pnzivW6t/EJ59vr3rNV0CorsX14WxHfZdyffuuzxneQffDOGMq wspg== X-Gm-Message-State: AOAM531Z6kbh3d5aaNSZehb3IoYxsl+r859OBQIj89JnMsvb7N25cVBo zi8GynrBoJnxsvF6QsCnCFDVEMgsZuHXHmFTrPfuBr9MylqA2W+GiinraunHbJ4zxMd43/m0CrZ RIdrGoM5fxp6ov2Y= X-Received: by 2002:a05:6214:dc8:: with SMTP id 8mr2480411qvt.58.1621526864098; Thu, 20 May 2021 09:07:44 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwPhwR2iO3OsvijEJveLP21P6CKKt2pzUpPuc0dO6IzG3Vvtp5hPP8cf6apLV/LFtZ9zoT2Rw== X-Received: by 2002:a05:6214:dc8:: with SMTP id 8mr2480367qvt.58.1621526863749; Thu, 20 May 2021 09:07:43 -0700 (PDT) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id w5sm2303497qkf.14.2021.05.20.09.07.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 20 May 2021 09:07:43 -0700 (PDT) From: Patrick Palka To: gcc-patches@gcc.gnu.org Cc: libstdc++@gcc.gnu.org, barry.revzin@gmail.com, Patrick Palka Subject: [PATCH] libstdc++: Support range adaptors with defaultable arguments Date: Thu, 20 May 2021 12:07:41 -0400 Message-Id: <20210520160741.1189134-1-ppalka@redhat.com> X-Mailer: git-send-email 2.32.0.rc0 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII" X-Spam-Status: No, score=-15.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=unavailable autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: libstdc++@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Libstdc++ mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 20 May 2021 16:07:49 -0000 This adds support for defining range adaptors with defaultable arguments. No such range adaptors have yet been standardized, but range-v3 has a couple, e.g. 'unique' and 'sample' (which are approximately implemented in the added testcase), and it would be good to preemptively support such adaptors. In order to make 'unique | unique' (where 'unique' is an adaptor that takes a single defaultable extra argument) unambiguously mean composition instead of the partial application 'unique(unique)', we need to additionally constrain the first operand in the first overload of _RangeAdaptorClosure::operator| as per [range.adaptor.object]/1, which says R | C is equivalent to C(R) only if R models viewable_range. However, for our purposes checking range instead of viewable_range suffices and is cheaper to check. Tested on x86_64-pc-linux-gnu, does this look OK for trunk/11? Existing adaptors aren't affected by this change. libstdc++-v3/ChangeLog: * include/std/ranges (__adaptor_partial_app_arity_ok): Define. (__adaptor_partial_app_viable): Use it. (_RangeAdaptorClosure::operator|): In the first overload, swap order of template parameters _Self and _Range. Add a range<_Range> constraint to this overload. (_RangeAdaptor): Document that _S_arity can also be defined as a pair consisting of the minimum and maximum arity. * testsuite/std/ranges/adaptors/detail/user_defined.cc: New test. --- libstdc++-v3/include/std/ranges | 27 +++++-- .../ranges/adaptors/detail/user_defined.cc | 81 +++++++++++++++++++ 2 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/detail/user_defined.cc diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index 48100e9d7f2..8f691ee41f6 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -742,12 +742,25 @@ namespace views::__adaptor concept __adaptor_invocable = requires { std::declval<_Adaptor>()(declval<_Args>()...); }; + template + constexpr bool + __adaptor_partial_app_arity_ok(int __nargs) + { + if constexpr (integral) + return 1 + __nargs == _Adaptor::_S_arity; + else + { + auto [__min, __max] = _Adaptor::_S_arity; + return 1 + __nargs >= __min && 1 + __nargs <= __max; + } + } + // True if the range adaptor non-closure _Adaptor can be partially applied // with _Args. template - concept __adaptor_partial_app_viable = (_Adaptor::_S_arity > 1) - && (sizeof...(_Args) == _Adaptor::_S_arity - 1) - && (constructible_from, _Args> && ...); + concept __adaptor_partial_app_viable + = __adaptor_partial_app_arity_ok<_Adaptor>(sizeof...(_Args)) + && (constructible_from, _Args> && ...); template struct _Partial; @@ -759,7 +772,7 @@ namespace views::__adaptor struct _RangeAdaptorClosure { // range | adaptor is equivalent to adaptor(range). - template + template requires derived_from, _RangeAdaptorClosure> && __adaptor_invocable<_Self, _Range> friend constexpr auto @@ -778,8 +791,10 @@ namespace views::__adaptor // The base class of every range adaptor non-closure. // - // The static data member _Derived::_S_arity must contain the total number of - // arguments that the adaptor takes, and the class _Derived must introduce + // The static data member _Derived::_S_arity must either be an integer + // denoting the total arity of the adaptor, or a tuple consisting of the + // minimum and maximum arity of the adaptor (if e.g. the adaptor has + // defaultable arguments). The class _Derived must also introduce // _RangeAdaptor::operator() into the class scope via a using-declaration. template struct _RangeAdaptor diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/detail/user_defined.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/detail/user_defined.cc new file mode 100644 index 00000000000..94dabb50db8 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/detail/user_defined.cc @@ -0,0 +1,81 @@ +// Copyright (C) 2021 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +#include + +using std::views::__adaptor::_RangeAdaptor; +using std::views::__adaptor::_RangeAdaptorClosure; + +// An example of a range adaptor that accepts one defaultable extra argument. +struct _Unique : _RangeAdaptor<_Unique>, _RangeAdaptorClosure +{ + template + std::ranges::empty_view + operator()(_Range&&, _Pred = {}) const; + + using _RangeAdaptor<_Unique>::operator(); + static constexpr std::pair _S_arity = {1,2}; +}; + +inline constexpr _Unique unique; + +void +test01() +{ + extern int r[42]; + auto p = std::ranges::equal_to{}; + r | unique; + r | (unique | unique); + r | (unique(p) | unique(p)); + r | (unique(p) | unique); + r | (unique | unique(p)); + unique(r, p); + unique(p)(r); +} + +struct default_rng { }; + +// An example of a range adaptor that accepts two extra arguments, one of which +// is defaultable. +struct _Sample : _RangeAdaptor<_Sample> +{ + template + std::ranges::empty_view + operator()(_Range&&, int, _Rng = {}) const; + + using _RangeAdaptor<_Sample>::operator(); + static constexpr std::pair _S_arity = {2,3}; +}; + +inline constexpr _Sample sample; + +void +test02() +{ + extern int r[42]; + sample(r, 5); + sample(r, 5, default_rng{}); + sample(5)(r); + sample(5, default_rng{})(r); + r | sample(5); + r | sample(5, default_rng{}); + r | (sample(5) | sample(5)); + r | (sample(5, default_rng{}) | sample(5, default_rng{})); +} -- 2.32.0.rc0