libstdc++: Implement C++20 constrained algorithms
authorPatrick Palka <ppalka@redhat.com>
Fri, 10 Jan 2020 22:11:07 +0000 (17:11 -0500)
committerPatrick Palka <ppalka@redhat.com>
Fri, 7 Feb 2020 01:08:34 +0000 (20:08 -0500)
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 <bits/ranges_algo.h>.
* include/bits/ranges_algo.h: New file.
* testsuite/25_algorithms/adjacent_find/constrained.cc: New test.
* testsuite/25_algorithms/all_of/constrained.cc: New test.
* testsuite/25_algorithms/any_of/constrained.cc: New test.
* testsuite/25_algorithms/binary_search/constrained.cc: New test.
* testsuite/25_algorithms/copy/constrained.cc: New test.
* testsuite/25_algorithms/copy_backward/constrained.cc: New test.
* testsuite/25_algorithms/copy_if/constrained.cc: New test.
* testsuite/25_algorithms/copy_n/constrained.cc: New test.
* testsuite/25_algorithms/count/constrained.cc: New test.
* testsuite/25_algorithms/count_if/constrained.cc: New test.
* testsuite/25_algorithms/equal/constrained.cc: New test.
* testsuite/25_algorithms/equal_range/constrained.cc: New test.
* testsuite/25_algorithms/fill/constrained.cc: New test.
* testsuite/25_algorithms/fill_n/constrained.cc: New test.
* testsuite/25_algorithms/find/constrained.cc: New test.
* testsuite/25_algorithms/find_end/constrained.cc: New test.
* testsuite/25_algorithms/find_first_of/constrained.cc: New test.
* testsuite/25_algorithms/find_if/constrained.cc: New test.
* testsuite/25_algorithms/find_if_not/constrained.cc: New test.
* testsuite/25_algorithms/for_each/constrained.cc: New test.
* testsuite/25_algorithms/generate/constrained.cc: New test.
* testsuite/25_algorithms/generate_n/constrained.cc: New test.
* testsuite/25_algorithms/heap/constrained.cc: New test.
* testsuite/25_algorithms/includes/constrained.cc: New test.
* testsuite/25_algorithms/inplace_merge/constrained.cc: New test.
* testsuite/25_algorithms/is_partitioned/constrained.cc: New test.
* testsuite/25_algorithms/is_permutation/constrained.cc: New test.
* testsuite/25_algorithms/is_sorted/constrained.cc: New test.
* testsuite/25_algorithms/is_sorted_until/constrained.cc: New test.
* testsuite/25_algorithms/lexicographical_compare/constrained.cc: New
test.
* testsuite/25_algorithms/lower_bound/constrained.cc: New test.
* testsuite/25_algorithms/max/constrained.cc: New test.
* testsuite/25_algorithms/max_element/constrained.cc: New test.
* testsuite/25_algorithms/merge/constrained.cc: New test.
* testsuite/25_algorithms/min/constrained.cc: New test.
* testsuite/25_algorithms/min_element/constrained.cc: New test.
* testsuite/25_algorithms/minmax/constrained.cc: New test.
* testsuite/25_algorithms/minmax_element/constrained.cc: New test.
* testsuite/25_algorithms/mismatch/constrained.cc: New test.
* testsuite/25_algorithms/move/constrained.cc: New test.
* testsuite/25_algorithms/move_backward/constrained.cc: New test.
* testsuite/25_algorithms/next_permutation/constrained.cc: New test.
* testsuite/25_algorithms/none_of/constrained.cc: New test.
* testsuite/25_algorithms/nth_element/constrained.cc: New test.
* testsuite/25_algorithms/partial_sort/constrained.cc: New test.
* testsuite/25_algorithms/partial_sort_copy/constrained.cc: New test.
* testsuite/25_algorithms/partition/constrained.cc: New test.
* testsuite/25_algorithms/partition_copy/constrained.cc: New test.
* testsuite/25_algorithms/partition_point/constrained.cc: New test.
* testsuite/25_algorithms/prev_permutation/constrained.cc: New test.
* testsuite/25_algorithms/remove/constrained.cc: New test.
* testsuite/25_algorithms/remove_copy/constrained.cc: New test.
* testsuite/25_algorithms/remove_copy_if/constrained.cc: New test.
* testsuite/25_algorithms/remove_if/constrained.cc: New test.
* testsuite/25_algorithms/replace/constrained.cc: New test.
* testsuite/25_algorithms/replace_copy/constrained.cc: New test.
* testsuite/25_algorithms/replace_copy_if/constrained.cc: New test.
* testsuite/25_algorithms/replace_if/constrained.cc: New test.
* testsuite/25_algorithms/reverse/constrained.cc: New test.
* testsuite/25_algorithms/reverse_copy/constrained.cc: New test.
* testsuite/25_algorithms/rotate/constrained.cc: New test.
* testsuite/25_algorithms/rotate_copy/constrained.cc: New test.
* testsuite/25_algorithms/search/constrained.cc: New test.
* testsuite/25_algorithms/search_n/constrained.cc: New test.
* testsuite/25_algorithms/set_difference/constrained.cc: New test.
* testsuite/25_algorithms/set_intersection/constrained.cc: New test.
* testsuite/25_algorithms/set_symmetric_difference/constrained.cc: New
test.
* testsuite/25_algorithms/set_union/constrained.cc: New test.
* testsuite/25_algorithms/shuffle/constrained.cc: New test.
* testsuite/25_algorithms/sort/constrained.cc: New test.
* testsuite/25_algorithms/stable_partition/constrained.cc: New test.
* testsuite/25_algorithms/stable_sort/constrained.cc: New test.
* testsuite/25_algorithms/swap_ranges/constrained.cc: New test.
* testsuite/25_algorithms/transform/constrained.cc: New test.
* testsuite/25_algorithms/unique/constrained.cc: New test.
* testsuite/25_algorithms/unique_copy/constrained.cc: New test.
* testsuite/25_algorithms/upper_bound/constrained.cc: New test.

82 files changed:
libstdc++-v3/ChangeLog
libstdc++-v3/include/Makefile.am
libstdc++-v3/include/Makefile.in
libstdc++-v3/include/bits/ranges_algo.h [new file with mode: 0644]
libstdc++-v3/include/std/algorithm
libstdc++-v3/testsuite/25_algorithms/adjacent_find/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/all_of/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/any_of/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/binary_search/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/copy/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/copy_backward/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/copy_if/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/copy_n/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/count/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/count_if/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/equal_range/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/fill_n/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/find/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/find_end/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/find_first_of/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/find_if/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/find_if_not/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/for_each/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/generate/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/generate_n/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/includes/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/is_partitioned/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/is_permutation/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/is_sorted/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/is_sorted_until/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/lower_bound/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/max/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/max_element/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/merge/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/min/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/min_element/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/mismatch/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/move/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/next_permutation/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/none_of/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/partition/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/partition_copy/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/partition_point/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/prev_permutation/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/remove/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/remove_copy/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/remove_copy_if/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/remove_if/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/replace/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/replace_copy/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/replace_copy_if/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/replace_if/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/reverse/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/reverse_copy/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/rotate/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/rotate_copy/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/search/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/search_n/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/set_difference/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/set_intersection/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/set_symmetric_difference/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/set_union/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/swap_ranges/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/transform/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/unique/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/unique_copy/constrained.cc [new file with mode: 0644]
libstdc++-v3/testsuite/25_algorithms/upper_bound/constrained.cc [new file with mode: 0644]

index 5ce1473b62119213f047bc400dbe0fc14d2a6632..b9c7f436a810ba774c5dccea1cb3d5524bbe8d28 100644 (file)
@@ -1,3 +1,91 @@
+2020-02-07  Patrick Palka  <ppalka@redhat.com>
+           Jonathan Wakely  <jwakely@redhat.com>
+
+       Implement C++20 constrained algorithms
+       * include/Makefile.am: Add new header.
+       * include/Makefile.in: Regenerate.
+       * include/std/algorithm: Include <bits/ranges_algo.h>.
+       * include/bits/ranges_algo.h: New file.
+       * testsuite/25_algorithms/adjacent_find/constrained.cc: New test.
+       * testsuite/25_algorithms/all_of/constrained.cc: New test.
+       * testsuite/25_algorithms/any_of/constrained.cc: New test.
+       * testsuite/25_algorithms/binary_search/constrained.cc: New test.
+       * testsuite/25_algorithms/copy/constrained.cc: New test.
+       * testsuite/25_algorithms/copy_backward/constrained.cc: New test.
+       * testsuite/25_algorithms/copy_if/constrained.cc: New test.
+       * testsuite/25_algorithms/copy_n/constrained.cc: New test.
+       * testsuite/25_algorithms/count/constrained.cc: New test.
+       * testsuite/25_algorithms/count_if/constrained.cc: New test.
+       * testsuite/25_algorithms/equal/constrained.cc: New test.
+       * testsuite/25_algorithms/equal_range/constrained.cc: New test.
+       * testsuite/25_algorithms/fill/constrained.cc: New test.
+       * testsuite/25_algorithms/fill_n/constrained.cc: New test.
+       * testsuite/25_algorithms/find/constrained.cc: New test.
+       * testsuite/25_algorithms/find_end/constrained.cc: New test.
+       * testsuite/25_algorithms/find_first_of/constrained.cc: New test.
+       * testsuite/25_algorithms/find_if/constrained.cc: New test.
+       * testsuite/25_algorithms/find_if_not/constrained.cc: New test.
+       * testsuite/25_algorithms/for_each/constrained.cc: New test.
+       * testsuite/25_algorithms/generate/constrained.cc: New test.
+       * testsuite/25_algorithms/generate_n/constrained.cc: New test.
+       * testsuite/25_algorithms/heap/constrained.cc: New test.
+       * testsuite/25_algorithms/includes/constrained.cc: New test.
+       * testsuite/25_algorithms/inplace_merge/constrained.cc: New test.
+       * testsuite/25_algorithms/is_partitioned/constrained.cc: New test.
+       * testsuite/25_algorithms/is_permutation/constrained.cc: New test.
+       * testsuite/25_algorithms/is_sorted/constrained.cc: New test.
+       * testsuite/25_algorithms/is_sorted_until/constrained.cc: New test.
+       * testsuite/25_algorithms/lexicographical_compare/constrained.cc: New
+       test.
+       * testsuite/25_algorithms/lower_bound/constrained.cc: New test.
+       * testsuite/25_algorithms/max/constrained.cc: New test.
+       * testsuite/25_algorithms/max_element/constrained.cc: New test.
+       * testsuite/25_algorithms/merge/constrained.cc: New test.
+       * testsuite/25_algorithms/min/constrained.cc: New test.
+       * testsuite/25_algorithms/min_element/constrained.cc: New test.
+       * testsuite/25_algorithms/minmax/constrained.cc: New test.
+       * testsuite/25_algorithms/minmax_element/constrained.cc: New test.
+       * testsuite/25_algorithms/mismatch/constrained.cc: New test.
+       * testsuite/25_algorithms/move/constrained.cc: New test.
+       * testsuite/25_algorithms/move_backward/constrained.cc: New test.
+       * testsuite/25_algorithms/next_permutation/constrained.cc: New test.
+       * testsuite/25_algorithms/none_of/constrained.cc: New test.
+       * testsuite/25_algorithms/nth_element/constrained.cc: New test.
+       * testsuite/25_algorithms/partial_sort/constrained.cc: New test.
+       * testsuite/25_algorithms/partial_sort_copy/constrained.cc: New test.
+       * testsuite/25_algorithms/partition/constrained.cc: New test.
+       * testsuite/25_algorithms/partition_copy/constrained.cc: New test.
+       * testsuite/25_algorithms/partition_point/constrained.cc: New test.
+       * testsuite/25_algorithms/prev_permutation/constrained.cc: New test.
+       * testsuite/25_algorithms/remove/constrained.cc: New test.
+       * testsuite/25_algorithms/remove_copy/constrained.cc: New test.
+       * testsuite/25_algorithms/remove_copy_if/constrained.cc: New test.
+       * testsuite/25_algorithms/remove_if/constrained.cc: New test.
+       * testsuite/25_algorithms/replace/constrained.cc: New test.
+       * testsuite/25_algorithms/replace_copy/constrained.cc: New test.
+       * testsuite/25_algorithms/replace_copy_if/constrained.cc: New test.
+       * testsuite/25_algorithms/replace_if/constrained.cc: New test.
+       * testsuite/25_algorithms/reverse/constrained.cc: New test.
+       * testsuite/25_algorithms/reverse_copy/constrained.cc: New test.
+       * testsuite/25_algorithms/rotate/constrained.cc: New test.
+       * testsuite/25_algorithms/rotate_copy/constrained.cc: New test.
+       * testsuite/25_algorithms/search/constrained.cc: New test.
+       * testsuite/25_algorithms/search_n/constrained.cc: New test.
+       * testsuite/25_algorithms/set_difference/constrained.cc: New test.
+       * testsuite/25_algorithms/set_intersection/constrained.cc: New test.
+       * testsuite/25_algorithms/set_symmetric_difference/constrained.cc: New
+       test.
+       * testsuite/25_algorithms/set_union/constrained.cc: New test.
+       * testsuite/25_algorithms/shuffle/constrained.cc: New test.
+       * testsuite/25_algorithms/sort/constrained.cc: New test.
+       * testsuite/25_algorithms/stable_partition/constrained.cc: New test.
+       * testsuite/25_algorithms/stable_sort/constrained.cc: New test.
+       * testsuite/25_algorithms/swap_ranges/constrained.cc: New test.
+       * testsuite/25_algorithms/transform/constrained.cc: New test.
+       * testsuite/25_algorithms/unique/constrained.cc: New test.
+       * testsuite/25_algorithms/unique_copy/constrained.cc: New test.
+       * testsuite/25_algorithms/upper_bound/constrained.cc: New test.
+
 2020-02-06  Jonathan Wakely  <jwakely@redhat.com>
 
        * include/bits/stl_iterator.h (__detail::__common_iter_ptr): Fix PR
index 89835759069dbbdbb5b1f7f918dcf7782c7e4b83..1d342cecbccfbf0e4b60632f5efa3306eb93d9b6 100644 (file)
@@ -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 \
index 123d24bb1c656ee6669569e4ee18511536740a9e..c735d67a5d30f5e0f054ba496ae42cf1816ced50 100644 (file)
@@ -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 (file)
index 0000000..a9b8728
--- /dev/null
@@ -0,0 +1,3640 @@
+// Core algorithmic facilities -*- C++ -*-
+
+// 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.
+
+// 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
+// <http://www.gnu.org/licenses/>.
+
+/** @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 <compare>
+#include <cmath>
+#include <iterator>
+// #include <bits/range_concepts.h>
+#include <ranges>
+#include <bits/invoke.h>
+#include <bits/cpp_type_traits.h> // __is_byte
+#include <bits/random.h> // concept uniform_random_bit_generator
+
+#if __cpp_lib_concepts
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace ranges
+{
+  namespace __detail
+  {
+    template<typename _Tp>
+      constexpr inline bool __is_normal_iterator = false;
+
+    template<typename _Iterator, typename _Container>
+      constexpr inline bool
+       __is_normal_iterator<__gnu_cxx::__normal_iterator<_Iterator,
+                                                         _Container>> = true;
+
+    template<typename _Tp>
+      constexpr inline bool __is_reverse_iterator = false;
+
+    template<typename _Iterator>
+      constexpr inline bool
+       __is_reverse_iterator<reverse_iterator<_Iterator>> = true;
+
+    template<typename _Tp>
+      constexpr inline bool __is_move_iterator = false;
+
+    template<typename _Iterator>
+      constexpr inline bool
+       __is_move_iterator<move_iterator<_Iterator>> = true;
+
+    template<typename _Comp, typename _Proj>
+      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<typename _Pred, typename _Proj>
+      constexpr auto
+      __make_pred_proj(_Pred& __pred, _Proj& __proj)
+      {
+       return [&] <typename _Tp> (_Tp&& __arg) -> bool {
+         return std::__invoke(__pred,
+                              std::__invoke(__proj, std::forward<_Tp>(__arg)));
+       };
+      }
+  } // namespace __detail
+
+  template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<input_range _Range, typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _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<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<input_range _Range, typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _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<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<input_range _Range, typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _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<typename _Iter, typename _Fp>
+    struct for_each_result
+    {
+      [[no_unique_address]] _Iter in;
+      [[no_unique_address]] _Fp fun;
+
+      template<typename _Iter2, typename _F2p>
+       requires convertible_to<const _Iter&, _Iter2>
+         && convertible_to<const _Fp&, _F2p>
+       operator for_each_result<_Iter2, _F2p>() const &
+       { return {in, fun}; }
+
+      template<typename _Iter2, typename _F2p>
+       requires convertible_to<_Iter, _Iter2> && convertible_to<_Fp, _F2p>
+       operator for_each_result<_Iter2, _F2p>() &&
+       { return {std::move(in), std::move(fun)}; }
+    };
+
+  template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirectly_unary_invocable<projected<_Iter, _Proj>> _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<input_range _Range, typename _Proj = identity,
+          indirectly_unary_invocable<projected<iterator_t<_Range>, _Proj>>
+            _Fun>
+    constexpr for_each_result<safe_iterator_t<_Range>, _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<input_iterator _Iter, sentinel_for<_Iter> _Sent, typename _Tp,
+          typename _Proj = identity>
+    requires indirect_binary_predicate<ranges::equal_to,
+                                      projected<_Iter, _Proj>, 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<input_range _Range, typename _Tp, typename _Proj = identity>
+    requires indirect_binary_predicate<ranges::equal_to,
+                                      projected<iterator_t<_Range>, _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<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<input_range _Range, typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _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<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<input_range _Range, typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _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<input_iterator _Iter1, sentinel_for<_Iter1> _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<input_range _Range1, forward_range _Range2,
+          typename _Pred = ranges::equal_to,
+          typename _Proj1 = identity, typename _Proj2 = identity>
+    requires indirectly_comparable<iterator_t<_Range1>, 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<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Tp, typename _Proj = identity>
+    requires indirect_binary_predicate<ranges::equal_to,
+                                      projected<_Iter, _Proj>,
+                                      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<input_range _Range, typename _Tp, typename _Proj = identity>
+    requires indirect_binary_predicate<ranges::equal_to,
+                                      projected<iterator_t<_Range>, _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<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<input_range _Range,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _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<typename _Iter1, typename _Iter2>
+    struct mismatch_result
+    {
+      [[no_unique_address]] _Iter1 in1;
+      [[no_unique_address]] _Iter2 in2;
+
+      template<typename _IIter1, typename _IIter2>
+       requires convertible_to<const _Iter1&, _IIter1>
+         && convertible_to<const _Iter2&, _IIter2>
+       operator mismatch_result<_IIter1, _IIter2>() const &
+       { return {in1, in2}; }
+
+      template<typename _IIter1, typename _IIter2>
+       requires convertible_to<_Iter1, _IIter1>
+         && convertible_to<_Iter2, _IIter2>
+       operator mismatch_result<_IIter1, _IIter2>() &&
+       { return {std::move(in1), std::move(in2)}; }
+    };
+
+  template<input_iterator _Iter1, sentinel_for<_Iter1> _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<input_range _Range1, input_range _Range2,
+          typename _Pred = ranges::equal_to,
+          typename _Proj1 = identity, typename _Proj2 = identity>
+    requires indirectly_comparable<iterator_t<_Range1>, iterator_t<_Range2>,
+                                  _Pred, _Proj1, _Proj2>
+    constexpr mismatch_result<iterator_t<_Range1>, 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<forward_iterator _Iter1, sentinel_for<_Iter1> _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<forward_range _Range1, forward_range _Range2,
+          typename _Pred = ranges::equal_to,
+          typename _Proj1 = identity, typename _Proj2 = identity>
+    requires indirectly_comparable<iterator_t<_Range1>, 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<forward_iterator _Iter, sentinel_for<_Iter> _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 = [&] <typename _Rp> (_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<forward_range _Range, typename _Tp,
+          typename _Pred = ranges::equal_to, typename _Proj = identity>
+    requires indirectly_comparable<iterator_t<_Range>, 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<forward_iterator _Iter1, sentinel_for<_Iter1> _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<forward_iterator _Iter1, sentinel_for<_Iter1> _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<forward_range _Range1, forward_range _Range2,
+          typename _Pred = ranges::equal_to,
+          typename _Proj1 = identity, typename _Proj2 = identity>
+    requires indirectly_comparable<iterator_t<_Range1>, 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<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_binary_predicate<projected<_Iter, _Proj>,
+                                    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<forward_range _Range, typename _Proj = identity,
+          indirect_binary_predicate<
+            projected<iterator_t<_Range>, _Proj>,
+            projected<iterator_t<_Range>, _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<forward_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
+          forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
+          typename _Proj1 = identity, typename _Proj2 = identity,
+          indirect_equivalence_relation<projected<_Iter1, _Proj1>,
+                                        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 = [&] <typename _Tp> (_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<forward_range _Range1, forward_range _Range2,
+          typename _Proj1 = identity, typename _Proj2 = identity,
+          indirect_equivalence_relation<
+            projected<iterator_t<_Range1>, _Proj1>,
+            projected<iterator_t<_Range2>, _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<input_iterator _Iter1, sentinel_for<_Iter1> _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<input_iterator _Iter1, sentinel_for<_Iter1> _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<input_range _Range1, input_range _Range2,
+          typename _Pred = ranges::equal_to,
+          typename _Proj1 = identity, typename _Proj2 = identity>
+    requires indirectly_comparable<iterator_t<_Range1>, 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<typename _Iter, typename _Out>
+    struct copy_result
+    {
+      [[no_unique_address]] _Iter in;
+      [[no_unique_address]] _Out out;
+
+      template<typename _Iter2, typename _Out2>
+       requires convertible_to<const _Iter&, _Iter2>
+         && convertible_to<const _Out&, _Out2>
+       operator copy_result<_Iter2, _Out2>() const &
+       { return {in, out}; }
+
+      template<typename _Iter2, typename _Out2>
+       requires convertible_to<_Iter, _Iter2>
+         && convertible_to<_Out, _Out2>
+       operator copy_result<_Iter2, _Out2>() &&
+       { return {std::move(in), std::move(out)}; }
+    };
+
+  template<typename _Iter, typename _Out>
+    using move_result = copy_result<_Iter, _Out>;
+
+  template<typename _Iter1, typename _Iter2>
+    using move_backward_result = copy_result<_Iter1, _Iter2>;
+
+  template<typename _Iter1, typename _Iter2>
+    using copy_backward_result = copy_result<_Iter1, _Iter2>;
+
+  template<bool _IsMove,
+          bidirectional_iterator _Iter, sentinel_for<_Iter> _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<bool _IsMove,
+          input_iterator _Iter, sentinel_for<_Iter> _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<true>(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<input_iterator _Iter, sentinel_for<_Iter> _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<false>(std::move(__first),
+                                          std::move(__last),
+                                          std::move(__result));
+    }
+
+  template<input_range _Range, weakly_incrementable _Out>
+    requires indirectly_copyable<iterator_t<_Range>, _Out>
+    constexpr copy_result<safe_iterator_t<_Range>, _Out>
+    copy(_Range&& __r, _Out __result)
+    {
+      return ranges::copy(ranges::begin(__r), ranges::end(__r),
+                         std::move(__result));
+    }
+
+  template<input_iterator _Iter, sentinel_for<_Iter> _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<true>(std::move(__first),
+                                         std::move(__last),
+                                         std::move(__result));
+    }
+
+  template<input_range _Range, weakly_incrementable _Out>
+    requires indirectly_movable<iterator_t<_Range>, _Out>
+    constexpr move_result<safe_iterator_t<_Range>, _Out>
+    move(_Range&& __r, _Out __result)
+    {
+      return ranges::move(ranges::begin(__r), ranges::end(__r),
+                         std::move(__result));
+    }
+
+  template<bool _IsMove,
+          bidirectional_iterator _Iter, sentinel_for<_Iter> _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<bidirectional_iterator _Iter1, sentinel_for<_Iter1> _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<false>(std::move(__first),
+                                                   std::move(__last),
+                                                   std::move(__result));
+    }
+
+  template<bidirectional_range _Range, bidirectional_iterator _Iter>
+    requires indirectly_copyable<iterator_t<_Range>, _Iter>
+    constexpr copy_backward_result<safe_iterator_t<_Range>, _Iter>
+    copy_backward(_Range&& __r, _Iter __result)
+    {
+      return ranges::copy_backward(ranges::begin(__r), ranges::end(__r),
+                                  std::move(__result));
+    }
+
+  template<bidirectional_iterator _Iter1, sentinel_for<_Iter1> _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<true>(std::move(__first),
+                                                  std::move(__last),
+                                                  std::move(__result));
+    }
+
+  template<bidirectional_range _Range, bidirectional_iterator _Iter>
+    requires indirectly_movable<iterator_t<_Range>, _Iter>
+    constexpr move_backward_result<safe_iterator_t<_Range>, _Iter>
+    move_backward(_Range&& __r, _Iter __result)
+    {
+      return ranges::move_backward(ranges::begin(__r), ranges::end(__r),
+                                  std::move(__result));
+    }
+
+  template<typename _Iter, typename _Out>
+    using copy_n_result = copy_result<_Iter, _Out>;
+
+  template<input_iterator _Iter, weakly_incrementable _Out>
+    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<typename _Iter, typename _Out>
+    using copy_if_result = copy_result<_Iter, _Out>;
+
+  template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          weakly_incrementable _Out, typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<input_range _Range, weakly_incrementable _Out,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
+    requires indirectly_copyable<iterator_t<_Range>, _Out>
+    constexpr copy_if_result<safe_iterator_t<_Range>, _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<typename _Iter1, typename _Iter2>
+    using swap_ranges_result = mismatch_result<_Iter1, _Iter2>;
+
+  template<input_iterator _Iter1, sentinel_for<_Iter1> _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<input_range _Range1, input_range _Range2>
+    requires indirectly_swappable<iterator_t<_Range1>, iterator_t<_Range2>>
+    constexpr swap_ranges_result<safe_iterator_t<_Range1>,
+                                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<typename _Iter, typename _Out>
+    using unary_transform_result = copy_result<_Iter, _Out>;
+
+  template<input_iterator _Iter, sentinel_for<_Iter> _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<input_range _Range, weakly_incrementable _Out,
+          copy_constructible _Fp, typename _Proj = identity>
+    requires writable<_Out,
+                     indirect_result_t<_Fp&, projected<iterator_t<_Range>,
+                                                     _Proj>>>
+    constexpr unary_transform_result<safe_iterator_t<_Range>, _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<typename _Iter1, typename _Iter2, typename _Out>
+    struct binary_transform_result
+    {
+      [[no_unique_address]] _Iter1 in1;
+      [[no_unique_address]] _Iter2 in2;
+      [[no_unique_address]] _Out  out;
+
+      template<typename _IIter1, typename _IIter2, typename _OOut>
+       requires convertible_to<const _Iter1&, _IIter1> &&
+         && convertible_to<const _Iter2&, _IIter2>
+         && convertible_to<const _Out&, _OOut>
+       operator binary_transform_result<_IIter1, _IIter2, _OOut>() const &
+       { return {in1, in2, out}; }
+
+      template<typename _IIter1, typename _IIter2, typename _OOut>
+       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<input_iterator _Iter1, sentinel_for<_Iter1> _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<input_range _Range1, input_range _Range2,
+          weakly_incrementable _Out, copy_constructible _Fp,
+          typename _Proj1 = identity, typename _Proj2 = identity>
+    requires writable<_Out, indirect_result_t<_Fp&,
+                                             projected<iterator_t<_Range1>,
+                                                       _Proj1>,
+                                             projected<iterator_t<_Range2>,
+                                                       _Proj2>>>
+    constexpr binary_transform_result<safe_iterator_t<_Range1>,
+                                     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<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Tp1, typename _Tp2, typename _Proj = identity>
+    requires writable<_Iter, const _Tp2&> &&
+            indirect_binary_predicate<ranges::equal_to,
+                                      projected<_Iter, _Proj>, 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<input_range _Range,
+          typename _Tp1, typename _Tp2, typename _Proj = identity>
+    requires writable<iterator_t<_Range>, const _Tp2&> &&
+            indirect_binary_predicate<ranges::equal_to,
+                                      projected<iterator_t<_Range>, _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<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Tp, typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<input_range _Range, typename _Tp, typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
+    requires writable<iterator_t<_Range>, 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<typename _Iter, typename _Out>
+    using replace_copy_result = copy_result<_Iter, _Out>;
+
+  template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Tp1, typename _Tp2, output_iterator<const _Tp2&> _Out,
+          typename _Proj = identity>
+    requires indirectly_copyable<_Iter, _Out>
+      && indirect_binary_predicate<ranges::equal_to,
+                                  projected<_Iter, _Proj>, 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<input_range _Range, typename _Tp1, typename _Tp2,
+          output_iterator<const _Tp2&> _Out, typename _Proj = identity>
+    requires indirectly_copyable<iterator_t<_Range>, _Out>
+      && indirect_binary_predicate<ranges::equal_to,
+                                  projected<iterator_t<_Range>, _Proj>,
+                                  const _Tp1*>
+    constexpr replace_copy_result<safe_iterator_t<_Range>, _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<typename _Iter, typename _Out>
+    using replace_copy_if_result = copy_result<_Iter, _Out>;
+
+  template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Tp, output_iterator<const _Tp&> _Out,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<input_range _Range,
+          typename _Tp, output_iterator<const _Tp&> _Out,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
+    requires indirectly_copyable<iterator_t<_Range>, _Out>
+    constexpr replace_copy_if_result<safe_iterator_t<_Range>, _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<typename _Tp, output_iterator<const _Tp&> _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<unsigned char>(__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<typename _Tp,
+          output_iterator<const _Tp&> _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<typename _Tp, output_range<const _Tp&> _Range>
+    constexpr safe_iterator_t<_Range>
+    fill(_Range&& __r, const _Tp& __value)
+    {
+      return ranges::fill(ranges::begin(__r), ranges::end(__r), __value);
+    }
+
+  template<input_or_output_iterator _Out, copy_constructible _Fp>
+    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<input_or_output_iterator _Out, sentinel_for<_Out> _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<typename _Range, copy_constructible _Fp>
+    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<permutable _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<forward_range _Range, typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
+    requires permutable<iterator_t<_Range>>
+    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<permutable _Iter, sentinel_for<_Iter> _Sent,
+          typename _Tp, typename _Proj = identity>
+    requires indirect_binary_predicate<ranges::equal_to,
+                                      projected<_Iter, _Proj>,
+                                      const _Tp*>
+    constexpr subrange<_Iter>
+    remove(_Iter __first, _Sent __last, const _Tp& __value, _Proj __proj = {})
+    {
+      auto __pred = [&] (auto&& __arg) {
+       return std::forward<decltype(__arg)>(__arg) == __value;
+      };
+      return ranges::remove_if(__first, __last,
+                              std::move(__pred), std::move(__proj));
+    }
+
+  template<forward_range _Range, typename _Tp, typename _Proj = identity>
+    requires permutable<iterator_t<_Range>> &&
+            indirect_binary_predicate<ranges::equal_to,
+                                      projected<iterator_t<_Range>, _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<typename _Iter, typename _Out>
+    using remove_copy_if_result = copy_result<_Iter, _Out>;
+
+  template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          weakly_incrementable _Out, typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<input_range _Range, weakly_incrementable _Out,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
+    requires indirectly_copyable<iterator_t<_Range>, _Out>
+    constexpr remove_copy_if_result<safe_iterator_t<_Range>, _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<typename _Iter, typename _Out>
+    using remove_copy_result = copy_result<_Iter, _Out>;
+
+  template<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          weakly_incrementable _Out, typename _Tp, typename _Proj = identity>
+    requires indirectly_copyable<_Iter, _Out>
+      && indirect_binary_predicate<ranges::equal_to,
+                                  projected<_Iter, _Proj>,
+                                  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<input_range _Range, weakly_incrementable _Out,
+          typename _Tp, typename _Proj = identity>
+    requires indirectly_copyable<iterator_t<_Range>, _Out>
+      && indirect_binary_predicate<ranges::equal_to,
+                                  projected<iterator_t<_Range>, _Proj>,
+                                  const _Tp*>
+    constexpr remove_copy_result<safe_iterator_t<_Range>, _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<permutable _Iter, sentinel_for<_Iter> _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<forward_range _Range, typename _Proj = identity,
+          indirect_equivalence_relation<
+            projected<iterator_t<_Range>, _Proj>> _Comp = ranges::equal_to>
+    requires permutable<iterator_t<_Range>>
+    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<typename _Iter, typename _Out>
+    using unique_copy_result = copy_result<_Iter, _Out>;
+
+  template<input_iterator _Iter, sentinel_for<_Iter> _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<_Iter>, 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<_Iter>, 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<input_range _Range,
+          weakly_incrementable _Out, typename _Proj = identity,
+          indirect_equivalence_relation<
+            projected<iterator_t<_Range>, _Proj>> _Comp = ranges::equal_to>
+    requires indirectly_copyable<iterator_t<_Range>, _Out>
+      && (forward_iterator<iterator_t<_Range>>
+         || (input_iterator<_Out>
+             && same_as<range_value_t<_Range>, iter_value_t<_Out>>)
+         || indirectly_copyable_storable<iterator_t<_Range>, _Out>)
+    constexpr unique_copy_result<safe_iterator_t<_Range>, _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<bidirectional_iterator _Iter, sentinel_for<_Iter> _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<bidirectional_range _Range>
+    requires permutable<iterator_t<_Range>>
+    constexpr safe_iterator_t<_Range>
+    reverse(_Range&& __r)
+    {
+      return ranges::reverse(ranges::begin(__r), ranges::end(__r));
+    }
+
+  template<typename _Iter, typename _Out>
+    using reverse_copy_result = copy_result<_Iter, _Out>;
+
+  template<bidirectional_iterator _Iter, sentinel_for<_Iter> _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<bidirectional_range _Range, weakly_incrementable _Out>
+    requires indirectly_copyable<iterator_t<_Range>, _Out>
+    constexpr reverse_copy_result<safe_iterator_t<_Range>, _Out>
+    reverse_copy(_Range&& __r, _Out __result)
+    {
+      return ranges::reverse_copy(ranges::begin(__r), ranges::end(__r),
+                                 std::move(__result));
+    }
+
+  template<permutable _Iter, sentinel_for<_Iter> _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<forward_range _Range>
+    requires permutable<iterator_t<_Range>>
+    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<typename _Iter, typename _Out>
+    using rotate_copy_result = copy_result<_Iter, _Out>;
+
+  template<forward_iterator _Iter, sentinel_for<_Iter> _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<forward_range _Range, weakly_incrementable _Out>
+    requires indirectly_copyable<iterator_t<_Range>, _Out>
+    constexpr rotate_copy_result<safe_iterator_t<_Range>, _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<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Gen>
+    requires permutable<_Iter>
+      && uniform_random_bit_generator<remove_reference_t<_Gen>>
+    _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<random_access_range _Range, typename _Gen>
+    requires permutable<iterator_t<_Range>>
+      && uniform_random_bit_generator<remove_reference_t<_Gen>>
+    safe_iterator_t<_Range>
+    shuffle(_Range&& __r, _Gen&& __g)
+    {
+      return ranges::shuffle(ranges::begin(__r), ranges::end(__r),
+                            std::forward<_Gen>(__g));
+    }
+#endif
+
+  template<random_access_iterator _Iter, sentinel_for<_Iter> _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<random_access_range _Range,
+          typename _Comp = ranges::less, typename _Proj = identity>
+    requires sortable<iterator_t<_Range>, _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<random_access_iterator _Iter, sentinel_for<_Iter> _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<random_access_range _Range,
+          typename _Comp = ranges::less, typename _Proj = identity>
+    requires sortable<iterator_t<_Range>, _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<random_access_iterator _Iter, sentinel_for<_Iter> _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<random_access_range _Range,
+          typename _Comp = ranges::less, typename _Proj = identity>
+    requires sortable<iterator_t<_Range>, _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<random_access_iterator _Iter, sentinel_for<_Iter> _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<random_access_range _Range,
+          typename _Comp = ranges::less, typename _Proj = identity>
+    requires sortable<iterator_t<_Range>, _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<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_strict_weak_order<projected<_Iter, _Proj>>
+            _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<random_access_range _Range,
+          typename _Proj = identity,
+          indirect_strict_weak_order<projected<iterator_t<_Range>, _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<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_strict_weak_order<projected<_Iter, _Proj>>
+            _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<random_access_range _Range,
+          typename _Proj = identity,
+          indirect_strict_weak_order<projected<iterator_t<_Range>, _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<random_access_iterator _Iter, sentinel_for<_Iter> _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<random_access_range _Range,
+          typename _Comp = ranges::less, typename _Proj = identity>
+    requires sortable<iterator_t<_Range>, _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<random_access_iterator _Iter, sentinel_for<_Iter> _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<random_access_range _Range,
+          typename _Comp = ranges::less, typename _Proj = identity>
+    requires sortable<iterator_t<_Range>, _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<random_access_iterator _Iter, sentinel_for<_Iter> _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<random_access_range _Range,
+          typename _Comp = ranges::less, typename _Proj = identity>
+    requires sortable<iterator_t<_Range>, _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<typename _Iter, typename _Out>
+    using partial_sort_copy_result = copy_result<_Iter, _Out>;
+
+  template<input_iterator _Iter1, sentinel_for<_Iter1> _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<input_range _Range1, random_access_range _Range2,
+          typename _Comp = ranges::less,
+          typename _Proj1 = identity, typename _Proj2 = identity>
+    requires indirectly_copyable<iterator_t<_Range1>, iterator_t<_Range2>>
+      && sortable<iterator_t<_Range2>, _Comp, _Proj2>
+      && indirect_strict_weak_order<_Comp,
+                                   projected<iterator_t<_Range1>, _Proj1>,
+                                   projected<iterator_t<_Range2>, _Proj2>>
+    constexpr partial_sort_copy_result<safe_iterator_t<_Range1>,
+                                      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<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_strict_weak_order<projected<_Iter, _Proj>>
+            _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<forward_range _Range, typename _Proj = identity,
+          indirect_strict_weak_order<projected<iterator_t<_Range>, _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<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_strict_weak_order<projected<_Iter, _Proj>>
+            _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<forward_range _Range, typename _Proj = identity,
+          indirect_strict_weak_order<projected<iterator_t<_Range>, _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<random_access_iterator _Iter, sentinel_for<_Iter> _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<random_access_range _Range,
+          typename _Comp = ranges::less, typename _Proj = identity>
+    requires sortable<iterator_t<_Range>, _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<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
+            _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<forward_range _Range, typename _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<const _Tp*,
+                                     projected<iterator_t<_Range>, _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<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
+            _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<forward_range _Range, typename _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<const _Tp*,
+                                     projected<iterator_t<_Range>, _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<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
+            _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<forward_range _Range,
+          typename _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<const _Tp*,
+                                     projected<iterator_t<_Range>, _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<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>>
+            _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<forward_range _Range,
+          typename _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<const _Tp*,
+                                     projected<iterator_t<_Range>, _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<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<input_range _Range, typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _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<permutable _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<forward_range _Range, typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
+    requires permutable<iterator_t<_Range>>
+    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<bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<bidirectional_range _Range, typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
+    requires permutable<iterator_t<_Range>>
+    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<typename _Iter, typename _Out1, typename _O2>
+    struct partition_copy_result
+    {
+      [[no_unique_address]] _Iter  in;
+      [[no_unique_address]] _Out1 out1;
+      [[no_unique_address]] _O2 out2;
+
+      template<typename _IIter, typename _OOut1, typename _OOut2>
+       requires convertible_to<const _Iter&, _IIter>
+         && convertible_to<const _Out1&, _OOut1>
+         && convertible_to<const _O2&, _OOut2>
+       operator partition_copy_result<_IIter, _OOut1, _OOut2>() const &
+       { return {in, out1, out2}; }
+
+      template<typename _IIter, typename _OOut1, typename _OOut2>
+       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<input_iterator _Iter, sentinel_for<_Iter> _Sent,
+          weakly_incrementable _Out1, weakly_incrementable _O2,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<input_range _Range, weakly_incrementable _Out1,
+          weakly_incrementable _O2,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
+    requires indirectly_copyable<iterator_t<_Range>, _Out1>
+      && indirectly_copyable<iterator_t<_Range>, _O2>
+    constexpr partition_copy_result<safe_iterator_t<_Range>, _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<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_unary_predicate<projected<_Iter, _Proj>> _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<forward_range _Range, typename _Proj = identity,
+          indirect_unary_predicate<projected<iterator_t<_Range>, _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<typename _Iter1, typename _Iter2, typename _Out>
+    using merge_result = binary_transform_result<_Iter1, _Iter2, _Out>;
+
+  template<input_iterator _Iter1, sentinel_for<_Iter1> _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<input_range _Range1, input_range _Range2, weakly_incrementable _Out,
+          typename _Comp = ranges::less,
+          typename _Proj1 = identity, typename _Proj2 = identity>
+    requires mergeable<iterator_t<_Range1>, iterator_t<_Range2>, _Out,
+                      _Comp, _Proj1, _Proj2>
+    constexpr merge_result<safe_iterator_t<_Range1>,
+                          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<bidirectional_iterator _Iter, sentinel_for<_Iter> _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<bidirectional_range _Range,
+          typename _Comp = ranges::less, typename _Proj = identity>
+    requires sortable<iterator_t<_Range>, _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<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
+          input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
+          typename _Proj1 = identity, typename _Proj2 = identity,
+          indirect_strict_weak_order<projected<_Iter1, _Proj1>,
+                                     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<input_range _Range1, input_range _Range2, typename _Proj1 = identity,
+          typename _Proj2 = identity,
+          indirect_strict_weak_order<projected<iterator_t<_Range1>, _Proj1>,
+                                     projected<iterator_t<_Range2>, _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<typename _Iter1, typename _Iter2, typename _Out>
+    using set_union_result = binary_transform_result<_Iter1, _Iter2, _Out>;
+
+  template<input_iterator _Iter1, sentinel_for<_Iter1> _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<input_range _Range1, input_range _Range2, weakly_incrementable _Out,
+          typename _Comp = ranges::less,
+          typename _Proj1 = identity, typename _Proj2 = identity>
+    requires mergeable<iterator_t<_Range1>, iterator_t<_Range2>, _Out,
+                      _Comp, _Proj1, _Proj2>
+    constexpr set_union_result<safe_iterator_t<_Range1>,
+                              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<typename _Iter1, typename _Iter2, typename _Out>
+    using set_intersection_result = binary_transform_result<_Iter1, _Iter2, _Out>;
+
+  template<input_iterator _Iter1, sentinel_for<_Iter1> _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<input_range _Range1, input_range _Range2, weakly_incrementable _Out,
+          typename _Comp = ranges::less,
+          typename _Proj1 = identity, typename _Proj2 = identity>
+    requires mergeable<iterator_t<_Range1>, iterator_t<_Range2>, _Out,
+                      _Comp, _Proj1, _Proj2>
+    constexpr set_intersection_result<safe_iterator_t<_Range1>,
+                                     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<typename _Iter, typename _Out>
+    using set_difference_result = copy_result<_Iter, _Out>;
+
+  template<input_iterator _Iter1, sentinel_for<_Iter1> _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<input_range _Range1, input_range _Range2, weakly_incrementable _Out,
+          typename _Comp = ranges::less,
+          typename _Proj1 = identity, typename _Proj2 = identity>
+    requires mergeable<iterator_t<_Range1>, iterator_t<_Range2>, _Out,
+                      _Comp, _Proj1, _Proj2>
+    constexpr set_difference_result<safe_iterator_t<_Range1>, _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<typename _Iter1, typename _Iter2, typename _Out>
+    using set_symmetric_difference_result
+      = binary_transform_result<_Iter1, _Iter2, _Out>;
+
+  template<input_iterator _Iter1, sentinel_for<_Iter1> _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<input_range _Range1, input_range _Range2, weakly_incrementable _Out,
+          typename _Comp = ranges::less,
+          typename _Proj1 = identity, typename _Proj2 = identity>
+    requires mergeable<iterator_t<_Range1>, iterator_t<_Range2>, _Out,
+                      _Comp, _Proj1, _Proj2>
+    constexpr set_symmetric_difference_result<safe_iterator_t<_Range1>,
+                                             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<typename _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<projected<const _Tp*, _Proj>>
+            _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<input_range _Range, typename _Proj = identity,
+          indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
+            _Comp = ranges::less>
+    requires indirectly_copyable_storable<iterator_t<_Range>,
+                                         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<copyable _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<projected<const _Tp*, _Proj>>
+            _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<typename _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<projected<const _Tp*, _Proj>>
+            _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<input_range _Range, typename _Proj = identity,
+          indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
+            _Comp = ranges::less>
+    requires indirectly_copyable_storable<iterator_t<_Range>,
+                                         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<copyable _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<projected<const _Tp*, _Proj>>
+            _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<typename _Tp>
+    struct minmax_result
+    {
+      [[no_unique_address]] _Tp min;
+      [[no_unique_address]] _Tp max;
+
+      template<typename _Tp2>
+       requires convertible_to<const _Tp&, _Tp2>
+       operator minmax_result<_Tp2>() const &
+       { return {min, max}; }
+
+      template<typename _Tp2>
+       requires convertible_to<_Tp, _Tp2>
+       operator minmax_result<_Tp2>() &&
+       { return {std::move(min), std::move(max)}; }
+    };
+
+  template<typename _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<projected<const _Tp*, _Proj>>
+            _Comp = ranges::less>
+    constexpr minmax_result<const _Tp&>
+    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<input_range _Range, typename _Proj = identity,
+          indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
+            _Comp = ranges::less>
+    requires indirectly_copyable_storable<iterator_t<_Range>,
+    range_value_t<_Range>*>
+    constexpr minmax_result<range_value_t<_Range>>
+    minmax(_Range&& __r, _Comp __comp = {}, _Proj __proj = {})
+    {
+      auto __first = ranges::begin(__r);
+      auto __last = ranges::end(__r);
+      __glibcxx_assert(__first != __last);
+      minmax_result<range_value_t<_Range>> __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<copyable _Tp, typename _Proj = identity,
+          indirect_strict_weak_order<projected<const _Tp*, _Proj>>
+            _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<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_strict_weak_order<projected<_Iter, _Proj>>
+            _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<forward_range _Range, typename _Proj = identity,
+          indirect_strict_weak_order<projected<iterator_t<_Range>, _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<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_strict_weak_order<projected<_Iter, _Proj>>
+            _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<forward_range _Range, typename _Proj = identity,
+          indirect_strict_weak_order<projected<iterator_t<_Range>, _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<typename _Iter>
+    using minmax_element_result = minmax_result<_Iter>;
+
+  template<forward_iterator _Iter, sentinel_for<_Iter> _Sent,
+          typename _Proj = identity,
+          indirect_strict_weak_order<projected<_Iter, _Proj>>
+            _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<forward_range _Range, typename _Proj = identity,
+          indirect_strict_weak_order<projected<iterator_t<_Range>, _Proj>>
+            _Comp = ranges::less>
+    constexpr minmax_element_result<safe_iterator_t<_Range>>
+    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<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
+          input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
+          typename _Proj1, typename _Proj2,
+          indirect_strict_weak_order<projected<_Iter1, _Proj1>,
+                                     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<input_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
+          input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
+          typename _Proj1 = identity, typename _Proj2 = identity,
+          indirect_strict_weak_order<projected<_Iter1, _Proj1>,
+                                     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<input_range _Range1, input_range _Range2, typename _Proj1 = identity,
+          typename _Proj2 = identity,
+          indirect_strict_weak_order<projected<iterator_t<_Range1>, _Proj1>,
+                                     projected<iterator_t<_Range2>, _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<typename _Iter>
+    struct next_permutation_result
+    {
+      bool found;
+      _Iter in;
+    };
+
+  template<bidirectional_iterator _Iter, sentinel_for<_Iter> _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<bidirectional_range _Range, typename _Comp = ranges::less,
+          typename _Proj = identity>
+    requires sortable<iterator_t<_Range>, _Comp, _Proj>
+    constexpr next_permutation_result<safe_iterator_t<_Range>>
+    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<typename _Iter>
+    using prev_permutation_result = next_permutation_result<_Iter>;
+
+  template<bidirectional_iterator _Iter, sentinel_for<_Iter> _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<bidirectional_range _Range, typename _Comp = ranges::less,
+          typename _Proj = identity>
+    requires sortable<iterator_t<_Range>, _Comp, _Proj>
+    constexpr prev_permutation_result<safe_iterator_t<_Range>>
+    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
index e3d34024b73c77a955bab2136e353e7a602cd4ac..4b956b894035992e339321af2c3b05ef383c4b33 100644 (file)
@@ -60,6 +60,9 @@
 #include <utility> // UK-300.
 #include <bits/stl_algobase.h>
 #include <bits/stl_algo.h>
+#if __cplusplus > 201703L
+# include <bits/ranges_algo.h>
+#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 (file)
index 0000000..d56ac5a
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> c(x);
+  VERIFY( ranges::adjacent_find(c, {}, &X::i) == ranges::begin(c) );
+
+  test_range<int, forward_iterator_wrapper> 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 (file)
index 0000000..e35a101
--- /dev/null
@@ -0,0 +1,90 @@
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<typename T>
+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<X, forward_iterator_wrapper> c(x);
+  VERIFY( ranges::all_of(c, NotZero<int>{}, &X::i) );
+
+  test_range<X, input_iterator_wrapper> r(x);
+  VERIFY( ranges::all_of(r, NotZero<int>{}, &X::i) );
+
+  r.bounds.first = x;
+  VERIFY( ranges::all_of(r, NotZero<X* const>{}, [](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 (file)
index 0000000..b234692
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<typename T>
+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<X, forward_iterator_wrapper> c(x);
+  VERIFY( ranges::any_of(c, NotZero<int>{}, &X::i) );
+
+  test_range<X, input_iterator_wrapper> r(x);
+  VERIFY( ranges::any_of(r, NotZero<int>{}, &X::i) );
+  VERIFY( ranges::any_of(r, NotZero<X* const>{}, [](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 (file)
index 0000000..42aaa8e
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<float, forward_iterator_wrapper> 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<float, forward_iterator_wrapper> 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 (file)
index 0000000..85f7d64
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> cx(x);
+      test_container<char, forward_iterator_wrapper> 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<char, input_iterator_wrapper> rx(x);
+      test_range<int, output_iterator_wrapper> 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<char> x = {1,2,3};
+      std::vector<int> 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<int> x = {1,2,3};
+      std::vector<int> 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<int> x = {1,2,3};
+      std::vector<int> 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<char> x = {1,2,3};
+      std::vector<int> 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<Y, input_iterator_wrapper> 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 (file)
index 0000000..900f78a
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, bidirectional_iterator_wrapper> cx(x);
+      test_container<char, bidirectional_iterator_wrapper> 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<char> x = {1,2,3};
+      std::vector<int> 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<int> x = {1,2,3};
+      std::vector<int> 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<int> x = {1,2,3};
+      std::vector<int> 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<char> x = {1,2,3};
+      std::vector<int> 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<Y, bidirectional_iterator_wrapper> 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 (file)
index 0000000..8a92d22
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, input_iterator_wrapper> rx(x);
+      test_range<int, output_iterator_wrapper> 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<int, input_iterator_wrapper> rx(x);
+      test_range<int, output_iterator_wrapper> 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 (file)
index 0000000..78a4539
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<template<typename> typename in_wrapper,
+        template<typename> typename out_wrapper>
+void
+test01()
+{
+  int x[] = {1,2,3,4,5,6,7};
+  for (int i = -1; i <= 7; i++)
+    {
+      test_range<int, in_wrapper> rx(x);
+      int w[7];
+      test_range<int, out_wrapper> 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<input_iterator_wrapper,
+        output_iterator_wrapper>();
+  test01<random_access_iterator_wrapper,
+        output_iterator_wrapper>();
+  test01<random_access_iterator_wrapper,
+        random_access_iterator_wrapper>();
+  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 (file)
index 0000000..2a9bb27
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> c(x);
+  res = ranges::count(c, 6, &X::i);
+  VERIFY( res == 1 );
+  res = ranges::count(c, 9, &X::i);
+  VERIFY( res == 0 );
+
+  test_range<X, input_iterator_wrapper> 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 (file)
index 0000000..79cdae3
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<X, input_iterator_wrapper> 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 (file)
index 0000000..231bd8c
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> cx(x), cy(y);
+  test_container<X, forward_iterator_wrapper> 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<int, input_iterator_wrapper> rx(x), ry(y);
+  test_range<X, input_iterator_wrapper> 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<int> x = { {2}, {2}, {6}, {8}, {10}, {11} };
+  std::vector<int> y = { {2}, {2}, {6}, {8}, {10}, {11} };
+  std::vector<int> 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 (file)
index 0000000..4ddf459
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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 (file)
index 0000000..4813b83
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <list>
+
+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<X, forward_iterator_wrapper> cx(x);
+      VERIFY( ranges::fill(cx, X{17}) == cx.end() );
+      VERIFY( ranges::equal(cx, c, {}, &X::i) );
+    }
+
+    {
+      int x[6];
+      test_range<int, output_iterator_wrapper> rx(x);
+      VERIFY( ranges::fill(rx, 17) == rx.end() );
+      VERIFY( ranges::equal(x, c) );
+    }
+
+    {
+      std::list<int> 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 (file)
index 0000000..e9ce8e8
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+#include <list>
+
+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<X, forward_iterator_wrapper> 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<int, output_iterator_wrapper> rx(x);
+      ranges::fill_n(ranges::begin(rx), 3, 17);
+      VERIFY( ranges::equal(x, c) );
+    }
+
+    {
+      std::list<int> 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 (file)
index 0000000..6f6b954
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<X, input_iterator_wrapper> 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 (file)
index 0000000..b51e4a7
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<X, forward_iterator_wrapper> 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<X, bidirectional_iterator_wrapper> 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 (file)
index 0000000..81a1576
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> c(x);
+  test_container<int, forward_iterator_wrapper> 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<X, forward_iterator_wrapper> d2(w+3, w+4);
+  res2 = ranges::find_first_of(c, d2, {}, &X::i, &X::i);
+  VERIFY( res2 == ranges::end(c) );
+
+  test_range<X, input_iterator_wrapper> r(x);
+  test_range<int, forward_iterator_wrapper> 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<X, forward_iterator_wrapper> 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 (file)
index 0000000..299bdd0
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<X, input_iterator_wrapper> 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 (file)
index 0000000..838434a
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<X, input_iterator_wrapper> 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 (file)
index 0000000..142ad2e
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> c(x);
+  int p = 0;
+  ranges::for_each(c, [&p](int i) { ++p; }, &X::i);
+  VERIFY( p == 6 );
+
+  test_range<X, input_iterator_wrapper> 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 (file)
index 0000000..71bcbaa
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> cx(x);
+      VERIFY( ranges::generate(cx, [&] { return a++; }) == cx.end() );
+      VERIFY( ranges::equal(cx, c) );
+    }
+
+    {
+      int x[6];
+      int a = 1;
+      test_range<int, output_iterator_wrapper> 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 (file)
index 0000000..ff894ad
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> 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<int, output_iterator_wrapper> 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 (file)
index 0000000..eacf290
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+// { dg-require-cstdint "" }
+
+#include <algorithm>
+#include <random>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_container;
+using __gnu_test::test_range;
+using __gnu_test::random_access_iterator_wrapper;
+
+namespace ranges = std::ranges;
+
+template<template<typename, template<typename> 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<int, random_access_iterator_wrapper> 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<test_range>();
+  test01<test_container>();
+  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 (file)
index 0000000..f959a1d
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, input_iterator_wrapper> 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<int, forward_iterator_wrapper> 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 (file)
index 0000000..8560568
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int> v(x, x+i);
+       v.insert(v.end(), x, x+j);
+       ranges::sort(v);
+
+       test_range<int, bidirectional_iterator_wrapper> 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 (file)
index 0000000..8035667
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> cx(x);
+  VERIFY( ranges::is_partitioned(cx, [] (int a) { return a%2==0; }) );
+
+  test_range<int, input_iterator_wrapper> 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 (file)
index 0000000..c5393be
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> cx(x), cy(y), cz(z);
+  test_range<int, forward_iterator_wrapper> 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<int, bidirectional_iterator_wrapper> 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 (file)
index 0000000..af00afe
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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 (file)
index 0000000..a81aa49
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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 (file)
index 0000000..b82c872
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, input_iterator_wrapper> rx(x);
+      test_range<char, input_iterator_wrapper> ry(y);
+      test_range<long, input_iterator_wrapper> rz(z);
+
+      VERIFY( ranges::lexicographical_compare(rx, ry) );
+      rx.bounds.first = x;
+      ry.bounds.first = y;
+      VERIFY( !ranges::lexicographical_compare(ry, rx) );
+    }
+
+  test_range<int, forward_iterator_wrapper> rx(x);
+  test_range<char, forward_iterator_wrapper> ry(y);
+  test_range<long, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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<int> 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 (file)
index 0000000..df93f41
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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 (file)
index 0000000..3fcdb3a
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, input_iterator_wrapper> 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 (file)
index 0000000..427faed
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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 (file)
index 0000000..3f3a0f7
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, input_iterator_wrapper> rx(x, x+i), ry(x, x+j);
+       test_range<int, output_iterator_wrapper> 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<int> 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 (file)
index 0000000..c3a83b9
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, input_iterator_wrapper> 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 (file)
index 0000000..5180605
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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 (file)
index 0000000..aa9364a
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+using __gnu_test::test_container;
+using __gnu_test::test_range;
+using __gnu_test::input_iterator_wrapper;
+
+namespace ranges = std::ranges;
+
+template<typename T1, typename T2>
+constexpr bool
+operator==(const ranges::minmax_result<T1>& lhs,
+          const ranges::minmax_result<T2>& rhs)
+{
+  return (lhs.min == rhs.min
+         && rhs.max == rhs.max);
+}
+
+
+struct X
+{
+  int i, j;
+};
+
+using res_t = ranges::minmax_result<int>;
+
+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<int, input_iterator_wrapper> 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 (file)
index 0000000..40019c4
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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 (file)
index 0000000..37e79a2
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> ca(xa);
+  test_container<X, forward_iterator_wrapper> 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<X, input_iterator_wrapper> ra(xa);
+  test_range<X, input_iterator_wrapper> rb(xb);
+  auto res3 = ranges::mismatch(ra, rb, {}, &X::i, &X::i);
+  VERIFY( res3.in1->i == 4 && res3.in2->i == 3 );
+
+  test_range<X, input_iterator_wrapper> 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 (file)
index 0000000..d205b35
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> cx(x);
+      test_container<char, forward_iterator_wrapper> 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<char, input_iterator_wrapper> cx(x);
+      test_range<int, output_iterator_wrapper> 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<char> x= {1,2,3};
+      std::vector<int> 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<int> x = {1,2,3};
+      std::vector<int> 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<int> x = {1,2,3};
+      std::vector<int> 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<char> x = {1,2,3};
+      std::vector<int> 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<X, input_iterator_wrapper> 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 (file)
index 0000000..3c4aa5d
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, bidirectional_iterator_wrapper> cx(x);
+      test_container<char, bidirectional_iterator_wrapper> 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<char> x= {1,2,3};
+      std::vector<int> 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<int> x = {1,2,3};
+      std::vector<int> 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<int> x = {1,2,3};
+      std::vector<int> 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<char> x = {1,2,3};
+      std::vector<int> 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 (file)
index 0000000..e69b551
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, bidirectional_iterator_wrapper> cx(x, x+i);
+      test_container<int, bidirectional_iterator_wrapper> 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<int, bidirectional_iterator_wrapper> 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 (file)
index 0000000..55617a9
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<typename T>
+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<X, forward_iterator_wrapper> c(x);
+  VERIFY( !ranges::none_of(c, NotZero<int>{}, &X::i) );
+
+  test_range<X, input_iterator_wrapper> r(x);
+  VERIFY( !ranges::none_of(r, NotZero<int>{}, &X::i) );
+  VERIFY( !ranges::none_of(r, NotZero<X* const>{}, [](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 (file)
index 0000000..34f3013
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+// { dg-require-cstdint "" }
+
+#include <algorithm>
+#include <random>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, random_access_iterator_wrapper> 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 (file)
index 0000000..430e3c0
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+// { dg-require-cstdint "" }
+
+#include <algorithm>
+#include <random>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int> vref(size);
+      std::iota(vref.begin(), vref.end(), 0);
+      std::vector<int> v1(vref), v2(vref);
+      test_container<int, random_access_iterator_wrapper> c
+       = {&v1[0], &v1[0] + size};
+      test_range<int, random_access_iterator_wrapper> 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 (file)
index 0000000..6b586f8
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+// { dg-require-cstdint "" }
+
+#include <algorithm>
+#include <random>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int> vref(size);
+      std::iota(vref.begin(), vref.end(), 0);
+      std::vector<int> 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<int, forward_iterator_wrapper> c
+           = {&v1[0], &v1[0] + size};
+         test_range<int, input_iterator_wrapper> r
+           = {&v2[0], &v2[0] + size};
+
+         std::vector<int> o1(middle), o2(middle);
+         test_range<int, random_access_iterator_wrapper> w1
+           = {&o1[0], &o1[0]+middle};
+         test_range<int, random_access_iterator_wrapper> 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 (file)
index 0000000..4e5fa5e
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<template<typename> typename wrapper>
+void
+test01()
+{
+    {
+      int x[] = {1,2,3,4,5,6,7,8,9,10};
+      test_container<int, wrapper> 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<int, wrapper> 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<forward_iterator_wrapper>();
+  test01<bidirectional_iterator_wrapper>();
+  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 (file)
index 0000000..8ed6e24
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> cx(x);
+      test_container<int, forward_iterator_wrapper> 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<int, input_iterator_wrapper> cx(x);
+      test_range<int, output_iterator_wrapper> 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 (file)
index 0000000..2a430f2
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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 (file)
index 0000000..25bbad9
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, bidirectional_iterator_wrapper> cx(x, x+i);
+      test_container<int, bidirectional_iterator_wrapper> 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<int, bidirectional_iterator_wrapper> 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 (file)
index 0000000..39a002f
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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<X, forward_iterator_wrapper> 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 (file)
index 0000000..0cf65a7
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<X, input_iterator_wrapper> cx(x);
+      test_range<X, output_iterator_wrapper> 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 (file)
index 0000000..b7c239f
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<X, input_iterator_wrapper> cx(x);
+      test_range<X, output_iterator_wrapper> 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 (file)
index 0000000..1abc231
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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<X, forward_iterator_wrapper> 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 (file)
index 0000000..3546872
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<int, input_iterator_wrapper> 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 (file)
index 0000000..12e76a4
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<X, input_iterator_wrapper> cx(x);
+      test_range<X, output_iterator_wrapper> 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 (file)
index 0000000..9186a0a
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<X, input_iterator_wrapper> cx(x);
+      test_range<X, output_iterator_wrapper> 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 (file)
index 0000000..8ebcc41
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<int, input_iterator_wrapper> 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 (file)
index 0000000..58cec27
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<template<typename> typename wrapper>
+void
+test01()
+{
+  int x[] = { 1, 2, 3, 4 };
+  test_container<int, wrapper> 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<template<typename> typename wrapper>
+void
+test02()
+{
+  int x[] = { 1, 2, 3, 4, 5 };
+  test_range<int, wrapper> 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<bidirectional_iterator_wrapper>();
+  test02<bidirectional_iterator_wrapper>();
+
+  test01<random_access_iterator_wrapper>();
+  test02<random_access_iterator_wrapper>();
+
+  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 (file)
index 0000000..1ee40be
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, bidirectional_iterator_wrapper> 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<int, bidirectional_iterator_wrapper> 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 (file)
index 0000000..34095e7
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X>);
+
+template<template<typename, template<typename> typename> typename container,
+        template<typename> typename wrapper,
+        typename T = int>
+void
+test01()
+{
+  for (int a = 0; a <= 7; a++)
+    {
+      T x[] = {1, 2, 3, 4, 5, 6, 7};
+      container<T, wrapper> 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<test_container, forward_iterator_wrapper>();
+  test01<test_range, forward_iterator_wrapper>();
+
+  test01<test_container, bidirectional_iterator_wrapper>();
+  test01<test_range, bidirectional_iterator_wrapper>();
+
+  test01<test_container, random_access_iterator_wrapper>();
+  test01<test_range, random_access_iterator_wrapper>();
+
+  test01<test_container, random_access_iterator_wrapper, X>();
+  test01<test_range, random_access_iterator_wrapper, X>();
+
+  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 (file)
index 0000000..f036377
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X>);
+
+template<template<typename, template<typename> typename> typename container,
+        template<typename> 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<T, wrapper> 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<test_container, forward_iterator_wrapper>();
+  test01<test_range, forward_iterator_wrapper>();
+
+  test01<test_container, random_access_iterator_wrapper>();
+  test01<test_range, random_access_iterator_wrapper>();
+
+  test01<test_container, random_access_iterator_wrapper, X>();
+  test01<test_range, random_access_iterator_wrapper, X>();
+
+  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 (file)
index 0000000..314d9d2
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<X, forward_iterator_wrapper> 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 (file)
index 0000000..c1ac6da
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int>());
+  VERIFY( res.begin() == z+3 && res.end() == z+6 );
+
+  test_container<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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 (file)
index 0000000..3f46a9b
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, input_iterator_wrapper> rx(x), ry(y);
+  test_range<int, output_iterator_wrapper> 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<int, forward_iterator_wrapper> rx(x), ry(y);
+  test_container<int, forward_iterator_wrapper> 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 (file)
index 0000000..0db3e41
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, input_iterator_wrapper> rx(x), ry(y);
+  test_range<int, output_iterator_wrapper> 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<int, forward_iterator_wrapper> rx(x), ry(y);
+  test_container<int, forward_iterator_wrapper> 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 (file)
index 0000000..b138aee
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+// { dg-require-cstdint "" }
+
+#include <algorithm>
+#include <random>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, input_iterator_wrapper> rx(x), ry(y);
+  test_range<int, output_iterator_wrapper> 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<int, forward_iterator_wrapper> rx(x), ry(y);
+  test_container<int, forward_iterator_wrapper> 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 (file)
index 0000000..19bcd7a
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, input_iterator_wrapper> rx(x), ry(y);
+  test_range<int, output_iterator_wrapper> 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<int, forward_iterator_wrapper> rx(x), ry(y);
+  test_container<int, forward_iterator_wrapper> 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 (file)
index 0000000..b96343a
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+// { dg-require-cstdint "" }
+
+#include <algorithm>
+#include <random>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int> vref(size);
+      std::iota(vref.begin(), vref.end(), 0);
+      std::vector<int> v1(vref), v2(vref);
+      test_container<int, random_access_iterator_wrapper> c
+       = {&v1[0], &v1[0] + size};
+      test_range<int, random_access_iterator_wrapper> 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 (file)
index 0000000..d822777
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+// { dg-require-cstdint "" }
+
+#include <algorithm>
+#include <random>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int> vref(size);
+      std::iota(vref.begin(), vref.end(), 0);
+      std::vector<int> v1(vref), v2(vref);
+      test_container<int, random_access_iterator_wrapper> c
+       = {&v1[0], &v1[0] + size};
+      test_range<int, random_access_iterator_wrapper> 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 (file)
index 0000000..761e3dd
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, bidirectional_iterator_wrapper> 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<int, bidirectional_iterator_wrapper> 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 (file)
index 0000000..23a8c03
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+// { dg-require-cstdint "" }
+
+#include <algorithm>
+#include <random>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int> vref(size);
+      std::iota(vref.begin(), vref.end(), 0);
+      std::vector<int> v1(vref), v2(vref);
+      test_container<int, random_access_iterator_wrapper> c
+       = {&v1[0], &v1[0] + size};
+      test_range<int, random_access_iterator_wrapper> 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 (file)
index 0000000..338b6a4
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> cx(x);
+      test_container<int, forward_iterator_wrapper> 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<int, input_iterator_wrapper> cx(x);
+      test_range<int, input_iterator_wrapper> 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 (file)
index 0000000..da8b7f2
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> cx(x);
+      test_container<int, forward_iterator_wrapper> 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<X, input_iterator_wrapper> rx(x), ry(y);
+      test_range<int, output_iterator_wrapper> 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<X, forward_iterator_wrapper> cx(x);
+      test_container<int, forward_iterator_wrapper> 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<X, input_iterator_wrapper> rx(x);
+      test_range<int, input_iterator_wrapper> ry(y), rz(z);
+      test_range<int, output_iterator_wrapper> 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 (file)
index 0000000..e863a60
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <list>
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<X, forward_iterator_wrapper> 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<X, forward_iterator_wrapper> 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<int>::iterator pos;
+
+    list<int> coll(T1, T1 + N);
+    pos = ranges::unique(coll.begin(), coll.end()).begin();
+    VERIFY( equal(coll.begin(), pos, A1) );
+
+    list<int> coll2(T2, T2 + N);
+    pos = ranges::unique(coll2.begin(), coll2.end()).begin();
+    VERIFY( equal(coll2.begin(), pos, B1) );
+  }
+
+  void test02()
+  {
+    using namespace std;
+
+    list<int>::iterator pos;
+
+    list<int> coll(T1, T1 + N);
+    pos = ranges::unique(coll.begin(), coll.end(), greater<int>()).begin();
+    VERIFY( equal(coll.begin(), pos, A2) );
+
+    list<int> coll2(T2, T2 + N);
+    pos = ranges::unique(coll2.begin(), coll2.end(), greater<int>()).begin();
+    VERIFY( equal(coll2.begin(), pos, B2) );
+  }
+
+  void test03()
+  {
+    using namespace std;
+
+    list<int>::iterator pos;
+
+    list<int> coll(T1, T1 + N);
+    pos = ranges::unique(coll.begin(), coll.end(), less<int>()).begin();
+    VERIFY( equal(coll.begin(), pos, A3) );
+
+    list<int> coll2(T2, T2 + N);
+    reverse(coll2.begin(), coll2.end());
+    pos = ranges::unique(coll2.begin(), coll2.end(), less<int>()).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 (file)
index 0000000..bf16cdc
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<template<typename> typename source_wrapper,
+        template<typename> 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<int, source_wrapper> rx(x);
+  test_range<int, dest_wrapper> 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<template<typename> typename source_wrapper,
+        template<typename> 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<int, source_wrapper> rx(x, x);
+  test_range<int, dest_wrapper> 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<template<typename> typename source_wrapper,
+        template<typename> 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<X, source_wrapper> rx(x);
+  test_range<X, dest_wrapper> 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<input_iterator_wrapper, output_iterator_wrapper>();
+  test01<input_iterator_wrapper, forward_iterator_wrapper>();
+  test01<forward_iterator_wrapper, output_iterator_wrapper>();
+
+  test02<input_iterator_wrapper, output_iterator_wrapper>();
+  test02<input_iterator_wrapper, forward_iterator_wrapper>();
+  test02<forward_iterator_wrapper, output_iterator_wrapper>();
+
+  test03<input_iterator_wrapper, output_iterator_wrapper>();
+  test03<input_iterator_wrapper, forward_iterator_wrapper>();
+  test03<forward_iterator_wrapper, output_iterator_wrapper>();
+
+  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 (file)
index 0000000..5182431
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do run { target c++2a } }
+
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_iterators.h>
+
+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<int, forward_iterator_wrapper> 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<int, forward_iterator_wrapper> 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());
+}