[gcc(refs/users/marxin/heads/marxin-gcc-benchmark-branch)] libstdc++: Implement C++20 constrained algorithms

Martin Liska marxin@gcc.gnu.org
Mon Mar 30 10:51:38 GMT 2020


https://gcc.gnu.org/g:bc4646410a38801029817e7951bf9b99a8c41461

commit bc4646410a38801029817e7951bf9b99a8c41461
Author: Patrick Palka <ppalka@redhat.com>
Date:   Fri Jan 10 17:11:07 2020 -0500

    libstdc++: Implement C++20 constrained algorithms
    
    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.

Diff:
---
 libstdc++-v3/ChangeLog                             |   88 +
 libstdc++-v3/include/Makefile.am                   |    1 +
 libstdc++-v3/include/Makefile.in                   |    1 +
 libstdc++-v3/include/bits/ranges_algo.h            | 3640 ++++++++++++++++++++
 libstdc++-v3/include/std/algorithm                 |    3 +
 .../25_algorithms/adjacent_find/constrained.cc     |   68 +
 .../testsuite/25_algorithms/all_of/constrained.cc  |   90 +
 .../testsuite/25_algorithms/any_of/constrained.cc  |   88 +
 .../25_algorithms/binary_search/constrained.cc     |   61 +
 .../testsuite/25_algorithms/copy/constrained.cc    |  225 ++
 .../25_algorithms/copy_backward/constrained.cc     |  193 ++
 .../testsuite/25_algorithms/copy_if/constrained.cc |   77 +
 .../testsuite/25_algorithms/copy_n/constrained.cc  |   72 +
 .../testsuite/25_algorithms/count/constrained.cc   |   75 +
 .../25_algorithms/count_if/constrained.cc          |   73 +
 .../testsuite/25_algorithms/equal/constrained.cc   |   96 +
 .../25_algorithms/equal_range/constrained.cc       |   69 +
 .../testsuite/25_algorithms/fill/constrained.cc    |   92 +
 .../testsuite/25_algorithms/fill_n/constrained.cc  |   98 +
 .../testsuite/25_algorithms/find/constrained.cc    |   75 +
 .../25_algorithms/find_end/constrained.cc          |   98 +
 .../25_algorithms/find_first_of/constrained.cc     |   83 +
 .../testsuite/25_algorithms/find_if/constrained.cc |   77 +
 .../25_algorithms/find_if_not/constrained.cc       |   77 +
 .../25_algorithms/for_each/constrained.cc          |   83 +
 .../25_algorithms/generate/constrained.cc          |   77 +
 .../25_algorithms/generate_n/constrained.cc        |   84 +
 .../testsuite/25_algorithms/heap/constrained.cc    |  107 +
 .../25_algorithms/includes/constrained.cc          |   74 +
 .../25_algorithms/inplace_merge/constrained.cc     |   69 +
 .../25_algorithms/is_partitioned/constrained.cc    |   58 +
 .../25_algorithms/is_permutation/constrained.cc    |   85 +
 .../25_algorithms/is_sorted/constrained.cc         |   67 +
 .../25_algorithms/is_sorted_until/constrained.cc   |   72 +
 .../lexicographical_compare/constrained.cc         |  164 +
 .../25_algorithms/lower_bound/constrained.cc       |   66 +
 .../testsuite/25_algorithms/max/constrained.cc     |   82 +
 .../25_algorithms/max_element/constrained.cc       |   60 +
 .../testsuite/25_algorithms/merge/constrained.cc   |   75 +
 .../testsuite/25_algorithms/min/constrained.cc     |   82 +
 .../25_algorithms/min_element/constrained.cc       |   60 +
 .../testsuite/25_algorithms/minmax/constrained.cc  |   98 +
 .../25_algorithms/minmax_element/constrained.cc    |   68 +
 .../25_algorithms/mismatch/constrained.cc          |   76 +
 .../testsuite/25_algorithms/move/constrained.cc    |  203 ++
 .../25_algorithms/move_backward/constrained.cc     |  170 +
 .../25_algorithms/next_permutation/constrained.cc  |   83 +
 .../testsuite/25_algorithms/none_of/constrained.cc |   88 +
 .../25_algorithms/nth_element/constrained.cc       |   76 +
 .../25_algorithms/partial_sort/constrained.cc      |   84 +
 .../25_algorithms/partial_sort_copy/constrained.cc |   97 +
 .../25_algorithms/partition/constrained.cc         |   71 +
 .../25_algorithms/partition_copy/constrained.cc    |   81 +
 .../25_algorithms/partition_point/constrained.cc   |   67 +
 .../25_algorithms/prev_permutation/constrained.cc  |   84 +
 .../testsuite/25_algorithms/remove/constrained.cc  |   97 +
 .../25_algorithms/remove_copy/constrained.cc       |  109 +
 .../25_algorithms/remove_copy_if/constrained.cc    |  113 +
 .../25_algorithms/remove_if/constrained.cc         |   97 +
 .../testsuite/25_algorithms/replace/constrained.cc |  104 +
 .../25_algorithms/replace_copy/constrained.cc      |  109 +
 .../25_algorithms/replace_copy_if/constrained.cc   |  118 +
 .../25_algorithms/replace_if/constrained.cc        |  109 +
 .../testsuite/25_algorithms/reverse/constrained.cc |   77 +
 .../25_algorithms/reverse_copy/constrained.cc      |   74 +
 .../testsuite/25_algorithms/rotate/constrained.cc  |   97 +
 .../25_algorithms/rotate_copy/constrained.cc       |   93 +
 .../testsuite/25_algorithms/search/constrained.cc  |   88 +
 .../25_algorithms/search_n/constrained.cc          |   80 +
 .../25_algorithms/set_difference/constrained.cc    |   87 +
 .../25_algorithms/set_intersection/constrained.cc  |   88 +
 .../set_symmetric_difference/constrained.cc        |  123 +
 .../25_algorithms/set_union/constrained.cc         |   91 +
 .../testsuite/25_algorithms/shuffle/constrained.cc |   70 +
 .../testsuite/25_algorithms/sort/constrained.cc    |   81 +
 .../25_algorithms/stable_partition/constrained.cc  |   76 +
 .../25_algorithms/stable_sort/constrained.cc       |   70 +
 .../25_algorithms/swap_ranges/constrained.cc       |  124 +
 .../25_algorithms/transform/constrained.cc         |  148 +
 .../testsuite/25_algorithms/unique/constrained.cc  |  143 +
 .../25_algorithms/unique_copy/constrained.cc       |  113 +
 .../25_algorithms/upper_bound/constrained.cc       |   66 +
 82 files changed, 10876 insertions(+)

diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 5ce1473b621..b9c7f436a81 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -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
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 89835759069..1d342cecbcc 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -157,6 +157,7 @@ bits_headers = \
 	${bits_srcdir}/random.tcc \
 	${bits_srcdir}/range_access.h \
 	${bits_srcdir}/range_cmp.h \
+	${bits_srcdir}/ranges_algo.h \
 	${bits_srcdir}/refwrap.h \
 	${bits_srcdir}/regex.h \
 	${bits_srcdir}/regex.tcc \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 123d24bb1c6..c735d67a5d3 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -502,6 +502,7 @@ bits_headers = \
 	${bits_srcdir}/random.tcc \
 	${bits_srcdir}/range_access.h \
 	${bits_srcdir}/range_cmp.h \
+	${bits_srcdir}/ranges_algo.h \
 	${bits_srcdir}/refwrap.h \
 	${bits_srcdir}/regex.h \
 	${bits_srcdir}/regex.tcc \
diff --git a/libstdc++-v3/include/bits/ranges_algo.h b/libstdc++-v3/include/bits/ranges_algo.h
new file mode 100644
index 00000000000..a9b87283f87
--- /dev/null
+++ b/libstdc++-v3/include/bits/ranges_algo.h
@@ -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
diff --git a/libstdc++-v3/include/std/algorithm b/libstdc++-v3/include/std/algorithm
index e3d34024b73..4b956b89403 100644
--- a/libstdc++-v3/include/std/algorithm
+++ b/libstdc++-v3/include/std/algorithm
@@ -60,6 +60,9 @@
 #include <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
index 00000000000..d56ac5a19db
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/adjacent_find/constrained.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..e35a1016764
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/all_of/constrained.cc
@@ -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
index 00000000000..b234692d2c7
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/any_of/constrained.cc
@@ -0,0 +1,88 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..42aaa8ef2f7
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/binary_search/constrained.cc
@@ -0,0 +1,61 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..85f7d649608
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/copy/constrained.cc
@@ -0,0 +1,225 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..900f78aaa73
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/copy_backward/constrained.cc
@@ -0,0 +1,193 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..8a92d227f16
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/copy_if/constrained.cc
@@ -0,0 +1,77 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..78a4539826a
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/copy_n/constrained.cc
@@ -0,0 +1,72 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..2a9bb27de5e
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/count/constrained.cc
@@ -0,0 +1,75 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..79cdae31826
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/count_if/constrained.cc
@@ -0,0 +1,73 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..231bd8cfeaa
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/equal/constrained.cc
@@ -0,0 +1,96 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..4ddf4590c21
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/equal_range/constrained.cc
@@ -0,0 +1,69 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..4813b8302ce
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/fill/constrained.cc
@@ -0,0 +1,92 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..e9ce8e8fb0a
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/fill_n/constrained.cc
@@ -0,0 +1,98 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..6f6b9547e67
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/find/constrained.cc
@@ -0,0 +1,75 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..b51e4a734fb
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/find_end/constrained.cc
@@ -0,0 +1,98 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..81a15761fa0
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/find_first_of/constrained.cc
@@ -0,0 +1,83 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..299bdd0fceb
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/find_if/constrained.cc
@@ -0,0 +1,77 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..838434aa7e0
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/find_if_not/constrained.cc
@@ -0,0 +1,77 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..142ad2e57da
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/for_each/constrained.cc
@@ -0,0 +1,83 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..71bcbaa616d
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/generate/constrained.cc
@@ -0,0 +1,77 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..ff894addecc
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/generate_n/constrained.cc
@@ -0,0 +1,84 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..eacf2906371
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/heap/constrained.cc
@@ -0,0 +1,107 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..f959a1d60a4
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/includes/constrained.cc
@@ -0,0 +1,74 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..856056865d9
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/inplace_merge/constrained.cc
@@ -0,0 +1,69 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..8035667b38d
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/is_partitioned/constrained.cc
@@ -0,0 +1,58 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..c5393becc8d
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/is_permutation/constrained.cc
@@ -0,0 +1,85 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..af00afe48e8
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/is_sorted/constrained.cc
@@ -0,0 +1,67 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..a81aa49ee94
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/is_sorted_until/constrained.cc
@@ -0,0 +1,72 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..b82c872bbbb
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/lexicographical_compare/constrained.cc
@@ -0,0 +1,164 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..df93f41e823
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/lower_bound/constrained.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..3fcdb3a366c
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/max/constrained.cc
@@ -0,0 +1,82 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..427faedbc44
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/max_element/constrained.cc
@@ -0,0 +1,60 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..3f3a0f79f9b
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/merge/constrained.cc
@@ -0,0 +1,75 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..c3a83b975c9
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/min/constrained.cc
@@ -0,0 +1,82 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..518060522a3
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/min_element/constrained.cc
@@ -0,0 +1,60 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..aa9364ab04c
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/minmax/constrained.cc
@@ -0,0 +1,98 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..40019c43326
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/minmax_element/constrained.cc
@@ -0,0 +1,68 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..37e79a2d62f
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/mismatch/constrained.cc
@@ -0,0 +1,76 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..d205b3572a1
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/move/constrained.cc
@@ -0,0 +1,203 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..3c4aa5dc70d
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/move_backward/constrained.cc
@@ -0,0 +1,170 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..e69b551a56b
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/next_permutation/constrained.cc
@@ -0,0 +1,83 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..55617a97a7b
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/none_of/constrained.cc
@@ -0,0 +1,88 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..34f3013b199
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/nth_element/constrained.cc
@@ -0,0 +1,76 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..430e3c0b61b
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort/constrained.cc
@@ -0,0 +1,84 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..6b586f885dd
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/partial_sort_copy/constrained.cc
@@ -0,0 +1,97 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..4e5fa5e32cd
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/partition/constrained.cc
@@ -0,0 +1,71 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..8ed6e24d451
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/partition_copy/constrained.cc
@@ -0,0 +1,81 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..2a430f23438
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/partition_point/constrained.cc
@@ -0,0 +1,67 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..25bbad9be0c
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/prev_permutation/constrained.cc
@@ -0,0 +1,84 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..39a002f3cb6
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/remove/constrained.cc
@@ -0,0 +1,97 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..0cf65a727b8
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/remove_copy/constrained.cc
@@ -0,0 +1,109 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..b7c239ff397
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/remove_copy_if/constrained.cc
@@ -0,0 +1,113 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..1abc231ab93
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/remove_if/constrained.cc
@@ -0,0 +1,97 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..3546872b72f
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/replace/constrained.cc
@@ -0,0 +1,104 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..12e76a4cfdf
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/replace_copy/constrained.cc
@@ -0,0 +1,109 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..9186a0a3d6c
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/replace_copy_if/constrained.cc
@@ -0,0 +1,118 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..8ebcc411997
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/replace_if/constrained.cc
@@ -0,0 +1,109 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..58cec27b5a0
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/reverse/constrained.cc
@@ -0,0 +1,77 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..1ee40bedb39
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/reverse_copy/constrained.cc
@@ -0,0 +1,74 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..34095e743ad
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/rotate/constrained.cc
@@ -0,0 +1,97 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..f036377817b
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/rotate_copy/constrained.cc
@@ -0,0 +1,93 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..314d9d2acf0
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/search/constrained.cc
@@ -0,0 +1,88 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..c1ac6da4bf8
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/search_n/constrained.cc
@@ -0,0 +1,80 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..3f46a9b523e
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/set_difference/constrained.cc
@@ -0,0 +1,87 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..0db3e411871
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/set_intersection/constrained.cc
@@ -0,0 +1,88 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..b138aee3adb
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/set_symmetric_difference/constrained.cc
@@ -0,0 +1,123 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..19bcd7aab9f
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/set_union/constrained.cc
@@ -0,0 +1,91 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..b96343aecce
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/shuffle/constrained.cc
@@ -0,0 +1,70 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..d8227773ccb
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/sort/constrained.cc
@@ -0,0 +1,81 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..761e3dd32d4
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/stable_partition/constrained.cc
@@ -0,0 +1,76 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..23a8c03b519
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/stable_sort/constrained.cc
@@ -0,0 +1,70 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..338b6a435f9
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/swap_ranges/constrained.cc
@@ -0,0 +1,124 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..da8b7f2be07
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/transform/constrained.cc
@@ -0,0 +1,148 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..e863a601ddd
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/unique/constrained.cc
@@ -0,0 +1,143 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..bf16cdc4ee9
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/unique_copy/constrained.cc
@@ -0,0 +1,113 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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
index 00000000000..5182431f68f
--- /dev/null
+++ b/libstdc++-v3/testsuite/25_algorithms/upper_bound/constrained.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <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());
+}


More information about the Libstdc++-cvs mailing list