[libcxx-commits] [libcxx] 005916d - [libc++][ranges]Refactor `copy{, _backward}` and `move{, _backward}`

Konstantin Varlamov via libcxx-commits libcxx-commits at lists.llvm.org
Sat Oct 1 17:35:47 PDT 2022


Author: Konstantin Varlamov
Date: 2022-10-01T17:35:12-07:00
New Revision: 005916de58f73aa5c4264c084ba7b0e21040d88f

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

LOG: [libc++][ranges]Refactor `copy{,_backward}` and `move{,_backward}`

Instead of using `reverse_iterator`, share the optimization between the 4 algorithms. The key observation here that `memmove` applies to both `copy` and `move` identically, and to their `_backward` versions very similarly. All algorithms now follow the same pattern along the lines of:
```
if constexpr (can_memmove<InIter, OutIter>) {
  memmove(first, last, out);
} else {
  naive_implementation(first, last, out);
}
```
A follow-up will delete `unconstrained_reverse_iterator`.

This patch removes duplication and divergence between `std::copy`, `std::move` and `std::move_backward`. It also improves testing:
- the test for whether the optimization is used only applied to `std::copy` and, more importantly, was essentially a no-op because it would still pass if the optimization was not used;
- there were no tests to make sure the optimization is not used when the effect would be visible.

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

Added: 
    libcxx/include/__algorithm/copy_move_common.h
    libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_nontrivial.pass.cpp
    libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_trivial.pass.cpp

Modified: 
    libcxx/include/CMakeLists.txt
    libcxx/include/__algorithm/copy.h
    libcxx/include/__algorithm/copy_backward.h
    libcxx/include/__algorithm/move.h
    libcxx/include/__algorithm/move_backward.h
    libcxx/include/__algorithm/ranges_copy.h
    libcxx/include/__algorithm/ranges_copy_backward.h
    libcxx/include/__algorithm/ranges_copy_n.h
    libcxx/include/__algorithm/ranges_move.h
    libcxx/include/__algorithm/ranges_move_backward.h
    libcxx/include/__algorithm/ranges_set_difference.h
    libcxx/include/__algorithm/ranges_set_symmetric_difference.h
    libcxx/include/__algorithm/ranges_set_union.h
    libcxx/include/__algorithm/rotate.h
    libcxx/include/__algorithm/set_difference.h
    libcxx/include/__algorithm/set_symmetric_difference.h
    libcxx/include/__algorithm/set_union.h
    libcxx/include/__iterator/reverse_iterator.h
    libcxx/include/algorithm
    libcxx/include/module.modulemap.in
    libcxx/include/valarray
    libcxx/test/libcxx/private_headers.verify.cpp
    libcxx/test/libcxx/transitive_includes/cxx2b.csv
    libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp
    libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp
    libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp
    libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp

Removed: 
    libcxx/test/libcxx/algorithms/alg.modifying.operations/copy.pass.cpp


################################################################################
diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 8e79e106a5a92..2cd4a9c7d9924 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -9,6 +9,7 @@ set(files
   __algorithm/copy.h
   __algorithm/copy_backward.h
   __algorithm/copy_if.h
+  __algorithm/copy_move_common.h
   __algorithm/copy_n.h
   __algorithm/count.h
   __algorithm/count_if.h

diff  --git a/libcxx/include/__algorithm/copy.h b/libcxx/include/__algorithm/copy.h
index d6a46f69523a8..5a887928e1162 100644
--- a/libcxx/include/__algorithm/copy.h
+++ b/libcxx/include/__algorithm/copy.h
@@ -9,15 +9,11 @@
 #ifndef _LIBCPP___ALGORITHM_COPY_H
 #define _LIBCPP___ALGORITHM_COPY_H
 
-#include <__algorithm/unwrap_iter.h>
-#include <__algorithm/unwrap_range.h>
+#include <__algorithm/copy_move_common.h>
+#include <__algorithm/iterator_operations.h>
 #include <__config>
-#include <__iterator/iterator_traits.h>
-#include <__iterator/reverse_iterator.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
-#include <cstring>
-#include <type_traits>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -25,82 +21,42 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-// copy
+struct __copy_loop {
+  template <class _InIter, class _Sent, class _OutIter>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
+  operator()(_InIter __first, _Sent __last, _OutIter __result) const {
+    while (__first != __last) {
+      *__result = *__first;
+      ++__first;
+      ++__result;
+    }
 
-template <class _InIter, class _Sent, class _OutIter>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
-pair<_InIter, _OutIter> __copy_impl(_InIter __first, _Sent __last, _OutIter __result) {
-  while (__first != __last) {
-    *__result = *__first;
-    ++__first;
-    ++__result;
+    return std::make_pair(std::move(__first), std::move(__result));
   }
-  return pair<_InIter, _OutIter>(std::move(__first), std::move(__result));
-}
+};
 
-template <class _InValueT,
-          class _OutValueT,
-          class = __enable_if_t<is_same<__remove_const_t<_InValueT>, _OutValueT>::value
-                             && is_trivially_copy_assignable<_OutValueT>::value> >
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
-pair<_InValueT*, _OutValueT*> __copy_impl(_InValueT* __first, _InValueT* __last, _OutValueT* __result) {
-  if (__libcpp_is_constant_evaluated()
-// TODO: Remove this once GCC supports __builtin_memmove during constant evaluation
-#ifndef _LIBCPP_COMPILER_GCC
-      && !is_trivially_copyable<_InValueT>::value
-#endif
-     )
-    return std::__copy_impl<_InValueT*, _InValueT*, _OutValueT*>(__first, __last, __result);
-  const size_t __n = static_cast<size_t>(__last - __first);
-  if (__n > 0)
-    ::__builtin_memmove(__result, __first, __n * sizeof(_OutValueT));
-  return std::make_pair(__first + __n, __result + __n);
-}
+struct __copy_trivial {
+  // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer.
+  template <class _In, class _Out, __enable_if_t< is_trivially_assignable<_Out&, _In&>::value, int > = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
+  operator()(_In* __first, _In* __last, _Out* __result) const {
+    return std::__copy_trivial_impl(__first, __last, __result);
+  }
+};
 
-template <class _InIter, class _OutIter,
-          __enable_if_t<is_same<__remove_const_t<__iter_value_type<_InIter> >, __iter_value_type<_OutIter> >::value
-                      && __is_cpp17_contiguous_iterator<typename _InIter::iterator_type>::value
-                      && __is_cpp17_contiguous_iterator<typename _OutIter::iterator_type>::value
-                      && is_trivially_copy_assignable<__iter_value_type<_OutIter> >::value
-                      && __is_reverse_iterator<_InIter>::value
-                      && __is_reverse_iterator<_OutIter>::value, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
+template <class _AlgPolicy, class _InIter, class _Sent, class _OutIter>
 pair<_InIter, _OutIter>
-__copy_impl(_InIter __first, _InIter __last, _OutIter __result) {
-  auto __first_base = std::__unwrap_iter(__first.base());
-  auto __last_base = std::__unwrap_iter(__last.base());
-  auto __result_base = std::__unwrap_iter(__result.base());
-  auto __result_first = __result_base - (__first_base - __last_base);
-  std::__copy_impl(__last_base, __first_base, __result_first);
-  return std::make_pair(__last, _OutIter(std::__rewrap_iter(__result.base(), __result_first)));
-}
-
-template <class _InIter, class _Sent, class _OutIter,
-          __enable_if_t<!(is_copy_constructible<_InIter>::value
-                       && is_copy_constructible<_Sent>::value
-                       && is_copy_constructible<_OutIter>::value), int> = 0 >
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
-pair<_InIter, _OutIter> __copy(_InIter __first, _Sent __last, _OutIter __result) {
-  return std::__copy_impl(std::move(__first), std::move(__last), std::move(__result));
-}
-
-template <class _InIter, class _Sent, class _OutIter,
-          __enable_if_t<is_copy_constructible<_InIter>::value
-                     && is_copy_constructible<_Sent>::value
-                     && is_copy_constructible<_OutIter>::value, int> = 0>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
-pair<_InIter, _OutIter> __copy(_InIter __first, _Sent __last, _OutIter __result) {
-  auto __range = std::__unwrap_range(__first, __last);
-  auto __ret   = std::__copy_impl(std::move(__range.first), std::move(__range.second), std::__unwrap_iter(__result));
-  return std::make_pair(
-      std::__rewrap_range<_Sent>(__first, __ret.first), std::__rewrap_iter(__result, __ret.second));
+__copy(_InIter __first, _Sent __last, _OutIter __result) {
+  return std::__dispatch_copy_or_move<_AlgPolicy, __copy_loop, __copy_trivial>(
+      std::move(__first), std::move(__last), std::move(__result));
 }
 
 template <class _InputIterator, class _OutputIterator>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
 _OutputIterator
 copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) {
-  return std::__copy(__first, __last, __result).second;
+  return std::__copy<_ClassicAlgPolicy>(__first, __last, __result).second;
 }
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/__algorithm/copy_backward.h b/libcxx/include/__algorithm/copy_backward.h
index 1db4f1e2d53ed..f8f0f4ff84523 100644
--- a/libcxx/include/__algorithm/copy_backward.h
+++ b/libcxx/include/__algorithm/copy_backward.h
@@ -9,19 +9,11 @@
 #ifndef _LIBCPP___ALGORITHM_COPY_BACKWARD_H
 #define _LIBCPP___ALGORITHM_COPY_BACKWARD_H
 
-#include <__algorithm/copy.h>
+#include <__algorithm/copy_move_common.h>
 #include <__algorithm/iterator_operations.h>
-#include <__algorithm/ranges_copy.h>
-#include <__algorithm/unwrap_iter.h>
-#include <__concepts/same_as.h>
 #include <__config>
-#include <__iterator/iterator_traits.h>
-#include <__iterator/reverse_iterator.h>
-#include <__ranges/subrange.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
-#include <cstring>
-#include <type_traits>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -29,32 +21,50 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _AlgPolicy, class _InputIterator, class _OutputIterator,
-          __enable_if_t<is_same<_AlgPolicy, _ClassicAlgPolicy>::value, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InputIterator, _OutputIterator>
-__copy_backward(_InputIterator __first, _InputIterator __last, _OutputIterator __result) {
-  auto __ret = std::__copy(
-      __unconstrained_reverse_iterator<_InputIterator>(__last),
-      __unconstrained_reverse_iterator<_InputIterator>(__first),
-      __unconstrained_reverse_iterator<_OutputIterator>(__result));
-  return pair<_InputIterator, _OutputIterator>(__ret.first.base(), __ret.second.base());
-}
+template <class _AlgPolicy>
+struct __copy_backward_loop {
+  template <class _InIter, class _Sent, class _OutIter>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
+  operator()(_InIter __first, _Sent __last, _OutIter __result) const {
+    auto __last_iter          = _IterOps<_AlgPolicy>::next(__first, __last);
+    auto __original_last_iter = __last_iter;
+
+    while (__first != __last_iter) {
+      *--__result = *--__last_iter;
+    }
+
+    return std::make_pair(std::move(__original_last_iter), std::move(__result));
+  }
+};
 
-#if _LIBCPP_STD_VER > 17
-template <class _AlgPolicy, class _Iter1, class _Sent1, class _Iter2,
-          __enable_if_t<is_same<_AlgPolicy, _RangeAlgPolicy>::value, int> = 0>
-_LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter1, _Iter2> __copy_backward(_Iter1 __first, _Sent1 __last, _Iter2 __result) {
-  auto __last_iter     = _IterOps<_AlgPolicy>::next(__first, std::move(__last));
-  auto __reverse_range = std::__reverse_range(std::ranges::subrange(std::move(__first), __last_iter));
-  auto __ret           = ranges::copy(std::move(__reverse_range), std::make_reverse_iterator(__result));
-  return std::make_pair(__last_iter, __ret.out.base());
+struct __copy_backward_trivial {
+  // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer.
+  template <class _In, class _Out, __enable_if_t< is_trivially_assignable<_Out&, _In&>::value, int > = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
+  operator()(_In* __first, _In* __last, _Out* __result) const {
+    return std::__copy_backward_trivial_impl(__first, __last, __result);
+  }
+};
+
+template <class _AlgPolicy, class _BidirectionalIterator1, class _Sentinel, class _BidirectionalIterator2>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+pair<_BidirectionalIterator1, _BidirectionalIterator2>
+__copy_backward(_BidirectionalIterator1 __first, _Sentinel __last, _BidirectionalIterator2 __result) {
+  return std::__dispatch_copy_or_move<_AlgPolicy, __copy_backward_loop<_AlgPolicy>, __copy_backward_trivial>(
+      std::move(__first), std::move(__last), std::move(__result));
 }
-#endif // _LIBCPP_STD_VER > 17
 
 template <class _BidirectionalIterator1, class _BidirectionalIterator2>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _BidirectionalIterator2
-copy_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, _BidirectionalIterator2 __result) {
-  return std::__copy_backward<_ClassicAlgPolicy>(__first, __last, __result).second;
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+_BidirectionalIterator2
+copy_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last,
+              _BidirectionalIterator2 __result)
+{
+  static_assert(std::is_copy_constructible<_BidirectionalIterator1>::value &&
+                std::is_copy_constructible<_BidirectionalIterator1>::value, "Iterators must be copy constructible.");
+
+  return std::__copy_backward<_ClassicAlgPolicy>(
+      std::move(__first), std::move(__last), std::move(__result)).second;
 }
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/__algorithm/copy_move_common.h b/libcxx/include/__algorithm/copy_move_common.h
new file mode 100644
index 0000000000000..7f8162b42f2a3
--- /dev/null
+++ b/libcxx/include/__algorithm/copy_move_common.h
@@ -0,0 +1,137 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_COPY_MOVE_COMMON_H
+#define _LIBCPP___ALGORITHM_COPY_MOVE_COMMON_H
+
+#include <__algorithm/iterator_operations.h>
+#include <__algorithm/unwrap_iter.h>
+#include <__algorithm/unwrap_range.h>
+#include <__config>
+#include <__iterator/iterator_traits.h>
+#include <__memory/pointer_traits.h>
+#include <__type_traits/enable_if.h>
+#include <__type_traits/integral_constant.h>
+#include <__type_traits/is_constant_evaluated.h>
+#include <__type_traits/is_copy_constructible.h>
+#include <__type_traits/is_trivially_assignable.h>
+#include <__utility/move.h>
+#include <__utility/pair.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// `memmove` algorithms implementation.
+
+template <class _In, class _Out>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
+__copy_trivial_impl(_In* __first, _In* __last, _Out* __result) {
+  const size_t __n = static_cast<size_t>(__last - __first);
+  ::__builtin_memmove(__result, __first, __n * sizeof(_Out));
+
+  return std::make_pair(__last, __result + __n);
+}
+
+template <class _In, class _Out>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
+__copy_backward_trivial_impl(_In* __first, _In* __last, _Out* __result) {
+  const size_t __n = static_cast<size_t>(__last - __first);
+  __result -= __n;
+
+  ::__builtin_memmove(__result, __first, __n * sizeof(_Out));
+
+  return std::make_pair(__last, __result);
+}
+
+// Iterator unwrapping and dispatching to the correct overload.
+
+template <class _F1, class _F2>
+struct __overload : _F1, _F2 {
+  using _F1::operator();
+  using _F2::operator();
+};
+
+template <class _InIter, class _Sent, class _OutIter, class = void>
+struct __can_rewrap : false_type {};
+
+template <class _InIter, class _Sent, class _OutIter>
+struct __can_rewrap<_InIter,
+                    _Sent,
+                    _OutIter,
+                    // Note that sentinels are always copy-constructible.
+                    __enable_if_t< is_copy_constructible<_InIter>::value &&
+                                   is_copy_constructible<_OutIter>::value > > : true_type {};
+
+template <class _Algorithm,
+          class _InIter,
+          class _Sent,
+          class _OutIter,
+          __enable_if_t<__can_rewrap<_InIter, _Sent, _OutIter>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 pair<_InIter, _OutIter>
+__unwrap_and_dispatch(_InIter __first, _Sent __last, _OutIter __out_first) {
+  auto __range  = std::__unwrap_range(__first, std::move(__last));
+  auto __result = _Algorithm()(std::move(__range.first), std::move(__range.second), std::__unwrap_iter(__out_first));
+  return std::make_pair(std::__rewrap_range<_Sent>(std::move(__first), std::move(__result.first)),
+                                 std::__rewrap_iter(std::move(__out_first), std::move(__result.second)));
+}
+
+template <class _Algorithm,
+          class _InIter,
+          class _Sent,
+          class _OutIter,
+          __enable_if_t<!__can_rewrap<_InIter, _Sent, _OutIter>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 pair<_InIter, _OutIter>
+__unwrap_and_dispatch(_InIter __first, _Sent __last, _OutIter __out_first) {
+  return _Algorithm()(std::move(__first), std::move(__last), std::move(__out_first));
+}
+
+template <class _IterOps, class _InValue, class _OutIter, class = void>
+struct __can_copy_without_conversion : false_type {};
+
+template <class _IterOps, class _InValue, class _OutIter>
+struct __can_copy_without_conversion<
+    _IterOps,
+    _InValue,
+    _OutIter,
+    __enable_if_t<is_same<_InValue, typename _IterOps::template __value_type<_OutIter> >::value> > : true_type {};
+
+template <class _AlgPolicy,
+          class _NaiveAlgorithm,
+          class _OptimizedAlgorithm,
+          class _InIter,
+          class _Sent,
+          class _OutIter>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 pair<_InIter, _OutIter>
+__dispatch_copy_or_move(_InIter __first, _Sent __last, _OutIter __out_first) {
+#ifdef _LIBCPP_COMPILER_GCC
+  // GCC doesn't support `__builtin_memmove` during constant evaluation.
+  if (__libcpp_is_constant_evaluated()) {
+    return std::__unwrap_and_dispatch<_NaiveAlgorithm>(std::move(__first), std::move(__last), std::move(__out_first));
+  }
+#else
+  // In Clang, `__builtin_memmove` only supports fully trivially copyable types (just having trivial copy assignment is
+  // insufficient). Also, conversions are not supported.
+  if (__libcpp_is_constant_evaluated()) {
+    using _InValue = typename _IterOps<_AlgPolicy>::template __value_type<_InIter>;
+    if (!is_trivially_copyable<_InValue>::value ||
+        !__can_copy_without_conversion<_IterOps<_AlgPolicy>, _InValue, _OutIter>::value) {
+      return std::__unwrap_and_dispatch<_NaiveAlgorithm>(std::move(__first), std::move(__last), std::move(__out_first));
+    }
+  }
+#endif // _LIBCPP_COMPILER_GCC
+
+  using _Algorithm = __overload<_NaiveAlgorithm, _OptimizedAlgorithm>;
+  return std::__unwrap_and_dispatch<_Algorithm>(std::move(__first), std::move(__last), std::move(__out_first));
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___ALGORITHM_COPY_MOVE_COMMON_H

diff  --git a/libcxx/include/__algorithm/move.h b/libcxx/include/__algorithm/move.h
index e2f8b22800dbc..2961314f08bcd 100644
--- a/libcxx/include/__algorithm/move.h
+++ b/libcxx/include/__algorithm/move.h
@@ -9,15 +9,11 @@
 #ifndef _LIBCPP___ALGORITHM_MOVE_H
 #define _LIBCPP___ALGORITHM_MOVE_H
 
+#include <__algorithm/copy_move_common.h>
 #include <__algorithm/iterator_operations.h>
-#include <__algorithm/unwrap_iter.h>
 #include <__config>
-#include <__iterator/iterator_traits.h>
-#include <__iterator/reverse_iterator.h>
 #include <__utility/move.h>
 #include <__utility/pair.h>
-#include <cstring>
-#include <type_traits>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -25,93 +21,45 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-// move
-
-template <class _AlgPolicy, class _InIter, class _Sent, class _OutIter>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX17
-pair<_InIter, _OutIter> __move_impl(_InIter __first, _Sent __last, _OutIter __result) {
-  while (__first != __last) {
-    *__result = _IterOps<_AlgPolicy>::__iter_move(__first);
-    ++__first;
-    ++__result;
+template <class _AlgPolicy>
+struct __move_loop {
+  template <class _InIter, class _Sent, class _OutIter>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
+  operator()(_InIter __first, _Sent __last, _OutIter __result) const {
+    while (__first != __last) {
+      *__result = _IterOps<_AlgPolicy>::__iter_move(__first);
+      ++__first;
+      ++__result;
+    }
+    return std::make_pair(std::move(__first), std::move(__result));
   }
-  return std::make_pair(std::move(__first), std::move(__result));
-}
-
-template <class _AlgPolicy,
-          class _InType,
-          class _OutType,
-          class = __enable_if_t<is_same<__remove_const_t<_InType>, _OutType>::value
-                             && is_trivially_move_assignable<_OutType>::value> >
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
-pair<_InType*, _OutType*> __move_impl(_InType* __first, _InType* __last, _OutType* __result) {
-  if (__libcpp_is_constant_evaluated()
-// TODO: Remove this once GCC supports __builtin_memmove during constant evaluation
-#ifndef _LIBCPP_COMPILER_GCC
-   && !is_trivially_copyable<_InType>::value
-#endif
-     )
-    return std::__move_impl<_AlgPolicy, _InType*, _InType*, _OutType*>(__first, __last, __result);
-  const size_t __n = static_cast<size_t>(__last - __first);
-  ::__builtin_memmove(__result, __first, __n * sizeof(_OutType));
-  return std::make_pair(__first + __n, __result + __n);
-}
-
-template <class>
-struct __is_trivially_move_assignable_unwrapped_impl : false_type {};
-
-template <class _Type>
-struct __is_trivially_move_assignable_unwrapped_impl<_Type*> : is_trivially_move_assignable<_Type> {};
-
-template <class _Iter>
-struct __is_trivially_move_assignable_unwrapped
-    : __is_trivially_move_assignable_unwrapped_impl<decltype(std::__unwrap_iter<_Iter>(std::declval<_Iter>()))> {};
-
-template <class _AlgPolicy,
-          class _InIter,
-          class _OutIter,
-          __enable_if_t<is_same<__remove_const_t<typename iterator_traits<_InIter>::value_type>,
-                                typename iterator_traits<_OutIter>::value_type>::value
-                     && __is_cpp17_contiguous_iterator<_InIter>::value
-                     && __is_cpp17_contiguous_iterator<_OutIter>::value
-                     && is_trivially_move_assignable<__iter_value_type<_OutIter> >::value, int> = 0>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17
-pair<reverse_iterator<_InIter>, reverse_iterator<_OutIter> >
-__move_impl(reverse_iterator<_InIter> __first,
-            reverse_iterator<_InIter> __last,
-            reverse_iterator<_OutIter> __result) {
-  auto __first_base = std::__unwrap_iter(__first.base());
-  auto __last_base = std::__unwrap_iter(__last.base());
-  auto __result_base = std::__unwrap_iter(__result.base());
-  auto __result_first = __result_base - (__first_base - __last_base);
-  std::__move_impl<_AlgPolicy>(__last_base, __first_base, __result_first);
-  return std::make_pair(__last, reverse_iterator<_OutIter>(std::__rewrap_iter(__result.base(), __result_first)));
-}
-
-template <class _AlgPolicy, class _InIter, class _Sent, class _OutIter>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
-__enable_if_t<is_copy_constructible<_InIter>::value
-           && is_copy_constructible<_Sent>::value
-           && is_copy_constructible<_OutIter>::value, pair<_InIter, _OutIter> >
-__move(_InIter __first, _Sent __last, _OutIter __result) {
-  auto __ret = std::__move_impl<_AlgPolicy>(
-      std::__unwrap_iter(__first), std::__unwrap_iter(__last), std::__unwrap_iter(__result));
-  return std::make_pair(std::__rewrap_iter(__first, __ret.first), std::__rewrap_iter(__result, __ret.second));
-}
+};
+
+struct __move_trivial {
+  // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer.
+  template <class _In, class _Out, __enable_if_t< is_trivially_assignable<_Out&, _In&&>::value, int > = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
+  operator()(_In* __first, _In* __last, _Out* __result) const {
+    return std::__copy_trivial_impl(__first, __last, __result);
+  }
+};
 
 template <class _AlgPolicy, class _InIter, class _Sent, class _OutIter>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
-__enable_if_t<!is_copy_constructible<_InIter>::value
-           || !is_copy_constructible<_Sent>::value
-           || !is_copy_constructible<_OutIter>::value, pair<_InIter, _OutIter> >
+pair<_InIter, _OutIter>
 __move(_InIter __first, _Sent __last, _OutIter __result) {
-  return std::__move_impl<_AlgPolicy>(std::move(__first), std::move(__last), std::move(__result));
+  return std::__dispatch_copy_or_move<_AlgPolicy, __move_loop<_AlgPolicy>, __move_trivial>(
+      std::move(__first), std::move(__last), std::move(__result));
 }
 
 template <class _InputIterator, class _OutputIterator>
 inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
 _OutputIterator move(_InputIterator __first, _InputIterator __last, _OutputIterator __result) {
-  return std::__move<_ClassicAlgPolicy>(__first, __last, __result).second;
+  static_assert(is_copy_constructible<_InputIterator>::value, "Iterators has to be copy constructible.");
+  static_assert(is_copy_constructible<_OutputIterator>::value, "The output iterator has to be copy constructible.");
+
+  return std::__move<_ClassicAlgPolicy>(
+      std::move(__first), std::move(__last), std::move(__result)).second;
 }
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/__algorithm/move_backward.h b/libcxx/include/__algorithm/move_backward.h
index 02aae26fc4499..312df3d335095 100644
--- a/libcxx/include/__algorithm/move_backward.h
+++ b/libcxx/include/__algorithm/move_backward.h
@@ -9,12 +9,11 @@
 #ifndef _LIBCPP___ALGORITHM_MOVE_BACKWARD_H
 #define _LIBCPP___ALGORITHM_MOVE_BACKWARD_H
 
+#include <__algorithm/copy_move_common.h>
 #include <__algorithm/iterator_operations.h>
-#include <__algorithm/unwrap_iter.h>
 #include <__config>
 #include <__utility/move.h>
-#include <cstring>
-#include <type_traits>
+#include <__utility/pair.h>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #  pragma GCC system_header
@@ -22,57 +21,40 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template <class _AlgPolicy, class _InputIterator, class _OutputIterator>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX17
-_OutputIterator
-__move_backward_constexpr(_InputIterator __first, _InputIterator __last, _OutputIterator __result)
-{
-    while (__first != __last)
-        *--__result = _IterOps<_AlgPolicy>::__iter_move(--__last);
-    return __result;
-}
+template <class _AlgPolicy>
+struct __move_backward_loop {
+  template <class _InIter, class _Sent, class _OutIter>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter>
+  operator()(_InIter __first, _Sent __last, _OutIter __result) const {
+    auto __last_iter          = _IterOps<_AlgPolicy>::next(__first, __last);
+    auto __original_last_iter = __last_iter;
 
-template <class _AlgPolicy, class _InputIterator, class _OutputIterator>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX17
-_OutputIterator
-__move_backward_impl(_InputIterator __first, _InputIterator __last, _OutputIterator __result)
-{
-    return _VSTD::__move_backward_constexpr<_AlgPolicy>(__first, __last, __result);
-}
-
-template <class _AlgPolicy, class _Tp, class _Up>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX17
-typename enable_if
-<
-    is_same<__remove_const_t<_Tp>, _Up>::value &&
-    is_trivially_move_assignable<_Up>::value,
-    _Up*
->::type
-__move_backward_impl(_Tp* __first, _Tp* __last, _Up* __result)
-{
-    const size_t __n = static_cast<size_t>(__last - __first);
-    if (__n > 0)
-    {
-        __result -= __n;
-        _VSTD::memmove(__result, __first, __n * sizeof(_Up));
+    while (__first != __last_iter) {
+      *--__result = _IterOps<_AlgPolicy>::__iter_move(--__last_iter);
     }
-    return __result;
-}
 
-template <class _AlgPolicy, class _BidirectionalIterator1, class _BidirectionalIterator2>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
-_BidirectionalIterator2
-__move_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last,
-                _BidirectionalIterator2 __result)
-{
-    if (__libcpp_is_constant_evaluated()) {
-        return _VSTD::__move_backward_constexpr<_AlgPolicy>(__first, __last, __result);
-    } else {
-        return _VSTD::__rewrap_iter(__result,
-            _VSTD::__move_backward_impl<_AlgPolicy>(_VSTD::__unwrap_iter(__first),
-                                                    _VSTD::__unwrap_iter(__last),
-                                                    _VSTD::__unwrap_iter(__result)));
-    }
+    return std::make_pair(std::move(__original_last_iter), std::move(__result));
+  }
+};
+
+struct __move_backward_trivial {
+  // At this point, the iterators have been unwrapped so any `contiguous_iterator` has been unwrapped to a pointer.
+  template <class _In, class _Out, __enable_if_t< is_trivially_assignable<_Out&, _In&&>::value, int > = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
+  operator()(_In* __first, _In* __last, _Out* __result) const {
+    return std::__copy_backward_trivial_impl(__first, __last, __result);
+  }
+};
+
+template <class _AlgPolicy, class _BidirectionalIterator1, class _Sentinel, class _BidirectionalIterator2>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
+pair<_BidirectionalIterator1, _BidirectionalIterator2>
+__move_backward(_BidirectionalIterator1 __first, _Sentinel __last, _BidirectionalIterator2 __result) {
+  static_assert(std::is_copy_constructible<_BidirectionalIterator1>::value &&
+                std::is_copy_constructible<_BidirectionalIterator1>::value, "Iterators must be copy constructible.");
+
+  return std::__dispatch_copy_or_move<_AlgPolicy, __move_backward_loop<_AlgPolicy>, __move_backward_trivial>(
+      std::move(__first), std::move(__last), std::move(__result));
 }
 
 template <class _BidirectionalIterator1, class _BidirectionalIterator2>
@@ -81,7 +63,8 @@ _BidirectionalIterator2
 move_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last,
               _BidirectionalIterator2 __result)
 {
-  return std::__move_backward<_ClassicAlgPolicy>(std::move(__first), std::move(__last), std::move(__result));
+  return std::__move_backward<_ClassicAlgPolicy>(
+      std::move(__first), std::move(__last), std::move(__result)).second;
 }
 
 _LIBCPP_END_NAMESPACE_STD

diff  --git a/libcxx/include/__algorithm/ranges_copy.h b/libcxx/include/__algorithm/ranges_copy.h
index 87a6a1e1361f1..bb02c84efbdb4 100644
--- a/libcxx/include/__algorithm/ranges_copy.h
+++ b/libcxx/include/__algorithm/ranges_copy.h
@@ -11,6 +11,7 @@
 
 #include <__algorithm/copy.h>
 #include <__algorithm/in_out_result.h>
+#include <__algorithm/iterator_operations.h>
 #include <__config>
 #include <__functional/identity.h>
 #include <__iterator/concepts.h>
@@ -40,7 +41,7 @@ struct __fn {
     requires indirectly_copyable<_InIter, _OutIter>
   _LIBCPP_HIDE_FROM_ABI constexpr
   copy_result<_InIter, _OutIter> operator()(_InIter __first, _Sent __last, _OutIter __result) const {
-    auto __ret = std::__copy(std::move(__first), std::move(__last), std::move(__result));
+    auto __ret = std::__copy<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__result));
     return {std::move(__ret.first), std::move(__ret.second)};
   }
 
@@ -48,7 +49,7 @@ struct __fn {
     requires indirectly_copyable<iterator_t<_Range>, _OutIter>
   _LIBCPP_HIDE_FROM_ABI constexpr
   copy_result<borrowed_iterator_t<_Range>, _OutIter> operator()(_Range&& __r, _OutIter __result) const {
-    auto __ret = std::__copy(ranges::begin(__r), ranges::end(__r), std::move(__result));
+    auto __ret = std::__copy<_RangeAlgPolicy>(ranges::begin(__r), ranges::end(__r), std::move(__result));
     return {std::move(__ret.first), std::move(__ret.second)};
   }
 };

diff  --git a/libcxx/include/__algorithm/ranges_copy_backward.h b/libcxx/include/__algorithm/ranges_copy_backward.h
index 67977201fa66c..f41af66f39fbd 100644
--- a/libcxx/include/__algorithm/ranges_copy_backward.h
+++ b/libcxx/include/__algorithm/ranges_copy_backward.h
@@ -14,7 +14,6 @@
 #include <__algorithm/iterator_operations.h>
 #include <__config>
 #include <__iterator/concepts.h>
-#include <__iterator/reverse_iterator.h>
 #include <__ranges/access.h>
 #include <__ranges/concepts.h>
 #include <__ranges/dangling.h>

diff  --git a/libcxx/include/__algorithm/ranges_copy_n.h b/libcxx/include/__algorithm/ranges_copy_n.h
index 38a0a308d30ac..04bb80b3ba1ae 100644
--- a/libcxx/include/__algorithm/ranges_copy_n.h
+++ b/libcxx/include/__algorithm/ranges_copy_n.h
@@ -11,6 +11,7 @@
 
 #include <__algorithm/copy.h>
 #include <__algorithm/in_out_result.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/ranges_copy.h>
 #include <__config>
 #include <__functional/identity.h>
@@ -51,7 +52,7 @@ struct __fn {
   template <random_access_iterator _InIter, class _DiffType, random_access_iterator _OutIter>
   _LIBCPP_HIDE_FROM_ABI constexpr static
   copy_n_result<_InIter, _OutIter> __go(_InIter __first, _DiffType __n, _OutIter __result) {
-    auto __ret = std::__copy(__first, __first + __n, __result);
+    auto __ret = std::__copy<_RangeAlgPolicy>(__first, __first + __n, __result);
     return {__ret.first, __ret.second};
   }
 

diff  --git a/libcxx/include/__algorithm/ranges_move.h b/libcxx/include/__algorithm/ranges_move.h
index 94f9970ed2089..46a0970f834ad 100644
--- a/libcxx/include/__algorithm/ranges_move.h
+++ b/libcxx/include/__algorithm/ranges_move.h
@@ -14,7 +14,6 @@
 #include <__algorithm/move.h>
 #include <__config>
 #include <__iterator/concepts.h>
-#include <__iterator/iter_move.h>
 #include <__ranges/access.h>
 #include <__ranges/concepts.h>
 #include <__ranges/dangling.h>

diff  --git a/libcxx/include/__algorithm/ranges_move_backward.h b/libcxx/include/__algorithm/ranges_move_backward.h
index 134e0877374df..d4e8eb1a50089 100644
--- a/libcxx/include/__algorithm/ranges_move_backward.h
+++ b/libcxx/include/__algorithm/ranges_move_backward.h
@@ -10,12 +10,12 @@
 #define _LIBCPP___ALGORITHM_RANGES_MOVE_BACKWARD_H
 
 #include <__algorithm/in_out_result.h>
-#include <__algorithm/ranges_move.h>
+#include <__algorithm/iterator_operations.h>
+#include <__algorithm/move_backward.h>
 #include <__config>
 #include <__iterator/concepts.h>
 #include <__iterator/iter_move.h>
 #include <__iterator/next.h>
-#include <__iterator/reverse_iterator.h>
 #include <__ranges/access.h>
 #include <__ranges/concepts.h>
 #include <__ranges/dangling.h>
@@ -40,11 +40,8 @@ struct __fn {
   template <class _InIter, class _Sent, class _OutIter>
   _LIBCPP_HIDE_FROM_ABI constexpr static
   move_backward_result<_InIter, _OutIter> __move_backward_impl(_InIter __first, _Sent __last, _OutIter __result) {
-    auto __last_iter = ranges::next(__first, std::move(__last));
-    auto __ret = ranges::move(std::make_reverse_iterator(__last_iter),
-                              std::make_reverse_iterator(__first),
-                              std::make_reverse_iterator(__result));
-    return {std::move(__last_iter), std::move(__ret.out.base())};
+    auto __ret = std::__move_backward<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__result));
+    return {std::move(__ret.first), std::move(__ret.second)};
   }
 
   template <bidirectional_iterator _InIter, sentinel_for<_InIter> _Sent, bidirectional_iterator _OutIter>

diff  --git a/libcxx/include/__algorithm/ranges_set_
diff erence.h b/libcxx/include/__algorithm/ranges_set_
diff erence.h
index 398ccc975f225..607dd687a5de6 100644
--- a/libcxx/include/__algorithm/ranges_set_
diff erence.h
+++ b/libcxx/include/__algorithm/ranges_set_
diff erence.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___ALGORITHM_RANGES_SET_DIFFERENCE_H
 
 #include <__algorithm/in_out_result.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_projected.h>
 #include <__algorithm/set_
diff erence.h>
 #include <__config>
@@ -60,7 +61,7 @@ struct __fn {
       _Comp __comp   = {},
       _Proj1 __proj1 = {},
       _Proj2 __proj2 = {}) const {
-    auto __ret = std::__set_
diff erence(
+    auto __ret = std::__set_
diff erence<_RangeAlgPolicy>(
         __first1, __last1, __first2, __last2, __result, ranges::__make_projected_comp(__comp, __proj1, __proj2));
     return {std::move(__ret.first), std::move(__ret.second)};
   }
@@ -81,7 +82,7 @@ struct __fn {
         _Comp __comp   = {},
         _Proj1 __proj1 = {},
         _Proj2 __proj2 = {}) const {
-    auto __ret = std::__set_
diff erence(
+    auto __ret = std::__set_
diff erence<_RangeAlgPolicy>(
         ranges::begin(__range1),
         ranges::end(__range1),
         ranges::begin(__range2),

diff  --git a/libcxx/include/__algorithm/ranges_set_symmetric_
diff erence.h b/libcxx/include/__algorithm/ranges_set_symmetric_
diff erence.h
index b0c79537b178e..bc4a9065503b4 100644
--- a/libcxx/include/__algorithm/ranges_set_symmetric_
diff erence.h
+++ b/libcxx/include/__algorithm/ranges_set_symmetric_
diff erence.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___ALGORITHM_RANGES_SET_SYMMETRIC_DIFFERENCE_H
 
 #include <__algorithm/in_in_out_result.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_projected.h>
 #include <__algorithm/set_symmetric_
diff erence.h>
 #include <__config>
@@ -58,7 +59,7 @@ struct __fn {
       _Comp __comp   = {},
       _Proj1 __proj1 = {},
       _Proj2 __proj2 = {}) const {
-    auto __ret = std::__set_symmetric_
diff erence(
+    auto __ret = std::__set_symmetric_
diff erence<_RangeAlgPolicy>(
         std::move(__first1),
         std::move(__last1),
         std::move(__first2),
@@ -92,7 +93,7 @@ struct __fn {
         _Comp __comp   = {},
         _Proj1 __proj1 = {},
         _Proj2 __proj2 = {}) const {
-    auto __ret = std::__set_symmetric_
diff erence(
+    auto __ret = std::__set_symmetric_
diff erence<_RangeAlgPolicy>(
         ranges::begin(__range1),
         ranges::end(__range1),
         ranges::begin(__range2),

diff  --git a/libcxx/include/__algorithm/ranges_set_union.h b/libcxx/include/__algorithm/ranges_set_union.h
index 500c0b2c2d3bc..f8cd45ca0e33b 100644
--- a/libcxx/include/__algorithm/ranges_set_union.h
+++ b/libcxx/include/__algorithm/ranges_set_union.h
@@ -10,6 +10,7 @@
 #define _LIBCPP___ALGORITHM_RANGES_SET_UNION_H
 
 #include <__algorithm/in_in_out_result.h>
+#include <__algorithm/iterator_operations.h>
 #include <__algorithm/make_projected.h>
 #include <__algorithm/set_union.h>
 #include <__config>
@@ -61,7 +62,7 @@ struct __fn {
       _Comp __comp   = {},
       _Proj1 __proj1 = {},
       _Proj2 __proj2 = {}) const {
-    auto __ret = std::__set_union(
+    auto __ret = std::__set_union<_RangeAlgPolicy>(
         std::move(__first1),
         std::move(__last1),
         std::move(__first2),
@@ -95,7 +96,7 @@ struct __fn {
         _Comp __comp   = {},
         _Proj1 __proj1 = {},
         _Proj2 __proj2 = {}) const {
-    auto __ret = std::__set_union(
+    auto __ret = std::__set_union<_RangeAlgPolicy>(
         ranges::begin(__range1),
         ranges::end(__range1),
         ranges::begin(__range2),

diff  --git a/libcxx/include/__algorithm/rotate.h b/libcxx/include/__algorithm/rotate.h
index 32682936e32e7..8934ce095bbc5 100644
--- a/libcxx/include/__algorithm/rotate.h
+++ b/libcxx/include/__algorithm/rotate.h
@@ -48,7 +48,7 @@ __rotate_right(_BidirectionalIterator __first, _BidirectionalIterator __last)
 
     _BidirectionalIterator __lm1 = _Ops::prev(__last);
     value_type __tmp = _Ops::__iter_move(__lm1);
-    _BidirectionalIterator __fp1 = std::__move_backward<_AlgPolicy>(__first, __lm1, std::move(__last));
+    _BidirectionalIterator __fp1 = std::__move_backward<_AlgPolicy>(__first, __lm1, std::move(__last)).second;
     *__first = _VSTD::move(__tmp);
     return __fp1;
 }

diff  --git a/libcxx/include/__algorithm/set_
diff erence.h b/libcxx/include/__algorithm/set_
diff erence.h
index e0385bf822ff9..cffdc8fc4fc00 100644
--- a/libcxx/include/__algorithm/set_
diff erence.h
+++ b/libcxx/include/__algorithm/set_
diff erence.h
@@ -12,6 +12,7 @@
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
 #include <__algorithm/copy.h>
+#include <__algorithm/iterator_operations.h>
 #include <__config>
 #include <__functional/identity.h>
 #include <__functional/invoke.h>
@@ -26,7 +27,7 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-template < class _Comp, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
+template <class _AlgPolicy, class _Comp, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<__remove_cvref_t<_InIter1>, __remove_cvref_t<_OutIter> >
 __set_
diff erence(
     _InIter1&& __first1, _Sent1&& __last1, _InIter2&& __first2, _Sent2&& __last2, _OutIter&& __result, _Comp&& __comp) {
@@ -42,7 +43,7 @@ __set_
diff erence(
       ++__first2;
     }
   }
-  return std::__copy(std::move(__first1), std::move(__last1), std::move(__result));
+  return std::__copy<_AlgPolicy>(std::move(__first1), std::move(__last1), std::move(__result));
 }
 
 template <class _InputIterator1, class _InputIterator2, class _OutputIterator, class _Compare>
@@ -53,7 +54,8 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_d
     _InputIterator2 __last2,
     _OutputIterator __result,
     _Compare __comp) {
-  return std::__set_
diff erence<__comp_ref_type<_Compare> >(__first1, __last1, __first2, __last2, __result, __comp)
+  return std::__set_
diff erence<_ClassicAlgPolicy, __comp_ref_type<_Compare> >(
+      __first1, __last1, __first2, __last2, __result, __comp)
       .second;
 }
 
@@ -64,7 +66,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_d
     _InputIterator2 __first2,
     _InputIterator2 __last2,
     _OutputIterator __result) {
-  return std::__set_
diff erence(
+  return std::__set_
diff erence<_ClassicAlgPolicy>(
       __first1,
       __last1,
       __first2,

diff  --git a/libcxx/include/__algorithm/set_symmetric_
diff erence.h b/libcxx/include/__algorithm/set_symmetric_
diff erence.h
index 97d3f1da7c249..bcb09587032ba 100644
--- a/libcxx/include/__algorithm/set_symmetric_
diff erence.h
+++ b/libcxx/include/__algorithm/set_symmetric_
diff erence.h
@@ -12,6 +12,7 @@
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
 #include <__algorithm/copy.h>
+#include <__algorithm/iterator_operations.h>
 #include <__config>
 #include <__iterator/iterator_traits.h>
 #include <__utility/move.h>
@@ -35,13 +36,13 @@ struct __set_symmetric_
diff erence_result {
       : __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {}
 };
 
-template <class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
+template <class _AlgPolicy, class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_symmetric_
diff erence_result<_InIter1, _InIter2, _OutIter>
 __set_symmetric_
diff erence(
     _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Compare&& __comp) {
   while (__first1 != __last1) {
     if (__first2 == __last2) {
-      auto __ret1 = std::__copy_impl(std::move(__first1), std::move(__last1), std::move(__result));
+      auto __ret1 = std::__copy<_AlgPolicy>(std::move(__first1), std::move(__last1), std::move(__result));
       return __set_symmetric_
diff erence_result<_InIter1, _InIter2, _OutIter>(
           std::move(__ret1.first), std::move(__first2), std::move((__ret1.second)));
     }
@@ -59,7 +60,7 @@ __set_symmetric_
diff erence(
       ++__first2;
     }
   }
-  auto __ret2 = std::__copy_impl(std::move(__first2), std::move(__last2), std::move(__result));
+  auto __ret2 = std::__copy<_AlgPolicy>(std::move(__first2), std::move(__last2), std::move(__result));
   return __set_symmetric_
diff erence_result<_InIter1, _InIter2, _OutIter>(
       std::move(__first1), std::move(__ret2.first), std::move((__ret2.second)));
 }
@@ -72,7 +73,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_symmetri
     _InputIterator2 __last2,
     _OutputIterator __result,
     _Compare __comp) {
-  return std::__set_symmetric_
diff erence<__comp_ref_type<_Compare> >(
+  return std::__set_symmetric_
diff erence<_ClassicAlgPolicy, __comp_ref_type<_Compare> >(
              std::move(__first1),
              std::move(__last1),
              std::move(__first2),

diff  --git a/libcxx/include/__algorithm/set_union.h b/libcxx/include/__algorithm/set_union.h
index addc77b7d8053..4d154b81e0920 100644
--- a/libcxx/include/__algorithm/set_union.h
+++ b/libcxx/include/__algorithm/set_union.h
@@ -12,6 +12,7 @@
 #include <__algorithm/comp.h>
 #include <__algorithm/comp_ref_type.h>
 #include <__algorithm/copy.h>
+#include <__algorithm/iterator_operations.h>
 #include <__config>
 #include <__iterator/iterator_traits.h>
 #include <__utility/move.h>
@@ -35,12 +36,12 @@ struct __set_union_result {
       : __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {}
 };
 
-template <class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
+template <class _AlgPolicy, class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_union_result<_InIter1, _InIter2, _OutIter> __set_union(
     _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Compare&& __comp) {
   for (; __first1 != __last1; ++__result) {
     if (__first2 == __last2) {
-      auto __ret1 = std::__copy_impl(std::move(__first1), std::move(__last1), std::move(__result));
+      auto __ret1 = std::__copy<_AlgPolicy>(std::move(__first1), std::move(__last1), std::move(__result));
       return __set_union_result<_InIter1, _InIter2, _OutIter>(
           std::move(__ret1.first), std::move(__first2), std::move((__ret1.second)));
     }
@@ -55,7 +56,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_union_result<_InIter1,
       ++__first1;
     }
   }
-  auto __ret2 = std::__copy_impl(std::move(__first2), std::move(__last2), std::move(__result));
+  auto __ret2 = std::__copy<_AlgPolicy>(std::move(__first2), std::move(__last2), std::move(__result));
   return __set_union_result<_InIter1, _InIter2, _OutIter>(
       std::move(__first1), std::move(__ret2.first), std::move((__ret2.second)));
 }
@@ -68,7 +69,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_union(
     _InputIterator2 __last2,
     _OutputIterator __result,
     _Compare __comp) {
-  return std::__set_union<__comp_ref_type<_Compare> >(
+  return std::__set_union<_ClassicAlgPolicy, __comp_ref_type<_Compare> >(
              std::move(__first1),
              std::move(__last1),
              std::move(__first2),

diff  --git a/libcxx/include/__iterator/reverse_iterator.h b/libcxx/include/__iterator/reverse_iterator.h
index 2933a29fc8417..73707097dfe4b 100644
--- a/libcxx/include/__iterator/reverse_iterator.h
+++ b/libcxx/include/__iterator/reverse_iterator.h
@@ -195,12 +195,6 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP
 #endif // _LIBCPP_STD_VER > 17
 };
 
-template <class _Iter>
-struct __is_reverse_iterator : false_type {};
-
-template <class _Iter>
-struct __is_reverse_iterator<reverse_iterator<_Iter> > : true_type {};
-
 template <class _Iter1, class _Iter2>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX17
 bool
@@ -478,9 +472,6 @@ class __unconstrained_reverse_iterator {
   }
 };
 
-template <class _Iter>
-struct __is_reverse_iterator<__unconstrained_reverse_iterator<_Iter>> : true_type {};
-
 #endif // _LIBCPP_STD_VER <= 17
 
 template <template <class> class _RevIter1, template <class> class _RevIter2, class _Iter>

diff  --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 9b21e7bbf1936..c1e098d881e66 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -1708,7 +1708,6 @@ template <class BidirectionalIterator, class Compare>
 #include <__config>
 #include <__debug>
 #include <cstddef>
-#include <cstring>
 #include <type_traits>
 #include <version>
 
@@ -1917,6 +1916,7 @@ template <class BidirectionalIterator, class Compare>
 
 #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
 #  include <atomic>
+#  include <cstring>
 #  include <iterator>
 #  include <memory>
 #  include <stdexcept>

diff  --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index dd7fd087e927a..0f58020fc0be9 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -251,6 +251,7 @@ module std [system] {
       module copy                            { private header "__algorithm/copy.h" }
       module copy_backward                   { private header "__algorithm/copy_backward.h" }
       module copy_if                         { private header "__algorithm/copy_if.h" }
+      module copy_move_common                { private header "__algorithm/copy_move_common.h" }
       module copy_n                          { private header "__algorithm/copy_n.h" }
       module count                           { private header "__algorithm/count.h" }
       module count_if                        { private header "__algorithm/count_if.h" }

diff  --git a/libcxx/include/valarray b/libcxx/include/valarray
index f28e471dfb3f9..3a7cd62966123 100644
--- a/libcxx/include/valarray
+++ b/libcxx/include/valarray
@@ -4931,6 +4931,7 @@ _LIBCPP_POP_MACROS
 
 #if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
 #  include <algorithm>
+#  include <cstring>
 #  include <functional>
 #endif
 

diff  --git a/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy.pass.cpp b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy.pass.cpp
deleted file mode 100644
index 8fafad9ad7f53..0000000000000
--- a/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy.pass.cpp
+++ /dev/null
@@ -1,179 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-
-// When the debug mode is enabled, we don't unwrap iterators in std::copy
-// so we don't get this optimization.
-// UNSUPPORTED: libcpp-has-debug-mode
-
-// <algorithm>
-
-// This test checks that std::copy forwards to memmove when appropriate.
-
-#include <algorithm>
-#include <cassert>
-#include <iterator>
-#include <ranges>
-#include <type_traits>
-
-struct S {
-  int i;
-  constexpr S(int i_) : i(i_) {}
-  S(const S&) = default;
-  S(S&&) = delete;
-  constexpr S& operator=(const S&) = default;
-  S& operator=(S&&) = delete;
-  constexpr bool operator==(const S&) const = default;
-};
-
-static_assert(std::is_trivially_copyable_v<S>);
-
-template <class T>
-struct NotIncrementableIt {
-  T* i;
-  using iterator_category = std::contiguous_iterator_tag;
-  using iterator_concept = std::contiguous_iterator_tag;
-  using value_type = T;
-  using 
diff erence_type = ptr
diff _t;
-  using pointer = T*;
-  using reference = T&;
-
-  constexpr NotIncrementableIt() = default;
-  constexpr NotIncrementableIt(T* i_) : i(i_) {}
-
-  friend constexpr bool operator==(const NotIncrementableIt& lhs, const NotIncrementableIt& rhs) {
-    return lhs.i == rhs.i;
-  }
-
-  constexpr T& operator*() { return *i; }
-  constexpr T& operator*() const { return *i; }
-  constexpr T* operator->() { return i; }
-  constexpr T* operator->() const { return i; }
-
-  constexpr NotIncrementableIt& operator++() {
-    assert(false);
-    return *this;
-  }
-
-  constexpr NotIncrementableIt& operator++(int) {
-    assert(false);
-    return *this;
-  }
-
-  constexpr NotIncrementableIt& operator--() {
-    assert(false);
-    return *this;
-  }
-
-  friend constexpr NotIncrementableIt operator+(const NotIncrementableIt& it, 
diff erence_type size) { return it.i + size; }
-  friend constexpr 
diff erence_type operator-(const NotIncrementableIt& x, const NotIncrementableIt& y) { return x.i - y.i; }
-  friend constexpr NotIncrementableIt operator-(const NotIncrementableIt& x, 
diff erence_type size) { return NotIncrementableIt(x.i - size); }
-};
-
-static_assert(std::__is_cpp17_contiguous_iterator<NotIncrementableIt<S>>::value);
-
-template <size_t N, class Iter, std::enable_if_t<N == 0>* = nullptr>
-constexpr auto wrap_n_times(Iter i) {
-  return i;
-}
-
-template <size_t N, class Iter, std::enable_if_t<N != 0>* = nullptr>
-constexpr auto wrap_n_times(Iter i) {
-  return std::make_reverse_iterator(wrap_n_times<N - 1>(i));
-}
-
-static_assert(std::is_same_v<decltype(wrap_n_times<2>(std::declval<int*>())),
-                             std::reverse_iterator<std::reverse_iterator<int*>>>);
-
-template <size_t InCount, size_t OutCount, class Iter>
-constexpr void test_normal() {
-  {
-    S a[] = {1, 2, 3, 4};
-    S b[] = {0, 0, 0, 0};
-    std::copy(wrap_n_times<InCount>(Iter(a)), wrap_n_times<InCount>(Iter(a + 4)), wrap_n_times<OutCount>(Iter(b)));
-    assert(std::equal(a, a + 4, b));
-  }
-  {
-    S a[] = {1, 2, 3, 4};
-    S b[] = {0, 0, 0, 0};
-    std::ranges::copy(wrap_n_times<InCount>(Iter(a)),
-                      wrap_n_times<InCount>(Iter(a + 4)),
-                      wrap_n_times<OutCount>(Iter(b)));
-    assert(std::equal(a, a + 4, b));
-  }
-  {
-    S a[] = {1, 2, 3, 4};
-    S b[] = {0, 0, 0, 0};
-    auto range = std::ranges::subrange(wrap_n_times<InCount>(Iter(a)), wrap_n_times<InCount>(Iter(a + 4)));
-    std::ranges::copy(range, Iter(b));
-    assert(std::equal(a, a + 4, b));
-  }
-}
-
-template <size_t InCount, size_t OutCount, class Iter>
-constexpr void test_reverse() {
-  {
-    S a[] = {1, 2, 3, 4};
-    S b[] = {0, 0, 0, 0};
-    std::copy(std::make_reverse_iterator(wrap_n_times<InCount>(Iter(a + 4))),
-              std::make_reverse_iterator(wrap_n_times<InCount>(Iter(a))),
-              std::make_reverse_iterator(wrap_n_times<OutCount>(Iter(b + 4))));
-    assert(std::equal(a, a + 4, b));
-  }
-  {
-    S a[] = {1, 2, 3, 4};
-    S b[] = {0, 0, 0, 0};
-    std::ranges::copy(std::make_reverse_iterator(wrap_n_times<InCount>(Iter(a + 4))),
-                      std::make_reverse_iterator(wrap_n_times<InCount>(Iter(a))),
-                      std::make_reverse_iterator(wrap_n_times<OutCount>(Iter(b + 4))));
-    assert(std::equal(a, a + 4, b));
-  }
-  {
-    S a[] = {1, 2, 3, 4};
-    S b[] = {0, 0, 0, 0};
-    auto range = std::ranges::subrange(wrap_n_times<InCount>(std::make_reverse_iterator(Iter(a + 4))),
-                                       wrap_n_times<InCount>(std::make_reverse_iterator(Iter(a))));
-    std::ranges::copy(range, std::make_reverse_iterator(wrap_n_times<OutCount>(Iter(b + 4))));
-    assert(std::equal(a, a + 4, b));
-  }
-}
-
-template <size_t InCount, size_t OutCount>
-constexpr void test_normal_reverse() {
-  test_normal<InCount, OutCount, S*>();
-  test_normal<InCount, OutCount, NotIncrementableIt<S>>();
-  test_reverse<InCount, OutCount, S*>();
-  test_reverse<InCount, OutCount, NotIncrementableIt<S>>();
-}
-
-template <size_t InCount>
-constexpr void test_out_count() {
-  test_normal_reverse<InCount, 0>();
-  test_normal_reverse<InCount, 2>();
-  test_normal_reverse<InCount, 4>();
-  test_normal_reverse<InCount, 6>();
-  test_normal_reverse<InCount, 8>();
-}
-
-constexpr bool test() {
-  test_out_count<0>();
-  test_out_count<2>();
-  test_out_count<4>();
-  test_out_count<6>();
-  test_out_count<8>();
-
-  return true;
-}
-
-int main(int, char**) {
-  test();
-  static_assert(test());
-
-  return 0;
-}

diff  --git a/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_nontrivial.pass.cpp b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_nontrivial.pass.cpp
new file mode 100644
index 0000000000000..fd60b4989c07f
--- /dev/null
+++ b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_nontrivial.pass.cpp
@@ -0,0 +1,250 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// <algorithm>
+
+// These tests checks that `std::copy` and `std::move` (including their variations like `copy_n`) don't forward to
+// `std::memmove` when doing so would be observable.
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <ranges>
+#include <type_traits>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+template <size_t N, class Iter>
+requires (N == 0)
+constexpr auto wrap_n_times(Iter i) {
+  return i;
+}
+
+template <size_t N, class Iter>
+requires (N != 0)
+constexpr auto wrap_n_times(Iter i) {
+  return std::make_reverse_iterator(wrap_n_times<N - 1>(i));
+}
+
+static_assert(std::is_same_v<decltype(wrap_n_times<2>(std::declval<int*>())),
+                             std::reverse_iterator<std::reverse_iterator<int*>>>);
+
+struct NonTrivialMoveAssignment {
+  int i;
+
+  constexpr NonTrivialMoveAssignment() = default;
+  constexpr NonTrivialMoveAssignment(int set_i) : i(set_i) {}
+
+  constexpr NonTrivialMoveAssignment(NonTrivialMoveAssignment&& rhs) = default;
+  constexpr NonTrivialMoveAssignment& operator=(NonTrivialMoveAssignment&& rhs) noexcept {
+    i = rhs.i;
+    return *this;
+  }
+
+  constexpr friend bool operator==(const NonTrivialMoveAssignment&, const NonTrivialMoveAssignment&) = default;
+};
+
+static_assert(!std::is_trivially_move_assignable_v<NonTrivialMoveAssignment>);
+
+struct NonTrivialMoveCtr {
+  int i;
+
+  constexpr NonTrivialMoveCtr() = default;
+  constexpr NonTrivialMoveCtr(int set_i) : i(set_i) {}
+
+  constexpr NonTrivialMoveCtr(NonTrivialMoveCtr&& rhs) noexcept : i(rhs.i) {}
+  constexpr NonTrivialMoveCtr& operator=(NonTrivialMoveCtr&& rhs) = default;
+
+  constexpr friend bool operator==(const NonTrivialMoveCtr&, const NonTrivialMoveCtr&) = default;
+};
+
+static_assert(std::is_trivially_move_assignable_v<NonTrivialMoveCtr>);
+static_assert(!std::is_trivially_copyable_v<NonTrivialMoveCtr>);
+
+struct NonTrivialCopyAssignment {
+  int i;
+
+  constexpr NonTrivialCopyAssignment() = default;
+  constexpr NonTrivialCopyAssignment(int set_i) : i(set_i) {}
+
+  constexpr NonTrivialCopyAssignment(const NonTrivialCopyAssignment& rhs) = default;
+  constexpr NonTrivialCopyAssignment& operator=(const NonTrivialCopyAssignment& rhs) {
+    i = rhs.i;
+    return *this;
+  }
+
+  constexpr friend bool operator==(const NonTrivialCopyAssignment&, const NonTrivialCopyAssignment&) = default;
+};
+
+static_assert(!std::is_trivially_copy_assignable_v<NonTrivialCopyAssignment>);
+
+struct NonTrivialCopyCtr {
+  int i;
+
+  constexpr NonTrivialCopyCtr() = default;
+  constexpr NonTrivialCopyCtr(int set_i) : i(set_i) {}
+
+  constexpr NonTrivialCopyCtr(const NonTrivialCopyCtr& rhs) : i(rhs.i) {}
+  constexpr NonTrivialCopyCtr& operator=(const NonTrivialCopyCtr& rhs) = default;
+
+  constexpr friend bool operator==(const NonTrivialCopyCtr&, const NonTrivialCopyCtr&) = default;
+};
+
+static_assert(std::is_trivially_copy_assignable_v<NonTrivialCopyCtr>);
+static_assert(!std::is_trivially_copyable_v<NonTrivialCopyCtr>);
+
+// Unwrapping the iterator inside `std::copy` and similar algorithms relies on `to_address`. If the `memmove`
+// optimization is used, the result of the call to `to_address` will be passed to `memmove`. This test deliberately
+// specializes `to_address` for `contiguous_iterator` to return a type that doesn't implicitly convert to `void*`, so
+// that a call to `memmove` would fail to compile.
+template <>
+struct std::pointer_traits<::contiguous_iterator<NonTrivialCopyAssignment*>> {
+  static constexpr ::contiguous_iterator<NonTrivialCopyAssignment*>
+  to_address(const ::contiguous_iterator<NonTrivialCopyAssignment*>& iter) {
+    return iter;
+  }
+};
+template <>
+struct std::pointer_traits<::contiguous_iterator<NonTrivialMoveAssignment*>> {
+  static constexpr ::contiguous_iterator<NonTrivialMoveAssignment*>
+  to_address(const ::contiguous_iterator<NonTrivialMoveAssignment*>& iter) {
+    return iter;
+  }
+};
+
+template <class InIter, template <class> class SentWrapper, class OutIter, size_t W1, size_t W2, class Func>
+constexpr void test_one(Func func) {
+  using Value = typename std::iterator_traits<InIter>::value_type;
+
+  {
+    const size_t N = 4;
+
+    Value input[N] = {Value{1}, {2}, {3}, {4}};
+    Value output[N];
+
+    auto in     = wrap_n_times<W1>(InIter(input));
+    auto in_end = wrap_n_times<W1>(InIter(input + N));
+    auto sent   = SentWrapper<decltype(in_end)>(in_end);
+    auto out    = wrap_n_times<W2>(OutIter(output));
+
+    func(in, sent, out, N);
+    assert(std::equal(input, input + N, output));
+  }
+
+  {
+    const size_t N = 0;
+
+    Value input[1]  = {1};
+    Value output[1] = {2};
+
+    auto in     = wrap_n_times<W1>(InIter(input));
+    auto in_end = wrap_n_times<W1>(InIter(input + N));
+    auto sent   = SentWrapper<decltype(in_end)>(in_end);
+    auto out    = wrap_n_times<W2>(OutIter(output));
+
+    func(in, sent, out, N);
+    assert(output[0] == Value(2));
+  }
+}
+
+template <class InIter, template <class> class SentWrapper, class OutIter, size_t W1, size_t W2>
+constexpr void test_copy() {
+  // Classic.
+  if constexpr (std::same_as<InIter, SentWrapper<InIter>>) {
+    test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t) {
+      std::copy(first, last, out);
+    });
+    test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t n) {
+      std::copy_backward(first, last, out + n);
+    });
+    test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto, auto out, size_t n) {
+      std::copy_n(first, n, out);
+    });
+  }
+
+  // Ranges.
+  test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t) {
+    std::ranges::copy(first, last, out);
+  });
+  test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t n) {
+    std::ranges::copy_backward(first, last, out + n);
+  });
+  test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto, auto out, size_t n) {
+    std::ranges::copy_n(first, n, out);
+  });
+}
+
+template <class InIter, template <class> class SentWrapper, class OutIter, size_t W1, size_t W2>
+constexpr void test_move() {
+  if constexpr (std::same_as<InIter, SentWrapper<InIter>>) {
+    test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t) {
+      std::move(first, last, out);
+    });
+    test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t n) {
+      std::move_backward(first, last, out + n);
+    });
+  }
+
+  // Ranges.
+  test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t) {
+    std::ranges::move(first, last, out);
+  });
+  test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t n) {
+    std::ranges::move_backward(first, last, out + n);
+  });
+}
+
+template <class T, size_t W1, size_t W2>
+constexpr void test_copy_with_type() {
+  using CopyIter = contiguous_iterator<T*>;
+
+  test_copy<CopyIter, std::type_identity_t, CopyIter, W1, W2>();
+  test_copy<CopyIter, sized_sentinel, CopyIter, W1, W2>();
+  test_copy<CopyIter, std::type_identity_t, T*, W1, W2>();
+  test_copy<T*, std::type_identity_t, CopyIter, W1, W2>();
+}
+
+template <class T, size_t W1, size_t W2>
+constexpr void test_move_with_type() {
+  using MoveIter = contiguous_iterator<T*>;
+
+  test_move<MoveIter, std::type_identity_t, MoveIter, W1, W2>();
+  test_move<MoveIter, sized_sentinel, MoveIter, W1, W2>();
+  test_move<MoveIter, std::type_identity_t, T*, W1, W2>();
+  test_move<T*, std::type_identity_t, MoveIter, W1, W2>();
+}
+
+template <size_t W1, size_t W2>
+constexpr void test_copy_and_move() {
+  test_copy_with_type<NonTrivialCopyAssignment, W1, W2>();
+  test_copy_with_type<NonTrivialCopyCtr, W1, W2>();
+
+  test_move_with_type<NonTrivialMoveAssignment, W1, W2>();
+  test_move_with_type<NonTrivialMoveCtr, W1, W2>();
+}
+
+constexpr bool test() {
+  test_copy_and_move<0, 0>();
+  test_copy_and_move<0, 2>();
+  test_copy_and_move<2, 0>();
+  test_copy_and_move<2, 2>();
+  test_copy_and_move<2, 4>();
+  test_copy_and_move<4, 4>();
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}

diff  --git a/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_trivial.pass.cpp b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_trivial.pass.cpp
new file mode 100644
index 0000000000000..1ea25f1495246
--- /dev/null
+++ b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_trivial.pass.cpp
@@ -0,0 +1,181 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// When the debug mode is enabled, we don't unwrap iterators in `std::copy` and similar algorithms so we don't get this
+// optimization.
+// UNSUPPORTED: libcpp-has-debug-mode
+// In the modules build, adding another overload of `memmove` doesn't work.
+// UNSUPPORTED: modules-build
+// GCC complains about "ambiguating" `__builtin_memmove`.
+// UNSUPPORTED: gcc
+
+// <algorithm>
+
+// These tests checks that `std::copy` and `std::move` (including their variations like `copy_n`) forward to
+// `memmove` when possible.
+
+#include <cstddef>
+
+struct Foo {
+  int i = 0;
+
+  Foo() = default;
+  Foo(int set_i) : i(set_i) {}
+
+  friend bool operator==(const Foo&, const Foo&) = default;
+};
+
+static bool memmove_called = false;
+
+// This overload is a better match than the actual `builtin_memmove`, so it should hijack the call inside `std::copy`
+// and similar algorithms.
+void* __builtin_memmove(Foo* dst, Foo* src, size_t count) {
+  memmove_called = true;
+  return __builtin_memmove(static_cast<void*>(dst), static_cast<void*>(src), count);
+}
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <ranges>
+#include <type_traits>
+
+#include "test_iterators.h"
+
+static_assert(std::is_trivially_copyable_v<Foo>);
+
+template <size_t N, class Iter>
+requires (N == 0)
+constexpr auto wrap_n_times(Iter i) {
+  return i;
+}
+
+template <size_t N, class Iter>
+requires (N != 0)
+constexpr auto wrap_n_times(Iter i) {
+  return std::make_reverse_iterator(wrap_n_times<N - 1>(i));
+}
+
+static_assert(std::is_same_v<decltype(wrap_n_times<2>(std::declval<int*>())),
+                             std::reverse_iterator<std::reverse_iterator<int*>>>);
+
+template <class InIter, template <class> class SentWrapper, class OutIter, size_t W1, size_t W2, class Func>
+void test_one(Func func) {
+  {
+    const size_t N = 4;
+
+    Foo input[N] = {{1}, {2}, {3}, {4}};
+    Foo output[N];
+
+    auto in     = wrap_n_times<W1>(InIter(input));
+    auto in_end = wrap_n_times<W1>(InIter(input + N));
+    auto sent   = SentWrapper<decltype(in_end)>(in_end);
+    auto out    = wrap_n_times<W2>(OutIter(output));
+
+    assert(!memmove_called);
+    func(in, sent, out, N);
+
+    assert(std::equal(input, input + N, output));
+    assert(memmove_called);
+    memmove_called = false;
+  }
+
+  {
+    const size_t N = 0;
+
+    Foo input[1]  = {1};
+    Foo output[1] = {2};
+
+    auto in     = wrap_n_times<W1>(InIter(input));
+    auto in_end = wrap_n_times<W1>(InIter(input + N));
+    auto sent   = SentWrapper<decltype(in_end)>(in_end);
+    auto out    = wrap_n_times<W2>(OutIter(output));
+
+    assert(!memmove_called);
+    func(in, sent, out, N);
+
+    assert(output[0] == 2);
+    assert(memmove_called);
+    memmove_called = false;
+  }
+}
+
+template <class InIter, template <class> class SentWrapper, class OutIter, size_t W1, size_t W2>
+void test_copy_and_move() {
+  // Classic.
+  if constexpr (std::same_as<InIter, SentWrapper<InIter>>) {
+    test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t) {
+      std::copy(first, last, out);
+    });
+    test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t n) {
+      std::copy_backward(first, last, out + n);
+    });
+    test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto, auto out, size_t n) {
+      std::copy_n(first, n, out);
+    });
+    test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t) {
+      std::move(first, last, out);
+    });
+    test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t n) {
+      std::move_backward(first, last, out + n);
+    });
+  }
+
+  // Ranges.
+  test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t) {
+    std::ranges::copy(first, last, out);
+  });
+  test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t n) {
+    std::ranges::copy_backward(first, last, out + n);
+  });
+  test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto, auto out, size_t n) {
+    std::ranges::copy_n(first, n, out);
+  });
+  test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t) {
+    std::ranges::move(first, last, out);
+  });
+  test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, size_t n) {
+    std::ranges::move_backward(first, last, out + n);
+  });
+}
+
+template <class InIter, template <class> class SentWrapper, class OutIter>
+void test_all_permutations_with_initer_sent_outiter() {
+  test_copy_and_move<InIter, SentWrapper, OutIter, 0, 0>();
+  test_copy_and_move<InIter, SentWrapper, OutIter, 0, 2>();
+  test_copy_and_move<InIter, SentWrapper, OutIter, 2, 0>();
+  test_copy_and_move<InIter, SentWrapper, OutIter, 2, 2>();
+  test_copy_and_move<InIter, SentWrapper, OutIter, 2, 4>();
+  test_copy_and_move<InIter, SentWrapper, OutIter, 4, 4>();
+}
+
+template <class InIter, template <class> class SentWrapper>
+void test_all_permutations_with_initer_sent() {
+  test_all_permutations_with_initer_sent_outiter<InIter, SentWrapper, Foo*>();
+  test_all_permutations_with_initer_sent_outiter<InIter, SentWrapper, contiguous_iterator<Foo*>>();
+}
+
+template <class InIter>
+void test_all_permutations_with_initer() {
+  test_all_permutations_with_initer_sent<InIter, std::type_identity_t>();
+  test_all_permutations_with_initer_sent<InIter, sized_sentinel>();
+}
+
+void test() {
+  test_all_permutations_with_initer<Foo*>();
+  test_all_permutations_with_initer<contiguous_iterator<Foo*>>();
+}
+
+int main(int, char**) {
+  test();
+  // The test relies on a global variable, so it cannot be made `constexpr`; the `memmove` optimization is not used in
+  // `constexpr` mode anyway.
+
+  return 0;
+}

diff  --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp
index 693dd1d3d15b3..e2d903eca6efc 100644
--- a/libcxx/test/libcxx/private_headers.verify.cpp
+++ b/libcxx/test/libcxx/private_headers.verify.cpp
@@ -46,6 +46,7 @@ END-SCRIPT
 #include <__algorithm/copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/copy.h'}}
 #include <__algorithm/copy_backward.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/copy_backward.h'}}
 #include <__algorithm/copy_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/copy_if.h'}}
+#include <__algorithm/copy_move_common.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/copy_move_common.h'}}
 #include <__algorithm/copy_n.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/copy_n.h'}}
 #include <__algorithm/count.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/count.h'}}
 #include <__algorithm/count_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/count_if.h'}}

diff  --git a/libcxx/test/libcxx/transitive_includes/cxx2b.csv b/libcxx/test/libcxx/transitive_includes/cxx2b.csv
index a17bc208b654d..e9369c86902a2 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx2b.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx2b.csv
@@ -761,7 +761,6 @@ valarray cmath
 valarray concepts
 valarray cstddef
 valarray cstdlib
-valarray cstring
 valarray initializer_list
 valarray limits
 valarray new

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp
index 5ca0ce9339928..0035d07235c83 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp
@@ -108,6 +108,7 @@ constexpr void test_in_iterators() {
   test_sentinels<bidirectional_iterator<int*>, Out>();
   test_sentinels<random_access_iterator<int*>, Out>();
   test_sentinels<contiguous_iterator<int*>, Out>();
+  test_sentinels<int*, Out>();
 }
 
 template <class Out>
@@ -125,6 +126,7 @@ constexpr bool test() {
   test_in_iterators<bidirectional_iterator<int*>>();
   test_in_iterators<random_access_iterator<int*>>();
   test_in_iterators<contiguous_iterator<int*>>();
+  test_in_iterators<int*>();
 
   test_proxy_in_iterators<ProxyIterator<cpp20_input_iterator<int*>>>();
   test_proxy_in_iterators<ProxyIterator<forward_iterator<int*>>>();

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp
index 766b220a04f40..a18ba9d6c344c 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy_backward.pass.cpp
@@ -111,6 +111,7 @@ constexpr void test_in_iterators() {
   test_sentinels<bidirectional_iterator<int*>, Out>();
   test_sentinels<random_access_iterator<int*>, Out>();
   test_sentinels<contiguous_iterator<int*>, Out>();
+  test_sentinels<int*, Out>();
 }
 
 template <class Out>
@@ -124,6 +125,7 @@ constexpr bool test() {
   test_in_iterators<bidirectional_iterator<int*>>();
   test_in_iterators<random_access_iterator<int*>>();
   test_in_iterators<contiguous_iterator<int*>>();
+  test_in_iterators<int*>();
 
   test_proxy_in_iterators<ProxyIterator<bidirectional_iterator<int*>>>();
   test_proxy_in_iterators<ProxyIterator<random_access_iterator<int*>>>();

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp
index d3350206d77e7..29630966e838d 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move.pass.cpp
@@ -92,6 +92,7 @@ constexpr void test_in_iterators() {
   test_iterators<bidirectional_iterator<int*>, Out>();
   test_iterators<random_access_iterator<int*>, Out>();
   test_iterators<contiguous_iterator<int*>, Out>();
+  test_iterators<int*, Out>();
 }
 
 template <class Out>
@@ -129,6 +130,7 @@ constexpr bool test() {
   test_in_iterators<bidirectional_iterator<int*>>();
   test_in_iterators<random_access_iterator<int*>>();
   test_in_iterators<contiguous_iterator<int*>>();
+  test_in_iterators<int*>();
 
   test_proxy_in_iterators<ProxyIterator<cpp20_input_iterator<int*>>>();
   test_proxy_in_iterators<ProxyIterator<forward_iterator<int*>>>();

diff  --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp
index 143848a455200..b77c1ed87398c 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.move/ranges.move_backward.pass.cpp
@@ -85,12 +85,19 @@ constexpr void test_iterators() {
   test<In, Out, Sent, 0>({});
 }
 
+template <class InIter, class OutIter>
+constexpr void test_sentinels() {
+  test_iterators<InIter, OutIter, InIter>();
+  test_iterators<InIter, OutIter, sentinel_wrapper<InIter>>();
+  test_iterators<InIter, OutIter, sized_sentinel<InIter>>();
+}
+
 template <class Out>
 constexpr void test_in_iterators() {
-  test_iterators<bidirectional_iterator<int*>, Out, sentinel_wrapper<bidirectional_iterator<int*>>>();
-  test_iterators<bidirectional_iterator<int*>, Out>();
-  test_iterators<random_access_iterator<int*>, Out>();
-  test_iterators<contiguous_iterator<int*>, Out>();
+  test_sentinels<bidirectional_iterator<int*>, Out>();
+  test_sentinels<random_access_iterator<int*>, Out>();
+  test_sentinels<contiguous_iterator<int*>, Out>();
+  test_sentinels<int*, Out>();
 }
 
 template <class Out>
@@ -125,6 +132,7 @@ constexpr bool test() {
   test_in_iterators<bidirectional_iterator<int*>>();
   test_in_iterators<random_access_iterator<int*>>();
   test_in_iterators<contiguous_iterator<int*>>();
+  test_in_iterators<int*>();
 
   test_proxy_in_iterators<ProxyIterator<bidirectional_iterator<int*>>>();
   test_proxy_in_iterators<ProxyIterator<random_access_iterator<int*>>>();


        


More information about the libcxx-commits mailing list