[libcxx-commits] [libcxx] a7c3379 - [libc++][ranges] Make range algorithms support proxy iterators

via libcxx-commits libcxx-commits at lists.llvm.org
Sun Jul 17 18:12:14 PDT 2022


Author: Konstantin Varlamov
Date: 2022-07-17T18:12:06-07:00
New Revision: a7c3379cf9a4efc9381f832639827a39f0396f65

URL: https://github.com/llvm/llvm-project/commit/a7c3379cf9a4efc9381f832639827a39f0396f65
DIFF: https://github.com/llvm/llvm-project/commit/a7c3379cf9a4efc9381f832639827a39f0396f65.diff

LOG: [libc++][ranges] Make range algorithms support proxy iterators

Also test all the range algorithms to verify the support.

Differential Revision: https://reviews.llvm.org/D129823

Added: 
    libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp

Modified: 
    libcxx/include/__algorithm/inplace_merge.h
    libcxx/include/__algorithm/iterator_operations.h
    libcxx/include/__algorithm/make_heap.h
    libcxx/include/__algorithm/min_element.h
    libcxx/include/__algorithm/nth_element.h
    libcxx/include/__algorithm/partial_sort.h
    libcxx/include/__algorithm/partial_sort_copy.h
    libcxx/include/__algorithm/pop_heap.h
    libcxx/include/__algorithm/push_heap.h
    libcxx/include/__algorithm/ranges_fill.h
    libcxx/include/__algorithm/ranges_make_heap.h
    libcxx/include/__algorithm/ranges_min_element.h
    libcxx/include/__algorithm/ranges_nth_element.h
    libcxx/include/__algorithm/ranges_pop_heap.h
    libcxx/include/__algorithm/ranges_push_heap.h
    libcxx/include/__algorithm/ranges_sort.h
    libcxx/include/__algorithm/ranges_sort_heap.h
    libcxx/include/__algorithm/ranges_stable_sort.h
    libcxx/include/__algorithm/shuffle.h
    libcxx/include/__algorithm/sift_down.h
    libcxx/include/__algorithm/sort.h
    libcxx/include/__algorithm/sort_heap.h
    libcxx/include/__algorithm/stable_sort.h
    libcxx/include/__debug_utils/randomize_range.h
    libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp
    libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp
    libcxx/test/support/test.support/test_proxy.pass.cpp
    libcxx/test/support/test_iterators.h

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h
index 58919ddbae76..7369786eeb06 100644
--- a/libcxx/include/__algorithm/inplace_merge.h
+++ b/libcxx/include/__algorithm/inplace_merge.h
@@ -11,6 +11,7 @@
 
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/lower_bound.h>
 #include <__algorithm/min.h>
 #include <__algorithm/move.h>
@@ -21,7 +22,6 @@
 #include <__iterator/distance.h>
 #include <__iterator/iterator_traits.h>
 #include <__iterator/reverse_iterator.h>
-#include <__utility/swap.h>
 #include <memory>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -53,7 +53,7 @@ class __invert // invert the sense of a comparison
     bool operator()(const _T1& __x, const _T2& __y) {return __p_(__y, __x);}
 };
 
-template <class _Compare, class _InputIterator1, class _InputIterator2,
+template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2,
           class _OutputIterator>
 void __half_inplace_merge(_InputIterator1 __first1, _InputIterator1 __last1,
                           _InputIterator2 __first2, _InputIterator2 __last2,
@@ -63,25 +63,26 @@ void __half_inplace_merge(_InputIterator1 __first1, _InputIterator1 __last1,
     {
         if (__first2 == __last2)
         {
+            // TODO(alg-policy): pass `_AlgPolicy` once it's supported by `move`.
             _VSTD::move(__first1, __last1, __result);
             return;
         }
 
         if (__comp(*__first2, *__first1))
         {
-            *__result = _VSTD::move(*__first2);
+            *__result = _IterOps<_AlgPolicy>::__iter_move(__first2);
             ++__first2;
         }
         else
         {
-            *__result = _VSTD::move(*__first1);
+            *__result = _IterOps<_AlgPolicy>::__iter_move(__first1);
             ++__first1;
         }
     }
     // __first2 through __last2 are already in the right spot.
 }
 
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
 void
 __buffered_inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
                 _Compare __comp, typename iterator_traits<_BidirectionalIterator>::
diff erence_type __len1,
@@ -95,30 +96,32 @@ __buffered_inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator
     {
         value_type* __p = __buff;
         for (_BidirectionalIterator __i = __first; __i != __middle; __d.template __incr<value_type>(), (void) ++__i, (void) ++__p)
-            ::new ((void*)__p) value_type(_VSTD::move(*__i));
-        _VSTD::__half_inplace_merge<_Compare>(__buff, __p, __middle, __last, __first, __comp);
+            ::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
+        std::__half_inplace_merge<_AlgPolicy, _Compare>(__buff, __p, __middle, __last, __first, __comp);
     }
     else
     {
         value_type* __p = __buff;
         for (_BidirectionalIterator __i = __middle; __i != __last; __d.template __incr<value_type>(), (void) ++__i, (void) ++__p)
-            ::new ((void*)__p) value_type(_VSTD::move(*__i));
+            ::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
         typedef reverse_iterator<_BidirectionalIterator> _RBi;
         typedef reverse_iterator<value_type*> _Rv;
         typedef __invert<_Compare> _Inverted;
-        _VSTD::__half_inplace_merge<_Inverted>(_Rv(__p), _Rv(__buff),
+        std::__half_inplace_merge<_AlgPolicy, _Inverted>(_Rv(__p), _Rv(__buff),
                                     _RBi(__middle), _RBi(__first),
                                     _RBi(__last), _Inverted(__comp));
     }
 }
 
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
 void
 __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
                 _Compare __comp, typename iterator_traits<_BidirectionalIterator>::
diff erence_type __len1,
                                  typename iterator_traits<_BidirectionalIterator>::
diff erence_type __len2,
                 typename iterator_traits<_BidirectionalIterator>::value_type* __buff, ptr
diff _t __buff_size)
 {
+    using _Ops = _IterOps<_AlgPolicy>;
+
     typedef typename iterator_traits<_BidirectionalIterator>::
diff erence_type 
diff erence_type;
     while (true)
     {
@@ -126,7 +129,7 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
         if (__len2 == 0)
             return;
         if (__len1 <= __buff_size || __len2 <= __buff_size)
-            return _VSTD::__buffered_inplace_merge<_Compare>
+            return std::__buffered_inplace_merge<_AlgPolicy, _Compare>
                    (__first, __middle, __last, __comp, __len1, __len2, __buff);
         // shrink [__first, __middle) as much as possible (with no moves), returning if it shrinks to 0
         for (; true; ++__first, (void) --__len1)
@@ -153,35 +156,37 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
         {   // __len >= 1, __len2 >= 2
             __len21 = __len2 / 2;
             __m2 = __middle;
-            _VSTD::advance(__m2, __len21);
+            _Ops::advance(__m2, __len21);
             __m1 = _VSTD::__upper_bound<_Compare>(__first, __middle, *__m2, __comp);
-            __len11 = _VSTD::distance(__first, __m1);
+            __len11 = _Ops::distance(__first, __m1);
         }
         else
         {
             if (__len1 == 1)
             {   // __len1 >= __len2 && __len2 > 0, therefore __len2 == 1
                 // It is known *__first > *__middle
-                swap(*__first, *__middle);
+              _Ops::iter_swap(__first, __middle);
                 return;
             }
             // __len1 >= 2, __len2 >= 1
             __len11 = __len1 / 2;
             __m1 = __first;
-            _VSTD::advance(__m1, __len11);
+            _Ops::advance(__m1, __len11);
             __m2 = std::lower_bound(__middle, __last, *__m1, __comp);
-            __len21 = _VSTD::distance(__middle, __m2);
+            __len21 = _Ops::distance(__middle, __m2);
         }
         
diff erence_type __len12 = __len1 - __len11;  // distance(__m1, __middle)
         
diff erence_type __len22 = __len2 - __len21;  // distance(__m2, __last)
         // [__first, __m1) [__m1, __middle) [__middle, __m2) [__m2, __last)
         // swap middle two partitions
+        // TODO(alg-policy): pass `_AlgPolicy` once it's supported by `rotate`.
         __middle = _VSTD::rotate(__m1, __middle, __m2);
         // __len12 and __len21 now have swapped meanings
         // merge smaller range with recursive call and larger with tail recursion elimination
         if (__len11 + __len21 < __len12 + __len22)
         {
-            _VSTD::__inplace_merge<_Compare>(__first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);
+            std::__inplace_merge<_AlgPolicy, _Compare>(
+                __first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);
 //          _VSTD::__inplace_merge<_Compare>(__middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);
             __first = __middle;
             __middle = __m2;
@@ -190,7 +195,8 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
         }
         else
         {
-            _VSTD::__inplace_merge<_Compare>(__middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);
+            std::__inplace_merge<_AlgPolicy, _Compare>(
+                __middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);
 //          _VSTD::__inplace_merge<_Compare>(__first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);
             __last = __middle;
             __middle = __m1;
@@ -217,7 +223,7 @@ _LIBCPP_SUPPRESS_DEPRECATED_PUSH
 _LIBCPP_SUPPRESS_DEPRECATED_POP
     unique_ptr<value_type, __return_temporary_buffer> __h(__buf.first);
     typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
-    return _VSTD::__inplace_merge<_Comp_ref>(__first, __middle, __last, __comp, __len1, __len2,
+    return _VSTD::__inplace_merge<_ClassicAlgPolicy, _Comp_ref>(__first, __middle, __last, __comp, __len1, __len2,
                                             __buf.first, __buf.second);
 }
 

diff  --git a/libcxx/include/__algorithm/iterator_operations.h b/libcxx/include/__algorithm/iterator_operations.h
index eb627e1ace7a..de9c8a130ecb 100644
--- a/libcxx/include/__algorithm/iterator_operations.h
+++ b/libcxx/include/__algorithm/iterator_operations.h
@@ -41,6 +41,7 @@ struct _IterOps<_RangeAlgPolicy> {
   static constexpr auto next = ranges::next;
   static constexpr auto __advance_to = ranges::advance;
 };
+
 #endif
 
 struct _ClassicAlgPolicy {};
@@ -85,7 +86,8 @@ struct _IterOps<_ClassicAlgPolicy> {
   }
 
   template <class _Iter>
-  _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11 void __advance_to(_Iter& __first, _Iter __last) {
+  _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11
+  void __advance_to(_Iter& __first, _Iter __last) {
     __first = __last;
   }
 };

diff  --git a/libcxx/include/__algorithm/make_heap.h b/libcxx/include/__algorithm/make_heap.h
index bc39d82bf916..bf9dd96756af 100644
--- a/libcxx/include/__algorithm/make_heap.h
+++ b/libcxx/include/__algorithm/make_heap.h
@@ -11,6 +11,7 @@
 
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/sift_down.h>
 #include <__config>
 #include <__iterator/iterator_traits.h>
@@ -22,7 +23,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
 void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
   using _CompRef = typename __comp_ref_type<_Compare>::type;
@@ -33,7 +34,7 @@ void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
   if (__n > 1) {
     // start from the first parent, there is no need to consider children
     for (
diff erence_type __start = (__n - 2) / 2; __start >= 0; --__start) {
-        std::__sift_down<_CompRef>(__first, __comp_ref, __n, __first + __start);
+        std::__sift_down<_AlgPolicy, _CompRef>(__first, __comp_ref, __n, __first + __start);
     }
   }
 }
@@ -41,7 +42,7 @@ void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
 template <class _RandomAccessIterator, class _Compare>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
 void make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
-  std::__make_heap(std::move(__first), std::move(__last), __comp);
+  std::__make_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
 }
 
 template <class _RandomAccessIterator>

diff  --git a/libcxx/include/__algorithm/min_element.h b/libcxx/include/__algorithm/min_element.h
index 129833d42bda..17b242c341e6 100644
--- a/libcxx/include/__algorithm/min_element.h
+++ b/libcxx/include/__algorithm/min_element.h
@@ -12,7 +12,11 @@
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
 #include <__config>
+#include <__functional/identity.h>
+#include <__functional/invoke.h>
 #include <__iterator/iterator_traits.h>
+#include <__type_traits/is_callable.h>
+#include <__utility/move.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -20,28 +24,38 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Compare, class _ForwardIterator>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator
-__min_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp)
-{
-    static_assert(__is_cpp17_forward_iterator<_ForwardIterator>::value,
-        "std::min_element requires a ForwardIterator");
-    if (__first != __last)
-    {
-        _ForwardIterator __i = __first;
-        while (++__i != __last)
-            if (__comp(*__i, *__first))
-                __first = __i;
-    }
+template <class _Comp, class _Iter, class _Sent, class _Proj>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+_Iter __min_element(_Iter __first, _Sent __last, _Comp __comp, _Proj& __proj) {
+  if (__first == __last)
     return __first;
+
+  _Iter __i = __first;
+  while (++__i != __last)
+    if (std::__invoke(__comp, std::__invoke(__proj, *__i), std::__invoke(__proj, *__first)))
+      __first = __i;
+
+  return __first;
+}
+
+template <class _Comp, class _Iter, class _Sent>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+_Iter __min_element(_Iter __first, _Sent __last, _Comp __comp) {
+  auto __proj = __identity();
+  return std::__min_element<_Comp>(std::move(__first), std::move(__last), __comp, __proj);
 }
 
 template <class _ForwardIterator, class _Compare>
 _LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator
 min_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp)
 {
-    typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
-    return _VSTD::__min_element<_Comp_ref>(__first, __last, __comp);
+  static_assert(__is_cpp17_forward_iterator<_ForwardIterator>::value,
+      "std::min_element requires a ForwardIterator");
+  static_assert(__is_callable<_Compare, decltype(*__first), decltype(*__first)>::value,
+              "The comparator has to be callable");
+
+  typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
+  return std::__min_element<_Comp_ref>(std::move(__first), std::move(__last), __comp);
 }
 
 template <class _ForwardIterator>

diff  --git a/libcxx/include/__algorithm/nth_element.h b/libcxx/include/__algorithm/nth_element.h
index c7cdef5be817..688398dee814 100644
--- a/libcxx/include/__algorithm/nth_element.h
+++ b/libcxx/include/__algorithm/nth_element.h
@@ -11,13 +11,13 @@
 
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/sort.h>
 #include <__config>
 #include <__debug>
 #include <__debug_utils/randomize_range.h>
 #include <__iterator/iterator_traits.h>
 #include <__utility/move.h>
-#include <__utility/swap.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -41,10 +41,12 @@ __nth_element_find_guard(_RandomAccessIterator& __i, _RandomAccessIterator& __j,
     }
 }
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 _LIBCPP_CONSTEXPR_AFTER_CXX11 void
 __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp)
 {
+    using _Ops = _IterOps<_AlgPolicy>;
+
     // _Compare is known to be a reference type
     typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type 
diff erence_type;
     const 
diff erence_type __limit = 7;
@@ -60,24 +62,24 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
             return;
         case 2:
             if (__comp(*--__last, *__first))
-                swap(*__first, *__last);
+                _Ops::iter_swap(__first, __last);
             return;
         case 3:
             {
             _RandomAccessIterator __m = __first;
-            _VSTD::__sort3<_Compare>(__first, ++__m, --__last, __comp);
+            std::__sort3<_AlgPolicy, _Compare>(__first, ++__m, --__last, __comp);
             return;
             }
         }
         if (__len <= __limit)
         {
-            _VSTD::__selection_sort<_Compare>(__first, __last, __comp);
+            std::__selection_sort<_AlgPolicy, _Compare>(__first, __last, __comp);
             return;
         }
         // __len > __limit >= 3
         _RandomAccessIterator __m = __first + __len/2;
         _RandomAccessIterator __lm1 = __last;
-        unsigned __n_swaps = _VSTD::__sort3<_Compare>(__first, __m, --__lm1, __comp);
+        unsigned __n_swaps = std::__sort3<_AlgPolicy, _Compare>(__first, __m, --__lm1, __comp);
         // *__m is median
         // partition [__first, __m) < *__m and *__m <= [__m, __last)
         // (this inhibits tossing elements equivalent to __m around unnecessarily)
@@ -90,7 +92,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
         {
             // *__first == *__m, *__first doesn't go in first part
             if (_VSTD::__nth_element_find_guard<_Compare>(__i, __j, __m, __comp)) {
-                swap(*__i, *__j);
+                _Ops::iter_swap(__i, __j);
                 ++__n_swaps;
             } else {
                 // *__first == *__m, *__m <= all other elements
@@ -102,7 +104,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
                         if (__i == __j) {
                             return;  // [__first, __last) all equivalent elements
                         } else if (__comp(*__first, *__i)) {
-                            swap(*__i, *__j);
+                            _Ops::iter_swap(__i, __j);
                             ++__n_swaps;
                             ++__i;
                             break;
@@ -121,7 +123,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
                         ;
                     if (__i >= __j)
                         break;
-                    swap(*__i, *__j);
+                    _Ops::iter_swap(__i, __j);
                     ++__n_swaps;
                     ++__i;
                 }
@@ -152,7 +154,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
                     ;
                 if (__i >= __j)
                     break;
-                swap(*__i, *__j);
+                _Ops::iter_swap(__i, __j);
                 ++__n_swaps;
                 // It is known that __m != __j
                 // If __m just moved, follow it
@@ -164,7 +166,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
         // [__first, __i) < *__m and *__m <= [__i, __last)
         if (__i != __m && __comp(*__m, *__i))
         {
-            swap(*__i, *__m);
+            _Ops::iter_swap(__i, __m);
             ++__n_swaps;
         }
         // [__first, __i) < *__i and *__i <= [__i+1, __last)
@@ -220,21 +222,21 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
     }
 }
 
-template <class _RandomAccessIterator, class _Compare>
+template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
 void __nth_element_impl(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last,
                         _Compare& __comp) {
   if (__nth == __last)
     return;
 
-  std::__debug_randomize_range(__first, __last);
+  std::__debug_randomize_range<_AlgPolicy>(__first, __last);
 
   using _Comp_ref = typename __comp_ref_type<_Compare>::type;
-  std::__nth_element<_Comp_ref>(__first, __nth, __last, __comp);
+  std::__nth_element<_AlgPolicy, _Comp_ref>(__first, __nth, __last, __comp);
 
-  std::__debug_randomize_range(__first, __nth);
+  std::__debug_randomize_range<_AlgPolicy>(__first, __nth);
   if (__nth != __last) {
-    std::__debug_randomize_range(++__nth, __last);
+    std::__debug_randomize_range<_AlgPolicy>(++__nth, __last);
   }
 }
 
@@ -242,7 +244,7 @@ template <class _RandomAccessIterator, class _Compare>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
 void nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last,
                  _Compare __comp) {
-  std::__nth_element_impl(std::move(__first), std::move(__nth), std::move(__last), __comp);
+  std::__nth_element_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__nth), std::move(__last), __comp);
 }
 
 template <class _RandomAccessIterator>

diff  --git a/libcxx/include/__algorithm/partial_sort.h b/libcxx/include/__algorithm/partial_sort.h
index e008c0c99679..2c2468fc09ac 100644
--- a/libcxx/include/__algorithm/partial_sort.h
+++ b/libcxx/include/__algorithm/partial_sort.h
@@ -11,6 +11,7 @@
 
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_heap.h>
 #include <__algorithm/sift_down.h>
 #include <__algorithm/sort_heap.h>
@@ -18,7 +19,6 @@
 #include <__debug>
 #include <__debug_utils/randomize_range.h>
 #include <__iterator/iterator_traits.h>
-#include <__utility/swap.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -26,24 +26,24 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 _LIBCPP_CONSTEXPR_AFTER_CXX17 void
 __partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
                _Compare __comp)
 {
     if (__first == __middle)
         return;
-    _VSTD::__make_heap<_Compare>(__first, __middle, __comp);
+    std::__make_heap<_AlgPolicy, _Compare>(__first, __middle, __comp);
     typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len = __middle - __first;
     for (_RandomAccessIterator __i = __middle; __i != __last; ++__i)
     {
         if (__comp(*__i, *__first))
         {
-            swap(*__i, *__first);
-            _VSTD::__sift_down<_Compare>(__first, __comp, __len, __first);
+            _IterOps<_AlgPolicy>::iter_swap(__i, __first);
+            std::__sift_down<_AlgPolicy, _Compare>(__first, __comp, __len, __first);
         }
     }
-    _VSTD::__sort_heap<_Compare>(__first, __middle, __comp);
+    std::__sort_heap<_AlgPolicy, _Compare>(__first, __middle, __comp);
 }
 
 template <class _RandomAccessIterator, class _Compare>
@@ -52,10 +52,10 @@ void
 partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
              _Compare __comp)
 {
-  std::__debug_randomize_range(__first, __last);
+  std::__debug_randomize_range<_ClassicAlgPolicy>(__first, __last);
   typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
-  _VSTD::__partial_sort<_Comp_ref>(__first, __middle, __last, __comp);
-  std::__debug_randomize_range(__middle, __last);
+  std::__partial_sort<_ClassicAlgPolicy, _Comp_ref>(__first, __middle, __last, __comp);
+  std::__debug_randomize_range<_ClassicAlgPolicy>(__middle, __last);
 }
 
 template <class _RandomAccessIterator>

diff  --git a/libcxx/include/__algorithm/partial_sort_copy.h b/libcxx/include/__algorithm/partial_sort_copy.h
index 7ed1e538e9b8..3556764e652d 100644
--- a/libcxx/include/__algorithm/partial_sort_copy.h
+++ b/libcxx/include/__algorithm/partial_sort_copy.h
@@ -11,6 +11,7 @@
 
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_heap.h>
 #include <__algorithm/sift_down.h>
 #include <__algorithm/sort_heap.h>
@@ -23,7 +24,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Compare, class _InputIterator, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _InputIterator, class _RandomAccessIterator>
 _LIBCPP_CONSTEXPR_AFTER_CXX17 _RandomAccessIterator
 __partial_sort_copy(_InputIterator __first, _InputIterator __last,
                     _RandomAccessIterator __result_first, _RandomAccessIterator __result_last, _Compare __comp)
@@ -33,15 +34,15 @@ __partial_sort_copy(_InputIterator __first, _InputIterator __last,
     {
         for (; __first != __last && __r != __result_last; ++__first, (void) ++__r)
             *__r = *__first;
-        _VSTD::__make_heap<_Compare>(__result_first, __r, __comp);
+        std::__make_heap<_AlgPolicy, _Compare>(__result_first, __r, __comp);
         typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len = __r - __result_first;
         for (; __first != __last; ++__first)
             if (__comp(*__first, *__result_first))
             {
                 *__result_first = *__first;
-                _VSTD::__sift_down<_Compare>(__result_first, __comp, __len, __result_first);
+                std::__sift_down<_AlgPolicy, _Compare>(__result_first, __comp, __len, __result_first);
             }
-        _VSTD::__sort_heap<_Compare>(__result_first, __r, __comp);
+        std::__sort_heap<_AlgPolicy, _Compare>(__result_first, __r, __comp);
     }
     return __r;
 }
@@ -53,7 +54,8 @@ partial_sort_copy(_InputIterator __first, _InputIterator __last,
                   _RandomAccessIterator __result_first, _RandomAccessIterator __result_last, _Compare __comp)
 {
     typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
-    return _VSTD::__partial_sort_copy<_Comp_ref>(__first, __last, __result_first, __result_last, __comp);
+    return std::__partial_sort_copy<_ClassicAlgPolicy, _Comp_ref>(
+        __first, __last, __result_first, __result_last, __comp);
 }
 
 template <class _InputIterator, class _RandomAccessIterator>

diff  --git a/libcxx/include/__algorithm/pop_heap.h b/libcxx/include/__algorithm/pop_heap.h
index cadda81f6c88..e9852ddcc3f2 100644
--- a/libcxx/include/__algorithm/pop_heap.h
+++ b/libcxx/include/__algorithm/pop_heap.h
@@ -11,6 +11,7 @@
 
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/push_heap.h>
 #include <__algorithm/sift_down.h>
 #include <__assert>
@@ -24,7 +25,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
 void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp,
     typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len) {
@@ -35,17 +36,17 @@ void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Co
 
   using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
   if (__len > 1) {
-    value_type __top = std::move(*__first);  // create a hole at __first
-    _RandomAccessIterator __hole = std::__floyd_sift_down<_CompRef>(__first, __comp_ref, __len);
+    value_type __top = _IterOps<_AlgPolicy>::__iter_move(__first);  // create a hole at __first
+    _RandomAccessIterator __hole = std::__floyd_sift_down<_AlgPolicy, _CompRef>(__first, __comp_ref, __len);
     --__last;
 
     if (__hole == __last) {
       *__hole = std::move(__top);
     } else {
-      *__hole = std::move(*__last);
+      *__hole = _IterOps<_AlgPolicy>::__iter_move(__last);
       ++__hole;
       *__last = std::move(__top);
-      std::__sift_up<_CompRef>(__first, __hole, __comp_ref, __hole - __first);
+      std::__sift_up<_AlgPolicy, _CompRef>(__first, __hole, __comp_ref, __hole - __first);
     }
   }
 }
@@ -54,7 +55,7 @@ template <class _RandomAccessIterator, class _Compare>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
 void pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
   typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len = __last - __first;
-  std::__pop_heap(std::move(__first), std::move(__last), __comp, __len);
+  std::__pop_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp, __len);
 }
 
 template <class _RandomAccessIterator>

diff  --git a/libcxx/include/__algorithm/push_heap.h b/libcxx/include/__algorithm/push_heap.h
index 1e3eec373d4f..a9aabb1dc24b 100644
--- a/libcxx/include/__algorithm/push_heap.h
+++ b/libcxx/include/__algorithm/push_heap.h
@@ -11,6 +11,7 @@
 
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
 #include <__config>
 #include <__iterator/iterator_traits.h>
 #include <__utility/move.h>
@@ -21,7 +22,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
 void __sift_up(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
         typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len) {
@@ -32,9 +33,9 @@ void __sift_up(_RandomAccessIterator __first, _RandomAccessIterator __last, _Com
     _RandomAccessIterator __ptr = __first + __len;
 
     if (__comp(*__ptr, *--__last)) {
-      value_type __t(std::move(*__last));
+      value_type __t(_IterOps<_AlgPolicy>::__iter_move(__last));
       do {
-        *__last = std::move(*__ptr);
+        *__last = _IterOps<_AlgPolicy>::__iter_move(__ptr);
         __last = __ptr;
         if (__len == 0)
           break;
@@ -47,18 +48,18 @@ void __sift_up(_RandomAccessIterator __first, _RandomAccessIterator __last, _Com
   }
 }
 
-template <class _RandomAccessIterator, class _Compare>
+template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
 void __push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
   using _CompRef = typename __comp_ref_type<_Compare>::type;
   typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len = __last - __first;
-  std::__sift_up<_CompRef>(std::move(__first), std::move(__last), __comp, __len);
+  std::__sift_up<_AlgPolicy, _CompRef>(std::move(__first), std::move(__last), __comp, __len);
 }
 
 template <class _RandomAccessIterator, class _Compare>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
 void push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
-  std::__push_heap(std::move(__first), std::move(__last), __comp);
+  std::__push_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
 }
 
 template <class _RandomAccessIterator>

diff  --git a/libcxx/include/__algorithm/ranges_fill.h b/libcxx/include/__algorithm/ranges_fill.h
index 846e31885141..7ce4a76ba9e9 100644
--- a/libcxx/include/__algorithm/ranges_fill.h
+++ b/libcxx/include/__algorithm/ranges_fill.h
@@ -30,7 +30,7 @@ struct __fn {
   template <class _Type, output_iterator<const _Type&> _Iter, sentinel_for<_Iter> _Sent>
   _LIBCPP_HIDE_FROM_ABI constexpr
   _Iter operator()(_Iter __first, _Sent __last, const _Type& __value) const {
-    if constexpr(random_access_iterator<_Iter>) {
+    if constexpr(random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter>) {
       return ranges::fill_n(__first, __last - __first, __value);
     } else {
       for (; __first != __last; ++__first)

diff  --git a/libcxx/include/__algorithm/ranges_make_heap.h b/libcxx/include/__algorithm/ranges_make_heap.h
index fd488dc11a4b..8eabdd12cd2f 100644
--- a/libcxx/include/__algorithm/ranges_make_heap.h
+++ b/libcxx/include/__algorithm/ranges_make_heap.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_MAKE_HEAP_H
 #define _LIBCPP___ALGORITHM_RANGES_MAKE_HEAP_H
 
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_heap.h>
 #include <__algorithm/make_projected.h>
 #include <__concepts/same_as.h>
@@ -45,7 +46,7 @@ struct __fn {
     auto __last_iter = ranges::next(__first, __last);
 
     auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
-    std::__make_heap(std::move(__first), __last_iter, __projected_comp);
+    std::__make_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
 
     return __last_iter;
   }

diff  --git a/libcxx/include/__algorithm/ranges_min_element.h b/libcxx/include/__algorithm/ranges_min_element.h
index ae82dceb9ad8..26f95fe3a6d2 100644
--- a/libcxx/include/__algorithm/ranges_min_element.h
+++ b/libcxx/include/__algorithm/ranges_min_element.h
@@ -30,6 +30,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 namespace ranges {
 
+// TODO(ranges): `ranges::min_element` can now simply delegate to `std::__min_element`.
 template <class _Ip, class _Sp, class _Proj, class _Comp>
 _LIBCPP_HIDE_FROM_ABI static constexpr
 _Ip __min_element_impl(_Ip __first, _Sp __last, _Comp& __comp, _Proj& __proj) {

diff  --git a/libcxx/include/__algorithm/ranges_nth_element.h b/libcxx/include/__algorithm/ranges_nth_element.h
index 2a929eacb89d..b15eb816b918 100644
--- a/libcxx/include/__algorithm/ranges_nth_element.h
+++ b/libcxx/include/__algorithm/ranges_nth_element.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_NTH_ELEMENT_H
 #define _LIBCPP___ALGORITHM_RANGES_NTH_ELEMENT_H
 
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_projected.h>
 #include <__algorithm/nth_element.h>
 #include <__config>
@@ -44,7 +45,7 @@ struct __fn {
     auto __last_iter = ranges::next(__first, __last);
 
     auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
-    std::__nth_element_impl(std::move(__first), std::move(__nth), __last_iter, __projected_comp);
+    std::__nth_element_impl<_RangeAlgPolicy>(std::move(__first), std::move(__nth), __last_iter, __projected_comp);
 
     return __last_iter;
   }

diff  --git a/libcxx/include/__algorithm/ranges_pop_heap.h b/libcxx/include/__algorithm/ranges_pop_heap.h
index d0b8314e5b0a..92df6119d34a 100644
--- a/libcxx/include/__algorithm/ranges_pop_heap.h
+++ b/libcxx/include/__algorithm/ranges_pop_heap.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_POP_HEAP_H
 #define _LIBCPP___ALGORITHM_RANGES_POP_HEAP_H
 
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_projected.h>
 #include <__algorithm/pop_heap.h>
 #include <__concepts/same_as.h>
@@ -46,7 +47,7 @@ struct __fn {
     auto __len = __last_iter - __first;
 
     auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
-    std::__pop_heap(std::move(__first), __last_iter, __projected_comp, __len);
+    std::__pop_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp, __len);
 
     return __last_iter;
   }

diff  --git a/libcxx/include/__algorithm/ranges_push_heap.h b/libcxx/include/__algorithm/ranges_push_heap.h
index e46ad19cfed7..4c41b00128de 100644
--- a/libcxx/include/__algorithm/ranges_push_heap.h
+++ b/libcxx/include/__algorithm/ranges_push_heap.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_PUSH_HEAP_H
 #define _LIBCPP___ALGORITHM_RANGES_PUSH_HEAP_H
 
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_projected.h>
 #include <__algorithm/push_heap.h>
 #include <__concepts/same_as.h>
@@ -45,7 +46,7 @@ struct __fn {
     auto __last_iter = ranges::next(__first, __last);
 
     auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
-    std::__push_heap(std::move(__first), __last_iter, __projected_comp);
+    std::__push_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
 
     return __last_iter;
   }

diff  --git a/libcxx/include/__algorithm/ranges_sort.h b/libcxx/include/__algorithm/ranges_sort.h
index 8297940df237..ef14db64295d 100644
--- a/libcxx/include/__algorithm/ranges_sort.h
+++ b/libcxx/include/__algorithm/ranges_sort.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_SORT_H
 #define _LIBCPP___ALGORITHM_RANGES_SORT_H
 
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_projected.h>
 #include <__algorithm/sort.h>
 #include <__config>
@@ -44,7 +45,7 @@ struct __fn {
     auto __last_iter = ranges::next(__first, __last);
 
     auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
-    std::__sort_impl(std::move(__first), __last_iter, __projected_comp);
+    std::__sort_impl<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
 
     return __last_iter;
   }

diff  --git a/libcxx/include/__algorithm/ranges_sort_heap.h b/libcxx/include/__algorithm/ranges_sort_heap.h
index c753e20c44a6..eb6a30dcd3d0 100644
--- a/libcxx/include/__algorithm/ranges_sort_heap.h
+++ b/libcxx/include/__algorithm/ranges_sort_heap.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_SORT_HEAP_H
 #define _LIBCPP___ALGORITHM_RANGES_SORT_HEAP_H
 
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_projected.h>
 #include <__algorithm/sort_heap.h>
 #include <__concepts/same_as.h>
@@ -45,7 +46,7 @@ struct __fn {
     auto __last_iter = ranges::next(__first, __last);
 
     auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
-    std::__sort_heap(std::move(__first), __last_iter, __projected_comp);
+    std::__sort_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
 
     return __last_iter;
   }

diff  --git a/libcxx/include/__algorithm/ranges_stable_sort.h b/libcxx/include/__algorithm/ranges_stable_sort.h
index 20e840426434..de48416a41be 100644
--- a/libcxx/include/__algorithm/ranges_stable_sort.h
+++ b/libcxx/include/__algorithm/ranges_stable_sort.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_RANGES_STABLE_SORT_H
 #define _LIBCPP___ALGORITHM_RANGES_STABLE_SORT_H
 
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_projected.h>
 #include <__algorithm/stable_sort.h>
 #include <__config>
@@ -44,7 +45,7 @@ struct __fn {
     auto __last_iter = ranges::next(__first, __last);
 
     auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
-    std::__stable_sort_impl(std::move(__first), __last_iter, __projected_comp);
+    std::__stable_sort_impl<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
 
     return __last_iter;
   }

diff  --git a/libcxx/include/__algorithm/shuffle.h b/libcxx/include/__algorithm/shuffle.h
index 6c6ff5675dad..077881562192 100644
--- a/libcxx/include/__algorithm/shuffle.h
+++ b/libcxx/include/__algorithm/shuffle.h
@@ -9,11 +9,13 @@
 #ifndef _LIBCPP___ALGORITHM_SHUFFLE_H
 #define _LIBCPP___ALGORITHM_SHUFFLE_H
 
+#include <__algorithm/iterator_operations.h>
 #include <__config>
 #include <__debug>
 #include <__iterator/iterator_traits.h>
 #include <__random/uniform_int_distribution.h>
-#include <__utility/swap.h>
+#include <__utility/forward.h>
+#include <__utility/move.h>
 #include <cstddef>
 #include <cstdint>
 
@@ -134,10 +136,8 @@ random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
 }
 #endif
 
-template<class _RandomAccessIterator, class _UniformRandomNumberGenerator>
-    void shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
-                 _UniformRandomNumberGenerator&& __g)
-{
+template <class _AlgPolicy, class _RandomAccessIterator, class _UniformRandomNumberGenerator>
+void __shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last, _UniformRandomNumberGenerator&& __g) {
     typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type 
diff erence_type;
     typedef uniform_int_distribution<ptr
diff _t> _Dp;
     typedef typename _Dp::param_type _Pp;
@@ -149,11 +149,18 @@ template<class _RandomAccessIterator, class _UniformRandomNumberGenerator>
         {
             
diff erence_type __i = __uid(__g, _Pp(0, __d));
             if (__i != 
diff erence_type(0))
-                swap(*__first, *(__first + __i));
+                _IterOps<_AlgPolicy>::iter_swap(__first, __first + __i);
         }
     }
 }
 
+template <class _RandomAccessIterator, class _UniformRandomNumberGenerator>
+void shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
+             _UniformRandomNumberGenerator&& __g) {
+  std::__shuffle<_ClassicAlgPolicy>(
+      std::move(__first), std::move(__last), std::forward<_UniformRandomNumberGenerator>(__g));
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 _LIBCPP_POP_MACROS

diff  --git a/libcxx/include/__algorithm/sift_down.h b/libcxx/include/__algorithm/sift_down.h
index 0351a1c578b0..be2eb29dd53a 100644
--- a/libcxx/include/__algorithm/sift_down.h
+++ b/libcxx/include/__algorithm/sift_down.h
@@ -9,6 +9,7 @@
 #ifndef _LIBCPP___ALGORITHM_SIFT_DOWN_H
 #define _LIBCPP___ALGORITHM_SIFT_DOWN_H
 
+#include <__algorithm/iterator_operations.h>
 #include <__assert>
 #include <__config>
 #include <__iterator/iterator_traits.h>
@@ -20,12 +21,14 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 _LIBCPP_CONSTEXPR_AFTER_CXX11 void
 __sift_down(_RandomAccessIterator __first, _Compare __comp,
             typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len,
             _RandomAccessIterator __start)
 {
+    using _Ops = _IterOps<_AlgPolicy>;
+
     typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type 
diff erence_type;
     typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
     // left-child of __start is at 2 * __start + 1
@@ -49,11 +52,11 @@ __sift_down(_RandomAccessIterator __first, _Compare __comp,
         // we are, __start is larger than its largest child
         return;
 
-    value_type __top(_VSTD::move(*__start));
+    value_type __top(_Ops::__iter_move(__start));
     do
     {
         // we are not in heap-order, swap the parent with its largest child
-        *__start = _VSTD::move(*__child_i);
+        *__start = _Ops::__iter_move(__child_i);
         __start = __child_i;
 
         if ((__len - 2) / 2 < __child)
@@ -74,7 +77,7 @@ __sift_down(_RandomAccessIterator __first, _Compare __comp,
     *__start = _VSTD::move(__top);
 }
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 _LIBCPP_CONSTEXPR_AFTER_CXX11 _RandomAccessIterator
 __floyd_sift_down(_RandomAccessIterator __first, _Compare __comp,
                   typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len)
@@ -97,7 +100,7 @@ __floyd_sift_down(_RandomAccessIterator __first, _Compare __comp,
         }
 
         // swap __hole with its largest child
-        *__hole = std::move(*__child_i);
+        *__hole = _IterOps<_AlgPolicy>::__iter_move(__child_i);
         __hole = __child_i;
 
         // if __hole is now a leaf, we're done

diff  --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h
index 76a18215731b..db658515b71b 100644
--- a/libcxx/include/__algorithm/sort.h
+++ b/libcxx/include/__algorithm/sort.h
@@ -11,6 +11,7 @@
 
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/min_element.h>
 #include <__algorithm/partial_sort.h>
 #include <__algorithm/unwrap_iter.h>
@@ -21,7 +22,6 @@
 #include <__functional/operations.h>
 #include <__functional/ranges_operations.h>
 #include <__iterator/iterator_traits.h>
-#include <__utility/swap.h>
 #include <climits>
 #include <memory>
 
@@ -31,37 +31,85 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+// Wraps an algorithm policy tag and a comparator in a single struct, used to pass the policy tag around without
+// changing the number of template arguments (to keep the ABI stable). This is only used for the "range" policy tag.
+//
+// To create an object of this type, use `_WrapAlgPolicy<T, C>::type` -- see the specialization below for the rationale.
+template <class _PolicyT, class _CompT, class = void>
+struct _WrapAlgPolicy {
+  using type = _WrapAlgPolicy;
+
+  using _AlgPolicy = _PolicyT;
+  using _Comp = _CompT;
+  _Comp& __comp;
+
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+  _WrapAlgPolicy(_Comp& __c) : __comp(__c) {}
+};
+
+// Specialization for the "classic" policy tag that avoids creating a struct and simply defines an alias for the
+// comparator. When unwrapping, a pristine comparator is always considered to have the "classic" tag attached. Passing
+// the pristine comparator where possible allows using template instantiations from the dylib.
+template <class _PolicyT, class _CompT>
+struct _WrapAlgPolicy<_PolicyT, _CompT, __enable_if_t<std::is_same<_PolicyT, _ClassicAlgPolicy>::value> > {
+  using type = _CompT;
+};
+
+// Unwraps a pristine functor (e.g. `std::less`) as if it were wrapped using `_WrapAlgPolicy`. The policy tag is always
+// set to "classic".
+template <class _CompT>
+struct _UnwrapAlgPolicy {
+  using _AlgPolicy = _ClassicAlgPolicy;
+  using _Comp = _CompT;
+
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 static
+  _Comp __get_comp(_Comp __comp) { return __comp; }
+};
+
+// Unwraps a `_WrapAlgPolicy` struct.
+template <class... _Ts>
+struct _UnwrapAlgPolicy<_WrapAlgPolicy<_Ts...> > {
+  using _Wrapped = _WrapAlgPolicy<_Ts...>;
+  using _AlgPolicy = typename _Wrapped::_AlgPolicy;
+  using _Comp = typename _Wrapped::_Comp;
+
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 static
+  _Comp __get_comp(_Wrapped& __w) { return __w.__comp; }
+};
+
 // stable, 2-3 compares, 0-2 swaps
 
-template <class _Compare, class _ForwardIterator>
+template <class _AlgPolicy, class _Compare, class _ForwardIterator>
 _LIBCPP_CONSTEXPR_AFTER_CXX11 unsigned __sort3(_ForwardIterator __x, _ForwardIterator __y, _ForwardIterator __z,
                                                _Compare __c) {
+  using _Ops = _IterOps<_AlgPolicy>;
+
   unsigned __r = 0;
   if (!__c(*__y, *__x))   // if x <= y
   {
     if (!__c(*__z, *__y)) // if y <= z
       return __r;         // x <= y && y <= z
                           // x <= y && y > z
-    swap(*__y, *__z);     // x <= z && y < z
+    _Ops::iter_swap(__y, __z);     // x <= z && y < z
     __r = 1;
     if (__c(*__y, *__x))  // if x > y
     {
-      swap(*__x, *__y);   // x < y && y <= z
+      _Ops::iter_swap(__x, __y);   // x < y && y <= z
       __r = 2;
     }
     return __r;           // x <= y && y < z
   }
   if (__c(*__z, *__y))    // x > y, if y > z
   {
-    swap(*__x, *__z);     // x < y && y < z
+    _Ops::iter_swap(__x, __z);     // x < y && y < z
     __r = 1;
     return __r;
   }
-  swap(*__x, *__y);       // x > y && y <= z
+  _Ops::iter_swap(__x, __y);       // x > y && y <= z
   __r = 1;                // x < y && x <= z
   if (__c(*__z, *__y))    // if y > z
   {
-    swap(*__y, *__z);     // x <= y && y < z
+    _Ops::iter_swap(__y, __z);     // x <= y && y < z
     __r = 2;
   }
   return __r;
@@ -69,18 +117,20 @@ _LIBCPP_CONSTEXPR_AFTER_CXX11 unsigned __sort3(_ForwardIterator __x, _ForwardIte
 
 // stable, 3-6 compares, 0-5 swaps
 
-template <class _Compare, class _ForwardIterator>
+template <class _AlgPolicy, class _Compare, class _ForwardIterator>
 unsigned __sort4(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3, _ForwardIterator __x4,
                  _Compare __c) {
-  unsigned __r = _VSTD::__sort3<_Compare>(__x1, __x2, __x3, __c);
+  using _Ops = _IterOps<_AlgPolicy>;
+
+  unsigned __r = std::__sort3<_AlgPolicy, _Compare>(__x1, __x2, __x3, __c);
   if (__c(*__x4, *__x3)) {
-    swap(*__x3, *__x4);
+    _Ops::iter_swap(__x3, __x4);
     ++__r;
     if (__c(*__x3, *__x2)) {
-      swap(*__x2, *__x3);
+      _Ops::iter_swap(__x2, __x3);
       ++__r;
       if (__c(*__x2, *__x1)) {
-        swap(*__x1, *__x2);
+        _Ops::iter_swap(__x1, __x2);
         ++__r;
       }
     }
@@ -90,21 +140,28 @@ unsigned __sort4(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator
 
 // stable, 4-10 compares, 0-9 swaps
 
-template <class _Compare, class _ForwardIterator>
+template <class _WrappedComp, class _ForwardIterator>
 _LIBCPP_HIDDEN unsigned __sort5(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3,
-                                _ForwardIterator __x4, _ForwardIterator __x5, _Compare __c) {
-  unsigned __r = _VSTD::__sort4<_Compare>(__x1, __x2, __x3, __x4, __c);
+                                _ForwardIterator __x4, _ForwardIterator __x5, _WrappedComp __wrapped_comp) {
+  using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
+  using _AlgPolicy = typename _Unwrap::_AlgPolicy;
+  using _Ops = _IterOps<_AlgPolicy>;
+
+  using _Compare = typename _Unwrap::_Comp;
+  _Compare __c = _Unwrap::__get_comp(__wrapped_comp);
+
+  unsigned __r = std::__sort4<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __c);
   if (__c(*__x5, *__x4)) {
-    swap(*__x4, *__x5);
+    _Ops::iter_swap(__x4, __x5);
     ++__r;
     if (__c(*__x4, *__x3)) {
-      swap(*__x3, *__x4);
+      _Ops::iter_swap(__x3, __x4);
       ++__r;
       if (__c(*__x3, *__x2)) {
-        swap(*__x2, *__x3);
+        _Ops::iter_swap(__x2, __x3);
         ++__r;
         if (__c(*__x2, *__x1)) {
-          swap(*__x1, *__x2);
+          _Ops::iter_swap(__x1, __x2);
           ++__r;
         }
       }
@@ -113,6 +170,16 @@ _LIBCPP_HIDDEN unsigned __sort5(_ForwardIterator __x1, _ForwardIterator __x2, _F
   return __r;
 }
 
+template <class _AlgPolicy, class _Compare, class _ForwardIterator>
+_LIBCPP_HIDDEN unsigned __sort5_wrap_policy(
+    _ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3, _ForwardIterator __x4, _ForwardIterator __x5,
+    _Compare __c) {
+  using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Compare>::type;
+  _WrappedComp __wrapped_comp(__c);
+  return std::__sort5<_WrappedComp>(
+      std::move(__x1), std::move(__x2), std::move(__x3), std::move(__x4), std::move(__x5), __wrapped_comp);
+}
+
 // The comparator being simple is a prerequisite for using the branchless optimization.
 template <class _Tp>
 struct __is_simple_comparator : false_type {};
@@ -137,6 +204,7 @@ using __use_branchless_sort =
 // Ensures that __c(*__x, *__y) is true by swapping *__x and *__y if necessary.
 template <class _Compare, class _RandomAccessIterator>
 inline _LIBCPP_HIDE_FROM_ABI void __cond_swap(_RandomAccessIterator __x, _RandomAccessIterator __y, _Compare __c) {
+  // Note: this function behaves correctly even with proxy iterators (because it relies on `value_type`).
   using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
   bool __r = __c(*__x, *__y);
   value_type __tmp = __r ? *__x : *__y;
@@ -149,6 +217,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __cond_swap(_RandomAccessIterator __x, _Random
 template <class _Compare, class _RandomAccessIterator>
 inline _LIBCPP_HIDE_FROM_ABI void __partially_sorted_swap(_RandomAccessIterator __x, _RandomAccessIterator __y,
                                                           _RandomAccessIterator __z, _Compare __c) {
+  // Note: this function behaves correctly even with proxy iterators (because it relies on `value_type`).
   using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
   bool __r = __c(*__z, *__x);
   value_type __tmp = __r ? *__z : *__x;
@@ -158,7 +227,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __partially_sorted_swap(_RandomAccessIterator
   *__y = __r ? *__y : __tmp;
 }
 
-template <class _Compare, class _RandomAccessIterator>
+template <class, class _Compare, class _RandomAccessIterator>
 inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
 __sort3_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
                          _Compare __c) {
@@ -166,14 +235,14 @@ __sort3_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2,
   _VSTD::__partially_sorted_swap<_Compare>(__x1, __x2, __x3, __c);
 }
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
 __sort3_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
                          _Compare __c) {
-  _VSTD::__sort3<_Compare>(__x1, __x2, __x3, __c);
+  std::__sort3<_AlgPolicy, _Compare>(__x1, __x2, __x3, __c);
 }
 
-template <class _Compare, class _RandomAccessIterator>
+template <class, class _Compare, class _RandomAccessIterator>
 inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
 __sort4_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
                          _RandomAccessIterator __x4, _Compare __c) {
@@ -184,14 +253,14 @@ __sort4_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2,
   _VSTD::__cond_swap<_Compare>(__x2, __x3, __c);
 }
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
 __sort4_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
                          _RandomAccessIterator __x4, _Compare __c) {
-  _VSTD::__sort4<_Compare>(__x1, __x2, __x3, __x4, __c);
+  std::__sort4<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __c);
 }
 
-template <class _Compare, class _RandomAccessIterator>
+template <class, class _Compare, class _RandomAccessIterator>
 inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
 __sort5_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
                          _RandomAccessIterator __x4, _RandomAccessIterator __x5, _Compare __c) {
@@ -203,53 +272,57 @@ __sort5_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2,
   _VSTD::__partially_sorted_swap<_Compare>(__x2, __x3, __x4, __c);
 }
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
 __sort5_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
                          _RandomAccessIterator __x4, _RandomAccessIterator __x5, _Compare __c) {
-  _VSTD::__sort5<_Compare>(__x1, __x2, __x3, __x4, __x5, __c);
+  std::__sort5_wrap_policy<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __x5, __c);
 }
 
 // Assumes size > 0
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
 _LIBCPP_CONSTEXPR_AFTER_CXX11 void __selection_sort(_BidirectionalIterator __first, _BidirectionalIterator __last,
                                                     _Compare __comp) {
   _BidirectionalIterator __lm1 = __last;
   for (--__lm1; __first != __lm1; ++__first) {
-    _BidirectionalIterator __i = _VSTD::min_element(__first, __last, __comp);
+    _BidirectionalIterator __i = std::__min_element<_Compare>(__first, __last, __comp);
     if (__i != __first)
-      swap(*__first, *__i);
+      _IterOps<_AlgPolicy>::iter_swap(__first, __i);
   }
 }
 
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
 void __insertion_sort(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) {
+  using _Ops = _IterOps<_AlgPolicy>;
+
   typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
   if (__first != __last) {
     _BidirectionalIterator __i = __first;
     for (++__i; __i != __last; ++__i) {
       _BidirectionalIterator __j = __i;
-      value_type __t(_VSTD::move(*__j));
+      value_type __t(_Ops::__iter_move(__j));
       for (_BidirectionalIterator __k = __i; __k != __first && __comp(__t, *--__k); --__j)
-        *__j = _VSTD::move(*__k);
+        *__j = _Ops::__iter_move(__k);
       *__j = _VSTD::move(__t);
     }
   }
 }
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 void __insertion_sort_3(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+  using _Ops = _IterOps<_AlgPolicy>;
+
   typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type 
diff erence_type;
   typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
   _RandomAccessIterator __j = __first + 
diff erence_type(2);
-  _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first + 
diff erence_type(1), __j, __comp);
+  std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + 
diff erence_type(1), __j, __comp);
   for (_RandomAccessIterator __i = __j + 
diff erence_type(1); __i != __last; ++__i) {
     if (__comp(*__i, *__j)) {
-      value_type __t(_VSTD::move(*__i));
+      value_type __t(_Ops::__iter_move(__i));
       _RandomAccessIterator __k = __j;
       __j = __i;
       do {
-        *__j = _VSTD::move(*__k);
+        *__j = _Ops::__iter_move(__k);
         __j = __k;
       } while (__j != __first && __comp(__t, *--__k));
       *__j = _VSTD::move(__t);
@@ -258,8 +331,16 @@ void __insertion_sort_3(_RandomAccessIterator __first, _RandomAccessIterator __l
   }
 }
 
-template <class _Compare, class _RandomAccessIterator>
-bool __insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+template <class _WrappedComp, class _RandomAccessIterator>
+bool __insertion_sort_incomplete(
+    _RandomAccessIterator __first, _RandomAccessIterator __last, _WrappedComp __wrapped_comp) {
+  using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
+  using _AlgPolicy = typename _Unwrap::_AlgPolicy;
+  using _Ops = _IterOps<_AlgPolicy>;
+
+  using _Compare = typename _Unwrap::_Comp;
+  _Compare __comp = _Unwrap::__get_comp(__wrapped_comp);
+
   typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type 
diff erence_type;
   switch (__last - __first) {
   case 0:
@@ -267,32 +348,33 @@ bool __insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIte
     return true;
   case 2:
     if (__comp(*--__last, *__first))
-      swap(*__first, *__last);
+      _IterOps<_AlgPolicy>::iter_swap(__first, __last);
     return true;
   case 3:
-    _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first + 
diff erence_type(1), --__last, __comp);
+    std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + 
diff erence_type(1), --__last, __comp);
     return true;
   case 4:
-    _VSTD::__sort4_maybe_branchless<_Compare>(__first, __first + 
diff erence_type(1), __first + 
diff erence_type(2),
-                                              --__last, __comp);
+    std::__sort4_maybe_branchless<_AlgPolicy, _Compare>(
+        __first, __first + 
diff erence_type(1), __first + 
diff erence_type(2), --__last, __comp);
     return true;
   case 5:
-    _VSTD::__sort5_maybe_branchless<_Compare>(__first, __first + 
diff erence_type(1), __first + 
diff erence_type(2),
-                                              __first + 
diff erence_type(3), --__last, __comp);
+    std::__sort5_maybe_branchless<_AlgPolicy, _Compare>(
+        __first, __first + 
diff erence_type(1), __first + 
diff erence_type(2), __first + 
diff erence_type(3),
+        --__last, __comp);
     return true;
   }
   typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
   _RandomAccessIterator __j = __first + 
diff erence_type(2);
-  _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first + 
diff erence_type(1), __j, __comp);
+  std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + 
diff erence_type(1), __j, __comp);
   const unsigned __limit = 8;
   unsigned __count = 0;
   for (_RandomAccessIterator __i = __j + 
diff erence_type(1); __i != __last; ++__i) {
     if (__comp(*__i, *__j)) {
-      value_type __t(_VSTD::move(*__i));
+      value_type __t(_Ops::__iter_move(__i));
       _RandomAccessIterator __k = __j;
       __j = __i;
       do {
-        *__j = _VSTD::move(*__k);
+        *__j = _Ops::__iter_move(__k);
         __j = __k;
       } while (__j != __first && __comp(__t, *--__k));
       *__j = _VSTD::move(__t);
@@ -304,27 +386,29 @@ bool __insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIte
   return true;
 }
 
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
 void __insertion_sort_move(_BidirectionalIterator __first1, _BidirectionalIterator __last1,
                            typename iterator_traits<_BidirectionalIterator>::value_type* __first2, _Compare __comp) {
+  using _Ops = _IterOps<_AlgPolicy>;
+
   typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
   if (__first1 != __last1) {
     __destruct_n __d(0);
     unique_ptr<value_type, __destruct_n&> __h(__first2, __d);
     value_type* __last2 = __first2;
-    ::new ((void*)__last2) value_type(_VSTD::move(*__first1));
+    ::new ((void*)__last2) value_type(_Ops::__iter_move(__first1));
     __d.template __incr<value_type>();
     for (++__last2; ++__first1 != __last1; ++__last2) {
       value_type* __j2 = __last2;
       value_type* __i2 = __j2;
       if (__comp(*__first1, *--__i2)) {
-        ::new ((void*)__j2) value_type(_VSTD::move(*__i2));
+        ::new ((void*)__j2) value_type(std::move(*__i2));
         __d.template __incr<value_type>();
         for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2)
-          *__j2 = _VSTD::move(*__i2);
-        *__j2 = _VSTD::move(*__first1);
+          *__j2 = std::move(*__i2);
+        *__j2 = _Ops::__iter_move(__first1);
       } else {
-        ::new ((void*)__j2) value_type(_VSTD::move(*__first1));
+        ::new ((void*)__j2) value_type(_Ops::__iter_move(__first1));
         __d.template __incr<value_type>();
       }
     }
@@ -332,9 +416,11 @@ void __insertion_sort_move(_BidirectionalIterator __first1, _BidirectionalIterat
   }
 }
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
                  typename iterator_traits<_RandomAccessIterator>::
diff erence_type __depth) {
+  using _Ops = _IterOps<_AlgPolicy>;
+
   typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type 
diff erence_type;
   typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
   const 
diff erence_type __limit =
@@ -348,28 +434,29 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
       return;
     case 2:
       if (__comp(*--__last, *__first))
-        swap(*__first, *__last);
+        _IterOps<_AlgPolicy>::iter_swap(__first, __last);
       return;
     case 3:
-      _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first + 
diff erence_type(1), --__last, __comp);
+      std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + 
diff erence_type(1), --__last, __comp);
       return;
     case 4:
-      _VSTD::__sort4_maybe_branchless<_Compare>(__first, __first + 
diff erence_type(1), __first + 
diff erence_type(2),
-                                                --__last, __comp);
+      std::__sort4_maybe_branchless<_AlgPolicy, _Compare>(
+          __first, __first + 
diff erence_type(1), __first + 
diff erence_type(2), --__last, __comp);
       return;
     case 5:
-      _VSTD::__sort5_maybe_branchless<_Compare>(__first, __first + 
diff erence_type(1), __first + 
diff erence_type(2),
-                                                __first + 
diff erence_type(3), --__last, __comp);
+      std::__sort5_maybe_branchless<_AlgPolicy, _Compare>(
+          __first, __first + 
diff erence_type(1), __first + 
diff erence_type(2), __first + 
diff erence_type(3),
+          --__last, __comp);
       return;
     }
     if (__len <= __limit) {
-      _VSTD::__insertion_sort_3<_Compare>(__first, __last, __comp);
+      std::__insertion_sort_3<_AlgPolicy, _Compare>(__first, __last, __comp);
       return;
     }
     // __len > 5
     if (__depth == 0) {
       // Fallback to heap sort as Introsort suggests.
-      _VSTD::__partial_sort<_Compare>(__first, __last, __last, __comp);
+      std::__partial_sort<_AlgPolicy, _Compare>(__first, __last, __last, __comp);
       return;
     }
     --__depth;
@@ -383,11 +470,12 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
         __delta = __len / 2;
         __m += __delta;
         __delta /= 2;
-        __n_swaps = _VSTD::__sort5<_Compare>(__first, __first + __delta, __m, __m + __delta, __lm1, __comp);
+        __n_swaps = std::__sort5_wrap_policy<_AlgPolicy, _Compare>(
+            __first, __first + __delta, __m, __m + __delta, __lm1, __comp);
       } else {
         __delta = __len / 2;
         __m += __delta;
-        __n_swaps = _VSTD::__sort3<_Compare>(__first, __m, __lm1, __comp);
+        __n_swaps = std::__sort3<_AlgPolicy, _Compare>(__first, __m, __lm1, __comp);
       }
     }
     // *__m is median
@@ -414,7 +502,7 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
               if (__i == __j)
                 return; // [__first, __last) all equivalent elements
               if (__comp(*__first, *__i)) {
-                swap(*__i, *__j);
+                _Ops::iter_swap(__i, __j);
                 ++__n_swaps;
                 ++__i;
                 break;
@@ -432,7 +520,7 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
               ;
             if (__i >= __j)
               break;
-            swap(*__i, *__j);
+            _Ops::iter_swap(__i, __j);
             ++__n_swaps;
             ++__i;
           }
@@ -443,7 +531,7 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
           goto __restart;
         }
         if (__comp(*__j, *__m)) {
-          swap(*__i, *__j);
+          _Ops::iter_swap(__i, __j);
           ++__n_swaps;
           break; // found guard for downward moving __j, now use unguarded partition
         }
@@ -465,7 +553,7 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
           ;
         if (__i > __j)
           break;
-        swap(*__i, *__j);
+        _Ops::iter_swap(__i, __j);
         ++__n_swaps;
         // It is known that __m != __j
         // If __m just moved, follow it
@@ -476,14 +564,16 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
     }
     // [__first, __i) < *__m and *__m <= [__i, __last)
     if (__i != __m && __comp(*__m, *__i)) {
-      swap(*__i, *__m);
+      _Ops::iter_swap(__i, __m);
       ++__n_swaps;
     }
     // [__first, __i) < *__i and *__i <= [__i+1, __last)
     // If we were given a perfect partition, see if insertion sort is quick...
     if (__n_swaps == 0) {
-      bool __fs = _VSTD::__insertion_sort_incomplete<_Compare>(__first, __i, __comp);
-      if (_VSTD::__insertion_sort_incomplete<_Compare>(__i + 
diff erence_type(1), __last, __comp)) {
+      using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Compare>::type;
+      _WrappedComp __wrapped_comp(__comp);
+      bool __fs = std::__insertion_sort_incomplete<_WrappedComp>(__first, __i, __wrapped_comp);
+      if (std::__insertion_sort_incomplete<_WrappedComp>(__i + 
diff erence_type(1), __last, __wrapped_comp)) {
         if (__fs)
           return;
         __last = __i;
@@ -497,10 +587,10 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
     }
     // sort smaller range with recursive call and larger with tail recursion elimination
     if (__i - __first < __last - __i) {
-      _VSTD::__introsort<_Compare>(__first, __i, __comp, __depth);
+      std::__introsort<_AlgPolicy, _Compare>(__first, __i, __comp, __depth);
       __first = ++__i;
     } else {
-      _VSTD::__introsort<_Compare>(__i + 
diff erence_type(1), __last, __comp, __depth);
+      std::__introsort<_AlgPolicy, _Compare>(__i + 
diff erence_type(1), __last, __comp, __depth);
       __last = __i;
     }
   }
@@ -525,17 +615,22 @@ inline _LIBCPP_HIDE_FROM_ABI _Number __log2i(_Number __n) {
   return __log2;
 }
 
-template <class _Compare, class _RandomAccessIterator>
-void __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+template <class _WrappedComp, class _RandomAccessIterator>
+void __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _WrappedComp __wrapped_comp) {
   typedef typename iterator_traits<_RandomAccessIterator>::
diff erence_type 
diff erence_type;
   
diff erence_type __depth_limit = 2 * __log2i(__last - __first);
-  _VSTD::__introsort<_Compare>(__first, __last, __comp, __depth_limit);
+
+  using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
+  using _AlgPolicy = typename _Unwrap::_AlgPolicy;
+  using _Compare = typename _Unwrap::_Comp;
+  _Compare __comp = _Unwrap::__get_comp(__wrapped_comp);
+  std::__introsort<_AlgPolicy, _Compare>(__first, __last, __comp, __depth_limit);
 }
 
 template <class _Compare, class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY void __sort(_Tp** __first, _Tp** __last, __less<_Tp*>&) {
   __less<uintptr_t> __comp;
-  _VSTD::__sort<__less<uintptr_t>&, uintptr_t*>((uintptr_t*)__first, (uintptr_t*)__last, __comp);
+  std::__sort<__less<uintptr_t>&, uintptr_t*>((uintptr_t*)__first, (uintptr_t*)__last, __comp);
 }
 
 extern template _LIBCPP_FUNC_VIS void __sort<__less<char>&, char*>(char*, char*, __less<char>&);
@@ -576,22 +671,27 @@ extern template _LIBCPP_FUNC_VIS bool __insertion_sort_incomplete<__less<long do
 
 extern template _LIBCPP_FUNC_VIS unsigned __sort5<__less<long double>&, long double*>(long double*, long double*, long double*, long double*, long double*, __less<long double>&);
 
-template <class _RandomAccessIterator, class _Comp>
+template <class _AlgPolicy, class _RandomAccessIterator, class _Comp>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
 void __sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) {
-  std::__debug_randomize_range(__first, __last);
+  std::__debug_randomize_range<_AlgPolicy>(__first, __last);
+
   using _Comp_ref = typename __comp_ref_type<_Comp>::type;
   if (__libcpp_is_constant_evaluated()) {
-    std::__partial_sort<_Comp_ref>(__first, __last, __last, _Comp_ref(__comp));
+    std::__partial_sort<_AlgPolicy, _Comp_ref>(__first, __last, __last, _Comp_ref(__comp));
+
   } else {
-    std::__sort<_Comp_ref>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), _Comp_ref(__comp));
+    using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Comp_ref>::type;
+    _Comp_ref __comp_ref(__comp);
+    _WrappedComp __wrapped_comp(__comp_ref);
+    std::__sort<_WrappedComp>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __wrapped_comp);
   }
 }
 
 template <class _RandomAccessIterator, class _Comp>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
 void sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) {
-  std::__sort_impl(std::move(__first), std::move(__last), __comp);
+  std::__sort_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
 }
 
 template <class _RandomAccessIterator>

diff  --git a/libcxx/include/__algorithm/sort_heap.h b/libcxx/include/__algorithm/sort_heap.h
index 261adedd0eaf..d0620eadf437 100644
--- a/libcxx/include/__algorithm/sort_heap.h
+++ b/libcxx/include/__algorithm/sort_heap.h
@@ -11,6 +11,7 @@
 
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/pop_heap.h>
 #include <__config>
 #include <__iterator/iterator_traits.h>
@@ -23,7 +24,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
 void __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
   using _CompRef = typename __comp_ref_type<_Compare>::type;
@@ -31,13 +32,13 @@ void __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
 
   using 
diff erence_type = typename iterator_traits<_RandomAccessIterator>::
diff erence_type;
   for (
diff erence_type __n = __last - __first; __n > 1; --__last, (void) --__n)
-    std::__pop_heap<_CompRef>(__first, __last, __comp_ref, __n);
+    std::__pop_heap<_AlgPolicy, _CompRef>(__first, __last, __comp_ref, __n);
 }
 
 template <class _RandomAccessIterator, class _Compare>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
 void sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
-  std::__sort_heap(std::move(__first), std::move(__last), __comp);
+  std::__sort_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
 }
 
 template <class _RandomAccessIterator>

diff  --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index e3479aad62e6..6122758bdefe 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -12,11 +12,11 @@
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
 #include <__algorithm/inplace_merge.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/sort.h>
 #include <__config>
 #include <__iterator/iterator_traits.h>
 #include <__utility/move.h>
-#include <__utility/swap.h>
 #include <memory>
 #include <type_traits>
 
@@ -26,12 +26,14 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Compare, class _InputIterator1, class _InputIterator2>
+template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2>
 void
 __merge_move_construct(_InputIterator1 __first1, _InputIterator1 __last1,
         _InputIterator2 __first2, _InputIterator2 __last2,
         typename iterator_traits<_InputIterator1>::value_type* __result, _Compare __comp)
 {
+    using _Ops = _IterOps<_AlgPolicy>;
+
     typedef typename iterator_traits<_InputIterator1>::value_type value_type;
     __destruct_n __d(0);
     unique_ptr<value_type, __destruct_n&> __h(__result, __d);
@@ -40,111 +42,115 @@ __merge_move_construct(_InputIterator1 __first1, _InputIterator1 __last1,
         if (__first1 == __last1)
         {
             for (; __first2 != __last2; ++__first2, (void) ++__result, __d.template __incr<value_type>())
-                ::new ((void*)__result) value_type(_VSTD::move(*__first2));
+                ::new ((void*)__result) value_type(_Ops::__iter_move(__first2));
             __h.release();
             return;
         }
         if (__first2 == __last2)
         {
             for (; __first1 != __last1; ++__first1, (void) ++__result, __d.template __incr<value_type>())
-                ::new ((void*)__result) value_type(_VSTD::move(*__first1));
+                ::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
             __h.release();
             return;
         }
         if (__comp(*__first2, *__first1))
         {
-            ::new ((void*)__result) value_type(_VSTD::move(*__first2));
+            ::new ((void*)__result) value_type(_Ops::__iter_move(__first2));
             __d.template __incr<value_type>();
             ++__first2;
         }
         else
         {
-            ::new ((void*)__result) value_type(_VSTD::move(*__first1));
+            ::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
             __d.template __incr<value_type>();
             ++__first1;
         }
     }
 }
 
-template <class _Compare, class _InputIterator1, class _InputIterator2, class _OutputIterator>
+template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2, class _OutputIterator>
 void
 __merge_move_assign(_InputIterator1 __first1, _InputIterator1 __last1,
         _InputIterator2 __first2, _InputIterator2 __last2,
         _OutputIterator __result, _Compare __comp)
 {
+    using _Ops = _IterOps<_AlgPolicy>;
+
     for (; __first1 != __last1; ++__result)
     {
         if (__first2 == __last2)
         {
             for (; __first1 != __last1; ++__first1, (void) ++__result)
-                *__result = _VSTD::move(*__first1);
+                *__result = _Ops::__iter_move(__first1);
             return;
         }
         if (__comp(*__first2, *__first1))
         {
-            *__result = _VSTD::move(*__first2);
+            *__result = _Ops::__iter_move(__first2);
             ++__first2;
         }
         else
         {
-            *__result = _VSTD::move(*__first1);
+            *__result = _Ops::__iter_move(__first1);
             ++__first1;
         }
     }
     for (; __first2 != __last2; ++__first2, (void) ++__result)
-        *__result = _VSTD::move(*__first2);
+        *__result = _Ops::__iter_move(__first2);
 }
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 void
 __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
               typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len,
               typename iterator_traits<_RandomAccessIterator>::value_type* __buff, ptr
diff _t __buff_size);
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 void
 __stable_sort_move(_RandomAccessIterator __first1, _RandomAccessIterator __last1, _Compare __comp,
                    typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len,
                    typename iterator_traits<_RandomAccessIterator>::value_type* __first2)
 {
+    using _Ops = _IterOps<_AlgPolicy>;
+
     typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
     switch (__len)
     {
     case 0:
         return;
     case 1:
-        ::new ((void*)__first2) value_type(_VSTD::move(*__first1));
+        ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
         return;
     case 2:
         __destruct_n __d(0);
         unique_ptr<value_type, __destruct_n&> __h2(__first2, __d);
         if (__comp(*--__last1, *__first1))
         {
-            ::new ((void*)__first2) value_type(_VSTD::move(*__last1));
+            ::new ((void*)__first2) value_type(_Ops::__iter_move(__last1));
             __d.template __incr<value_type>();
             ++__first2;
-            ::new ((void*)__first2) value_type(_VSTD::move(*__first1));
+            ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
         }
         else
         {
-            ::new ((void*)__first2) value_type(_VSTD::move(*__first1));
+            ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
             __d.template __incr<value_type>();
             ++__first2;
-            ::new ((void*)__first2) value_type(_VSTD::move(*__last1));
+            ::new ((void*)__first2) value_type(_Ops::__iter_move(__last1));
         }
         __h2.release();
         return;
     }
     if (__len <= 8)
     {
-        _VSTD::__insertion_sort_move<_Compare>(__first1, __last1, __first2, __comp);
+        std::__insertion_sort_move<_AlgPolicy, _Compare>(__first1, __last1, __first2, __comp);
         return;
     }
     typename iterator_traits<_RandomAccessIterator>::
diff erence_type __l2 = __len / 2;
     _RandomAccessIterator __m = __first1 + __l2;
-    _VSTD::__stable_sort<_Compare>(__first1, __m, __comp, __l2, __first2, __l2);
-    _VSTD::__stable_sort<_Compare>(__m, __last1, __comp, __len - __l2, __first2 + __l2, __len - __l2);
-    _VSTD::__merge_move_construct<_Compare>(__first1, __m, __m, __last1, __first2, __comp);
+    std::__stable_sort<_AlgPolicy, _Compare>(__first1, __m, __comp, __l2, __first2, __l2);
+    std::__stable_sort<_AlgPolicy, _Compare>(__m, __last1, __comp, __len - __l2, __first2 + __l2, __len - __l2);
+    std::__merge_move_construct<_AlgPolicy, _Compare>(__first1, __m, __m, __last1, __first2, __comp);
 }
 
 template <class _Tp>
@@ -153,7 +159,7 @@ struct __stable_sort_switch
     static const unsigned value = 128*is_trivially_copy_assignable<_Tp>::value;
 };
 
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
 void
 __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
               typename iterator_traits<_RandomAccessIterator>::
diff erence_type __len,
@@ -168,12 +174,12 @@ __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp
         return;
     case 2:
         if (__comp(*--__last, *__first))
-            swap(*__first, *__last);
+            _IterOps<_AlgPolicy>::iter_swap(__first, __last);
         return;
     }
     if (__len <= static_cast<
diff erence_type>(__stable_sort_switch<value_type>::value))
     {
-        _VSTD::__insertion_sort<_Compare>(__first, __last, __comp);
+        std::__insertion_sort<_AlgPolicy, _Compare>(__first, __last, __comp);
         return;
     }
     typename iterator_traits<_RandomAccessIterator>::
diff erence_type __l2 = __len / 2;
@@ -182,11 +188,12 @@ __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp
     {
         __destruct_n __d(0);
         unique_ptr<value_type, __destruct_n&> __h2(__buff, __d);
-        _VSTD::__stable_sort_move<_Compare>(__first, __m, __comp, __l2, __buff);
+        std::__stable_sort_move<_AlgPolicy, _Compare>(__first, __m, __comp, __l2, __buff);
         __d.__set(__l2, (value_type*)nullptr);
-        _VSTD::__stable_sort_move<_Compare>(__m, __last, __comp, __len - __l2, __buff + __l2);
+        std::__stable_sort_move<_AlgPolicy, _Compare>(__m, __last, __comp, __len - __l2, __buff + __l2);
         __d.__set(__len, (value_type*)nullptr);
-        _VSTD::__merge_move_assign<_Compare>(__buff, __buff + __l2, __buff + __l2, __buff + __len, __first, __comp);
+        std::__merge_move_assign<_AlgPolicy, _Compare>(
+            __buff, __buff + __l2, __buff + __l2, __buff + __len, __first, __comp);
 //         _VSTD::__merge<_Compare>(move_iterator<value_type*>(__buff),
 //                                  move_iterator<value_type*>(__buff + __l2),
 //                                  move_iterator<_RandomAccessIterator>(__buff + __l2),
@@ -194,12 +201,12 @@ __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp
 //                                  __first, __comp);
         return;
     }
-    _VSTD::__stable_sort<_Compare>(__first, __m, __comp, __l2, __buff, __buff_size);
-    _VSTD::__stable_sort<_Compare>(__m, __last, __comp, __len - __l2, __buff, __buff_size);
-    _VSTD::__inplace_merge<_Compare>(__first, __m, __last, __comp, __l2, __len - __l2, __buff, __buff_size);
+    std::__stable_sort<_AlgPolicy, _Compare>(__first, __m, __comp, __l2, __buff, __buff_size);
+    std::__stable_sort<_AlgPolicy, _Compare>(__m, __last, __comp, __len - __l2, __buff, __buff_size);
+    std::__inplace_merge<_AlgPolicy, _Compare>(__first, __m, __last, __comp, __l2, __len - __l2, __buff, __buff_size);
 }
 
-template <class _RandomAccessIterator, class _Compare>
+template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
 inline _LIBCPP_HIDE_FROM_ABI
 void __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
   using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
@@ -217,13 +224,13 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP
   }
 
   using _Comp_ref = typename __comp_ref_type<_Compare>::type;
-  std::__stable_sort<_Comp_ref>(__first, __last, __comp, __len, __buf.first, __buf.second);
+  std::__stable_sort<_AlgPolicy, _Comp_ref>(__first, __last, __comp, __len, __buf.first, __buf.second);
 }
 
 template <class _RandomAccessIterator, class _Compare>
 inline _LIBCPP_HIDE_FROM_ABI
 void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
-  std::__stable_sort_impl(std::move(__first), std::move(__last), __comp);
+  std::__stable_sort_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
 }
 
 template <class _RandomAccessIterator>

diff  --git a/libcxx/include/__debug_utils/randomize_range.h b/libcxx/include/__debug_utils/randomize_range.h
index fd5b9e588493..9ed22556c416 100644
--- a/libcxx/include/__debug_utils/randomize_range.h
+++ b/libcxx/include/__debug_utils/randomize_range.h
@@ -22,7 +22,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _Iterator>
+template <class _AlgPolicy, class _Iterator>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 void __debug_randomize_range(_Iterator __first, _Iterator __last) {
 #ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY
 #  ifdef _LIBCPP_CXX03_LANG
@@ -30,7 +30,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 void __debug_randomize_range
 #  endif
 
   if (!__libcpp_is_constant_evaluated())
-    std::shuffle(__first, __last, __libcpp_debug_randomizer());
+    std::__shuffle<_AlgPolicy>(__first, __last, __libcpp_debug_randomizer());
 #else
   (void)__first;
   (void)__last;

diff  --git a/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp b/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp
index 4913a7085bf6..7124e54c2285 100644
--- a/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp
@@ -34,7 +34,7 @@ std::vector<MyType> deterministic() {
   for (int i = 0; i < kSize; ++i) {
     v[i].value = (i % 2 ? i : kSize / 2 + i);
   }
-  std::__nth_element(v.begin(), v.begin() + kSize / 2, v.end(), std::less<MyType>());
+  std::__nth_element<std::_ClassicAlgPolicy>(v.begin(), v.begin() + kSize / 2, v.end(), std::less<MyType>());
   return v;
 }
 

diff  --git a/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp b/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp
index 8aa91bd551c1..99e0b0e127e9 100644
--- a/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp
@@ -34,7 +34,7 @@ std::vector<MyType> deterministic() {
   for (int i = 0; i < kSize; ++i) {
     v[i].value = (i % 2 ? 1 : kSize / 2 + i);
   }
-  std::__partial_sort(v.begin(), v.begin() + kSize / 2, v.end(), std::less<MyType>());
+  std::__partial_sort<std::_ClassicAlgPolicy>(v.begin(), v.begin() + kSize / 2, v.end(), std::less<MyType>());
   return v;
 }
 

diff  --git a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
new file mode 100644
index 000000000000..f6eaf15862e3
--- /dev/null
+++ b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
@@ -0,0 +1,170 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// <algorithm>
+//
+// Range algorithms should work with proxy iterators. For example, the implementations should use `iter_swap` (which is
+// a customization point) rather than plain `swap` (which might not work with certain valid iterators).
+
+#include <algorithm>
+
+#include <array>
+#include <concepts>
+#include <initializer_list>
+#include <iterator>
+#include <memory>
+#include <random>
+#include <ranges>
+
+#include "test_iterators.h"
+
+template <class Func, std::ranges::range Input, class ...Args>
+constexpr void test(Func&& func, Input& in, Args&& ...args) {
+  func(in.begin(), in.end(), std::forward<Args>(args)...);
+  func(in, std::forward<Args>(args)...);
+}
+
+template <class Func, std::ranges::range Range1, std::ranges::range Range2, class ...Args>
+constexpr void test(Func&& func, Range1& r1, Range2& r2, Args&& ...args) {
+  func(r1.begin(), r1.end(), r2.begin(), r2.end(), std::forward<Args>(args)...);
+  func(r1, r2, std::forward<Args>(args)...);
+}
+
+template <class Func, std::ranges::range Input, class ...Args>
+constexpr void test_mid(Func&& func, Input& in, std::ranges::iterator_t<Input> mid, Args&& ...args) {
+  func(in.begin(), mid, in.end(), std::forward<Args>(args)...);
+  func(in, mid, std::forward<Args>(args)...);
+}
+
+constexpr bool test_all() {
+  std::array input = {1, 2, 3};
+  ProxyRange in{input};
+  std::array input2 = {4, 5, 6};
+  ProxyRange in2{input2};
+
+  auto mid = in.begin() + 1;
+
+  std::array output = {4, 5, 6, 7, 8, 9};
+  ProxyIterator out{output.begin()};
+  //auto out2 = output.begin() + 1;
+
+  int num = 2;
+  Proxy<int&> x{num};
+  int count = 1;
+
+  auto unary_pred = [](const Proxy<int>& val) { return val.getData() > 0; };
+  //auto binary_pred = [](const Proxy<int>& lhs, const Proxy<int>& rhs) { return lhs.getData() == rhs.getData(); };
+  auto binary_func = [](const Proxy<int>& lhs, const Proxy<int>&) -> Proxy<int> { return lhs.getData(); };
+  //auto gen = [] { return Proxy<int>(42); };
+  //std::mt19937 rand_gen;
+
+  test(std::ranges::any_of, in, unary_pred);
+  test(std::ranges::all_of, in, unary_pred);
+  test(std::ranges::none_of, in, unary_pred);
+  test(std::ranges::find, in, x);
+  test(std::ranges::find_if, in, unary_pred);
+  test(std::ranges::find_if_not, in, unary_pred);
+  test(std::ranges::find_first_of, in, in2);
+  test(std::ranges::adjacent_find, in);
+  test(std::ranges::mismatch, in, in2);
+  test(std::ranges::equal, in, in2);
+  test(std::ranges::lexicographical_compare, in, in2);
+  //test(std::ranges::partition_point, unary_pred);
+  test(std::ranges::lower_bound, in, x);
+  test(std::ranges::upper_bound, in, x);
+  //test(std::ranges::equal_range, in, x);
+  test(std::ranges::binary_search, in, x);
+
+  test(std::ranges::min_element, in);
+  test(std::ranges::max_element, in);
+  test(std::ranges::minmax_element, in);
+  test(std::ranges::count, in, x);
+  test(std::ranges::count_if, in, unary_pred);
+  test(std::ranges::search, in, in2);
+  test(std::ranges::search_n, in, count, x);
+  test(std::ranges::find_end, in, in2);
+  test(std::ranges::is_partitioned, in, unary_pred);
+  test(std::ranges::is_sorted, in);
+  test(std::ranges::is_sorted_until, in);
+  //test(std::ranges::includes, in, in2);
+  //test(std::ranges::is_heap, in);
+  //test(std::ranges::is_heap_until, in);
+  //test(std::ranges::is_permutation, in, in2);
+  test(std::ranges::for_each, in, std::identity{});
+  std::ranges::for_each_n(in.begin(), count, std::identity{});
+  test(std::ranges::copy, in, out);
+  std::ranges::copy_n(in.begin(), count, out);
+  test(std::ranges::copy_if, in, out, unary_pred);
+  // TODO: uncomment `copy_backward` once https://reviews.llvm.org/D128864 lands.
+  //test(std::ranges::copy_backward, in, out);
+  test(std::ranges::move, in, out);
+  // TODO: uncomment `move_backward` once https://reviews.llvm.org/D128864 lands.
+  // test(std::ranges::move_backward, in, out);
+  test(std::ranges::fill, in, x);
+  std::ranges::fill_n(in.begin(), count, x);
+  test(std::ranges::transform, in, out, std::identity{});
+  test(std::ranges::transform, in, in2, out, binary_func);
+  //test(std::ranges::generate, in, gen);
+  //std::ranges::generate_n(in.begin(), count, gen);
+  //test(std::ranges::remove_copy, in, out, x);
+  //test(std::ranges::remove_copy_if, in, out, unary_pred);
+  test(std::ranges::replace, in, x, x);
+  test(std::ranges::replace_if, in, unary_pred, x);
+  //test(std::ranges::replace_copy, in, out, x, x);
+  //test(std::ranges::replace_copy_if, in, out, unary_pred, x);
+  //test(std::ranges::swap_ranges, in, in2);
+  test(std::ranges::reverse_copy, in, out);
+  test_mid(std::ranges::rotate_copy, in, mid, out);
+  //test(std::ranges::sample, in, out, count, rand_gen);
+  //test(std::ranges::unique_copy, in, out);
+  //test(std::ranges::partition_copy, in, out, out2, unary_pred);
+  //test_mid(std::ranges::partial_sort_copy, in, in2);
+  test(std::ranges::merge, in, in2, out);
+  test(std::ranges::set_
diff erence, in, in2, out);
+  test(std::ranges::set_intersection, in, in2, out);
+  test(std::ranges::set_symmetric_
diff erence, in, in2, out);
+  test(std::ranges::set_union, in, in2, out);
+  test(std::ranges::remove, in, x);
+  test(std::ranges::remove_if, in, unary_pred);
+  test(std::ranges::reverse, in);
+  //test_mid(std::ranges::rotate, in, mid);
+  //test(std::ranges::shuffle, in, rand_gen);
+  //test(std::ranges::unique, in);
+  //test(std::ranges::partition, in, binary_pred);
+  //if (!std::is_constant_evaluated())
+  //  test(std::ranges::stable_partition, in, binary_pred);
+  test(std::ranges::sort, in);
+  // TODO: `stable_sort` requires `ranges::rotate` to be implemented.
+  //if (!std::is_constant_evaluated())
+  //  test(std::ranges::stable_sort, in);
+  //test_mid(std::ranges::partial_sort, in, mid);
+  test_mid(std::ranges::nth_element, in, mid);
+  //if (!std::is_constant_evaluated())
+  //  test_mid(std::ranges::inplace_merge, in, mid);
+  test(std::ranges::make_heap, in);
+  test(std::ranges::push_heap, in);
+  test(std::ranges::pop_heap, in);
+  test(std::ranges::sort_heap, in);
+  //test(std::ranges::prev_permutation, in);
+  //test(std::ranges::next_permutation, in);
+
+  // The algorithms that work on uninitialized memory have constraints that prevent proxy iterators from being used with
+  // them.
+
+  return true;
+}
+
+int main(int, char**) {
+  test_all();
+  static_assert(test_all());
+
+  return 0;
+}

diff  --git a/libcxx/test/support/test.support/test_proxy.pass.cpp b/libcxx/test/support/test.support/test_proxy.pass.cpp
index 515423a3d269..29583865deae 100644
--- a/libcxx/test/support/test.support/test_proxy.pass.cpp
+++ b/libcxx/test/support/test.support/test_proxy.pass.cpp
@@ -58,10 +58,20 @@ constexpr void testProxy() {
     p4 = std::move(p3);
     assert(p4.data.get() == 8);
 
-    int i = 5, j = 6;
+    // `T` is a reference type.
+    int i = 5, j = 6, k = 7, x = 8;
     Proxy<int&> p5{i};
+    // `Other` is a prvalue.
     p5 = Proxy<int&>{j};
     assert(p5.data == 6);
+    // `Other` is a const lvalue.
+    const Proxy<int&> p_ref{k};
+    p5 = p_ref;
+    assert(p5.data == 7);
+    // `Other` is an xvalue.
+    Proxy<int&> px{x};
+    p5 = std::move(px);
+    assert(p5.data == 8);
   }
 
   // const assignment
@@ -87,6 +97,18 @@ constexpr void testProxy() {
     Proxy<int> p2{6};
     assert(p1 != p2);
     assert(p1 < p2);
+
+    // Comparing `T` and `T&`.
+    int i = 5, j = 6;
+    Proxy<int&> p_ref{i};
+    Proxy<const int&> p_cref{j};
+    assert(p1 == p_ref);
+    assert(p2 == p_cref);
+    assert(p_ref == p1);
+    assert(p_cref == p2);
+    assert(p_ref == p_ref);
+    assert(p_cref == p_cref);
+    assert(p_ref != p_cref);
   }
 }
 

diff  --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
index c222c93c524d..2f20e50e54c2 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -827,12 +827,12 @@ class Iterator {
 // ======================================================================
 // Proxy that can wrap a value or a reference. It simulates C++23's tuple
 // but simplified to just hold one argument.
-// Note that unlike tuple, this class deliberately doesn't have special handling 
-// of swap to cause a compilation error if it's used in an algorithm that relies 
+// Note that unlike tuple, this class deliberately doesn't have special handling
+// of swap to cause a compilation error if it's used in an algorithm that relies
 // on plain swap instead of ranges::iter_swap.
 // This class is useful for testing that if algorithms support proxy iterator
 // properly, i.e. calling ranges::iter_swap and ranges::iter_move instead of
-// plain swap and std::move 
+// plain swap and std::move
 template <class T>
 struct Proxy;
 
@@ -878,17 +878,40 @@ struct Proxy {
     return *this;
   }
 
+  // If `T` is a reference type, the implicitly-generated assignment operator will be deleted (and would take precedence
+  // over the templated `operator=` above because it's a better match).
+  constexpr Proxy& operator=(const Proxy& rhs) {
+    data = rhs.data;
+    return *this;
+  }
+
   // no specialised swap function that takes const Proxy& and no specialised const member swap
   // Calling swap(Proxy<T>{}, Proxy<T>{}) would fail (pass prvalues)
 
   // Compare operators are defined for the convenience of the tests
   friend constexpr bool operator==(const Proxy&, const Proxy&)
-    requires std::equality_comparable<T>
+    requires (std::equality_comparable<T> && !std::is_reference_v<T>)
   = default;
 
+  // Helps compare e.g. `Proxy<int>` and `Proxy<int&>`. Note that the default equality comparison operator is deleted
+  // when `T` is a reference type.
+  template <class U>
+  friend constexpr bool operator==(const Proxy& lhs, const Proxy<U>& rhs)
+    requires std::equality_comparable_with<std::decay_t<T>, std::decay_t<U>> {
+    return lhs.data == rhs.data;
+  }
+
   friend constexpr auto operator<=>(const Proxy&, const Proxy&)
-    requires std::three_way_comparable<T>
+    requires (std::three_way_comparable<T> && !std::is_reference_v<T>)
   = default;
+
+  // Helps compare e.g. `Proxy<int>` and `Proxy<int&>`. Note that the default 3-way comparison operator is deleted when
+  // `T` is a reference type.
+  template <class U>
+  friend constexpr auto operator<=>(const Proxy& lhs, const Proxy<U>& rhs)
+    requires std::three_way_comparable_with<std::decay_t<T>, std::decay_t<U>> {
+    return lhs.data <=> rhs.data;
+  }
 };
 
 // This is to make ProxyIterator model `std::indirectly_readable`
@@ -920,7 +943,7 @@ struct ProxyIteratorBase {};
 template <class Base>
   requires std::derived_from<
       typename std::iterator_traits<Base>::iterator_category,
-      std::input_iterator_tag> 
+      std::input_iterator_tag>
 struct ProxyIteratorBase<Base> {
   using iterator_category = std::input_iterator_tag;
 };
@@ -951,8 +974,8 @@ struct ProxyIterator : ProxyIteratorBase<Base> {
   = default;
 
   constexpr ProxyIterator(Base base) : base_{std::move(base)} {}
-  
-  template <class T> 
+
+  template <class T>
     requires std::constructible_from<Base, T&&>
   constexpr ProxyIterator(T&& t) : base_{std::forward<T>(t)} {}
 
@@ -1076,6 +1099,7 @@ struct ProxyIterator : ProxyIteratorBase<Base> {
 
 static_assert(std::indirectly_readable<ProxyIterator<int*>>);
 static_assert(std::indirectly_writable<ProxyIterator<int*>, Proxy<int>>);
+static_assert(std::indirectly_writable<ProxyIterator<int*>, Proxy<int&>>);
 
 template <class BaseSent>
 struct ProxySentinel {


        


More information about the libcxx-commits mailing list