[libc++] Rationalize our treatment of contiguous iterators and __unwrap_iter().

- Implement C++20's changes to `reverse_iterator`, so that it won't be
    accidentally counted as a contiguous iterator in C++20 mode.
- Implement C++20's changes to `move_iterator` as well.
- `move_iterator` should not be contiguous. This fixes a bug where
    we optimized `std::copy`-of-move-iterators in an observable way.
    Add a regression test for that bugfix.
- Add libcxx tests for `__is_cpp17_contiguous_iterator` of all relevant
    standard iterator types. Particularly check that vector::iterator
    is still considered contiguous in all C++ modes, even C++03.

After this patch, there continues to be no supported way to write your
own iterator type in C++17-and-earlier such that libc++ will consider it
"contiguous"; however, we now fully support the C++20 approach (in C++20
mode only). If you want user-defined contiguous iterators in C++17-and-earlier,
libc++'s position is "please upgrade to C++20."

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

GitOrigin-RevId: d41c6d51cbadbbd0f81c6ac0d6628d01b881e2a5
diff --git a/include/algorithm b/include/algorithm
index 9bc31f8..d8fbac7 100644
--- a/include/algorithm
+++ b/include/algorithm
@@ -1639,69 +1639,43 @@
                            __value_, __equal_to<__v, _Tp>());
 }
 
-// copy
-template <class _Iter>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
-_Iter
-__unwrap_iter(_Iter __i)
-{
-    return __i;
-}
+// __unwrap_iter
 
-template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
-typename enable_if
-<
-    is_trivially_copy_assignable<_Tp>::value,
-    _Tp*
->::type
-__unwrap_iter(move_iterator<_Tp*> __i)
-{
-    return __i.base();
-}
+// The job of __unwrap_iter is to lower iterators-that-are-tantamount-to-pointers
+// (such as vector<T>::iterator) into pointers, to reduce the number of template
+// instantiations and to enable pointer-based optimizations e.g. in std::copy.
+// In debug mode, we don't do this.
+
+template <class _Iter, bool = __is_cpp17_contiguous_iterator<_Iter>::value>
+struct __unwrap_iter_impl {
+    static _LIBCPP_CONSTEXPR _Iter
+    __apply(_Iter __i) _NOEXCEPT {
+        return __i;
+    }
+};
 
 #if _LIBCPP_DEBUG_LEVEL < 2
 
-template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
-typename enable_if
-<
-    is_trivially_copy_assignable<_Tp>::value,
-    _Tp*
->::type
-__unwrap_iter(__wrap_iter<_Tp*> __i)
-{
-    return __i.base();
-}
-
-template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
-typename enable_if
-<
-    is_trivially_copy_assignable<_Tp>::value,
-    const _Tp*
->::type
-__unwrap_iter(__wrap_iter<const _Tp*> __i)
-{
-    return __i.base();
-}
-
-#else
-
-template <class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
-typename enable_if
-<
-    is_trivially_copy_assignable<_Tp>::value,
-    __wrap_iter<_Tp*>
->::type
-__unwrap_iter(__wrap_iter<_Tp*> __i)
-{
-    return __i;
-}
+template <class _Iter>
+struct __unwrap_iter_impl<_Iter, true> {
+    static _LIBCPP_CONSTEXPR decltype(_VSTD::__to_address(declval<_Iter>()))
+    __apply(_Iter __i) _NOEXCEPT {
+        return _VSTD::__to_address(__i);
+    }
+};
 
 #endif  // _LIBCPP_DEBUG_LEVEL < 2
 
+template<class _Iter, class _Impl = __unwrap_iter_impl<_Iter> >
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+decltype(_Impl::__apply(_VSTD::declval<_Iter>()))
+__unwrap_iter(_Iter __i) _NOEXCEPT
+{
+    return _Impl::__apply(__i);
+}
+
+// copy
+
 template <class _InputIterator, class _OutputIterator>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
 _OutputIterator
@@ -1894,7 +1868,7 @@
 typename enable_if
 <
     is_same<typename remove_const<_Tp>::type, _Up>::value &&
-    is_trivially_copy_assignable<_Up>::value,
+    is_trivially_move_assignable<_Up>::value,
     _Up*
 >::type
 __move(_Tp* __first, _Tp* __last, _Up* __result)
@@ -1942,7 +1916,7 @@
 typename enable_if
 <
     is_same<typename remove_const<_Tp>::type, _Up>::value &&
-    is_trivially_copy_assignable<_Up>::value,
+    is_trivially_move_assignable<_Up>::value,
     _Up*
 >::type
 __move_backward(_Tp* __first, _Tp* __last, _Up* __result)