3 changes: 2 additions & 1 deletion libcxx/include/__algorithm/find_first_of.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredica
_LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator1 __find_first_of_ce(_ForwardIterator1 __first1,
_ForwardIterator1 __last1,
_ForwardIterator2 __first2,
_ForwardIterator2 __last2, _BinaryPredicate __pred) {
_ForwardIterator2 __last2,
_BinaryPredicate&& __pred) {
for (; __first1 != __last1; ++__first1)
for (_ForwardIterator2 __j = __first2; __j != __last2; ++__j)
if (__pred(*__first1, *__j))
Expand Down
6 changes: 2 additions & 4 deletions libcxx/include/__algorithm/inplace_merge.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
#ifndef _LIBCPP___ALGORITHM_INPLACE_MERGE_H
#define _LIBCPP___ALGORITHM_INPLACE_MERGE_H

#include <__algorithm/algorithm_family.h>
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
#include <__algorithm/iterator_operations.h>
Expand Down Expand Up @@ -65,7 +64,7 @@ void __half_inplace_merge(_InputIterator1 __first1, _Sent1 __last1,
{
if (__first2 == __last2)
{
_AlgFamily<_AlgPolicy>::__move(__first1, __last1, __result);
std::__move<_AlgPolicy>(__first1, __last1, __result);
return;
}

Expand Down Expand Up @@ -185,8 +184,7 @@ void __inplace_merge(
difference_type __len22 = __len2 - __len21; // distance(__m2, __last)
// [__first, __m1) [__m1, __middle) [__middle, __m2) [__m2, __last)
// swap middle two partitions
// TODO(alg-policy): pass `_AlgPolicy` once it's supported by `rotate`.
__middle = _VSTD::rotate(__m1, __middle, __m2);
__middle = std::__rotate<_AlgPolicy>(__m1, __middle, __m2).first;
// __len12 and __len21 now have swapped meanings
// merge smaller range with recursive call and larger with tail recursion elimination
if (__len11 + __len21 < __len12 + __len22)
Expand Down
259 changes: 168 additions & 91 deletions libcxx/include/__algorithm/is_permutation.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,151 +11,228 @@
#define _LIBCPP___ALGORITHM_IS_PERMUTATION_H

#include <__algorithm/comp.h>
#include <__algorithm/iterator_operations.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
#include <__iterator/concepts.h>
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/next.h>
#include <__utility/move.h>
#include <type_traits>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
_LIBCPP_NODISCARD_EXT _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_BinaryPredicate __pred) {
// shorten sequences as much as possible by lopping of any equal prefix
for (; __first1 != __last1; ++__first1, (void)++__first2)
if (!__pred(*__first1, *__first2))
break;
if (__first1 == __last1)
return true;
template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class = void>
struct _ConstTimeDistance : false_type {};

// __first1 != __last1 && *__first1 != *__first2
typedef typename iterator_traits<_ForwardIterator1>::difference_type _D1;
_D1 __l1 = _VSTD::distance(__first1, __last1);
if (__l1 == _D1(1))
return false;
_ForwardIterator2 __last2 = _VSTD::next(__first2, __l1);
// For each element in [f1, l1) see if there are the same number of
// equal elements in [f2, l2)
for (_ForwardIterator1 __i = __first1; __i != __last1; ++__i) {
#if _LIBCPP_STD_VER > 17

template <class _Iter1, class _Sent1, class _Iter2, class _Sent2>
struct _ConstTimeDistance<_Iter1, _Sent1, _Iter2, _Sent2, __enable_if_t<
sized_sentinel_for<_Sent1, _Iter1> &&
sized_sentinel_for<_Sent2, _Iter2>
>> : true_type {};

#else

template <class _Iter1, class _Iter2>
struct _ConstTimeDistance<_Iter1, _Iter1, _Iter2, _Iter2, __enable_if_t<
is_same<typename iterator_traits<_Iter1>::iterator_category, random_access_iterator_tag>::value &&
is_same<typename iterator_traits<_Iter2>::iterator_category, random_access_iterator_tag>::value
> > : true_type {};

#endif // _LIBCPP_STD_VER > 17

// Internal functions

// For each element in [f1, l1) see if there are the same number of equal elements in [f2, l2)
template <class _AlgPolicy,
class _Iter1, class _Sent1, class _Iter2, class _Sent2,
class _Proj1, class _Proj2, class _Pred>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
__is_permutation_impl(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2,
_Pred&& __pred, _Proj1&& __proj1, _Proj2&& __proj2) {
using _D1 = __iter_diff_t<_Iter1>;

for (auto __i = __first1; __i != __last1; ++__i) {
// Have we already counted the number of *__i in [f1, l1)?
_ForwardIterator1 __match = __first1;
for (; __match != __i; ++__match)
if (__pred(*__match, *__i))
auto __match = __first1;
for (; __match != __i; ++__match) {
if (std::__invoke(__pred, std::__invoke(__proj1, *__match), std::__invoke(__proj1, *__i)))
break;
}

if (__match == __i) {
// Count number of *__i in [f2, l2)
_D1 __c2 = 0;
for (_ForwardIterator2 __j = __first2; __j != __last2; ++__j)
if (__pred(*__i, *__j))
for (auto __j = __first2; __j != __last2; ++__j) {
if (std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj2, *__j)))
++__c2;
}
if (__c2 == 0)
return false;

// Count number of *__i in [__i, l1) (we can start with 1)
_D1 __c1 = 1;
for (_ForwardIterator1 __j = _VSTD::next(__i); __j != __last1; ++__j)
if (__pred(*__i, *__j))
for (auto __j = _IterOps<_AlgPolicy>::next(__i); __j != __last1; ++__j) {
if (std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj1, *__j)))
++__c1;
}
if (__c1 != __c2)
return false;
}
}

return true;
}

template <class _ForwardIterator1, class _ForwardIterator2>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) {
typedef typename iterator_traits<_ForwardIterator1>::value_type __v1;
typedef typename iterator_traits<_ForwardIterator2>::value_type __v2;
return _VSTD::is_permutation(__first1, __last1, __first2, __equal_to<__v1, __v2>());
// 2+1 iterators, predicate. Not used by range algorithms.
template <class _AlgPolicy, class _ForwardIterator1, class _Sentinel1, class _ForwardIterator2, class _BinaryPredicate>
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
__is_permutation(_ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2 __first2,
_BinaryPredicate&& __pred) {
// Shorten sequences as much as possible by lopping of any equal prefix.
for (; __first1 != __last1; ++__first1, (void)++__first2) {
if (!__pred(*__first1, *__first2))
break;
}

if (__first1 == __last1)
return true;

// __first1 != __last1 && *__first1 != *__first2
using _D1 = __iter_diff_t<_ForwardIterator1>;
_D1 __l1 = _IterOps<_AlgPolicy>::distance(__first1, __last1);
if (__l1 == _D1(1))
return false;
auto __last2 = _IterOps<_AlgPolicy>::next(__first2, __l1);

return std::__is_permutation_impl<_AlgPolicy>(
std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2),
__pred, __identity(), __identity());
}

#if _LIBCPP_STD_VER > 11
template <class _BinaryPredicate, class _ForwardIterator1, class _ForwardIterator2>
_LIBCPP_CONSTEXPR_AFTER_CXX17 bool
__is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2, _BinaryPredicate __pred, forward_iterator_tag, forward_iterator_tag) {
// shorten sequences as much as possible by lopping of any equal prefix
for (; __first1 != __last1 && __first2 != __last2; ++__first1, (void)++__first2)
if (!__pred(*__first1, *__first2))
// 2+2 iterators, predicate, non-constant time `distance`.
template <class _AlgPolicy,
class _Iter1, class _Sent1, class _Iter2, class _Sent2,
class _Proj1, class _Proj2, class _Pred>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
__is_permutation(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2,
_Pred&& __pred, _Proj1&& __proj1, _Proj2&& __proj2,
/*_ConstTimeDistance=*/false_type) {
// Shorten sequences as much as possible by lopping of any equal prefix.
while (__first1 != __last1 && __first2 != __last2) {
if (!std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2)))
break;
++__first1;
++__first2;
}

if (__first1 == __last1)
return __first2 == __last2;
else if (__first2 == __last2)
if (__first2 == __last2) // Second range is shorter
return false;

typedef typename iterator_traits<_ForwardIterator1>::difference_type _D1;
_D1 __l1 = _VSTD::distance(__first1, __last1);
using _D1 = __iter_diff_t<_Iter1>;
_D1 __l1 = _IterOps<_AlgPolicy>::distance(__first1, __last1);

typedef typename iterator_traits<_ForwardIterator2>::difference_type _D2;
_D2 __l2 = _VSTD::distance(__first2, __last2);
using _D2 = __iter_diff_t<_Iter2>;
_D2 __l2 = _IterOps<_AlgPolicy>::distance(__first2, __last2);
if (__l1 != __l2)
return false;

// For each element in [f1, l1) see if there are the same number of
// equal elements in [f2, l2)
for (_ForwardIterator1 __i = __first1; __i != __last1; ++__i) {
// Have we already counted the number of *__i in [f1, l1)?
_ForwardIterator1 __match = __first1;
for (; __match != __i; ++__match)
if (__pred(*__match, *__i))
break;
if (__match == __i) {
// Count number of *__i in [f2, l2)
_D1 __c2 = 0;
for (_ForwardIterator2 __j = __first2; __j != __last2; ++__j)
if (__pred(*__i, *__j))
++__c2;
if (__c2 == 0)
return false;
// Count number of *__i in [__i, l1) (we can start with 1)
_D1 __c1 = 1;
for (_ForwardIterator1 __j = _VSTD::next(__i); __j != __last1; ++__j)
if (__pred(*__i, *__j))
++__c1;
if (__c1 != __c2)
return false;
}
}
return true;
return std::__is_permutation_impl<_AlgPolicy>(
std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2),
__pred, __proj1, __proj2);
}

template <class _BinaryPredicate, class _RandomAccessIterator1, class _RandomAccessIterator2>
_LIBCPP_CONSTEXPR_AFTER_CXX17 bool __is_permutation(_RandomAccessIterator1 __first1, _RandomAccessIterator2 __last1,
_RandomAccessIterator1 __first2, _RandomAccessIterator2 __last2,
_BinaryPredicate __pred, random_access_iterator_tag,
random_access_iterator_tag) {
if (_VSTD::distance(__first1, __last1) != _VSTD::distance(__first2, __last2))
// 2+2 iterators, predicate, specialization for constant-time `distance` call.
template <class _AlgPolicy,
class _Iter1, class _Sent1, class _Iter2, class _Sent2,
class _Proj1, class _Proj2, class _Pred>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
__is_permutation(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2,
_Pred&& __pred, _Proj1&& __proj1, _Proj2&& __proj2,
/*_ConstTimeDistance=*/true_type) {
if (std::distance(__first1, __last1) != std::distance(__first2, __last2))
return false;
return _VSTD::is_permutation<_RandomAccessIterator1, _RandomAccessIterator2,
_BinaryPredicate&>(__first1, __last1, __first2, __pred);
return std::__is_permutation<_AlgPolicy>(
std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2),
__pred, __proj1, __proj2,
/*_ConstTimeDistance=*/false_type());
}

// 2+2 iterators, predicate
template <class _AlgPolicy,
class _Iter1, class _Sent1, class _Iter2, class _Sent2,
class _Proj1, class _Proj2, class _Pred>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
__is_permutation(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2,
_Pred&& __pred, _Proj1&& __proj1, _Proj2&& __proj2) {
return std::__is_permutation<_AlgPolicy>(
std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2),
__pred, __proj1, __proj2,
_ConstTimeDistance<_Iter1, _Sent1, _Iter2, _Sent2>());
}

// Public interface

// 2+1 iterators, predicate
template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2, _BinaryPredicate __pred) {
return _VSTD::__is_permutation<_BinaryPredicate&>(
__first1, __last1, __first2, __last2, __pred, typename iterator_traits<_ForwardIterator1>::iterator_category(),
typename iterator_traits<_ForwardIterator2>::iterator_category());
_BinaryPredicate __pred) {
static_assert(__is_callable<_BinaryPredicate, decltype(*__first1), decltype(*__first2)>::value,
"The predicate has to be callable");

return std::__is_permutation<_ClassicAlgPolicy>(
std::move(__first1), std::move(__last1), std::move(__first2), __pred);
}

// 2+1 iterators
template <class _ForwardIterator1, class _ForwardIterator2>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) {
using __v1 = __iter_value_type<_ForwardIterator1>;
using __v2 = __iter_value_type<_ForwardIterator2>;
return std::is_permutation(__first1, __last1, __first2, __equal_to<__v1, __v2>());
}

#if _LIBCPP_STD_VER > 11

// 2+2 iterators
template <class _ForwardIterator1, class _ForwardIterator2>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2) {
typedef typename iterator_traits<_ForwardIterator1>::value_type __v1;
typedef typename iterator_traits<_ForwardIterator2>::value_type __v2;
return _VSTD::__is_permutation(__first1, __last1, __first2, __last2, __equal_to<__v1, __v2>(),
typename iterator_traits<_ForwardIterator1>::iterator_category(),
typename iterator_traits<_ForwardIterator2>::iterator_category());
using __v1 = __iter_value_type<_ForwardIterator1>;
using __v2 = __iter_value_type<_ForwardIterator2>;

return std::__is_permutation<_ClassicAlgPolicy>(
std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2),
__equal_to<__v1, __v2>(), __identity(), __identity());
}
#endif

// 2+2 iterators, predicate
template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
is_permutation(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2,
_ForwardIterator2 __last2, _BinaryPredicate __pred) {
static_assert(__is_callable<_BinaryPredicate, decltype(*__first1), decltype(*__first2)>::value,
"The predicate has to be callable");

return std::__is_permutation<_ClassicAlgPolicy>(
std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2),
__pred, __identity(), __identity());
}

#endif // _LIBCPP_STD_VER > 11

_LIBCPP_END_NAMESPACE_STD

Expand Down
12 changes: 11 additions & 1 deletion libcxx/include/__algorithm/iterator_operations.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <__iterator/iter_swap.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/next.h>
#include <__iterator/prev.h>
#include <__iterator/readable_traits.h>
#include <__utility/declval.h>
#include <__utility/forward.h>
Expand Down Expand Up @@ -53,6 +54,7 @@ struct _IterOps<_RangeAlgPolicy> {
static constexpr auto __iter_move = ranges::iter_move;
static constexpr auto iter_swap = ranges::iter_swap;
static constexpr auto next = ranges::next;
static constexpr auto prev = ranges::prev;
static constexpr auto __advance_to = ranges::advance;
};

Expand Down Expand Up @@ -146,10 +148,18 @@ struct _IterOps<_ClassicAlgPolicy> {
template <class _Iter>
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11
__uncvref_t<_Iter> next(_Iter&& __it,
typename iterator_traits<__uncvref_t<_Iter> >::difference_type __n = 1){
typename iterator_traits<__uncvref_t<_Iter> >::difference_type __n = 1) {
return std::next(std::forward<_Iter>(__it), __n);
}

// prev
template <class _Iter>
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11
__uncvref_t<_Iter> prev(_Iter&& __iter,
typename iterator_traits<__uncvref_t<_Iter> >::difference_type __n = 1) {
return std::prev(std::forward<_Iter>(__iter), __n);
}

template <class _Iter>
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11
void __advance_to(_Iter& __first, _Iter __last) {
Expand Down
26 changes: 15 additions & 11 deletions libcxx/include/__algorithm/move.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_MOVE_H
#define _LIBCPP___ALGORITHM_MOVE_H

#include <__algorithm/iterator_operations.h>
#include <__algorithm/unwrap_iter.h>
#include <__config>
#include <__iterator/iterator_traits.h>
Expand All @@ -26,18 +27,19 @@ _LIBCPP_BEGIN_NAMESPACE_STD

// move

template <class _InIter, class _Sent, class _OutIter>
template <class _AlgPolicy, class _InIter, class _Sent, class _OutIter>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
pair<_InIter, _OutIter> __move_impl(_InIter __first, _Sent __last, _OutIter __result) {
while (__first != __last) {
*__result = std::move(*__first);
*__result = _IterOps<_AlgPolicy>::__iter_move(__first);
++__first;
++__result;
}
return std::make_pair(std::move(__first), std::move(__result));
}

template <class _InType,
template <class _AlgPolicy,
class _InType,
class _OutType,
class = __enable_if_t<is_same<typename remove_const<_InType>::type, _OutType>::value
&& is_trivially_move_assignable<_OutType>::value> >
Expand All @@ -49,7 +51,7 @@ pair<_InType*, _OutType*> __move_impl(_InType* __first, _InType* __last, _OutTyp
&& !is_trivially_copyable<_InType>::value
#endif
)
return std::__move_impl<_InType*, _InType*, _OutType*>(__first, __last, __result);
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);
Expand All @@ -65,7 +67,8 @@ 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 _InIter,
template <class _AlgPolicy,
class _InIter,
class _OutIter,
__enable_if_t<is_same<typename remove_const<typename iterator_traits<_InIter>::value_type>::type,
typename iterator_traits<_OutIter>::value_type>::value
Expand All @@ -81,33 +84,34 @@ __move_impl(reverse_iterator<_InIter> __first,
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(__last_base, __first_base, __result_first);
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 _InIter, class _Sent, class _OutIter>
template <class _AlgPolicy, class _InIter, class _Sent, class _OutIter>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
__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(std::__unwrap_iter(__first), std::__unwrap_iter(__last), std::__unwrap_iter(__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 _InIter, class _Sent, class _OutIter>
template <class _AlgPolicy, class _InIter, class _Sent, class _OutIter>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
__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(std::move(__first), std::move(__last), std::move(__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_AFTER_CXX17
_OutputIterator move(_InputIterator __first, _InputIterator __last, _OutputIterator __result) {
return std::__move(__first, __last, __result).second;
return std::__move<_ClassicAlgPolicy>(__first, __last, __result).second;
}

_LIBCPP_END_NAMESPACE_STD
Expand Down
38 changes: 24 additions & 14 deletions libcxx/include/__algorithm/move_backward.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_MOVE_BACKWARD_H
#define _LIBCPP___ALGORITHM_MOVE_BACKWARD_H

#include <__algorithm/iterator_operations.h>
#include <__algorithm/unwrap_iter.h>
#include <__config>
#include <__utility/move.h>
Expand All @@ -21,33 +22,33 @@

_LIBCPP_BEGIN_NAMESPACE_STD

template <class _InputIterator, class _OutputIterator>
template <class _AlgPolicy, class _InputIterator, class _OutputIterator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
_OutputIterator
__move_backward_constexpr(_InputIterator __first, _InputIterator __last, _OutputIterator __result)
{
while (__first != __last)
*--__result = _VSTD::move(*--__last);
*--__result = _IterOps<_AlgPolicy>::__iter_move(--__last);
return __result;
}

template <class _InputIterator, class _OutputIterator>
template <class _AlgPolicy, class _InputIterator, class _OutputIterator>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
_OutputIterator
__move_backward(_InputIterator __first, _InputIterator __last, _OutputIterator __result)
__move_backward_impl(_InputIterator __first, _InputIterator __last, _OutputIterator __result)
{
return _VSTD::__move_backward_constexpr(__first, __last, __result);
return _VSTD::__move_backward_constexpr<_AlgPolicy>(__first, __last, __result);
}

template <class _Tp, class _Up>
template <class _AlgPolicy, class _Tp, class _Up>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
typename enable_if
<
is_same<typename remove_const<_Tp>::type, _Up>::value &&
is_trivially_move_assignable<_Up>::value,
_Up*
>::type
__move_backward(_Tp* __first, _Tp* __last, _Up* __result)
__move_backward_impl(_Tp* __first, _Tp* __last, _Up* __result)
{
const size_t __n = static_cast<size_t>(__last - __first);
if (__n > 0)
Expand All @@ -58,22 +59,31 @@ __move_backward(_Tp* __first, _Tp* __last, _Up* __result)
return __result;
}

template <class _BidirectionalIterator1, class _BidirectionalIterator2>
template <class _AlgPolicy, class _BidirectionalIterator1, class _BidirectionalIterator2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
_BidirectionalIterator2
move_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last,
_BidirectionalIterator2 __result)
__move_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last,
_BidirectionalIterator2 __result)
{
if (__libcpp_is_constant_evaluated()) {
return _VSTD::__move_backward_constexpr(__first, __last, __result);
return _VSTD::__move_backward_constexpr<_AlgPolicy>(__first, __last, __result);
} else {
return _VSTD::__rewrap_iter(__result,
_VSTD::__move_backward(_VSTD::__unwrap_iter(__first),
_VSTD::__unwrap_iter(__last),
_VSTD::__unwrap_iter(__result)));
_VSTD::__move_backward_impl<_AlgPolicy>(_VSTD::__unwrap_iter(__first),
_VSTD::__unwrap_iter(__last),
_VSTD::__unwrap_iter(__result)));
}
}

template <class _BidirectionalIterator1, class _BidirectionalIterator2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
_BidirectionalIterator2
move_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last,
_BidirectionalIterator2 __result)
{
return std::__move_backward<_ClassicAlgPolicy>(std::move(__first), std::move(__last), std::move(__result));
}

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___ALGORITHM_MOVE_BACKWARD_H
65 changes: 65 additions & 0 deletions libcxx/include/__algorithm/ranges_clamp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//===----------------------------------------------------------------------===//
//
// 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_RANGES_CLAMP_H
#define _LIBCPP___ALGORITHM_RANGES_CLAMP_H

#include <__assert>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/projected.h>
#include <__utility/forward.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

_LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {
namespace __clamp {
struct __fn {

template <class _Type,
class _Proj = identity,
indirect_strict_weak_order<projected<const _Type*, _Proj>> _Comp = ranges::less>
_LIBCPP_HIDE_FROM_ABI constexpr
const _Type& operator()(const _Type& __value,
const _Type& __low,
const _Type& __high,
_Comp __comp = {},
_Proj __proj = {}) const {
_LIBCPP_ASSERT(!bool(std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __low))),
"Bad bounds passed to std::ranges::clamp");

if (std::invoke(__comp, std::invoke(__proj, __value), std::invoke(__proj, __low)))
return __low;
else if (std::invoke(__comp, std::invoke(__proj, __high), std::invoke(__proj, __value)))
return __high;
else
return __value;
}

};
} // namespace __clamp

inline namespace __cpo {
inline constexpr auto clamp = __clamp::__fn{};
} // namespace __cpo
} // namespace ranges

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

#endif // _LIBCPP___ALGORITHM_RANGES_CLAMP_H
89 changes: 89 additions & 0 deletions libcxx/include/__algorithm/ranges_is_permutation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//===----------------------------------------------------------------------===//
//
// 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_RANGES_IS_PERMUTATION_H
#define _LIBCPP___ALGORITHM_RANGES_IS_PERMUTATION_H

#include <__algorithm/is_permutation.h>
#include <__algorithm/iterator_operations.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/distance.h>
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

_LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {
namespace __is_permutation {
struct __fn {

template <class _Iter1, class _Sent1, class _Iter2, class _Sent2,
class _Proj1, class _Proj2, class _Pred>
_LIBCPP_HIDE_FROM_ABI constexpr static
bool __is_permutation_func_impl(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2,
_Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) {
return std::__is_permutation<_RangeAlgPolicy>(
std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2),
__pred, __proj1, __proj2);
}

template <forward_iterator _Iter1, sentinel_for<_Iter1> _Sent1,
forward_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
class _Proj1 = identity,
class _Proj2 = identity,
indirect_equivalence_relation<projected<_Iter1, _Proj1>,
projected<_Iter2, _Proj2>> _Pred = ranges::equal_to>
_LIBCPP_HIDE_FROM_ABI constexpr
bool operator()(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2,
_Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const {
return __is_permutation_func_impl(
std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2),
__pred, __proj1, __proj2);
}

template <forward_range _Range1,
forward_range _Range2,
class _Proj1 = identity,
class _Proj2 = identity,
indirect_equivalence_relation<projected<iterator_t<_Range1>, _Proj1>, projected<iterator_t<_Range2>, _Proj2>> _Pred = ranges::equal_to>
_LIBCPP_HIDE_FROM_ABI constexpr
bool operator()(_Range1&& __range1, _Range2&& __range2,
_Pred __pred = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const {
if constexpr (sized_range<_Range1> && sized_range<_Range2>) {
if (ranges::distance(__range1) != ranges::distance(__range2))
return false;
}

return __is_permutation_func_impl(
ranges::begin(__range1), ranges::end(__range1), ranges::begin(__range2), ranges::end(__range2),
__pred, __proj1, __proj2);
}
};
} // namespace __is_permutation

inline namespace __cpo {
inline constexpr auto is_permutation = __is_permutation::__fn{};
} // namespace __cpo
} // namespace ranges

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

#endif // _LIBCPP___ALGORITHM_RANGES_IS_PERMUTATION_H
15 changes: 2 additions & 13 deletions libcxx/include/__algorithm/ranges_move.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define _LIBCPP___ALGORITHM_RANGES_MOVE_H

#include <__algorithm/in_out_result.h>
#include <__algorithm/iterator_operations.h>
#include <__algorithm/move.h>
#include <__config>
#include <__iterator/concepts.h>
Expand All @@ -36,24 +37,12 @@ namespace __move {
struct __fn {

template <class _InIter, class _Sent, class _OutIter>
requires __iter_move::__move_deref<_InIter> // check that we are allowed to std::move() the value
_LIBCPP_HIDE_FROM_ABI constexpr static
move_result<_InIter, _OutIter> __move_impl(_InIter __first, _Sent __last, _OutIter __result) {
auto __ret = std::__move(std::move(__first), std::move(__last), std::move(__result));
auto __ret = std::__move<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__result));
return {std::move(__ret.first), std::move(__ret.second)};
}

template <class _InIter, class _Sent, class _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr static
move_result<_InIter, _OutIter> __move_impl(_InIter __first, _Sent __last, _OutIter __result) {
while (__first != __last) {
*__result = ranges::iter_move(__first);
++__first;
++__result;
}
return {std::move(__first), std::move(__result)};
}

template <input_iterator _InIter, sentinel_for<_InIter> _Sent, weakly_incrementable _OutIter>
requires indirectly_movable<_InIter, _OutIter>
_LIBCPP_HIDE_FROM_ABI constexpr
Expand Down
71 changes: 71 additions & 0 deletions libcxx/include/__algorithm/ranges_rotate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//===----------------------------------------------------------------------===//
//
// 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_RANGES_ROTATE_H
#define _LIBCPP___ALGORITHM_RANGES_ROTATE_H

#include <__algorithm/iterator_operations.h>
#include <__algorithm/ranges_iterator_concept.h>
#include <__algorithm/rotate.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/permutable.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/subrange.h>
#include <__utility/move.h>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif

#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

_LIBCPP_BEGIN_NAMESPACE_STD

namespace ranges {
namespace __rotate {

struct __fn {

template <class _Iter, class _Sent>
_LIBCPP_HIDE_FROM_ABI constexpr
static subrange<_Iter> __rotate_fn_impl(_Iter __first, _Iter __middle, _Sent __last) {
auto __ret = std::__rotate<_RangeAlgPolicy>(
std::move(__first), std::move(__middle), std::move(__last));
return {std::move(__ret.first), std::move(__ret.second)};
}

template <permutable _Iter, sentinel_for<_Iter> _Sent>
_LIBCPP_HIDE_FROM_ABI constexpr
subrange<_Iter> operator()(_Iter __first, _Iter __middle, _Sent __last) const {
return __rotate_fn_impl(std::move(__first), std::move(__middle), std::move(__last));
}

template <forward_range _Range>
requires permutable<iterator_t<_Range>>
_LIBCPP_HIDE_FROM_ABI constexpr
borrowed_subrange_t<_Range> operator()(_Range&& __range, iterator_t<_Range> __middle) const {
return __rotate_fn_impl(ranges::begin(__range), std::move(__middle), ranges::end(__range));
}

};

} // namespace __rotate

inline namespace __cpo {
inline constexpr auto rotate = __rotate::__fn{};
} // namespace __cpo
} // namespace ranges

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)

#endif // _LIBCPP___ALGORITHM_RANGES_ROTATE_H
11 changes: 5 additions & 6 deletions libcxx/include/__algorithm/ranges_swap_ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#define _LIBCPP___ALGORITHM_RANGES_SWAP_RANGES_H

#include <__algorithm/in_in_result.h>
#include <__algorithm/iterator_operations.h>
#include <__algorithm/swap_ranges.h>
#include <__config>
#include <__iterator/concepts.h>
#include <__iterator/iter_swap.h>
Expand Down Expand Up @@ -38,12 +40,9 @@ struct __fn {
requires indirectly_swappable<_I1, _I2>
_LIBCPP_HIDE_FROM_ABI constexpr swap_ranges_result<_I1, _I2>
operator()(_I1 __first1, _S1 __last1, _I2 __first2, _S2 __last2) const {
while (__first1 != __last1 && __first2 != __last2) {
ranges::iter_swap(__first1, __first2);
++__first1;
++__first2;
}
return {_VSTD::move(__first1), _VSTD::move(__first2)};
auto __ret = std::__swap_ranges<_RangeAlgPolicy>(
std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2));
return {std::move(__ret.first), std::move(__ret.second)};
}

template <input_range _R1, input_range _R2>
Expand Down
57 changes: 32 additions & 25 deletions libcxx/include/__algorithm/rotate.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@
#include <__algorithm/swap_ranges.h>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__iterator/next.h>
#include <__iterator/prev.h>
#include <__utility/move.h>
#include <__utility/swap.h>
#include <__utility/pair.h>
#include <type_traits>

#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand All @@ -32,9 +30,11 @@ _LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator
__rotate_left(_ForwardIterator __first, _ForwardIterator __last)
{
typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
value_type __tmp = _IterOps<_AlgPolicy>::__iter_move(__first);
// TODO(ranges): pass `_AlgPolicy` to `move`.
_ForwardIterator __lm1 = _VSTD::move(_VSTD::next(__first), __last, __first);
using _Ops = _IterOps<_AlgPolicy>;

value_type __tmp = _Ops::__iter_move(__first);
_ForwardIterator __lm1 = std::__move<_AlgPolicy>(
_Ops::next(__first), __last, __first).second;
*__lm1 = _VSTD::move(__tmp);
return __lm1;
}
Expand All @@ -44,11 +44,11 @@ _LIBCPP_CONSTEXPR_AFTER_CXX11 _BidirectionalIterator
__rotate_right(_BidirectionalIterator __first, _BidirectionalIterator __last)
{
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
// TODO(ranges): pass `_AlgPolicy` to `prev`.
_BidirectionalIterator __lm1 = _VSTD::prev(__last);
value_type __tmp = _IterOps<_AlgPolicy>::__iter_move(__lm1);
// TODO(ranges): pass `_AlgPolicy` to `move_backward`.
_BidirectionalIterator __fp1 = _VSTD::move_backward(__first, __lm1, __last);
using _Ops = _IterOps<_AlgPolicy>;

_BidirectionalIterator __lm1 = _Ops::prev(__last);
value_type __tmp = _Ops::__iter_move(__lm1);
_BidirectionalIterator __fp1 = std::__move_backward<_AlgPolicy>(__first, __lm1, std::move(__last));
*__first = _VSTD::move(__tmp);
return __fp1;
}
Expand Down Expand Up @@ -108,26 +108,26 @@ __rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _Ran
{
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
using _Ops = _IterOps<_AlgPolicy>;

const difference_type __m1 = __middle - __first;
const difference_type __m2 = __last - __middle;
const difference_type __m2 = _Ops::distance(__middle, __last);
if (__m1 == __m2)
{
// TODO(ranges): pass `_AlgPolicy` to `swap_ranges`.
_VSTD::swap_ranges(__first, __middle, __middle);
std::__swap_ranges<_AlgPolicy>(__first, __middle, __middle, __last);
return __middle;
}
const difference_type __g = _VSTD::__algo_gcd(__m1, __m2);
for (_RandomAccessIterator __p = __first + __g; __p != __first;)
{
value_type __t(_IterOps<_AlgPolicy>::__iter_move(--__p));
value_type __t(_Ops::__iter_move(--__p));
_RandomAccessIterator __p1 = __p;
_RandomAccessIterator __p2 = __p1 + __m1;
do
{
*__p1 = _IterOps<_AlgPolicy>::__iter_move(__p2);
*__p1 = _Ops::__iter_move(__p2);
__p1 = __p2;
const difference_type __d = __last - __p2;
const difference_type __d = _Ops::distance(__p2, __last);
if (__m1 < __d)
__p2 += __m1;
else
Expand Down Expand Up @@ -188,25 +188,32 @@ __rotate_impl(_RandomAccessIterator __first, _RandomAccessIterator __middle, _Ra
return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
}

template <class _AlgPolicy, class _RandomAccessIterator, class _IterCategory>
template <class _AlgPolicy, class _Iterator, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
_RandomAccessIterator __rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle,
_RandomAccessIterator __last, _IterCategory __iter_category) {
pair<_Iterator, _Iterator>
__rotate(_Iterator __first, _Iterator __middle, _Sentinel __last) {
using _Ret = pair<_Iterator, _Iterator>;
_Iterator __last_iter = _IterOps<_AlgPolicy>::next(__middle, __last);

if (__first == __middle)
return __last;
return _Ret(__last_iter, __last_iter);
if (__middle == __last)
return __first;
return _Ret(std::move(__first), std::move(__last_iter));

using _IterCategory = typename _IterOps<_AlgPolicy>::template __iterator_category<_Iterator>;
auto __result = std::__rotate_impl<_AlgPolicy>(
std::move(__first), std::move(__middle), __last_iter, _IterCategory());

return std::__rotate_impl<_AlgPolicy>(std::move(__first), std::move(__middle), std::move(__last), __iter_category);
return _Ret(std::move(__result), std::move(__last_iter));
}

template <class _ForwardIterator>
inline _LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last)
{
return std::__rotate<_ClassicAlgPolicy>(__first, __middle, __last,
typename iterator_traits<_ForwardIterator>::iterator_category());
return std::__rotate<_ClassicAlgPolicy>(
std::move(__first), std::move(__middle), std::move(__last)).first;
}

_LIBCPP_END_NAMESPACE_STD
Expand Down
4 changes: 2 additions & 2 deletions libcxx/include/__algorithm/stable_partition.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ __stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Pred
__second_half_done:
// TTTFFFFFTTTTTFFFFF
// f ff m sf l
return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false, __fit);
return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false).first;
// TTTTTTTTFFFFFFFFFF
// |
}
Expand Down Expand Up @@ -253,7 +253,7 @@ __stable_partition_impl(_BidirectionalIterator __first, _BidirectionalIterator _
__second_half_done:
// TTTFFFFFTTTTTFFFFF
// f ff m sf l
return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false, __bit);
return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false).first;
// TTTTTTTTFFFFFFFFFF
// |
}
Expand Down
37 changes: 33 additions & 4 deletions libcxx/include/__algorithm/swap_ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,50 @@
#ifndef _LIBCPP___ALGORITHM_SWAP_RANGES_H
#define _LIBCPP___ALGORITHM_SWAP_RANGES_H

#include <__algorithm/iterator_operations.h>
#include <__config>
#include <__utility/swap.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

// 2+2 iterators: the shorter size will be used.
template <class _AlgPolicy, class _ForwardIterator1, class _Sentinel1, class _ForwardIterator2, class _Sentinel2>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
pair<_ForwardIterator1, _ForwardIterator2>
__swap_ranges(_ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2 __first2, _Sentinel2 __last2) {
while (__first1 != __last1 && __first2 != __last2) {
_IterOps<_AlgPolicy>::iter_swap(__first1, __first2);
++__first1;
++__first2;
}

return pair<_ForwardIterator1, _ForwardIterator2>(std::move(__first1), std::move(__first2));
}

// 2+1 iterators: size2 >= size1.
template <class _AlgPolicy, class _ForwardIterator1, class _Sentinel1, class _ForwardIterator2>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
pair<_ForwardIterator1, _ForwardIterator2>
__swap_ranges(_ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2 __first2) {
while (__first1 != __last1) {
_IterOps<_AlgPolicy>::iter_swap(__first1, __first2);
++__first1;
++__first2;
}

return pair<_ForwardIterator1, _ForwardIterator2>(std::move(__first1), std::move(__first2));
}

template <class _ForwardIterator1, class _ForwardIterator2>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator2
swap_ranges(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) {
for (; __first1 != __last1; ++__first1, (void)++__first2)
swap(*__first1, *__first2);
return __first2;
return std::__swap_ranges<_ClassicAlgPolicy>(
std::move(__first1), std::move(__last1), std::move(__first2)).second;
}

_LIBCPP_END_NAMESPACE_STD
Expand Down
24 changes: 7 additions & 17 deletions libcxx/include/__availability
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,11 @@
// user has provided their own).
//
// Users can pass -D_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED
// to the compiler to tell the library to ignore the fact that the
// default function isn't available on their deployment target. Note that
// defining this macro but failing to define a custom function will lead to
// a load-time error on back-deployment targets, so it should be avoided.
# define _LIBCPP_AVAILABILITY_DEFAULT_VERBOSE_ABORT
// to the compiler to tell the library not to define its own verbose abort.
// Note that defining this macro but failing to define a custom function
// will lead to a load-time error on back-deployment targets, so it should
// be avoided.
// # define _LIBCPP_HAS_NO_VERBOSE_ABORT_IN_LIBRARY

#elif defined(__APPLE__)

Expand Down Expand Up @@ -271,8 +271,8 @@
__attribute__((unavailable))
# define _LIBCPP_AVAILABILITY_DISABLE_FTM___cpp_lib_format

# define _LIBCPP_AVAILABILITY_DEFAULT_VERBOSE_ABORT \
__attribute__((unavailable))
# define _LIBCPP_HAS_NO_VERBOSE_ABORT_IN_LIBRARY

#else

// ...New vendors can add availability markup here...
Expand All @@ -296,14 +296,4 @@
# define _LIBCPP_AVAILABILITY_THROW_BAD_VARIANT_ACCESS _LIBCPP_AVAILABILITY_BAD_VARIANT_ACCESS
#endif

// Define the special verbose termination function availability attribute, which can be silenced by
// users if they provide their own custom function. The rest of the code should not use the
// *_DEFAULT_* macro directly, since that would make it ignore the fact that the user provided
// a custom function.
#if defined(_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED)
# define _LIBCPP_AVAILABILITY_VERBOSE_ABORT /* nothing */
#else
# define _LIBCPP_AVAILABILITY_VERBOSE_ABORT _LIBCPP_AVAILABILITY_DEFAULT_VERBOSE_ABORT
#endif

#endif // _LIBCPP___AVAILABILITY
6 changes: 6 additions & 0 deletions libcxx/include/__iterator/iterator_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,12 @@ using __iterator_category_type = typename iterator_traits<_Iter>::iterator_categ
template <class _Iter>
using __iterator_pointer_type = typename iterator_traits<_Iter>::pointer;

template <class _Iter>
using __iter_diff_t = typename iterator_traits<_Iter>::difference_type;

template<class _InputIterator>
using __iter_value_type = typename iterator_traits<_InputIterator>::value_type;

_LIBCPP_END_NAMESPACE_STD

#endif // _LIBCPP___ITERATOR_ITERATOR_TRAITS_H
10 changes: 9 additions & 1 deletion libcxx/include/__iterator/reverse_iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ class __unconstrained_reverse_iterator {
_Iter __iter_;

public:
static_assert(__is_cpp17_bidirectional_iterator<_Iter>::value);
static_assert(__is_cpp17_bidirectional_iterator<_Iter>::value || bidirectional_iterator<_Iter>);

using iterator_type = _Iter;
using iterator_category =
Expand Down Expand Up @@ -391,6 +391,14 @@ class __unconstrained_reverse_iterator {
}
}

_LIBCPP_HIDE_FROM_ABI friend constexpr
iter_rvalue_reference_t<_Iter> iter_move(const __unconstrained_reverse_iterator& __i)
noexcept(is_nothrow_copy_constructible_v<_Iter> &&
noexcept(ranges::iter_move(--declval<_Iter&>()))) {
auto __tmp = __i.base();
return ranges::iter_move(--__tmp);
}

_LIBCPP_HIDE_FROM_ABI constexpr __unconstrained_reverse_iterator& operator++() {
--__iter_;
return *this;
Expand Down
25 changes: 23 additions & 2 deletions libcxx/include/__memory/pointer_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,30 @@ _Tp* __to_address(_Tp* __p) _NOEXCEPT {
return __p;
}

template <class _Pointer, class = void>
struct _HasToAddress : false_type {};

template <class _Pointer>
struct _HasToAddress<_Pointer,
decltype((void)pointer_traits<_Pointer>::to_address(declval<const _Pointer&>()))
> : true_type {};

template <class _Pointer, class = void>
struct _HasArrow : false_type {};

template <class _Pointer>
struct _HasArrow<_Pointer,
decltype((void)declval<const _Pointer&>().operator->())
> : true_type {};

template <class _Pointer>
struct _IsFancyPointer {
static const bool value = _HasArrow<_Pointer>::value || _HasToAddress<_Pointer>::value;
};

// enable_if is needed here to avoid instantiating checks for fancy pointers on raw pointers
template <class _Pointer, class = __enable_if_t<
!is_pointer<_Pointer>::value && !is_array<_Pointer>::value && !is_function<_Pointer>::value
_And<is_class<_Pointer>, _IsFancyPointer<_Pointer> >::value
> >
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
typename decay<decltype(__to_address_helper<_Pointer>::__call(declval<const _Pointer&>()))>::type
Expand Down Expand Up @@ -208,7 +229,7 @@ auto to_address(_Tp *__p) noexcept {

template <class _Pointer>
inline _LIBCPP_INLINE_VISIBILITY constexpr
auto to_address(const _Pointer& __p) noexcept {
auto to_address(const _Pointer& __p) noexcept -> decltype(std::__to_address(__p)) {
return _VSTD::__to_address(__p);
}
#endif
Expand Down
25 changes: 24 additions & 1 deletion libcxx/include/__verbose_abort
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,34 @@
# pragma GCC system_header
#endif

// Provide a default implementation of __libcpp_verbose_abort if we know that neither the built
// library not the user is providing one. Otherwise, just declare it and use the one from the
// built library or the one provided by the user.
//
// We can't provide a great implementation because it needs to be pretty much
// dependency-free (this is included everywhere else in the library).
#if defined(_LIBCPP_HAS_NO_VERBOSE_ABORT_IN_LIBRARY) && !defined(_LIBCPP_AVAILABILITY_CUSTOM_VERBOSE_ABORT_PROVIDED)

extern "C" void abort();

_LIBCPP_BEGIN_NAMESPACE_STD

_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_AVAILABILITY_VERBOSE_ABORT _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2)
_LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2) _LIBCPP_HIDE_FROM_ABI inline
void __libcpp_verbose_abort(const char *, ...) {
::abort();
}

_LIBCPP_END_NAMESPACE_STD

#else

_LIBCPP_BEGIN_NAMESPACE_STD

_LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 2)
void __libcpp_verbose_abort(const char *__format, ...);

_LIBCPP_END_NAMESPACE_STD

#endif

#endif // _LIBCPP___VERBOSE_ABORT
30 changes: 30 additions & 0 deletions libcxx/include/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,11 @@ namespace ranges {
constexpr borrowed_iterator_t<R>
ranges::replace_if(R&& r, Pred pred, const T& new_value, Proj proj = {}); // since C++20
template<class T, class Proj = identity,
indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
constexpr const T&
ranges::clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {}); // since C++20
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
class Proj1 = identity, class Proj2 = identity,
indirect_strict_weak_order<projected<I1, Proj1>,
Expand Down Expand Up @@ -745,6 +750,13 @@ namespace ranges {
constexpr ranges::reverse_copy_result<borrowed_iterator_t<R>, O>
ranges::reverse_copy(R&& r, O result); // since C++20
template<permutable I, sentinel_for<I> S>
constexpr subrange<I> rotate(I first, I middle, S last); // since C++20
template<forward_range R>
requires permutable<iterator_t<R>>
constexpr borrowed_subrange_t<R> rotate(R&& r, iterator_t<R> middle); // Since C++20
template <class _InIter, class _OutIter>
using rotate_copy_result = in_out_result<_InIter, _OutIter>; // since C++20
Expand Down Expand Up @@ -780,6 +792,21 @@ namespace ranges {
uniform_random_bit_generator<remove_reference_t<Gen>>
borrowed_iterator_t<R> shuffle(R&& r, Gen&& g); // Since C++20
template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
sentinel_for<I2> S2, class Proj1 = identity, class Proj2 = identity,
indirect_equivalence_relation<projected<I1, Proj1>,
projected<I2, Proj2>> Pred = ranges::equal_to>
constexpr bool ranges::is_permutation(I1 first1, S1 last1, I2 first2, S2 last2,
Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {}); // Since C++20
template<forward_range R1, forward_range R2,
class Proj1 = identity, class Proj2 = identity,
indirect_equivalence_relation<projected<iterator_t<R1>, Proj1>,
projected<iterator_t<R2>, Proj2>> Pred = ranges::equal_to>
constexpr bool ranges::is_permutation(R1&& r1, R2&& r2, Pred pred = {},
Proj1 proj1 = {}, Proj2 proj2 = {}); // Since C++20
template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
sentinel_for<I2> S2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
Expand Down Expand Up @@ -1757,6 +1784,7 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_all_of.h>
#include <__algorithm/ranges_any_of.h>
#include <__algorithm/ranges_binary_search.h>
#include <__algorithm/ranges_clamp.h>
#include <__algorithm/ranges_copy.h>
#include <__algorithm/ranges_copy_backward.h>
#include <__algorithm/ranges_copy_if.h>
Expand All @@ -1781,6 +1809,7 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_is_heap.h>
#include <__algorithm/ranges_is_heap_until.h>
#include <__algorithm/ranges_is_partitioned.h>
#include <__algorithm/ranges_is_permutation.h>
#include <__algorithm/ranges_is_sorted.h>
#include <__algorithm/ranges_is_sorted_until.h>
#include <__algorithm/ranges_lexicographical_compare.h>
Expand Down Expand Up @@ -1817,6 +1846,7 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_replace_if.h>
#include <__algorithm/ranges_reverse.h>
#include <__algorithm/ranges_reverse_copy.h>
#include <__algorithm/ranges_rotate.h>
#include <__algorithm/ranges_rotate_copy.h>
#include <__algorithm/ranges_sample.h>
#include <__algorithm/ranges_search.h>
Expand Down
4 changes: 3 additions & 1 deletion libcxx/include/module.modulemap.in
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,6 @@ module std [system] {

module __algorithm {
module adjacent_find { private header "__algorithm/adjacent_find.h" }
module algorithm_family { private header "__algorithm/algorithm_family.h" }
module all_of { private header "__algorithm/all_of.h" }
module any_of { private header "__algorithm/any_of.h" }
module binary_search { private header "__algorithm/binary_search.h" }
Expand Down Expand Up @@ -312,6 +311,7 @@ module std [system] {
module ranges_all_of { private header "__algorithm/ranges_all_of.h" }
module ranges_any_of { private header "__algorithm/ranges_any_of.h" }
module ranges_binary_search { private header "__algorithm/ranges_binary_search.h" }
module ranges_clamp { private header "__algorithm/ranges_clamp.h" }
module ranges_copy { private header "__algorithm/ranges_copy.h" }
module ranges_copy_backward { private header "__algorithm/ranges_copy_backward.h" }
module ranges_copy_if { private header "__algorithm/ranges_copy_if.h" }
Expand All @@ -336,6 +336,7 @@ module std [system] {
module ranges_is_heap { private header "__algorithm/ranges_is_heap.h" }
module ranges_is_heap_until { private header "__algorithm/ranges_is_heap_until.h" }
module ranges_is_partitioned { private header "__algorithm/ranges_is_partitioned.h" }
module ranges_is_permutation { private header "__algorithm/ranges_is_permutation.h" }
module ranges_is_sorted { private header "__algorithm/ranges_is_sorted.h" }
module ranges_is_sorted_until { private header "__algorithm/ranges_is_sorted_until.h" }
module ranges_iterator_concept { private header "__algorithm/ranges_iterator_concept.h" }
Expand Down Expand Up @@ -373,6 +374,7 @@ module std [system] {
module ranges_replace_if { private header "__algorithm/ranges_replace_if.h" }
module ranges_reverse { private header "__algorithm/ranges_reverse.h" }
module ranges_reverse_copy { private header "__algorithm/ranges_reverse_copy.h" }
module ranges_rotate { private header "__algorithm/ranges_rotate.h" }
module ranges_rotate_copy { private header "__algorithm/ranges_rotate_copy.h" }
module ranges_sample { private header "__algorithm/ranges_sample.h" }
module ranges_search { private header "__algorithm/ranges_search.h" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ constexpr bool all_the_algorithms()
(void)std::ranges::any_of(a, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::binary_search(first, last, value, Less(&copies)); assert(copies == 0);
(void)std::ranges::binary_search(a, value, Less(&copies)); assert(copies == 0);
//(void)std::ranges::clamp(value, value, value, Less(&copies)); assert(copies == 0);
(void)std::ranges::clamp(value, value, value, Less(&copies)); assert(copies == 0);
(void)std::ranges::count_if(first, last, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::count_if(a, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::copy_if(first, last, first2, UnaryTrue(&copies)); assert(copies == 0);
Expand All @@ -121,9 +121,9 @@ constexpr bool all_the_algorithms()
(void)std::ranges::for_each(first, last, UnaryVoid(&copies)); assert(copies == 1); copies = 0;
(void)std::ranges::for_each(a, UnaryVoid(&copies)); assert(copies == 1); copies = 0;
(void)std::ranges::for_each_n(first, count, UnaryVoid(&copies)); assert(copies == 1); copies = 0;
//(void)std::ranges::generate(first, last, NullaryValue(&copies)); assert(copies == 0);
//(void)std::ranges::generate(a, NullaryValue(&copies)); assert(copies == 0);
//(void)std::ranges::generate_n(first, count, NullaryValue(&copies)); assert(copies == 0);
(void)std::ranges::generate(first, last, NullaryValue(&copies)); assert(copies == 0);
(void)std::ranges::generate(a, NullaryValue(&copies)); assert(copies == 0);
(void)std::ranges::generate_n(first, count, NullaryValue(&copies)); assert(copies == 0);
(void)std::ranges::includes(first, last, first2, last2, Less(&copies)); assert(copies == 0);
(void)std::ranges::includes(a, b, Less(&copies)); assert(copies == 0);
(void)std::ranges::is_heap(first, last, Less(&copies)); assert(copies == 0);
Expand All @@ -132,8 +132,8 @@ constexpr bool all_the_algorithms()
(void)std::ranges::is_heap_until(a, Less(&copies)); assert(copies == 0);
(void)std::ranges::is_partitioned(first, last, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::is_partitioned(a, UnaryTrue(&copies)); assert(copies == 0);
//(void)std::ranges::is_permutation(first, last, first2, last2, Equal(&copies)); assert(copies == 0);
//(void)std::ranges::is_permutation(a, b, Equal(&copies)); assert(copies == 0);
(void)std::ranges::is_permutation(first, last, first2, last2, Equal(&copies)); assert(copies == 0);
(void)std::ranges::is_permutation(a, b, Equal(&copies)); assert(copies == 0);
(void)std::ranges::is_sorted(first, last, Less(&copies)); assert(copies == 0);
(void)std::ranges::is_sorted(a, Less(&copies)); assert(copies == 0);
(void)std::ranges::is_sorted_until(first, last, Less(&copies)); assert(copies == 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ constexpr bool all_the_algorithms()
(void)std::ranges::any_of(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::binary_search(first, last, value, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::binary_search(a, value, Less(), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::clamp(T(), T(), T(), Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::clamp(T(), T(), T(), Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::count(first, last, value, Proj(&copies)); assert(copies == 0);
(void)std::ranges::count(a, value, Proj(&copies)); assert(copies == 0);
(void)std::ranges::count_if(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
Expand Down Expand Up @@ -115,8 +115,8 @@ constexpr bool all_the_algorithms()
(void)std::ranges::is_heap_until(a, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::is_partitioned(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::is_partitioned(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::is_permutation(first, last, first2, last2, Equal(), Proj(&copies), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::is_permutation(a, b, Equal(), Proj(&copies), Proj(&copies)); assert(copies == 0);
(void)std::ranges::is_permutation(first, last, first2, last2, Equal(), Proj(&copies), Proj(&copies)); assert(copies == 0);
(void)std::ranges::is_permutation(a, b, Equal(), Proj(&copies), Proj(&copies)); assert(copies == 0);
(void)std::ranges::is_sorted(first, last, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::is_sorted(a, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::is_sorted_until(first, last, Less(), Proj(&copies)); assert(copies == 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ TEST_CONSTEXPR_CXX20 bool all_the_algorithms()
#endif
(void)std::equal_range(first, last, value, Less<T>(&copies)); assert(copies == 0);
(void)std::find_end(first, last, first2, mid2, Equal<T>(&copies)); assert(copies == 0);
//(void)std::find_first_of(first, last, first2, last2, Equal(&copies)); assert(copies == 0);
(void)std::find_first_of(first, last, first2, last2, Equal<T>(&copies)); assert(copies == 0);
(void)std::find_if(first, last, UnaryTrue<T>(&copies)); assert(copies == 0);
(void)std::find_if_not(first, last, UnaryTrue<T>(&copies)); assert(copies == 0);
(void)std::for_each(first, last, UnaryVoid<T>(&copies)); assert(copies == 1); copies = 0;
Expand Down

This file was deleted.

4 changes: 0 additions & 4 deletions libcxx/test/libcxx/assertions/default_verbose_abort.pass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,6 @@

// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1

// We flag uses of the verbose termination function in older dylibs at compile-time to avoid runtime
// failures when back-deploying.
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}}

#include <csignal>
#include <cstdlib>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@

// Test that all public C++ headers define the verbose termination function.

// We flag uses of the verbose termination function in older dylibs at compile-time to avoid runtime
// failures when back-deploying.
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}}

// The system-provided <uchar.h> seems to be broken on AIX, which trips up this test.
// XFAIL: LIBCXX-AIX-FIXME

Expand Down
4 changes: 0 additions & 4 deletions libcxx/test/libcxx/assertions/single_expression.sh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,6 @@
// RUN: %{build} -Wno-macro-redefined -D_LIBCPP_ENABLE_ASSERTIONS=0 -D_LIBCPP_ASSERTIONS_DISABLE_ASSUME
// RUN: %{run}

// We flag uses of the assertion handler in older dylibs at compile-time to avoid runtime
// failures when back-deploying.
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}}

#include <__assert>
#include <cassert>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// UNSUPPORTED: clang-13, clang-14

// AppleClang does not support the -fexperimental-library flag yet
// UNSUPPORTED: apple-clang-13
// UNSUPPORTED: apple-clang-13, apple-clang-14.0

// Clang on AIX currently pretends that it is Clang 15, even though it is not (as of writing
// this, LLVM 15 hasn't even been branched yet).
Expand Down
4 changes: 3 additions & 1 deletion libcxx/test/libcxx/private_headers.verify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ END-SCRIPT
// DO NOT MANUALLY EDIT ANYTHING BETWEEN THE MARKERS BELOW
// GENERATED-MARKER
#include <__algorithm/adjacent_find.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/adjacent_find.h'}}
#include <__algorithm/algorithm_family.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/algorithm_family.h'}}
#include <__algorithm/all_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/all_of.h'}}
#include <__algorithm/any_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/any_of.h'}}
#include <__algorithm/binary_search.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/binary_search.h'}}
Expand Down Expand Up @@ -110,6 +109,7 @@ END-SCRIPT
#include <__algorithm/ranges_all_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_all_of.h'}}
#include <__algorithm/ranges_any_of.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_any_of.h'}}
#include <__algorithm/ranges_binary_search.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_binary_search.h'}}
#include <__algorithm/ranges_clamp.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_clamp.h'}}
#include <__algorithm/ranges_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy.h'}}
#include <__algorithm/ranges_copy_backward.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy_backward.h'}}
#include <__algorithm/ranges_copy_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_copy_if.h'}}
Expand All @@ -134,6 +134,7 @@ END-SCRIPT
#include <__algorithm/ranges_is_heap.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_heap.h'}}
#include <__algorithm/ranges_is_heap_until.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_heap_until.h'}}
#include <__algorithm/ranges_is_partitioned.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_partitioned.h'}}
#include <__algorithm/ranges_is_permutation.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_permutation.h'}}
#include <__algorithm/ranges_is_sorted.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_sorted.h'}}
#include <__algorithm/ranges_is_sorted_until.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_is_sorted_until.h'}}
#include <__algorithm/ranges_iterator_concept.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_iterator_concept.h'}}
Expand Down Expand Up @@ -171,6 +172,7 @@ END-SCRIPT
#include <__algorithm/ranges_replace_if.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_replace_if.h'}}
#include <__algorithm/ranges_reverse.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_reverse.h'}}
#include <__algorithm/ranges_reverse_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_reverse_copy.h'}}
#include <__algorithm/ranges_rotate.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_rotate.h'}}
#include <__algorithm/ranges_rotate_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_rotate_copy.h'}}
#include <__algorithm/ranges_sample.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_sample.h'}}
#include <__algorithm/ranges_search.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/ranges_search.h'}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-has-no-incomplete-ranges

// <algorithm>

// template<permutable I, sentinel_for<I> S>
// constexpr subrange<I> rotate(I first, I middle, S last); // since C++20
//
// template<forward_range R>
// requires permutable<iterator_t<R>>
// constexpr borrowed_subrange_t<R> rotate(R&& r, iterator_t<R> middle); // Since C++20

#include <algorithm>
#include <array>
#include <cassert>
#include <ranges>

#include "almost_satisfies_types.h"
#include "test_iterators.h"

// Test constraints of the (iterator, sentinel) overload.
// ======================================================

template <class Iter = int*, class Sent = int*>
concept HasRotateIter =
requires(Iter&& iter, Sent&& sent) {
std::ranges::rotate(std::forward<Iter>(iter), std::forward<Iter>(iter), std::forward<Sent>(sent));
};

static_assert(HasRotateIter<int*, int*>);

// !permutable<I>
static_assert(!HasRotateIter<PermutableNotForwardIterator>);
static_assert(!HasRotateIter<PermutableNotSwappable>);

// !sentinel_for<S, I>
static_assert(!HasRotateIter<int*, SentinelForNotSemiregular>);
static_assert(!HasRotateIter<int*, SentinelForNotWeaklyEqualityComparableWith>);

// Test constraints of the (range) overload.
// =========================================

template <class Range>
concept HasRotateRange =
requires(Range&& range, std::ranges::iterator_t<Range> iter) {
std::ranges::rotate(std::forward<Range>(range), iter);
};

template <class T>
using R = UncheckedRange<T>;

static_assert(HasRotateRange<R<int*>>);

// !forward_range<R>
static_assert(!HasRotateRange<ForwardRangeNotDerivedFrom>);
static_assert(!HasRotateRange<ForwardRangeNotIncrementable>);
static_assert(!HasRotateRange<ForwardRangeNotSentinelSemiregular>);
static_assert(!HasRotateRange<ForwardRangeNotSentinelEqualityComparableWith>);

// !permutable<iterator_t<R>>
static_assert(!HasRotateRange<PermutableRangeNotForwardIterator>);
static_assert(!HasRotateRange<PermutableRangeNotSwappable>);

template <class Iter, class Sent, size_t N>
constexpr void test_one(const std::array<int, N> input, size_t mid_index, std::array<int, N> expected) {
assert(mid_index <= N);

{ // (iterator, sentinel) overload.
auto in = input;
auto begin = Iter(in.data());
auto mid = Iter(in.data() + mid_index);
auto end = Sent(Iter(in.data() + in.size()));

std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::rotate(begin, mid, end);
assert(base(result.begin()) == in.data() + in.size() - mid_index);
assert(base(result.end()) == in.data() + in.size());
assert(in == expected);
}

{ // (range) overload.
auto in = input;
auto begin = Iter(in.data());
auto mid = Iter(in.data() + mid_index);
auto end = Sent(Iter(in.data() + in.size()));
auto range = std::ranges::subrange(std::move(begin), std::move(end));

std::same_as<std::ranges::subrange<Iter>> decltype(auto) result = std::ranges::rotate(range, mid);
assert(base(result.begin()) == in.data() + in.size() - mid_index);
assert(base(result.end()) == in.data() + in.size());
assert(in == expected);
}
}

template <class Iter, class Sent>
constexpr void test_iter_sent() {
// Empty sequence.
test_one<Iter, Sent, 0>({}, 0, {});

// 1-element sequence.
test_one<Iter, Sent, 1>({1}, 0, {1});

// 2-element sequence.
test_one<Iter, Sent, 2>({1, 2}, 1, {2, 1});

// 3-element sequence.
test_one<Iter, Sent, 3>({1, 2, 3}, 1, {2, 3, 1});
test_one<Iter, Sent, 3>({1, 2, 3}, 2, {3, 1, 2});

// Longer sequence.
test_one<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, 2, {3, 4, 5, 6, 7, 1, 2});

// Rotate around the middle.
test_one<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, 3, {4, 5, 6, 7, 1, 2, 3});

// Rotate around the 1st element (no-op).
test_one<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, 0, {1, 2, 3, 4, 5, 6, 7});

// Rotate around the 2nd element.
test_one<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, 1, {2, 3, 4, 5, 6, 7, 1});

// Rotate around the last element.
test_one<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, 6, {7, 1, 2, 3, 4, 5, 6});

// Pass `end()` as `mid` (no-op).
test_one<Iter, Sent, 7>({1, 2, 3, 4, 5, 6, 7}, 7, {1, 2, 3, 4, 5, 6, 7});
}

template <class Iter>
constexpr void test_iter() {
test_iter_sent<Iter, Iter>();
test_iter_sent<Iter, sentinel_wrapper<Iter>>();
}

constexpr void test_iterators() {
test_iter<forward_iterator<int*>>();
test_iter<bidirectional_iterator<int*>>();
test_iter<random_access_iterator<int*>>();
test_iter<contiguous_iterator<int*>>();
test_iter<int*>();
}

constexpr bool test() {
test_iterators();

{ // Complexity: at most `last - first` swaps.
const std::array input = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
auto expected = static_cast<int>(input.size());

{
auto in = input;
int swaps = 0;
auto begin = adl::Iterator::TrackSwaps(in.data(), swaps);
auto end = adl::Iterator::TrackSwaps(in.data() + in.size(), swaps);

for (size_t mid = 0; mid != input.size(); ++mid) {
std::ranges::rotate(begin, begin + mid, end);
assert(swaps <= expected);
}
}

{
auto in = input;
int swaps = 0;
auto begin = adl::Iterator::TrackSwaps(in.data(), swaps);
auto end = adl::Iterator::TrackSwaps(in.data() + in.size(), swaps);
auto range = std::ranges::subrange(begin, end);

for (size_t mid = 0; mid != input.size(); ++mid) {
std::ranges::rotate(range, begin + mid);
assert(swaps <= expected);
}
}
}

return true;
}

int main(int, char**) {
test();
static_assert(test());

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-has-no-incomplete-ranges

// <algorithm>

// template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
// sentinel_for<I2> S2, class Proj1 = identity, class Proj2 = identity,
// indirect_equivalence_relation<projected<I1, Proj1>,
// projected<I2, Proj2>> Pred = ranges::equal_to>
// constexpr bool ranges::is_permutation(I1 first1, S1 last1, I2 first2, S2 last2,
// Pred pred = {},
// Proj1 proj1 = {}, Proj2 proj2 = {}); // Since C++20
//
// template<forward_range R1, forward_range R2,
// class Proj1 = identity, class Proj2 = identity,
// indirect_equivalence_relation<projected<iterator_t<R1>, Proj1>,
// projected<iterator_t<R2>, Proj2>> Pred = ranges::equal_to>
// constexpr bool ranges::is_permutation(R1&& r1, R2&& r2, Pred pred = {},
// Proj1 proj1 = {}, Proj2 proj2 = {}); // Since C++20

#include <algorithm>
#include <array>
#include <concepts>
#include <list>
#include <ranges>

#include "almost_satisfies_types.h"
#include "counting_predicates.h"
#include "counting_projection.h"
#include "test_iterators.h"

template <class Iter1, class Sent1 = int*, class Iter2 = int*, class Sent2 = int*>
concept HasIsPermutationIt = requires(Iter1 first1, Sent1 last1, Iter2 first2, Sent2 last2) {
std::ranges::is_permutation(first1, last1, first2, last2);
};

template <class Range1, class Range2 = UncheckedRange<int*>>
concept HasIsPermutationR = requires(Range1 range1, Range2 range2) {
std::ranges::is_permutation(range1, range2);
};

static_assert(HasIsPermutationIt<int*>);
static_assert(!HasIsPermutationIt<ForwardIteratorNotDerivedFrom>);
static_assert(!HasIsPermutationIt<ForwardIteratorNotIncrementable>);
static_assert(!HasIsPermutationIt<int*, SentinelForNotSemiregular>);
static_assert(!HasIsPermutationIt<int*, SentinelForNotWeaklyEqualityComparableWith>);
static_assert(!HasIsPermutationIt<int*, int*, ForwardIteratorNotDerivedFrom>);
static_assert(!HasIsPermutationIt<int*, int*, ForwardIteratorNotIncrementable>);
static_assert(!HasIsPermutationIt<int*, int*, int*, SentinelForNotSemiregular>);
static_assert(!HasIsPermutationIt<int*, int*, int*, SentinelForNotWeaklyEqualityComparableWith>);
// !indirect_equivalence_relation<Pred, projected<I1, Proj1>, projected<I2, Proj2>>;
static_assert(!HasIsPermutationIt<int*, int*, int**, int**>);

static_assert(HasIsPermutationR<UncheckedRange<int*>>);
static_assert(!HasIsPermutationR<ForwardRangeNotDerivedFrom>);
static_assert(!HasIsPermutationR<ForwardRangeNotIncrementable>);
static_assert(!HasIsPermutationR<int*, ForwardRangeNotSentinelSemiregular>);
static_assert(!HasIsPermutationR<int*, ForwardRangeNotSentinelEqualityComparableWith>);
static_assert(!HasIsPermutationR<UncheckedRange<int*>, ForwardRangeNotDerivedFrom>);
static_assert(!HasIsPermutationR<UncheckedRange<int*>, ForwardRangeNotIncrementable>);
static_assert(!HasIsPermutationR<UncheckedRange<int*>, ForwardRangeNotSentinelSemiregular>);
static_assert(!HasIsPermutationR<UncheckedRange<int*>, ForwardRangeNotSentinelEqualityComparableWith>);
// !indirect_equivalence_relation<Pred, projected<iterator_t<I1>, Proj1>, projected<iterator_t<I2>, Proj2>>;
static_assert(!HasIsPermutationIt<UncheckedRange<int*>, UncheckedRange<int**>>);

template <int N, int M>
struct Data {
std::array<int, N> input1;
std::array<int, M> input2;
bool expected;
};

template <class Iter1, class Sent1, class Iter2, class Sent2, int N, int M>
constexpr void test(Data<N, M> d) {
{
std::same_as<bool> decltype(auto) ret = std::ranges::is_permutation(Iter1(d.input1.data()),
Sent1(Iter1(d.input1.data() + N)),
Iter1(d.input2.data()),
Sent1(Iter1(d.input2.data() + M)));
assert(ret == d.expected);
}
{
auto range1 = std::ranges::subrange(Iter1(d.input1.data()), Sent1(Iter1(d.input1.data() + N)));
auto range2 = std::ranges::subrange(Iter1(d.input2.data()), Sent1(Iter1(d.input2.data() + M)));
std::same_as<bool> decltype(auto) ret = std::ranges::is_permutation(range1, range2);
assert(ret == d.expected);
}
}

template <class Iter1, class Sent1, class Iter2, class Sent2 = Iter2>
constexpr void test_iterators() {
// Ranges are identical.
test<Iter1, Sent1, Iter2, Sent2, 4, 4>({.input1 = {1, 2, 3, 4}, .input2 = {1, 2, 3, 4}, .expected = true});

// Ranges are reversed.
test<Iter1, Sent1, Iter2, Sent2, 4, 4>({.input1 = {1, 2, 3, 4}, .input2 = {4, 3, 2, 1}, .expected = true});

// Two elements are swapped.
test<Iter1, Sent1, Iter2, Sent2, 4, 4>({.input1 = {4, 2, 3, 1}, .input2 = {1, 2, 3, 4}, .expected = true});

// The first range is shorter.
test<Iter1, Sent1, Iter2, Sent2, 4, 5>({.input1 = {4, 2, 3, 1}, .input2 = {4, 3, 2, 1, 5}, .expected = false});

// The first range is longer.
test<Iter1, Sent1, Iter2, Sent2, 5, 4>({.input1 = {4, 2, 3, 1, 5}, .input2 = {4, 3, 2, 1}, .expected = false});

// The first range is empty.
test<Iter1, Sent1, Iter2, Sent2, 0, 4>({.input1 = {}, .input2 = {4, 3, 2, 1}, .expected = false});

// The second range is empty.
test<Iter1, Sent1, Iter2, Sent2, 5, 0>({.input1 = {4, 2, 3, 1, 5}, .input2 = {}, .expected = false});

// Both ranges are empty.
test<Iter1, Sent1, Iter2, Sent2, 0, 0>({.input1 = {}, .input2 = {}, .expected = true});

// 1-element range, same value.
test<Iter1, Sent1, Iter2, Sent2, 1, 1>({.input1 = {1}, .input2 = {1}, .expected = true});

// 1-element range, different values.
test<Iter1, Sent1, Iter2, Sent2, 1, 1>({.input1 = {1}, .input2 = {2}, .expected = false});
}

template <class Iter1, class Sent1 = Iter1>
constexpr void test_iterators1() {
test_iterators<Iter1, Sent1, forward_iterator<int*>, sentinel_wrapper<forward_iterator<int*>>>();
test_iterators<Iter1, Sent1, forward_iterator<int*>>();
test_iterators<Iter1, Sent1, bidirectional_iterator<int*>>();
test_iterators<Iter1, Sent1, random_access_iterator<int*>>();
test_iterators<Iter1, Sent1, contiguous_iterator<int*>>();
test_iterators<Iter1, Sent1, int*>();
test_iterators<Iter1, Sent1, const int*>();
}

constexpr bool test() {
test_iterators1<forward_iterator<int*>, sentinel_wrapper<forward_iterator<int*>>>();
test_iterators1<forward_iterator<int*>>();
test_iterators1<bidirectional_iterator<int*>>();
test_iterators1<random_access_iterator<int*>>();
test_iterators1<contiguous_iterator<int*>>();
test_iterators1<int*>();
test_iterators1<const int*>();

{ // A custom comparator works.
struct A {
int a;
constexpr bool pred(const A& rhs) const { return a == rhs.a; }
};

std::array in1 = {A{2}, A{3}, A{1}};
std::array in2 = {A{1}, A{2}, A{3}};

{
auto ret = std::ranges::is_permutation(in1.begin(), in1.end(), in2.begin(), in2.end(), &A::pred);
assert(ret);
}

{
auto ret = std::ranges::is_permutation(in1, in2, &A::pred);
assert(ret);
}
}

{ // A custom projection works.
struct A {
int a;

constexpr bool operator==(const A&) const = default;

constexpr A x2() const { return A{a * 2}; }
constexpr A div2() const { return A{a / 2}; }
};

std::array in1 = {A{1}, A{2}, A{3}}; // [2, 4, 6] after applying `x2`.
std::array in2 = {A{4}, A{8}, A{12}}; // [2, 4, 6] after applying `div2`.

{
auto ret = std::ranges::is_permutation(
in1.begin(), in1.end(), in2.begin(), in2.end(), {}, &A::x2, &A::div2);
assert(ret);
}

{
auto ret = std::ranges::is_permutation(in1, in2, {}, &A::x2, &A::div2);
assert(ret);
}
}


{ // Check that complexity requirements are met.
int predCount = 0;
int proj1Count = 0;
int proj2Count = 0;
auto reset_counters = [&] {
predCount = proj1Count = proj2Count = 0;
};

counting_predicate pred(std::ranges::equal_to{}, predCount);
counting_projection<> proj1(proj1Count);
counting_projection<> proj2(proj2Count);

{
// 1. No applications of the corresponding predicate if `ForwardIterator1` and `ForwardIterator2` meet the
// requirements of random access iterators and `last1 - first1 != last2 - first2`.
int a[] = {1, 2, 3, 4, 5};
int b[] = {1, 2, 3, 4};
// Make sure that the iterators have different types.
auto b_begin = random_access_iterator<int*>(std::begin(b));
auto b_end = random_access_iterator<int*>(std::end(b));

{
auto ret = std::ranges::is_permutation(a, a + 5, b_begin, b_end, pred, proj1, proj2);
assert(!ret);

assert(predCount == 0);
assert(proj1Count == 0);
assert(proj2Count == 0);
reset_counters();
}

{
auto ret = std::ranges::is_permutation(a, std::ranges::subrange(b_begin, b_end), pred, proj1, proj2);
assert(!ret);

assert(predCount == 0);
assert(proj1Count == 0);
assert(proj2Count == 0);
reset_counters();
}
}

// 2. Otherwise, exactly last1 - first1 applications of the corresponding predicate if
// `equal(first1, last1, first2, last2, pred)` would return true.
{
int a[] = {1, 2, 3, 4, 5};
int b[] = {1, 2, 3, 4, 5};
int expected = 5;

{
auto ret = std::ranges::is_permutation(a, a + 5, b, b + 5, pred, proj1, proj2);
assert(ret);

assert(predCount == expected);
assert(proj1Count == expected);
assert(proj2Count == expected);
reset_counters();
}

{
auto ret = std::ranges::is_permutation(a, b, pred, proj1, proj2);
assert(ret);

assert(predCount == expected);
assert(proj1Count == expected);
assert(proj2Count == expected);
reset_counters();
}
}

// Note: we currently don't have the setup to test big-O complexity, but copying the requirement for completeness'
// sake.
// 3. Otherwise, at worst `O(N^2)`, where `N` has the value `last1 - first1`.
}


return true;
}

int main(int, char**) {
test();
static_assert(test());

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// REQUIRES: has-unix-headers
// UNSUPPORTED: c++03, c++11, c++14, c++17, libcpp-has-no-incomplete-ranges
// XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0}}
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1

// <algorithm>

// In a call to `ranges::clamp(val, low, high)`, `low` must be `<= high`.

#include <algorithm>
#include <functional>

#include "check_assertion.h"

int main(int, char**) {
std::ranges::clamp(1, 2, 0, std::ranges::greater{});
TEST_LIBCPP_ASSERT_FAILURE(std::ranges::clamp(1, 2, 0), "Bad bounds passed to std::ranges::clamp");

std::ranges::clamp(1, 0, 2);
TEST_LIBCPP_ASSERT_FAILURE(std::ranges::clamp(1, 0, 2, std::ranges::greater{}),
"Bad bounds passed to std::ranges::clamp");

std::ranges::clamp(1, 1, 1); // Equal bounds should be fine.

return 0;
}
123 changes: 123 additions & 0 deletions libcxx/test/std/algorithms/alg.sorting/alg.clamp/ranges.clamp.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// <algorithm>

// UNSUPPORTED: c++03, c++11, c++14, c++17
// UNSUPPORTED: libcpp-has-no-incomplete-ranges

// Older Clangs don't properly deduce decltype(auto) with a concept constraint
// XFAIL: apple-clang-13.0

// template<class T, class Proj = identity,
// indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
// constexpr const T&
// ranges::clamp(const T& v, const T& lo, const T& hi, Comp comp = {}, Proj proj = {});

#include <algorithm>
#include <cassert>
#include <functional>
#include <utility>

template <class T, class Comp = std::ranges::less, class Proj = std::identity>
concept HasClamp =
requires(T&& val, T&& low, T&& high, Comp&& comp, Proj&& proj) {
std::ranges::clamp(std::forward<T>(val), std::forward<T>(low), std::forward<T>(high),
std::forward<Comp>(comp), std::forward<Proj>(proj));
};

struct NoComp {};
struct CreateNoComp {
auto operator()(int) const { return NoComp(); }
};

static_assert(HasClamp<int, std::ranges::less, std::identity>);
static_assert(!HasClamp<NoComp>);
static_assert(!HasClamp<int, NoComp>);
static_assert(!HasClamp<int, std::ranges::less, CreateNoComp>);

constexpr bool test() {
{ // low < val < high
int val = 2;
int low = 1;
int high = 3;
std::same_as<const int&> decltype(auto) ret = std::ranges::clamp(val, low, high);
assert(ret == 2);
assert(&ret == &val);
}

{ // low > val < high
assert(std::ranges::clamp(10, 20, 30) == 20);
}

{ // low < val > high
assert(std::ranges::clamp(15, 5, 10) == 10);
}

{ // low == val == high
int val = 10;
assert(&std::ranges::clamp(val, 10, 10) == &val);
}

{ // Check that a custom comparator works.
assert(std::ranges::clamp(10, 30, 20, std::ranges::greater{}) == 20);
}

{ // Check that a custom projection works.
struct S {
int i;

constexpr const int& lvalue_proj() const { return i; }
constexpr int prvalue_proj() const { return i; }
};

struct Comp {
constexpr bool operator()(const int& lhs, const int& rhs) const { return lhs < rhs; }
constexpr bool operator()(int&& lhs, int&& rhs) const { return lhs > rhs; }
};

auto val = S{10};
auto low = S{20};
auto high = S{30};
// Check that the value category of the projection return type is preserved.
assert(&std::ranges::clamp(val, low, high, Comp{}, &S::lvalue_proj) == &low);
assert(&std::ranges::clamp(val, high, low, Comp{}, &S::prvalue_proj) == &low);
}

{ // Check that the implementation doesn't cause double moves (which could result from calling the projection on
// `value` once and then forwarding the result into the comparator).
struct CheckDoubleMove {
int i;
bool moved = false;

constexpr explicit CheckDoubleMove(int set_i) : i(set_i) {}
constexpr CheckDoubleMove(const CheckDoubleMove&) = default;
constexpr CheckDoubleMove(CheckDoubleMove&& rhs) noexcept : i(rhs.i) {
assert(!rhs.moved);
rhs.moved = true;
}
};

auto val = CheckDoubleMove{20};
auto low = CheckDoubleMove{10};
auto high = CheckDoubleMove{30};

auto moving_comp = [](CheckDoubleMove lhs, CheckDoubleMove rhs) { return lhs.i < rhs.i; };
auto prvalue_proj = [](const CheckDoubleMove& x) -> CheckDoubleMove { return x; };
assert(&std::ranges::clamp(val, low, high, moving_comp, prvalue_proj) == &val);
}

return true;
}

int main(int, char**) {
test();
static_assert(test());

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "test_iterators.h"
#include "MoveOnly.h"

const int LargeN = 128;

template<int N, class T, class Iter>
TEST_CONSTEXPR_CXX20 bool test()
{
Expand Down Expand Up @@ -61,14 +63,14 @@ int main(int, char**)
{
test<7, int, int*>();
test<7, int, random_access_iterator<int*> >();
test<257, int, int*>();
test<257, int, random_access_iterator<int*> >();
test<LargeN, int, int*>();
test<LargeN, int, random_access_iterator<int*> >();

#if TEST_STD_VER >= 11
test<7, MoveOnly, MoveOnly*>();
test<7, MoveOnly, random_access_iterator<MoveOnly*> >();
test<257, MoveOnly, MoveOnly*>();
test<257, MoveOnly, random_access_iterator<MoveOnly*> >();
test<LargeN, MoveOnly, MoveOnly*>();
test<LargeN, MoveOnly, random_access_iterator<MoveOnly*> >();
#endif

test_pointers<17, char, char**>();
Expand All @@ -80,26 +82,26 @@ int main(int, char**)

#if TEST_STD_VER >= 20
test<7, int, contiguous_iterator<int*>>();
test<257, int, contiguous_iterator<int*>>();
test<LargeN, int, contiguous_iterator<int*>>();
test<7, MoveOnly, contiguous_iterator<MoveOnly*>>();
test<257, MoveOnly, contiguous_iterator<MoveOnly*>>();
test<LargeN, MoveOnly, contiguous_iterator<MoveOnly*>>();
test_pointers<17, char, contiguous_iterator<char**>>();
test_pointers<17, const char, contiguous_iterator<const char**>>();
test_pointers<17, int, contiguous_iterator<int**>>();

static_assert(test<7, int, int*>());
static_assert(test<7, int, random_access_iterator<int*>>());
static_assert(test<7, int, contiguous_iterator<int*>>());
static_assert(test<257, int, int*>());
static_assert(test<257, int, random_access_iterator<int*>>());
static_assert(test<257, int, contiguous_iterator<int*>>());
static_assert(test<LargeN, int, int*>());
static_assert(test<LargeN, int, random_access_iterator<int*>>());
static_assert(test<LargeN, int, contiguous_iterator<int*>>());

static_assert(test<7, MoveOnly, MoveOnly*>());
static_assert(test<7, MoveOnly, random_access_iterator<MoveOnly*>>());
static_assert(test<7, MoveOnly, contiguous_iterator<MoveOnly*>>());
static_assert(test<257, MoveOnly, MoveOnly*>());
static_assert(test<257, MoveOnly, random_access_iterator<MoveOnly*>>());
static_assert(test<257, MoveOnly, contiguous_iterator<MoveOnly*>>());
static_assert(test<LargeN, MoveOnly, MoveOnly*>());
static_assert(test<LargeN, MoveOnly, random_access_iterator<MoveOnly*>>());
static_assert(test<LargeN, MoveOnly, contiguous_iterator<MoveOnly*>>());

static_assert(test_pointers<17, char, char**>());
static_assert(test_pointers<17, char, random_access_iterator<char**>>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
#include "test_iterators.h"
#include "MoveOnly.h"

const int LargeN = 128;

template<int N, class T, class Iter>
TEST_CONSTEXPR_CXX20 bool test()
{
Expand Down Expand Up @@ -62,14 +64,14 @@ int main(int, char**)
{
test<7, int, int*>();
test<7, int, random_access_iterator<int*> >();
test<257, int, int*>();
test<257, int, random_access_iterator<int*> >();
test<LargeN, int, int*>();
test<LargeN, int, random_access_iterator<int*> >();

#if TEST_STD_VER >= 11
test<7, MoveOnly, MoveOnly*>();
test<7, MoveOnly, random_access_iterator<MoveOnly*> >();
test<257, MoveOnly, MoveOnly*>();
test<257, MoveOnly, random_access_iterator<MoveOnly*> >();
test<LargeN, MoveOnly, MoveOnly*>();
test<LargeN, MoveOnly, random_access_iterator<MoveOnly*> >();
#endif

test_pointers<17, char, char**>();
Expand All @@ -81,26 +83,26 @@ int main(int, char**)

#if TEST_STD_VER >= 20
test<7, int, contiguous_iterator<int*>>();
test<257, int, contiguous_iterator<int*>>();
test<LargeN, int, contiguous_iterator<int*>>();
test<7, MoveOnly, contiguous_iterator<MoveOnly*>>();
test<257, MoveOnly, contiguous_iterator<MoveOnly*>>();
test<LargeN, MoveOnly, contiguous_iterator<MoveOnly*>>();
test_pointers<17, char, contiguous_iterator<char**>>();
test_pointers<17, const char, contiguous_iterator<const char**>>();
test_pointers<17, int, contiguous_iterator<int**>>();

static_assert(test<7, int, int*>());
static_assert(test<7, int, random_access_iterator<int*>>());
static_assert(test<7, int, contiguous_iterator<int*>>());
static_assert(test<257, int, int*>());
static_assert(test<257, int, random_access_iterator<int*>>());
static_assert(test<257, int, contiguous_iterator<int*>>());
static_assert(test<LargeN, int, int*>());
static_assert(test<LargeN, int, random_access_iterator<int*>>());
static_assert(test<LargeN, int, contiguous_iterator<int*>>());

static_assert(test<7, MoveOnly, MoveOnly*>());
static_assert(test<7, MoveOnly, random_access_iterator<MoveOnly*>>());
static_assert(test<7, MoveOnly, contiguous_iterator<MoveOnly*>>());
static_assert(test<257, MoveOnly, MoveOnly*>());
static_assert(test<257, MoveOnly, random_access_iterator<MoveOnly*>>());
static_assert(test<257, MoveOnly, contiguous_iterator<MoveOnly*>>());
static_assert(test<LargeN, MoveOnly, MoveOnly*>());
static_assert(test<LargeN, MoveOnly, random_access_iterator<MoveOnly*>>());
static_assert(test<LargeN, MoveOnly, contiguous_iterator<MoveOnly*>>());

static_assert(test_pointers<17, char, char**>());
static_assert(test_pointers<17, char, random_access_iterator<char**>>());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ static_assert(std::is_same_v<in_out_result<int, long>, remove_copy_result<int, l
static_assert(std::is_same_v<in_out_result<int, long>, remove_copy_if_result<int, long>>);
static_assert(std::is_same_v<in_out_result<int, long>, replace_copy_result<int, long>>);
static_assert(std::is_same_v<in_out_result<int, long>, replace_copy_if_result<int, long>>);
// static_assert(std::is_same_v<in_out_result<int, long>, reverse_copy_result<int, long>>);
// static_assert(std::is_same_v<in_out_result<int, long>, rotate_copy_result<int, long>>);
static_assert(std::is_same_v<in_out_result<int, long>, reverse_copy_result<int, long>>);
static_assert(std::is_same_v<in_out_result<int, long>, rotate_copy_result<int, long>>);
static_assert(std::is_same_v<in_out_result<int, long>, set_difference_result<int, long>>);
static_assert(std::is_same_v<in_out_result<int, long>, unary_transform_result<int, long>>);
static_assert(std::is_same_v<in_out_result<int, long>, uninitialized_copy_result<int, long>>);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,10 @@ constexpr bool test_all() {
using std::ranges::mismatch_result;
using std::ranges::move_result;
using std::ranges::move_backward_result;
using std::ranges::next_permutation_result;
using std::ranges::partial_sort_copy_result;
using std::ranges::partition_copy_result;
using std::ranges::prev_permutation_result;
using std::ranges::remove_copy_result;
using std::ranges::remove_copy_if_result;
using std::ranges::replace_copy_result;
Expand Down Expand Up @@ -181,7 +183,7 @@ constexpr bool test_all() {
dangling_1st(std::ranges::remove, in, x);
dangling_1st(std::ranges::remove_if, in, unary_pred);
dangling_1st(std::ranges::reverse, in);
//dangling_1st(std::ranges::rotate, in, mid);
dangling_1st(std::ranges::rotate, in, mid);
if (!std::is_constant_evaluated()) // `shuffle` isn't `constexpr`.
dangling_1st(std::ranges::shuffle, in, rand_gen());
dangling_1st(std::ranges::unique, in);
Expand All @@ -199,8 +201,8 @@ constexpr bool test_all() {
dangling_1st(std::ranges::push_heap, in);
dangling_1st(std::ranges::pop_heap, in);
dangling_1st(std::ranges::sort_heap, in);
//dangling_1st(std::ranges::prev_permutation, in);
//dangling_1st(std::ranges::next_permutation, in);
dangling_1st<prev_permutation_result<dangling>>(std::ranges::prev_permutation, in);
dangling_1st<next_permutation_result<dangling>>(std::ranges::next_permutation, in);

return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ constexpr bool test_all() {

test(std::ranges::equal, in, in2, eq, proj1, proj2);
test(std::ranges::lexicographical_compare, in, in2, eq, proj1, proj2);
//test(std::ranges::is_permutation, in, in2, eq, proj1, proj2);
test(std::ranges::is_permutation, in, in2, eq, proj1, proj2);
test(std::ranges::includes, in, in2, less, proj1, proj2);
test(std::ranges::find_first_of, in, in2, eq, proj1, proj2);
test(std::ranges::mismatch, in, in2, eq, proj1, proj2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ constexpr bool test_all() {
test(std::ranges::includes, in, in2, binary_pred);
test(std::ranges::is_heap, in, binary_pred);
test(std::ranges::is_heap_until, in, binary_pred);
//std::ranges::clamp(2, 1, 3, binary_pred);
//test(std::ranges::is_permutation, in, in2, binary_pred);
std::ranges::clamp(2, 1, 3, binary_pred);
test(std::ranges::is_permutation, in, in2, binary_pred);
test(std::ranges::copy_if, in, out, unary_pred);
test(std::ranges::remove_copy_if, in, out, unary_pred);
test(std::ranges::replace_if, in, unary_pred, x);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ constexpr bool test_all() {

Bar a{Foo{1}};
Bar b{Foo{2}};
//Bar c{Foo{3}};
Bar c{Foo{3}};

Foo x{2};
size_t count = 1;
Expand Down Expand Up @@ -116,8 +116,8 @@ constexpr bool test_all() {
test(std::ranges::includes, in, in2, &Foo::binary_pred, &Bar::val, &Bar::val);
test(std::ranges::is_heap, in, &Foo::binary_pred, &Bar::val);
test(std::ranges::is_heap_until, in, &Foo::binary_pred, &Bar::val);
//std::ranges::clamp(b, a, c, &Foo::binary_pred);
//test(std::ranges::is_permutation, in, in2, &Foo::binary_pred, &Bar::val, &Bar::val);
std::ranges::clamp(b, a, c, &Foo::binary_pred, &Bar::val);
test(std::ranges::is_permutation, in, in2, &Foo::binary_pred, &Bar::val, &Bar::val);
test(std::ranges::for_each, in, &Foo::unary_pred, &Bar::val);
std::ranges::for_each_n(in.begin(), count, &Foo::unary_pred, &Bar::val);
// `copy`, `copy_n` and `copy_backward` have neither a projection nor a predicate.
Expand Down
Loading