From patchwork Tue Feb 4 02:07:22 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1233097 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-518822-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha1 header.s=default header.b=FT41Aiyq; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=MDQn5qxD; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 48BSl26yMKz9sX0 for ; Tue, 4 Feb 2020 13:07:41 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:mime-version:content-type :content-transfer-encoding; q=dns; s=default; b=r5dZrSZusyck5OzJ FUpMYWJ15okRAWnfZ/NZiyUgtlXJMCuBOTksWfP2o47zknkcrafbldHe1c9nghRe SvyEYIYFEBoDl3ygWtgPJ7/+NKQgjGfXSyYBV64aB4fnd9FlGQkFPPtedm6oT9Mj Qnj8ABScf88TgAWV7mfiFj4uIXE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:mime-version:content-type :content-transfer-encoding; s=default; bh=9uD15hiK2ncOmuT0Dh8xD1 IRSwA=; b=FT41AiyqYIRaqFGEJwxOiG7xxbyCa4CjGSqk8GGwQ8XPQeOWXTd3FK Vuoh7dcfLWomeU1YWQ+timTJAwnWB9yeFGs+rf4xsIBMudK8Sze23gdu1bKUqv1c pSzq2n5AHPe9xdB5OxGPCERvgaFmgbF/KAnLQXSvVxSXg0mNgaKoQ= Received: (qmail 114527 invoked by alias); 4 Feb 2020 02:07:33 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 114513 invoked by uid 89); 4 Feb 2020 02:07:32 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-22.2 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_NUMSUBJECT, RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 spammy= X-HELO: us-smtp-1.mimecast.com Received: from us-smtp-delivery-1.mimecast.com (HELO us-smtp-1.mimecast.com) (205.139.110.120) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 04 Feb 2020 02:07:31 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1580782049; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=6N38/aZy7jtBpW2RPlCpEmwwuz3KPZzynKY7kWfAN/M=; b=MDQn5qxDsvmYR6UlDYcr+EUIPS0efNWZwGLD5ZR+C6hkfDdt1GDizaeQ980Iv2aRFh2NgV VdExJOlNZm48iYTqJG/eWpkB5vB1QDHWrgFKDLbrflhr9Bq8I8hAfMT5tVsuA7jiEI8ZcE Bn7PuqWWXLve3zHimye6Gmf8edA8z2o= 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-84-o9wJ9ZU5NjadSXBvX28y5Q-1; Mon, 03 Feb 2020 21:07:27 -0500 Received: by mail-qt1-f200.google.com with SMTP id r9so11400731qtc.4 for ; Mon, 03 Feb 2020 18:07:27 -0800 (PST) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id a36sm11185884qtk.29.2020.02.03.18.07.26 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 03 Feb 2020 18:07:26 -0800 (PST) From: Patrick Palka To: gcc-patches@gcc.gnu.org Cc: libstdc++@gcc.gnu.org, jwakely@redhat.com, Patrick Palka Subject: [PATCH 1/3] libstdc++: Apply the move_iterator changes described in P1207R4 Date: Mon, 3 Feb 2020 21:07:22 -0500 Message-Id: <20200204020724.217468-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-IsSubscribed: yes These changes are needed for some of the tests in the constrained algorithm patch, because they use move_iterator with an uncopyable output_iterator. The other changes described in the paper are already applied, it seems. libstdc++-v3/ChangeLog: * include/bits/stl_iterator.h (move_iterator::move_iterator): Move the iterator when initializing _M_current. (move_iterator::base): Split into two overloads differing in ref-qualifiers as in P1207R4. --- libstdc++-v3/include/bits/stl_iterator.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 784d200d22f..1a288a5c785 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -1166,7 +1166,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit _GLIBCXX17_CONSTEXPR move_iterator(iterator_type __i) - : _M_current(__i) { } + : _M_current(std::move(__i)) { } template _GLIBCXX17_CONSTEXPR @@ -1174,9 +1174,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : _M_current(__i.base()) { } _GLIBCXX17_CONSTEXPR iterator_type - base() const + base() const & +#if __cplusplus > 201703L && __cpp_lib_concepts + requires copy_constructible +#endif { return _M_current; } + _GLIBCXX17_CONSTEXPR iterator_type + base() && + { return std::move(_M_current); } + _GLIBCXX17_CONSTEXPR reference operator*() const { return static_cast(*_M_current); } From patchwork Tue Feb 4 02:07:23 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1233099 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-518824-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha1 header.s=default header.b=SSzx8UcM; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=DyOzrwxK; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 48BSpB52K0z9sWy for ; Tue, 4 Feb 2020 13:10:26 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; q=dns; s= default; b=X7eZYOHrNDqhAboNczydZmw1DBcCoxJzUqUELPRZf0GRzAQuSFd8t Tol1GFOPqfy2RNHxjCJO6P7VLY5GJixQzVJjBpFLn/JV5hd4SBsiaPw7DwaZAPFq nndg4NNTrc07Obg8whSlxAcdPIYW+b/8/qR/06WaFAruBxZN5uGTLI= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s=default; bh=WSbZc66K6o9RSwBq7GjFUnqC3cQ=; b=SSzx8UcMFT6uIe05Xy/6q7Lvpiea 4lLnVy1gkp8uMWzktAYUVTaZUSZcYsIhDqfiLrEgHbAUv6jaEHbhiqP1nHGRtypL oP0Oz1D684KsTlKvqrr45bLZFTf7npqnB8dU3g7fI88DhZL35CLH8amAsJmDWa6A GhlgHUD/rTppz8g= Received: (qmail 122302 invoked by alias); 4 Feb 2020 02:09:04 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 121590 invoked by uid 89); 4 Feb 2020 02:08:57 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.1 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SCC_5_SHORT_WORD_LINES autolearn=unavailable version=3.3.1 spammy=outstanding, 1164, 1124, UD:r.begin X-HELO: us-smtp-1.mimecast.com Received: from us-smtp-delivery-1.mimecast.com (HELO us-smtp-1.mimecast.com) (205.139.110.120) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 04 Feb 2020 02:07:42 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1580782060; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=urvEMFexd6PDLPXpPg6mi8QC3SlhF5Ye2xZgX+zEf9Q=; b=DyOzrwxKA2IihImNW9ZE0sadrCumjpc7KJVyCE/PA2kRVulG5fDHfeLh4MjsRBOunxIXc5 ui1Nb0t9BpeppUGg0j/xrZwNlEZEj9/k2Gyv2+LgOEQPnwNcyKBobUdtTnC+Tu6FUQi+bs 0Xl5aWTWjWcIDNlIqvl6mqEQZid8beI= Received: from mail-qv1-f70.google.com (mail-qv1-f70.google.com [209.85.219.70]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-112-rhxVg3-SPGS_fsTqA7ngLw-1; Mon, 03 Feb 2020 21:07:33 -0500 Received: by mail-qv1-f70.google.com with SMTP id v3so10804539qvm.2 for ; Mon, 03 Feb 2020 18:07:33 -0800 (PST) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id a36sm11185884qtk.29.2020.02.03.18.07.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 03 Feb 2020 18:07:28 -0800 (PST) From: Patrick Palka To: gcc-patches@gcc.gnu.org Cc: libstdc++@gcc.gnu.org, jwakely@redhat.com, Patrick Palka Subject: [PATCH 2/3] libstdc++: Implement C++20 constrained algorithms Date: Mon, 3 Feb 2020 21:07:23 -0500 Message-Id: <20200204020724.217468-2-ppalka@redhat.com> In-Reply-To: <20200204020724.217468-1-ppalka@redhat.com> References: <20200204020724.217468-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-IsSubscribed: yes This patch implements the C++20 ranges overloads for the algorithms in [algorithms]. Most of the algorithms were reimplemented, with each of their implementations very closely following the existing implementation in bits/stl_algo.h and bits/stl_algobase.h. The reason for reimplementing most of the algorithms instead of forwarding to their STL-style overload is because forwarding cannot be conformantly and efficiently performed for algorithms that operate on non-random-access iterators. But algorithms that operate on random access iterators can safely and efficiently be forwarded to the STL-style implementation, and this patch does so for push_heap, pop_heap, make_heap, sort_heap, sort, stable_sort, nth_element, inplace_merge and stable_partition. What's missing from this patch is debug-iterator and container specializations that are present for some of the STL-style algorithms that need to be ported over to the ranges algos. I marked them missing at TODO comments. There are also some other minor outstanding TODOs. The code that could use the most thorough review is ranges::__copy_or_move, ranges::__copy_or_move_backward, ranges::__equal and ranges::__lexicographical_compare. In the tests, I tried to test the interface of each new overload, as well as the correctness of the new implementation. libstdc++-v3/ChangeLog: Implement C++20 constrained algorithms * include/Makefile.am: Add new header. * include/Makefile.in: Regenerate. * include/std/algorithm: Include . * include/bits/ranges_algo.h: New file. * testsuite/25_algorithms/adjacent_find/constrained.cc: New file. * testsuite/25_algorithms/all_of/constrained.cc: New file. * testsuite/25_algorithms/any_of/constrained.cc: New file. * testsuite/25_algorithms/binary_search/constrained.cc: New file. * testsuite/25_algorithms/copy/constrained.cc: New file. * testsuite/25_algorithms/copy_backward/constrained.cc: New file. * testsuite/25_algorithms/copy_if/constrained.cc: New file. * testsuite/25_algorithms/copy_n/constrained.cc: New file. * testsuite/25_algorithms/count/constrained.cc: New file. * testsuite/25_algorithms/count_if/constrained.cc: New file. * testsuite/25_algorithms/equal/constrained.cc: New file. * testsuite/25_algorithms/equal_range/constrained.cc: New file. * testsuite/25_algorithms/fill/constrained.cc: New file. * testsuite/25_algorithms/fill_n/constrained.cc: New file. * testsuite/25_algorithms/find/constrained.cc: New file. * testsuite/25_algorithms/find_end/constrained.cc: New file. * testsuite/25_algorithms/find_first_of/constrained.cc: New file. * testsuite/25_algorithms/find_if/constrained.cc: New file. * testsuite/25_algorithms/find_if_not/constrained.cc: New file. * testsuite/25_algorithms/for_each/constrained.cc: New file. * testsuite/25_algorithms/generate/constrained.cc: New file. * testsuite/25_algorithms/generate_n/constrained.cc: New file. * testsuite/25_algorithms/heap/constrained.cc: New file. * testsuite/25_algorithms/includes/constrained.cc: New file. * testsuite/25_algorithms/inplace_merge/constrained.cc: New file. * testsuite/25_algorithms/is_partitioned/constrained.cc: New file. * testsuite/25_algorithms/is_permutation/constrained.cc: New file. * testsuite/25_algorithms/is_sorted/constrained.cc: New file. * testsuite/25_algorithms/is_sorted_until/constrained.cc: New file. * testsuite/25_algorithms/lexicographical_compare/constrained.cc: New file. * testsuite/25_algorithms/lower_bound/constrained.cc: New file. * testsuite/25_algorithms/max/constrained.cc: New file. * testsuite/25_algorithms/max_element/constrained.cc: New file. * testsuite/25_algorithms/merge/constrained.cc: New file. * testsuite/25_algorithms/min/constrained.cc: New file. * testsuite/25_algorithms/min_element/constrained.cc: New file. * testsuite/25_algorithms/minmax/constrained.cc: New file. * testsuite/25_algorithms/minmax_element/constrained.cc: New file. * testsuite/25_algorithms/mismatch/constrained.cc: New file. * testsuite/25_algorithms/move/constrained.cc: New file. * testsuite/25_algorithms/move_backward/constrained.cc: New file. * testsuite/25_algorithms/next_permutation/constrained.cc: New file. * testsuite/25_algorithms/none_of/constrained.cc: New file. * testsuite/25_algorithms/nth_element/constrained.cc: New file. * testsuite/25_algorithms/partial_sort/constrained.cc: New file. * testsuite/25_algorithms/partial_sort_copy/constrained.cc: New file. * testsuite/25_algorithms/partition/constrained.cc: New file. * testsuite/25_algorithms/partition_copy/constrained.cc: New file. * testsuite/25_algorithms/partition_point/constrained.cc: New file. * testsuite/25_algorithms/prev_permutation/constrained.cc: New file. * testsuite/25_algorithms/remove/constrained.cc: New file. * testsuite/25_algorithms/remove_copy/constrained.cc: New file. * testsuite/25_algorithms/remove_copy_if/constrained.cc: New file. * testsuite/25_algorithms/remove_if/constrained.cc: New file. * testsuite/25_algorithms/replace/constrained.cc: New file. * testsuite/25_algorithms/replace_copy/constrained.cc: New file. * testsuite/25_algorithms/replace_copy_if/constrained.cc: New file. * testsuite/25_algorithms/replace_if/constrained.cc: New file. * testsuite/25_algorithms/reverse/constrained.cc: New file. * testsuite/25_algorithms/reverse_copy/constrained.cc: New file. * testsuite/25_algorithms/rotate/constrained.cc: New file. * testsuite/25_algorithms/rotate_copy/constrained.cc: New file. * testsuite/25_algorithms/search/constrained.cc: New file. * testsuite/25_algorithms/search_n/constrained.cc: New file. * testsuite/25_algorithms/set_difference/constrained.cc: New file. * testsuite/25_algorithms/set_intersection/constrained.cc: New file. * testsuite/25_algorithms/set_symmetric_difference/constrained.cc: New file. * testsuite/25_algorithms/set_union/constrained.cc: New file. * testsuite/25_algorithms/shuffle/constrained.cc: New file. * testsuite/25_algorithms/sort/constrained.cc: New file. * testsuite/25_algorithms/stable_partition/constrained.cc: New file. * testsuite/25_algorithms/stable_sort/constrained.cc: New file. * testsuite/25_algorithms/swap_ranges/constrained.cc: New file. * testsuite/25_algorithms/transform/constrained.cc: New file. * testsuite/25_algorithms/unique/constrained.cc: New file. * testsuite/25_algorithms/unique_copy/constrained.cc: New file. * testsuite/25_algorithms/upper_bound/constrained.cc: New file. --- libstdc++-v3/include/Makefile.am | 1 + libstdc++-v3/include/Makefile.in | 1 + libstdc++-v3/include/bits/ranges_algo.h | 3640 +++++++++++++++++ libstdc++-v3/include/std/algorithm | 3 + .../adjacent_find/constrained.cc | 68 + .../25_algorithms/all_of/constrained.cc | 90 + .../25_algorithms/any_of/constrained.cc | 88 + .../binary_search/constrained.cc | 61 + .../25_algorithms/copy/constrained.cc | 225 + .../copy_backward/constrained.cc | 193 + .../25_algorithms/copy_if/constrained.cc | 77 + .../25_algorithms/copy_n/constrained.cc | 72 + .../25_algorithms/count/constrained.cc | 75 + .../25_algorithms/count_if/constrained.cc | 73 + .../25_algorithms/equal/constrained.cc | 96 + .../25_algorithms/equal_range/constrained.cc | 69 + .../25_algorithms/fill/constrained.cc | 92 + .../25_algorithms/fill_n/constrained.cc | 98 + .../25_algorithms/find/constrained.cc | 75 + .../25_algorithms/find_end/constrained.cc | 98 + .../find_first_of/constrained.cc | 83 + .../25_algorithms/find_if/constrained.cc | 77 + .../25_algorithms/find_if_not/constrained.cc | 77 + .../25_algorithms/for_each/constrained.cc | 83 + .../25_algorithms/generate/constrained.cc | 77 + .../25_algorithms/generate_n/constrained.cc | 84 + .../25_algorithms/heap/constrained.cc | 107 + .../25_algorithms/includes/constrained.cc | 74 + .../inplace_merge/constrained.cc | 69 + .../is_partitioned/constrained.cc | 58 + .../is_permutation/constrained.cc | 85 + .../25_algorithms/is_sorted/constrained.cc | 67 + .../is_sorted_until/constrained.cc | 72 + .../lexicographical_compare/constrained.cc | 164 + .../25_algorithms/lower_bound/constrained.cc | 66 + .../25_algorithms/max/constrained.cc | 82 + .../25_algorithms/max_element/constrained.cc | 60 + .../25_algorithms/merge/constrained.cc | 75 + .../25_algorithms/min/constrained.cc | 82 + .../25_algorithms/min_element/constrained.cc | 60 + .../25_algorithms/minmax/constrained.cc | 98 + .../minmax_element/constrained.cc | 68 + .../25_algorithms/mismatch/constrained.cc | 76 + .../25_algorithms/move/constrained.cc | 203 + .../move_backward/constrained.cc | 170 + .../next_permutation/constrained.cc | 83 + .../25_algorithms/none_of/constrained.cc | 88 + .../25_algorithms/nth_element/constrained.cc | 76 + .../25_algorithms/partial_sort/constrained.cc | 84 + .../partial_sort_copy/constrained.cc | 97 + .../25_algorithms/partition/constrained.cc | 71 + .../partition_copy/constrained.cc | 81 + .../partition_point/constrained.cc | 67 + .../prev_permutation/constrained.cc | 84 + .../25_algorithms/remove/constrained.cc | 97 + .../25_algorithms/remove_copy/constrained.cc | 109 + .../remove_copy_if/constrained.cc | 113 + .../25_algorithms/remove_if/constrained.cc | 97 + .../25_algorithms/replace/constrained.cc | 104 + .../25_algorithms/replace_copy/constrained.cc | 109 + .../replace_copy_if/constrained.cc | 118 + .../25_algorithms/replace_if/constrained.cc | 109 + .../25_algorithms/reverse/constrained.cc | 77 + .../25_algorithms/reverse_copy/constrained.cc | 74 + .../25_algorithms/rotate/constrained.cc | 97 + .../25_algorithms/rotate_copy/constrained.cc | 93 + .../25_algorithms/search/constrained.cc | 88 + .../25_algorithms/search_n/constrained.cc | 80 + .../set_difference/constrained.cc | 87 + .../set_intersection/constrained.cc | 88 + .../set_symmetric_difference/constrained.cc | 123 + .../25_algorithms/set_union/constrained.cc | 91 + .../25_algorithms/shuffle/constrained.cc | 70 + .../25_algorithms/sort/constrained.cc | 81 + .../stable_partition/constrained.cc | 76 + .../25_algorithms/stable_sort/constrained.cc | 70 + .../25_algorithms/swap_ranges/constrained.cc | 124 + .../25_algorithms/transform/constrained.cc | 148 + .../25_algorithms/unique/constrained.cc | 143 + .../25_algorithms/unique_copy/constrained.cc | 113 + .../25_algorithms/upper_bound/constrained.cc | 66 + 81 files changed, 10788 insertions(+) create mode 100644 libstdc++-v3/include/bits/ranges_algo.h create mode 100644 libstdc++-v3/testsuite/25_algorithms/adjacent_find/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/all_of/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/any_of/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/binary_search/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/copy/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/copy_backward/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/copy_if/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/copy_n/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/count/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/count_if/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/equal_range/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/fill_n/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/find/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/find_end/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/find_first_of/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/find_if/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/find_if_not/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/for_each/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/generate/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/generate_n/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/includes/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/is_partitioned/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/is_permutation/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/is_sorted/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/is_sorted_until/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/lower_bound/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/max/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/max_element/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/merge/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/min/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/min_element/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/mismatch/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/move/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/next_permutation/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/none_of/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/partition/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/partition_copy/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/partition_point/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/prev_permutation/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/remove/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/remove_copy/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/remove_copy_if/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/remove_if/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/replace/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/replace_copy/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/replace_copy_if/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/replace_if/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/reverse/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/reverse_copy/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/rotate/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/rotate_copy/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/search/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/search_n/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/set_difference/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/set_intersection/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/set_symmetric_difference/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/set_union/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/swap_ranges/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/transform/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/unique/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/unique_copy/constrained.cc create mode 100644 libstdc++-v3/testsuite/25_algorithms/upper_bound/constrained.cc diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am index 89835759069..1d342cecbcc 100644 --- a/libstdc++-v3/include/Makefile.am +++ b/libstdc++-v3/include/Makefile.am @@ -157,6 +157,7 @@ bits_headers = \ ${bits_srcdir}/random.tcc \ ${bits_srcdir}/range_access.h \ ${bits_srcdir}/range_cmp.h \ + ${bits_srcdir}/ranges_algo.h \ ${bits_srcdir}/refwrap.h \ ${bits_srcdir}/regex.h \ ${bits_srcdir}/regex.tcc \ diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in index 123d24bb1c6..c735d67a5d3 100644 --- a/libstdc++-v3/include/Makefile.in +++ b/libstdc++-v3/include/Makefile.in @@ -502,6 +502,7 @@ bits_headers = \ ${bits_srcdir}/random.tcc \ ${bits_srcdir}/range_access.h \ ${bits_srcdir}/range_cmp.h \ + ${bits_srcdir}/ranges_algo.h \ ${bits_srcdir}/refwrap.h \ ${bits_srcdir}/regex.h \ ${bits_srcdir}/regex.tcc \ diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h new file mode 100644 index 00000000000..2e177ce7f7a --- /dev/null +++ b/libstdc++-v3/include/bits/ranges_algo.h @@ -0,0 +1,3640 @@ +// Core algorithmic facilities -*- C++ -*- + +// Copyright (C) 2019-2020 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. + +// Under Section 7 of GPL version 3, you are granted additional +// permissions described in the GCC Runtime Library Exception, version +// 3.1, as published by the Free Software Foundation. + +// You should have received a copy of the GNU General Public License and +// a copy of the GCC Runtime Library Exception along with this program; +// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +// . + +/** @file bits/ranges_algo.h + * This is an internal header file, included by other library headers. + * Do not attempt to use it directly. @headername{algorithm} + */ + +#ifndef _RANGES_ALGO_H +#define _RANGES_ALGO_H 1 + +#if __cplusplus > 201703L + +#include +#include +#include +// #include +#include +#include +#include // __is_byte +#include // concept uniform_random_bit_generator + +#if __cpp_lib_concepts +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION +namespace ranges +{ + namespace __detail + { + template + constexpr inline bool __is_normal_iterator = false; + + template + constexpr inline bool + __is_normal_iterator<__gnu_cxx::__normal_iterator<_Iterator, _Container>> + = true; + + template + constexpr inline bool __is_reverse_iterator = false; + + template + constexpr inline bool + __is_reverse_iterator> = true; + + template + constexpr inline bool __is_move_iterator = false; + + template + constexpr inline bool + __is_move_iterator> = true; + + template + constexpr auto + __make_comp_proj(_Comp& __comp, _Proj& __proj) + { + return [&] (auto&& __lhs, auto&& __rhs) -> bool { + using _TL = decltype(__lhs); + using _TR = decltype(__rhs); + return std::__invoke(__comp, + std::__invoke(__proj, std::forward<_TL>(__lhs)), + std::__invoke(__proj, std::forward<_TR>(__rhs))); + }; + } + + template + constexpr auto + __make_pred_proj(_Pred& __pred, _Proj& __proj) + { + return [&] (_Tp&& __arg) -> bool { + return std::__invoke(__pred, + std::__invoke(__proj, std::forward<_Tp>(__arg))); + }; + } + } + + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr bool + all_of(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) + { + for (; __first != __last; ++__first) + if (!(bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) + return false; + return true; + } + + template, _Proj>> _Pred> + constexpr bool + all_of(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return ranges::all_of(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr bool + any_of(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) + { + for (; __first != __last; ++__first) + if (std::__invoke(__pred, std::__invoke(__proj, *__first))) + return true; + return false; + } + + template, _Proj>> _Pred> + constexpr bool + any_of(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return ranges::any_of(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr bool + none_of(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) + { + for (; __first != __last; ++__first) + if (std::__invoke(__pred, std::__invoke(__proj, *__first))) + return false; + return true; + } + + template, _Proj>> _Pred> + constexpr bool + none_of(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return ranges::none_of(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template + struct for_each_result + { + [[no_unique_address]] _Iter in; + [[no_unique_address]] _Fp fun; + + template + requires convertible_to + && convertible_to + operator for_each_result<_Iter2, _F2p>() const & + { return {in, fun}; } + + template + requires convertible_to<_Iter, _Iter2> && convertible_to<_Fp, _F2p> + operator for_each_result<_Iter2, _F2p>() && + { return {std::move(in), std::move(fun)}; } + }; + + template _Sent, + typename _Proj = identity, + indirectly_unary_invocable> _Fun> + constexpr for_each_result<_Iter, _Fun> + for_each(_Iter __first, _Sent __last, _Fun __f, _Proj __proj = {}) + { + for (; __first != __last; ++__first) + std::__invoke(__f, std::__invoke(__proj, *__first)); + return { std::move(__first), std::move(__f) }; + } + + template, _Proj>> + _Fun> + constexpr for_each_result, _Fun> + for_each(_Range&& __r, _Fun __f, _Proj __proj = {}) + { + return ranges::for_each(ranges::begin(__r), ranges::end(__r), + std::move(__f), std::move(__proj)); + } + + template _Sent, typename _Tp, + typename _Proj = identity> + requires indirect_binary_predicate, const _Tp*> + constexpr _Iter + find(_Iter __first, _Sent __last, const _Tp& __value, _Proj __proj = {}) + { + while (__first != __last + && !(std::__invoke(__proj, *__first) == __value)) + ++__first; + return __first; + } + + template + requires indirect_binary_predicate, _Proj>, + const _Tp*> + constexpr safe_iterator_t<_Range> + find(_Range&& __r, const _Tp& __value, _Proj __proj = {}) + { + return ranges::find(ranges::begin(__r), ranges::end(__r), __value, + std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr _Iter + find_if(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) + { + while (__first != __last + && !(bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) + ++__first; + return __first; + } + + template, _Proj>> + _Pred> + constexpr safe_iterator_t<_Range> + find_if(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return ranges::find_if(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr _Iter + find_if_not(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) + { + while (__first != __last + && (bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) + ++__first; + return __first; + } + + template, _Proj>> + _Pred> + constexpr safe_iterator_t<_Range> + find_if_not(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return ranges::find_if_not(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template _Sent1, + forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + constexpr _Iter1 + find_first_of(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, + _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + for (; __first1 != __last1; ++__first1) + for (auto __iter = __first2; __iter != __last2; ++__iter) + if (std::__invoke(__pred, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__iter))) + return __first1; + return __first1; + } + + template + requires indirectly_comparable, iterator_t<_Range2>, + _Pred, _Proj1, _Proj2> + constexpr safe_iterator_t<_Range1> + find_first_of(_Range1&& __r1, _Range2&& __r2, + _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::find_first_of(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + template _Sent, + typename _Tp, typename _Proj = identity> + requires indirect_binary_predicate, + const _Tp*> + constexpr iter_difference_t<_Iter> + count(_Iter __first, _Sent __last, const _Tp& __value, _Proj __proj = {}) + { + iter_difference_t<_Iter> __n = 0; + for (; __first != __last; ++__first) + if (std::__invoke(__proj, *__first) == __value) + ++__n; + return __n; + } + + template + requires indirect_binary_predicate, _Proj>, + const _Tp*> + constexpr range_difference_t<_Range> + count(_Range&& __r, const _Tp& __value, _Proj __proj = {}) + { + return ranges::count(ranges::begin(__r), ranges::end(__r), + __value, std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr iter_difference_t<_Iter> + count_if(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) + { + iter_difference_t<_Iter> __n = 0; + for (; __first != __last; ++__first) + if (std::__invoke(__pred, std::__invoke(__proj, *__first))) + ++__n; + return __n; + } + + template, _Proj>> _Pred> + constexpr range_difference_t<_Range> + count_if(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return ranges::count_if(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template + struct mismatch_result + { + [[no_unique_address]] _Iter1 in1; + [[no_unique_address]] _Iter2 in2; + + template + requires convertible_to + && convertible_to + operator mismatch_result<_IIter1, _IIter2>() const & + { return {in1, in2}; } + + template + requires convertible_to<_Iter1, _IIter1> + && convertible_to<_Iter2, _IIter2> + operator mismatch_result<_IIter1, _IIter2>() && + { return {std::move(in1), std::move(in2)}; } + }; + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + constexpr mismatch_result<_Iter1, _Iter2> + mismatch(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, + _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + while (__first1 != __last1 && __first2 != __last2 + && (bool)std::__invoke(__pred, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + { + ++__first1; + ++__first2; + } + return { std::move(__first1), std::move(__first2) }; + } + + template + requires indirectly_comparable, iterator_t<_Range2>, + _Pred, _Proj1, _Proj2> + constexpr mismatch_result, iterator_t<_Range2>> + mismatch(_Range1&& __r1, _Range2&& __r2, + _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::mismatch(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + template _Sent1, + forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + constexpr subrange<_Iter1> + search(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, + _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + if (__first1 == __last1 || __first2 == __last2) + return {__first1, __first1}; + + for (;;) + { + for (;;) + { + if (__first1 == __last1) + return {__first1, __first1}; + if (std::__invoke(__pred, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + break; + ++__first1; + } + auto __cur1 = __first1; + auto __cur2 = __first2; + for (;;) + { + if (++__cur2 == __last2) + return {__first1, ++__cur1}; + if (++__cur1 == __last1) + return {__cur1, __cur1}; + if (!(bool)std::__invoke(__pred, + std::__invoke(__proj1, *__cur1), + std::__invoke(__proj2, *__cur2))) + { + ++__first1; + break; + } + } + } + } + + template + requires indirectly_comparable, iterator_t<_Range2>, + _Pred, _Proj1, _Proj2> + constexpr safe_subrange_t<_Range1> + search(_Range1&& __r1, _Range2&& __r2, + _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::search(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + template _Sent, typename _Tp, + typename _Pred = ranges::equal_to, typename _Proj = identity> + requires indirectly_comparable<_Iter, const _Tp*, _Pred, _Proj> + constexpr subrange<_Iter> + search_n(_Iter __first, _Sent __last, iter_difference_t<_Iter> __count, + const _Tp& __value, _Pred __pred = {}, _Proj __proj = {}) + { + if (__count <= 0) + return {__first, __first}; + + auto __value_comp = [&] (_Rp&& __arg) { + return std::__invoke(__pred, std::forward<_Rp>(__arg), __value); + }; + if (__count == 1) + { + __first = ranges::find_if(std::move(__first), __last, + std::move(__value_comp), std::move(__proj)); + if (__first == __last) + return {__first, __first}; + else + { + auto __end = __first; + return {__first, ++__end}; + } + } + + if constexpr (sized_sentinel_for<_Sent, _Iter>) + { + auto __tail_size = __last - __first; + auto __remainder = __count; + + while (__remainder <= __tail_size) + { + __first += __remainder; + __tail_size -= __remainder; + auto __backtrack = __first; + while (__value_comp(std::__invoke(__proj, *--__backtrack))) + { + if (--__remainder == 0) + return {__first - __count, __first}; + } + } + auto __i = __first + __tail_size; + return {__i, __i}; + } + else + { + __first = ranges::find_if(__first, __last, __value_comp, __proj); + while (__first != __last) + { + auto __n = __count; + auto __i = __first; + ++__i; + while (__i != __last && __n != 1 + && __value_comp(std::__invoke(__proj, *__i))) + { + ++__i; + --__n; + } + if (__n == 1) + return {__first, __i}; + if (__i == __last) + return {__i, __i}; + __first = ranges::find_if(++__i, __last, __value_comp, __proj); + } + return {__first, __first}; + } + } + + template + requires indirectly_comparable, const _Tp*, _Pred, _Proj> + constexpr safe_subrange_t<_Range> + search_n(_Range&& __r, range_difference_t<_Range> __count, + const _Tp& __value, _Pred __pred = {}, _Proj __proj = {}) + { + return ranges::search_n(ranges::begin(__r), ranges::end(__r), + std::move(__count), __value, + std::move(__pred), std::move(__proj)); + } + + template _Sent1, + forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + constexpr subrange<_Iter1> + __find_end(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, + _Pred __pred, _Proj1 __proj1, _Proj2 __proj2) + { + auto __i = ranges::next(__first1, __last1); + if (__first2 == __last2) + return {__i, __i}; + + auto __result_begin = __i; + auto __result_end = __i; + for (;;) + { + auto __new_range = ranges::search(__first1, __last1, + __first2, __last2, + __pred, __proj1, __proj2); + auto __new_result_begin = ranges::begin(__new_range); + auto __new_result_end = ranges::end(__new_range); + if (__new_result_begin == __last1) + return {__result_begin, __result_end}; + else + { + __result_begin = __new_result_begin; + __result_end = __new_result_end; + __first1 = __result_begin; + ++__first1; + } + } + } + + template _Sent1, + forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + constexpr subrange<_Iter1> + find_end(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, + _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + if constexpr (bidirectional_iterator<_Iter1> + && bidirectional_iterator<_Iter2>) + { + auto __i1 = ranges::next(__first1, __last1); + auto __i2 = ranges::next(__first2, __last2); + auto __rresult + = ranges::search(reverse_iterator<_Iter1>{__i1}, + reverse_iterator<_Iter1>{__first1}, + reverse_iterator<_Iter2>{__i2}, + reverse_iterator<_Iter2>{__first2}, + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + auto __result_first = ranges::end(__rresult).base(); + auto __result_last = ranges::begin(__rresult).base(); + if (__result_last == __first1) + return {__i1, __i1}; + else + return {__result_first, __result_last}; + } + else + return ranges::__find_end(__first1, __last1, __first2, __last2, + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + template + requires indirectly_comparable, iterator_t<_Range2>, + _Pred, _Proj1, _Proj2> + constexpr safe_subrange_t<_Range1> + find_end(_Range1&& __r1, _Range2&& __r2, + _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::find_end(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + template _Sent, + typename _Proj = identity, + indirect_binary_predicate, + projected<_Iter, _Proj>> _Pred + = ranges::equal_to> + constexpr _Iter + adjacent_find(_Iter __first, _Sent __last, + _Pred __pred = {}, _Proj __proj = {}) + { + if (__first == __last) + return __first; + auto __next = __first; + for (; ++__next != __last; __first = __next) + { + if (std::__invoke(__pred, + std::__invoke(__proj, *__first), + std::__invoke(__proj, *__next))) + return __first; + } + return __next; + } + + template, _Proj>, + projected, _Proj>> _Pred = ranges::equal_to> + constexpr safe_iterator_t<_Range> + adjacent_find(_Range&& __r, _Pred __pred = {}, _Proj __proj = {}) + { + return ranges::adjacent_find(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template _Sent1, + forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Proj1 = identity, typename _Proj2 = identity, + indirect_equivalence_relation, + projected<_Iter2, _Proj2>> _Pred + = ranges::equal_to> + constexpr bool + is_permutation(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, _Pred __pred = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + constexpr bool __sized_iters + = (sized_sentinel_for<_Sent1, _Iter1> + && sized_sentinel_for<_Sent2, _Iter2>); + if constexpr (__sized_iters) + { + auto __d1 = ranges::distance(__first1, __last1); + auto __d2 = ranges::distance(__first2, __last2); + if (__d1 != __d2) + return false; + } + + // Efficiently compare identical prefixes: O(N) if sequences + // have the same elements in the same order. + for (; __first1 != __last1 && __first2 != __last2; + ++__first1, (void)++__first2) + if (!(bool)std::__invoke(__pred, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + break; + + if constexpr (__sized_iters) + { + if (__first1 == __last1) + return true; + } + else + { + auto __d1 = ranges::distance(__first1, __last1); + auto __d2 = ranges::distance(__first2, __last2); + if (__d1 == 0 && __d2 == 0) + return true; + if (__d1 != __d2) + return false; + } + + for (auto __scan = __first1; __scan != __last1; ++__scan) + { + auto __proj_scan = std::__invoke(__proj1, *__scan); + auto __comp_scan = [&] (_Tp&& __arg) { + return std::__invoke(__pred, __proj_scan, + std::forward<_Tp>(__arg)); + }; + if (__scan != ranges::find_if(__first1, __scan, + __comp_scan, __proj1)) + continue; // We've seen this one before. + + auto __matches = ranges::count_if(__first2, __last2, + __comp_scan, __proj2); + if (__matches == 0 + || ranges::count_if(__scan, __last1, + __comp_scan, __proj1) != __matches) + return false; + } + return true; + } + + template, _Proj1>, + projected, _Proj2>> _Pred = ranges::equal_to> + constexpr bool + is_permutation(_Range1&& __r1, _Range2&& __r2, _Pred __pred = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::is_permutation(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Pred, typename _Proj1, typename _Proj2> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + constexpr bool + __equal(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, + _Pred __pred, _Proj1 __proj1, _Proj2 __proj2) + { + // TODO: implement more specializations to at least have parity with + // std::equal. + constexpr bool __sized_iters + = (sized_sentinel_for<_Sent1, _Iter1> + && sized_sentinel_for<_Sent2, _Iter2>); + if constexpr (__sized_iters) + { + auto __d1 = ranges::distance(__first1, __last1); + auto __d2 = ranges::distance(__first2, __last2); + if (__d1 != __d2) + return false; + + using _ValueType1 = iter_value_t<_Iter1>; + using _ValueType2 = iter_value_t<_Iter2>; + constexpr bool __use_memcmp + = ((is_integral_v<_ValueType1> || is_pointer_v<_ValueType1>) + && is_same_v<_ValueType1, _ValueType2> + && is_pointer_v<_Iter1> + && is_pointer_v<_Iter2> + && is_same_v<_Pred, ranges::equal_to> + && is_same_v<_Proj1, identity> + && is_same_v<_Proj2, identity>); + if constexpr (__use_memcmp) + { + if (const size_t __len = (__last1 - __first1)) + return !std::__memcmp(__first1, __first2, __len); + return true; + } + else + { + for (; __first1 != __last1; ++__first1, (void)++__first2) + if (!(bool)std::__invoke(__pred, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + return false; + return true; + } + } + else + { + for (; __first1 != __last1 && __first2 != __last2; + ++__first1, (void)++__first2) + if (!(bool)std::__invoke(__pred, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + return false; + return __first1 == __last1 && __first2 == __last2; + } + } + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + constexpr bool + equal(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, + _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::__equal(std::__niter_base(std::move(__first1)), + std::__niter_base(std::move(__last1)), + std::__niter_base(std::move(__first2)), + std::__niter_base(std::move(__last2)), + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + template + requires indirectly_comparable, iterator_t<_Range2>, + _Pred, _Proj1, _Proj2> + constexpr bool + equal(_Range1&& __r1, _Range2&& __r2, + _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::equal(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__pred), + std::move(__proj1), std::move(__proj2)); + } + + template + struct copy_result + { + [[no_unique_address]] _Iter in; + [[no_unique_address]] _Out out; + + template + requires convertible_to + && convertible_to + operator copy_result<_Iter2, _Out2>() const & + { return {in, out}; } + + template + requires convertible_to<_Iter, _Iter2> + && convertible_to<_Out, _Out2> + operator copy_result<_Iter2, _Out2>() && + { return {std::move(in), std::move(out)}; } + }; + + template + using move_result = copy_result<_Iter, _Out>; + + template + using move_backward_result = copy_result<_Iter1, _Iter2>; + + template + using copy_backward_result = copy_result<_Iter1, _Iter2>; + + template _Sent, + bidirectional_iterator _Out> + requires (_IsMove + ? indirectly_movable<_Iter, _Out> + : indirectly_copyable<_Iter, _Out>) + constexpr conditional_t<_IsMove, + move_backward_result<_Iter, _Out>, + copy_backward_result<_Iter, _Out>> + __copy_or_move_backward(_Iter __first, _Sent __last, _Out __result); + + template _Sent, + weakly_incrementable _Out> + requires (_IsMove + ? indirectly_movable<_Iter, _Out> + : indirectly_copyable<_Iter, _Out>) + constexpr conditional_t<_IsMove, + move_result<_Iter, _Out>, + copy_result<_Iter, _Out>> + __copy_or_move(_Iter __first, _Sent __last, _Out __result) + { + // TODO: implement more specializations to be at least on par with + // std::copy/std::move. + constexpr bool __normal_iterator_p + = (__detail::__is_normal_iterator<_Iter> + || __detail::__is_normal_iterator<_Out>); + constexpr bool __reverse_p + = (__detail::__is_reverse_iterator<_Iter> + && __detail::__is_reverse_iterator<_Out>); + constexpr bool __move_iterator_p = __detail::__is_move_iterator<_Iter>; + if constexpr (__move_iterator_p) + { + auto [__in, __out] + = ranges::__copy_or_move(std::move(__first).base(), + std::move(__last).base(), + std::move(__result)); + return {move_iterator{std::move(__in)}, std::move(__out)}; + } + else if constexpr (__reverse_p) + { + auto [__in,__out] + = ranges::__copy_or_move_backward<_IsMove>(__last.base(), + __first.base(), + __result.base()); + return {reverse_iterator{std::move(__in)}, + reverse_iterator{std::move(__out)}}; + } + else if constexpr (__normal_iterator_p) + { + auto [__in,__out] + = ranges::__copy_or_move<_IsMove>(std::__niter_base(__first), + std::__niter_base(__last), + std::__niter_base(__result)); + return {std::__niter_wrap(__first, std::move(__in)), + std::__niter_wrap(__result, std::move(__out))}; + } + else if constexpr (sized_sentinel_for<_Sent, _Iter>) + { + using _ValueTypeI = iter_value_t<_Iter>; + using _ValueTypeO = iter_value_t<_Out>; + constexpr bool __use_memmove + = (is_trivially_copyable_v<_ValueTypeI> + && is_same_v<_ValueTypeI, _ValueTypeO> + && is_pointer_v<_Iter> + && is_pointer_v<_Out>); + + if constexpr (__use_memmove) + { + static_assert(_IsMove + ? is_move_assignable_v<_ValueTypeI> + : is_copy_assignable_v<_ValueTypeI>); + auto __num = __last - __first; + if (__num) + std::__memmove<_IsMove>(__result, __first, __num); + return {__first + __num, __result + __num}; + } + else + { + for (auto __n = __last - __first; __n > 0; --__n) + { + if constexpr (_IsMove) + *__result = std::move(*__first); + else + *__result = *__first; + ++__first; + ++__result; + } + return {std::move(__first), std::move(__result)}; + } + } + else + { + while (__first != __last) + { + if constexpr (_IsMove) + *__result = std::move(*__first); + else + *__result = *__first; + ++__first; + ++__result; + } + return {std::move(__first), std::move(__result)}; + } + } + + template _Sent, + weakly_incrementable _Out> + requires indirectly_copyable<_Iter, _Out> + constexpr copy_result<_Iter, _Out> + copy(_Iter __first, _Sent __last, _Out __result) + { + return ranges::__copy_or_move(std::move(__first), + std::move(__last), + std::move(__result)); + } + + template + requires indirectly_copyable, _Out> + constexpr copy_result, _Out> + copy(_Range&& __r, _Out __result) + { + return ranges::copy(ranges::begin(__r), ranges::end(__r), + std::move(__result)); + } + + template _Sent, + weakly_incrementable _Out> + requires indirectly_movable<_Iter, _Out> + constexpr move_result<_Iter, _Out> + move(_Iter __first, _Sent __last, _Out __result) + { + return ranges::__copy_or_move(std::move(__first), + std::move(__last), + std::move(__result)); + } + + template + requires indirectly_movable, _Out> + constexpr move_result, _Out> + move(_Range&& __r, _Out __result) + { + return ranges::move(ranges::begin(__r), ranges::end(__r), + std::move(__result)); + } + + template _Sent, + bidirectional_iterator _Out> + requires (_IsMove + ? indirectly_movable<_Iter, _Out> + : indirectly_copyable<_Iter, _Out>) + constexpr conditional_t<_IsMove, + move_backward_result<_Iter, _Out>, + copy_backward_result<_Iter, _Out>> + __copy_or_move_backward(_Iter __first, _Sent __last, _Out __result) + { + // TODO: implement more specializations to be at least on par with + // std::copy_backward/std::move_backward. + constexpr bool __normal_iterator_p + = (__detail::__is_normal_iterator<_Iter> + || __detail::__is_normal_iterator<_Out>); + constexpr bool __reverse_p + = (__detail::__is_reverse_iterator<_Iter> + && __detail::__is_reverse_iterator<_Out>); + if constexpr (__reverse_p) + { + auto [__in,__out] + = ranges::__copy_or_move<_IsMove>(__last.base(), + __first.base(), + __result.base()); + return {reverse_iterator{std::move(__in)}, + reverse_iterator{std::move(__out)}}; + } + else if constexpr (__normal_iterator_p) + { + auto [__in,__out] + = ranges::__copy_or_move_backward<_IsMove> + (std::__niter_base(__first), + std::__niter_base(__last), + std::__niter_base(__result)); + return {std::__niter_wrap(__first, std::move(__in)), + std::__niter_wrap(__result, std::move(__out))}; + } + else if constexpr (sized_sentinel_for<_Sent, _Iter>) + { + using _ValueTypeI = iter_value_t<_Iter>; + using _ValueTypeO = iter_value_t<_Out>; + constexpr bool __use_memmove + = (is_trivially_copyable_v<_ValueTypeI> + && is_same_v<_ValueTypeI, _ValueTypeO> + && is_pointer_v<_Iter> + && is_pointer_v<_Out>); + if constexpr (__use_memmove) + { + static_assert(_IsMove + ? is_move_assignable_v<_ValueTypeI> + : is_copy_assignable_v<_ValueTypeI>); + auto __num = __last - __first; + if (__num) + std::__memmove<_IsMove>(__result - __num, __first, __num); + return {__first + __num, __result - __num}; + } + else + { + auto __lasti = ranges::next(__first, __last); + auto __tail = __lasti; + + for (auto __n = __last - __first; __n > 0; --__n) + { + --__tail; + --__result; + if constexpr (_IsMove) + *__result = std::move(*__tail); + else + *__result = *__tail; + } + return {std::move(__lasti), std::move(__result)}; + } + } + else + { + auto __lasti = ranges::next(__first, __last); + auto __tail = __lasti; + + while (__first != __tail) + { + --__tail; + --__result; + if constexpr (_IsMove) + *__result = std::move(*__tail); + else + *__result = *__tail; + } + return {std::move(__lasti), std::move(__result)}; + } + } + + template _Sent1, + bidirectional_iterator _Iter2> + requires indirectly_copyable<_Iter1, _Iter2> + constexpr copy_backward_result<_Iter1, _Iter2> + copy_backward(_Iter1 __first, _Sent1 __last, _Iter2 __result) + { + return ranges::__copy_or_move_backward(std::move(__first), + std::move(__last), + std::move(__result)); + } + + template + requires indirectly_copyable, _Iter> + constexpr copy_backward_result, _Iter> + copy_backward(_Range&& __r, _Iter __result) + { + return ranges::copy_backward(ranges::begin(__r), ranges::end(__r), + std::move(__result)); + } + + template _Sent1, + bidirectional_iterator _Iter2> + requires indirectly_movable<_Iter1, _Iter2> + constexpr move_backward_result<_Iter1, _Iter2> + move_backward(_Iter1 __first, _Sent1 __last, _Iter2 __result) + { + return ranges::__copy_or_move_backward(std::move(__first), + std::move(__last), + std::move(__result)); + } + + template + requires indirectly_movable, _Iter> + constexpr move_backward_result, _Iter> + move_backward(_Range&& __r, _Iter __result) + { + return ranges::move_backward(ranges::begin(__r), ranges::end(__r), + std::move(__result)); + } + + template + using copy_n_result = copy_result<_Iter, _Out>; + + template + requires indirectly_copyable<_Iter, _Out> + constexpr copy_n_result<_Iter, _Out> + copy_n(_Iter __first, iter_difference_t<_Iter> __n, _Out __result) + { + if constexpr (random_access_iterator<_Iter>) + return ranges::copy(__first, __first + __n, std::move(__result)); + else + { + for (; __n > 0; --__n, (void)++__result, (void)++__first) + *__result = *__first; + return {std::move(__first), std::move(__result)}; + } + } + + template + using copy_if_result = copy_result<_Iter, _Out>; + + template _Sent, + weakly_incrementable _Out, typename _Proj = identity, + indirect_unary_predicate> _Pred> + requires indirectly_copyable<_Iter, _Out> + constexpr copy_if_result<_Iter, _Out> + copy_if(_Iter __first, _Sent __last, _Out __result, + _Pred __pred, _Proj __proj = {}) + { + for (; __first != __last; ++__first) + if (std::__invoke(__pred, std::__invoke(__proj, *__first))) + { + *__result = *__first; + ++__result; + } + return {std::move(__first), std::move(__result)}; + } + + template, _Proj>> _Pred> + requires indirectly_copyable, _Out> + constexpr copy_if_result, _Out> + copy_if(_Range&& __r, _Out __result, _Pred __pred, _Proj __proj = {}) + { + return ranges::copy_if(ranges::begin(__r), ranges::end(__r), + std::move(__result), + std::move(__pred), std::move(__proj)); + } + + template + using swap_ranges_result = mismatch_result<_Iter1, _Iter2>; + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2> + requires indirectly_swappable<_Iter1, _Iter2> + constexpr swap_ranges_result<_Iter1, _Iter2> + swap_ranges(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2) + { + for (; __first1 != __last1 && __first2 != __last2; + ++__first1, (void)++__first2) + ranges::iter_swap(__first1, __first2); + return {std::move(__first1), std::move(__first2)}; + } + + template + requires indirectly_swappable, iterator_t<_Range2>> + constexpr swap_ranges_result, + safe_iterator_t<_Range2>> + swap_ranges(_Range1&& __r1, _Range2&& __r2) + { + return ranges::swap_ranges(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2)); + } + + template + using unary_transform_result = copy_result<_Iter, _Out>; + + template _Sent, + weakly_incrementable _Out, + copy_constructible _Fp, typename _Proj = identity> + requires writable<_Out, indirect_result_t<_Fp&, projected<_Iter, _Proj>>> + constexpr unary_transform_result<_Iter, _Out> + transform(_Iter __first1, _Sent __last1, _Out __result, + _Fp __op, _Proj __proj = {}) + { + for (; __first1 != __last1; ++__first1, (void)++__result) + *__result = std::__invoke(__op, std::__invoke(__proj, *__first1)); + return {std::move(__first1), std::move(__result)}; + } + + template + requires writable<_Out, + indirect_result_t<_Fp&, projected, + _Proj>>> + constexpr unary_transform_result, _Out> + transform(_Range&& __r, _Out __result, _Fp __op, _Proj __proj = {}) + { + return ranges::transform(ranges::begin(__r), ranges::end(__r), + std::move(__result), + std::move(__op), std::move(__proj)); + } + + template + struct binary_transform_result + { + [[no_unique_address]] _Iter1 in1; + [[no_unique_address]] _Iter2 in2; + [[no_unique_address]] _Out out; + + template + requires convertible_to && + && convertible_to + && convertible_to + operator binary_transform_result<_IIter1, _IIter2, _OOut>() const & + { return {in1, in2, out}; } + + template + requires convertible_to<_Iter1, _IIter1> + && convertible_to<_Iter2, _IIter2> + && convertible_to<_Out, _OOut> + operator binary_transform_result<_IIter1, _IIter2, _OOut>() && + { return {std::move(in1), std::move(in2), std::move(out)}; } + }; + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + weakly_incrementable _Out, copy_constructible _Fp, + typename _Proj1 = identity, typename _Proj2 = identity> + requires writable<_Out, indirect_result_t<_Fp&, projected<_Iter1, _Proj1>, + projected<_Iter2, _Proj2>>> + constexpr binary_transform_result<_Iter1, _Iter2, _Out> + transform(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, + _Out __result, _Fp __binary_op, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + for (; __first1 != __last1 && __first2 != __last2; + ++__first1, (void)++__first2, ++__result) + *__result = std::__invoke(__binary_op, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2)); + return {std::move(__first1), std::move(__first2), std::move(__result)}; + } + + template + requires writable<_Out, indirect_result_t<_Fp&, + projected, + _Proj1>, + projected, + _Proj2>>> + constexpr binary_transform_result, + safe_iterator_t<_Range2>, _Out> + transform(_Range1&& __r1, _Range2&& __r2, _Out __result, + _Fp __binary_op, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::transform(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__result), std::move(__binary_op), + std::move(__proj1), std::move(__proj2)); + } + + template _Sent, + typename _Tp1, typename _Tp2, typename _Proj = identity> + requires writable<_Iter, const _Tp2&> && + indirect_binary_predicate, const _Tp1*> + constexpr _Iter + replace(_Iter __first, _Sent __last, + const _Tp1& __old_value, const _Tp2& __new_value, + _Proj __proj = {}) + { + for (; __first != __last; ++__first) + if (std::__invoke(__proj, *__first) == __old_value) + *__first = __new_value; + return __first; + } + + template + requires writable, const _Tp2&> && + indirect_binary_predicate, _Proj>, + const _Tp1*> + constexpr safe_iterator_t<_Range> + replace(_Range&& __r, + const _Tp1& __old_value, const _Tp2& __new_value, + _Proj __proj = {}) + { + return ranges::replace(ranges::begin(__r), ranges::end(__r), + __old_value, __new_value, std::move(__proj)); + } + + template _Sent, + typename _Tp, typename _Proj = identity, + indirect_unary_predicate> _Pred> + requires writable<_Iter, const _Tp&> + constexpr _Iter + replace_if(_Iter __first, _Sent __last, + _Pred __pred, const _Tp& __new_value, _Proj __proj = {}) + { + for (; __first != __last; ++__first) + if (std::__invoke(__pred, std::__invoke(__proj, *__first))) + *__first = __new_value; + return std::move(__first); + } + + template, _Proj>> _Pred> + requires writable, const _Tp&> + constexpr safe_iterator_t<_Range> + replace_if(_Range&& __r, + _Pred __pred, const _Tp& __new_value, _Proj __proj = {}) + { + return ranges::replace_if(ranges::begin(__r), ranges::end(__r), + std::move(__pred), __new_value, + std::move(__proj)); + } + + template + using replace_copy_result = copy_result<_Iter, _Out>; + + template _Sent, + typename _Tp1, typename _Tp2, output_iterator _Out, + typename _Proj = identity> + requires indirectly_copyable<_Iter, _Out> + && indirect_binary_predicate, const _Tp1*> + constexpr replace_copy_result<_Iter, _Out> + replace_copy(_Iter __first, _Sent __last, _Out __result, + const _Tp1& __old_value, const _Tp2& __new_value, + _Proj __proj = {}) + { + for (; __first != __last; ++__first, (void)++__result) + if (std::__invoke(__proj, *__first) == __old_value) + *__result = __new_value; + else + *__result = *__first; + return {std::move(__first), std::move(__result)}; + } + + template _Out, typename _Proj = identity> + requires indirectly_copyable, _Out> + && indirect_binary_predicate, _Proj>, + const _Tp1*> + constexpr replace_copy_result, _Out> + replace_copy(_Range&& __r, _Out __result, + const _Tp1& __old_value, const _Tp2& __new_value, + _Proj __proj = {}) + { + return ranges::replace_copy(ranges::begin(__r), ranges::end(__r), + std::move(__result), __old_value, + __new_value, std::move(__proj)); + } + + template + using replace_copy_if_result = copy_result<_Iter, _Out>; + + template _Sent, + typename _Tp, output_iterator _Out, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + requires indirectly_copyable<_Iter, _Out> + constexpr replace_copy_if_result<_Iter, _Out> + replace_copy_if(_Iter __first, _Sent __last, _Out __result, + _Pred __pred, const _Tp& __new_value, _Proj __proj = {}) + { + for (; __first != __last; ++__first, (void)++__result) + if (std::__invoke(__pred, std::__invoke(__proj, *__first))) + *__result = __new_value; + else + *__result = *__first; + return {std::move(__first), std::move(__result)}; + } + + template _Out, + typename _Proj = identity, + indirect_unary_predicate, _Proj>> _Pred> + requires indirectly_copyable, _Out> + constexpr replace_copy_if_result, _Out> + replace_copy_if(_Range&& __r, _Out __result, + _Pred __pred, const _Tp& __new_value, _Proj __proj = {}) + { + return ranges::replace_copy_if(ranges::begin(__r), ranges::end(__r), + std::move(__result), std::move(__pred), + __new_value, std::move(__proj)); + } + + template _Out> + constexpr _Out + fill_n(_Out __first, iter_difference_t<_Out> __n, const _Tp& __value) + { + // TODO: implement more specializations to be at least on par with + // std::fill_n + if (__n <= 0) + return __first; + + // TODO: is __is_byte the best condition? + if constexpr (is_pointer_v<_Out> && __is_byte<_Tp>::__value) + { + __builtin_memset(__first, static_cast(__value), __n); + return __first + __n; + } + else if constexpr (is_scalar_v<_Tp>) + { + const auto __tmp = __value; + for (; __n > 0; --__n, (void)++__first) + *__first = __tmp; + return __first; + } + else + { + for (; __n > 0; --__n, (void)++__first) + *__first = __value; + return __first; + } + } + + template _Out, sentinel_for<_Out> _Sent> + constexpr _Out + fill(_Out __first, _Sent __last, const _Tp& __value) + { + // TODO: implement more specializations to be at least on par with + // std::fill + if constexpr (sized_sentinel_for<_Sent, _Out>) + { + const auto __len = __last - __first; + return ranges::fill_n(__first, __len, __value); + } + else if constexpr (is_scalar_v<_Tp>) + { + const auto __tmp = __value; + for (; __first != __last; ++__first) + *__first = __tmp; + return __first; + } + else + { + for (; __first != __last; ++__first) + *__first = __value; + return __first; + } + } + + template _Range> + constexpr safe_iterator_t<_Range> + fill(_Range&& __r, const _Tp& __value) + { + return ranges::fill(ranges::begin(__r), ranges::end(__r), __value); + } + + template + requires invocable<_Fp&> && writable<_Out, invoke_result_t<_Fp&>> + constexpr _Out + generate_n(_Out __first, iter_difference_t<_Out> __n, _Fp __gen) + { + for (; __n > 0; --__n, (void)++__first) + *__first = std::__invoke(__gen); + return __first; + } + + template _Sent, + copy_constructible _Fp> + requires invocable<_Fp&> && writable<_Out, invoke_result_t<_Fp&>> + constexpr _Out + generate(_Out __first, _Sent __last, _Fp __gen) + { + for (; __first != __last; ++__first) + *__first = std::__invoke(__gen); + return __first; + } + + template + requires invocable<_Fp&> && output_range<_Range, invoke_result_t<_Fp&>> + constexpr safe_iterator_t<_Range> + generate(_Range&& __r, _Fp __gen) + { + return ranges::generate(ranges::begin(__r), ranges::end(__r), + std::move(__gen)); + } + + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr subrange<_Iter> + remove_if(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) + { + __first = ranges::find_if(__first, __last, __pred, __proj); + if (__first == __last) + return {__first, __first}; + + auto __result = __first; + ++__first; + for (; __first != __last; ++__first) + if (!(bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) + { + *__result = std::move(*__first); + ++__result; + } + + return {__result, __first}; + } + + template, _Proj>> _Pred> + requires permutable> + constexpr safe_subrange_t<_Range> + remove_if(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return ranges::remove_if(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template _Sent, + typename _Tp, typename _Proj = identity> + requires indirect_binary_predicate, + const _Tp*> + constexpr subrange<_Iter> + remove(_Iter __first, _Sent __last, const _Tp& __value, _Proj __proj = {}) + { + auto __pred = [&] (auto&& __arg) { + return std::forward(__arg) == __value; + }; + return ranges::remove_if(__first, __last, + std::move(__pred), std::move(__proj)); + } + + template + requires permutable> && + indirect_binary_predicate, _Proj>, + const _Tp*> + constexpr safe_subrange_t<_Range> + remove(_Range&& __r, const _Tp& __value, _Proj __proj = {}) + { + return ranges::remove(ranges::begin(__r), ranges::end(__r), + __value, std::move(__proj)); + } + + template + using remove_copy_if_result = copy_result<_Iter, _Out>; + + template _Sent, + weakly_incrementable _Out, typename _Proj = identity, + indirect_unary_predicate> _Pred> + requires indirectly_copyable<_Iter, _Out> + constexpr remove_copy_if_result<_Iter, _Out> + remove_copy_if(_Iter __first, _Sent __last, _Out __result, + _Pred __pred, _Proj __proj = {}) + { + for (; __first != __last; ++__first) + if (!(bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) + { + *__result = *__first; + ++__result; + } + return {std::move(__first), std::move(__result)}; + } + + template, _Proj>> _Pred> + requires indirectly_copyable, _Out> + constexpr remove_copy_if_result, _Out> + remove_copy_if(_Range&& __r, _Out __result, + _Pred __pred, _Proj __proj = {}) + { + return ranges::remove_copy_if(ranges::begin(__r), ranges::end(__r), + std::move(__result), + std::move(__pred), std::move(__proj)); + } + + template + using remove_copy_result = copy_result<_Iter, _Out>; + + template _Sent, + weakly_incrementable _Out, typename _Tp, typename _Proj = identity> + requires indirectly_copyable<_Iter, _Out> + && indirect_binary_predicate, + const _Tp*> + constexpr remove_copy_result<_Iter, _Out> + remove_copy(_Iter __first, _Sent __last, _Out __result, + const _Tp& __value, _Proj __proj = {}) + { + for (; __first != __last; ++__first) + if (!(std::__invoke(__proj, *__first) == __value)) + { + *__result = *__first; + ++__result; + } + return {std::move(__first), std::move(__result)}; + } + + template + requires indirectly_copyable, _Out> + && indirect_binary_predicate, _Proj>, + const _Tp*> + constexpr remove_copy_result, _Out> + remove_copy(_Range&& __r, _Out __result, + const _Tp& __value, _Proj __proj = {}) + { + return ranges::remove_copy(ranges::begin(__r), ranges::end(__r), + std::move(__result), __value, + std::move(__proj)); + + } + + template _Sent, + typename _Proj = identity, + indirect_equivalence_relation< + projected<_Iter, _Proj>> _Comp = ranges::equal_to> + constexpr subrange<_Iter> + unique(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) + { + __first = ranges::adjacent_find(__first, __last, __comp, __proj); + if (__first == __last) + return {__first, __first}; + + auto __dest = __first; + ++__first; + while (++__first != __last) + if (!(bool)std::__invoke(__comp, + std::__invoke(__proj, *__dest), + std::__invoke(__proj, *__first))) + *++__dest = std::move(*__first); + return {++__dest, __first}; + } + + template, _Proj>> _Comp = ranges::equal_to> + requires permutable> + constexpr safe_subrange_t<_Range> + unique(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::unique(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template + using unique_copy_result = copy_result<_Iter, _Out>; + + template _Sent, + weakly_incrementable _Out, typename _Proj = identity, + indirect_equivalence_relation< + projected<_Iter, _Proj>> _Comp = ranges::equal_to> + requires indirectly_copyable<_Iter, _Out> + && (forward_iterator<_Iter> + || (input_iterator<_Out> + && same_as, iter_value_t<_Out>>) + || indirectly_copyable_storable<_Iter, _Out>) + constexpr unique_copy_result<_Iter, _Out> + unique_copy(_Iter __first, _Sent __last, _Out __result, + _Comp __comp = {}, _Proj __proj = {}) + { + if (__first == __last) + return {std::move(__first), std::move(__result)}; + + // TODO: perform a closer comparison with reference implementations + if constexpr (forward_iterator<_Iter>) + { + auto __next = __first; + *__result = *__next; + while (++__next != __last) + if (!(bool)std::__invoke(__comp, + std::__invoke(__proj, *__first), + std::__invoke(__proj, *__next))) + { + __first = __next; + *++__result = *__first; + } + return {__next, std::move(++__result)}; + } + else if constexpr (input_iterator<_Out> + && same_as, iter_value_t<_Out>>) + { + *__result = *__first; + while (++__first != __last) + if (!(bool)std::__invoke(__comp, + std::__invoke(__proj, *__result), + std::__invoke(__proj, *__first))) + *++__result = *__first; + return {std::move(__first), std::move(++__result)}; + } + else // indirectly_copyable_storable<_Iter, _Out> + { + auto __value = *__first; + *__result = __value; + while (++__first != __last) + { + if (!(bool)std::__invoke(__comp, + std::__invoke(__proj, *__first), + std::__invoke(__proj, __value))) + { + __value = *__first; + *++__result = __value; + } + } + return {std::move(__first), std::move(++__result)}; + } + } + + template, _Proj>> _Comp = ranges::equal_to> + requires indirectly_copyable, _Out> + && (forward_iterator> + || (input_iterator<_Out> + && same_as, iter_value_t<_Out>>) + || indirectly_copyable_storable, _Out>) + constexpr unique_copy_result, _Out> + unique_copy(_Range&& __r, _Out __result, + _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::unique_copy(ranges::begin(__r), ranges::end(__r), + std::move(__result), + std::move(__comp), std::move(__proj)); + } + + template _Sent> + requires permutable<_Iter> + constexpr _Iter + reverse(_Iter __first, _Sent __last) + { + auto __i = ranges::next(__first, __last); + auto __tail = __i; + + if constexpr (random_access_iterator<_Iter>) + { + if (__first != __last) + { + --__tail; + while (__first < __tail) + { + ranges::iter_swap(__first, __tail); + ++__first; + --__tail; + } + } + return __i; + } + else + { + for (;;) + if (__first == __tail || __first == --__tail) + break; + else + { + ranges::iter_swap(__first, __tail); + ++__first; + } + return __i; + } + } + + template + requires permutable> + constexpr safe_iterator_t<_Range> + reverse(_Range&& __r) + { + return ranges::reverse(ranges::begin(__r), ranges::end(__r)); + } + + template + using reverse_copy_result = copy_result<_Iter, _Out>; + + template _Sent, + weakly_incrementable _Out> + requires indirectly_copyable<_Iter, _Out> + constexpr reverse_copy_result<_Iter, _Out> + reverse_copy(_Iter __first, _Sent __last, _Out __result) + { + auto __i = ranges::next(__first, __last); + auto __tail = __i; + while (__first != __tail) + { + --__tail; + *__result = *__tail; + ++__result; + } + return {__i, __result}; + } + + template + requires indirectly_copyable, _Out> + constexpr reverse_copy_result, _Out> + reverse_copy(_Range&& __r, _Out __result) + { + return ranges::reverse_copy(ranges::begin(__r), ranges::end(__r), + std::move(__result)); + } + + template _Sent> + constexpr subrange<_Iter> + rotate(_Iter __first, _Iter __middle, _Sent __last) + { + auto __lasti = ranges::next(__first, __last); + if (__first == __middle) + return {__lasti, __lasti}; + if (__last == __middle) + return {std::move(__first), std::move(__lasti)}; + + if constexpr (random_access_iterator<_Iter>) + { + auto __n = __lasti - __first; + auto __k = __middle - __first; + + if (__k == __n - __k) + { + ranges::swap_ranges(__first, __middle, __middle, __middle + __k); + return {std::move(__middle), std::move(__lasti)}; + } + + auto __p = __first; + auto __ret = __first + (__lasti - __middle); + + for (;;) + { + if (__k < __n - __k) + { + // TODO: is_pod is deprecated, but this condition is + // consistent with the STL implementation. + if constexpr (__is_pod(iter_value_t<_Iter>)) + if (__k == 1) + { + auto __t = std::move(*__p); + ranges::move(__p + 1, __p + __n, __p); + *(__p + __n - 1) = std::move(__t); + return {std::move(__ret), std::move(__lasti)}; + } + auto __q = __p + __k; + for (decltype(__n) __i = 0; __i < __n - __k; ++ __i) + { + ranges::iter_swap(__p, __q); + ++__p; + ++__q; + } + __n %= __k; + if (__n == 0) + return {std::move(__ret), std::move(__lasti)}; + ranges::swap(__n, __k); + __k = __n - __k; + } + else + { + __k = __n - __k; + // TODO: is_pod is deprecated, but this condition is + // consistent with the STL implementation. + if constexpr (__is_pod(iter_value_t<_Iter>)) + if (__k == 1) + { + auto __t = std::move(*(__p + __n - 1)); + ranges::move_backward(__p, __p + __n - 1, __p + __n); + *__p = std::move(__t); + return {std::move(__ret), std::move(__lasti)}; + } + auto __q = __p + __n; + __p = __q - __k; + for (decltype(__n) __i = 0; __i < __n - __k; ++ __i) + { + --__p; + --__q; + ranges::iter_swap(__p, __q); + } + __n %= __k; + if (__n == 0) + return {std::move(__ret), std::move(__lasti)}; + std::swap(__n, __k); + } + } + } + else if constexpr (bidirectional_iterator<_Iter>) + { + auto __tail = __lasti; + + ranges::reverse(__first, __middle); + ranges::reverse(__middle, __tail); + + while (__first != __middle && __middle != __tail) + { + ranges::iter_swap(__first, --__tail); + ++__first; + } + + if (__first == __middle) + { + ranges::reverse(__middle, __tail); + return {std::move(__tail), std::move(__lasti)}; + } + else + { + ranges::reverse(__first, __middle); + return {std::move(__first), std::move(__lasti)}; + } + } + else + { + auto __first2 = __middle; + do + { + ranges::iter_swap(__first, __first2); + ++__first; + ++__first2; + if (__first == __middle) + __middle = __first2; + } while (__first2 != __last); + + auto __ret = __first; + + __first2 = __middle; + + while (__first2 != __last) + { + ranges::iter_swap(__first, __first2); + ++__first; + ++__first2; + if (__first == __middle) + __middle = __first2; + else if (__first2 == __last) + __first2 = __middle; + } + return {std::move(__ret), std::move(__lasti)}; + } + } + + template + requires permutable> + constexpr safe_subrange_t<_Range> + rotate(_Range&& __r, iterator_t<_Range> __middle) + { + return ranges::rotate(ranges::begin(__r), + std::move(__middle), + ranges::end(__r)); + } + + template + using rotate_copy_result = copy_result<_Iter, _Out>; + + template _Sent, + weakly_incrementable _Out> + requires indirectly_copyable<_Iter, _Out> + constexpr rotate_copy_result<_Iter, _Out> + rotate_copy(_Iter __first, _Iter __middle, _Sent __last, _Out __result) + { + auto __copy1 = ranges::copy(__middle, + std::move(__last), + std::move(__result)); + auto __copy2 = ranges::copy(std::move(__first), + std::move(__middle), + std::move(__copy1.out)); + return { std::move(__copy1.in), std::move(__copy2.out) }; + } + + template + requires indirectly_copyable, _Out> + constexpr rotate_copy_result, _Out> + rotate_copy(_Range&& __r, iterator_t<_Range> __middle, _Out __result) + { + return ranges::rotate_copy(ranges::begin(__r), + std::move(__middle), + ranges::end(__r), + std::move(__result)); + } + +#ifdef _GLIBCXX_USE_C99_STDINT_TR1 + template _Sent, + typename _Gen> + requires permutable<_Iter> + && uniform_random_bit_generator> + _Iter + shuffle(_Iter __first, _Sent __last, _Gen&& __g) + { + auto __lasti = ranges::next(__first, __last); + std::shuffle(std::move(__first), __lasti, std::forward<_Gen>(__g)); + return __lasti; + } + + template + requires permutable> + && uniform_random_bit_generator> + safe_iterator_t<_Range> + shuffle(_Range&& __r, _Gen&& __g) + { + return ranges::shuffle(ranges::begin(__r), ranges::end(__r), + std::forward<_Gen>(__g)); + } +#endif + + template _Sent, + typename _Comp = ranges::less, typename _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + constexpr _Iter + push_heap(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) + { + auto __lasti = ranges::next(__first, __last); + std::push_heap(__first, __lasti, + __detail::__make_comp_proj(__comp, __proj)); + return __lasti; + } + + template + requires sortable, _Comp, _Proj> + constexpr safe_iterator_t<_Range> + push_heap(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::push_heap(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Comp = ranges::less, typename _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + constexpr _Iter + pop_heap(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) + { + auto __lasti = ranges::next(__first, __last); + std::pop_heap(__first, __lasti, + __detail::__make_comp_proj(__comp, __proj)); + return __lasti; + } + + template + requires sortable, _Comp, _Proj> + constexpr safe_iterator_t<_Range> + pop_heap(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::pop_heap(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Comp = ranges::less, typename _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + constexpr _Iter + make_heap(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) + { + auto __lasti = ranges::next(__first, __last); + std::make_heap(__first, __lasti, + __detail::__make_comp_proj(__comp, __proj)); + return __lasti; + } + + template + requires sortable, _Comp, _Proj> + constexpr safe_iterator_t<_Range> + make_heap(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::make_heap(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Comp = ranges::less, typename _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + constexpr _Iter + sort_heap(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) + { + auto __lasti = ranges::next(__first, __last); + std::sort_heap(__first, __lasti, + __detail::__make_comp_proj(__comp, __proj)); + return __lasti; + } + + template + requires sortable, _Comp, _Proj> + constexpr safe_iterator_t<_Range> + sort_heap(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::sort_heap(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_strict_weak_order> + _Comp = ranges::less> + constexpr _Iter + is_heap_until(_Iter __first, _Sent __last, + _Comp __comp = {}, _Proj __proj = {}) + { + iter_difference_t<_Iter> __n = ranges::distance(__first, __last); + iter_difference_t<_Iter> __parent = 0, __child = 1; + for (; __child < __n; ++__child) + if (std::__invoke(__comp, + std::__invoke(__proj, *(__first + __parent)), + std::__invoke(__proj, *(__first + __child)))) + return __first + __child; + else if ((__child & 1) == 0) + ++__parent; + + return __first + __n; + } + + template, _Proj>> + _Comp = ranges::less> + constexpr safe_iterator_t<_Range> + is_heap_until(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::is_heap_until(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_strict_weak_order> + _Comp = ranges::less> + constexpr bool + is_heap(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) + { + return (__last + == ranges::is_heap_until(__first, __last, + std::move(__comp), + std::move(__proj))); + } + + template, _Proj>> + _Comp = ranges::less> + constexpr bool + is_heap(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::is_heap(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Comp = ranges::less, typename _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + constexpr _Iter + sort(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) + { + auto __lasti = ranges::next(__first, __last); + std::sort(std::move(__first), __lasti, + __detail::__make_comp_proj(__comp, __proj)); + return __lasti; + } + + template + requires sortable, _Comp, _Proj> + constexpr safe_iterator_t<_Range> + sort(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::sort(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Comp = ranges::less, typename _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _Iter + stable_sort(_Iter __first, _Sent __last, + _Comp __comp = {}, _Proj __proj = {}) + { + auto __lasti = ranges::next(__first, __last); + std::stable_sort(std::move(__first), __lasti, + __detail::__make_comp_proj(__comp, __proj)); + return __lasti; + } + + template + requires sortable, _Comp, _Proj> + safe_iterator_t<_Range> + stable_sort(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::stable_sort(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Comp = ranges::less, typename _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + constexpr _Iter + partial_sort(_Iter __first, _Iter __middle, _Sent __last, + _Comp __comp = {}, _Proj __proj = {}) + { + if (__first == __middle) + return ranges::next(__first, __last); + + ranges::make_heap(__first, __middle, __comp, __proj); + auto __i = __middle; + for (; __i != __last; ++__i) + if (std::__invoke(__comp, + std::__invoke(__proj, *__i), + std::__invoke(__proj, *__first))) + { + ranges::pop_heap(__first, __middle, __comp, __proj); + ranges::iter_swap(__middle-1, __i); + ranges::push_heap(__first, __middle, __comp, __proj); + } + ranges::sort_heap(__first, __middle, __comp, __proj); + + return __i; + } + + template + requires sortable, _Comp, _Proj> + constexpr safe_iterator_t<_Range> + partial_sort(_Range&& __r, iterator_t<_Range> __middle, + _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::partial_sort(ranges::begin(__r), + std::move(__middle), + ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template + using partial_sort_copy_result = copy_result<_Iter, _Out>; + + template _Sent1, + random_access_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Comp = ranges::less, + typename _Proj1 = identity, typename _Proj2 = identity> + requires indirectly_copyable<_Iter1, _Iter2> + && sortable<_Iter2, _Comp, _Proj2> + && indirect_strict_weak_order<_Comp, + projected<_Iter1, _Proj1>, + projected<_Iter2, _Proj2>> + constexpr partial_sort_copy_result<_Iter1, _Iter2> + partial_sort_copy(_Iter1 __first, _Sent1 __last, + _Iter2 __result_first, _Sent2 __result_last, + _Comp __comp = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + if (__result_first == __result_last) + { + // TODO: Eliminating the variable __lasti triggers an ICE. + auto __lasti = ranges::next(std::move(__first), + std::move(__last)); + return {std::move(__lasti), std::move(__result_first)}; + } + + auto __result_real_last = __result_first; + while (__first != __last && __result_real_last != __result_last) + { + *__result_real_last = *__first; + ++__result_real_last; + ++__first; + } + + ranges::make_heap(__result_first, __result_real_last, __comp, __proj2); + for (; __first != __last; ++__first) + if (std::__invoke(__comp, + std::__invoke(__proj1, *__first), + std::__invoke(__proj2, *__result_first))) + { + ranges::pop_heap(__result_first, __result_real_last, + __comp, __proj2); + *(__result_real_last-1) = *__first; + ranges::push_heap(__result_first, __result_real_last, + __comp, __proj2); + } + ranges::sort_heap(__result_first, __result_real_last, __comp, __proj2); + + return {std::move(__first), std::move(__result_real_last)}; + } + + template + requires indirectly_copyable, iterator_t<_Range2>> + && sortable, _Comp, _Proj2> + && indirect_strict_weak_order<_Comp, + projected, _Proj1>, + projected, _Proj2>> + constexpr partial_sort_copy_result, + safe_iterator_t<_Range2>> + partial_sort_copy(_Range1&& __r, _Range2&& __out, _Comp __comp = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::partial_sort_copy(ranges::begin(__r), ranges::end(__r), + ranges::begin(__out), ranges::end(__out), + std::move(__comp), + std::move(__proj1), std::move(__proj2)); + } + + template _Sent, + typename _Proj = identity, + indirect_strict_weak_order> + _Comp = ranges::less> + constexpr _Iter + is_sorted_until(_Iter __first, _Sent __last, + _Comp __comp = {}, _Proj __proj = {}) + { + if (__first == __last) + return __first; + + auto __next = __first; + for (++__next; __next != __last; __first = __next, (void)++__next) + if (std::__invoke(__comp, + std::__invoke(__proj, *__next), + std::__invoke(__proj, *__first))) + return __next; + return __next; + } + + template, _Proj>> + _Comp = ranges::less> + constexpr safe_iterator_t<_Range> + is_sorted_until(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::is_sorted_until(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_strict_weak_order> + _Comp = ranges::less> + constexpr bool + is_sorted(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) + { + if (__first == __last) + return true; + + auto __next = __first; + for (++__next; __next != __last; __first = __next, (void)++__next) + if (std::__invoke(__comp, + std::__invoke(__proj, *__next), + std::__invoke(__proj, *__first))) + return false; + return true; + } + + template, _Proj>> + _Comp = ranges::less> + constexpr bool + is_sorted(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::is_sorted(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Comp = ranges::less, typename _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + constexpr _Iter + nth_element(_Iter __first, _Iter __nth, _Sent __last, + _Comp __comp = {}, _Proj __proj = {}) + { + auto __lasti = ranges::next(__first, __last); + std::nth_element(std::move(__first), std::move(__nth), __lasti, + __detail::__make_comp_proj(__comp, __proj)); + return __lasti; + } + + template + requires sortable, _Comp, _Proj> + constexpr safe_iterator_t<_Range> + nth_element(_Range&& __r, iterator_t<_Range> __nth, + _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::nth_element(ranges::begin(__r), std::move(__nth), + ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Tp, typename _Proj = identity, + indirect_strict_weak_order> + _Comp = ranges::less> + constexpr _Iter + lower_bound(_Iter __first, _Sent __last, + const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) + { + auto __len = ranges::distance(__first, __last); + + while (__len > 0) + { + auto __half = __len / 2; + auto __middle = __first; + ranges::advance(__middle, __half); + if (std::__invoke(__comp, std::__invoke(__proj, *__middle), __value)) + { + __first = __middle; + ++__first; + __len = __len - __half - 1; + } + else + __len = __half; + } + return __first; + } + + template, _Proj>> + _Comp = ranges::less> + constexpr safe_iterator_t<_Range> + lower_bound(_Range&& __r, + const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::lower_bound(ranges::begin(__r), ranges::end(__r), + __value, + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Tp, typename _Proj = identity, + indirect_strict_weak_order> + _Comp = ranges::less> + constexpr _Iter + upper_bound(_Iter __first, _Sent __last, + const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) + { + auto __len = ranges::distance(__first, __last); + + while (__len > 0) + { + auto __half = __len / 2; + auto __middle = __first; + ranges::advance(__middle, __half); + if (std::__invoke(__comp, __value, std::__invoke(__proj, *__middle))) + __len = __half; + else + { + __first = __middle; + ++__first; + __len = __len - __half - 1; + } + } + return __first; + } + + template, _Proj>> + _Comp = ranges::less> + constexpr safe_iterator_t<_Range> + upper_bound(_Range&& __r, + const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::upper_bound(ranges::begin(__r), ranges::end(__r), + __value, + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Tp, typename _Proj = identity, + indirect_strict_weak_order> + _Comp = ranges::less> + constexpr subrange<_Iter> + equal_range(_Iter __first, _Sent __last, + const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) + { + auto __len = ranges::distance(__first, __last); + + while (__len > 0) + { + auto __half = __len / 2; + auto __middle = __first; + ranges::advance(__middle, __half); + if (std::__invoke(__comp, + std::__invoke(__proj, *__middle), + __value)) + { + __first = __middle; + ++__first; + __len = __len - __half - 1; + } + else if (std::__invoke(__comp, + __value, + std::__invoke(__proj, *__middle))) + __len = __half; + else + { + auto __left + = ranges::lower_bound(__first, __middle, + __value, __comp, __proj); + ranges::advance(__first, __len); + auto __right + = ranges::upper_bound(++__middle, __first, + __value, __comp, __proj); + return {__left, __right}; + } + } + return {__first, __first}; + } + + template, _Proj>> + _Comp = ranges::less> + constexpr safe_subrange_t<_Range> + equal_range(_Range&& __r, const _Tp& __value, + _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::equal_range(ranges::begin(__r), ranges::end(__r), + __value, + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Tp, typename _Proj = identity, + indirect_strict_weak_order> + _Comp = ranges::less> + constexpr bool + binary_search(_Iter __first, _Sent __last, + const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) + { + auto __i = ranges::lower_bound(__first, __last, __value, __comp, __proj); + if (__i == __last) + return false; + return !(bool)std::__invoke(__comp, __value, std::__invoke(__proj, *__i)); + } + + template, _Proj>> + _Comp = ranges::less> + constexpr bool + binary_search(_Range&& __r, const _Tp& __value, _Comp __comp = {}, + _Proj __proj = {}) + { + return ranges::binary_search(ranges::begin(__r), ranges::end(__r), + __value, + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr bool + is_partitioned(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) + { + __first = ranges::find_if_not(std::move(__first), __last, __pred, __proj); + if (__first == __last) + return true; + ++__first; + return ranges::none_of(std::move(__first), std::move(__last), + std::move(__pred), std::move(__proj)); + } + + template, _Proj>> _Pred> + constexpr bool + is_partitioned(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return ranges::is_partitioned(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr subrange<_Iter> + partition(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) + { + if constexpr (bidirectional_iterator<_Iter>) + { + auto __lasti = ranges::next(__first, __last); + auto __tail = __lasti; + for (;;) + { + for (;;) + if (__first == __tail) + return {std::move(__first), std::move(__lasti)}; + else if (std::__invoke(__pred, std::__invoke(__proj, *__first))) + ++__first; + else + break; + --__tail; + for (;;) + if (__first == __tail) + return {std::move(__first), std::move(__lasti)}; + else if (!(bool)std::__invoke(__pred, + std::__invoke(__proj, *__tail))) + --__tail; + else + break; + ranges::iter_swap(__first, __tail); + ++__first; + } + } + else + { + if (__first == __last) + return {std::move(__first), std::move(__first)}; + + while (std::__invoke(__pred, std::__invoke(__proj, *__first))) + if (++__first == __last) + return {std::move(__first), std::move(__first)}; + + auto __next = __first; + while (++__next != __last) + if (std::__invoke(__pred, std::__invoke(__proj, *__next))) + { + ranges::iter_swap(__first, __next); + ++__first; + } + + return {std::move(__first), std::move(__next)}; + } + } + + template, _Proj>> _Pred> + requires permutable> + constexpr safe_subrange_t<_Range> + partition(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return ranges::partition(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + requires permutable<_Iter> + subrange<_Iter> + stable_partition(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) + { + auto __lasti = ranges::next(__first, __last); + auto __middle + = std::stable_partition(std::move(__first), __lasti, + __detail::__make_pred_proj(__pred, __proj)); + return {std::move(__middle), std::move(__lasti)}; + } + + template, _Proj>> _Pred> + requires permutable> + safe_subrange_t<_Range> + stable_partition(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return ranges::stable_partition(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template + struct partition_copy_result + { + [[no_unique_address]] _Iter in; + [[no_unique_address]] _Out1 out1; + [[no_unique_address]] _O2 out2; + + template + requires convertible_to + && convertible_to + && convertible_to + operator partition_copy_result<_IIter, _OOut1, _OOut2>() const & + { return {in, out1, out2}; } + + template + requires convertible_to<_Iter, _IIter> + && convertible_to<_Out1, _OOut1> + && convertible_to<_O2, _OOut2> + operator partition_copy_result<_IIter, _OOut1, _OOut2>() && + { return {std::move(in), std::move(out1), std::move(out2)}; } + }; + + template _Sent, + weakly_incrementable _Out1, weakly_incrementable _O2, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + requires indirectly_copyable<_Iter, _Out1> + && indirectly_copyable<_Iter, _O2> + constexpr partition_copy_result<_Iter, _Out1, _O2> + partition_copy(_Iter __first, _Sent __last, + _Out1 __out_true, _O2 __out_false, + _Pred __pred, _Proj __proj = {}) + { + for (; __first != __last; ++__first) + if (std::__invoke(__pred, std::__invoke(__proj, *__first))) + { + *__out_true = *__first; + ++__out_true; + } + else + { + *__out_false = *__first; + ++__out_false; + } + + return {std::move(__first), std::move(__out_true), std::move(__out_false)}; + } + + template, _Proj>> _Pred> + requires indirectly_copyable, _Out1> + && indirectly_copyable, _O2> + constexpr partition_copy_result, _Out1, _O2> + partition_copy(_Range&& __r, _Out1 out_true, _O2 out_false, + _Pred __pred, _Proj __proj = {}) + { + return ranges::partition_copy(ranges::begin(__r), ranges::end(__r), + std::move(out_true), std::move(out_false), + std::move(__pred), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr _Iter + partition_point(_Iter __first, _Sent __last, + _Pred __pred, _Proj __proj = {}) + { + auto __len = ranges::distance(__first, __last); + + while (__len > 0) + { + auto __half = __len / 2; + auto __middle = __first; + ranges::advance(__middle, __half); + if (std::__invoke(__pred, std::__invoke(__proj, *__middle))) + { + __first = __middle; + ++__first; + __len = __len - __half - 1; + } + else + __len = __half; + } + return __first; + } + + template, _Proj>> _Pred> + constexpr safe_iterator_t<_Range> + partition_point(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return ranges::partition_point(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template + using merge_result = binary_transform_result<_Iter1, _Iter2, _Out>; + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + weakly_incrementable _Out, typename _Comp = ranges::less, + typename _Proj1 = identity, typename _Proj2 = identity> + requires mergeable<_Iter1, _Iter2, _Out, _Comp, _Proj1, _Proj2> + constexpr merge_result<_Iter1, _Iter2, _Out> + merge(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, _Out __result, + _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + while (__first1 != __last1 && __first2 != __last2) + { + if (std::__invoke(__comp, + std::__invoke(__proj2, *__first2), + std::__invoke(__proj1, *__first1))) + { + *__result = *__first2; + ++__first2; + } + else + { + *__result = *__first1; + ++__first1; + } + ++__result; + } + auto __copy1 = ranges::copy(std::move(__first1), std::move(__last1), + std::move(__result)); + auto __copy2 = ranges::copy(std::move(__first2), std::move(__last2), + std::move(__copy1.out)); + return { std::move(__copy1.in), std::move(__copy2.in), + std::move(__copy2.out) }; + } + + template + requires mergeable, iterator_t<_Range2>, _Out, + _Comp, _Proj1, _Proj2> + constexpr merge_result, + safe_iterator_t<_Range2>, + _Out> + merge(_Range1&& __r1, _Range2&& __r2, _Out __result, + _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::merge(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__result), std::move(__comp), + std::move(__proj1), std::move(__proj2)); + } + + template _Sent, + typename _Comp = ranges::less, + typename _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + _Iter + inplace_merge(_Iter __first, _Iter __middle, _Sent __last, + _Comp __comp = {}, _Proj __proj = {}) + { + auto __lasti = ranges::next(__first, __last); + std::inplace_merge(std::move(__first), std::move(__middle), __lasti, + __detail::__make_comp_proj(__comp, __proj)); + return __lasti; + } + + template + requires sortable, _Comp, _Proj> + safe_iterator_t<_Range> + inplace_merge(_Range&& __r, iterator_t<_Range> __middle, + _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::inplace_merge(ranges::begin(__r), std::move(__middle), + ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Proj1 = identity, typename _Proj2 = identity, + indirect_strict_weak_order, + projected<_Iter2, _Proj2>> + _Comp = ranges::less> + constexpr bool + includes(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, + _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + while (__first1 != __last1 && __first2 != __last2) + if (std::__invoke(__comp, + std::__invoke(__proj2, *__first2), + std::__invoke(__proj1, *__first1))) + return false; + else if (std::__invoke(__comp, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + ++__first1; + else + { + ++__first1; + ++__first2; + } + + return __first2 == __last2; + } + + template, _Proj1>, + projected, _Proj2>> + _Comp = ranges::less> + constexpr bool + includes(_Range1&& __r1, _Range2&& __r2, _Comp __comp = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::includes(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__comp), + std::move(__proj1), std::move(__proj2)); + } + + template + using set_union_result = binary_transform_result<_Iter1, _Iter2, _Out>; + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + weakly_incrementable _Out, typename _Comp = ranges::less, + typename _Proj1 = identity, typename _Proj2 = identity> + requires mergeable<_Iter1, _Iter2, _Out, _Comp, _Proj1, _Proj2> + constexpr set_union_result<_Iter1, _Iter2, _Out> + set_union(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, + _Out __result, _Comp __comp = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + while (__first1 != __last1 && __first2 != __last2) + { + if (std::__invoke(__comp, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + { + *__result = *__first1; + ++__first1; + } + else if (std::__invoke(__comp, + std::__invoke(__proj2, *__first2), + std::__invoke(__proj1, *__first1))) + { + *__result = *__first2; + ++__first2; + } + else + { + *__result = *__first1; + ++__first1; + ++__first2; + } + ++__result; + } + auto __copy1 = ranges::copy(std::move(__first1), std::move(__last1), + std::move(__result)); + auto __copy2 = ranges::copy(std::move(__first2), std::move(__last2), + std::move(__copy1.out)); + return {std::move(__copy1.in), std::move(__copy2.in), + std::move(__copy2.out)}; + } + + template + requires mergeable, iterator_t<_Range2>, _Out, + _Comp, _Proj1, _Proj2> + constexpr set_union_result, + safe_iterator_t<_Range2>, _Out> + set_union(_Range1&& __r1, _Range2&& __r2, _Out __result, _Comp __comp = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::set_union(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__result), std::move(__comp), + std::move(__proj1), std::move(__proj2)); + } + + template + using set_intersection_result = binary_transform_result<_Iter1, _Iter2, _Out>; + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + weakly_incrementable _Out, typename _Comp = ranges::less, + typename _Proj1 = identity, typename _Proj2 = identity> + requires mergeable<_Iter1, _Iter2, _Out, _Comp, _Proj1, _Proj2> + constexpr set_intersection_result<_Iter1, _Iter2, _Out> + set_intersection(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, _Out __result, + _Comp __comp = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + while (__first1 != __last1 && __first2 != __last2) + if (std::__invoke(__comp, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + ++__first1; + else if (std::__invoke(__comp, + std::__invoke(__proj2, *__first2), + std::__invoke(__proj1, *__first1))) + ++__first2; + else + { + *__result = *__first1; + ++__first1; + ++__first2; + ++__result; + } + // TODO: Eliminating these variables triggers an ICE. + auto __last1i = ranges::next(std::move(__first1), std::move(__last1)); + auto __last2i = ranges::next(std::move(__first2), std::move(__last2)); + return {std::move(__last1i), std::move(__last2i), std::move(__result)}; + } + + template + requires mergeable, iterator_t<_Range2>, _Out, + _Comp, _Proj1, _Proj2> + constexpr set_intersection_result, + safe_iterator_t<_Range2>, _Out> + set_intersection(_Range1&& __r1, _Range2&& __r2, _Out __result, + _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::set_intersection(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__result), std::move(__comp), + std::move(__proj1), std::move(__proj2)); + } + + template + using set_difference_result = copy_result<_Iter, _Out>; + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + weakly_incrementable _Out, typename _Comp = ranges::less, + typename _Proj1 = identity, typename _Proj2 = identity> + requires mergeable<_Iter1, _Iter2, _Out, _Comp, _Proj1, _Proj2> + constexpr set_difference_result<_Iter1, _Out> + set_difference(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, _Out __result, + _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + while (__first1 != __last1 && __first2 != __last2) + if (std::__invoke(__comp, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + { + *__result = *__first1; + ++__first1; + ++__result; + } + else if (std::__invoke(__comp, + std::__invoke(__proj2, *__first2), + std::__invoke(__proj1, *__first1))) + ++__first2; + else + { + ++__first1; + ++__first2; + } + return ranges::copy(std::move(__first1), std::move(__last1), + std::move(__result)); + } + + template + requires mergeable, iterator_t<_Range2>, _Out, + _Comp, _Proj1, _Proj2> + constexpr set_difference_result, _Out> + set_difference(_Range1&& __r1, _Range2&& __r2, _Out __result, + _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return ranges::set_difference(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__result), std::move(__comp), + std::move(__proj1), std::move(__proj2)); + } + + template + using set_symmetric_difference_result + = binary_transform_result<_Iter1, _Iter2, _Out>; + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + weakly_incrementable _Out, typename _Comp = ranges::less, + typename _Proj1 = identity, typename _Proj2 = identity> + requires mergeable<_Iter1, _Iter2, _Out, _Comp, _Proj1, _Proj2> + constexpr set_symmetric_difference_result<_Iter1, _Iter2, _Out> + set_symmetric_difference(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, + _Out __result, _Comp __comp = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + while (__first1 != __last1 && __first2 != __last2) + if (std::__invoke(__comp, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + { + *__result = *__first1; + ++__first1; + ++__result; + } + else if (std::__invoke(__comp, + std::__invoke(__proj2, *__first2), + std::__invoke(__proj1, *__first1))) + { + *__result = *__first2; + ++__first2; + ++__result; + } + else + { + ++__first1; + ++__first2; + } + auto __copy1 = ranges::copy(std::move(__first1), std::move(__last1), + std::move(__result)); + auto __copy2 = ranges::copy(std::move(__first2), std::move(__last2), + std::move(__copy1.out)); + return {std::move(__copy1.in), std::move(__copy2.in), + std::move(__copy2.out)}; + } + + template + requires mergeable, iterator_t<_Range2>, _Out, + _Comp, _Proj1, _Proj2> + constexpr set_symmetric_difference_result, + safe_iterator_t<_Range2>, + _Out> + set_symmetric_difference(_Range1&& __r1, _Range2&& __r2, _Out __result, + _Comp __comp = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return (ranges::set_symmetric_difference + (ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__result), std::move(__comp), + std::move(__proj1), std::move(__proj2))); + } + + template> + _Comp = ranges::less> + constexpr const _Tp& + min(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {}) + { + if (std::__invoke(std::move(__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> + min(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + 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 + min(initializer_list<_Tp> __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::min(ranges::subrange(__r), + std::move(__comp), std::move(__proj)); + } + + template> + _Comp = ranges::less> + constexpr const _Tp& + max(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {}) + { + if (std::__invoke(std::move(__comp), + std::__invoke(__proj, __a), + std::__invoke(__proj, __b))) + return __b; + else + return __a; + } + + template, _Proj>> + _Comp = ranges::less> + requires indirectly_copyable_storable, + range_value_t<_Range>*> + constexpr range_value_t<_Range> + max(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + 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, __result), + std::__invoke(__proj, __tmp))) + __result = std::move(__tmp); + } + return __result; + } + + template> + _Comp = ranges::less> + constexpr _Tp + max(initializer_list<_Tp> __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::max(ranges::subrange(__r), + std::move(__comp), std::move(__proj)); + } + + template + struct minmax_result + { + [[no_unique_address]] _Tp min; + [[no_unique_address]] _Tp max; + + template + requires convertible_to + operator minmax_result<_Tp2>() const & + { return {min, max}; } + + template + requires convertible_to<_Tp, _Tp2> + operator minmax_result<_Tp2>() && + { return {std::move(min), std::move(max)}; } + }; + + template> + _Comp = ranges::less> + constexpr minmax_result + minmax(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {}) + { + if (std::__invoke(std::move(__comp), + std::__invoke(__proj, __b), + std::__invoke(__proj, __a))) + return {__b, __a}; + else + return {__a, __b}; + } + + template, _Proj>> + _Comp = ranges::less> + requires indirectly_copyable_storable, + range_value_t<_Range>*> + constexpr minmax_result> + minmax(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + auto __first = ranges::begin(__r); + auto __last = ranges::end(__r); + __glibcxx_assert(__first != __last); + minmax_result> __result = {*__first, *__first}; + while (++__first != __last) + { + auto __tmp = *__first; + if (std::__invoke(__comp, + std::__invoke(__proj, __tmp), + std::__invoke(__proj, __result.min))) + __result.min = std::move(__tmp); + if (!(bool)std::__invoke(__comp, + std::__invoke(__proj, __tmp), + std::__invoke(__proj, __result.max))) + __result.max = std::move(__tmp); + } + return __result; + } + + template> + _Comp = ranges::less> + constexpr minmax_result<_Tp> + minmax(initializer_list<_Tp> __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::minmax(ranges::subrange(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_strict_weak_order> + _Comp = ranges::less> + constexpr _Iter + min_element(_Iter __first, _Sent __last, + _Comp __comp = {}, _Proj __proj = {}) + { + if (__first == __last) + return __first; + + auto __i = __first; + while (++__i != __last) + { + if (std::__invoke(__comp, + std::__invoke(__proj, *__i), + std::__invoke(__proj, *__first))) + __first = __i; + } + return __first; + } + + template, _Proj>> + _Comp = ranges::less> + constexpr safe_iterator_t<_Range> + min_element(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::min_element(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_strict_weak_order> + _Comp = ranges::less> + constexpr _Iter + max_element(_Iter __first, _Sent __last, + _Comp __comp = {}, _Proj __proj = {}) + { + if (__first == __last) + return __first; + + auto __i = __first; + while (++__i != __last) + { + if (std::__invoke(__comp, + std::__invoke(__proj, *__first), + std::__invoke(__proj, *__i))) + __first = __i; + } + return __first; + } + + template, _Proj>> + _Comp = ranges::less> + constexpr safe_iterator_t<_Range> + max_element(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::max_element(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template + using minmax_element_result = minmax_result<_Iter>; + + template _Sent, + typename _Proj = identity, + indirect_strict_weak_order> + _Comp = ranges::less> + constexpr minmax_element_result<_Iter> + minmax_element(_Iter __first, _Sent __last, + _Comp __comp = {}, _Proj __proj = {}) + { + if (__first == __last) + return {__first, __first}; + + minmax_element_result<_Iter> __result = {__first, __first}; + auto __i = __first; + while (++__i != __last) + { + if (std::__invoke(__comp, + std::__invoke(__proj, *__i), + std::__invoke(__proj, *__result.min))) + __result.min = __i; + if (!(bool)std::__invoke(__comp, + std::__invoke(__proj, *__i), + std::__invoke(__proj, *__result.max))) + __result.max = __i; + } + return __result; + } + + template, _Proj>> + _Comp = ranges::less> + constexpr minmax_element_result> + minmax_element(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::minmax_element(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Proj1, typename _Proj2, + indirect_strict_weak_order, + projected<_Iter2, _Proj2>> _Comp> + constexpr bool + __lexicographical_compare(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, + _Comp __comp, _Proj1 __proj1, _Proj2 __proj2) + { + constexpr bool __sized_iters + = (sized_sentinel_for<_Sent1, _Iter1> + && sized_sentinel_for<_Sent2, _Iter2>); + if constexpr (__sized_iters) + { + auto __d1 = ranges::distance(__first1, __last1); + auto __d2 = ranges::distance(__first2, __last2); + + using _ValueType1 = iter_value_t<_Iter1>; + using _ValueType2 = iter_value_t<_Iter2>; + constexpr bool __use_memcmp + = ((is_integral_v<_ValueType1> || is_pointer_v<_ValueType1>) + && is_same_v<_ValueType1, _ValueType2> + && is_pointer_v<_Iter1> + && is_pointer_v<_Iter2> + && (is_same_v<_Comp, ranges::less> + || is_same_v<_Comp, ranges::greater>) + && is_same_v<_Proj1, identity> + && is_same_v<_Proj2, identity>); + if constexpr (__use_memcmp) + { + if (const auto __len = std::min(__d1, __d2)) + { + const auto __c = std::__memcmp(__first1, __first2, __len); + if constexpr (is_same_v<_Comp, ranges::less>) + { + if (__c < 0) + return true; + if (__c > 0) + return false; + } + else if constexpr (is_same_v<_Comp, ranges::greater>) + { + if (__c > 0) + return true; + if (__c < 0) + return false; + } + else + __builtin_unreachable(); + } + return (__last1 - __first1 < __last2 - __first2); + } + } + + for (; __first1 != __last1 && __first2 != __last2; + ++__first1, (void) ++__first2) + { + if (std::__invoke(__comp, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + return true; + if (std::__invoke(__comp, + std::__invoke(__proj2, *__first2), + std::__invoke(__proj1, *__first1))) + return false; + } + return __first1 == __last1 && __first2 != __last2; + } + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Proj1 = identity, typename _Proj2 = identity, + indirect_strict_weak_order, + projected<_Iter2, _Proj2>> + _Comp = ranges::less> + constexpr bool + lexicographical_compare(_Iter1 __first1, _Sent1 __last1, + _Iter2 __first2, _Sent2 __last2, + _Comp __comp = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return (ranges::__lexicographical_compare + (std::__niter_base(std::move(__first1)), + std::__niter_base(std::move(__last1)), + std::__niter_base(std::move(__first2)), + std::__niter_base(std::move(__last2)), + std::move(__comp), + std::move(__proj1), std::move(__proj2))); + } + + template, _Proj1>, + projected, _Proj2>> + _Comp = ranges::less> + constexpr bool + lexicographical_compare(_Range1&& __r1, _Range2&& __r2, _Comp __comp = {}, + _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + return (ranges::lexicographical_compare + (ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2), + std::move(__comp), + std::move(__proj1), std::move(__proj2))); + } + + template + struct next_permutation_result + { + bool found; + _Iter in; + }; + + template _Sent, + typename _Comp = ranges::less, typename _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + constexpr next_permutation_result<_Iter> + next_permutation(_Iter __first, _Sent __last, + _Comp __comp = {}, _Proj __proj = {}) + { + if (__first == __last) + return {false, std::move(__first)}; + + auto __i = __first; + ++__i; + if (__i == __last) + return {false, std::move(__i)}; + + auto __lasti = ranges::next(__first, __last); + __i = __lasti; + --__i; + + for (;;) + { + auto __ii = __i; + --__i; + if (std::__invoke(__comp, + std::__invoke(__proj, *__i), + std::__invoke(__proj, *__ii))) + { + auto __j = __lasti; + while (!(bool)std::__invoke(__comp, + std::__invoke(__proj, *__i), + std::__invoke(__proj, *--__j))) + ; + ranges::iter_swap(__i, __j); + ranges::reverse(__ii, __last); + return {true, std::move(__lasti)}; + } + if (__i == __first) + { + ranges::reverse(__first, __last); + return {false, std::move(__lasti)}; + } + } + } + + template + requires sortable, _Comp, _Proj> + constexpr next_permutation_result> + next_permutation(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::next_permutation(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + + template + using prev_permutation_result = next_permutation_result<_Iter>; + + template _Sent, + typename _Comp = ranges::less, typename _Proj = identity> + requires sortable<_Iter, _Comp, _Proj> + constexpr prev_permutation_result<_Iter> + prev_permutation(_Iter __first, _Sent __last, + _Comp __comp = {}, _Proj __proj = {}) + { + if (__first == __last) + return {false, std::move(__first)}; + + auto __i = __first; + ++__i; + if (__i == __last) + return {false, std::move(__i)}; + + auto __lasti = ranges::next(__first, __last); + __i = __lasti; + --__i; + + for (;;) + { + auto __ii = __i; + --__i; + if (std::__invoke(__comp, + std::__invoke(__proj, *__ii), + std::__invoke(__proj, *__i))) + { + auto __j = __lasti; + while (!(bool)std::__invoke(__comp, + std::__invoke(__proj, *--__j), + std::__invoke(__proj, *__i))) + ; + ranges::iter_swap(__i, __j); + ranges::reverse(__ii, __last); + return {true, std::move(__lasti)}; + } + if (__i == __first) + { + ranges::reverse(__first, __last); + return {false, std::move(__lasti)}; + } + } + } + + template + requires sortable, _Comp, _Proj> + constexpr prev_permutation_result> + prev_permutation(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) + { + return ranges::prev_permutation(ranges::begin(__r), ranges::end(__r), + std::move(__comp), std::move(__proj)); + } + +} // namespace ranges +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std +#endif // concepts +#endif // C++20 +#endif // _RANGES_ALGO_H diff --git a/libstdc++-v3/include/std/algorithm b/libstdc++-v3/include/std/algorithm index e3d34024b73..4b956b89403 100644 --- a/libstdc++-v3/include/std/algorithm +++ b/libstdc++-v3/include/std/algorithm @@ -60,6 +60,9 @@ #include // UK-300. #include #include +#if __cplusplus > 201703L +# include +#endif #if __cplusplus > 201402L // Parallel STL algorithms diff --git a/libstdc++-v3/testsuite/25_algorithms/adjacent_find/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/adjacent_find/constrained.cc new file mode 100644 index 00000000000..d56ac5a19db --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/adjacent_find/constrained.cc @@ -0,0 +1,68 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + X x[] = { {2}, {2}, {6}, {8}, {10}, {11} }; + int y[] = { 2, 7, 8, 8, 9 }; + + VERIFY( ranges::adjacent_find(x, x+6, {}, &X::i) == x+0 ); + VERIFY( ranges::adjacent_find(x+1, x+6, {}, &X::i) == x+6 ); + VERIFY( ranges::adjacent_find(y) == y+2 ); + VERIFY( ranges::adjacent_find(y, y+4) == y+2 ); + + test_container c(x); + VERIFY( ranges::adjacent_find(c, {}, &X::i) == ranges::begin(c) ); + + test_range r(y); + auto res = ranges::adjacent_find(r); + VERIFY( *res == 8 && *++res == 8 ); +} + +void +test02() +{ + static constexpr X x[] = { {2}, {2}, {6}, {8}, {10}, {11} }; + static constexpr X y[] = { {2}, {6}, {8}, {10}, {11} }; + static_assert(ranges::adjacent_find(x, {}, &X::i) == x+0); + static_assert(ranges::adjacent_find(y, {}, &X::i) == y+5); +} + +int +main() +{ + test01(); + test02(); +} + diff --git a/libstdc++-v3/testsuite/25_algorithms/all_of/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/all_of/constrained.cc new file mode 100644 index 00000000000..a472dd0750a --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/all_of/constrained.cc @@ -0,0 +1,90 @@ +// Copyright (C) 2019 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +struct XLess +{ + int val; + bool operator()(X& x) const { return x.i < val; } +}; + +struct ILess +{ + int val; + bool operator()(int& i) const { return i < val; } +}; + +template +struct NotZero +{ + bool operator()(T& t) const { return t != 0; } +}; + +void +test01() +{ + X x[] = { {2}, {4}, {6}, {8}, {10}, {11} }; + + VERIFY( ranges::all_of(x, x+5, XLess{11}) ); + VERIFY( ranges::all_of(x, x+5, ILess{11}, &X::i) ); + VERIFY( !ranges::all_of(x, x+6, ILess{11}, &X::i) ); + VERIFY( !ranges::all_of(x, XLess{11}) ); + VERIFY( ranges::all_of(x, XLess{12}) ); + VERIFY( ranges::all_of(x, ILess{12}, &X::i) ); + VERIFY( !ranges::all_of(x, ILess{11}, &X::i) ); + + test_container c(x); + VERIFY( ranges::all_of(c, NotZero{}, &X::i) ); + + test_range r(x); + VERIFY( ranges::all_of(r, NotZero{}, &X::i) ); + + r.bounds.first = x; + VERIFY( ranges::all_of(r, NotZero{}, [](X& x) { return &x; }) ); +} + +struct Y { int i; int j; }; + +void +test02() +{ + static constexpr Y y[] = { {1,2}, {2,4}, {3,6} }; + static_assert(ranges::all_of(y, [](int j) { return j%2 == 0; }, &Y::j)); + static_assert(ranges::all_of(y, [](const Y& y) { return y.j == y.i * 2; })); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/any_of/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/any_of/constrained.cc new file mode 100644 index 00000000000..b234692d2c7 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/any_of/constrained.cc @@ -0,0 +1,88 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +struct XLess +{ + int val; + bool operator()(X& x) const { return x.i < val; } +}; + +struct ILess +{ + int val; + bool operator()(int& i) const { return i < val; } +}; + +template +struct NotZero +{ + bool operator()(T& t) const { return t != 0; } +}; + +void +test01() +{ + X x[] = { {2}, {4}, {6}, {8}, {10}, {11} }; + + VERIFY( ranges::any_of(x, x+6, XLess{3}) ); + VERIFY( ranges::any_of(x, x+6, ILess{3}, &X::i) ); + VERIFY( !ranges::any_of(x+1, x+6, XLess{3}) ); + VERIFY( !ranges::any_of(x+1, x+6, ILess{3}, &X::i) ); + VERIFY( ranges::any_of(x, XLess{5}) ); + VERIFY( ranges::any_of(x, ILess{5}, &X::i) ); + + test_container c(x); + VERIFY( ranges::any_of(c, NotZero{}, &X::i) ); + + test_range r(x); + VERIFY( ranges::any_of(r, NotZero{}, &X::i) ); + VERIFY( ranges::any_of(r, NotZero{}, [](X& x) { return &x; }) ); +} + +struct Y { int i; int j; }; + +void +test02() +{ + static constexpr Y y[] = { {1,2}, {2,4}, {3,6} }; + static_assert(ranges::any_of(y, [](int i) { return i%2 == 0; }, &Y::i)); + static_assert(ranges::any_of(y, [](const Y& y) { return y.i + y.j == 3; })); + static_assert(!ranges::any_of(y, [](const Y& y) { return y.i == y.j; })); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/binary_search/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/binary_search/constrained.cc new file mode 100644 index 00000000000..42aaa8ef2f7 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/binary_search/constrained.cc @@ -0,0 +1,61 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + float x[] = {1, 2, 3, 4, 5, 5, 6, 7}; + test_container cx(x); + for (int i = 0; i < 7; i++) + { + VERIFY( ranges::binary_search(cx, i, {}, [] (int a) { return a-1; }) ); + VERIFY( !ranges::binary_search(cx.begin(), cx.end(), i+0.5) ); + } + VERIFY( !ranges::binary_search(cx, 0) ); + + ranges::reverse(x); + test_range rx(x); + VERIFY( ranges::binary_search(rx, 5, ranges::greater{}) ); +} + +constexpr bool +test02() +{ + int x[] = {1, 2, 3}; + return (ranges::binary_search(x, 3) + && !ranges::binary_search(x, x, 3)); +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/copy/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/copy/constrained.cc new file mode 100644 index 00000000000..85f7d649608 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy/constrained.cc @@ -0,0 +1,225 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + { + int x[7] = { 1, 2, 3, 4, 5, 6, 7 }; + int y[7] = { 0 }; + int z[7] = { 1, 2, 3, 4, 5, 6, 7 }; + auto [in, out] = ranges::copy(x, y); + VERIFY( ranges::equal(x, y) && in == x+7 && out == y+7 ); + VERIFY( ranges::equal(x, z) ); + } + + { + int x[3] = { 1, 2, 3 }; + char y[4] = { 0 }; + int z[3] = { 1, 2, 3 }; + test_container cx(x); + test_container cy(y); + auto [in, out] = ranges::copy(cx, ranges::begin(cy)); + VERIFY( ranges::equal(x, x+3, y, y+3) && in.ptr == x+3 && out.ptr == y+3 ); + VERIFY( ranges::equal(x, z) ); + } + + { + char x[3] = { 1, 2, 3 }; + int y[4] = { 0 }; + int z[3] = { 1, 2, 3 }; + test_range rx(x); + test_range ry(y); + auto [in, out] = ranges::copy(rx, ranges::begin(ry)); + VERIFY( ranges::equal(x, x+3, y, y+3) && in.ptr == x+3 && out.ptr == y+3 ); + VERIFY( ranges::equal(x, z) ); + } + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in, out] = ranges::copy(x, ranges::begin(y)); + VERIFY( in.base() == x.data()+3 ); + VERIFY( out.base() == y.data()+3 ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } + + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in, out] = ranges::copy(x, ranges::begin(y)); + VERIFY( in.base() == x.data()+3 ); + VERIFY( out.base() == y.data()+3 ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in,out] = ranges::copy(make_reverse_iterator(x.end()), + make_reverse_iterator(x.begin()), + make_reverse_iterator(y.end())); + VERIFY( in.base().base() == x.data()+3 ); + VERIFY( out.base().base() == y.data() ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in,out] = ranges::copy(make_reverse_iterator(x.end()), + make_reverse_iterator(x.begin()), + make_reverse_iterator(y.end())); + VERIFY( in.base().base() == x.data()+3 ); + VERIFY( out.base().base() == y.data() ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } +} + +struct X +{ + int i; + constexpr X (int a) : i(a) { } +}; + +void +test02() +{ + int x[] = { {2}, {2}, {6}, {8}, {10} }; + X y[] = { {2}, {6}, {8}, {10}, {11}, {2} }; + int z[] = { {2}, {2}, {6}, {8}, {10} }; + auto [in, out] = ranges::copy(x, y); + VERIFY( ranges::equal(x, x+5, y, y+5, {}, {}, &X::i) ); + VERIFY( in == x+5 ); + VERIFY( out == y+5 ); + VERIFY( y[5].i == 2 ); + VERIFY( ranges::equal(x, z) ); +} + +constexpr bool +test03() +{ + bool ok = true; + int x[] = { {2}, {2}, {6}, {8}, {10} }; + X y[] = { {2}, {6}, {8}, {10}, {11}, {2} }; + int z[] = { {2}, {2}, {6}, {8}, {10} }; + auto [in, out] = ranges::copy(x, y); + ok &= ranges::equal(x, x+5, y, y+5, {}, {}, &X::i); + ok &= (in == x+5); + ok &= (out == y+5); + ok &= (y[5].i == 2); + ok &= ranges::equal(x, z); + return ok; +} + +struct Y +{ + int i; + int moved = 0; + + constexpr Y(int a) : i(a) { } + + constexpr Y(const Y&) = delete; + constexpr Y& operator=(const Y&) = delete; + + constexpr Y(Y&& other) + { + *this = std::move(other); + } + + constexpr Y& + operator=(Y&& other) + { + other.moved++; + i = other.i; + return *this; + } + + friend constexpr bool + operator==(const Y& a, const Y& b) + { return a.i == b.i; } +}; + +void +test04() +{ + Y x[7] = { 1, 2, 3, 4, 5, 6, 7 }; + Y y[7] = { 0, 0, 0, 0, 0, 0, 0 }; + Y z[7] = { 1, 2, 3, 4, 5, 6, 7 }; + test_range rx(x); + auto [in, out] = ranges::copy(std::move_iterator{ranges::begin(rx)}, + std::move_sentinel{ranges::end(rx)}, + ranges::begin(y)); + VERIFY( ranges::equal(x, y) && std::move(in).base().ptr == x+7 && out == y+7 ); + VERIFY( ranges::equal(x, z) ); + for (const auto& v : x) + VERIFY( v.moved == 1 ); + for (const auto& v : y) + VERIFY( v.moved == 0 ); +} + +constexpr bool +test05() +{ + bool ok = true; + Y x[7] = { 1, 2, 3, 4, 5, 6, 7 }; + Y y[7] = { 0, 0, 0, 0, 0, 0, 0 }; + Y z[7] = { 1, 2, 3, 4, 5, 6, 7 }; + auto [in, out] = ranges::copy(std::move_iterator{ranges::begin(x)}, + std::move_sentinel{ranges::end(x)}, + ranges::begin(y)); + ok &= ranges::equal(x, y); + ok &= in.base() == x+7; + ok &= out == y+7; + ok &= ranges::equal(x, z); + for (const auto& v : x) + ok &= v.moved == 1; + for (const auto& v : y) + ok &= v.moved == 0; + return ok; +} + +int +main() +{ + test01(); + test02(); + static_assert(test03()); + test04(); + static_assert(test05()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_backward/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/copy_backward/constrained.cc new file mode 100644 index 00000000000..900f78aaa73 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy_backward/constrained.cc @@ -0,0 +1,193 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + { + int x[7] = { 1, 2, 3, 4, 5, 6, 7 }; + int y[7] = { 0 }; + int z[7] = { 1, 2, 3, 4, 5, 6, 7 }; + auto [in, out] = ranges::copy_backward(x, ranges::end(y)); + VERIFY( ranges::equal(x, y) && in == x+7 && out == y); + VERIFY( ranges::equal(x, z) ); + } + + { + int x[3] = { 1, 2, 3 }; + char y[4] = { 0 }; + int z[3] = { 1, 2, 3 }; + test_container cx(x); + test_container cy(y); + auto [in, out] = ranges::copy_backward(cx, ranges::end(cy)); + VERIFY( ranges::equal(x, x+3, y+1, y+4) && in.ptr == x+3 && out.ptr == y+1 ); + VERIFY( ranges::equal(x, z) ); + } + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in, out] = ranges::copy_backward(x, ranges::end(y)); + VERIFY( in.base() == x.data()+3 ); + VERIFY( out.base() == y.data() ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } + + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in, out] = ranges::copy_backward(x, ranges::end(y)); + VERIFY( in.base() == x.data()+3 ); + VERIFY( out.base() == y.data() ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in,out] = ranges::copy_backward(make_reverse_iterator(x.end()), + make_reverse_iterator(x.begin()), + make_reverse_iterator(y.begin())); + VERIFY( in.base().base() == x.data()+3 ); + VERIFY( out.base().base() == y.data()+3 ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in,out] = ranges::copy_backward(make_reverse_iterator(x.end()), + make_reverse_iterator(x.begin()), + make_reverse_iterator(y.begin())); + VERIFY( in.base().base() == x.data()+3 ); + VERIFY( out.base().base() == y.data()+3 ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } +} + +constexpr bool +test02() +{ + bool ok = true; + int x[] = { {2}, {2}, {6}, {8}, {10} }; + int y[] = { {2}, {6}, {8}, {10}, {11}, {2} }; + const int z[] = { {2}, {2}, {6}, {8}, {10} }; + auto [in, out] = ranges::copy_backward(x, ranges::end(y)); + ok &= ranges::equal(x, x+5, y+1, y+6); + ok &= (in == x+5); + ok &= (out == y+1); + ok &= (y[0] == 2); + ok &= ranges::equal(x, z); + return ok; +} + +/* move_iterators are always input_iterators and therefore do not model + * bidirectional_iterator, so I think the following tests are rightly invalid. + +struct Y +{ + int i; + int moved = 0; + + constexpr Y(int a) : i(a) { } + + constexpr Y(const Y&) = delete; + constexpr Y& operator=(const Y&) = delete; + + constexpr Y(Y&& other) + { + *this = std::move(other); + } + + constexpr Y& + operator=(Y&& other) + { + other.moved++; + i = other.i; + return *this; + } + + friend constexpr bool + operator==(const Y& a, const Y& b) + { return a.i == b.i; } +}; + +void +test02() +{ + Y x[7] = { 1, 2, 3, 4, 5, 6, 7 }; + Y y[7] = { 0, 0, 0, 0, 0, 0, 0 }; + Y z[7] = { 1, 2, 3, 4, 5, 6, 7 }; + test_range rx(x); + auto [in, out] = ranges::copy_backward(std::move_iterator{ranges::begin(rx)}, + std::move_sentinel{ranges::end(rx)}, + ranges::end(y)); + VERIFY( ranges::equal(x, y) && std::move(in).base().ptr == x+7 && out == y ); + VERIFY( ranges::equal(x, z) ); + for (const auto& v : x) + VERIFY( v.moved == 1 ); + for (const auto& v : y) + VERIFY( v.moved == 0 ); +} + +constexpr bool +test03() +{ + bool ok = true; + Y x[7] = { 1, 2, 3, 4, 5, 6, 7 }; + Y y[7] = { 0, 0, 0, 0, 0, 0, 0 }; + Y z[7] = { 1, 2, 3, 4, 5, 6, 7 }; + auto [in, out] = ranges::copy_backward(std::move_iterator{ranges::begin(x)}, + std::move_sentinel{ranges::end(x)}, + ranges::end(y)); + ok &= ranges::equal(x, y); + ok &= in.base() == x+7; + ok &= out == y; + ok &= ranges::equal(x, z); + for (const auto& v : x) + ok &= v.moved == 1; + for (const auto& v : y) + ok &= v.moved == 0; + return ok; +} +*/ + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_if/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/copy_if/constrained.cc new file mode 100644 index 00000000000..8a92d227f16 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy_if/constrained.cc @@ -0,0 +1,77 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {1,2,3,4,5,6,7}; + + { + const int y[] = {2,4,6}; + int w[7]; + test_range rx(x); + test_range rw(w); + auto [in,out] = ranges::copy_if(rx, rw.begin(), + [] (int a) { return (a%2)==0; }); + VERIFY( in == rx.end() && out.ptr == w+3 ); + VERIFY( ranges::equal(w, w+3, y, y+3) ); + } + + { + const int y[] = {1,3,5,7}; + int w[7]; + test_range rx(x); + test_range rw(w); + auto [in,out] = ranges::copy_if(rx, rw.begin(), + [] (int a) { return (a%2)==0; }, + [] (int a) { return a+1; }); + VERIFY( in == rx.end() && out.ptr == w+4 ); + VERIFY( ranges::equal(w, w+4, y, y+4) ); + } +} + +constexpr bool +test02() +{ + int x[] = {1,2,3}; + const int y[] = {1,3}; + int w[3]; + auto [in,out] = ranges::copy_if(x, w, [] (int a) { return (a%2)==1; }); + return ranges::equal(w, out, y, y+2); +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/copy_n/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/copy_n/constrained.cc new file mode 100644 index 00000000000..78a4539826a --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/copy_n/constrained.cc @@ -0,0 +1,72 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::random_access_iterator_wrapper; + +namespace ranges = std::ranges; + +template typename in_wrapper, + template typename out_wrapper> +void +test01() +{ + int x[] = {1,2,3,4,5,6,7}; + for (int i = -1; i <= 7; i++) + { + test_range rx(x); + int w[7]; + test_range rw(w); + ranges::copy_n(rx.begin(), i, rw.begin()); + if (i >= 0) + VERIFY( ranges::equal(x, x+i, w, w+i) ); + } +} + +constexpr bool +test02() +{ + int x[] = {1,2,3}; + int y[2]; + auto [in,out] = ranges::copy_n(x, 2, y); + return (in == x+2 + && out == y+2 + && ranges::equal(x, x+2, y, y+2)); +} + +int +main() +{ + test01(); + test01(); + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/count/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/count/constrained.cc new file mode 100644 index 00000000000..2a9bb27de5e --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/count/constrained.cc @@ -0,0 +1,75 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + X x[] = { {2}, {2}, {6}, {8}, {10}, {11}, {2} }; + auto res = ranges::count(x, x+7, 2, &X::i); + VERIFY( res == 3 ); + res = ranges::count(x, x+7, 8, &X::i); + VERIFY( res == 1 ); + res = ranges::count(x, x+7, 9, &X::i); + VERIFY( res == 0 ); + + test_container c(x); + res = ranges::count(c, 6, &X::i); + VERIFY( res == 1 ); + res = ranges::count(c, 9, &X::i); + VERIFY( res == 0 ); + + test_range r(x); + res = ranges::count(r, 2, &X::i); + VERIFY( res == 3 ); + + r.bounds.first = x; + res = ranges::count(r, 9, &X::i); + VERIFY( res == 0 ); +} + +struct Y { int i; int j; }; + +void +test02() +{ + static constexpr Y y[] = { {1,2}, {2,4}, {3,6}, {1,6} }; + static_assert(ranges::count(y, 6, &Y::j) == 2); + static_assert(ranges::count(y, 5, &Y::j) == 0); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/count_if/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/count_if/constrained.cc new file mode 100644 index 00000000000..79cdae31826 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/count_if/constrained.cc @@ -0,0 +1,73 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + X x[] = { {2}, {2}, {6}, {8}, {10}, {11}, {2} }; + auto res = ranges::count_if(x, x+7, [] (int i) { return i % 2 == 0; }, &X::i); + VERIFY( res == 6 ); + res = ranges::count_if(x, x+7, [] (int i) { return i % 2 == 1; }, &X::i); + VERIFY( res == 1 ); + res = ranges::count_if(x, x+7, [] (int i) { return i < 0; }, &X::i); + VERIFY( res == 0 ); + + test_container c(x); + res = ranges::count_if(c, [] (int i) { return i == 2; }, &X::i); + VERIFY( res == 3 ); + res = ranges::count_if(c, [] (int i) { return i < 0; }, &X::i); + VERIFY( res == 0 ); + + test_range r(x); + res = ranges::count_if(c, [] (int i) { return i == 2; }, &X::i); + VERIFY( res == 3 ); + res = ranges::count_if(c, [] (int i) { return i < 0; }, &X::i); + VERIFY( res == 0 ); +} + +struct Y { int i; int j; }; + +void +test02() +{ + static constexpr Y y[] = { {1,2}, {2,4}, {3,6}, {1,6} }; + static_assert(ranges::count_if(y, [] (int i) { return i < 5; }, &Y::j) == 2); + static_assert(ranges::count_if(y, [] (int i) { return i != 4; }, &Y::j) == 3); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc new file mode 100644 index 00000000000..231bd8cfeaa --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc @@ -0,0 +1,96 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + int x[] = { {2}, {2}, {6}, {8}, {10}, {11}, {11} }; + int y[] = { {2}, {2}, {6}, {8}, {10}, {11}, {11} }; + X z[] = { {2}, {6}, {8}, {10}, {2}, {2} }; + int w[] = { {1}, {1}, {1}, {1}, {1} }; + + VERIFY( ranges::equal(w, w+4, w+1, w+5) ); + VERIFY( ranges::equal(w, w+5, w, w+5, ranges::greater{}, + [] (int a) { return a+1; }) ); + + test_container cx(x), cy(y); + test_container cz(z); + VERIFY( ranges::equal(cx, cy) ); + VERIFY( !ranges::equal(cx, cy, {}, [] (int a) { return a+1; }) ); + VERIFY( !ranges::equal(cx, cz, {}, {}, &X::i) ); + + test_range rx(x), ry(y); + test_range rz(z); + VERIFY( ranges::equal(rx, ry) ); + + rx.bounds.first = x; + ry.bounds.first = y; + VERIFY( !ranges::equal(rx, ry, {}, {}, [] (int a) { return a+1; }) ); + + rx.bounds.first = x; + rz.bounds.first = z; + VERIFY( !ranges::equal(rx, rz, {}, {}, &X::i) ); +} + +void +test02() +{ + static constexpr X x[] = { {2}, {2}, {6}, {8}, {10}, {11} }; + static constexpr X y[] = { {2}, {6}, {8}, {10}, {11}, {2} }; + static constexpr int z[] = { {2}, {6}, {8}, {10}, {2}, {2} }; + static constexpr int w[] = { {2}, {6}, {8}, {10}, {2}, {2} }; + + static_assert(ranges::equal(z, w)); + static_assert(!ranges::equal(z, z+5, w+1, w+6)); + static_assert(!ranges::equal(z, z, {}, {}, [] (int a) { return a+1; })); + static_assert(!ranges::equal(x, y, {}, &X::i, &X::i)); +} + +void +test03() +{ + std::vector x = { {2}, {2}, {6}, {8}, {10}, {11} }; + std::vector y = { {2}, {2}, {6}, {8}, {10}, {11} }; + std::vector z = { {2}, {2}, {6}, {8}, {10}, {12} }; + VERIFY( ranges::equal(x, y) ); + VERIFY( !ranges::equal(x, z) ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/equal_range/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/equal_range/constrained.cc new file mode 100644 index 00000000000..4ddf4590c21 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/equal_range/constrained.cc @@ -0,0 +1,69 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {1, 2, 3, 4, 5, 5, 6, 7}; + for (unsigned i = 0; i < 5; i++) + for (unsigned j = 6; j < 8; j++) + { + test_container cx(x); + auto range = ranges::equal_range(std::next(cx.begin(), i), + std::next(cx.begin(), j), + 4, {}, [] (int a) { return a-1; }); + VERIFY( range.begin().ptr == x+4 && range.end().ptr == x+6 ); + } + + ranges::reverse(x); + test_range rx(x); + auto range = ranges::equal_range(rx, 5, ranges::greater{}, + [] (int a) { return a+1; }); + VERIFY( range.begin().ptr == x+4 && range.end().ptr == x+5 ); +} + +constexpr bool +test02() +{ + int x[] = {1, 2, 3, 4, 5}; + auto range1 = ranges::equal_range(x, 6); + auto range2 = ranges::equal_range(x, x, 6); + auto range3 = ranges::equal_range(x, 1); + return (range1.begin() == x+5 && range1.end() == x+5 + && range2.begin() == x && range2.end() == x + && range3.begin() == x && range3.end() == x+1); +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc new file mode 100644 index 00000000000..4813b8302ce --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc @@ -0,0 +1,92 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; +}; + +void +test01() +{ + const int c[6] = { 17, 17, 17, 17, 17, 17 }; + { + X x[6]; + VERIFY( ranges::fill(x, X{17}) == x+6 ); + VERIFY( ranges::equal(x, c, {}, &X::i) ); + } + + { + char x[6]; + VERIFY( ranges::fill(x, 17) == x+6 ); + VERIFY( ranges::equal(x, c) ); + } + + { + X x[6]; + test_container cx(x); + VERIFY( ranges::fill(cx, X{17}) == cx.end() ); + VERIFY( ranges::equal(cx, c, {}, &X::i) ); + } + + { + int x[6]; + test_range rx(x); + VERIFY( ranges::fill(rx, 17) == rx.end() ); + VERIFY( ranges::equal(x, c) ); + } + + { + std::list list(6); + ranges::fill(list, 17); + VERIFY( ranges::equal(list, c) ); + } +} + +constexpr bool +test02() +{ + bool ok = true; + int x[5]; + ranges::fill(x, 17); + for (auto v : x) + ok &= v == 17; + return ok; +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/fill_n/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/fill_n/constrained.cc new file mode 100644 index 00000000000..e9ce8e8fb0a --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/fill_n/constrained.cc @@ -0,0 +1,98 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; +}; + +void +test01() +{ + const int c[6] = { 17, 17, 17, 4, 5, 6 }; + { + X x[6] = { {1}, {2}, {3}, {4}, {5}, {6} }; + VERIFY( ranges::fill_n(x, 3, X{17}) == x+3 ); + VERIFY( ranges::equal(x, c, {}, &X::i) ); + } + + { + char x[6]; + VERIFY( ranges::fill_n(x, 3, 17) == x+3 ); + VERIFY( ranges::equal(x, x+3, c, c+3) ); + } + + { + X x[6] = { 1, 2, 3, 4, 5, 6 }; + test_container cx(x); + VERIFY( ranges::fill_n(cx.begin(), 3, X{17})->i == 4 ); + VERIFY( ranges::equal(cx, c, {}, &X::i) ); + } + + { + int x[6] = { 1, 2, 3, 4, 5, 6 };; + test_range rx(x); + ranges::fill_n(ranges::begin(rx), 3, 17); + VERIFY( ranges::equal(x, c) ); + } + + { + std::list list({1, 2, 3, 4, 5, 6}); + ranges::fill_n(list.begin(), 3, 17); + VERIFY( ranges::equal(list, c) ); + } +} + +constexpr bool +test02() +{ + bool ok = true; + int x[6] = { 1, 2, 3, 4, 5, 6 }; + const int y[6] = { 1, 2, 3, 4, 5, 6 }; + const int z[6] = { 17, 17, 17, 4, 5, 6 }; + + ranges::fill_n(x, 0, 17); + ranges::fill_n(x, -1, 17); + ok &= ranges::equal(x, y); + + ranges::fill_n(x, 3, 17); + ok &= ranges::equal(x, z); + return ok; +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/find/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/find/constrained.cc new file mode 100644 index 00000000000..6f6b9547e67 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/find/constrained.cc @@ -0,0 +1,75 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + X x[] = { {2}, {2}, {6}, {8}, {10}, {11} }; + auto res = ranges::find(x, x+6, 8, &X::i); + VERIFY( res == x+3 ); + res = ranges::find(x, x+6, 2, &X::i); + VERIFY( res == x+0 ); + res = ranges::find(x, x+6, 9, &X::i); + VERIFY( res == x+6 ); + + test_container c(x); + auto res2 = ranges::find(c, 8, &X::i); + VERIFY( res2 != ranges::end(c) && res2->i == 8 ); + res2 = ranges::find(c, 9, &X::i); + VERIFY( res2 == ranges::end(c) ); + + test_range r(x); + auto res3 = ranges::find(r, 8, &X::i); + VERIFY( res3 != ranges::end(r) && res3->i == 8 ); + + r.bounds.first = x; + res3 = ranges::find(r, 9, &X::i); + VERIFY( res3 == ranges::end(r) ); +} + +struct Y { int i; int j; }; + +void +test02() +{ + static constexpr Y y[] = { {1,2}, {2,4}, {3,6} }; + static_assert(ranges::find(y, 4, &Y::j) == y+1); + static_assert(ranges::find(y, 5, &Y::j) == y+3); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/find_end/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/find_end/constrained.cc new file mode 100644 index 00000000000..b51e4a734fb --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/find_end/constrained.cc @@ -0,0 +1,98 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + X x[] = { {10}, {11}, {2}, {6}, {8}, {10}, {11} }; + X y[] = { {10}, {11} }; + { + + test_container c(x); + auto res = ranges::find_end(c, y, {}, &X::i, &X::i); + VERIFY( std::get<0>(res)->i == 10 && std::get<1>(res) == ranges::end(c) ); + res = ranges::find_end(c, c, {}, &X::i, &X::i); + VERIFY( std::get<0>(res) == ranges::begin(c) + && std::get<1>(res) == ranges::end(c) ); + } + + { + test_range r(x); + auto res = ranges::find_end(r, y, {}, &X::i, &X::i); + VERIFY( std::get<0>(res)->i == 10 && std::get<1>(res) == ranges::end(r) ); + res = ranges::find_end(r, r, {}, &X::i, &X::i); + VERIFY( std::get<0>(res) == ranges::begin(r) + && std::get<1>(res) == ranges::end(r) ); + } + + { + test_range r(x); + auto res = ranges::find_end(r, y, {}, &X::i, &X::i); + VERIFY( std::get<0>(res)->i == 10 && std::get<1>(res) == ranges::end(r) ); + res = ranges::find_end(r, r, {}, &X::i, &X::i); + VERIFY( std::get<0>(res) == ranges::begin(r) + && std::get<1>(res) == ranges::end(r) ); + } +} + +void +test02() +{ + static constexpr X x[] = { {2}, {2}, {6}, {8}, {10}, {6}, {8}, {11} }; + static constexpr X y[] = { {6}, {8} }; + static constexpr int z[] = { 2, 8 }; + static constexpr int w[] = { 2 }; + + static_assert(std::get<0>(ranges::find_end(x, y, {}, &X::i, &X::i)) == x+5); + static_assert(std::get<1>(ranges::find_end(x, y, {}, &X::i, &X::i)) == x+7); + + static_assert(std::get<0>(ranges::find_end(x, z, {}, &X::i)) == x+8); + static_assert(std::get<1>(ranges::find_end(x, z, {}, &X::i)) == x+8); + + static_assert(std::get<0>(ranges::find_end(x, w, {}, &X::i)) == x+1); + static_assert(std::get<1>(ranges::find_end(x, w, {}, &X::i)) == x+2); + + static_assert(std::get<0>(ranges::find_end(x, x+6, w, w, {}, &X::i)) == x+6); + static_assert(std::get<1>(ranges::find_end(x, x+6, w, w, {}, &X::i)) == x+6); + + static_assert(std::get<0>(ranges::find_end(x, x, w, w+1, {}, &X::i)) == x+0); + static_assert(std::get<1>(ranges::find_end(x, x, w, w+1, {}, &X::i)) == x+0); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/find_first_of/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/find_first_of/constrained.cc new file mode 100644 index 00000000000..81a15761fa0 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/find_first_of/constrained.cc @@ -0,0 +1,83 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + X x[] = { {2}, {2}, {6}, {8}, {10}, {11} }; + int y[] = { 2, 7, 8, 9 }; + X w[] = { {2}, {7}, {8}, {9} }; + + auto res = ranges::find_first_of(x, x+6, y+1, y+4, {}, &X::i); + VERIFY( res == x+3 ); + res = ranges::find_first_of(x, x+6, w, w+4, {}, &X::i, &X::i); + VERIFY( res == x+0 ); + res = ranges::find_first_of(x, x+6, y+3, y+4, {}, &X::i); + VERIFY( res == x+6 ); + + test_container c(x); + test_container d1(y+1, y+4); + auto res2 = ranges::find_first_of(c, d1, {}, &X::i); + VERIFY( res2 != ranges::end(c) && res2->i == 8 ); + + test_container d2(w+3, w+4); + res2 = ranges::find_first_of(c, d2, {}, &X::i, &X::i); + VERIFY( res2 == ranges::end(c) ); + + test_range r(x); + test_range s1(y+1, y+4); + auto res3 = ranges::find_first_of(r, s1, {}, &X::i); + VERIFY( res3 != ranges::end(r) && res3->i == 8 ); + + test_range s2(w+3, w+4); + r.bounds.first = x; + res3 = ranges::find_first_of(r, s2, {}, &X::i, &X::i); + VERIFY( res3 == ranges::end(r) ); +} + +struct Y { int i; int j; }; + +void +test02() +{ + static constexpr Y y[] = { {1,2}, {2,4}, {3,6} }; + static_assert(ranges::find_first_of(y, y, {}, &Y::j, &Y::i) == y); + static_assert(ranges::find_first_of(y, y, {}, &Y::i, &Y::j) == y+1); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/find_if/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/find_if/constrained.cc new file mode 100644 index 00000000000..299bdd0fceb --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/find_if/constrained.cc @@ -0,0 +1,77 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + X x[] = { {2}, {2}, {6}, {8}, {10}, {11} }; + auto res = ranges::find_if(x, x+6, [] (X& v) { return v.i == 8; }); + VERIFY( res == x+3 ); + res = ranges::find_if(x, x+6, [] (X& v) { return v.i % 2 == 0; }); + VERIFY( res == x+0 ); + res = ranges::find_if(x, x+6, [] (X& v) { return v.i == 9; }); + VERIFY( res == x+6 ); + + test_container c(x); + auto res2 = ranges::find_if(c, [] (int i) { return i > 7; }, &X::i); + VERIFY( res2 != ranges::end(c) && res2->i == 8 ); + res2 = ranges::find_if(c, [] (int i) { return i > 11; }, &X::i); + VERIFY( res2 == ranges::end(c) ); + + test_range r(x); + auto res3 = ranges::find_if(r, [] (int i) { return i > 10; }, &X::i); + VERIFY( res3 != ranges::end(r) && res3->i == 11 ); + + r.bounds.first = x; + res3 = ranges::find_if(r, [] (int i) { return i == 9; }, &X::i); + VERIFY( res3 == ranges::end(r) ); +} + +struct Y { int i; int j; }; + +void +test02() +{ + static constexpr Y y[] = { {1,2}, {2,4}, {3,6} }; + static_assert(ranges::find_if(y, [] (int i) { return i > 3; }, &Y::j) + == y+1); + static_assert(ranges::find_if(y, [] (int i) { return i == 5; }, &Y::j) + == y+3); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/find_if_not/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/find_if_not/constrained.cc new file mode 100644 index 00000000000..838434aa7e0 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/find_if_not/constrained.cc @@ -0,0 +1,77 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + X x[] = { {2}, {2}, {6}, {8}, {10}, {11} }; + auto res = ranges::find_if_not(x, x+6, [] (X& v) { return v.i != 8; }); + VERIFY( res == x+3 ); + res = ranges::find_if_not(x, x+6, [] (X& v) { return v.i % 2 == 1; }); + VERIFY( res == x+0 ); + res = ranges::find_if_not(x, x+6, [] (X& v) { return v.i != 9; }); + VERIFY( res == x+6 ); + + test_container c(x); + auto res2 = ranges::find_if_not(c, [] (int i) { return i <= 7; }, &X::i); + VERIFY( res2 != ranges::end(c) && res2->i == 8 ); + res2 = ranges::find_if_not(c, [] (int i) { return i <= 11; }, &X::i); + VERIFY( res2 == ranges::end(c) ); + + test_range r(x); + auto res3 = ranges::find_if_not(r, [] (int i) { return i <= 10; }, &X::i); + VERIFY( res3 != ranges::end(r) && res3->i == 11 ); + + r.bounds.first = x; + res3 = ranges::find_if_not(r, [] (int i) { return i != 9; }, &X::i); + VERIFY( res3 == ranges::end(r) ); +} + +struct Y { int i; int j; }; + +void +test02() +{ + static constexpr Y y[] = { {1,2}, {2,4}, {3,6} }; + static_assert(ranges::find_if_not(y, [] (int i) { return i <= 3; }, &Y::j) + == y+1); + static_assert(ranges::find_if_not(y, [] (int i) { return i != 5; }, &Y::j) + == y+3); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/for_each/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/for_each/constrained.cc new file mode 100644 index 00000000000..142ad2e57da --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/for_each/constrained.cc @@ -0,0 +1,83 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +static int a; + +void +f(int& i) +{ + a += i; +} + +void +test01() +{ + X x[] = { {2}, {4}, {6}, {8}, {10}, {11} }; + + auto res = ranges::for_each(x, x+6, f, &X::i); + VERIFY( res.in == x+6 ); + VERIFY( res.fun == &f ); + VERIFY( a == 41 ); + + test_container c(x); + int p = 0; + ranges::for_each(c, [&p](int i) { ++p; }, &X::i); + VERIFY( p == 6 ); + + test_range r(x); + int q = 0; + ranges::for_each(r, [&q](X&) { ++q; }); + VERIFY( q == 6 ); +} + +struct Y { int i; int j; }; + +void +test02() +{ + auto f = [] + { + Y y[] = { {1,2}, {2,4}, {3,6} }; + int a = 0; + ranges::for_each(y, [&a](int i) { a += i; }, &Y::i); + return a; + }; + static_assert(f() == 6); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/generate/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/generate/constrained.cc new file mode 100644 index 00000000000..71bcbaa616d --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/generate/constrained.cc @@ -0,0 +1,77 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + const int c[6] = { 1, 2, 3, 4, 5, 6 }; + + { + int x[6]; + int a = 1; + VERIFY( ranges::generate(x, [&] { return a++; }) == x+6 ); + VERIFY( ranges::equal(x, c) ); + } + + { + int x[6]; + int a = 1; + test_container cx(x); + VERIFY( ranges::generate(cx, [&] { return a++; }) == cx.end() ); + VERIFY( ranges::equal(cx, c) ); + } + + { + int x[6]; + int a = 1; + test_range rx(x); + VERIFY( ranges::generate(rx, [&] { return a++; }) == rx.end() ); + VERIFY( ranges::equal(x, c) ); + } +} + +constexpr bool +test02() +{ + const int c[6] = { 1, 2, 3, 4, 5, 6 }; + int x[6]; + int a = 1; + ranges::generate(x, [&] { return a++; }); + return ranges::equal(x, c); +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/generate_n/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/generate_n/constrained.cc new file mode 100644 index 00000000000..ff894addecc --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/generate_n/constrained.cc @@ -0,0 +1,84 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + const int c[6] = { 1, 2, 3, 4, 5, 6 }; + + { + int x[6] = { 7, 8, 9, 4, 5, 6 }; + int a = 1; + VERIFY( ranges::generate_n(x, 3, [&] { return a++; }) == x+3 ); + VERIFY( ranges::equal(x, c) ); + } + + { + int x[6] = { 7, 8, 9, 4, 5, 6 }; + int a = 1; + test_container cx(x); + VERIFY( *ranges::generate_n(cx.begin(), 3, [&] { return a++; }) + == 4 ); + VERIFY( ranges::equal(cx, c) ); + } + + { + int x[6] = { 7, 8, 9, 4, 5, 6 }; + int a = 1; + test_range rx(x); + ranges::generate_n(ranges::begin(rx), 3, [&] { return a++; }); + VERIFY( ranges::equal(x, c) ); + } +} + +constexpr bool +test02() +{ + bool ok = true; + int c[6] = { 1, 2, 3, 4, 5, 6 }; + int x[6]; + int a = 1; + ranges::generate_n(x, 6, [&] { return a++; }); + ok &= ranges::equal(x, c); + ranges::generate_n(c, 0, [] { return -1; }); + ok &= ranges::equal(x, c); + ranges::generate_n(c, -2, [] { return -1; }); + ok &= ranges::equal(x, c); + return ok; +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc new file mode 100644 index 00000000000..eacf2906371 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc @@ -0,0 +1,107 @@ +// Copyright (C) 2020 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 run { target c++2a } } +// { dg-require-cstdint "" } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::random_access_iterator_wrapper; + +namespace ranges = std::ranges; + +template typename> typename container> +void +test01() +{ + int x[50]; + + auto pred = std::greater{}; + auto proj = [] (int a) { return -a; }; + for (int i = 0; i < 50; i++) + { + std::iota(x, x+50, 1); + container rx(x); + + std::ranlux48_base g(i); + ranges::shuffle(rx, g); + + auto iter = ranges::make_heap(rx, pred, proj); + VERIFY( iter == rx.end() ); + VERIFY( ranges::is_heap(rx, pred, proj) ); + VERIFY( ranges::is_heap_until(rx, pred, proj) == rx.end() ); + + iter = ranges::pop_heap(rx, pred, proj); + VERIFY( iter == rx.end() ); + VERIFY( *(iter-1) == 50 ); + VERIFY( ranges::is_heap_until(rx, pred, proj) == iter-1 ); + + iter = ranges::pop_heap(rx.begin(), iter-1, pred, proj); + VERIFY( iter+1 == rx.end() ); + VERIFY( *(iter-1) == 49 ); + VERIFY( ranges::is_heap_until(rx, pred, proj) == iter-1 ); + + *(iter-1) = i; + iter = ranges::push_heap(rx.begin(), iter, pred, proj); + VERIFY( iter+1 == rx.end() ); + VERIFY( ranges::is_heap_until(rx, pred, proj) == iter ); + + *iter = 2*i; + iter = ranges::push_heap(rx.begin(), rx.end(), pred, proj); + VERIFY( iter == rx.end() ); + VERIFY( ranges::is_heap_until(rx, pred, proj) == iter ); + + *(rx.begin()+1) *= -1; + VERIFY( !ranges::is_heap(rx, pred, proj) ); + *(rx.begin()+1) *= -1; + VERIFY( ranges::is_heap(rx, pred, proj) ); + + iter = ranges::sort_heap(rx, pred, proj); + VERIFY( iter == rx.end() ); + VERIFY( ranges::is_sorted(rx, pred, proj) ); + } +} + +constexpr bool +test02() +{ + bool ok = true; + int x[] = {1,2,3,4,5}; + ranges::make_heap(x); + ranges::pop_heap(x); + x[4] = 7; + ranges::push_heap(x); + ok &= ranges::is_heap(x); + ok &= ranges::is_heap_until(x) == x+5; + ranges::sort_heap(x); + ok &= ranges::equal(x, (int[]){1,2,3,4,7}); + return ok; +} + +int +main() +{ + test01(); + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/includes/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/includes/constrained.cc new file mode 100644 index 00000000000..f959a1d60a4 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/includes/constrained.cc @@ -0,0 +1,74 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {1,2,3,4,5,6,7}; + int y[] = {2,4,6}; + test_range rx(x), ry(y); + + VERIFY( ranges::includes(rx, ry) ); + + rx.bounds.first = x; + ry.bounds.first = y; + VERIFY( ranges::includes(rx, ry, + ranges::greater{}, + std::negate<>{}, + std::negate<>{}) ); + + test_container cx(x), cy(y); + VERIFY( ranges::includes(cx.begin(), cx.end(), + cy.begin(), cy.end(), + {}, + [] (int a) { return a+1; }, + [] (int a) { return a+2; }) ); + + VERIFY( ranges::includes(x, x+1, y, y) ); +} + +constexpr bool +test03() +{ + bool ok = true; + ok &= ranges::includes((int[]){1,2,3}, + (int[]){1}); + ok &= !ranges::includes((int[]){1,2,3}, + (int[]){1,2,3,4}); + return true; +} + +int +main() +{ + test01(); + static_assert(test03()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc new file mode 100644 index 00000000000..856056865d9 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc @@ -0,0 +1,69 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {1,2,3,4,5}; + for (int i = 0; i <= 5; i++) + for (int j = 0; j <= 5; j++) + { + std::vector v(x, x+i); + v.insert(v.end(), x, x+j); + ranges::sort(v); + + test_range rz(&v[0], &v[0]+i+j); + auto result = ranges::inplace_merge(rz, next(ranges::begin(rz), i)); + VERIFY( result == rz.end() ); + + VERIFY( ranges::is_sorted(rz) ); + } +} + +void +test02() +{ + struct X { int i, j; }; + X x[] = { {1, 1}, {3, 4}, {5, 5}, {2, 2}, {2, 3} }; + auto comp = ranges::greater{}; + auto proj = [] (X a) { return -a.i; }; + ranges::inplace_merge(x, x+3, x+5, comp, proj); + VERIFY( ranges::is_sorted(x, {}, &X::i) ); + VERIFY( ranges::is_sorted(x, {}, &X::j) ); +} + + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/is_partitioned/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/is_partitioned/constrained.cc new file mode 100644 index 00000000000..8035667b38d --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/is_partitioned/constrained.cc @@ -0,0 +1,58 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {2,4,6,1,3,5}; + test_container cx(x); + VERIFY( ranges::is_partitioned(cx, [] (int a) { return a%2==0; }) ); + + test_range rx(x); + VERIFY( ranges::is_partitioned(rx, + [] (int a) { return a%2==1; }, + [] (int a) { return a+1; }) ); +} + +constexpr bool +test02() +{ + int x[] = {1,2,3,4,5,6,1}; + return (ranges::is_partitioned(x, x+6, [] (int a) { return a<=2; }) + && !ranges::is_partitioned(x, x+7, [] (int a) { return a<=2; })); +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/is_permutation/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/is_permutation/constrained.cc new file mode 100644 index 00000000000..c5393becc8d --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/is_permutation/constrained.cc @@ -0,0 +1,85 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + int x[] = { {2}, {2}, {6}, {8}, {10}, {11} }; + int y[] = { {2}, {6}, {8}, {10}, {11}, {2} }; + int z[] = { {2}, {6}, {8}, {10}, {2}, {2} }; + + VERIFY( ranges::is_permutation(x, x+6, y, y+6) ); + VERIFY( !ranges::is_permutation(x, x+6, y, y+5) ); + + test_container cx(x), cy(y), cz(z); + test_range rx(x), ry(y), rz(z); + VERIFY( ranges::is_permutation(cx, ry) ); + VERIFY( !ranges::is_permutation(rx, cz) ); + VERIFY( ranges::is_permutation(rx, cy) ); + VERIFY( !ranges::is_permutation(cx, rz) ); +} + +void +test02() +{ + static constexpr X x[] = { {2}, {2}, {6}, {8}, {10}, {11} }; + static constexpr X y[] = { {2}, {6}, {8}, {10}, {11}, {2} }; + static constexpr int z[] = { {2}, {6}, {8}, {10}, {2}, {2} }; + static_assert(ranges::is_permutation(x, y, {}, &X::i, &X::i)); + static_assert(!ranges::is_permutation(x, z, {}, &X::i)); + static_assert(!ranges::is_permutation(z, y, {}, {}, &X::i)); +} + +void +test03() +{ + int x[] = { 1, 2, 3, 4 }; + int y[] = { 1, 2, 3, 3 }; + test_container cx(x); + do + do + { + VERIFY( ranges::is_permutation(cx, x) ); + VERIFY( !ranges::is_permutation(y, cx) ); + } while (std::next_permutation(y, y+4)); + while (std::next_permutation(std::begin(cx), std::end(cx))); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/is_sorted/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/is_sorted/constrained.cc new file mode 100644 index 00000000000..af00afe48e8 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/is_sorted/constrained.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {3,4,5,1}; + test_container cx(x); + VERIFY( ranges::is_sorted(cx.begin(), ranges::next(cx.begin(), 3)) ); + VERIFY( !ranges::is_sorted(cx) ); + VERIFY( !ranges::is_sorted(cx, ranges::greater{}) ); + VERIFY( ranges::is_sorted(cx, {}, [] (int a) { return 0; }) ); +} + +void +test02() +{ + int x[] = {1,2,3,4,5}; + test_range rx(x); + VERIFY( ranges::is_sorted(rx) ); + VERIFY( !ranges::is_sorted(ranges::begin(rx), + next(ranges::begin(rx), 2), + ranges::greater{}) ); +} + +constexpr bool +test03() +{ + int x[] = { 1,2 }; + return (ranges::is_sorted(x) + && ranges::is_sorted(x, x) ); +} + +int +main() +{ + test01(); + test02(); + static_assert(test03()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/is_sorted_until/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/is_sorted_until/constrained.cc new file mode 100644 index 00000000000..a81aa49ee94 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/is_sorted_until/constrained.cc @@ -0,0 +1,72 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {3,4,5,1}; + test_container cx(x); + VERIFY( ranges::is_sorted_until(cx.begin(), + ranges::next(cx.begin(), 3)) + == ranges::next(cx.begin(), 3) ); + VERIFY( ranges::is_sorted_until(cx) == ranges::next(cx.begin(), 3) ); + VERIFY( ranges::is_sorted_until(cx, ranges::greater{}) + == ranges::next(cx.begin(), 1) ); + VERIFY( ranges::is_sorted_until(cx, {}, [] (int a) { return 0; }) + == cx.end() ); +} + +void +test02() +{ + int x[] = {1,2,3,4,5}; + test_range rx(x); + VERIFY( ranges::is_sorted_until(rx) == ranges::end(rx) ); + VERIFY( ranges::is_sorted_until(ranges::begin(rx), + next(ranges::begin(rx), 2), + ranges::greater{}) + == next(ranges::begin(rx), 1) ); +} + +constexpr bool +test03() +{ + int x[] = { 1,2 }; + return (ranges::is_sorted_until(x) == x+2 + && ranges::is_sorted_until(x, x) == x ); +} + +int +main() +{ + test01(); + test02(); + static_assert(test03()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/constrained.cc new file mode 100644 index 00000000000..b82c872bbbb --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/constrained.cc @@ -0,0 +1,164 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {1, 2, 3, 4, 5}; + char y[] = {1, 2, 3, 5}; + long z[] = {1, 2, 3, 4, 5, 6}; + + { + test_range rx(x); + test_range ry(y); + test_range rz(z); + + VERIFY( ranges::lexicographical_compare(rx, ry) ); + rx.bounds.first = x; + ry.bounds.first = y; + VERIFY( !ranges::lexicographical_compare(ry, rx) ); + } + + test_range rx(x); + test_range ry(y); + test_range rz(z); + + VERIFY( ranges::lexicographical_compare(rx, rz) ); + VERIFY( !ranges::lexicographical_compare(rz, rx) ); + + VERIFY( !ranges::lexicographical_compare(rx, rx) ); + VERIFY( ranges::lexicographical_compare(rx, rx, {}, std::negate<>{}) ); + VERIFY( ranges::lexicographical_compare(rx, rx, std::greater{}, + {}, std::negate<>{}) ); + + VERIFY( !ranges::lexicographical_compare(rx, ry, {}, + std::negate<>{}, + std::negate<>{}) ); + VERIFY( ranges::lexicographical_compare(ry, rx, {}, + std::negate<>{}, + std::negate<>{}) ); + + VERIFY( ranges::lexicographical_compare(rx, rz, ranges::greater{}) ); + VERIFY( !ranges::lexicographical_compare(rz, rx, ranges::greater{}) ); + + VERIFY( ranges::lexicographical_compare(rx, ry, ranges::greater{}, + std::negate<>{}, + std::negate<>{}) ); + VERIFY( !ranges::lexicographical_compare(ry, rx, ranges::greater{}, + std::negate<>{}, + std::negate<>{}) ); +} + +void +test02() +{ + int x[] = {1, 2, 3, 4, 5}; + int y[] = {1, 2, 3, 5}; + int z[] = {1, 2, 3, 4, 5, 6}; + + VERIFY( ranges::lexicographical_compare(x, y) ); + VERIFY( !ranges::lexicographical_compare(y, x) ); + + VERIFY( ranges::lexicographical_compare(x, z) ); + VERIFY( !ranges::lexicographical_compare(z, x) ); + + VERIFY( !ranges::lexicographical_compare(x, x) ); + + VERIFY( !ranges::lexicographical_compare(x, y, {}, + std::negate<>{}, + std::negate<>{}) ); + VERIFY( ranges::lexicographical_compare(y, x, {}, + std::negate<>{}, + std::negate<>{}) ); + + VERIFY( ranges::lexicographical_compare(x, z, ranges::greater{}) ); + VERIFY( !ranges::lexicographical_compare(z, x, ranges::greater{}) ); + + VERIFY( ranges::lexicographical_compare(x, y, ranges::greater{}, + std::negate<>{}, + std::negate<>{}) ); + VERIFY( !ranges::lexicographical_compare(y, x, ranges::greater{}, + std::negate<>{}, + std::negate<>{}) ); +} + +void +test03() +{ + int x[] = {1, 2, 3, 4, 5}; + int y[] = {1, 2, 5, 3}; + int z[] = {1, 2, 3, 5}; + + do + { + VERIFY( ranges::lexicographical_compare(x, y) ); + VERIFY( !ranges::lexicographical_compare(x, y, ranges::greater{}) ); + VERIFY( !ranges::lexicographical_compare(y, x) ); + VERIFY( ranges::lexicographical_compare(y, x, ranges::greater{}) ); + + test_container cy(y); + VERIFY( ranges::lexicographical_compare(x, cy) ); + VERIFY( !ranges::lexicographical_compare(x, cy, ranges::greater{}) ); + VERIFY( !ranges::lexicographical_compare(cy, x) ); + VERIFY( ranges::lexicographical_compare(cy, x, ranges::greater{}) ); + + test_container cz(z); + VERIFY( ranges::lexicographical_compare(cz.begin(), cz.end(), + cy.begin(), cy.end()) ); + VERIFY( !ranges::lexicographical_compare(cy.begin(), cy.end(), + cz.begin(), cz.end()) ); + + std::vector vx(x, x+5), vy(y, y+5); + VERIFY( ranges::lexicographical_compare(vx, vy) ); + VERIFY( !ranges::lexicographical_compare(vx, vy, ranges::greater{}) ); + VERIFY( !ranges::lexicographical_compare(vy, vx) ); + VERIFY( ranges::lexicographical_compare(vy, vx, ranges::greater{}) ); + } while (ranges::next_permutation(y).found); +} + +constexpr bool +test04() +{ + int x[] = {1}; + int y[] = {1}; + return (ranges::lexicographical_compare((int[]){1,2,3,5}, + (int[]){1,2,4}) + && !ranges::lexicographical_compare(x, x, y, y)); +} + +int +main() +{ + test01(); + test02(); + test03(); + static_assert(test04()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/lower_bound/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/lower_bound/constrained.cc new file mode 100644 index 00000000000..df93f41e823 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/lower_bound/constrained.cc @@ -0,0 +1,66 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {1, 2, 3, 4, 5, 5, 6, 7}; + for (unsigned i = 0; i < 5; i++) + for (unsigned j = 5; j < 8; j++) + { + test_container cx(x); + auto result = ranges::lower_bound(std::next(cx.begin(), i), + std::next(cx.begin(), j), + 4, {}, [] (int a) { return a-1; }); + VERIFY( result.ptr == x+4 ); + } + + ranges::reverse(x); + test_range rx(x); + auto result = ranges::lower_bound(rx, 5, ranges::greater{}, + [] (int a) { return a+1; }); + VERIFY( result.ptr == x+4 ); +} + +constexpr bool +test02() +{ + int x[] = {1, 2, 3, 4, 5}; + return (ranges::lower_bound(x, 6) == x+5 + && ranges::lower_bound(x, x, 6) == x + && ranges::lower_bound(x, 1) == x); +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc new file mode 100644 index 00000000000..3fcdb3a366c --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc @@ -0,0 +1,82 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i, j; +}; + +void +test01() +{ + VERIFY( ranges::max(1, 2) == 2); + VERIFY( ranges::max(2, 1) == 2); + VERIFY( ranges::max(1, 2, ranges::greater{}) == 1); + VERIFY( ranges::max(1, 2, ranges::greater{}, std::negate<>{}) == 2); + VERIFY( ranges::max(1, 2, {}, std::negate<>{}) == 1); + VERIFY( ranges::max(X{1,2}, X{1,3}, {}, &X::i).j == 2 ); +} + +void +test02() +{ + int x[] = {1,2,3,4}; + do + { + test_range cx(x); + VERIFY( ranges::max(cx) == 4 ); + cx.bounds.first = x; + VERIFY( ranges::max(cx, ranges::greater{}) == 1 ); + cx.bounds.first = x; + VERIFY( ranges::max(cx, {}, std::negate<>{}) == 1); + cx.bounds.first = x; + VERIFY( ranges::max(cx, ranges::greater{}, std::negate<>{}) == 4 ); + } while (ranges::next_permutation(x).found); + + constexpr X y[] = {{0,5},{1,2},{1,3}}; + static_assert(ranges::max(y, {}, &X::i).j == 2); +} + +void +test03() +{ + VERIFY( ranges::max({2,3,1,4}) == 4 ); + VERIFY( ranges::max({2,3,1,4}, ranges::greater{}) == 1 ); + VERIFY( ranges::max({2,3,1,4}, {}, std::negate<>{}) == 1 ); + VERIFY( ranges::max({2,3,1,4}, ranges::greater{}, std::negate<>{}) == 4 ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/max_element/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/max_element/constrained.cc new file mode 100644 index 00000000000..427faedbc44 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/max_element/constrained.cc @@ -0,0 +1,60 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i, j; +}; + +void +test01() +{ + int x[] = {1,2,3,4}; + do + { + test_range cx(x); + VERIFY( *ranges::max_element(cx) == 4 ); + VERIFY( *ranges::max_element(cx, ranges::greater{}) == 1 ); + VERIFY( *ranges::max_element(cx, {}, std::negate<>{}) == 1); + VERIFY( *ranges::max_element(cx, ranges::greater{}, std::negate<>{}) == 4 ); + } while (ranges::next_permutation(x).found); + + test_container cx(x); + VERIFY( ranges::max_element(cx.begin(), cx.begin()) == cx.begin() ); + + constexpr X y[] = {{0,5},{1,2},{1,3}}; + static_assert(ranges::max_element(y, y+3, {}, &X::i)->j == 2); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/merge/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/merge/constrained.cc new file mode 100644 index 00000000000..3f3a0f79f9b --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/merge/constrained.cc @@ -0,0 +1,75 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {1,2,3,4,5}; + for (int i = 0; i <= 5; i++) + for (int j = 0; j <= 5; j++) + { + int z[10]; + test_range rx(x, x+i), ry(x, x+j); + test_range rz(z, z+i+j); + auto [in1,in2,out] = ranges::merge(rx, ry, rz.begin()); + VERIFY( in1 == rx.end() ); + VERIFY( in2 == ry.end() ); + VERIFY( out == rz.end() ); + + std::vector v(x, x+i); + v.insert(v.end(), x, x+j); + ranges::sort(v); + + VERIFY( ranges::equal(v.begin(), v.end(), z, z+i+j) ); + } +} + +constexpr bool +test02() +{ + int x[] = {-1,-3,-5}; + int y[] = {2,4,6}; + int z[6]; + ranges::merge(x, x+3, y, y+3, z, + ranges::greater{}, {}, [] (int a) { return -a; }); + + const int w[6] = {-1, 2, -3, 4, -5, 6}; + return ranges::equal(w, z); +} + + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc new file mode 100644 index 00000000000..c3a83b975c9 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc @@ -0,0 +1,82 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i, j; +}; + +void +test01() +{ + VERIFY( ranges::min(1, 2) == 1); + VERIFY( ranges::min(2, 1) == 1); + VERIFY( ranges::min(1, 2, ranges::greater{}) == 2); + VERIFY( ranges::min(1, 2, ranges::greater{}, std::negate<>{}) == 1); + VERIFY( ranges::min(1, 2, {}, std::negate<>{}) == 2); + VERIFY( ranges::min(X{1,2}, X{1,3}, {}, &X::i).j == 2 ); +} + +void +test02() +{ + int x[] = {1,2,3,4}; + do + { + test_range cx(x); + VERIFY( ranges::min(cx) == 1 ); + cx.bounds.first = x; + VERIFY( ranges::min(cx, ranges::greater{}) == 4 ); + cx.bounds.first = x; + VERIFY( ranges::min(cx, {}, std::negate<>{}) == 4); + cx.bounds.first = x; + VERIFY( ranges::min(cx, ranges::greater{}, std::negate<>{}) == 1 ); + } while (ranges::next_permutation(x).found); + + constexpr X y[] = {{5,0},{1,2},{1,3}}; + static_assert(ranges::min(y, {}, &X::i).j == 2); +} + +void +test03() +{ + VERIFY( ranges::min({2,3,1,4}) == 1 ); + VERIFY( ranges::min({2,3,1,4}, ranges::greater{}) == 4 ); + VERIFY( ranges::min({2,3,1,4}, {}, std::negate<>{}) == 4 ); + VERIFY( ranges::min({2,3,1,4}, ranges::greater{}, std::negate<>{}) == 1 ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/min_element/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/min_element/constrained.cc new file mode 100644 index 00000000000..518060522a3 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/min_element/constrained.cc @@ -0,0 +1,60 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i, j; +}; + +void +test01() +{ + int x[] = {1,2,3,4}; + do + { + test_range cx(x); + VERIFY( *ranges::min_element(cx) == 1 ); + VERIFY( *ranges::min_element(cx, ranges::greater{}) == 4 ); + VERIFY( *ranges::min_element(cx, {}, std::negate<>{}) == 4); + VERIFY( *ranges::min_element(cx, ranges::greater{}, std::negate<>{}) == 1 ); + } while (ranges::next_permutation(x).found); + + test_container cx(x); + VERIFY( ranges::min_element(cx.begin(), cx.begin()) == cx.begin() ); + + constexpr X y[] = {{5,0},{1,2},{1,3}}; + static_assert(ranges::min_element(y, y+3, {}, &X::i)->j == 2); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc new file mode 100644 index 00000000000..aa9364ab04c --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc @@ -0,0 +1,98 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; + +namespace ranges = std::ranges; + +template +constexpr bool +operator==(const ranges::minmax_result& lhs, + const ranges::minmax_result& rhs) +{ + return (lhs.min == rhs.min + && rhs.max == rhs.max); +} + + +struct X +{ + int i, j; +}; + +using res_t = ranges::minmax_result; + +void +test01() +{ + VERIFY( ranges::minmax(1, 2) == res_t(1,2) ); + VERIFY( ranges::minmax(2, 1) == res_t(1,2) ); + VERIFY( ranges::minmax(1, 2, ranges::greater{}) == res_t(2,1) ); + VERIFY( ranges::minmax(1, 2, ranges::greater{}, std::negate<>{}) == res_t(1,2) ); + VERIFY( ranges::minmax(1, 2, {}, std::negate<>{}) == res_t(2,1) ); + VERIFY( ranges::minmax(X{1,2}, X{1,3}, {}, &X::i).min.j == 2 ); + VERIFY( ranges::minmax(X{1,2}, X{1,3}, {}, &X::i).max.j == 3 ); +} + +void +test02() +{ + int x[] = {1,2,3,4}; + do + { + test_range cx(x); + VERIFY( ranges::minmax(cx) == res_t(1,4) ); + cx.bounds.first = x; + VERIFY( ranges::minmax(cx, ranges::greater{}) == res_t(4,1) ); + cx.bounds.first = x; + VERIFY( ranges::minmax(cx, {}, std::negate<>{}) == res_t(4,1)); + cx.bounds.first = x; + VERIFY( ranges::minmax(cx, ranges::greater{}, std::negate<>{}) + == res_t(1,4) ); + } while (ranges::next_permutation(x).found); + + constexpr X y[] = {{1,5},{1,2},{1,3}}; + static_assert(ranges::minmax(y, {}, &X::i).min.j == 5); + static_assert(ranges::minmax(y, {}, &X::i).max.j == 3); +} + +void +test03() +{ + VERIFY( ranges::minmax({2,3,1,4}) == res_t(1,4) ); + VERIFY( ranges::minmax({2,3,1,4}, ranges::greater{}) == res_t(4,1) ); + VERIFY( ranges::minmax({2,3,1,4}, {}, std::negate<>{}) == res_t(4,1) ); + VERIFY( ranges::minmax({2,3,1,4}, ranges::greater{}, std::negate<>{}) + == res_t(1,4) ); +} + +int +main() +{ + test01(); + test02(); + test03(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc new file mode 100644 index 00000000000..40019c43326 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc @@ -0,0 +1,68 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i, j; +}; + +void +test01() +{ + int x[] = {1,2,3,4}; + do + { + test_range cx(x); + VERIFY( *ranges::minmax_element(cx).min == 1 ); + VERIFY( *ranges::minmax_element(cx).max == 4 ); + VERIFY( *ranges::minmax_element(cx, ranges::greater{}).min == 4 ); + VERIFY( *ranges::minmax_element(cx, ranges::greater{}).max == 1 ); + VERIFY( *ranges::minmax_element(cx, {}, std::negate<>{}).min == 4); + VERIFY( *ranges::minmax_element(cx, {}, std::negate<>{}).max == 1); + VERIFY( *ranges::minmax_element(cx, ranges::greater{}, std::negate<>{}).min + == 1 ); + VERIFY( *ranges::minmax_element(cx, ranges::greater{}, std::negate<>{}).max + == 4 ); + } while (ranges::next_permutation(x).found); + + test_container cx(x); + VERIFY( ranges::minmax_element(cx.begin(), cx.begin()).min == cx.begin() ); + VERIFY( ranges::minmax_element(cx.begin(), cx.begin()).max == cx.begin() ); + + constexpr X y[] = {{1,5},{1,2},{1,3}}; + static_assert(ranges::minmax_element(y, y+3, {}, &X::i).min->j == 5); + static_assert(ranges::minmax_element(y, y+3, {}, &X::i).max->j == 3); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/mismatch/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/mismatch/constrained.cc new file mode 100644 index 00000000000..37e79a2d62f --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/mismatch/constrained.cc @@ -0,0 +1,76 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + X xa[] = { {1}, {2}, {3}, {4}, {5}, {6} }; + X xb[] = { {1}, {2}, {3}, {3}, {5}, {6} }; + auto res = ranges::mismatch(xa, xa+6, xb, xb+6, {}, &X::i, &X::i); + VERIFY( res.in1 == xa+3 && res.in2 == xb+3 ); + + test_container ca(xa); + test_container cb(xb); + auto res2 = ranges::mismatch(ca, cb, {}, &X::i, &X::i); + VERIFY( res2.in1->i == 4 && res2.in2->i == 3 ); + res2 = ranges::mismatch(ca, ca, {}, &X::i, &X::i); + VERIFY( res2.in1 == ranges::end(ca) && res2.in2 == ranges::end(ca) ); + + test_range ra(xa); + test_range rb(xb); + auto res3 = ranges::mismatch(ra, rb, {}, &X::i, &X::i); + VERIFY( res3.in1->i == 4 && res3.in2->i == 3 ); + + test_range ra2(xa); + ra.bounds.first = xa; + res3 = ranges::mismatch(ra, ra2, {}, &X::i, &X::i); + VERIFY( res3.in1 == ranges::end(ra) && res3.in2 == ranges::end(ra2) ); +} + +struct Y { int i; int j; }; + +void +test02() +{ + static constexpr Y ya[] = { {1,2}, {2,4}, {3,6}, {1,6} }; + static constexpr Y yb[] = { {2,1}, {4,2}, {4,2}, {7,1} }; + static_assert(ranges::mismatch(ya, yb, {}, &Y::i, &Y::j).in1 == ya+2); + static_assert(ranges::mismatch(ya, yb, {}, &Y::i, &Y::j).in2 == yb+2); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc new file mode 100644 index 00000000000..d205b3572a1 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc @@ -0,0 +1,203 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; + int moved = 0; + + constexpr X() : i(0) { } + constexpr X(int a) : i(a) { } + + constexpr X(const X&) = delete; + constexpr X& operator=(const X&) = delete; + + constexpr X(X&& other) + { + *this = std::move(other); + } + + constexpr X& + operator=(X&& other) + { + other.moved++; + i = other.i; + return *this; + } + + friend constexpr bool + operator==(const X& a, const X& b) + { return a.i == b.i; } +}; + +void +test01() +{ + { + X x[7] = { 1, 2, 3, 4, 5, 6, 7 }; + X y[7] = { 0, 0, 0, 0, 0, 0, 0 }; + X z[7] = { 1, 2, 3, 4, 5, 6, 7 }; + auto [in, out] = ranges::move(x, y); + VERIFY( ranges::equal(x, y) && in == x+7 && out == y+7 ); + VERIFY( ranges::equal(x, z) ); + } + + { + int x[3] = { 1, 2, 3 }; + char y[4] = { 0 }; + int z[3] = { 1, 2, 3 }; + test_container cx(x); + test_container cy(y); + auto [in, out] = ranges::move(cx, cy.begin()); + VERIFY( ranges::equal(x, x+3, y, y+3) && in.ptr == x+3 && out.ptr == y+3 ); + VERIFY( ranges::equal(x, z) ); + } + + { + char x[3] = { 1, 2, 3 }; + int y[4] = { 0 }; + int z[3] = { 1, 2, 3 }; + test_range cx(x); + test_range cy(y); + auto [in, out] = ranges::move(cx, ranges::begin(cy)); + VERIFY( ranges::equal(x, x+3, y, y+3) && in.ptr == x+3 && out.ptr == y+3 ); + VERIFY( ranges::equal(x, z) ); + } + + { + std::vector x= {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in, out] = ranges::move(x, ranges::begin(y)); + VERIFY( in.base() == x.data()+3 ); + VERIFY( out.base() == y.data()+3 ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } + + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in, out] = ranges::move(x, ranges::begin(y)); + VERIFY( in.base() == x.data()+3 ); + VERIFY( out.base() == y.data()+3 ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in,out] = ranges::move(make_reverse_iterator(x.end()), + make_reverse_iterator(x.begin()), + make_reverse_iterator(y.end())); + VERIFY( in.base().base() == x.data()+3 ); + VERIFY( out.base().base() == y.data() ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in,out] = ranges::move(make_reverse_iterator(x.end()), + make_reverse_iterator(x.begin()), + make_reverse_iterator(y.end())); + VERIFY( in.base().base() == x.data()+3 ); + VERIFY( out.base().base() == y.data() ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } +} + +void +test02() +{ + X x[] = { {2}, {2}, {6}, {8}, {10} }; + X y[] = { {2}, {6}, {8}, {10}, {11}, {2} }; + X z[] = { {2}, {2}, {6}, {8}, {10} }; + auto [in, out] = ranges::move(x, y); + VERIFY( ranges::equal(x, x+5, y, y+5) ); + VERIFY( in == x+5 ); + VERIFY( out == y+5 ); + VERIFY( y[5].i == 2 ); + VERIFY( ranges::equal(x, z) ); + VERIFY( ranges::count(x, 1, &X::moved) == 5 ); + VERIFY( ranges::count(y, 0, &X::moved) == 6 ); +} + +constexpr bool +test03() +{ + bool ok = true; + X x[] = { {2}, {2}, {6}, {8}, {10} }; + X y[] = { {2}, {6}, {8}, {10}, {11}, {2} }; + X z[] = { {2}, {2}, {6}, {8}, {10} }; + auto [in, out] = ranges::move(x, y); + ok &= ranges::equal(x, x+5, y, y+5); + ok &= (in == x+5); + ok &= (out == y+5); + ok &= (y[5].i == 2); + ok &= ranges::equal(x, z); + ok &= ranges::count(x, 1, &X::moved) == 5; + ok &= ranges::count(y, 0, &X::moved) == 6; + return ok; +} + +void +test04() +{ + X x[] = { {2}, {2}, {6}, {8}, {10} }; + X y[] = { {2}, {6}, {8}, {10}, {11}, {2} }; + X z[] = { {2}, {2}, {6}, {8}, {10} }; + test_range rx(x); + auto [in, out] = ranges::move(std::move_iterator{ranges::begin(rx)}, + std::move_sentinel{ranges::end(rx)}, + ranges::begin(y)); + VERIFY( ranges::equal(x, x+5, y, y+5) ); + VERIFY( std::move(in).base().ptr == x+5 ); + VERIFY( out == y+5 ); + VERIFY( y[5].i == 2 ); + VERIFY( ranges::equal(x, z) ); + VERIFY( ranges::count(x, 1, &X::moved) == 5 ); + VERIFY( ranges::count(y, 0, &X::moved) == 6 ); +} + +int +main() +{ + test01(); + test02(); + static_assert(test03()); + test04(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc new file mode 100644 index 00000000000..3c4aa5dc70d --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc @@ -0,0 +1,170 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; + int moved = 0; + + constexpr X() : i(0) { } + constexpr X(int a) : i(a) { } + + constexpr X(const X&) = delete; + constexpr X& operator=(const X&) = delete; + + constexpr X(X&& other) + { + *this = std::move(other); + } + + constexpr X& + operator=(X&& other) + { + other.moved++; + i = other.i; + return *this; + } + + friend constexpr bool + operator==(const X& a, const X& b) + { return a.i == b.i; } +}; + +void +test01() +{ + { + X x[7] = { 1, 2, 3, 4, 5, 6, 7 }; + X y[7] = { 0, 0, 0, 0, 0, 0, 0 }; + X z[7] = { 1, 2, 3, 4, 5, 6, 7 }; + auto [in, out] = ranges::move_backward(x, y+7); + VERIFY( ranges::equal(x, y) && in == x+7 && out == y ); + VERIFY( ranges::equal(x, z) ); + } + + { + int x[3] = { 1, 2, 3 }; + char y[4] = { 0 }; + int z[3] = { 1, 2, 3 }; + test_container cx(x); + test_container cy(y); + auto [in, out] = ranges::move_backward(cx, cy.end()); + VERIFY( ranges::equal(x, x+3, y+1, y+4) && in.ptr == x+3 && out.ptr == y+1 ); + VERIFY( ranges::equal(x, z) ); + } + + { + std::vector x= {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in, out] = ranges::move_backward(x, ranges::end(y)); + VERIFY( in.base() == x.data()+3 ); + VERIFY( out.base() == y.data() ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } + + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in, out] = ranges::move_backward(x, ranges::end(y)); + VERIFY( in.base() == x.data()+3 ); + VERIFY( out.base() == y.data() ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in,out] = ranges::move_backward(make_reverse_iterator(x.end()), + make_reverse_iterator(x.begin()), + make_reverse_iterator(y.begin())); + VERIFY( in.base().base() == x.data()+3 ); + VERIFY( out.base().base() == y.data()+3 ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } + + { + std::vector x = {1,2,3}; + std::vector y(3); + const int z[3] = { 1, 2, 3 }; + auto [in,out] = ranges::move_backward(make_reverse_iterator(x.end()), + make_reverse_iterator(x.begin()), + make_reverse_iterator(y.begin())); + VERIFY( in.base().base() == x.data()+3 ); + VERIFY( out.base().base() == y.data()+3 ); + VERIFY( ranges::equal(y, z) && ranges::equal(x, z) ); + } +} + +void +test02() +{ + X x[] = { {2}, {2}, {6}, {8}, {10} }; + X y[] = { {2}, {6}, {8}, {10}, {11}, {2} }; + const X z[] = { {2}, {2}, {6}, {8}, {10} }; + auto [in, out] = ranges::move_backward(x, ranges::end(y)); + VERIFY( ranges::equal(x, x+5, y+1, y+6) ); + VERIFY( in == x+5 ); + VERIFY( out == y+1 ); + VERIFY( y[0].i == 2 ); + VERIFY( ranges::equal(x, z) ); + VERIFY( ranges::count(x, 1, &X::moved) == 5 ); + VERIFY( ranges::count(y, 0, &X::moved) == 6 ); +} + +constexpr bool +test03() +{ + bool ok = true; + X x[] = { {2}, {2}, {6}, {8}, {10} }; + X y[] = { {2}, {6}, {8}, {10}, {11}, {2} }; + const X z[] = { {2}, {2}, {6}, {8}, {10} }; + auto [in, out] = ranges::move_backward(x, ranges::end(y)); + ok &= ranges::equal(x, x+5, y+1, y+6); + ok &= (in == x+5); + ok &= (out == y+1); + ok &= (y[0].i == 2); + ok &= ranges::equal(x, z); + ok &= ranges::count(x, 1, &X::moved) == 5; + ok &= ranges::count(y, 0, &X::moved) == 6; + return ok; +} + +int +main() +{ + test01(); + test02(); + static_assert(test03()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/next_permutation/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/next_permutation/constrained.cc new file mode 100644 index 00000000000..e69b551a56b --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/next_permutation/constrained.cc @@ -0,0 +1,83 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {1, 2, 3, 4, 5}; + int y[] = {1, 2, 3, 4, 5}; + + for (int i = 0; i <= 5; i++) + { + test_container cx(x, x+i); + test_container cy(y, y+i); + for (int j = 0; ; j++) + { + auto found1 = std::next_permutation(cx.begin(), cx.end()); + auto [found2,last] = ranges::next_permutation(cy.begin(), cy.end()); + VERIFY( found1 == found2 ); + VERIFY( ranges::equal(cx, cy) ); + if (!found2) + break; + } + } +} + +void +test02() +{ + int x[] = {5, 4, 3, 2, 1}; + test_range rx(x); + auto [found,last] = ranges::next_permutation(rx, ranges::greater{}); + VERIFY( found && last == rx.end() ); + VERIFY( last == rx.end() ); + VERIFY( ranges::equal(rx, (int[]){5,4,3,1,2}) ); + ranges::next_permutation(rx, {}, [] (int a) { return -a; }); + VERIFY( ranges::equal(rx, (int[]){5,4,2,3,1}) ); + + VERIFY( !ranges::next_permutation(x, x).found ); + VERIFY( !ranges::next_permutation(x, x+1).found ); +} + +constexpr bool +test03() +{ + int x[] = {1,2,3}; + ranges::next_permutation(x); + return ranges::equal(x, (int[]){1,3,2}); +} + +int +main() +{ + test01(); + test02(); + static_assert(test03()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/none_of/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/none_of/constrained.cc new file mode 100644 index 00000000000..55617a97a7b --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/none_of/constrained.cc @@ -0,0 +1,88 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +struct XLess +{ + int val; + bool operator()(X& x) const { return x.i < val; } +}; + +struct ILess +{ + int val; + bool operator()(int& i) const { return i < val; } +}; + +template +struct NotZero +{ + bool operator()(T& t) const { return t != 0; } +}; + +void +test01() +{ + X x[] = { {2}, {4}, {6}, {8}, {10}, {11} }; + + VERIFY( !ranges::none_of(x, x+6, XLess{3}) ); + VERIFY( !ranges::none_of(x, x+6, ILess{3}, &X::i) ); + VERIFY( ranges::none_of(x+1, x+6, XLess{3}) ); + VERIFY( ranges::none_of(x+1, x+6, ILess{3}, &X::i) ); + VERIFY( !ranges::none_of(x, XLess{5}) ); + VERIFY( !ranges::none_of(x, ILess{5}, &X::i) ); + + test_container c(x); + VERIFY( !ranges::none_of(c, NotZero{}, &X::i) ); + + test_range r(x); + VERIFY( !ranges::none_of(r, NotZero{}, &X::i) ); + VERIFY( !ranges::none_of(r, NotZero{}, [](X& x) { return &x; }) ); +} + +struct Y { int i; int j; }; + +void +test02() +{ + static constexpr Y y[] = { {1,2}, {2,4}, {3,6} }; + static_assert(!ranges::none_of(y, [](int i) { return i%2 == 0; }, &Y::i)); + static_assert(!ranges::none_of(y, [](const Y& y) { return y.i + y.j == 3; })); + static_assert(ranges::none_of(y, [](const Y& y) { return y.i == y.j; })); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc new file mode 100644 index 00000000000..34f3013b199 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc @@ -0,0 +1,76 @@ +// Copyright (C) 2020 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 run { target c++2a } } +// { dg-require-cstdint "" } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::random_access_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[50]; + std::iota(x, x+50, 0); + + auto pred = std::greater{}; + auto proj = [] (int a) { return -a; }; + for (int i = 0; i < 50; i++) + { + test_range rx(x); + std::ranlux48_base g(i); + ranges::shuffle(rx, g); + + auto result = ranges::nth_element(rx, rx.begin()+i, pred, proj); + VERIFY( result == rx.end() ); + VERIFY( x[i] == i ); + for (int j = 0; j < i; j++) + for (int k = i; k < 50; k++) + VERIFY( !pred(proj(x[k]), proj(x[j])) ); + + result = ranges::nth_element(rx, rx.begin()+i, pred); + VERIFY( result == rx.end() ); + VERIFY( x[i] == 49-i ); + for (int j = 0; j < i; j++) + for (int k = i; k < 50; k++) + VERIFY( !pred(x[k], x[j]) ); + } +} + +constexpr bool +test02() +{ + int x[] = {5,2,1,3,4}; + ranges::nth_element(x, x+3); + return x[3] == 4; +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc new file mode 100644 index 00000000000..430e3c0b61b --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc @@ -0,0 +1,84 @@ +// Copyright (C) 2020 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 run { target c++2a } } +// { dg-require-cstdint "" } + +#include +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::random_access_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + for (unsigned size = 0; size < 50; ++size) + { + std::vector vref(size); + std::iota(vref.begin(), vref.end(), 0); + std::vector v1(vref), v2(vref); + test_container c + = {&v1[0], &v1[0] + size}; + test_range r + = {&v2[0], &v2[0] + size}; + + std::ranlux48_base g1(size), g2(size + 1); + ranges::shuffle(c, g1); + ranges::shuffle(ranges::begin(r), ranges::end(r), g2); + + for (unsigned middle = 0; middle < std::min(size, 10U); ++middle) + { + auto res1 = ranges::partial_sort(c.begin(), c.begin()+middle, c.end(), + {}, std::negate<>{}); + VERIFY( res1 == c.end() ); + + auto res2 = ranges::partial_sort(r, + ranges::begin(r)+middle, + ranges::greater{}); + VERIFY( res2 == ranges::end(r) ); + + VERIFY( ranges::equal(c.begin(), c.begin()+middle, + r.begin(), r.begin()+middle) ); + VERIFY( ranges::equal(c.begin(), c.begin()+middle, + vref.rbegin(), vref.rbegin()+middle) ); + } + } +} + +constexpr bool +test02() +{ + int x[] = { 5,4,1,3,2 }; + const int y[] = { 1,2,3 }; + ranges::partial_sort(x, x+3, x+5); + return ranges::equal(x, x+3, y, y+3); +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc new file mode 100644 index 00000000000..6b586f885dd --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc @@ -0,0 +1,97 @@ +// Copyright (C) 2020 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 run { target c++2a } } +// { dg-require-cstdint "" } + +#include +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::random_access_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + for (unsigned size = 0; size < 50; ++size) + { + std::vector vref(size); + std::iota(vref.begin(), vref.end(), 0); + std::vector v1(vref), v2(vref); + + std::ranlux48_base g1(size), g2(size + 1); + ranges::shuffle(v1, g1); + ranges::shuffle(v2, g2); + + for (unsigned middle = 0; middle < 10; ++middle) + { + test_container c + = {&v1[0], &v1[0] + size}; + test_range r + = {&v2[0], &v2[0] + size}; + + std::vector o1(middle), o2(middle); + test_range w1 + = {&o1[0], &o1[0]+middle}; + test_range w2 + = {&o2[0], &o2[0]+middle}; + + auto [in1, out1] = ranges::partial_sort_copy(c.begin(), c.end(), + w1.begin(), w1.end(), + {}, + std::negate<>{}, + std::negate<>{}); + VERIFY( in1 == c.end() ); + VERIFY( out1 == w1.begin() + std::min(size, middle) ); + + auto [in2,out2] = ranges::partial_sort_copy(r, w2, ranges::greater{}); + VERIFY( in2 == ranges::end(r) ); + VERIFY( out2 == w2.begin() + std::min(size, middle) ); + + VERIFY( ranges::equal(w1.begin(), out1, w2.begin(), out2) ); + VERIFY( ranges::equal(w1.begin(), out1, + vref.rbegin(), + vref.rbegin()+(out1-w1.begin())) ); + } + } +} + +constexpr bool +test02() +{ + int x[] = { 5,4,1,3,2 }; + int w[3]; + const int y[] = { 1,2,3 }; + ranges::partial_sort_copy(x, x+5, w, w+3); + return ranges::equal(w, y); +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/partition/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/partition/constrained.cc new file mode 100644 index 00000000000..4e5fa5e32cd --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/partition/constrained.cc @@ -0,0 +1,71 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +template typename wrapper> +void +test01() +{ + { + int x[] = {1,2,3,4,5,6,7,8,9,10}; + test_container cx(x); + auto range = ranges::partition(cx, [] (int a) { return a%2==0; }); + VERIFY( range.begin().ptr == x+5 ); + VERIFY( range.end().ptr == x+10 ); + VERIFY( ranges::is_partitioned(cx, [] (int a) { return a%2==0; }) ); + } + + { + int x[] = {1,2,3,4,5,6,7,8}; + test_range rx(x); + auto range = ranges::partition(rx, + [] (int a) { return a%2==0; }, + [] (int a) { return a+1; }); + VERIFY( range.begin().ptr == x+4 ); + VERIFY( range.end().ptr == x+8 ); + VERIFY( ranges::is_partitioned(rx, [] (int a) { return a%2==1; }) ); + } +} + +constexpr bool +test02() +{ + int x[] = {1,2,3,4,5,6,7,8,9,10}; + auto range = ranges::partition(x, x+9, [] (int a) { return a < 100; }); + return (range.begin() == x+9 && range.end() == x+9); +} + +int +main() +{ + test01(); + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/partition_copy/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/partition_copy/constrained.cc new file mode 100644 index 00000000000..8ed6e24d451 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/partition_copy/constrained.cc @@ -0,0 +1,81 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + { + int x[] = {1,2,3,4,5,6,7,8,9,10,11}; + int y[5], z[6]; + test_container cx(x); + test_container cy(y), cz(z); + auto pred = [] (int a) { return a%2==0; }; + auto [in,out_true,out_false] + = ranges::partition_copy(cx, cy.begin(), cz.begin(), pred); + VERIFY( in.ptr == x+11 ); + VERIFY( out_true.ptr == y+5 ); + VERIFY( out_false.ptr == z+6 ); + VERIFY( ranges::all_of(cy, pred) ); + VERIFY( ranges::none_of(cz, pred) ); + } + + { + int x[] = {1,2,3,4,5,6,7,8,9,10,11}; + int y[6], z[5]; + test_range cx(x); + test_range cy(y), cz(z); + auto pred = [] (int a) { return a%2==0; }; + auto proj = [] (int a) { return a+1; }; + auto [in,out_true,out_false] + = ranges::partition_copy(cx, cy.begin(), cz.begin(), pred, proj); + VERIFY( in.ptr == x+11 ); + VERIFY( out_true.ptr == y+6 ); + VERIFY( out_false.ptr == z+5 ); + VERIFY( ranges::none_of(y, pred) ); + VERIFY( ranges::all_of(z, pred) ); + } +} + +constexpr bool +test02() +{ + int x[] = {1,2,3,4,5,6,7,8,9,10}; + auto range = ranges::partition(x, x+9, [] (int a) { return a < 100; }); + return (range.begin() == x+9 && range.end() == x+9); +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/partition_point/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/partition_point/constrained.cc new file mode 100644 index 00000000000..2a430f23438 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/partition_point/constrained.cc @@ -0,0 +1,67 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + for (int k = 1; k <= 7; k++) + { + int x[] = {1,2,3,4,5,6,7}; + test_container cx(x); + auto pred = [&] (int a) { return a <= k; }; + auto middle = ranges::partition_point(cx, pred); + VERIFY( middle.ptr == x+k ); + } + + for (int k = 1; k <= 8; k++) + { + int x[] = {1,2,3,4,5,6,7,8}; + test_range rx(x); + auto pred = [&] (int a) { return a > -k; }; + auto proj = [] (int a) { return -a; }; + auto middle = ranges::partition_point(rx, pred, proj); + VERIFY( middle.ptr == x+k-1 ); + } +} + +constexpr bool +test02() +{ + int x[] = {1,2,3,4,5}; + return (ranges::partition_point(x, x+5, [] (int a) { return a < 6; }) == x+5 + && ranges::partition_point(x, x+5, [] (int a) { return a < 0; }) == x); +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/prev_permutation/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/prev_permutation/constrained.cc new file mode 100644 index 00000000000..25bbad9be0c --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/prev_permutation/constrained.cc @@ -0,0 +1,84 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {5, 4, 3, 2, 1}; + int y[] = {5, 4, 3, 2, 1}; + + for (int i = 0; i <= 5; i++) + { + test_container cx(x, x+i); + test_container cy(y, y+i); + for (int j = 0; ; j++) + { + auto found1 = std::prev_permutation(cx.begin(), cx.end()); + auto [found2,last] = ranges::prev_permutation(cy.begin(), cy.end()); + VERIFY( found1 == found2 ); + VERIFY( ranges::equal(cx, cy) ); + if (!found2) + break; + } + } +} + +void +test02() +{ + int x[] = {1, 2, 3, 4, 5}; + test_range rx(x); + auto [found,last] = ranges::prev_permutation(rx, ranges::greater{}); + VERIFY( found && last == rx.end() ); + VERIFY( last == rx.end() ); + VERIFY( ranges::equal(rx, (int[]){1,2,3,5,4}) ); + ranges::prev_permutation(rx, {}, [] (int a) { return -a; }); + VERIFY( ranges::equal(rx, (int[]){1,2,4,3,5}) ); + + VERIFY( !ranges::prev_permutation(x, x).found ); + VERIFY( !ranges::prev_permutation(x, x+1).found ); +} + +constexpr bool +test03() +{ + int x[] = {3,2,1}; + ranges::prev_permutation(x); + return ranges::equal(x, (int[]){3,1,2}); +} + +int +main() +{ + test01(); + test02(); + static_assert(test03()); +} + diff --git a/libstdc++-v3/testsuite/25_algorithms/remove/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/remove/constrained.cc new file mode 100644 index 00000000000..39a002f3cb6 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/remove/constrained.cc @@ -0,0 +1,97 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; +}; + +void +test01() +{ + int x[5] = { 1, 2, 3, 4, 5 }; + const int y[4] = { 1, 2, 4, 5 }; + auto res = ranges::remove(x, 3); + VERIFY( res.begin() == x+4 && res.end() == x+5 ); + VERIFY( ranges::equal(x, x+4, y, y+4) ); +} + +void +test02() +{ + int x[1]; + test_container c(x, x); + auto res = ranges::remove(c, 1); + VERIFY( res.begin().ptr == x && res.end().ptr == x ); +} + +void +test03() +{ + int x[1] = {1}; + test_container c(x); + auto res = ranges::remove(c, 0); + VERIFY( res.begin().ptr == x+1 && res.end().ptr == x+1 ); + res = ranges::remove(c, 1); + VERIFY( res.begin().ptr == x && res.end().ptr == x+1 ); +} + +void +test04() +{ + X x[8] = { {0}, {1}, {0}, {1}, {0}, {0}, {1}, {1} }; + const int y[4] = { 0, 0, 0, 0 }; + test_container c(x); + auto res = ranges::remove(c, 1, &X::i); + VERIFY( res.begin().ptr == x+4 && res.end().ptr == x+8 ); + VERIFY( ranges::equal(x, x+4, y, y+4, {}, &X::i) ); +} + +constexpr bool +test05() +{ + int x[6] = { 3, 2, 3, 3, 5, 3 }; + const int y[2] = { 2, 5 }; + auto res = ranges::remove(x, 3); + return ranges::equal(x, res.begin(), y, y+2); +} + + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + static_assert(test05()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/remove_copy/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/remove_copy/constrained.cc new file mode 100644 index 00000000000..0cf65a727b8 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/remove_copy/constrained.cc @@ -0,0 +1,109 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; + + friend constexpr bool + operator==(const X& a, const X& b) + { + return a.i == b.i; + } +}; + +void +test01() +{ + { + const X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[4]; + X z[4] = { {2}, {2}, {6}, {10} }; + auto [in,out] = ranges::remove_copy(x, x+5, y, 8, &X::i); + VERIFY( in == x+5 && out == y+4 ); + VERIFY( ranges::equal(y, z) ); + } + + { + const X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[5]; + X z[5] = { {2}, {2}, {6}, {8}, {10} }; + auto [in,out] = ranges::remove_copy(x, x+5, y, 11, &X::i); + VERIFY( in == x+5 && out == y+5 ); + VERIFY( ranges::equal(x, x+5, y, y+5) && ranges::equal(y, z) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {2} }; + X y[3]; + X z[3] = { {6}, {8}, {10} }; + test_container cx(x), cy(y), cz(z); + auto [in, out] = ranges::remove_copy(cx, cy.begin(), 2, &X::i); + VERIFY( in == cx.end() && out == cy.end() ); + VERIFY( ranges::equal(cy, cz) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[4]; + const X z[4] = { {6}, {8}, {10}, {11} }; + test_range cx(x); + test_range cy(y); + auto [in, out] = ranges::remove_copy(cx, cy.begin(), 2, &X::i); + VERIFY( in == cx.end() && out == cy.end() ); + VERIFY( ranges::equal(y, z) ); + } +} + +struct Y { int i; int j; }; + +constexpr bool +test02() +{ + bool ok = true; + Y x[3] = { {3,2}, {2,4}, {3,6} }; + Y y[1]; + Y z[1] = { {2,4} }; + auto [in, out] = ranges::remove_copy(x, y, 3, &Y::i); + ok &= in == x+3; + ok &= out == y+1; + ok &= ranges::equal(y, z, {}, &Y::i, &Y::i); + ok &= ranges::equal(y, z, {}, &Y::j, &Y::j); + return ok; +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/remove_copy_if/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/remove_copy_if/constrained.cc new file mode 100644 index 00000000000..b7c239ff397 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/remove_copy_if/constrained.cc @@ -0,0 +1,113 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; + + friend constexpr bool + operator==(const X& a, const X& b) + { + return a.i == b.i; + } +}; + +void +test01() +{ + auto is_negative_p = [] (int a) { return a < 0; }; + auto is_two_p = [] (int a) { return a == 2; }; + + { + const X x[6] = { {2}, {2}, {6}, {8}, {2}, {11} }; + X y[2]; + X z[2] = { {6}, {8} }; + auto [in, out] = ranges::remove_copy_if(x, x+5, y, is_two_p, &X::i); + VERIFY( in == x+5 && out == y+2 ); + VERIFY( ranges::equal(y, z) ); + } + + { + const X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[5]; + X z[5] = { {2}, {2}, {6}, {8}, {10} }; + auto [in, out] = ranges::remove_copy_if(x, x+5, y, is_negative_p, &X::i); + VERIFY( in == x+5 && out == y+5 ); + VERIFY( ranges::equal(x, x+5, y, y+5) && ranges::equal(y, z) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[4]; + X z[4] = { {6}, {8}, {10}, {11} }; + test_container cx(x), cy(y), cz(z); + auto [in, out] = ranges::remove_copy_if(cx, cy.begin(), is_two_p, &X::i); + VERIFY( in == cx.end() && out == cy.end() ); + VERIFY( ranges::equal(cy, cz) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[4]; + const X z[4] = { {6}, {8}, {10}, {11} }; + test_range cx(x); + test_range cy(y); + auto [in, out] = ranges::remove_copy_if(cx, cy.begin(), is_two_p, &X::i); + VERIFY( in == cx.end() && out == cy.end() ); + VERIFY( ranges::equal(y, z) ); + } +} + +struct Y { int i; int j; }; + +constexpr bool +test02() +{ + bool ok = true; + Y x[3] = { {3,2}, {2,4}, {3,6} }; + Y y[1]; + Y z[1] = { {2,4} }; + auto [in, out] + = ranges::remove_copy_if(x, y, [] (int a) { return a%2 == 1; }, &Y::i); + ok &= in == x+3; + ok &= out == y+1; + ok &= ranges::equal(y, z, {}, &Y::i, &Y::i); + ok &= ranges::equal(y, z, {}, &Y::j, &Y::j); + return ok; +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/remove_if/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/remove_if/constrained.cc new file mode 100644 index 00000000000..1abc231ab93 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/remove_if/constrained.cc @@ -0,0 +1,97 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; +}; + +void +test01() +{ + int x[5] = { 1, 2, 3, 4, 5 }; + const int y[4] = { 1, 2, 4, 5 }; + auto res = ranges::remove_if(x, [] (int a) { return a == 3; }); + VERIFY( res.begin() == x+4 && res.end() == x+5 ); + VERIFY( ranges::equal(x, x+4, y, y+4) ); +} + +void +test02() +{ + int x[1]; + test_container c(x, x); + auto res = ranges::remove_if(c, [] (int a) { return a == 1; }); + VERIFY( res.begin().ptr == x && res.end().ptr == x ); +} + +void +test03() +{ + int x[1] = {1}; + test_container c(x); + auto res = ranges::remove_if(c, [] (int a) { return a == 0; }); + VERIFY( res.begin().ptr == x+1 && res.end().ptr == x+1 ); + res = ranges::remove_if(c, [] (int a) { return a == 1; }); + VERIFY( res.begin().ptr == x && res.end().ptr == x+1 ); +} + +void +test04() +{ + X x[8] = { {0}, {1}, {0}, {1}, {0}, {0}, {1}, {1} }; + const int y[4] = { 0, 0, 0, 0 }; + test_range c(x); + auto res = ranges::remove_if(c, [] (int a) { return a == 1; }, &X::i); + VERIFY( res.begin().ptr == x+4 && res.end().ptr == x+8 ); + VERIFY( ranges::equal(x, x+4, y, y+4, {}, &X::i) ); +} + +constexpr bool +test05() +{ + int x[6] = { 3, 2, 3, 3, 5, 3 }; + const int y[2] = { 2, 5 }; + auto res = ranges::remove_if(x, [] (int a) { return a == 3; }); + return ranges::equal(x, res.begin(), y, y+2); +} + + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + static_assert(test05()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/replace/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/replace/constrained.cc new file mode 100644 index 00000000000..3546872b72f --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/replace/constrained.cc @@ -0,0 +1,104 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; + + friend constexpr bool + operator==(const X& a, const X& b) + { + return a.i == b.i; + } +}; + +void +test01() +{ + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[6] = { {2}, {2}, {6}, {9}, {10}, {11} }; + auto res = ranges::replace(x, x+5, 8, X{9}, &X::i); + VERIFY( res == x+5 ); + VERIFY( ranges::equal(x, y) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + auto res = ranges::replace(x, x+5, 7, X{9}, &X::i); + VERIFY( res == x+5 ); + VERIFY( ranges::equal(x, y) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[6] = { {7}, {7}, {6}, {8}, {10}, {11} }; + test_container cx(x), cy(y); + auto res = ranges::replace(cx, 2, X{7}, &X::i); + VERIFY( res == cx.end() ); + VERIFY( ranges::equal(cx, cy) ); + } + + { + int x[6] = { {2}, {2}, {6}, {8}, {10}, {2} }; + int y[6] = { {7}, {7}, {6}, {8}, {10}, {7} }; + test_range rx(x), ry(y); + auto res = ranges::replace(rx, 2, 7); + VERIFY( res == rx.end() ); + + rx.bounds.first = x; + ry.bounds.first = y; + VERIFY( ranges::equal(rx, ry) ); + } +} + +struct Y { int i; int j; }; + +constexpr bool +test02() +{ + bool ok = true; + Y x[] = { {3,2}, {2,4}, {3,6} }; + Y y[] = { {4,5}, {2,4}, {4,5} }; + auto res = ranges::replace(x, 3, Y{4,5}, &Y::i); + ok &= res == x+3; + ok &= ranges::equal(x, y, {}, &Y::i, &Y::i); + ok &= ranges::equal(x, y, {}, &Y::j, &Y::j); + return ok; +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/replace_copy/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/replace_copy/constrained.cc new file mode 100644 index 00000000000..12e76a4cfdf --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/replace_copy/constrained.cc @@ -0,0 +1,109 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; + + friend constexpr bool + operator==(const X& a, const X& b) + { + return a.i == b.i; + } +}; + +void +test01() +{ + { + const X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[5]; + X z[5] = { {2}, {2}, {6}, {9}, {10} }; + auto [in,out] = ranges::replace_copy(x, x+5, y, 8, X{9}, &X::i); + VERIFY( in == x+5 && out == y+5 ); + VERIFY( ranges::equal(y, z) ); + } + + { + const X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[5]; + X z[5] = { {2}, {2}, {6}, {8}, {10} }; + auto [in,out] = ranges::replace_copy(x, x+5, y, 7, X{9}, &X::i); + VERIFY( in == x+5 && out == y+5 ); + VERIFY( ranges::equal(x, x+5, y, y+5) && ranges::equal(y, z) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[6]; + X z[6] = { {7}, {7}, {6}, {8}, {10}, {11} }; + test_container cx(x), cy(y), cz(z); + auto [in, out] = ranges::replace_copy(cx, cy.begin(), 2, X{7}, &X::i); + VERIFY( in == cx.end() && out == cy.end() ); + VERIFY( ranges::equal(cy, cz) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[6]; + const X z[6] = { {7}, {7}, {6}, {8}, {10}, {11} }; + test_range cx(x); + test_range cy(y); + auto [in, out] = ranges::replace_copy(cx, cy.begin(), 2, X{7}, &X::i); + VERIFY( in == cx.end() && out == cy.end() ); + VERIFY( ranges::equal(y, z) ); + } +} + +struct Y { int i; int j; }; + +constexpr bool +test02() +{ + bool ok = true; + Y x[] = { {3,2}, {2,4}, {3,6} }; + Y y[] = { {4,5}, {2,4}, {4,5} }; + Y z[] = { {4,5}, {2,4}, {4,5} }; + auto [in, out] = ranges::replace_copy(x, y, 3, Y{4,5}, &Y::i); + ok &= in == x+3; + ok &= out == y+3; + ok &= ranges::equal(y, z, {}, &Y::i, &Y::i); + ok &= ranges::equal(y, z, {}, &Y::j, &Y::j); + return ok; +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/replace_copy_if/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/replace_copy_if/constrained.cc new file mode 100644 index 00000000000..9186a0a3d6c --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/replace_copy_if/constrained.cc @@ -0,0 +1,118 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; + + friend constexpr bool + operator==(const X& a, const X& b) + { + return a.i == b.i; + } +}; + +void +test01() +{ + auto is_negative_p = [] (int a) { return a < 0; }; + auto is_two_p = [] (int a) { return a == 2; }; + + { + const X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[5]; + X z[5] = { {9}, {9}, {6}, {8}, {10} }; + auto [in, out] = ranges::replace_copy_if(x, x+5, y, + is_two_p, X{9}, &X::i); + VERIFY( in == x+5 && out == y+5 ); + VERIFY( ranges::equal(y, z) ); + } + + { + const X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[5]; + X z[5] = { {2}, {2}, {6}, {8}, {10} }; + auto [in, out] = ranges::replace_copy_if(x, x+5, y, + is_negative_p, X{9}, &X::i); + VERIFY( in == x+5 && out == y+5 ); + VERIFY( ranges::equal(x, x+5, y, y+5) && ranges::equal(y, z) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[6]; + X z[6] = { {7}, {7}, {6}, {8}, {10}, {11} }; + test_container cx(x), cy(y), cz(z); + auto [in, out] = ranges::replace_copy_if(cx, cy.begin(), + is_two_p, X{7}, &X::i); + VERIFY( in == cx.end() && out == cy.end() ); + VERIFY( ranges::equal(cy, cz) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[6]; + const X z[6] = { {7}, {7}, {6}, {8}, {10}, {11} }; + test_range cx(x); + test_range cy(y); + auto [in, out] = ranges::replace_copy_if(cx, cy.begin(), + is_two_p, X{7}, &X::i); + VERIFY( in == cx.end() && out == cy.end() ); + VERIFY( ranges::equal(y, z) ); + } +} + +struct Y { int i; int j; }; + +constexpr bool +test02() +{ + bool ok = true; + Y x[] = { {3,2}, {2,4}, {3,6} }; + Y y[] = { {4,5}, {2,4}, {4,5} }; + Y z[] = { {4,5}, {2,4}, {4,5} }; + auto [in, out] + = ranges::replace_copy_if(x, y, + [] (int a) { return a%2 == 1; }, Y{4,5}, &Y::i); + ok &= in == x+3; + ok &= out == y+3; + ok &= ranges::equal(y, z, {}, &Y::i, &Y::i); + ok &= ranges::equal(y, z, {}, &Y::j, &Y::j); + return ok; +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/replace_if/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/replace_if/constrained.cc new file mode 100644 index 00000000000..8ebcc411997 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/replace_if/constrained.cc @@ -0,0 +1,109 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; + + friend constexpr bool + operator==(const X& a, const X& b) + { + return a.i == b.i; + } +}; + +void +test01() +{ + auto is_even_p = [] (int a) { return a%2 == 0; }; + auto is_negative_p = [] (int a) { return a < 0; }; + auto is_two_p = [] (int a) { return a == 2; }; + { + X x[6] = { {1}, {2}, {6}, {8}, {10}, {11} }; + X y[6] = { {1}, {9}, {9}, {9}, {9}, {11} }; + auto res = ranges::replace_if(x, x+5, is_even_p, X{9}, &X::i); + VERIFY( res == x+5 ); + VERIFY( ranges::equal(x, y) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + auto res = ranges::replace_if(x, x+5, is_negative_p, X{9}, &X::i); + VERIFY( res == x+5 ); + VERIFY( ranges::equal(x, y) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {10}, {11} }; + X y[6] = { {7}, {7}, {6}, {8}, {10}, {11} }; + test_container cx(x), cy(y); + auto res = ranges::replace_if(cx, is_two_p, X{7}, &X::i); + VERIFY( res == cx.end() ); + VERIFY( ranges::equal(cx, cy) ); + } + + { + int x[6] = { {2}, {2}, {6}, {8}, {10}, {2} }; + int y[6] = { {7}, {7}, {6}, {8}, {10}, {7} }; + test_range rx(x), ry(y); + auto res = ranges::replace_if(rx, is_two_p, 7); + VERIFY( res == rx.end() ); + + rx.bounds.first = x; + ry.bounds.first = y; + VERIFY( ranges::equal(rx, ry) ); + } +} + +struct Y { int i; int j; }; + +constexpr bool +test02() +{ + bool ok = true; + Y x[] = { {3,2}, {2,4}, {3,6} }; + Y y[] = { {4,5}, {2,4}, {4,5} }; + auto res = ranges::replace_if(x, [] (int a) { return a%2 == 1; }, + Y{4,5}, &Y::i); + ok &= res == x+3; + ok &= ranges::equal(x, y, {}, &Y::i, &Y::i); + ok &= ranges::equal(x, y, {}, &Y::j, &Y::j); + return ok; +} + +int +main() +{ + test01(); + static_assert(test02()); +} + diff --git a/libstdc++-v3/testsuite/25_algorithms/reverse/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/reverse/constrained.cc new file mode 100644 index 00000000000..58cec27b5a0 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/reverse/constrained.cc @@ -0,0 +1,77 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::test_container; +using __gnu_test::bidirectional_iterator_wrapper; +using __gnu_test::random_access_iterator_wrapper; + +namespace ranges = std::ranges; + +template typename wrapper> +void +test01() +{ + int x[] = { 1, 2, 3, 4 }; + test_container cx(x); + const int y[] = { 4, 3, 2, 1 }; + + auto res = ranges::reverse(cx); + VERIFY( res == ranges::end(cx) ); + VERIFY( ranges::equal(cx, y) ); +} + +template typename wrapper> +void +test02() +{ + int x[] = { 1, 2, 3, 4, 5 }; + test_range rx(x); + const int y[] = { 5, 4, 3, 2, 1 }; + + auto res = ranges::reverse(rx); + VERIFY( res == ranges::end(rx) ); + VERIFY( ranges::equal(rx, y) ); +} + +constexpr bool +test03() +{ + int x[] = { 1, 2, 3 }; + const int y[] = { 2, 1, 3 }; + ranges::reverse(x, x+2); + return ranges::equal(x, y); +} + +int +main() +{ + test01(); + test02(); + + test01(); + test02(); + + static_assert(test03()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/reverse_copy/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/reverse_copy/constrained.cc new file mode 100644 index 00000000000..1ee40bedb39 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/reverse_copy/constrained.cc @@ -0,0 +1,74 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::test_container; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = { 1, 2, 3, 4 }; + int w[4]; + test_container cx(x), cw(w); + const int y[] = { 4, 3, 2, 1 }; + + auto [in,out] = ranges::reverse_copy(cx, cw.begin()); + VERIFY( in == ranges::end(cx) && out == cw.end() ); + VERIFY( ranges::equal(cw, y) ); +} + +void +test02() +{ + int x[] = { 1, 2, 3, 4, 5 }; + int w[5]; + test_range rx(x), rw(w); + const int y[] = { 5, 4, 3, 2, 1 }; + + auto [in,out] = ranges::reverse_copy(rx, ranges::begin(rw)); + VERIFY( in == ranges::end(rx) && out == ranges::end(rw) ); + VERIFY( ranges::equal(rw, y) ); +} + +constexpr bool +test03() +{ + const int x[] = { 1, 2, 3 }; + int w[2]; + const int y[] = { 2, 1 }; + ranges::reverse_copy(x, x+2, w); + return ranges::equal(w, y); +} + +int +main() +{ + test01(); + test02(); + + static_assert(test03()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/rotate/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/rotate/constrained.cc new file mode 100644 index 00000000000..34095e743ad --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/rotate/constrained.cc @@ -0,0 +1,97 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::bidirectional_iterator_wrapper; +using __gnu_test::random_access_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; + X (int a) : i(a) { } + + friend bool + operator==(const X& lhs, const X& rhs) + { + return lhs.i == rhs.i; + } +}; + +static_assert(!std::is_trivial_v); + +template typename> typename container, + template typename wrapper, + typename T = int> +void +test01() +{ + for (int a = 0; a <= 7; a++) + { + T x[] = {1, 2, 3, 4, 5, 6, 7}; + container rx(x); + auto i = ranges::begin(rx); + std::advance(i, a); + auto res = ranges::rotate(rx, i); + if (a == 0) + VERIFY( ranges::begin(res) == ranges::end(rx) ); + else + VERIFY( ranges::begin(res) + == std::next(ranges::begin(rx), + ranges::distance(i, ranges::end(rx))) ); + VERIFY( ranges::end(res) == ranges::end(rx) ); + for (int k = 0; k < 7; k++) + VERIFY( x[k] == (k+a)%7 + 1 ); + } +} + +constexpr bool +test02() +{ + int x[] = {1, 2, 3, 4}; + const int y[] = { 2, 3, 1, 4 }; + ranges::rotate(x, x+1, x+3); + return ranges::equal(x, y); +} + +int +main() +{ + test01(); + test01(); + + test01(); + test01(); + + test01(); + test01(); + + test01(); + test01(); + + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/rotate_copy/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/rotate_copy/constrained.cc new file mode 100644 index 00000000000..f036377817b --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/rotate_copy/constrained.cc @@ -0,0 +1,93 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::random_access_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; + X () : i(0) { } + X (int a) : i(a) { } + + friend bool + operator==(const X& lhs, const X& rhs) + { + return lhs.i == rhs.i; + } +}; + +static_assert(!std::is_trivial_v); + +template typename> typename container, + template typename wrapper, + typename T = int> +void +test01() +{ + for (int a = 0; a <= 7; a++) + { + T x[] = {1, 2, 3, 4, 5, 6, 7}; + T w[7]; + container rx(x), rw(w); + auto i = ranges::begin(rx); + std::advance(i, a); + auto [in,out] = ranges::rotate_copy(rx, i, ranges::begin(rw)); + VERIFY( in == ranges::end(rx) ); + VERIFY( out == ranges::end(rw) ); + for (int k = 0; k < 7; k++) + VERIFY( w[k] == (k+a)%7 + 1 ); + } +} + +constexpr bool +test02() +{ + const int x[] = {1, 2, 3, 4}; + int w[3]; + const int y[] = { 2, 3, 1}; + auto [in,out] = ranges::rotate_copy(x, x+1, x+3, w); + return (in == x+3 + && out == w+3 + && ranges::equal(w, y)); +} + +int +main() +{ + test01(); + test01(); + + test01(); + test01(); + + test01(); + test01(); + + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/search/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/search/constrained.cc new file mode 100644 index 00000000000..314d9d2acf0 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/search/constrained.cc @@ -0,0 +1,88 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + X x[] = { {2}, {6}, {8}, {10}, {11} }; + X y[] = { {10}, {11} }; + { + + test_container c(x); + auto res = ranges::search(c, y, {}, &X::i, &X::i); + VERIFY( std::get<0>(res)->i == 10 && std::get<1>(res) == ranges::end(c) ); + res = ranges::search(c, c, {}, &X::i, &X::i); + VERIFY( std::get<0>(res) == ranges::begin(c) + && std::get<1>(res) == ranges::end(c) ); + } + + { + test_range r(x); + auto res = ranges::search(r, y, {}, &X::i, &X::i); + VERIFY( std::get<0>(res)->i == 10 && std::get<1>(res) == ranges::end(r) ); + res = ranges::search(r, r, {}, &X::i, &X::i); + VERIFY( std::get<0>(res) == ranges::begin(r) + && std::get<1>(res) == ranges::end(r) ); + } +} + +void +test02() +{ + static constexpr X x[] = { {2}, {2}, {6}, {8}, {10}, {11} }; + static constexpr X y[] = { {6}, {8} }; + static constexpr int z[] = { 2, 8 }; + static constexpr int w[] = { 2 }; + + static_assert(std::get<0>(ranges::search(x, y, {}, &X::i, &X::i)) == x+2); + static_assert(std::get<1>(ranges::search(x, y, {}, &X::i, &X::i)) == x+4); + + static_assert(std::get<0>(ranges::search(x, z, {}, &X::i)) == x+6); + static_assert(std::get<1>(ranges::search(x, z, {}, &X::i)) == x+6); + + static_assert(std::get<0>(ranges::search(x, w, {}, &X::i)) == x+0); + static_assert(std::get<1>(ranges::search(x, w, {}, &X::i)) == x+1); + + static_assert(std::get<0>(ranges::search(x, x+6, w, w, {}, &X::i)) == x+0); + static_assert(std::get<1>(ranges::search(x, x+6, w, w, {}, &X::i)) == x+0); + + static_assert(std::get<0>(ranges::search(x, x, w, w+1, {}, &X::i)) == x+0); + static_assert(std::get<1>(ranges::search(x, x, w, w+1, {}, &X::i)) == x+0); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/search_n/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/search_n/constrained.cc new file mode 100644 index 00000000000..c1ac6da4bf8 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/search_n/constrained.cc @@ -0,0 +1,80 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + int x[] = { {2}, {2}, {6}, {8}, {10}, {11} }; + auto res = ranges::search_n(x+0, x+6, 2, 2); + VERIFY( res.begin() == x+0 && res.end() == x+2 ); + + int z[] = { {1}, {2}, {2}, {4}, {5}, {6} }; + res = ranges::search_n(z, 3, 3, std::greater()); + VERIFY( res.begin() == z+3 && res.end() == z+6 ); + + test_container cx(x); + auto res2 = ranges::search_n(cx, 2, 2); + VERIFY( res2.begin() == cx.begin() && *res2.end() == 6 ); + + int y[] = { {2}, {2}, {8}, {2}, {2}, {2}, {5} }; + test_range ry(y); + auto res3 = ranges::search_n(ry, 3, 2); + VERIFY( *res3.begin() == 2 && *res3.end() == 5 ); + + auto res4 = ranges::search_n(ry, 1, 8); + VERIFY( res4.begin().ptr == y+2 && res4.end().ptr == y+3 ); +} + +void +test02() +{ + static constexpr X x[] = { {2}, {2}, {6}, {8}, {10}, {2} }; + static constexpr X y[] = { {2}, {6}, {8}, {8}, {8}, {2} }; + static constexpr int z[] = { {2}, {6}, {8}, {10}, {2}, {2} }; + + static_assert(ranges::search_n(z, 0, 5).end() == z+0); + static_assert(ranges::search_n(z, 1, 5).begin() == z+6); + static_assert(ranges::search_n(x, 2, 3, {}, &X::i).begin() == x+6); + static_assert(ranges::search_n(x, 2, 2, {}, &X::i).end() == x+2); + static_assert(ranges::search_n(y, 3, 8, {}, &X::i).begin() == y+2); + static_assert(ranges::search_n(y, 3, 8, {}, &X::i).end() == y+5); +} + +int +main() +{ + test01(); + test02(); +} + diff --git a/libstdc++-v3/testsuite/25_algorithms/set_difference/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/set_difference/constrained.cc new file mode 100644 index 00000000000..3f46a9b523e --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/set_difference/constrained.cc @@ -0,0 +1,87 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {4,2,1,1,0}; + int y[] = {3,2,1}; + int z[3]; + test_range rx(x), ry(y); + test_range rz(z); + auto [in,out] + = ranges::set_difference(rx, ry, rz.begin(), ranges::greater{}); + VERIFY( in.ptr == x+5 ); + VERIFY( out.ptr == z+3 ); + VERIFY( ranges::equal(z, (int[]){4,1,0}) ); +} + +void +test02() +{ + int x[] = {3,2,1,1,0}; + int y[] = {3,2,2,1,0}; + int z[1]; + test_container rx(x), ry(y); + test_container rz(z); + auto [in,out] + = ranges::set_difference(rx.begin(), rx.end(), + ry.begin(), ry.end(), + rz.begin(), + {}, + std::negate<>{}, + std::negate<>{}); + VERIFY( in.ptr == x+5 ); + VERIFY( out.ptr == z+1 ); + VERIFY( ranges::equal(z, (int[]){1}) ); +} + +constexpr bool +test03() +{ + bool ok = true; + int x[1] = {0}; + int y[1] = {1}; + int z[1]; + ok &= ranges::set_difference(x, x, y, y+1, z).out == z; + ok &= ranges::set_difference(x, x+1, y, y, z).out == z+1; + ok &= z[0] == 0; + return ok; +} + +int +main() +{ + test01(); + test02(); + static_assert(test03()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/set_intersection/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/set_intersection/constrained.cc new file mode 100644 index 00000000000..0db3e411871 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/set_intersection/constrained.cc @@ -0,0 +1,88 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {4,2,1,1,0}; + int y[] = {3,2,1}; + int z[2]; + test_range rx(x), ry(y); + test_range rz(z); + auto [in1,in2,out] + = ranges::set_intersection(rx, ry, rz.begin(), ranges::greater{}); + VERIFY( in1.ptr == x+5 ); + VERIFY( in2.ptr == y+3 ); + VERIFY( out.ptr == z+2 ); + VERIFY( ranges::equal(z, (int[]){2,1}) ); +} + +void +test02() +{ + int x[] = {3,2,1,1,0}; + int y[] = {3,2,1,0}; + int z[4]; + test_container rx(x), ry(y); + test_container rz(z); + auto [in1,in2,out] + = ranges::set_intersection(rx.begin(), rx.end(), + ry.begin(), ry.end(), + rz.begin(), + {}, + std::negate<>{}, + std::negate<>{}); + VERIFY( in1.ptr == x+5 ); + VERIFY( in2.ptr == y+4 ); + VERIFY( out.ptr == z+4 ); + VERIFY( ranges::equal(z, (int[]){3,2,1,0}) ); +} + +constexpr bool +test03() +{ + bool ok = true; + int x[1] = {0}; + int y[1] = {1}; + int z[1]; + ok &= ranges::set_intersection(x, x, y, y+1, z).out == z; + ok &= ranges::set_intersection(x, x+1, y, y, z).out == z; + return ok; +} + +int +main() +{ + test01(); + test02(); + static_assert(test03()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/set_symmetric_difference/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/set_symmetric_difference/constrained.cc new file mode 100644 index 00000000000..b138aee3adb --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/set_symmetric_difference/constrained.cc @@ -0,0 +1,123 @@ +// Copyright (C) 2020 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 run { target c++2a } } +// { dg-require-cstdint "" } + +#include +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {4,2,1,1,0}; + int y[] = {3,2,2,1}; + int z[5]; + test_range rx(x), ry(y); + test_range rz(z); + auto [in1,in2,out] + = ranges::set_symmetric_difference(rx, ry, rz.begin(), ranges::greater{}); + VERIFY( in1.ptr == x+5 ); + VERIFY( in2.ptr == y+4 ); + VERIFY( out.ptr == z+5 ); + VERIFY( ranges::equal(z, (int[]){4,3,2,1,0}) ); +} + +void +test02() +{ + int x[] = {3,2,1,1,0}; + int y[] = {3,2,1,0}; + int z[1]; + test_container rx(x), ry(y); + test_container rz(z); + auto [in1,in2,out] + = ranges::set_symmetric_difference(rx.begin(), rx.end(), + ry.begin(), ry.end(), + rz.begin(), + {}, + std::negate<>{}, + std::negate<>{}); + VERIFY( in1.ptr == x+5 ); + VERIFY( in2.ptr == y+4 ); + VERIFY( out.ptr == z+1 ); + VERIFY( ranges::equal(z, (int[]){1}) ); +} + +constexpr bool +test03() +{ + bool ok = true; + int x[1] = {0}; + int y[1] = {1}; + int z[1]; + ok &= ranges::set_symmetric_difference(x, x, y, y+1, z).out == z+1; + ok &= z[0] == 1; + ok &= ranges::set_symmetric_difference(x, x+1, y, y, z).out == z+1; + ok &= z[0] == 0; + return ok; +} + +void +test04() +{ + int x[15] = {5,5,5,5,5,4,4,4,4,3,3,3,2,2,1}; + int y[15] = {5,5,5,5,5,4,4,4,4,3,3,3,2,2,1}; + for (int k = 0; k < 100; k++) + { + std::ranlux48_base g(k); + ranges::shuffle(x, g); + ranges::shuffle(y, g); + ranges::sort(x, x+10); + ranges::sort(y, y+10); + + int z[15]; + auto z_out = ranges::set_symmetric_difference(x, x+10, y, y+10, z).out; + + int w1[15]; + auto w1_out = ranges::set_difference(x, x+10, y, y+10, w1).out; + + int w2[15]; + auto w2_out = ranges::set_difference(y, y+10, x, x+10, w2).out; + + int w3[15]; + auto w3_out = ranges::set_union(w1, w1_out, w2, w2_out, w3).out; + + VERIFY( ranges::equal(z, z_out, w3, w3_out) ); + } +} + +int +main() +{ + test01(); + test02(); + static_assert(test03()); + test04(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/set_union/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/set_union/constrained.cc new file mode 100644 index 00000000000..19bcd7aab9f --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/set_union/constrained.cc @@ -0,0 +1,91 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {4,2,1,1,0}; + int y[] = {3,2,1}; + int z[6]; + test_range rx(x), ry(y); + test_range rz(z); + auto [in1,in2,out] + = ranges::set_union(rx, ry, rz.begin(), + ranges::greater{}); + VERIFY( in1.ptr == x+5 ); + VERIFY( in2.ptr == y+3 ); + VERIFY( out.ptr == z+6 ); + VERIFY( ranges::equal(z, (int[]){4,3,2,1,1,0}) ); +} + +void +test02() +{ + int x[] = {4,2,1,1,0}; + int y[] = {3,2,1,1,0}; + int z[6]; + test_container rx(x), ry(y); + test_container rz(z); + auto [in1,in2,out] + = ranges::set_union(rx.begin(), rx.end(), + ry.begin(), ry.end(), + rz.begin(), + {}, + std::negate<>{}, + std::negate<>{}); + VERIFY( in1.ptr == x+5 ); + VERIFY( in2.ptr == y+5 ); + VERIFY( out.ptr == z+6 ); + VERIFY( ranges::equal(z, (int[]){4,3,2,1,1,0}) ); +} + +constexpr bool +test03() +{ + bool ok = true; + int x[1] = {0}; + int y[1] = {1}; + int z[1]; + ranges::set_union(x, x, y, y+1, z); + ok &= z[0] == 1; + ranges::set_union(x, x+1, y, y, z); + ok &= z[0] == 0; + return ok; +} + +int +main() +{ + test01(); + test02(); + static_assert(test03()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc new file mode 100644 index 00000000000..b96343aecce --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc @@ -0,0 +1,70 @@ +// Copyright (C) 2020 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 run { target c++2a } } +// { dg-require-cstdint "" } + +#include +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::random_access_iterator_wrapper; + +namespace ranges = std::ranges; + +// This test is adapted from 25_algorithms/shuffle/1.cc. + +void +test01() +{ + for (unsigned size = 0; size < 50; ++size) + { + std::vector vref(size); + std::iota(vref.begin(), vref.end(), 0); + std::vector v1(vref), v2(vref); + test_container c + = {&v1[0], &v1[0] + size}; + test_range r + = {&v2[0], &v2[0] + size}; + + std::ranlux48_base g1(size), g2(size + 1); + VERIFY( ranges::shuffle(c, g1) == c.end() ); + VERIFY( ranges::shuffle(ranges::begin(r), ranges::end(r), g2) + == ranges::end(r) ); + + if (size >= 10) + { + VERIFY( !ranges::equal(c, vref) ); + VERIFY( !ranges::equal(r, vref) ); + VERIFY( !ranges::equal(c, r) ); + } + + VERIFY( ranges::is_permutation(c, vref) ); + VERIFY( ranges::is_permutation(r, vref) ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc new file mode 100644 index 00000000000..d8227773ccb --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc @@ -0,0 +1,81 @@ +// Copyright (C) 2020 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 run { target c++2a } } +// { dg-require-cstdint "" } + +#include +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::random_access_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + for (unsigned size = 0; size < 50; ++size) + { + std::vector vref(size); + std::iota(vref.begin(), vref.end(), 0); + std::vector v1(vref), v2(vref); + test_container c + = {&v1[0], &v1[0] + size}; + test_range r + = {&v2[0], &v2[0] + size}; + + std::ranlux48_base g1(size), g2(size + 1); + ranges::shuffle(c, g1); + ranges::shuffle(ranges::begin(r), ranges::end(r), g2); + + VERIFY( ranges::sort(c) == c.end() ); + VERIFY( ranges::sort(r) == ranges::end(r) ); + + VERIFY( ranges::equal(c, vref) ); + VERIFY( ranges::equal(r, vref) ); + } +} + +struct X +{ + int i; + constexpr X(int a) : i(a) { } +}; + +constexpr bool +test02() +{ + X x[] = {3,4,2,1,5}; + const X y[] = {4,3,2,1,5}; + + auto res = ranges::sort(x, x+4, ranges::greater{}, &X::i); + return (res == x+4 + && ranges::equal(x, y, {}, &X::i, &X::i)); +} + +int +main() +{ + test01(); + static_assert(test02()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc new file mode 100644 index 00000000000..761e3dd32d4 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc @@ -0,0 +1,76 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + { + int x[] = {1,2,3,4,5,6,7,8,9,10}; + test_container cx(x); + auto pred = [] (int a) { return a%2==0; }; + auto range = ranges::stable_partition(cx, pred); + VERIFY( ranges::all_of(cx.begin(), range.begin(), pred) ); + VERIFY( ranges::none_of(range, pred) ); + } + + { + int x[] = {1,2,3,4,5,6,7,8,9,10,11}; + test_range cx(x); + auto pred = [] (int a) { return a%2==0; }; + auto range = ranges::stable_partition(cx, pred); + VERIFY( ranges::all_of(cx.begin(), range.begin(), pred) ); + VERIFY( ranges::none_of(range, pred) ); + } +} + +void +test02() +{ + for (int k = 1; k <= 10; k++) + { + int x[] = {1,2,3,4,5,6,7,8,9,10}; + auto pred = [&] (int a) { return a >= k; }; + auto proj = [] (int a) { return a-1; }; + auto range = ranges::stable_partition(x, x+10, pred, proj); + VERIFY( ranges::all_of(x, range.begin(), pred, proj) ); + VERIFY( ranges::none_of(range, pred, proj) ); + + int y[] = {0,1,2,3,4,5,6,7,8,9}; + ranges::rotate(y, y+k); + VERIFY( ranges::equal(x, y, {}, proj) ); + } +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc new file mode 100644 index 00000000000..23a8c03b519 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc @@ -0,0 +1,70 @@ +// Copyright (C) 2020 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 run { target c++2a } } +// { dg-require-cstdint "" } + +#include +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::random_access_iterator_wrapper; + +namespace ranges = std::ranges; + +// This test doesn't verify the stability property of ranges::stable_sort, +// because at the moment it's just defined to be a wrapper over +// std::stable_sort. + +void +test01() +{ + for (unsigned size = 0; size < 50; ++size) + { + std::vector vref(size); + std::iota(vref.begin(), vref.end(), 0); + std::vector v1(vref), v2(vref); + test_container c + = {&v1[0], &v1[0] + size}; + test_range r + = {&v2[0], &v2[0] + size}; + + std::ranlux48_base g1(size), g2(size + 1); + ranges::shuffle(c, g1); + ranges::shuffle(ranges::begin(r), ranges::end(r), g2); + + auto res1 = ranges::stable_sort(c.begin(), c.end(), {}, std::negate<>{}); + VERIFY( res1 == c.end() ); + + auto res2 = ranges::stable_sort(r, ranges::greater{}); + VERIFY( res2 == ranges::end(r) ); + + VERIFY( ranges::equal(c, r) ); + VERIFY( ranges::equal(c.begin(), c.end(), vref.rbegin(), vref.rend()) ); + } +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/swap_ranges/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/swap_ranges/constrained.cc new file mode 100644 index 00000000000..338b6a435f9 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/swap_ranges/constrained.cc @@ -0,0 +1,124 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X +{ + int i; + int moved = 0; + + constexpr X(int a) : i(a) { } + + constexpr X(const X&) = delete; + constexpr X& operator=(const X&) = delete; + + constexpr X(X&& other) + { + *this = std::move(other); + } + + constexpr X& + operator=(X&& other) + { + other.moved++; + i = other.i; + return *this; + } + + friend constexpr bool + operator==(const X& a, const X& b) + { return a.i == b.i; } +}; + +void +test01() +{ + { + X x[7] = { 1, 2, 3, 4, 5, 6, 7 }; + X y[7] = { 2, 4, 3, 5, 8, 9, 1 }; + X z[7] = { 1, 2, 3, 4, 5, 6, 7 }; + X w[7] = { 2, 4, 3, 5, 8, 9, 1 }; + auto [x_iter, y_iter] = ranges::swap_ranges(x, y); + VERIFY( ranges::equal(y, z) && x_iter == x+7 && y_iter == y+7 ); + VERIFY( ranges::equal(x, w) ); + } + + { + int x[3] = { 1, 2, 3 }; + int y[4] = { 2, 4, 6, 0 }; + int z[3] = { 1, 2, 3 }; + int w[3] = { 2, 4, 6 }; + test_container cx(x); + test_container cy(y); + auto [x_iter, y_iter] = ranges::swap_ranges(cx, cy); + VERIFY( ranges::equal(y, y+3, z, z+3) ); + VERIFY( x_iter.ptr == x+3 && y_iter.ptr == y+3 ); + VERIFY( y[3] == 0 ); + VERIFY( ranges::equal(x, w) ); + } + + { + int x[3] = { 1, 2, 3 }; + int y[4] = { 2, 4, 6, 0 }; + int z[3] = { 1, 2, 3 }; + int w[3] = { 2, 4, 6 }; + test_range cx(x); + test_range cy(y); + auto [y_iter, x_iter] = ranges::swap_ranges(cy, cx); + VERIFY( ranges::equal(y, y+3, z, z+3) ); + VERIFY( x_iter.ptr == x+3 && y_iter.ptr == y+3 ); + VERIFY( y[3] == 0 ); + VERIFY( ranges::equal(x, w) ); + } +} + +constexpr bool +test02() +{ + bool ok = true; + X x[7] = { 1, 2, 3, 4, 5, 6, 7 }; + X y[7] = { 2, 4, 3, 5, 8, 9, 1 }; + X z[7] = { 1, 2, 3, 4, 5, 6, 7 }; + X w[7] = { 2, 4, 3, 5, 8, 9, 1 }; + auto [x_iter, y_iter] = ranges::swap_ranges(x, y); + ok &= ranges::equal(y, z) && x_iter == x+7 && y_iter == y+7; + ok &= ranges::equal(x, w); + return ok; +} + +int +main() +{ + test01(); + static_assert(test02()); +} + + diff --git a/libstdc++-v3/testsuite/25_algorithms/transform/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/transform/constrained.cc new file mode 100644 index 00000000000..da8b7f2be07 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/transform/constrained.cc @@ -0,0 +1,148 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +struct X { int i; }; + +void +test01() +{ + { + int x[6] = { {2}, {4}, {6}, {8}, {10}, {11} }; + int y[6] = { {3}, {5}, {7}, {9}, {11}, {12} }; + auto [in, out] = ranges::transform(x, x, [] (int a) { return a+1; }); + VERIFY( in == x+6 && out == x+6 ); + VERIFY( ranges::equal(x, y) ); + } + + { + X x[6] = { {2}, {4}, {6}, {8}, {10}, {11} }; + int y[7] = { {3}, {5}, {7}, {9}, {11}, {12}, {0} }; + int z[7] = { {0}, {0}, {0}, {0}, {0}, {0}, {0} }; + test_container cx(x); + test_container cy(y), cz(z); + auto [in, out] + = ranges::transform(cx, cz.begin(), [] (int a) { return a+1; }, &X::i); + VERIFY( ranges::equal(cy, cz) ); + VERIFY( in == cx.end() && ++out == cz.end() ); + } + + { + X x[6] = { {2}, {4}, {6}, {8}, {10}, {11} }; + X y[7] = { {3}, {5}, {7}, {9}, {11}, {12}, {0} }; + int z[7] = { {0}, {0}, {0}, {0}, {0}, {0}, {0} }; + test_range rx(x), ry(y); + test_range rz(z); + auto [in, out] + = ranges::transform(rx, rz.begin(), [] (int a) { return a+1; }, &X::i); + VERIFY( ranges::equal(ry, z, {}, &X::i) ); + VERIFY( in == rx.end() && out.ptr == z+6 ); + } +} + +struct Y { int i; int j; }; + +constexpr bool +test02() +{ + int x[] = { 1, 2, 3 }; + Y y[] = { {1,2}, {2,4}, {3,6} }; + ranges::transform(y, y+3, x, [] (int a) { return -a; }, &Y::i); + return x[0] == -1 && x[1] == -2 && x[2] == -3; +} + +void +test03() +{ + { + int x[6] = { {2}, {4}, {6}, {8}, {10}, {11} }; + const int y[6] = { {3}, {5}, {7}, {9}, {11}, {12} }; + int z[6] = { {5}, {9}, {13}, {17}, {21}, {23} }; + auto [in1, in2, out] = ranges::transform(x, y, x, std::plus<>{}); + VERIFY( in1 == x+6 && in2 == y+6 && out == x+6 ); + VERIFY( ranges::equal(x, z) ); + } + + { + int x[6] = { {2}, {4}, {6}, {8}, {10}, {11} }; + const int y[6] = { {3}, {5}, {7}, {9}, {11}, {12} }; + int z[6] = { {5}, {9}, {13}, {17}, {21}, {23} }; + auto [in1, in2, out] = ranges::transform(y, x, x, std::plus<>{}); + VERIFY( in1 == y+6 && in2 == x+6 && out == x+6 ); + VERIFY( ranges::equal(x, z) ); + } + + { + X x[6] = { {2}, {4}, {6}, {8}, {10}, {11} }; + int y[7] = { {3}, {5}, {7}, {9}, {11}, {12}, {0} }; + int z[6] = { {5}, {9}, {13}, {17}, {21}, {23} }; + int w[6]; + test_container cx(x); + test_container cy(y), cz(z), cw(w); + auto [in1, in2, out] + = ranges::transform(cx, cy, cw.begin(), std::plus<>{}, &X::i); + VERIFY( in1 == cx.end() && ++in2 == cy.end() && out == cw.end() ); + VERIFY( ranges::equal(cw, cz) ); + } + + { + X x[6] = { {2}, {4}, {6}, {8}, {10}, {11} }; + int y[7] = { {3}, {5}, {7}, {9}, {11}, {12}, {0} }; + int z[6] = { {5}, {9}, {13}, {17}, {21}, {23} }; + int w[6]; + test_range rx(x); + test_range ry(y), rz(z); + test_range rw(w); + auto [in1, in2, out] + = ranges::transform(rx, ry, rw.begin(), std::plus<>{}, &X::i); + VERIFY( in1 == rx.end() && ++in2 == ry.end() && out.ptr == w+6 ); + VERIFY( ranges::equal(w, rz) ); + } +} + +constexpr bool +test04() +{ + int x[3]; + const Y y[3] = { {1,2}, {2,4}, {3,6} }; + ranges::transform(y, y+3, y, y+3, x, std::plus<>{}, &Y::i, &Y::j); + return x[0] == 3 && x[1] == 6 && x[2] == 9; +} + +int +main() +{ + test01(); + static_assert(test02()); + test03(); + static_assert(test04()); +} + diff --git a/libstdc++-v3/testsuite/25_algorithms/unique/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/unique/constrained.cc new file mode 100644 index 00000000000..e863a601ddd --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/unique/constrained.cc @@ -0,0 +1,143 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + + +namespace ranges = std::ranges; + +struct X +{ + int i; +}; + +void +test01() +{ + { + X x[6] = { {2}, {2}, {6}, {8}, {2}, {11} }; + const int y[5] = { {2}, {6}, {8}, {2}, {11} }; + test_container cx(x); + auto res = ranges::unique(cx, {}, &X::i); + VERIFY( res.end() == cx.end() ); + VERIFY( ranges::equal(cx.begin(), res.begin(), y, y+5, {}, &X::i) ); + } + + { + X x[6] = { {2}, {2}, {6}, {8}, {2}, {11} }; + const int y[5] = { {2}, {6}, {8}, {2}, {11} }; + test_range rx(x); + auto res = ranges::unique(rx, {}, &X::i); + VERIFY( res.end() == rx.end() ); + VERIFY( ranges::equal(rx.begin(), res.begin(), y, y+5, {}, &X::i) ); + } +} + +constexpr bool +test02() +{ + int x[2] = {2, 2}; + const int y[1] = {2}; + auto res = ranges::unique(x); + return ranges::equal(x, res.begin(), y, y+1, ranges::equal_to{}); +} + +/* The following is adapted from 25_algorithms/unique/2.cc. */ + +namespace two_dot_cc +{ + const int T1[] = {1, 4, 4, 6, 1, 2, 2, 3, 1, 6, 6, 6, 5, 7, 5, 4, 4}; + const int T2[] = {1, 1, 1, 2, 2, 1, 1, 7, 6, 6, 7, 8, 8, 8, 8, 9, 9}; + const int N = sizeof(T1) / sizeof(int); + + const int A1[] = {1, 4, 6, 1, 2, 3, 1, 6, 5, 7, 5, 4}; + const int A2[] = {1, 4, 4, 6, 6, 6, 6, 7}; + const int A3[] = {1, 1, 1}; + + const int B1[] = {1, 2, 1, 7, 6, 7, 8, 9}; + const int B2[] = {1, 1, 1, 2, 2, 7, 7, 8, 8, 8, 8, 9, 9}; + const int B3[] = {9, 9, 8, 8, 8, 8, 7, 6, 6, 1, 1, 1, 1, 1}; + + void test01() + { + using namespace std; + + list::iterator pos; + + list coll(T1, T1 + N); + pos = ranges::unique(coll.begin(), coll.end()).begin(); + VERIFY( equal(coll.begin(), pos, A1) ); + + list coll2(T2, T2 + N); + pos = ranges::unique(coll2.begin(), coll2.end()).begin(); + VERIFY( equal(coll2.begin(), pos, B1) ); + } + + void test02() + { + using namespace std; + + list::iterator pos; + + list coll(T1, T1 + N); + pos = ranges::unique(coll.begin(), coll.end(), greater()).begin(); + VERIFY( equal(coll.begin(), pos, A2) ); + + list coll2(T2, T2 + N); + pos = ranges::unique(coll2.begin(), coll2.end(), greater()).begin(); + VERIFY( equal(coll2.begin(), pos, B2) ); + } + + void test03() + { + using namespace std; + + list::iterator pos; + + list coll(T1, T1 + N); + pos = ranges::unique(coll.begin(), coll.end(), less()).begin(); + VERIFY( equal(coll.begin(), pos, A3) ); + + list coll2(T2, T2 + N); + reverse(coll2.begin(), coll2.end()); + pos = ranges::unique(coll2.begin(), coll2.end(), less()).begin(); + VERIFY( equal(coll2.begin(), pos, B3) ); + } +} // namespace two_dot_cc + +int main() +{ + test01(); + static_assert(test02()); + + two_dot_cc::test01(); + two_dot_cc::test02(); + two_dot_cc::test03(); + + return 0; +} diff --git a/libstdc++-v3/testsuite/25_algorithms/unique_copy/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/unique_copy/constrained.cc new file mode 100644 index 00000000000..bf16cdc4ee9 --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/unique_copy/constrained.cc @@ -0,0 +1,113 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::input_iterator_wrapper; +using __gnu_test::output_iterator_wrapper; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +template typename source_wrapper, + template typename dest_wrapper> +void +test01() +{ + int x[6] = {0, 0, 0, 1, 1, 1}; + int y[2]; + const int z[2] = {0, 1}; + + test_range rx(x); + test_range ry(y); + auto [in,out] = ranges::unique_copy(rx, ry.begin()); + VERIFY( in == ranges::end(rx) && out == ranges::end(ry) ); + VERIFY( ranges::equal(y, z) ); +} + +template typename source_wrapper, + template typename dest_wrapper> +void +test02() +{ + int x[6] = {0, 0, 0, 1, 1, 1}; + int y[2] = {0, 0}; + const int z[2] = {0, 0}; + + test_range rx(x, x); + test_range ry(y, y); + auto [in, out] = ranges::unique_copy(rx.begin(), rx.end(), ry.begin()); + VERIFY( in.ptr == x && out.ptr == y ); + VERIFY( ranges::equal(y, z) ); +} + +template typename source_wrapper, + template typename dest_wrapper> +void +test03() +{ + struct X { int i; }; + X x[6] = { {1}, {2}, {2}, {4}, {4}, {6} }; + X y[4] = { {1}, {2}, {4}, {6} }; + const X z[4] = { {1}, {2}, {4}, {6} }; + + test_range rx(x); + test_range ry(y); + auto [in, out] + = ranges::unique_copy(rx, ry.begin(), ranges::equal_to{}, &X::i); + VERIFY( in == ranges::end(rx) && out == ranges::end(ry) ); + VERIFY( ranges::equal(y, z, {}, &X::i, &X::i) ); +} + +constexpr bool +test04() +{ + struct X { int i; }; + X x[7] = { {1}, {2}, {2}, {2}, {4}, {4}, {6} }; + X y[4] = { {1}, {2}, {4}, {6} }; + const X z[4] = { {1}, {2}, {4}, {6} }; + + auto [in, out] + = ranges::unique_copy(x, x+7, y, ranges::equal_to{}, &X::i); + return (in == ranges::end(x) + && out == ranges::end(y) + && ranges::equal(y, z, {}, &X::i, &X::i)); +} + +int +main() +{ + test01(); + test01(); + test01(); + + test02(); + test02(); + test02(); + + test03(); + test03(); + test03(); + + static_assert(test04()); +} diff --git a/libstdc++-v3/testsuite/25_algorithms/upper_bound/constrained.cc b/libstdc++-v3/testsuite/25_algorithms/upper_bound/constrained.cc new file mode 100644 index 00000000000..5182431f68f --- /dev/null +++ b/libstdc++-v3/testsuite/25_algorithms/upper_bound/constrained.cc @@ -0,0 +1,66 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include + +using __gnu_test::test_container; +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; + +void +test01() +{ + int x[] = {1, 2, 3, 4, 5, 5, 6, 7}; + for (unsigned i = 0; i < 5; i++) + for (unsigned j = 6; j < 8; j++) + { + test_container cx(x); + auto result = ranges::upper_bound(std::next(cx.begin(), i), + std::next(cx.begin(), j), + 4, {}, [] (int a) { return a-1; }); + VERIFY( result.ptr == x+6 ); + } + + ranges::reverse(x); + test_range rx(x); + auto result = ranges::upper_bound(rx, 5, ranges::greater{}, + [] (int a) { return a+1; }); + VERIFY( result.ptr == x+5 ); +} + +constexpr bool +test02() +{ + int x[] = {1, 2, 3, 4, 5}; + return (ranges::upper_bound(x, 6) == x+5 + && ranges::upper_bound(x, x, 6) == x + && ranges::upper_bound(x, 1) == x+1); +} + +int +main() +{ + test01(); + static_assert(test02()); +} From patchwork Tue Feb 4 02:07:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 1233098 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-518823-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha1 header.s=default header.b=NumGMNgm; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=DaWj5bxQ; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 48BSmC4Qfyz9sWy for ; Tue, 4 Feb 2020 13:08:43 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; q=dns; s= default; b=NZK2kau3f+2gAyGqcuM2Pt5CeaYWvIUmtWsTpAl7ezLOxXiYvSaiv tro3tv8/Rq33fh9iSCm/p8CAL1thz3BwqbvNyRra2evcUE2AxVpFtUHKn0X9536V NHoF7YdkzGwQK5H60H5OvI1gW2tfv/YXJmVJTm7dCAL7n+zke9KhaY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-type:content-transfer-encoding; s=default; bh=Y9C9hcDPBx7Zv/wTrKBvKMGetGQ=; b=NumGMNgmszrK+OZ2WE0xOJItwNqU nJogDC7VPYp1w22wBxogsG8SFr989TtooLokufeBkkMgNvbPmxP96BrQ21ssg0x0 EsG1TxFcxqyakyBSF4FGqX5Te8mTLKnUBB/wNOTUqyDxIeLCNO3rFA3OY0rtqmLT onowSicWEcXm8ls= Received: (qmail 117449 invoked by alias); 4 Feb 2020 02:08:05 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 117166 invoked by uid 89); 4 Feb 2020 02:08:01 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-23.2 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=unavailable version=3.3.1 spammy=Applied, 5076, all.cc, allcc X-HELO: us-smtp-delivery-1.mimecast.com Received: from us-smtp-2.mimecast.com (HELO us-smtp-delivery-1.mimecast.com) (205.139.110.61) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 04 Feb 2020 02:07:41 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1580782059; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Yl3GnO9bxeAPggldlKoS5ACtf4N7KaYwKNOpaGaNm+M=; b=DaWj5bxQBJpb3oBgk57SRZZSaCS4+mHwNDODUB0JZ6XvBMs0EHq4lqEV/1FZ3YnIMusl82 Cgsy9gQws0sKevU1I4E+z5nQoC0wAJLj6cgZ/PQRK1RplN8DoA3bcru0g2BidoNnKzU/iV 0vdJziWjp8txO/Qcn5czsYKijJHOIA0= Received: from mail-qt1-f197.google.com (mail-qt1-f197.google.com [209.85.160.197]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-276-J59DblfOM0my71lOMrtB8w-1; Mon, 03 Feb 2020 21:07:35 -0500 Received: by mail-qt1-f197.google.com with SMTP id o18so11360268qtt.19 for ; Mon, 03 Feb 2020 18:07:35 -0800 (PST) Received: from localhost.localdomain (ool-457d493a.dyn.optonline.net. [69.125.73.58]) by smtp.gmail.com with ESMTPSA id a36sm11185884qtk.29.2020.02.03.18.07.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 03 Feb 2020 18:07:31 -0800 (PST) From: Patrick Palka To: gcc-patches@gcc.gnu.org Cc: libstdc++@gcc.gnu.org, jwakely@redhat.com, Patrick Palka Subject: [PATCH 3/3] libstdc++: Implement C++20 range adaptors Date: Mon, 3 Feb 2020 21:07:24 -0500 Message-Id: <20200204020724.217468-3-ppalka@redhat.com> In-Reply-To: <20200204020724.217468-1-ppalka@redhat.com> References: <20200204020724.217468-1-ppalka@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-IsSubscribed: yes This patch implements [range.adaptors]. It also includes the changes from P3280 and P3278 and P3323, without which many standard examples won't work. The implementation is mostly dictated by the spec and there was not much room for implementation discretion. The most interesting part that was not specified by the spec is the design of the range adaptors and range adaptor closures, which I tried to design in a way that minimizes boilerplate and statefulness (so that e.g. the composition of two stateless closures is stateless). What is left unimplemented is caching of calls to begin() in filter_view, drop_view and reverse_view, which is required to guarantee that begin() has amortized constant time complexity. I can implement this in a subsequent patch. "Interesting" parts of the patch are marked with XXX comments. libstdc++-v3/ChangeLog: Implement C++20 range adaptors * include/std/ranges: Include . (subrange::_S_store_size): Mark as const instead of constexpr to avoid what seems to be a bug in GCC. (__detail::__box): Give it defaulted copy and move constructors. (views::_Single::operator()): Mark constexpr. (views::_Iota::operator()): Mark constexpr. (__detail::Empty): Define. (views::_RangeAdaptor, views::_RangeAdaptorClosure, ref_view, all_view, views::all, filter_view, views::filter, transform_view, views::transform, take_view, views::take, take_while_view, views::take_while, drop_view, views::drop, join_view, views::join, __detail::require_constant, __detail::tiny_range, split_view, views::split, views::_Counted, views::counted, common_view, views::common, reverse_view, views::reverse, views::__detail::__is_reversible_subrange, views::__detail::__is_reverse_view, reverse_view, views::reverse, __detail::__has_tuple_element, elements_view, views::elements, views::keys, views::values): Define. * testsuite/std/ranges/adaptors/all.cc: New test. * testsuite/std/ranges/adaptors/common.cc: Likewise. * testsuite/std/ranges/adaptors/counted.cc: Likewise. * testsuite/std/ranges/adaptors/drop.cc: Likewise. * testsuite/std/ranges/adaptors/drop_while.cc: Likewise. * testsuite/std/ranges/adaptors/elements.cc: Likewise. * testsuite/std/ranges/adaptors/filter.cc: Likewise. * testsuite/std/ranges/adaptors/join.cc: Likewise. * testsuite/std/ranges/adaptors/reverse.cc: Likewise. * testsuite/std/ranges/adaptors/split.cc: Likewise. * testsuite/std/ranges/adaptors/take.cc: Likewise. * testsuite/std/ranges/adaptors/take_while.cc: Likewise. * testsuite/std/ranges/adaptors/transform.cc: Likewise. --- libstdc++-v3/include/std/ranges | 2415 ++++++++++++++++- .../testsuite/std/ranges/adaptors/all.cc | 124 + .../testsuite/std/ranges/adaptors/common.cc | 68 + .../testsuite/std/ranges/adaptors/counted.cc | 64 + .../testsuite/std/ranges/adaptors/drop.cc | 107 + .../std/ranges/adaptors/drop_while.cc | 63 + .../testsuite/std/ranges/adaptors/elements.cc | 52 + .../testsuite/std/ranges/adaptors/filter.cc | 97 + .../testsuite/std/ranges/adaptors/join.cc | 112 + .../testsuite/std/ranges/adaptors/reverse.cc | 86 + .../testsuite/std/ranges/adaptors/split.cc | 82 + .../testsuite/std/ranges/adaptors/take.cc | 95 + .../std/ranges/adaptors/take_while.cc | 62 + .../std/ranges/adaptors/transform.cc | 86 + 14 files changed, 3509 insertions(+), 4 deletions(-) create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/all.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/common.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/counted.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/drop_while.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/join.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/reverse.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/split.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/take.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc create mode 100644 libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index ea558c76c9d..947e223f7f9 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -39,6 +39,7 @@ #if __cpp_lib_concepts #include +#include // std::ref #include #include #include @@ -255,7 +256,8 @@ namespace ranges class subrange : public view_interface> { private: - static constexpr bool _S_store_size + // XXX: gcc complains when using constexpr here + static const bool _S_store_size = _Kind == subrange_kind::sized && !sized_sentinel_for<_Sent, _It>; _It _M_begin = _It(); @@ -507,6 +509,9 @@ namespace ranges : std::optional<_Tp>{std::in_place} { } + __box(const __box&) = default; + __box(__box&&) = default; + using std::optional<_Tp>::operator=; __box& @@ -922,7 +927,7 @@ namespace views struct _Single { template - auto + constexpr auto operator()(_Tp&& __e) const { return single_view{std::forward<_Tp>(__e)}; } }; @@ -932,19 +937,2421 @@ namespace views struct _Iota { template - auto + constexpr auto operator()(_Tp&& __e) const { return iota_view{std::forward<_Tp>(__e)}; } template - auto + constexpr auto operator()(_Tp&& __e, _Up&& __f) const { return iota_view{std::forward<_Tp>(__e), std::forward<_Tp>(__f)}; } }; inline constexpr _Iota iota{}; +} // namespace views + +namespace __detail +{ + struct _Empty { }; +} // namespace __detail + +namespace views +{ + template + struct _RangeAdaptorClosure; + + template + struct _RangeAdaptor + { + protected: + [[no_unique_address]] + conditional_t, + _Callable, __detail::_Empty> _M_callable; + + public: + constexpr + _RangeAdaptor(const _Callable& = {}) + requires is_default_constructible_v<_Callable> + { } + + constexpr + _RangeAdaptor(_Callable __callable) + requires (!is_default_constructible_v<_Callable>) + : _M_callable(std::move(__callable)) + { } + + template + requires (sizeof...(_Args) >= 1) + constexpr auto + operator()(_Args&&... __args) const + { + if constexpr (is_invocable_v<_Callable, _Args...>) + { + static_assert(sizeof...(_Args) != 1, + "a _RangeAdaptor that accepts only one argument " + "should be defined as a _RangeAdaptorClosure"); + return _Callable{}(std::forward<_Args>(__args)...); + } + else + { + auto __closure = [__args...] (_Range&& __r) { + return _Callable{}(std::forward<_Range>(__r), __args...); + }; + using _ClosureType = decltype(__closure); + return _RangeAdaptorClosure<_ClosureType>(std::move(__closure)); + } + } + }; + + template + struct _RangeAdaptorClosure : public _RangeAdaptor<_Callable> + { + using _RangeAdaptor<_Callable>::_RangeAdaptor; + + template + requires requires { declval<_Callable>()(declval<_Range>()); } + constexpr auto + operator()(_Range&& __r) const + { + if constexpr (is_default_constructible_v<_Callable>) + return _Callable{}(std::forward<_Range>(__r)); + else + return this->_M_callable(std::forward<_Range>(__r)); + } + + template + requires requires { declval<_Callable>()(declval<_Range>()); } + friend constexpr auto + operator|(_Range&& __r, const _RangeAdaptorClosure& __o) + { return __o(std::forward<_Range>(__r)); } + + template + friend constexpr auto + operator|(const _RangeAdaptorClosure<_Tp>& __x, + const _RangeAdaptorClosure& __y) + { + if constexpr (is_default_constructible_v<_Tp> + && is_default_constructible_v<_Callable>) + { + auto __closure = [] (_Up&& __e) { + return std::forward<_Up>(__e) | decltype(__x){} | decltype(__y){}; + }; + return _RangeAdaptorClosure(__closure); + } + else if constexpr (is_default_constructible_v<_Tp> + && !is_default_constructible_v<_Callable>) + { + auto __closure = [__y] (_Up&& __e) { + return std::forward<_Up>(__e) | decltype(__x){} | __y; + }; + return _RangeAdaptorClosure(__closure); + } + else if constexpr (!is_default_constructible_v<_Tp> + && is_default_constructible_v<_Callable>) + { + auto __closure = [__x] (_Up&& __e) { + return std::forward<_Up>(__e) | __x | decltype(__y){}; + }; + return _RangeAdaptorClosure(__closure); + } + else + { + auto __closure = [__x, __y] (_Up&& __e) { + return std::forward<_Up>(__e) | __x | __y; + }; + return _RangeAdaptorClosure(__closure); + } + } + }; + template + _RangeAdaptorClosure(_Callable) -> _RangeAdaptorClosure<_Callable>; } // namespace views + + template requires is_object_v<_Range> + class ref_view : public view_interface> + { + private: + _Range* _M_r = nullptr; + + static void _S_fun(_Range&); // not defined + static void _S_fun(_Range&&) = delete; + + public: + constexpr + ref_view() noexcept = default; + + template<__detail::__not_same_as _Tp> + requires convertible_to<_Tp, _Range&> + && requires { _S_fun(declval<_Tp>()); } + constexpr + ref_view(_Tp&& __t) + : _M_r(addressof(static_cast<_Range&>(std::forward<_Tp>(__t)))) + { } + + constexpr _Range& + base() const + { return *_M_r; } + + constexpr iterator_t<_Range> + begin() const + { return ranges::begin(*_M_r); } + + constexpr sentinel_t<_Range> + end() const + { return ranges::end(*_M_r); } + + constexpr bool + empty() const requires requires { ranges::empty(*_M_r); } + { return ranges::empty(*_M_r); } + + constexpr auto + size() const requires sized_range<_Range> + { return ranges::size(*_M_r); } + + constexpr auto + data() const requires contiguous_range<_Range> + { return ranges::data(*_M_r); } + }; + + template + ref_view(_Range&) -> ref_view<_Range>; + + template + inline constexpr bool enable_safe_range> = true; + + namespace views + { + inline constexpr _RangeAdaptorClosure all + = [] (_Range&& __r) + { + if constexpr (view>) + return std::forward<_Range>(__r); + else if constexpr (requires { ref_view{std::forward<_Range>(__r)}; }) + return ref_view{std::forward<_Range>(__r)}; + else + return subrange{std::forward<_Range>(__r)}; + }; + } // namespace views + + template + using all_view = decltype(views::all(declval<_Range>())); + + // XXX: the following algos are copied verbatim from ranges_algo.h to avoid a + // circular dependency with that header. + namespace __detail + { + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr _Iter + find_if(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) + { + while (__first != __last + && !(bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) + ++__first; + return __first; + } + + template, _Proj>> + _Pred> + constexpr safe_iterator_t<_Range> + find_if(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return __detail::find_if(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template _Sent, + typename _Proj = identity, + indirect_unary_predicate> _Pred> + constexpr _Iter + find_if_not(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) + { + while (__first != __last + && (bool)std::__invoke(__pred, std::__invoke(__proj, *__first))) + ++__first; + return __first; + } + + template, _Proj>> + _Pred> + constexpr safe_iterator_t<_Range> + find_if_not(_Range&& __r, _Pred __pred, _Proj __proj = {}) + { + return __detail::find_if_not(ranges::begin(__r), ranges::end(__r), + std::move(__pred), std::move(__proj)); + } + + template> + _Comp = ranges::less> + constexpr const _Tp& + min(const _Tp& __a, const _Tp& __b, _Comp __comp = {}, _Proj __proj = {}) + { + if (std::__invoke(std::move(__comp), + std::__invoke(__proj, __b), + std::__invoke(__proj, __a))) + return __b; + else + return __a; + } + + template + struct mismatch_result + { + [[no_unique_address]] _Iter1 in1; + [[no_unique_address]] _Iter2 in2; + + template + requires convertible_to + && convertible_to + operator mismatch_result<_IIter1, _IIter2>() const & + { + return {in1, in2}; + } + + template + requires convertible_to<_Iter1, _IIter1> + && convertible_to<_Iter2, _IIter2> + operator mismatch_result<_IIter1, _IIter2>() && + { + return {std::move(in1), std::move(in2)}; + } + }; + + template _Sent1, + input_iterator _Iter2, sentinel_for<_Iter2> _Sent2, + typename _Pred = ranges::equal_to, + typename _Proj1 = identity, typename _Proj2 = identity> + requires indirectly_comparable<_Iter1, _Iter2, _Pred, _Proj1, _Proj2> + constexpr mismatch_result<_Iter1, _Iter2> + mismatch(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, + _Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) + { + while (__first1 != __last1 && __first2 != __last2 + && (bool)std::__invoke(__pred, + std::__invoke(__proj1, *__first1), + std::__invoke(__proj2, *__first2))) + { + ++__first1; + ++__first2; + } + return { std::move(__first1), std::move(__first2) }; + } + } // namespace __detail + + template> _Pred> + requires view<_Vp> && is_object_v<_Pred> + class filter_view : public view_interface> + { + private: + struct _Sentinel; + + struct _Iterator + { + private: + static constexpr auto + _S_iter_concept() + { + if constexpr (bidirectional_range<_Vp>) + return bidirectional_iterator_tag{}; + else if constexpr (forward_range<_Vp>) + return forward_iterator_tag{}; + else + return input_iterator_tag{}; + } + + static constexpr auto + _S_iter_cat() + { + using _Cat = iterator_traits>::iterator_category; + if constexpr (derived_from<_Cat, bidirectional_iterator_tag>) + return bidirectional_iterator_tag{}; + else if constexpr (derived_from<_Cat, forward_iterator_tag>) + return forward_iterator_tag{}; + else + return _Cat{}; + } + + friend filter_view; + + iterator_t<_Vp> _M_current = iterator_t<_Vp>(); + filter_view* _M_parent = nullptr; + + public: + using iterator_concept = decltype(_S_iter_concept()); + using iterator_category = decltype(_S_iter_cat()); + using value_type = range_value_t<_Vp>; + using difference_type = range_difference_t<_Vp>; + + _Iterator() = default; + + constexpr + _Iterator(filter_view& __parent, iterator_t<_Vp> __current) + : _M_current(std::move(__current)), + _M_parent(addressof(__parent)) + { } + + constexpr iterator_t<_Vp> + base() const & + requires copyable> + { return _M_current; } + + constexpr iterator_t<_Vp> + base() && + { return std::move(_M_current); } + + constexpr range_reference_t<_Vp> + operator*() const + { return *_M_current; } + + constexpr iterator_t<_Vp> + operator->() const + requires __detail::__has_arrow> + && copyable> + { return _M_current; } + + constexpr _Iterator& + operator++() + { + _M_current = __detail::find_if(std::move(++_M_current), + ranges::end(_M_parent->_M_base), + std::ref(*_M_parent->_M_pred)); + return *this; + } + + constexpr void + operator++(int) + { ++*this; } + + constexpr _Iterator + operator++(int) requires forward_range<_Vp> + { + auto __tmp = *this; + ++*this; + return __tmp; + } + + constexpr _Iterator& + operator--() requires bidirectional_range<_Vp> + { + do + --_M_current; + while (!invoke(*_M_parent->_M_pred, *_M_current)); + return *this; + } + + constexpr _Iterator + operator--(int) requires bidirectional_range<_Vp> + { + auto __tmp = *this; + --*this; + return __tmp; + } + + friend constexpr bool + operator==(const _Iterator& __x, const _Iterator& __y) + requires equality_comparable> + { return __x._M_current == __y._M_current; } + + friend constexpr range_rvalue_reference_t<_Vp> + iter_move(const _Iterator& __i) + noexcept(noexcept(ranges::iter_move(__i._M_current))) + { return ranges::iter_move(__i._M_current); } + + friend constexpr void + iter_swap(const _Iterator& __x, const _Iterator& __y) + noexcept(noexcept(ranges::iter_swap(__x._M_current, __y._M_current))) + requires indirectly_swappable> + { ranges::iter_swap(__x._M_current, __y._M_current); } + }; + + struct _Sentinel + { + private: + sentinel_t<_Vp> _M_end = sentinel_t<_Vp>(); + + constexpr bool + __equal(const _Iterator& __i) const + { return __i._M_current == _M_end; } + + public: + _Sentinel() = default; + + constexpr explicit + _Sentinel(filter_view& __parent) + : _M_end(ranges::end(__parent._M_base)) + { } + + constexpr sentinel_t<_Vp> + base() const + { return _M_end; } + + friend constexpr bool + operator==(const _Iterator& __x, const _Sentinel& __y) + { return __y.__equal(__x); } + }; + + _Vp _M_base = _Vp(); + __detail::__box<_Pred> _M_pred; + + public: + filter_view() = default; + + constexpr + filter_view(_Vp __base, _Pred __pred) + : _M_base(std::move(__base)), _M_pred(std::move(__pred)) + { } + + /* XXX: P3280 removes this constructor + template + requires viewable_range<_Range> + && constructible_from<_Vp, all_view<_Range>> + constexpr + filter_view(_Range&& __r, _Pred __pred) + : _M_base(views::all(std::forward<_Range>(__r))), + _M_pred(std::move(__pred)) + { } + */ + + constexpr _Vp + base() const& requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr _Iterator + begin() + { + // XXX: we need to cache the result here as per [range.filter.view] + __glibcxx_assert(_M_pred.has_value()); + return {*this, __detail::find_if(_M_base, std::ref(*_M_pred))}; + } + + constexpr auto + end() + { + if constexpr (common_range<_Vp>) + return _Iterator{*this, ranges::end(_M_base)}; + else + return _Sentinel{*this}; + } + }; + + template + filter_view(_Range&&, _Pred) -> filter_view, _Pred>; + + namespace views + { + inline constexpr _RangeAdaptor filter + = [] (_Range&& __r, _Pred&& __p) + { + return filter_view{std::forward<_Range>(__r), std::forward<_Pred>(__p)}; + }; + } // namespace views + + template + requires view<_Vp> && is_object_v<_Fp> + && regular_invocable<_Fp&, range_reference_t<_Vp>> + class transform_view : public view_interface> + { + private: + template + struct _Sentinel; + + template + struct _Iterator + { + private: + using _Parent + = conditional_t<_Const, const transform_view, transform_view>; + using _Base = conditional_t<_Const, const _Vp, _Vp>; + + static constexpr auto + _S_iter_concept() + { + if constexpr (random_access_range<_Vp>) + return random_access_iterator_tag{}; + else if constexpr (bidirectional_range<_Vp>) + return bidirectional_iterator_tag{}; + else if constexpr (forward_range<_Vp>) + return forward_iterator_tag{}; + else + return input_iterator_tag{}; + } + + static constexpr auto + _S_iter_cat() + { + using _Cat = iterator_traits>::iterator_category; + if constexpr (derived_from<_Cat, contiguous_iterator_tag>) + return random_access_iterator_tag{}; + else + return _Cat{}; + } + + static constexpr decltype(auto) + __iter_move(const _Iterator& __i = {}) + noexcept(noexcept(invoke(*__i._M_parent->_M_fun, *__i._M_current))) + { + if constexpr (is_lvalue_reference_v) + return std::move(*__i); + else + return *__i; + } + + iterator_t<_Base> _M_current = iterator_t<_Base>(); + _Parent* _M_parent = nullptr; + + public: + using iterator_concept = decltype(_S_iter_concept()); + using iterator_category = decltype(_S_iter_cat()); + using value_type + = remove_cvref_t>>; + using difference_type = range_difference_t<_Base>; + + _Iterator() = default; + + constexpr + _Iterator(_Parent& __parent, iterator_t<_Base> __current) + : _M_current(std::move(__current)), _M_parent(addressof(__parent)) + { } + + constexpr + _Iterator(_Iterator __i) + requires _Const + && convertible_to, iterator_t<_Base>> + : _M_current(std::move(__i._M_current)), _M_parent(__i._M_parent) + { } + + constexpr iterator_t<_Base> + base() const & + requires copyable> + { return _M_current; } + + constexpr iterator_t<_Base> + base() && + { return std::move(_M_current); } + + constexpr decltype(auto) + operator*() const + { return invoke(*_M_parent->_M_fun, *_M_current); } + + constexpr _Iterator& + operator++() + { + ++_M_current; + return *this; + } + + constexpr void + operator++(int) + { ++_M_current; } + + constexpr _Iterator + operator++(int) requires forward_range<_Base> + { + auto __tmp = *this; + ++*this; + return __tmp; + } + + constexpr _Iterator& + operator--() requires bidirectional_range<_Base> + { + --_M_current; + return *this; + } + + constexpr _Iterator + operator--(int) requires bidirectional_range<_Base> + { + auto __tmp = *this; + --*this; + return __tmp; + } + + constexpr _Iterator& + operator+=(difference_type __n) requires random_access_range<_Base> + { + _M_current += __n; + return *this; + } + + constexpr _Iterator& + operator-=(difference_type __n) requires random_access_range<_Base> + { + _M_current -= __n; + return *this; + } + + constexpr decltype(auto) + operator[](difference_type __n) const + requires random_access_range<_Base> + { return invoke(*_M_parent->_M_fun, _M_current[__n]); } + + friend constexpr bool + operator==(const _Iterator& __x, const _Iterator& __y) + requires equality_comparable> + { return __x._M_current == __y._M_current; } + + friend constexpr bool + operator<(const _Iterator& __x, const _Iterator& __y) + requires random_access_range<_Base> + { return __x._M_current < __y._M_current; } + + friend constexpr bool + operator>(const _Iterator& __x, const _Iterator& __y) + requires random_access_range<_Base> + { return __y < __x; } + + friend constexpr bool + operator<=(const _Iterator& __x, const _Iterator& __y) + requires random_access_range<_Base> + { return !(__y < __x); } + + friend constexpr bool + operator>=(const _Iterator& __x, const _Iterator& __y) + requires random_access_range<_Base> + { return !(__x < __y); } + +#ifdef __cpp_lib_threeway_comparison + friend constexpr compare_three_way_result_t> + operator<=>(const _Iterator& __x, const _Iterator& __y) + requires random_access_range<_Base> + && three_way_comparable> + { return __x._M_current <=> __y._M_current; } +#endif + + friend constexpr _Iterator + operator+(_Iterator __i, difference_type __n) + requires random_access_range<_Base> + { return {*__i._M_parent, __i._M_current + __n}; } + + friend constexpr _Iterator + operator+(difference_type __n, _Iterator __i) + requires random_access_range<_Base> + { return {*__i._M_parent, __i._M_current + __n}; } + + friend constexpr _Iterator + operator-(_Iterator __i, difference_type __n) + requires random_access_range<_Base> + { return {*__i._M_parent, __i._M_current - __n}; } + + friend constexpr difference_type + operator-(const _Iterator& __x, const _Iterator& __y) + requires random_access_range<_Base> + { return __x._M_current - __y._M_current; } + + friend constexpr decltype(auto) + iter_move(const _Iterator& __i) noexcept(noexcept(__iter_move())) + { return __iter_move(__i); } + + friend constexpr void + iter_swap(const _Iterator& __x, const _Iterator& __y) + noexcept(noexcept(ranges::iter_swap(__x._M_current, __y._M_current))) + requires indirectly_swappable> + { return ranges::iter_swap(__x._M_current, __y._M_current); } + + friend _Sentinel<_Const>; + }; + + template + struct _Sentinel + { + private: + using _Parent + = conditional_t<_Const, const transform_view, transform_view>; + using _Base = conditional_t<_Const, const _Vp, _Vp>; + + constexpr range_difference_t<_Base> + __distance_from(const _Iterator<_Const>& __i) const + { return _M_end - __i._M_current; } + + constexpr bool + __equal(const _Iterator<_Const>& __i) const + { return __i._M_current == _M_end; } + + sentinel_t<_Base> _M_end = sentinel_t<_Base>(); + + public: + _Sentinel() = default; + + constexpr explicit + _Sentinel(sentinel_t<_Base> __end) + : _M_end(__end) + { } + + constexpr + _Sentinel(_Sentinel __i) + requires _Const + && convertible_to, sentinel_t<_Base>> + : _M_end(std::move(__i._M_end)) + { } + + constexpr sentinel_t<_Base> + base() const + { return _M_end; } + + friend constexpr bool + operator==(const _Iterator<_Const>& __x, const _Sentinel& __y) + { return __y.__equal(__x); } + + friend constexpr range_difference_t<_Base> + operator-(const _Iterator<_Const>& __x, const _Sentinel& __y) + requires sized_sentinel_for, iterator_t<_Base>> + { return -__y.__distance_from(__x); } + + friend constexpr range_difference_t<_Base> + operator-(const _Sentinel& __y, const _Iterator<_Const>& __x) + requires sized_sentinel_for, iterator_t<_Base>> + { return __y.__distance_from(__x); } + }; + + _Vp _M_base = _Vp(); + __detail::__box<_Fp> _M_fun; + + public: + transform_view() = default; + + constexpr + transform_view(_Vp __base, _Fp __fun) + : _M_base(std::move(__base)), _M_fun(std::move(__fun)) + { } + + /* XXX: P3280 removes this constructor + template + requires viewable_range<_Range> + && constructible_from<_Vp, all_view<_Range>> + constexpr + transform_view(_Range&& __r, _Fp __fun) + : _M_base(views::all(std::forward<_Range>(__r))) + { + } + */ + + constexpr _Vp + base() const& requires copy_constructible<_Vp> + { return _M_base ; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr _Iterator + begin() + { return _Iterator{*this, ranges::begin(_M_base)}; } + + constexpr _Iterator + begin() const + requires range + && regular_invocable> + { return _Iterator{*this, ranges::begin(_M_base)}; } + + constexpr _Sentinel + end() + { return _Sentinel{ranges::end(_M_base)}; } + + constexpr _Iterator + end() requires common_range<_Vp> + { return _Iterator{*this, ranges::end(_M_base)}; } + + constexpr _Sentinel + end() const + requires range + && regular_invocable> + { return _Sentinel{ranges::end(_M_base)}; } + + constexpr _Iterator + end() const + requires common_range + && regular_invocable> + { return _Iterator{*this, ranges::end(_M_base)}; } + + constexpr auto + size() requires sized_range<_Vp> + { return ranges::size(_M_base); } + + constexpr auto + size() const requires sized_range + { return ranges::size(_M_base); } + }; + + template + transform_view(_Range&&, _Fp) -> transform_view, _Fp>; + + namespace views + { + inline constexpr _RangeAdaptor transform + = [] (_Range&& __r, _Fp&& __f) + { + return transform_view{std::forward<_Range>(__r), std::forward<_Fp>(__f)}; + }; + } // namespace views + + template + class take_view : public view_interface> + { + private: + template + struct _Sentinel + { + private: + using _Base = conditional_t<_Const, const _Vp, _Vp>; + using _CI = counted_iterator>; + + sentinel_t<_Base> _M_end = sentinel_t<_Base>(); + + public: + _Sentinel() = default; + + constexpr explicit + _Sentinel(sentinel_t<_Base> __end) + : _M_end(__end) + { } + + constexpr + _Sentinel(_Sentinel __s) + requires _Const && convertible_to, sentinel_t<_Base>> + : _M_end(std::move(__s._M_end)) + { } + + constexpr sentinel_t<_Base> + base() const + { return _M_end; } + + friend constexpr bool operator==(const _CI& __y, const _Sentinel& __x) + { return __y.count() == 0 || __y.base() == __x._M_end; } + }; + + _Vp _M_base = _Vp(); + range_difference_t<_Vp> _M_count = 0; + + public: + take_view() = default; + + constexpr + take_view(_Vp base, range_difference_t<_Vp> __count) + : _M_base(std::move(base)), _M_count(std::move(__count)) + { } + + /* XXX: P3280 removes this constructor + template + requires constructible_from<_Vp, all_view<_Range>> + constexpr + take_view(_Range&& __r, range_difference_t<_Vp> __count) + : _M_base(views::all(std::forward<_Range>(__r))), _M_count(__count) + { } + */ + + constexpr _Vp + base() const& requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr auto + begin() requires (!__detail::__simple_view<_Vp>) + { + if constexpr (sized_range<_Vp>) { + if constexpr (random_access_range<_Vp>) + return ranges::begin(_M_base); + else + return counted_iterator{ranges::begin(_M_base), size()}; + } else + return counted_iterator{ranges::begin(_M_base), _M_count}; + } + + constexpr auto + begin() const requires range + { + if constexpr (sized_range) { + if constexpr (random_access_range) + return ranges::begin(_M_base); + else + return counted_iterator{ranges::begin(_M_base), size()}; + } else + return counted_iterator{ranges::begin(_M_base), _M_count}; + } + + constexpr auto + end() requires (!__detail::__simple_view<_Vp>) + { + if constexpr (sized_range<_Vp>) { + if constexpr (random_access_range<_Vp>) + return ranges::begin(_M_base) + size(); + else + return default_sentinel; + } else + return _Sentinel{ranges::end(_M_base)}; + } + + constexpr auto + end() const requires range + { + if constexpr (sized_range) { + if constexpr (random_access_range) + return ranges::begin(_M_base) + size(); + else + return default_sentinel; + } else + return _Sentinel{ranges::end(_M_base)}; + } + + constexpr auto + size() requires sized_range<_Vp> + { + auto __n = ranges::size(_M_base); + return __detail::min(__n, static_cast(_M_count)); + } + + constexpr auto + size() const requires sized_range + { + auto __n = ranges::size(_M_base); + return __detail::min(__n, static_cast(_M_count)); + } + }; + + template + take_view(_Range&&, range_difference_t<_Range>) + -> take_view>; + + namespace views + { + inline constexpr _RangeAdaptor take + = [] (_Range&& __r, _Tp&& __n) + { + return take_view{std::forward<_Range>(__r), std::forward<_Tp>(__n)}; + }; + } // namespace views + + template + requires input_range<_Vp> && is_object_v<_Pred> + && indirect_unary_predicate> + class take_while_view : public view_interface> + { + template + struct _Sentinel + { + private: + using _Base = conditional_t<_Const, const _Vp, _Vp>; + + sentinel_t<_Base> _M_end = sentinel_t<_Base>(); + const _Pred* _M_pred = nullptr; + + public: + _Sentinel() = default; + + constexpr explicit + _Sentinel(sentinel_t<_Base> __end, const _Pred* __pred) + : _M_end(__end), _M_pred(__pred) + { } + + constexpr + _Sentinel(_Sentinel __s) + requires _Const && convertible_to, sentinel_t<_Base>> + : _M_end(__s._M_end), _M_pred(__s._M_pred) + { } + + constexpr sentinel_t<_Base> + base() const { return _M_end; } + + friend constexpr bool + operator==(const iterator_t<_Base>& __x, const _Sentinel& __y) + { return __y._M_end == __x || !invoke(*__y._M_pred, *__x); } + }; + + _Vp _M_base; + __detail::__box<_Pred> _M_pred; + + public: + take_while_view() = default; + + constexpr + take_while_view(_Vp base, _Pred __pred) + : _M_base(std::move(base)), _M_pred(std::move(__pred)) + { + } + + constexpr _Vp + base() const& requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr const _Pred& + pred() const + { return *_M_pred; } + + constexpr auto + begin() requires (!__detail::__simple_view<_Vp>) + { return ranges::begin(_M_base); } + + constexpr auto + begin() const requires range + { return ranges::begin(_M_base); } + + constexpr auto + end() requires (!__detail::__simple_view<_Vp>) + { return _Sentinel(ranges::end(_M_base), + addressof(*_M_pred)); } + + constexpr auto + end() const requires range + { return _Sentinel(ranges::end(_M_base), + addressof(*_M_pred)); } + }; + + template + take_while_view(_Range&&, _Pred) + -> take_while_view, _Pred>; + + namespace views + { + inline constexpr _RangeAdaptor take_while + = [] (_Range&& __r, _Pred&& __p) + { + return take_while_view{std::forward<_Range>(__r), std::forward<_Pred>(__p)}; + }; + } // namespace views + + template + class drop_view : public view_interface> + { + private: + _Vp _M_base; + range_difference_t<_Vp> _M_count; + + public: + drop_view() = default; + + constexpr + drop_view(_Vp __base, range_difference_t<_Vp> __count) + : _M_base(std::move(__base)), _M_count(__count) + { __glibcxx_assert(__count >= 0); } + + constexpr _Vp + base() const& requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr auto + begin() requires (!(__detail::__simple_view<_Vp> + && random_access_range<_Vp>)) + { + // XXX: we need to cache the result here as per [range.drop.view] + return ranges::next(ranges::begin(_M_base), _M_count, + ranges::end(_M_base)); + } + + constexpr auto + begin() const requires random_access_range + { + return ranges::next(ranges::begin(_M_base), _M_count, + ranges::end(_M_base)); + } + + constexpr auto + end() requires (!__detail::__simple_view<_Vp>) + { return ranges::end(_M_base); } + + constexpr auto + end() const requires range + { return ranges::end(_M_base); } + + constexpr auto + size() requires sized_range<_Vp> + { + const auto __s = ranges::size(_M_base); + const auto __c = static_cast(_M_count); + return __s < __c ? 0 : __s - __c; + } + + constexpr auto + size() const requires sized_range + { + const auto __s = ranges::size(_M_base); + const auto __c = static_cast(_M_count); + return __s < __c ? 0 : __s - __c; + } + }; + + template + drop_view(_Range&&, range_difference_t<_Range>) + -> drop_view>; + + namespace views + { + inline constexpr _RangeAdaptor drop + = [] (_Range&& __r, _Tp&& __n) + { + return drop_view{std::forward<_Range>(__r), std::forward<_Tp>(__n)}; + }; + } // namespace views + + template + requires input_range<_Vp> && is_object_v<_Pred> + && indirect_unary_predicate> + class drop_while_view : public view_interface> + { + private: + _Vp _M_base; + __detail::__box<_Pred> _M_pred; + + public: + drop_while_view() = default; + + constexpr + drop_while_view(_Vp __base, _Pred __pred) + : _M_base(std::move(__base)), _M_pred(std::move(__pred)) + { } + + constexpr _Vp + base() const& requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr const _Pred& + pred() const + { return *_M_pred; } + + constexpr auto + begin() + { + // XXX: we need to cache the result here as per [range.drop.while.view] + return __detail::find_if_not(_M_base, cref(*_M_pred)); + } + + constexpr auto + end() + { return ranges::end(_M_base); } + }; + + template + drop_while_view(_Range&&, _Pred) + -> drop_while_view, _Pred>; + + namespace views + { + inline constexpr _RangeAdaptor drop_while + = [] (_Range&& __r, _Pred&& __p) + { + return drop_while_view{std::forward<_Range>(__r), + std::forward<_Pred>(__p)}; + }; + } // namespace views + + template + requires view<_Vp> && input_range> + && (is_reference_v> + || view>) + class join_view : public view_interface> + { + private: + using _InnerRange = range_reference_t<_Vp>; + + template + struct _Sentinel; + + template + struct _Iterator + { + private: + using _Parent = conditional_t<_Const, const join_view, join_view>; + using _Base = conditional_t<_Const, const _Vp, _Vp>; + + static constexpr bool _S_ref_is_glvalue + = is_reference_v>; + + constexpr void + _M_satisfy() + { + auto __update_inner = [this] (range_reference_t<_Base> __x) -> auto& + { + if constexpr (_S_ref_is_glvalue) + return __x; + else + return (_M_parent->_M_inner = views::all(std::move(__x))); + }; + + for (; _M_outer != ranges::end(_M_parent->_M_base); ++_M_outer) + { + auto& inner = __update_inner(*_M_outer); + _M_inner = ranges::begin(inner); + if (_M_inner != ranges::end(inner)) + return; + } + + if constexpr (_S_ref_is_glvalue) + _M_inner = iterator_t>(); + } + + static constexpr auto + _S_iter_concept() + { + if constexpr (_S_ref_is_glvalue + && bidirectional_range<_Base> + && bidirectional_range>) + return bidirectional_iterator_tag{}; + else if constexpr (_S_ref_is_glvalue + && forward_range<_Base> + && forward_range>) + return forward_iterator_tag{}; + else + return input_iterator_tag{}; + } + + static constexpr auto + _S_iter_cat() + { + using _OuterCat + = iterator_traits>::iterator_category; + using _InnerCat + = iterator_traits>> + ::iterator_category; + if constexpr (_S_ref_is_glvalue + && derived_from<_OuterCat, bidirectional_iterator_tag> + && derived_from<_InnerCat, bidirectional_iterator_tag>) + return bidirectional_iterator_tag{}; + else if constexpr (_S_ref_is_glvalue + && derived_from<_OuterCat, forward_iterator_tag> + && derived_from<_InnerCat, forward_iterator_tag>) + return forward_iterator_tag{}; + else if constexpr (derived_from<_OuterCat, input_iterator_tag> + && derived_from<_InnerCat, input_iterator_tag>) + return input_iterator_tag{}; + else + return output_iterator_tag{}; + } + + iterator_t<_Base> _M_outer = iterator_t<_Base>(); + iterator_t> _M_inner + = iterator_t>(); + _Parent* _M_parent = nullptr; + + public: + using iterator_concept = decltype(_S_iter_concept()); + using iterator_category = decltype(_S_iter_cat()); + using value_type = range_value_t>; + using difference_type + = common_type_t, + range_difference_t>>; + + _Iterator() = default; + + // XXX: had to change the type of __outer from iterator_t<_Vp> to + // iterator_t<_Base> here, a possible defect in the spec? + constexpr + _Iterator(_Parent& __parent, iterator_t<_Base> __outer) + : _M_outer(std::move(__outer)), _M_parent(addressof(__parent)) + { _M_satisfy(); } + + constexpr + _Iterator(_Iterator __i) + requires _Const + && convertible_to, iterator_t<_Base>> + && convertible_to, + iterator_t>> + : _M_outer(std::move(__i._M_outer)), _M_inner(__i._M_inner), + _M_parent(__i._M_parent) + { } + + constexpr decltype(auto) + operator*() const + { return *_M_inner; } + + constexpr iterator_t<_Base> + operator->() const + requires __detail::__has_arrow> + && copyable> + { return _M_inner; } + + constexpr _Iterator& + operator++() + { + auto&& __inner_range = [this] () -> decltype(auto) { + if constexpr (_S_ref_is_glvalue) + return *_M_outer; + else + return _M_parent->_M_inner; + }(); + if (++_M_inner == ranges::end(__inner_range)) + { + ++_M_outer; + _M_satisfy(); + } + return *this; + } + + constexpr void + operator++(int) + { ++*this; } + + constexpr _Iterator + operator++(int) + requires _S_ref_is_glvalue && forward_range<_Base> + && forward_range> + { + auto __tmp = *this; + ++*this; + return __tmp; + } + + constexpr _Iterator& + operator--() + requires _S_ref_is_glvalue && bidirectional_range<_Base> + && bidirectional_range> + { + if (_M_outer == ranges::end(_M_parent->_M_base)) + _M_inner = ranges::end(*--_M_outer); + while (_M_inner == ranges::begin(*_M_outer)) + _M_inner = ranges::end(*--_M_outer); + --_M_inner; + return *this; + } + + constexpr _Iterator + operator--(int) + requires _S_ref_is_glvalue && bidirectional_range<_Base> + && bidirectional_range> + { + auto __tmp = *this; + --*this; + return __tmp; + } + + friend constexpr bool + operator==(const _Iterator& __x, const _Iterator& __y) + requires _S_ref_is_glvalue + && equality_comparable> + && equality_comparable>> + { + return (__x._M_outer == __y._M_outer + && __x._M_inner == __y._M_inner); + } + + friend constexpr decltype(auto) + iter_move(const _Iterator& __i) + noexcept(noexcept(ranges::iter_move(__i._M_inner))) + { return ranges::iter_move(__i._M_inner); } + + friend constexpr void + iter_swap(const _Iterator& __x, const _Iterator& __y) + noexcept(noexcept(ranges::iter_swap(__x._M_inner, __y._M_inner))) + { return ranges::iter_swap(__x._M_inner, __y._M_inner); } + + friend _Sentinel<_Const>; + }; + + template + struct _Sentinel + { + private: + using _Parent = conditional_t<_Const, const join_view, join_view>; + using _Base = conditional_t<_Const, const _Vp, _Vp>; + + constexpr bool + __equal(const _Iterator<_Const>& __i) const + { return __i._M_outer == _M_end; } + + sentinel_t<_Base> _M_end = sentinel_t<_Base>(); + + public: + _Sentinel() = default; + + constexpr explicit + _Sentinel(_Parent& __parent) + : _M_end(ranges::end(__parent._M_base)) + { } + + constexpr + _Sentinel(_Sentinel __s) + requires _Const && convertible_to, sentinel_t<_Base>> + : _M_end(std::move(__s._M_end)) + { } + + friend constexpr bool + operator==(const _Iterator<_Const>& __x, const _Sentinel& __y) + { return __y.__equal(__x); } + }; + + _Vp _M_base = _Vp(); + + // XXX: _M_inner is "present only when !is_reference_v<_InnerRange>" + // Applied P3278 and made this field mutable. + [[no_unique_address]] mutable + conditional_t, + all_view<_InnerRange>, __detail::_Empty> _M_inner; + + public: + join_view() = default; + + constexpr explicit + join_view(_Vp __base) + : _M_base(std::move(__base)) + { } + + /* XXX: P3280 removes this constructor + template + requires viewable_range<_Range> + && constructible_from<_Vp, all_view<_Range>> + constexpr explicit + join_view(_Range&& __r) + : _M_base(views::all(std::forward<_Range>(__r))) + { } + */ + + constexpr _Vp + base() const& requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr auto + begin() + { + return _Iterator<__detail::__simple_view<_Vp>>{*this, + ranges::begin(_M_base)}; + } + + constexpr auto + begin() const + requires input_range + && is_reference_v> + { + return _Iterator{*this, ranges::begin(_M_base)}; + } + + constexpr auto + end() + { + if constexpr (forward_range<_Vp> && is_reference_v<_InnerRange> + && forward_range<_InnerRange> + && common_range<_Vp> && common_range<_InnerRange>) + return _Iterator<__detail::__simple_view<_Vp>>{*this, + ranges::end(_M_base)}; + else + return _Sentinel<__detail::__simple_view<_Vp>>{*this}; + } + + constexpr auto + end() const + requires input_range + && is_reference_v> + { + if constexpr (forward_range + && is_reference_v> + && forward_range> + && common_range + && common_range>) + return _Iterator{*this, ranges::end(_M_base)}; + else + return _Sentinel{*this}; + } + }; + + template + explicit join_view(_Range&&) -> join_view>; + + namespace views + { + inline constexpr _RangeAdaptorClosure join + = [] (_Range&& __r) + { + return join_view{std::forward<_Range>(__r)}; + }; + } // namespace views + + namespace __detail + { + template + struct __require_constant; + + template + concept __tiny_range = sized_range<_Range> + && requires + { typename __require_constant::size()>; } + && (remove_reference_t<_Range>::size() <= 1); + } + + template + requires view<_Vp> && view<_Pattern> + && indirectly_comparable, iterator_t<_Pattern>, + ranges::equal_to> + && (forward_range<_Vp> || __detail::__tiny_range<_Pattern>) + class split_view : public view_interface> + { + private: + template + struct _InnerIter; + + template + struct _OuterIter + { + private: + using _Parent = conditional_t<_Const, const split_view, split_view>; + using _Base = conditional_t<_Const, const _Vp, _Vp>; + + constexpr bool + __at_end() const + { return _M_current == ranges::end(_M_parent->_M_base); } + + // XXX: [24.7.11.3.1] + // Many of the following specifications refer to the notional member + // current of outer-iterator. current is equivalent to current_­ if + // V models forward_range, and parent_->current_­ otherwise. + constexpr auto& + __current() + { + if constexpr (forward_range<_Vp>) + return _M_current; + else + return _M_parent->_M_current; + } + + constexpr auto& + __current() const + { + if constexpr (forward_range<_Vp>) + return _M_current; + else + return _M_parent->_M_current; + } + + _Parent* _M_parent = nullptr; + + // XXX: _M_current is present only if "V models forward_range" + [[no_unique_address]] + conditional_t, + iterator_t<_Base>, __detail::_Empty> _M_current; + + public: + using iterator_concept = conditional_t, + forward_iterator_tag, + input_iterator_tag>; + using iterator_category = input_iterator_tag; + using difference_type = range_difference_t<_Base>; + + struct value_type : view_interface + { + private: + _OuterIter _M_i = _OuterIter(); + + public: + value_type() = default; + + constexpr explicit + value_type(_OuterIter __i) + : _M_i(std::move(__i)) + { } + + constexpr _InnerIter<_Const> + begin() const + requires copyable<_OuterIter> + { return _InnerIter<_Const>{_M_i}; } + + constexpr _InnerIter<_Const> + begin() + requires (!copyable<_OuterIter>) + { return _InnerIter<_Const>{std::move(_M_i)}; } + + constexpr default_sentinel_t + end() const + { return default_sentinel; } + }; + + _OuterIter() = default; + + constexpr explicit + _OuterIter(_Parent& __parent) requires (!forward_range<_Base>) + : _M_parent(address(__parent)) + { } + + constexpr + _OuterIter(_Parent& __parent, iterator_t<_Base> __current) + requires forward_range<_Base> + : _M_parent(addressof(__parent)), _M_current(std::move(__current)) + { } + + constexpr + _OuterIter(_OuterIter __i) + requires _Const + && convertible_to, iterator_t> + : _M_parent(__i._M_parent), _M_current(std::move(__i._M_current)) + { } + + constexpr value_type + operator*() const + { return value_type{*this}; } + + constexpr _OuterIter& + operator++() + { + const auto __end = ranges::end(_M_parent->_M_base); + if (_M_current == __end) + return *this; + const auto __pbegin = ranges::begin(_M_parent->_M_pattern); + const auto __pend = ranges::end(_M_parent->_M_pattern); + if (__pbegin == __pend) + ++_M_current; + else + do + { + auto [__b, __p] + = __detail::mismatch(std::move(_M_current), __end, + __pbegin, __pend); + _M_current = std::move(__b); + if (__p == __pend) + break; + } while (++_M_current != __end); + return *this; + } + + constexpr decltype(auto) + operator++(int) + { + if constexpr (forward_range<_Base>) + { + auto __tmp = *this; + ++*this; + return __tmp; + } + else + ++*this; + } + + friend constexpr bool + operator==(const _OuterIter& __x, const _OuterIter& __y) + requires forward_range<_Base> + { return __x._M_current == __y._M_current; } + + friend constexpr bool + operator==(const _OuterIter& __x, default_sentinel_t) + { return __x.__at_end(); }; + + friend _InnerIter<_Const>; + }; + + template + struct _InnerIter + { + private: + using _Base = conditional_t<_Const, const _Vp, _Vp>; + + constexpr bool + __at_end() const + { + // XXX: the spec says + // auto [__pcur, __pend] = subrange{_M_i._M_parent->_M_pattern}; + // but a subrange cannot be decomposed with a structured binding + auto& __pattern = _M_i._M_parent->_M_pattern; + auto __pcur = ranges::begin(__pattern); + auto __pend = ranges::end(__pattern); + + auto __end = ranges::end(_M_i._M_parent->_M_base); + if constexpr (__detail::__tiny_range<_Pattern>) + { + const auto& __cur = _M_i.__current(); + if (__cur == __end) + return true; + if (__pcur == __pend) + return _M_incremented; + return *__cur == *__pcur; + } + else + { + auto __cur = _M_i.__current(); + if (__cur == __end) + return true; + if (__pcur == __pend) + return _M_incremented; + do + { + if (*__cur != *__pcur) + return false; + if (++__pcur == __pend) + return true; + } while (++__cur != __end); + return false; + } + } + + static constexpr auto + _S_iter_cat() + { + using _Cat = iterator_traits>::iterator_category; + if constexpr (derived_from<_Cat, forward_iterator_tag>) + return forward_iterator_tag{}; + else + return _Cat{}; + } + + static constexpr decltype(auto) + __iter_move(const _InnerIter& __i = {}) + noexcept(noexcept(ranges::iter_move(__i._M_i.__current()))) + { return ranges::iter_move(__i._M_i.__current()); } + + static constexpr void + __iter_swap(const _InnerIter& __x = {}, const _InnerIter& __y = {}) + noexcept(noexcept(ranges::iter_swap(__x._M_i.__current(), + __y._M_i.__current()))) + { ranges::iter_swap(__x._M_i.__current(), __y._M_i.__current()); } + + _OuterIter<_Const> _M_i = _OuterIter<_Const>(); + bool _M_incremented = false; + + public: + using iterator_concept = typename _OuterIter<_Const>::iterator_concept; + using iterator_category = decltype(_S_iter_cat()); + using value_type = range_value_t<_Base>; + using difference_type = range_difference_t<_Base>; + + _InnerIter() = default; + + constexpr explicit + _InnerIter(_OuterIter<_Const> __i) + : _M_i(std::move(__i)) + { } + + constexpr decltype(auto) + operator*() const + { return *_M_i._M_current; } + + constexpr _InnerIter& + operator++() + { + _M_incremented = true; + if constexpr (!forward_range<_Base>) + if constexpr (_Pattern::size() == 0) + return *this; + ++_M_i.__current(); + return *this; + } + + constexpr decltype(auto) + operator++(int) + { + if constexpr (forward_range<_Vp>) + { + auto __tmp = *this; + ++*this; + return __tmp; + } + else + ++*this; + } + + friend constexpr bool + operator==(const _InnerIter& __x, const _InnerIter& __y) + requires forward_range<_Base> + { return __x._M_i.__current() == __y._M_i.__current(); } + + friend constexpr bool + operator==(const _InnerIter& __x, default_sentinel_t) + { return __x.__at_end(); } + + friend constexpr decltype(auto) + iter_move(const _InnerIter& __i) noexcept(noexcept(__iter_move())) + { return __iter_move(__i); } + + friend constexpr void + iter_swap(const _InnerIter& __x, const _InnerIter& __y) + noexcept(noexcept(__iter_swap())) + requires indirectly_swappable> + { __iter_swap(__x, __y); } + }; + + _Vp _M_base = _Vp(); + _Pattern _M_pattern = _Pattern(); + + // XXX: _M_current is "present only if !forward_range" + [[no_unique_address]] + conditional_t, + iterator_t<_Vp>, __detail::_Empty> _M_current; + + + public: + split_view() = default; + + constexpr + split_view(_Vp __base, _Pattern __pattern) + : _M_base(std::move(__base)), _M_pattern(std::move(__pattern)) + { } + + /* XXX: P3280 removes this constructor + template + requires constructible_from<_Vp, all_view<_Range>> + && constructible_from<_Pattern, all_view<_Pred>> + constexpr + split_view(_Range&& __r, _Pred&& __p) + : _M_base(views::all(std::forward<_Range>(__r))), + _M_pattern(views::all(std::forward<_Pred>(__p))) + { } + */ + + template + requires constructible_from<_Vp, all_view<_Range>> + && constructible_from<_Pattern, single_view>> + constexpr + split_view(_Range&& __r, range_value_t<_Range> __e) + : _M_base(views::all(std::forward<_Range>(__r))), + _M_pattern(std::move(__e)) + { } + + constexpr _Vp + base() const& requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr auto + begin() + { + if constexpr (forward_range<_Vp>) + return _OuterIter<__detail::__simple_view<_Vp>>{*this, + ranges::begin(_M_base)}; + else + { + _M_current = ranges::begin(_M_base); + return _OuterIter{*this}; + } + } + + constexpr auto + begin() const requires forward_range<_Vp> && forward_range + { + return _OuterIter{*this, ranges::begin(_M_base)}; + } + + constexpr auto + end() requires forward_range<_Vp> && common_range<_Vp> + { + return _OuterIter<__detail::__simple_view<_Vp>>{*this, ranges::end(_M_base)}; + } + + constexpr auto + end() const + { + if constexpr (forward_range<_Vp> + && forward_range + && common_range) + return _OuterIter{*this, ranges::end(_M_base)}; + else + return default_sentinel; + } + }; + + template + split_view(_Range&&, _Pred&&) + -> split_view, all_view<_Pred>>; + + template + split_view(_Range&&, range_value_t<_Range>) + -> split_view, single_view>>; + + namespace views + { + inline constexpr _RangeAdaptor split + = [] (_Range&& __r, _Fp&& __f) + { + return split_view{std::forward<_Range>(__r), std::forward<_Fp>(__f)}; + }; + } // namespace views + + namespace views + { + struct _Counted + { + template + constexpr auto + operator()(_Iter __i, iter_difference_t<_Iter> __n) const + { + if constexpr (random_access_iterator<_Iter>) + return subrange{__i, __i + __n}; + else + return subrange{counted_iterator{__i, __n}, default_sentinel}; + } + }; + + inline constexpr _Counted counted{}; + } // namespace views + + template + requires (!common_range<_Vp>) && copyable> + class common_view : public view_interface> + { + private: + _Vp _M_base = _Vp(); + + public: + common_view() = default; + + constexpr explicit + common_view(_Vp __r) + : _M_base(std::move(__r)) + { } + + /* XXX: P3280 doesn't remove this constructor, but I think it should? + template + requires (!common_range<_Range>) && constructible_from<_Vp, all_view<_Range>> + constexpr explicit + common_view(_Range&& __r) + : _M_base(views::all(std::forward<_Range>(__r))) + { } + */ + + constexpr _Vp + base() const& requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr auto + begin() + { + if constexpr (random_access_range<_Vp> && sized_range<_Vp>) + return ranges::begin(_M_base); + else + return common_iterator, sentinel_t<_Vp>> + (ranges::begin(_M_base)); + } + + constexpr auto + begin() const requires range + { + if constexpr (random_access_range && sized_range) + return ranges::begin(_M_base); + else + return common_iterator, sentinel_t> + (ranges::begin(_M_base)); + } + + constexpr auto + end() + { + if constexpr (random_access_range<_Vp> && sized_range<_Vp>) + return ranges::begin(_M_base) + ranges::size(_M_base); + else + return common_iterator, sentinel_t<_Vp>> + (ranges::end(_M_base)); + } + + constexpr auto + end() const requires range + { + if constexpr (random_access_range && sized_range) + return ranges::begin(_M_base) + ranges::size(_M_base); + else + return common_iterator, sentinel_t> + (ranges::end(_M_base)); + } + + constexpr auto + size() requires sized_range<_Vp> + { return ranges::size(_M_base); } + + constexpr auto + size() const requires sized_range + { return ranges::size(_M_base); } + }; + + template + common_view(_Range&&) -> common_view>; + + namespace views + { + inline constexpr _RangeAdaptorClosure common + = [] (_Range&& __r) + { + if constexpr (common_range<_Range> + && requires { views::all(std::forward<_Range>(__r)); }) + return views::all(std::forward<_Range>(__r)); + else + return common_view{std::forward<_Range>(__r)}; + }; + + } // namespace views + + template + requires bidirectional_range<_Vp> + class reverse_view : public view_interface> + { + private: + _Vp _M_base = _Vp(); + + public: + reverse_view() = default; + + constexpr explicit + reverse_view(_Vp __r) + : _M_base(std::move(__r)) + { } + + /* XXX: P3280 removes this constructor + template + requires bidirectional_range<_Range> && constructible_from<_Vp, all_view<_Range>> + constexpr explicit + reverse_view(_Range&& __r) + : _M_base(views::all(std::forward<_Range>(__r))) + { } + */ + + constexpr _Vp + base() const& requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr reverse_iterator> + begin() + { + // XXX: we need to cache the result here as per [range.reverse.view] + return make_reverse_iterator(ranges::next(ranges::begin(_M_base), + ranges::end(_M_base))); + } + + constexpr auto + begin() requires common_range<_Vp> + { return make_reverse_iterator(ranges::end(_M_base)); } + + constexpr auto + begin() const requires common_range + { return make_reverse_iterator(ranges::end(_M_base)); } + + constexpr reverse_iterator> + end() + { return make_reverse_iterator(ranges::begin(_M_base)); } + + constexpr auto + end() const requires common_range + { return make_reverse_iterator(ranges::begin(_M_base)); } + + constexpr auto + size() requires sized_range<_Vp> + { return ranges::size(_M_base); } + + constexpr auto + size() const requires sized_range + { return ranges::size(_M_base); } + }; + + template + reverse_view(_Range&&) -> reverse_view>; + + namespace views + { + namespace __detail + { + template + inline constexpr bool __is_reversible_subrange = false; + + template + inline constexpr bool + __is_reversible_subrange, + reverse_iterator<_Iter>, + _Kind>> = true; + + template + inline constexpr bool __is_reverse_view = false; + + template + inline constexpr bool __is_reverse_view> = true; + } + + inline constexpr _RangeAdaptorClosure reverse + = [] (_Range&& __r) + { + using _Tp = remove_cvref_t<_Range>; + if constexpr (__detail::__is_reverse_view<_Tp>) + return std::forward<_Range>(__r).base(); + else if constexpr (__detail::__is_reversible_subrange<_Tp>) + { + using _Iter = decltype(ranges::begin(__r).base()); + if constexpr (sized_range<_Tp>) + return subrange<_Iter, _Iter, subrange_kind::sized> + (__r.end().base(), __r.begin().base(), __r.size()); + else + return subrange<_Iter, _Iter, subrange_kind::unsized> + (__r.end().base(), __r.begin().base()); + } + else + return reverse_view{std::forward<_Range>(__r)}; + }; + } // namespace views + + namespace __detail + { + template + concept __has_tuple_element = requires(_Tp __t) + { + typename tuple_size<_Tp>::type; + requires _Nm < tuple_size_v<_Tp>; + typename tuple_element_t<_Nm, _Tp>; + // XXX: we applied P3323 here + { get<_Nm>(__t) } -> convertible_to&>; + }; + } + + template + requires view<_Vp> + && __detail::__has_tuple_element, _Nm> + && __detail::__has_tuple_element>, + _Nm> + class elements_view : public view_interface> + { + public: + elements_view() = default; + + constexpr explicit + elements_view(_Vp base) + : _M_base(std::move(base)) + { } + + constexpr _Vp + base() const& requires copy_constructible<_Vp> + { return _M_base; } + + constexpr _Vp + base() && + { return std::move(_M_base); } + + constexpr auto + begin() requires (!__detail::__simple_view<_Vp>) + { return _Iterator(ranges::begin(_M_base)); } + + constexpr auto + begin() const requires __detail::__simple_view<_Vp> + { return _Iterator(ranges::begin(_M_base)); } + + constexpr auto + end() requires (!__detail::__simple_view<_Vp>) + { return ranges::end(_M_base); } + + constexpr auto + end() const requires __detail::__simple_view<_Vp> + { return ranges::end(_M_base); } + + constexpr auto + size() requires sized_range<_Vp> + { return ranges::size(_M_base); } + + constexpr auto + size() const requires sized_range + { return ranges::size(_M_base); } + + private: + template + struct _Iterator + { + using _Base = conditional_t<_Const, const _Vp, _Vp>; + + iterator_t<_Base> _M_current; + + friend _Iterator; + + public: + using iterator_category + = typename iterator_traits>::iterator_category; + using value_type + = remove_cvref_t>>; + using difference_type = range_difference_t<_Base>; + + _Iterator() = default; + + constexpr explicit + _Iterator(iterator_t<_Base> current) + : _M_current(std::move(current)) + { } + + constexpr + _Iterator(_Iterator i) + requires _Const && convertible_to, iterator_t<_Base>> + : _M_current(std::move(i._M_current)) + { } + + constexpr iterator_t<_Base> + base() const& + requires copyable> + { return _M_current; } + + constexpr iterator_t<_Base> + base() && + { return std::move(_M_current); } + + constexpr decltype(auto) + operator*() const + { return get<_Nm>(*_M_current); } + + constexpr _Iterator& + operator++() + { + ++_M_current; + return *this; + } + + constexpr void + operator++(int) requires (!forward_range<_Base>) + { ++_M_current; } + + constexpr _Iterator + operator++(int) requires forward_range<_Base> + { + auto __tmp = *this; + ++_M_current; + return __tmp; + } + + constexpr _Iterator& + operator--() requires bidirectional_range<_Base> + { + --_M_current; + return *this; + } + + constexpr _Iterator + operator--(int) requires bidirectional_range<_Base> + { + auto __tmp = *this; + --_M_current; + return __tmp; + } + + constexpr _Iterator& + operator+=(difference_type __n) + requires random_access_range<_Base> + { + _M_current += __n; + return *this; + } + + constexpr _Iterator& + operator-=(difference_type __n) + requires random_access_range<_Base> + { + _M_current -= __n; + return *this; + } + + constexpr decltype(auto) + operator[](difference_type __n) const + requires random_access_range<_Base> + { return get<_Nm>(*(_M_current + __n)); } + + friend constexpr bool + operator==(const _Iterator& __x, const _Iterator& __y) + requires equality_comparable> + { return __x._M_current == __y._M_current; } + + friend constexpr bool + operator==(const _Iterator& __x, const sentinel_t<_Base>& __y) + { return __x._M_current == __y; } + + friend constexpr bool + operator<(const _Iterator& __x, const _Iterator& __y) + requires random_access_range<_Base> + { return __x._M_current < __y._M_current; } + + friend constexpr bool + operator>(const _Iterator& __x, const _Iterator& __y) + requires random_access_range<_Base> + { return __y._M_current < __x._M_current; } + + friend constexpr bool + operator<=(const _Iterator& __x, const _Iterator& __y) + requires random_access_range<_Base> + { return !(__y._M_current > __x._M_current); } + + friend constexpr bool + operator>=(const _Iterator& __x, const _Iterator& __y) + requires random_access_range<_Base> + { return !(__x._M_current > __y._M_current); } + +#ifdef __cpp_lib_threeway_comparison + friend constexpr compare_three_way_result_t> + operator<=>(const _Iterator& __x, const _Iterator& __y) + requires random_access_range<_Base> + && three_way_comparable> + { return __x._M_current <=> __y._M_current; } +#endif + + friend constexpr _Iterator + operator+(const _Iterator& __x, difference_type __y) + requires random_access_range<_Base> + { return _Iterator{__x} += __y; } + + friend constexpr _Iterator + operator+(difference_type __x, const _Iterator& __y) + requires random_access_range<_Base> + { return __y + __x; } + + friend constexpr _Iterator + operator-(const _Iterator& __x, difference_type __y) + requires random_access_range<_Base> + { return _Iterator{__x} -= __y; } + + friend constexpr difference_type + operator-(const _Iterator& __x, const _Iterator& __y) + requires random_access_range<_Base> + { return __x._M_current - __y._M_current; } + + friend constexpr difference_type + operator-(const _Iterator<_Const>& __x, const sentinel_t<_Base>& __y) + requires sized_sentinel_for, iterator_t<_Base>> + { return __x._M_current - __y; } + + friend constexpr difference_type + operator-(const sentinel_t<_Base>& __x, const _Iterator<_Const>& __y) + requires sized_sentinel_for, iterator_t<_Base>> + { return -(__y - __x); } + }; + + _Vp _M_base = _Vp(); + }; + + template + using keys_view = elements_view, 0>; + + template + using values_view = elements_view, 1>; + + namespace views + { + template + inline constexpr _RangeAdaptorClosure elements + = [] (_Range&& __r) + { + return elements_view, _Nm>{std::forward<_Range>(__r)}; + }; + + inline constexpr _RangeAdaptorClosure keys = elements<0>; + inline constexpr _RangeAdaptorClosure values = elements<1>; + } // namespace views + } // namespace ranges _GLIBCXX_END_NAMESPACE_VERSION } // namespace diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc new file mode 100644 index 00000000000..7815475ed24 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc @@ -0,0 +1,124 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +namespace ranges = std::ranges; +namespace views = std::ranges::views; + +void +test01() +{ + int x[] = {1,2,3,4,5}; + auto v = views::all(x); + + static_assert(ranges::view); + static_assert(ranges::random_access_range); + + VERIFY( ranges::size(v) == 5 ); + VERIFY( ranges::size(x | views::all) == 5 ); + VERIFY( ranges::size(v | views::all | views::all) == 5 ); + VERIFY( ranges::size(v | (views::all | views::all)) == 5 ); + + ranges::reverse(v); + VERIFY( ranges::equal(v, (int[]){5,4,3,2,1}) ); +} + +void +test02() +{ + int x[5] = { 0 }; + int k = 0; + for (auto&& i : ranges::ref_view{x}) + i += ++k; + VERIFY( ranges::equal(x, (int[]){1,2,3,4,5}) ); +} + +constexpr bool +test03() +{ + std::array ints{0,1,2,3,4,5}; + auto even = [] (int i) { return i%2==0; }; + auto odd = [] (int i) { return i%2==1; }; + auto square = [] (int i) { return i*i; }; + int count = 0; + for (auto v : (ints + | (views::all + | (views::filter(even) + | (views::filter(odd) | views::all))) + | views::transform(square))) + count++; + return count == 0; +} + +constexpr bool +test04() +{ + auto even = [] (int i) { return i%2==0; }; + auto odd = [] (int i) { return i%2==1; }; + auto square = [] (int i) { return i*i; }; + auto increment = [] (int i) { return i+1; }; + auto small = [] (int i) { return i<30; }; + auto non_negative = [] (int i) { return i>=0; }; + auto negative = [] (int i) { return i<0; }; + int count = 0; + return ranges::equal(views::iota(-5) + | views::drop_while(negative) + | views::take_while(non_negative) + | views::transform(increment) + | views::filter(odd) + | views::take(3) + | views::all + | views::transform(square), + views::iota(-5) + | views::drop_while(negative) + | views::drop(1) + | views::filter(odd) + | views::transform(square) + | views::take_while(small) + | views::take_while(small)); +} + +static_assert(std::is_empty_v); +static_assert(sizeof(decltype(views::take(5) | views::drop(5))) + == sizeof(decltype(views::take(5) + | views::join + | views::common + | views::all + | views::keys + | views::drop(5) + | views::reverse))); + +int +main() +{ + test01(); + test02(); + static_assert(test03()); + static_assert(test04()); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/common.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/common.cc new file mode 100644 index 00000000000..d1600544605 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/common.cc @@ -0,0 +1,68 @@ +// Copyright (C) 2019-2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; +namespace views = ranges::views; + +void +test01() +{ + int x[] = {1,2,1,3}; + auto v = x | views::common; + VERIFY( std::count(v.begin(), v.end(), 1) == 2); + static_assert(ranges::common_range); + static_assert(ranges::view); + static_assert(ranges::random_access_range); + static_assert(std::same_as); + + auto v2 = v | (views::common | views::common); + VERIFY( std::count(v2.begin(), v2.end(), 1) == 2); +} + +void +test02() +{ + int x[] = {1,2,1,3}; + test_range rx(x); + auto v = ranges::common_view(rx); + VERIFY( std::count(v.begin(), v.end(), 1) == 2); + static_assert(ranges::common_range); + static_assert(ranges::view); + static_assert(ranges::forward_range); + static_assert(std::same_as); + + auto v2 = v | (views::common | views::common); + VERIFY( std::count(v2.begin(), v2.end(), 1) == 2); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/counted.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/counted.cc new file mode 100644 index 00000000000..c81a8a89741 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/counted.cc @@ -0,0 +1,64 @@ +// Copyright (C) 2019-2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; +namespace views = ranges::views; + +void +test01() +{ + int x[] = {0,1,2,3,4,5,0,1,2,3,4,5}; + auto v = views::counted(x, 5); + VERIFY( ranges::equal(v, (int[]){0,1,2,3,4}) ); + using R = decltype(v); + static_assert(ranges::view); + static_assert(ranges::sized_range); + static_assert(ranges::common_range); + static_assert(ranges::random_access_range); +} + +void +test02() +{ + int x[] = {0,1,2,3,4,5,0,1,2,3,4,5}; + test_range rx(x); + auto v = views::counted(rx.begin(), 5); + VERIFY( ranges::equal(v, (int[]){0,1,2,3,4}) ); + using R = decltype(v); + static_assert(ranges::view); + static_assert(ranges::sized_range); + static_assert(!ranges::common_range); + static_assert(!ranges::bidirectional_range); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc new file mode 100644 index 00000000000..93fbafcf5a3 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc @@ -0,0 +1,107 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; +namespace views = ranges::views; + +void +test01() +{ + int x[] = {1,2,3,4,5}; + auto v = x | views::drop(3); + using R = decltype(v); + static_assert(ranges::view); + static_assert(ranges::sized_range); + static_assert(ranges::random_access_range); + VERIFY( ranges::equal(v, (int[]){4,5}) ); +} + +void +test02() +{ + int x[] = {1,2,3,4,5}; + auto t = views::drop(3) | views::reverse; + auto v = x | t; + using R = decltype(v); + static_assert(ranges::view); + static_assert(ranges::sized_range); + static_assert(ranges::random_access_range); + VERIFY( ranges::equal(v, (int[]){5,4}) ); +} + +void +test03() +{ + int x[] = {1,2,3,4,5}; + test_range rx(x); + auto v = rx | views::drop(3); + using R = decltype(v); + static_assert(ranges::view); + static_assert(!ranges::sized_range); + static_assert(ranges::bidirectional_range); + VERIFY( ranges::equal(v, (int[]){4,5}) ); +} + + +void +test04() +{ + auto v = views::iota(0) | views::drop(10); + using R = decltype(v); + static_assert(ranges::view); + static_assert(!ranges::sized_range); + VERIFY( ranges::equal(v | views::take(3), (int[]){10,11,12}) ); +} + +void +test05() +{ + int x[] = {1,2,3}; + auto r = ranges::subrange(x, x+1); + auto v = views::drop(r, 2); + VERIFY( ranges::begin(v) == x+1 ); + VERIFY( ranges::size(v) == 0 ); +} + +void +test06() +{ + int x[] = {1,2,3}; + VERIFY( ranges::empty(x | views::drop(10)) ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); + test06(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/drop_while.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/drop_while.cc new file mode 100644 index 00000000000..be47551563d --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/drop_while.cc @@ -0,0 +1,63 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; +namespace views = std::ranges::views; + +void +test01() +{ + auto p = [] (int i) { return i != 16; }; + auto v = views::iota(10) | views::drop_while(p); + VERIFY( ranges::equal(v | views::take(5), (int[]){16,17,18,19,20}) ); + using R = decltype(v); + static_assert(ranges::view); + static_assert(!ranges::common_range); + static_assert(ranges::random_access_range); +} + +void +test02() +{ + int x[] = {1,2,3,4,5}; + test_range rx(x); + auto v = rx | views::drop_while([] (int i) { return i<4; }); + VERIFY( ranges::equal(v, (int[]){4,5}) ); + using R = decltype(v); + static_assert(ranges::view); + static_assert(!ranges::common_range); + static_assert(ranges::bidirectional_range); +} + +int +main() +{ + test01(); + test02(); +} + diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc new file mode 100644 index 00000000000..0c6ee4bf58d --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc @@ -0,0 +1,52 @@ +// Copyright (C) 2019-2020 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 run { target c++2a } } + +#include +#include +#include +#include +#include + +namespace ranges = std::ranges; +namespace views = ranges::views; + +void +test01() +{ + std::tuple x[] = {{1,2},{3,4},{5,6}}; + auto v0 = x | views::elements<0>; + VERIFY( ranges::equal(v0, (int[]){1,3,5}) ); + VERIFY( ranges::equal(v0, x | views::keys) ); + VERIFY( ranges::size(v0) == 3 ); + + using R0 = decltype(v0); + static_assert(ranges::random_access_range); + static_assert(ranges::sized_range); + + auto v1 = x | views::reverse | views::elements<1> | views::reverse; + VERIFY( ranges::equal(v1, (int[]){2,4,6}) ); + VERIFY( ranges::equal(v1, x | views::values) ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc new file mode 100644 index 00000000000..83d52967a0f --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc @@ -0,0 +1,97 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; +namespace views = std::ranges::views; + +void +test01() +{ + int x[] = {1,2,3,4,5,6}; + auto is_odd = [] (int i) { return i%2==1; }; + auto v = x | views::filter(is_odd); + using R = decltype(v); + static_assert(std::same_as); + static_assert(ranges::view); + static_assert(ranges::input_range); + static_assert(ranges::common_range); + static_assert(!ranges::sized_range); + static_assert(ranges::bidirectional_range); + static_assert(!ranges::random_access_range); + static_assert(ranges::range>); + VERIFY( ranges::equal(v, (int[]){1,3,5}) ); + VERIFY( ranges::equal(v | views::reverse, (int[]){5,3,1}) ); +} + +void +test02() +{ + int x[] = {1,2,3,4,5,6}; + auto f = [flag=false] (int) mutable { return flag = !flag; }; + auto v = views::filter(f)(x); + using R = decltype(v); + static_assert(std::same_as); + static_assert(ranges::range); + static_assert(std::copyable); + static_assert(!ranges::view); + VERIFY( ranges::equal(v, (int[]){1,3,5}) ); +} + +struct X +{ + int i, j; +}; + +void +test03() +{ + X x[] = {{1,3}, {2,5}, {3,7}, {4,9}}; + test_range rx(x); + auto v = rx | views::filter([] (auto&& p) { return p.i%2==0; }); + int sum = 0; + for (auto i = v.begin(); i != v.end(); ++i) + sum += i->j; + VERIFY( sum == 14 ); +} + +void +test04() +{ + auto yes = [] (int) { return true; }; + VERIFY( ranges::equal(views::iota(0) | views::filter(yes) | views::take(1), + (int[]){0}) ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc new file mode 100644 index 00000000000..d3e652da009 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc @@ -0,0 +1,112 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include +#include +#include +#include + +namespace ranges = std::ranges; +namespace views = std::ranges::views; + +void +test01() +{ + using namespace std::literals; + std::string_view cs[] = {"the", "quick", "brown", "fox"}; + auto v = cs | views::join; + VERIFY( ranges::equal(v, "thequickbrownfox"sv) ); + using R = decltype(v); + static_assert(ranges::bidirectional_range); + static_assert(ranges::bidirectional_range); + static_assert(ranges::common_range); + static_assert(ranges::common_range); +} + +void +test02() +{ + auto v = (views::iota(0,4) + | views::transform([] (int i) { return views::iota(0,i); }) + | views::join); + VERIFY( ranges::equal(v, (int[]){0,0,1,0,1,2}) ); + using R = decltype(v); + static_assert(ranges::input_range); + static_assert(!ranges::range); + static_assert(!ranges::forward_range); + static_assert(!ranges::common_range); +} + +void +test03() +{ + auto v = (views::iota(0,4) + | views::transform([] (int i) { return views::iota(0,i); }) + | views::filter([] (auto) { return true; }) + | views::join); + VERIFY( ranges::equal(v, (int[]){0,0,1,0,1,2}) ); + using R = decltype(v); + static_assert(ranges::input_range); + static_assert(!ranges::range); + static_assert(!ranges::forward_range); + static_assert(!ranges::common_range); +} + +void +test04() +{ + auto v = (views::iota(0,4) + | views::transform([] (int i) { return views::iota(0,i); })); + auto v2 = ranges::ref_view{v}; + VERIFY( ranges::equal(v2 | views::join, (int[]){0,0,1,0,1,2}) ); + using R = decltype(v2); + static_assert(ranges::random_access_range); + static_assert(ranges::range); + static_assert(ranges::common_range); + static_assert(ranges::random_access_range>); + static_assert(!std::is_reference_v>); +} + +void +test05() +{ + using namespace std::literals; + std::vector x = {"the", " ", "quick", " ", "brown", " ", "fox"}; + auto v = x | views::join | views::split(' '); + auto i = v.begin(); + VERIFY( ranges::equal(*i++, "the"sv) ); + VERIFY( ranges::equal(*i++, "quick"sv) ); + VERIFY( ranges::equal(*i++, "brown"sv) ); + VERIFY( ranges::equal(*i++, "fox"sv) ); + VERIFY( i == v.end() ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/reverse.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/reverse.cc new file mode 100644 index 00000000000..b3f2e7eef3b --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/reverse.cc @@ -0,0 +1,86 @@ +// Copyright (C) 2019-2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; +namespace views = ranges::views; + +void +test01() +{ + int x[] = {1,2,3,4,5}; + auto v = x | views::reverse; + VERIFY( ranges::equal(v, (int[]){5,4,3,2,1}) ); + VERIFY( ranges::equal(v | views::reverse, x) ); + static_assert(ranges::view); + static_assert(ranges::sized_range); + static_assert(ranges::common_range); + static_assert(ranges::random_access_range); +} + +void +test02() +{ + int x[] = {1,2,3,4,5}; + test_range rx(x); + auto v = views::reverse(rx); + VERIFY( ranges::equal(v, (int[]){5,4,3,2,1}) ); + VERIFY( ranges::equal(v | views::reverse, rx) ); + static_assert(ranges::view); + static_assert(!ranges::sized_range); + static_assert(ranges::common_range); + static_assert(!ranges::random_access_range); + static_assert(ranges::bidirectional_range); +} + +void +test03() +{ + int x[] = {1,7,3,6,5,2,4,8}; + auto is_even = [] (int i) { return i%2==0; }; + int sum = 0; + for (auto i : x | views::reverse | views::filter(is_even)) + sum += i; + VERIFY( sum == 20 ); +} + +void +test04() +{ + int x[] = {1,2,3,4,5}; + VERIFY( ranges::equal(x | views::reverse | (views::reverse | views::reverse), + (int[]){5,4,3,2,1}) ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc new file mode 100644 index 00000000000..129a8249f21 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc @@ -0,0 +1,82 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; +namespace views = std::ranges::views; + +using namespace std::literals; + +void +test01() +{ + auto x = "the quick brown fox"sv; + auto p = std::string{" "}; + auto v = x | views::split(p); + auto i = v.begin(); + VERIFY( ranges::equal(*i++, "the"sv) ); + VERIFY( ranges::equal(*i++, "quick"sv) ); + VERIFY( ranges::equal(*i++, "brown"sv) ); + VERIFY( ranges::equal(*i++, "fox"sv) ); + VERIFY( i == v.end() ); +} + +void +test02() +{ + auto x = "the quick brown fox"sv; + auto v = x | views::split(' '); + auto i = v.begin(); + VERIFY( ranges::equal(*i++, "the"sv) ); + VERIFY( ranges::equal(*i++, "quick"sv) ); + VERIFY( ranges::equal(*i++, "brown"sv) ); + VERIFY( ranges::equal(*i++, "fox"sv) ); + VERIFY( i == v.end() ); +} + +void +test03() +{ + char x[] = "the quick brown fox"; + test_range rx(x); + auto v = rx | views::split(' '); + auto i = v.begin(); + VERIFY( ranges::equal(*i++, "the"sv) ); + VERIFY( ranges::equal(*i++, "quick"sv) ); + VERIFY( ranges::equal(*i++, "brown"sv) ); + VERIFY( ranges::equal(*i++, "fox"sv) ); + VERIFY( i == v.end() ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc new file mode 100644 index 00000000000..32ea9fc5107 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc @@ -0,0 +1,95 @@ +// Copyright (C) 2019-2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::bidirectional_iterator_wrapper; + +namespace ranges = std::ranges; +namespace views = ranges::views; + +void +test01() +{ + auto v = views::iota(0) | views::take(5); + static_assert(ranges::view); + static_assert(!ranges::sized_range); + static_assert(!ranges::common_range); + static_assert(ranges::random_access_range); + static_assert(!ranges::contiguous_range); + static_assert(ranges::range); + VERIFY( ranges::equal(v, (int[]){0,1,2,3,4}) ); +} + +void +test02() +{ + auto v = views::take(views::iota(0, 20), 5); + static_assert(ranges::view); + static_assert(ranges::sized_range); + static_assert(ranges::common_range); + static_assert(ranges::random_access_range); + static_assert(!ranges::contiguous_range); + static_assert(ranges::range); + VERIFY( ranges::equal(v, (int[]){0,1,2,3,4}) ); +} + +void +test03() +{ + int x[] = {0,1,2,3,4,5}; + auto is_odd = [] (int i) { return i%2 == 1; }; + auto v = x | views::filter(is_odd) | views::take(3); + ranges::begin(v); + using R = decltype(v); + static_assert(ranges::view); + static_assert(!ranges::sized_range); + static_assert(!ranges::common_range); + static_assert(ranges::forward_range); + static_assert(!ranges::random_access_range); + static_assert(!ranges::range); + VERIFY( ranges::equal(v, (int[]){1,3,5}) ); +} + +void +test04() +{ + int x[] = {1,2,3,4,5}; + test_range rx(x); + auto v = ranges::take_view{rx, 3}; + using R = decltype(v); + static_assert(ranges::view); + static_assert(!ranges::sized_range); + static_assert(ranges::bidirectional_range); + VERIFY( ranges::equal(v | views::take(5), (int[]){1,2,3}) ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc new file mode 100644 index 00000000000..b261ffd1aae --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc @@ -0,0 +1,62 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::forward_iterator_wrapper; + +namespace ranges = std::ranges; +namespace views = std::ranges::views; + +void +test01() +{ + auto p = [] (int i) { return i != 16; }; + auto v = views::iota(10) | views::take_while(p); + VERIFY( ranges::equal(v, (int[]){10,11,12,13,14,15}) ); + using R = decltype(v); + static_assert(ranges::view); + static_assert(!ranges::common_range); + static_assert(ranges::random_access_range); +} + +void +test02() +{ + int x[] = {1,2,3,4,5}; + test_range rx(x); + auto v = rx | views::take_while([] (int i) { return i<4; }); + VERIFY( ranges::equal(v, (int[]){1,2,3}) ); + using R = decltype(v); + static_assert(ranges::view); + static_assert(!ranges::common_range); + static_assert(ranges::forward_range); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc new file mode 100644 index 00000000000..ad51fffb43d --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc @@ -0,0 +1,86 @@ +// Copyright (C) 2020 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 run { target c++2a } } + +#include +#include +#include +#include + +using __gnu_test::test_range; +using __gnu_test::random_access_iterator_wrapper; + +namespace ranges = std::ranges; +namespace views = std::ranges::views; + +void +test01() +{ + int x[] = {1,2,3,4,5}; + auto is_odd = [] (int i) { return i%2==1; }; + auto v = x | views::transform(is_odd); + VERIFY( ranges::equal(v, (int[]){1,0,1,0,1}) ); + using R = decltype(v); + static_assert(std::same_as); + static_assert(ranges::view); + static_assert(ranges::sized_range); + static_assert(ranges::random_access_range); +} + +struct X +{ + int i,j; +}; + +void +test02() +{ + X x[] = {{1,2},{3,4},{5,6},{7,8},{9,10}}; + test_range rx(x); + auto v = rx | views::transform(&X::i); + VERIFY( ranges::size(v) == 5 ); + VERIFY( ranges::distance(v.begin(), v.end()) == 5 ); + VERIFY( ranges::equal(v, (int[]){1,3,5,7,9}) ); + VERIFY( ranges::equal(v | views::reverse, (int[]){9,7,5,3,1}) ); + using R = decltype(v); + static_assert(std::same_as); + static_assert(std::same_as>>); + static_assert(ranges::view); + static_assert(ranges::sized_range); + static_assert(!ranges::common_range); + static_assert(ranges::random_access_range); +} + +void +test03() +{ + auto id = [] (int i) { return i; }; + auto v = views::iota(0) | (views::filter(id) + | views::transform(id) + | views::take(5)); + VERIFY( ranges::equal(v, (int[]){1,2,3,4,5}) ); +} + +int +main() +{ + test01(); + test02(); + test03(); +}