Revert "[libc++][ranges]Refactor copy{,_backward} and move{,_backward}"

Breaks msan, asan

https://lab.llvm.org/buildbot/#/builders/5/builds/27904

This reverts commit 005916de58.
This commit is contained in:
Vitaly Buka 2022-10-02 16:23:35 -07:00
parent 961439cd7e
commit a6e1080b87
30 changed files with 463 additions and 762 deletions

View File

@ -9,7 +9,6 @@ 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

View File

@ -9,11 +9,15 @@
#ifndef _LIBCPP___ALGORITHM_COPY_H
#define _LIBCPP___ALGORITHM_COPY_H
#include <__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 <__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
@ -21,42 +25,82 @@
_LIBCPP_BEGIN_NAMESPACE_STD
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;
}
// copy
return std::make_pair(std::move(__first), std::move(__result));
}
};
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 _AlgPolicy, class _InIter, class _Sent, class _OutIter>
pair<_InIter, _OutIter>
template <class _InIter, class _Sent, class _OutIter>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14
__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));
pair<_InIter, _OutIter> __copy_impl(_InIter __first, _Sent __last, _OutIter __result) {
while (__first != __last) {
*__result = *__first;
++__first;
++__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);
}
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
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));
}
template <class _InputIterator, class _OutputIterator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
_OutputIterator
copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) {
return std::__copy<_ClassicAlgPolicy>(__first, __last, __result).second;
return std::__copy(__first, __last, __result).second;
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -9,11 +9,19 @@
#ifndef _LIBCPP___ALGORITHM_COPY_BACKWARD_H
#define _LIBCPP___ALGORITHM_COPY_BACKWARD_H
#include <__algorithm/copy_move_common.h>
#include <__algorithm/copy.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
@ -21,50 +29,32 @@
_LIBCPP_BEGIN_NAMESPACE_STD
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));
}
};
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));
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 _BidirectionalIterator1, class _BidirectionalIterator2>
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.");
#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());
}
#endif // _LIBCPP_STD_VER > 17
return std::__copy_backward<_ClassicAlgPolicy>(
std::move(__first), std::move(__last), std::move(__result)).second;
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;
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -1,137 +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
//
//===----------------------------------------------------------------------===//
#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

View File

@ -9,11 +9,15 @@
#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
@ -21,45 +25,93 @@
_LIBCPP_BEGIN_NAMESPACE_STD
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));
}
};
// move
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_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;
}
};
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
pair<_InIter, _OutIter>
__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) {
return std::__dispatch_copy_or_move<_AlgPolicy, __move_loop<_AlgPolicy>, __move_trivial>(
std::move(__first), std::move(__last), std::move(__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));
}
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) {
return std::__move_impl<_AlgPolicy>(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) {
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;
return std::__move<_ClassicAlgPolicy>(__first, __last, __result).second;
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -9,11 +9,12 @@
#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 <__utility/pair.h>
#include <cstring>
#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@ -21,40 +22,57 @@
_LIBCPP_BEGIN_NAMESPACE_STD
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_constexpr(_InputIterator __first, _InputIterator __last, _OutputIterator __result)
{
while (__first != __last)
*--__result = _IterOps<_AlgPolicy>::__iter_move(--__last);
return __result;
}
while (__first != __last_iter) {
*--__result = _IterOps<_AlgPolicy>::__iter_move(--__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));
}
return __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 _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)));
}
}
template <class _BidirectionalIterator1, class _BidirectionalIterator2>
@ -63,8 +81,7 @@ _BidirectionalIterator2
move_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last,
_BidirectionalIterator2 __result)
{
return std::__move_backward<_ClassicAlgPolicy>(
std::move(__first), std::move(__last), std::move(__result)).second;
return std::__move_backward<_ClassicAlgPolicy>(std::move(__first), std::move(__last), std::move(__result));
}
_LIBCPP_END_NAMESPACE_STD

View File

@ -11,7 +11,6 @@
#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>
@ -41,7 +40,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<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__result));
auto __ret = std::__copy(std::move(__first), std::move(__last), std::move(__result));
return {std::move(__ret.first), std::move(__ret.second)};
}
@ -49,7 +48,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<_RangeAlgPolicy>(ranges::begin(__r), ranges::end(__r), std::move(__result));
auto __ret = std::__copy(ranges::begin(__r), ranges::end(__r), std::move(__result));
return {std::move(__ret.first), std::move(__ret.second)};
}
};

View File

@ -14,6 +14,7 @@
#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>

View File

@ -11,7 +11,6 @@
#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>
@ -52,7 +51,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<_RangeAlgPolicy>(__first, __first + __n, __result);
auto __ret = std::__copy(__first, __first + __n, __result);
return {__ret.first, __ret.second};
}

View File

@ -14,6 +14,7 @@
#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>

View File

@ -10,12 +10,12 @@
#define _LIBCPP___ALGORITHM_RANGES_MOVE_BACKWARD_H
#include <__algorithm/in_out_result.h>
#include <__algorithm/iterator_operations.h>
#include <__algorithm/move_backward.h>
#include <__algorithm/ranges_move.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,8 +40,11 @@ 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 __ret = std::__move_backward<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__result));
return {std::move(__ret.first), std::move(__ret.second)};
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())};
}
template <bidirectional_iterator _InIter, sentinel_for<_InIter> _Sent, bidirectional_iterator _OutIter>

View File

@ -10,7 +10,6 @@
#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>
@ -61,7 +60,7 @@ struct __fn {
_Comp __comp = {},
_Proj1 __proj1 = {},
_Proj2 __proj2 = {}) const {
auto __ret = std::__set_difference<_RangeAlgPolicy>(
auto __ret = std::__set_difference(
__first1, __last1, __first2, __last2, __result, ranges::__make_projected_comp(__comp, __proj1, __proj2));
return {std::move(__ret.first), std::move(__ret.second)};
}
@ -82,7 +81,7 @@ struct __fn {
_Comp __comp = {},
_Proj1 __proj1 = {},
_Proj2 __proj2 = {}) const {
auto __ret = std::__set_difference<_RangeAlgPolicy>(
auto __ret = std::__set_difference(
ranges::begin(__range1),
ranges::end(__range1),
ranges::begin(__range2),

View File

@ -10,7 +10,6 @@
#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>
@ -59,7 +58,7 @@ struct __fn {
_Comp __comp = {},
_Proj1 __proj1 = {},
_Proj2 __proj2 = {}) const {
auto __ret = std::__set_symmetric_difference<_RangeAlgPolicy>(
auto __ret = std::__set_symmetric_difference(
std::move(__first1),
std::move(__last1),
std::move(__first2),
@ -93,7 +92,7 @@ struct __fn {
_Comp __comp = {},
_Proj1 __proj1 = {},
_Proj2 __proj2 = {}) const {
auto __ret = std::__set_symmetric_difference<_RangeAlgPolicy>(
auto __ret = std::__set_symmetric_difference(
ranges::begin(__range1),
ranges::end(__range1),
ranges::begin(__range2),

View File

@ -10,7 +10,6 @@
#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>
@ -62,7 +61,7 @@ struct __fn {
_Comp __comp = {},
_Proj1 __proj1 = {},
_Proj2 __proj2 = {}) const {
auto __ret = std::__set_union<_RangeAlgPolicy>(
auto __ret = std::__set_union(
std::move(__first1),
std::move(__last1),
std::move(__first2),
@ -96,7 +95,7 @@ struct __fn {
_Comp __comp = {},
_Proj1 __proj1 = {},
_Proj2 __proj2 = {}) const {
auto __ret = std::__set_union<_RangeAlgPolicy>(
auto __ret = std::__set_union(
ranges::begin(__range1),
ranges::end(__range1),
ranges::begin(__range2),

View File

@ -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)).second;
_BidirectionalIterator __fp1 = std::__move_backward<_AlgPolicy>(__first, __lm1, std::move(__last));
*__first = _VSTD::move(__tmp);
return __fp1;
}

View File

@ -12,7 +12,6 @@
#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>
@ -27,7 +26,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _AlgPolicy, class _Comp, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
template < 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) {
@ -43,7 +42,7 @@ __set_difference(
++__first2;
}
}
return std::__copy<_AlgPolicy>(std::move(__first1), std::move(__last1), std::move(__result));
return std::__copy(std::move(__first1), std::move(__last1), std::move(__result));
}
template <class _InputIterator1, class _InputIterator2, class _OutputIterator, class _Compare>
@ -54,8 +53,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_d
_InputIterator2 __last2,
_OutputIterator __result,
_Compare __comp) {
return std::__set_difference<_ClassicAlgPolicy, __comp_ref_type<_Compare> >(
__first1, __last1, __first2, __last2, __result, __comp)
return std::__set_difference<__comp_ref_type<_Compare> >(__first1, __last1, __first2, __last2, __result, __comp)
.second;
}
@ -66,7 +64,7 @@ inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_d
_InputIterator2 __first2,
_InputIterator2 __last2,
_OutputIterator __result) {
return std::__set_difference<_ClassicAlgPolicy>(
return std::__set_difference(
__first1,
__last1,
__first2,

View File

@ -12,7 +12,6 @@
#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>
@ -36,13 +35,13 @@ struct __set_symmetric_difference_result {
: __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {}
};
template <class _AlgPolicy, class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
template <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<_AlgPolicy>(std::move(__first1), std::move(__last1), std::move(__result));
auto __ret1 = std::__copy_impl(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)));
}
@ -60,7 +59,7 @@ __set_symmetric_difference(
++__first2;
}
}
auto __ret2 = std::__copy<_AlgPolicy>(std::move(__first2), std::move(__last2), std::move(__result));
auto __ret2 = std::__copy_impl(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)));
}
@ -73,7 +72,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_symmetri
_InputIterator2 __last2,
_OutputIterator __result,
_Compare __comp) {
return std::__set_symmetric_difference<_ClassicAlgPolicy, __comp_ref_type<_Compare> >(
return std::__set_symmetric_difference<__comp_ref_type<_Compare> >(
std::move(__first1),
std::move(__last1),
std::move(__first2),

View File

@ -12,7 +12,6 @@
#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>
@ -36,12 +35,12 @@ struct __set_union_result {
: __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {}
};
template <class _AlgPolicy, class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
template <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<_AlgPolicy>(std::move(__first1), std::move(__last1), std::move(__result));
auto __ret1 = std::__copy_impl(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)));
}
@ -56,7 +55,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 __set_union_result<_InIter1,
++__first1;
}
}
auto __ret2 = std::__copy<_AlgPolicy>(std::move(__first2), std::move(__last2), std::move(__result));
auto __ret2 = std::__copy_impl(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)));
}
@ -69,7 +68,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator set_union(
_InputIterator2 __last2,
_OutputIterator __result,
_Compare __comp) {
return std::__set_union<_ClassicAlgPolicy, __comp_ref_type<_Compare> >(
return std::__set_union<__comp_ref_type<_Compare> >(
std::move(__first1),
std::move(__last1),
std::move(__first2),

View File

@ -195,6 +195,12 @@ public:
#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
@ -472,6 +478,9 @@ public:
}
};
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>

View File

@ -1708,6 +1708,7 @@ template <class BidirectionalIterator, class Compare>
#include <__config>
#include <__debug>
#include <cstddef>
#include <cstring>
#include <type_traits>
#include <version>
@ -1916,7 +1917,6 @@ 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>

View File

@ -251,7 +251,6 @@ 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" }

View File

@ -4931,7 +4931,6 @@ _LIBCPP_POP_MACROS
#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20
# include <algorithm>
# include <cstring>
# include <functional>
#endif

View File

@ -0,0 +1,179 @@
//===----------------------------------------------------------------------===//
//
// 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;
}

View File

@ -1,250 +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
// <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;
}

View File

@ -1,181 +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` 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;
}

View File

@ -46,7 +46,6 @@ 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'}}

View File

@ -108,7 +108,6 @@ 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>
@ -126,7 +125,6 @@ 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*>>>();

View File

@ -111,7 +111,6 @@ 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,7 +124,6 @@ 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*>>>();

View File

@ -92,7 +92,6 @@ 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>
@ -130,7 +129,6 @@ 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*>>>();

View File

@ -85,19 +85,12 @@ 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_sentinels<bidirectional_iterator<int*>, Out>();
test_sentinels<random_access_iterator<int*>, Out>();
test_sentinels<contiguous_iterator<int*>, Out>();
test_sentinels<int*, Out>();
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>();
}
template <class Out>
@ -132,7 +125,6 @@ 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*>>>();