diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -9,6 +9,7 @@ __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 --- 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 --- 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 --- /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 --- 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 --- 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 @@ 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 --- 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 @@ 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 @@ 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 --- 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 --- 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 @@ 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 --- 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 --- 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 @@ 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_difference.h b/libcxx/include/__algorithm/ranges_set_difference.h --- a/libcxx/include/__algorithm/ranges_set_difference.h +++ b/libcxx/include/__algorithm/ranges_set_difference.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_difference.h> #include <__config> @@ -60,7 +61,7 @@ _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { - auto __ret = std::__set_difference( + auto __ret = std::__set_difference<_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 @@ _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { - auto __ret = std::__set_difference( + auto __ret = std::__set_difference<_RangeAlgPolicy>( ranges::begin(__range1), ranges::end(__range1), ranges::begin(__range2), diff --git a/libcxx/include/__algorithm/ranges_set_symmetric_difference.h b/libcxx/include/__algorithm/ranges_set_symmetric_difference.h --- a/libcxx/include/__algorithm/ranges_set_symmetric_difference.h +++ b/libcxx/include/__algorithm/ranges_set_symmetric_difference.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_difference.h> #include <__config> @@ -58,7 +59,7 @@ _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { - auto __ret = std::__set_symmetric_difference( + auto __ret = std::__set_symmetric_difference<_RangeAlgPolicy>( std::move(__first1), std::move(__last1), std::move(__first2), @@ -92,7 +93,7 @@ _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const { - auto __ret = std::__set_symmetric_difference( + auto __ret = std::__set_symmetric_difference<_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 --- 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 @@ _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 @@ _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 --- a/libcxx/include/__algorithm/rotate.h +++ b/libcxx/include/__algorithm/rotate.h @@ -48,7 +48,7 @@ _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_difference.h b/libcxx/include/__algorithm/set_difference.h --- a/libcxx/include/__algorithm/set_difference.h +++ b/libcxx/include/__algorithm/set_difference.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_difference( _InIter1&& __first1, _Sent1&& __last1, _InIter2&& __first2, _Sent2&& __last2, _OutIter&& __result, _Comp&& __comp) { @@ -42,7 +43,7 @@ ++__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 @@ _InputIterator2 __last2, _OutputIterator __result, _Compare __comp) { - return std::__set_difference<__comp_ref_type<_Compare> >(__first1, __last1, __first2, __last2, __result, __comp) + return std::__set_difference<_ClassicAlgPolicy, __comp_ref_type<_Compare> >( + __first1, __last1, __first2, __last2, __result, __comp) .second; } @@ -64,7 +66,7 @@ _InputIterator2 __first2, _InputIterator2 __last2, _OutputIterator __result) { - return std::__set_difference( + return std::__set_difference<_ClassicAlgPolicy>( __first1, __last1, __first2, diff --git a/libcxx/include/__algorithm/set_symmetric_difference.h b/libcxx/include/__algorithm/set_symmetric_difference.h --- a/libcxx/include/__algorithm/set_symmetric_difference.h +++ b/libcxx/include/__algorithm/set_symmetric_difference.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 @@ : __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_difference_result<_InIter1, _InIter2, _OutIter> __set_symmetric_difference( _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_difference_result<_InIter1, _InIter2, _OutIter>( std::move(__ret1.first), std::move(__first2), std::move((__ret1.second))); } @@ -59,7 +60,7 @@ ++__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_difference_result<_InIter1, _InIter2, _OutIter>( std::move(__first1), std::move(__ret2.first), std::move((__ret2.second))); } @@ -72,7 +73,7 @@ _InputIterator2 __last2, _OutputIterator __result, _Compare __comp) { - return std::__set_symmetric_difference<__comp_ref_type<_Compare> >( + return std::__set_symmetric_difference<_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 --- 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 @@ : __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 @@ ++__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 @@ _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 --- a/libcxx/include/__iterator/reverse_iterator.h +++ b/libcxx/include/__iterator/reverse_iterator.h @@ -195,12 +195,6 @@ #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 @@ } }; -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 --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -1708,7 +1708,6 @@ #include <__config> #include <__debug> #include <cstddef> -#include <cstring> #include <type_traits> #include <version> @@ -1917,6 +1916,7 @@ #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 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -251,6 +251,7 @@ 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 --- a/libcxx/include/valarray +++ b/libcxx/include/valarray @@ -4931,6 +4931,7 @@ #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 --- 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 difference_type = ptrdiff_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, difference_type size) { return it.i + size; } - friend constexpr difference_type operator-(const NotIncrementableIt& x, const NotIncrementableIt& y) { return x.i - y.i; } - friend constexpr NotIncrementableIt operator-(const NotIncrementableIt& x, difference_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 --- /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 --- /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 --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -46,6 +46,7 @@ #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 --- a/libcxx/test/libcxx/transitive_includes/cxx2b.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx2b.csv @@ -761,7 +761,6 @@ 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 --- 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 @@ 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 @@ 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 --- 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 @@ 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 @@ 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 --- 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 @@ 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 @@ 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 --- 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 @@ 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 @@ 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*>>>();