diff --git a/libcxx/include/__algorithm/make_projected.h b/libcxx/include/__algorithm/make_projected.h index ec854763a5a291..3a86701118146e 100644 --- a/libcxx/include/__algorithm/make_projected.h +++ b/libcxx/include/__algorithm/make_projected.h @@ -96,7 +96,7 @@ decltype(auto) __make_projected_comp(_Comp& __comp, _Proj1& __proj1, _Proj2& __p return __comp; } else { - return [&](auto&& __lhs, auto&& __rhs) { + return [&](auto&& __lhs, auto&& __rhs) -> bool { return std::invoke(__comp, std::invoke(__proj1, std::forward(__lhs)), std::invoke(__proj2, std::forward(__rhs))); diff --git a/libcxx/include/__algorithm/ranges_find_if_not.h b/libcxx/include/__algorithm/ranges_find_if_not.h index 6beade1462e099..a18bea43165e0d 100644 --- a/libcxx/include/__algorithm/ranges_find_if_not.h +++ b/libcxx/include/__algorithm/ranges_find_if_not.h @@ -39,14 +39,14 @@ struct __fn { indirect_unary_predicate> _Pred> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __first, _Sp __last, _Pred __pred, _Proj __proj = {}) const { - auto __pred2 = [&](auto&& __e) { return !std::invoke(__pred, std::forward(__e)); }; + auto __pred2 = [&](auto&& __e) -> bool { return !std::invoke(__pred, std::forward(__e)); }; return ranges::__find_if_impl(std::move(__first), std::move(__last), __pred2, __proj); } template , _Proj>> _Pred> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Rp> operator()(_Rp&& __r, _Pred __pred, _Proj __proj = {}) const { - auto __pred2 = [&](auto&& __e) { return !std::invoke(__pred, std::forward(__e)); }; + auto __pred2 = [&](auto&& __e) -> bool { return !std::invoke(__pred, std::forward(__e)); }; return ranges::__find_if_impl(ranges::begin(__r), ranges::end(__r), __pred2, __proj); } }; diff --git a/libcxx/include/__algorithm/ranges_max.h b/libcxx/include/__algorithm/ranges_max.h index 5cc418d3393cef..782ce2670f0553 100644 --- a/libcxx/include/__algorithm/ranges_max.h +++ b/libcxx/include/__algorithm/ranges_max.h @@ -56,7 +56,7 @@ struct __fn { operator()(initializer_list<_Tp> __il, _Comp __comp = {}, _Proj __proj = {}) const { _LIBCPP_ASSERT_UNCATEGORIZED(__il.begin() != __il.end(), "initializer_list must contain at least one element"); - auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) { return std::invoke(__comp, __rhs, __lhs); }; + auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool { return std::invoke(__comp, __rhs, __lhs); }; return *ranges::__min_element_impl(__il.begin(), __il.end(), __comp_lhs_rhs_swapped, __proj); } @@ -72,7 +72,9 @@ struct __fn { _LIBCPP_ASSERT_UNCATEGORIZED(__first != __last, "range must contain at least one element"); if constexpr (forward_range<_Rp> && !__is_cheap_to_copy>) { - auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) { return std::invoke(__comp, __rhs, __lhs); }; + auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool { + return std::invoke(__comp, __rhs, __lhs); + }; return *ranges::__min_element_impl(std::move(__first), std::move(__last), __comp_lhs_rhs_swapped, __proj); } else { range_value_t<_Rp> __result = *__first; diff --git a/libcxx/include/__algorithm/ranges_max_element.h b/libcxx/include/__algorithm/ranges_max_element.h index 2d92661c810999..2ba97042f1f6e0 100644 --- a/libcxx/include/__algorithm/ranges_max_element.h +++ b/libcxx/include/__algorithm/ranges_max_element.h @@ -37,7 +37,7 @@ struct __fn { indirect_strict_weak_order> _Comp = ranges::less> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __first, _Sp __last, _Comp __comp = {}, _Proj __proj = {}) const { - auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) { return std::invoke(__comp, __rhs, __lhs); }; + auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool { return std::invoke(__comp, __rhs, __lhs); }; return ranges::__min_element_impl(__first, __last, __comp_lhs_rhs_swapped, __proj); } @@ -46,7 +46,7 @@ struct __fn { indirect_strict_weak_order, _Proj>> _Comp = ranges::less> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Rp> operator()(_Rp&& __r, _Comp __comp = {}, _Proj __proj = {}) const { - auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) { return std::invoke(__comp, __rhs, __lhs); }; + auto __comp_lhs_rhs_swapped = [&](auto&& __lhs, auto&& __rhs) -> bool { return std::invoke(__comp, __rhs, __lhs); }; return ranges::__min_element_impl(ranges::begin(__r), ranges::end(__r), __comp_lhs_rhs_swapped, __proj); } }; diff --git a/libcxx/include/__algorithm/ranges_remove.h b/libcxx/include/__algorithm/ranges_remove.h index bf0928df599ceb..e27c4bdd733d81 100644 --- a/libcxx/include/__algorithm/ranges_remove.h +++ b/libcxx/include/__algorithm/ranges_remove.h @@ -36,7 +36,7 @@ struct __fn { requires indirect_binary_predicate, const _Type*> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> operator()(_Iter __first, _Sent __last, const _Type& __value, _Proj __proj = {}) const { - auto __pred = [&](auto&& __other) { return __value == __other; }; + auto __pred = [&](auto&& __other) -> bool { return __value == __other; }; return ranges::__remove_if_impl(std::move(__first), std::move(__last), __pred, __proj); } @@ -45,7 +45,7 @@ struct __fn { indirect_binary_predicate, _Proj>, const _Type*> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range> operator()(_Range&& __range, const _Type& __value, _Proj __proj = {}) const { - auto __pred = [&](auto&& __other) { return __value == __other; }; + auto __pred = [&](auto&& __other) -> bool { return __value == __other; }; return ranges::__remove_if_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj); } }; diff --git a/libcxx/include/__algorithm/ranges_remove_copy.h b/libcxx/include/__algorithm/ranges_remove_copy.h index 457d593957adb5..5158a78e481405 100644 --- a/libcxx/include/__algorithm/ranges_remove_copy.h +++ b/libcxx/include/__algorithm/ranges_remove_copy.h @@ -47,7 +47,7 @@ struct __fn { indirect_binary_predicate, const _Type*> _LIBCPP_HIDE_FROM_ABI constexpr remove_copy_result<_InIter, _OutIter> operator()(_InIter __first, _Sent __last, _OutIter __result, const _Type& __value, _Proj __proj = {}) const { - auto __pred = [&](auto&& __val) { return __value == __val; }; + auto __pred = [&](auto&& __val) -> bool { return __value == __val; }; return ranges::__remove_copy_if_impl(std::move(__first), std::move(__last), std::move(__result), __pred, __proj); } @@ -56,7 +56,7 @@ struct __fn { indirect_binary_predicate, _Proj>, const _Type*> _LIBCPP_HIDE_FROM_ABI constexpr remove_copy_result, _OutIter> operator()(_Range&& __range, _OutIter __result, const _Type& __value, _Proj __proj = {}) const { - auto __pred = [&](auto&& __val) { return __value == __val; }; + auto __pred = [&](auto&& __val) -> bool { return __value == __val; }; return ranges::__remove_copy_if_impl( ranges::begin(__range), ranges::end(__range), std::move(__result), __pred, __proj); } diff --git a/libcxx/include/__algorithm/ranges_replace.h b/libcxx/include/__algorithm/ranges_replace.h index 714fd5c7b089f2..b66a41aa8d0d77 100644 --- a/libcxx/include/__algorithm/ranges_replace.h +++ b/libcxx/include/__algorithm/ranges_replace.h @@ -36,7 +36,7 @@ struct __fn { indirect_binary_predicate, const _Type1*> _LIBCPP_HIDE_FROM_ABI constexpr _Iter operator()( _Iter __first, _Sent __last, const _Type1& __old_value, const _Type2& __new_value, _Proj __proj = {}) const { - auto __pred = [&](const auto& __val) { return __val == __old_value; }; + auto __pred = [&](const auto& __val) -> bool { return __val == __old_value; }; return ranges::__replace_if_impl(std::move(__first), std::move(__last), __pred, __new_value, __proj); } @@ -45,7 +45,7 @@ struct __fn { indirect_binary_predicate, _Proj>, const _Type1*> _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> operator()(_Range&& __range, const _Type1& __old_value, const _Type2& __new_value, _Proj __proj = {}) const { - auto __pred = [&](auto&& __val) { return __val == __old_value; }; + auto __pred = [&](auto&& __val) -> bool { return __val == __old_value; }; return ranges::__replace_if_impl(ranges::begin(__range), ranges::end(__range), __pred, __new_value, __proj); } }; diff --git a/libcxx/include/__algorithm/ranges_replace_copy.h b/libcxx/include/__algorithm/ranges_replace_copy.h index 124ff8f2c559d1..a7627024812fd2 100644 --- a/libcxx/include/__algorithm/ranges_replace_copy.h +++ b/libcxx/include/__algorithm/ranges_replace_copy.h @@ -53,7 +53,7 @@ struct __fn { const _OldType& __old_value, const _NewType& __new_value, _Proj __proj = {}) const { - auto __pred = [&](const auto& __value) { return __value == __old_value; }; + auto __pred = [&](const auto& __value) -> bool { return __value == __old_value; }; return ranges::__replace_copy_if_impl( std::move(__first), std::move(__last), std::move(__result), __pred, __new_value, __proj); } @@ -68,7 +68,7 @@ struct __fn { _LIBCPP_HIDE_FROM_ABI constexpr replace_copy_result, _OutIter> operator()( _Range&& __range, _OutIter __result, const _OldType& __old_value, const _NewType& __new_value, _Proj __proj = {}) const { - auto __pred = [&](const auto& __value) { return __value == __old_value; }; + auto __pred = [&](const auto& __value) -> bool { return __value == __old_value; }; return ranges::__replace_copy_if_impl( ranges::begin(__range), ranges::end(__range), std::move(__result), __pred, __new_value, __proj); } diff --git a/libcxx/include/__algorithm/ranges_upper_bound.h b/libcxx/include/__algorithm/ranges_upper_bound.h index a12a0e39b08490..7b571fb3448f94 100644 --- a/libcxx/include/__algorithm/ranges_upper_bound.h +++ b/libcxx/include/__algorithm/ranges_upper_bound.h @@ -39,7 +39,7 @@ struct __fn { indirect_strict_weak_order> _Comp = ranges::less> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr _Iter operator()(_Iter __first, _Sent __last, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { - auto __comp_lhs_rhs_swapped = [&](const auto& __lhs, const auto& __rhs) { + auto __comp_lhs_rhs_swapped = [&](const auto& __lhs, const auto& __rhs) -> bool { return !std::invoke(__comp, __rhs, __lhs); }; @@ -52,7 +52,7 @@ struct __fn { indirect_strict_weak_order, _Proj>> _Comp = ranges::less> _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr borrowed_iterator_t<_Range> operator()(_Range&& __r, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) const { - auto __comp_lhs_rhs_swapped = [&](const auto& __lhs, const auto& __rhs) { + auto __comp_lhs_rhs_swapped = [&](const auto& __lhs, const auto& __rhs) -> bool { return !std::invoke(__comp, __rhs, __lhs); }; diff --git a/libcxx/include/__memory/ranges_uninitialized_algorithms.h b/libcxx/include/__memory/ranges_uninitialized_algorithms.h index 108f6537538413..96b6a9a9976568 100644 --- a/libcxx/include/__memory/ranges_uninitialized_algorithms.h +++ b/libcxx/include/__memory/ranges_uninitialized_algorithms.h @@ -196,7 +196,7 @@ struct __fn { operator()(_InputIterator __ifirst, _Sentinel1 __ilast, _OutputIterator __ofirst, _Sentinel2 __olast) const { using _ValueType = remove_reference_t>; - auto __stop_copying = [&__olast](auto&& __out_iter) { return __out_iter == __olast; }; + auto __stop_copying = [&__olast](auto&& __out_iter) -> bool { return __out_iter == __olast; }; auto __result = std::__uninitialized_copy<_ValueType>( std::move(__ifirst), std::move(__ilast), std::move(__ofirst), __stop_copying); return {_VSTD::move(__result.first), _VSTD::move(__result.second)}; @@ -233,7 +233,7 @@ struct __fn { operator()(_InputIterator __ifirst, iter_difference_t<_InputIterator> __n, _OutputIterator __ofirst, _Sentinel __olast) const { using _ValueType = remove_reference_t>; - auto __stop_copying = [&__olast](auto&& __out_iter) { return __out_iter == __olast; }; + auto __stop_copying = [&__olast](auto&& __out_iter) -> bool { return __out_iter == __olast; }; auto __result = std::__uninitialized_copy_n<_ValueType>(std::move(__ifirst), __n, std::move(__ofirst), __stop_copying); return {_VSTD::move(__result.first), _VSTD::move(__result.second)}; @@ -263,7 +263,7 @@ struct __fn { operator()(_InputIterator __ifirst, _Sentinel1 __ilast, _OutputIterator __ofirst, _Sentinel2 __olast) const { using _ValueType = remove_reference_t>; auto __iter_move = [](auto&& __iter) -> decltype(auto) { return ranges::iter_move(__iter); }; - auto __stop_moving = [&__olast](auto&& __out_iter) { return __out_iter == __olast; }; + auto __stop_moving = [&__olast](auto&& __out_iter) -> bool { return __out_iter == __olast; }; auto __result = std::__uninitialized_move<_ValueType>( std::move(__ifirst), std::move(__ilast), std::move(__ofirst), __stop_moving, __iter_move); return {_VSTD::move(__result.first), _VSTD::move(__result.second)}; @@ -301,7 +301,7 @@ struct __fn { _OutputIterator __ofirst, _Sentinel __olast) const { using _ValueType = remove_reference_t>; auto __iter_move = [](auto&& __iter) -> decltype(auto) { return ranges::iter_move(__iter); }; - auto __stop_moving = [&__olast](auto&& __out_iter) { return __out_iter == __olast; }; + auto __stop_moving = [&__olast](auto&& __out_iter) -> bool { return __out_iter == __olast; }; auto __result = std::__uninitialized_move_n<_ValueType>( std::move(__ifirst), __n, std::move(__ofirst), __stop_moving, __iter_move); return {_VSTD::move(__result.first), _VSTD::move(__result.second)}; diff --git a/libcxx/include/__ranges/chunk_by_view.h b/libcxx/include/__ranges/chunk_by_view.h index cfb149b443571e..e4699868764698 100644 --- a/libcxx/include/__ranges/chunk_by_view.h +++ b/libcxx/include/__ranges/chunk_by_view.h @@ -16,8 +16,6 @@ #include <__config> #include <__functional/bind_back.h> #include <__functional/invoke.h> -#include <__functional/not_fn.h> -#include <__functional/reference_wrapper.h> #include <__iterator/concepts.h> #include <__iterator/default_sentinel.h> #include <__iterator/iterator_traits.h> @@ -69,10 +67,11 @@ class chunk_by_view : public view_interface> { _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> __find_next(iterator_t<_View> __current) { _LIBCPP_ASSERT_UNCATEGORIZED( __pred_.__has_value(), "Trying to call __find_next() on a chunk_by_view that does not have a valid predicate."); - - return ranges::next(ranges::adjacent_find(__current, ranges::end(__base_), std::not_fn(std::ref(*__pred_))), - 1, - ranges::end(__base_)); + auto __reversed_pred = [this](_Tp&& __x, _Up&& __y) -> bool { + return !std::invoke(*__pred_, std::forward<_Tp>(__x), std::forward<_Up>(__y)); + }; + return ranges::next( + ranges::adjacent_find(__current, ranges::end(__base_), __reversed_pred), 1, ranges::end(__base_)); } _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> __find_prev(iterator_t<_View> __current) @@ -85,7 +84,7 @@ class chunk_by_view : public view_interface> { auto __first = ranges::begin(__base_); reverse_view __reversed{subrange{__first, __current}}; - auto __reversed_pred = [this](_Tp&& __x, _Up&& __y) { + auto __reversed_pred = [this](_Tp&& __x, _Up&& __y) -> bool { return !std::invoke(*__pred_, std::forward<_Up>(__y), std::forward<_Tp>(__x)); }; return ranges::prev(ranges::adjacent_find(__reversed, __reversed_pred).base(), 1, std::move(__first)); diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.remove/ranges.remove.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.remove/ranges.remove.pass.cpp index 7836dede7342ae..523de4cf7b10a8 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.remove/ranges.remove.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.remove/ranges.remove.pass.cpp @@ -25,7 +25,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" template > @@ -181,20 +180,6 @@ constexpr bool test() { } } - { - // check that the implicit conversion to bool works - { - StrictComparable a[] = {1, 2, 3, 4}; - auto ret = std::ranges::remove(a, a + 4, StrictComparable{2}); - assert(ret.begin() == a + 3); - } - { - StrictComparable a[] = {1, 2, 3, 4}; - auto ret = std::ranges::remove(a, StrictComparable{2}); - assert(ret.begin() == a + 3); - } - } - return true; } diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.remove/ranges.remove_if.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.remove/ranges.remove_if.pass.cpp index 1db4f171b91072..9b8cf1121a13d1 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.remove/ranges.remove_if.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.remove/ranges.remove_if.pass.cpp @@ -25,7 +25,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" struct FalsePredicate { @@ -197,20 +196,6 @@ constexpr bool test() { } } - { - // check that the implicit conversion to bool works - { - int a[] = {1, 2, 3, 4}; - auto ret = std::ranges::remove_if(a, a + 4, [](const int& i) { return BooleanTestable{i == 3}; }); - assert(ret.begin() == a + 3); - } - { - int a[] = {1, 2, 3, 4}; - auto ret = std::ranges::remove_if(a, [](const int& b) { return BooleanTestable{b == 3}; }); - assert(ret.begin() == a + 3); - } - } - return true; } // clang-format on diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/ranges.replace.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/ranges.replace.pass.cpp index 92ba59c1ddb2b4..ab2f705bafe9d0 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/ranges.replace.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/ranges.replace.pass.cpp @@ -138,19 +138,6 @@ constexpr bool test() { } } - { // check that the implicit conversion to bool works - { - StrictComparable a[] = {1, 2, 2, 4}; - auto ret = std::ranges::replace(std::begin(a), std::end(a), 1, 2); - assert(ret == std::end(a)); - } - { - StrictComparable a[] = {1, 2, 2, 4}; - auto ret = std::ranges::replace(a, 1, 2); - assert(ret == std::end(a)); - } - } - { // check that T1 and T2 can be different types { StrictComparable a[] = {1, 2, 2, 4}; diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/ranges.replace_if.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/ranges.replace_if.pass.cpp index 67e5e87af35be0..79098b090873c0 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/ranges.replace_if.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.replace/ranges.replace_if.pass.cpp @@ -26,7 +26,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" struct FalsePredicate { @@ -133,19 +132,6 @@ constexpr bool test() { } } - { // check that the implicit conversion to bool works - { - int a[] = {1, 2, 2, 4}; - auto ret = std::ranges::replace_if(std::begin(a), std::end(a), [](int) { return BooleanTestable{false}; }, 2); - assert(ret == std::end(a)); - } - { - int a[] = {1, 2, 2, 4}; - auto ret = std::ranges::replace_if(a, [](int) { return BooleanTestable{false}; }, 2); - assert(ret == std::end(a)); - } - } - { // check that std::ranges::dangling is returned [[maybe_unused]] std::same_as decltype(auto) ret = std::ranges::replace_if(std::array {1, 2, 3, 4}, [](int) { return false; }, 1); diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.adjacent.find/ranges.adjacent_find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.adjacent.find/ranges.adjacent_find.pass.cpp index d2e0bb5d182d69..7558f6b968132e 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.adjacent.find/ranges.adjacent_find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.adjacent.find/ranges.adjacent_find.pass.cpp @@ -26,7 +26,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" template @@ -172,19 +171,6 @@ constexpr bool test() { } } - { // check that the implicit conversion to bool works - { - int a[] = {1, 2, 2, 4}; - auto ret = std::ranges::adjacent_find(a, a + 4, [](int i, int j) { return BooleanTestable{i == j}; }); - assert(ret == a + 1); - } - { - int a[] = {1, 2, 2, 4}; - auto ret = std::ranges::adjacent_find(a, [](int i, int j) { return BooleanTestable{i == j}; }); - assert(ret == a + 1); - } - } - return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/ranges.find_first_of.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/ranges.find_first_of.pass.cpp index cea30420428cd5..a74e6d721f773b 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/ranges.find_first_of.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find.first.of/ranges.find_first_of.pass.cpp @@ -30,7 +30,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" template @@ -194,19 +193,6 @@ constexpr bool test() { } } - { // check that the implicit conversion to bool works - StrictComparable a[] = {1, 2, 3, 4}; - StrictComparable b[] = {2, 3}; - { - auto ret = std::ranges::find_first_of(a, std::end(a), b, std::end(b)); - assert(ret == a + 1); - } - { - auto ret = std::ranges::find_first_of(a, b); - assert(ret == a + 1); - } - } - { // check that the complexity requirements are met int a[] = {1, 2, 3, 4}; int b[] = {2, 3}; diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp index a1fb92a984e915..22f938f73ae078 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find.pass.cpp @@ -27,7 +27,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" struct NotEqualityComparable {}; diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find_if.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find_if.pass.cpp index 3f7ec622f145ef..2585feba5614e0 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find_if.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find_if.pass.cpp @@ -24,7 +24,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" struct Predicate { @@ -224,20 +223,6 @@ constexpr bool test() { } } - { - // check that the implicit conversion to bool works - { - int a[] = {1, 2, 3, 4}; - auto ret = std::ranges::find_if(a, a + 4, [](const int& i) { return BooleanTestable{i == 3}; }); - assert(ret == a + 2); - } - { - int a[] = {1, 2, 3, 4}; - auto ret = std::ranges::find_if(a, [](const int& b) { return BooleanTestable{b == 3}; }); - assert(ret == a + 2); - } - } - return true; } diff --git a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find_if_not.pass.cpp b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find_if_not.pass.cpp index 95860745f56204..171ffefa75cf97 100644 --- a/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find_if_not.pass.cpp +++ b/libcxx/test/std/algorithms/alg.nonmodifying/alg.find/ranges.find_if_not.pass.cpp @@ -24,7 +24,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" struct Predicate { @@ -218,20 +217,6 @@ constexpr bool test() { } } - { - // check that the implicit conversion to bool works - { - int a[] = {1, 2, 3, 4}; - auto ret = std::ranges::find_if_not(a, a + 4, [](const int& i) { return BooleanTestable{i != 3}; }); - assert(ret == a + 2); - } - { - int a[] = {1, 2, 3, 4}; - auto ret = std::ranges::find_if_not(a, [](const int& b) { return BooleanTestable{b != 3}; }); - assert(ret == a + 2); - } - } - return true; } diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/make.heap/ranges_make_heap.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/make.heap/ranges_make_heap.pass.cpp index 5d8086df450abb..6fc6f3ee1bf25e 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/make.heap/ranges_make_heap.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/make.heap/ranges_make_heap.pass.cpp @@ -28,7 +28,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" // SFINAE tests. @@ -191,22 +190,6 @@ constexpr bool test() { } } - { // The comparator can return any type that's convertible to `bool`. - const std::array input = {2, 1, 3}; - std::array expected = {3, 1, 2}; - { - auto in = input; - auto last = std::ranges::make_heap(in.begin(), in.end(), [](int i, int j) { return BooleanTestable{i < j}; }); - verify_heap(in, last, expected); - } - - { - auto in = input; - auto last = std::ranges::make_heap(in, [](int i, int j) { return BooleanTestable{i < j}; }); - verify_heap(in, last, expected); - } - } - { // `std::ranges::dangling` is returned. [[maybe_unused]] std::same_as decltype(auto) result = std::ranges::make_heap(std::array{1, 2, 3}); diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/pop.heap/ranges_pop_heap.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/pop.heap/ranges_pop_heap.pass.cpp index e190586fef813b..9ffde7acc3b65a 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/pop.heap/ranges_pop_heap.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/pop.heap/ranges_pop_heap.pass.cpp @@ -28,7 +28,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" // SFINAE tests. @@ -190,22 +189,6 @@ constexpr bool test() { } } - { // The comparator can return any type that's convertible to `bool`. - const std::array input = {3, 1, 2}; - std::array expected = {2, 1, 3}; - { - auto in = input; - auto last = std::ranges::pop_heap(in.begin(), in.end(), [](int i, int j) { return BooleanTestable{i < j}; }); - verify_heap(in, last, expected); - } - - { - auto in = input; - auto last = std::ranges::pop_heap(in, [](int i, int j) { return BooleanTestable{i < j}; }); - verify_heap(in, last, expected); - } - } - { // `std::ranges::dangling` is returned. [[maybe_unused]] std::same_as decltype(auto) result = std::ranges::pop_heap(std::array{2, 1, 3}); diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/push.heap/ranges_push_heap.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/push.heap/ranges_push_heap.pass.cpp index 331f07755fae49..082de929efae83 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/push.heap/ranges_push_heap.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/push.heap/ranges_push_heap.pass.cpp @@ -28,7 +28,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" // SFINAE tests. @@ -193,22 +192,6 @@ constexpr bool test() { } } - { // The comparator can return any type that's convertible to `bool`. - const std::array input = {2, 1, 3}; - std::array expected = {3, 1, 2}; - { - auto in = input; - auto last = std::ranges::push_heap(in.begin(), in.end(), [](int i, int j) { return BooleanTestable{i < j}; }); - verify_heap(in, last, expected); - } - - { - auto in = input; - auto last = std::ranges::push_heap(in, [](int i, int j) { return BooleanTestable{i < j}; }); - verify_heap(in, last, expected); - } - } - { // `std::ranges::dangling` is returned. [[maybe_unused]] std::same_as decltype(auto) result = std::ranges::push_heap(std::array{1, 2, 3}); diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/sort.heap/ranges_sort_heap.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/sort.heap/ranges_sort_heap.pass.cpp index 5723ed0d3db25e..245d163f984c19 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/sort.heap/ranges_sort_heap.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.heap.operations/sort.heap/ranges_sort_heap.pass.cpp @@ -29,7 +29,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" // SFINAE tests. @@ -189,22 +188,6 @@ constexpr bool test() { } } - { // The comparator can return any type that's convertible to `bool`. - const std::array input = {3, 1, 2}; - std::array expected = {1, 2, 3}; - { - auto in = input; - auto last = std::ranges::sort_heap(in.begin(), in.end(), [](int i, int j) { return BooleanTestable{i < j}; }); - verify_sorted(in, last, expected); - } - - { - auto in = input; - auto last = std::ranges::sort_heap(in, [](int i, int j) { return BooleanTestable{i < j}; }); - verify_sorted(in, last, expected); - } - } - { // `std::ranges::dangling` is returned. [[maybe_unused]] std::same_as decltype(auto) result = std::ranges::sort_heap(std::array{3, 1, 2}); diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/ranges.lexicographical_compare.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/ranges.lexicographical_compare.pass.cpp index 058be468d35b66..3c03af7db05cd0 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/ranges.lexicographical_compare.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.lex.comparison/ranges.lexicographical_compare.pass.cpp @@ -31,7 +31,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" template @@ -185,21 +184,6 @@ constexpr bool test() { } } - { // check that the implicit conversion to bool works - { - int a[] = {1, 2, 3, 4}; - auto ret = std::ranges::lexicographical_compare(std::begin(a), std::end(a), - std::begin(a), std::end(a), - [](int i, int j) { return BooleanTestable{i < j}; }); - assert(!ret); - } - { - int a[] = {1, 2, 3, 4}; - auto ret = std::ranges::lexicographical_compare(a, a, [](int i, int j) { return BooleanTestable{i < j}; }); - assert(!ret); - } - } - { // check that the complexity requirements are met { int predCount = 0; diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.nth.element/ranges_nth_element.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.nth.element/ranges_nth_element.pass.cpp index ad3c8ab699ab44..48816305c89443 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.nth.element/ranges_nth_element.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.nth.element/ranges_nth_element.pass.cpp @@ -30,7 +30,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" // SFINAE tests. @@ -257,25 +256,6 @@ constexpr bool test() { } } - { // The comparator can return any type that's convertible to `bool`. - const std::array input = {2, 1, 3}; - auto pred = [](int i, int j) { return BooleanTestable{i < j}; }; - - { - std::array in = input; - auto last = std::ranges::nth_element(in.begin(), in.begin() + 1, in.end(), pred); - assert(in[1] == 2); - assert(last == in.end()); - } - - { - std::array in = input; - auto last = std::ranges::nth_element(in, in.begin() + 1, pred); - assert(in[1] == 2); - assert(last == in.end()); - } - } - { // `std::ranges::dangling` is returned. std::array in{1, 2, 3}; [[maybe_unused]] std::same_as decltype(auto) result = diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort/ranges_partial_sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort/ranges_partial_sort.pass.cpp index af304662599ca7..f348c6e93e19c9 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort/ranges_partial_sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/partial.sort/ranges_partial_sort.pass.cpp @@ -28,7 +28,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" // SFINAE tests. diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp index 2463bf733196d0..d7bf6dd75f90fb 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/sort/ranges.sort.pass.cpp @@ -28,7 +28,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" // SFINAE tests. @@ -184,22 +183,6 @@ constexpr bool test() { } } - { // The comparator can return any type that's convertible to `bool`. - { - std::array in = {2, 1, 3}; - auto last = std::ranges::sort(in.begin(), in.end(), [](int i, int j) { return BooleanTestable{i < j}; }); - assert((in == std::array{1, 2, 3})); - assert(last == in.end()); - } - - { - std::array in = {2, 1, 3}; - auto last = std::ranges::sort(in, [](int i, int j) { return BooleanTestable{i < j}; }); - assert((in == std::array{1, 2, 3})); - assert(last == in.end()); - } - } - { // `std::ranges::dangling` is returned. [[maybe_unused]] std::same_as decltype(auto) result = std::ranges::sort(std::array{1, 2, 3}); } diff --git a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/ranges.stable.sort.pass.cpp b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/ranges.stable.sort.pass.cpp index ea0a3ebdf85b26..c8f76b20c68254 100644 --- a/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/ranges.stable.sort.pass.cpp +++ b/libcxx/test/std/algorithms/alg.sorting/alg.sort/stable.sort/ranges.stable.sort.pass.cpp @@ -27,7 +27,6 @@ #include #include "almost_satisfies_types.h" -#include "boolean_testable.h" #include "test_iterators.h" // SFINAE tests. @@ -238,22 +237,6 @@ void test() { } } - { // The comparator can return any type that's convertible to `bool`. - { - std::array in = {2, 1, 3}; - auto last = std::ranges::stable_sort(in.begin(), in.end(), [](int i, int j) { return BooleanTestable{i < j}; }); - assert((in == std::array{1, 2, 3})); - assert(last == in.end()); - } - - { - std::array in = {2, 1, 3}; - auto last = std::ranges::stable_sort(in, [](int i, int j) { return BooleanTestable{i < j}; }); - assert((in == std::array{1, 2, 3})); - assert(last == in.end()); - } - } - { // `std::ranges::dangling` is returned. [[maybe_unused]] std::same_as decltype(auto) result = std::ranges::stable_sort(std::array{1, 2, 3}); diff --git a/libcxx/test/std/algorithms/ranges_robust_against_nonbool.compile.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_nonbool.compile.pass.cpp new file mode 100644 index 00000000000000..a5668f20ccfd25 --- /dev/null +++ b/libcxx/test/std/algorithms/ranges_robust_against_nonbool.compile.pass.cpp @@ -0,0 +1,285 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// +// +// Range algorithms that take predicates should support predicates that return a non-boolean value as long as the +// returned type is implicitly convertible to bool. + +#include + +#include +#include + +#include "boolean_testable.h" +#include "test_macros.h" + +using Value = StrictComparable; +using Iterator = StrictBooleanIterator; +using Range = std::ranges::subrange; +auto pred1 = StrictUnaryPredicate; +auto pred2 = StrictBinaryPredicate; +auto projection = [](Value const& val) -> Value { return val; }; + +void f(Iterator it, Range in, Iterator out, std::size_t n, Value const& val, std::initializer_list ilist) { + // Functions of the form (in, pred) + auto in_pred = [&](auto func, auto pred) { + (void)func(it, it, pred); + (void)func(in, pred); + (void)func(it, it, pred, projection); + (void)func(in, pred, projection); + }; + + // Functions of the form (in, in, pred) + auto in_in_pred = [&](auto func, auto pred) { + (void)func(it, it, it, it, pred); + (void)func(in, in, pred); + (void)func(it, it, it, it, pred, projection); + (void)func(in, in, pred, projection); + }; + + in_pred(std::ranges::any_of, pred1); + in_pred(std::ranges::all_of, pred1); +#if TEST_STD_VER >= 23 + in_in_pred(std::ranges::ends_with, pred2); +#endif + in_pred(std::ranges::none_of, pred1); + in_pred(std::ranges::find_if, pred1); + in_pred(std::ranges::find_if_not, pred1); + in_in_pred(std::ranges::find_first_of, pred2); + in_pred(std::ranges::adjacent_find, pred2); + in_in_pred(std::ranges::mismatch, pred2); + in_in_pred(std::ranges::equal, pred2); + in_in_pred(std::ranges::lexicographical_compare, pred2); + in_pred(std::ranges::partition_point, pred1); + // lower_bound + { + (void)std::ranges::lower_bound(it, it, val, pred2); + (void)std::ranges::lower_bound(in, val, pred2); + (void)std::ranges::lower_bound(it, it, val, pred2, projection); + (void)std::ranges::lower_bound(in, val, pred2, projection); + } + // upper_bound + { + (void)std::ranges::upper_bound(it, it, val, pred2); + (void)std::ranges::upper_bound(in, val, pred2); + (void)std::ranges::upper_bound(it, it, val, pred2, projection); + (void)std::ranges::upper_bound(in, val, pred2, projection); + } + // equal_range + { + (void)std::ranges::equal_range(it, it, val, pred2); + (void)std::ranges::equal_range(in, val, pred2); + (void)std::ranges::equal_range(it, it, val, pred2, projection); + (void)std::ranges::equal_range(in, val, pred2, projection); + } + // binary_search + { + (void)std::ranges::binary_search(it, it, val, pred2); + (void)std::ranges::binary_search(in, val, pred2); + (void)std::ranges::binary_search(it, it, val, pred2, projection); + (void)std::ranges::binary_search(in, val, pred2, projection); + } + // min + { + (void)std::ranges::min(val, val, pred2); + (void)std::ranges::min(val, val, pred2, projection); + (void)std::ranges::min(ilist, pred2); + (void)std::ranges::min(ilist, pred2, projection); + (void)std::ranges::min(in, pred2); + (void)std::ranges::min(in, pred2, projection); + } + // max + { + (void)std::ranges::max(val, val, pred2); + (void)std::ranges::max(val, val, pred2, projection); + (void)std::ranges::max(ilist, pred2); + (void)std::ranges::max(ilist, pred2, projection); + (void)std::ranges::max(in, pred2); + (void)std::ranges::max(in, pred2, projection); + } + // minmax + { + (void)std::ranges::minmax(val, val, pred2); + (void)std::ranges::minmax(val, val, pred2, projection); + (void)std::ranges::minmax(ilist, pred2); + (void)std::ranges::minmax(ilist, pred2, projection); + (void)std::ranges::minmax(in, pred2); + (void)std::ranges::minmax(in, pred2, projection); + } + + in_pred(std::ranges::min_element, pred2); + in_pred(std::ranges::max_element, pred2); + in_pred(std::ranges::minmax_element, pred2); + in_pred(std::ranges::count_if, pred1); + in_in_pred(std::ranges::search, pred2); + // search_n + { + (void)std::ranges::search_n(it, it, n, val, pred2); + (void)std::ranges::search_n(in, n, val, pred2); + (void)std::ranges::search_n(it, it, n, val, pred2, projection); + (void)std::ranges::search_n(in, n, val, pred2, projection); + } + in_in_pred(std::ranges::find_end, pred2); + in_pred(std::ranges::is_partitioned, pred1); + in_pred(std::ranges::is_sorted, pred2); + in_pred(std::ranges::is_sorted_until, pred2); + in_in_pred(std::ranges::includes, pred2); + in_pred(std::ranges::is_heap, pred2); + in_pred(std::ranges::is_heap_until, pred2); + // clamp + { + (void)std::ranges::clamp(val, val, val); + (void)std::ranges::clamp(val, val, val, pred2); + (void)std::ranges::clamp(val, val, val, pred2, projection); + } + in_in_pred(std::ranges::is_permutation, pred2); + // copy_if + { + (void)std::ranges::copy_if(it, it, out, pred1); + (void)std::ranges::copy_if(in, out, pred1); + (void)std::ranges::copy_if(it, it, out, pred1, projection); + (void)std::ranges::copy_if(in, out, pred1, projection); + } + { + (void)std::ranges::remove_copy_if(it, it, out, pred1); + (void)std::ranges::remove_copy_if(in, out, pred1); + (void)std::ranges::remove_copy_if(it, it, out, pred1, projection); + (void)std::ranges::remove_copy_if(in, out, pred1, projection); + } + // remove_copy + { + (void)std::ranges::remove_copy(it, it, out, val); + (void)std::ranges::remove_copy(in, out, val); + (void)std::ranges::remove_copy(it, it, out, val, projection); + (void)std::ranges::remove_copy(in, out, val, projection); + } + // replace + { + (void)std::ranges::replace(it, it, val, val); + (void)std::ranges::replace(in, val, val); + (void)std::ranges::replace(it, it, val, val, projection); + (void)std::ranges::replace(in, val, val, projection); + } + // replace_if + { + (void)std::ranges::replace_if(it, it, pred1, val); + (void)std::ranges::replace_if(in, pred1, val); + (void)std::ranges::replace_if(it, it, pred1, val, projection); + (void)std::ranges::replace_if(in, pred1, val, projection); + } + // replace_copy_if + { + (void)std::ranges::replace_copy_if(it, it, out, pred1, val); + (void)std::ranges::replace_copy_if(in, out, pred1, val); + (void)std::ranges::replace_copy_if(it, it, out, pred1, val, projection); + (void)std::ranges::replace_copy_if(in, out, pred1, val, projection); + } + // replace_copy + { + (void)std::ranges::replace_copy(it, it, out, val, val); + (void)std::ranges::replace_copy(in, out, val, val); + (void)std::ranges::replace_copy(it, it, out, val, val, projection); + (void)std::ranges::replace_copy(in, out, val, val, projection); + } + // unique_copy + { + (void)std::ranges::unique_copy(it, it, out, pred2); + (void)std::ranges::unique_copy(in, out, pred2); + (void)std::ranges::unique_copy(it, it, out, pred2, projection); + (void)std::ranges::unique_copy(in, out, pred2, projection); + } + // partition_copy + { + (void)std::ranges::partition_copy(it, it, out, out, pred1); + (void)std::ranges::partition_copy(in, out, out, pred1); + (void)std::ranges::partition_copy(it, it, out, out, pred1, projection); + (void)std::ranges::partition_copy(in, out, out, pred1, projection); + } + in_in_pred(std::ranges::partial_sort_copy, pred2); +#if TEST_STD_VER > 20 + in_in_pred(std::ranges::starts_with, pred2); +#endif + // merge + { + (void)std::ranges::merge(it, it, it, it, out, pred2); + (void)std::ranges::merge(in, in, out, pred2); + (void)std::ranges::merge(it, it, it, it, out, pred2, projection, projection); + (void)std::ranges::merge(in, in, out, pred2, projection, projection); + } + // set_difference + { + (void)std::ranges::set_difference(it, it, it, it, out, pred2); + (void)std::ranges::set_difference(in, in, out, pred2); + (void)std::ranges::set_difference(it, it, it, it, out, pred2, projection, projection); + (void)std::ranges::set_difference(in, in, out, pred2, projection, projection); + } + // set_intersection + { + (void)std::ranges::set_intersection(it, it, it, it, out, pred2); + (void)std::ranges::set_intersection(in, in, out, pred2); + (void)std::ranges::set_intersection(it, it, it, it, out, pred2, projection, projection); + (void)std::ranges::set_intersection(in, in, out, pred2, projection, projection); + } + // set_symmetric_difference + { + (void)std::ranges::set_symmetric_difference(it, it, it, it, out, pred2); + (void)std::ranges::set_symmetric_difference(in, in, out, pred2); + (void)std::ranges::set_symmetric_difference(it, it, it, it, out, pred2, projection, projection); + (void)std::ranges::set_symmetric_difference(in, in, out, pred2, projection, projection); + } + // set_union + { + (void)std::ranges::set_union(it, it, it, it, out, pred2); + (void)std::ranges::set_union(in, in, out, pred2); + (void)std::ranges::set_union(it, it, it, it, out, pred2, projection, projection); + (void)std::ranges::set_union(in, in, out, pred2, projection, projection); + } + in_pred(std::ranges::remove_if, pred1); + // remove + { + (void)std::ranges::remove(it, it, val); + (void)std::ranges::remove(it, it, val, projection); + (void)std::ranges::remove(in, val); + (void)std::ranges::remove(in, val, projection); + } + in_pred(std::ranges::unique, pred2); + in_pred(std::ranges::partition, pred1); + in_pred(std::ranges::stable_partition, pred1); + in_pred(std::ranges::sort, pred2); + in_pred(std::ranges::stable_sort, pred2); + // partial_sort + { + (void)std::ranges::partial_sort(it, it, it, pred2); + (void)std::ranges::partial_sort(in, it, pred2); + (void)std::ranges::partial_sort(it, it, it, pred2, projection); + (void)std::ranges::partial_sort(in, it, pred2, projection); + } + // nth_element + { + (void)std::ranges::nth_element(it, it, it, pred2); + (void)std::ranges::nth_element(in, it, pred2); + (void)std::ranges::nth_element(it, it, it, pred2, projection); + (void)std::ranges::nth_element(in, it, pred2, projection); + } + // inplace_merge + { + (void)std::ranges::inplace_merge(it, it, it, pred2); + (void)std::ranges::inplace_merge(in, it, pred2); + (void)std::ranges::inplace_merge(it, it, it, pred2, projection); + (void)std::ranges::inplace_merge(in, it, pred2, projection); + } + in_pred(std::ranges::make_heap, pred2); + in_pred(std::ranges::push_heap, pred2); + in_pred(std::ranges::pop_heap, pred2); + in_pred(std::ranges::sort_heap, pred2); + in_pred(std::ranges::prev_permutation, pred2); + in_pred(std::ranges::next_permutation, pred2); +} diff --git a/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.pass.cpp deleted file mode 100644 index 04773f0f5bc802..00000000000000 --- a/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.pass.cpp +++ /dev/null @@ -1,159 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -// UNSUPPORTED: c++03, c++11, c++14, c++17 - -// -// -// Range algorithms that take predicates should support predicates that return a non-boolean value as long as the -// returned type is implicitly convertible to bool. - -#include - -#include -#include -#include -#include -#include - -#include "boolean_testable.h" -#include "test_macros.h" - -constexpr auto unary_pred = [](int i) { return BooleanTestable(i > 0); }; -static_assert(!std::same_as); -static_assert(std::convertible_to); - -constexpr auto binary_pred = [](int i, int j) { return BooleanTestable(i < j); }; -static_assert(!std::same_as); -static_assert(std::convertible_to); - -// Invokes both the (iterator, sentinel, ...) and the (range, ...) overloads of the given niebloid. - -// (in, ...) -template -constexpr void test(Func&& func, Input& in, Args&&... args) { - (void)func(in.begin(), in.end(), std::forward(args)...); - (void)func(in, std::forward(args)...); -} - -// (in1, in2, ...) -template -constexpr void test(Func&& func, Input& in1, Input& in2, Args&&... args) { - (void)func(in1.begin(), in1.end(), in2.begin(), in2.end(), std::forward(args)...); - (void)func(in1, in2, std::forward(args)...); -} - -// (in, mid, ...) -template -constexpr void test_mid(Func&& func, Input& in, std::ranges::iterator_t mid, Args&&... args) { - (void)func(in.begin(), mid, in.end(), std::forward(args)...); - (void)func(in, mid, std::forward(args)...); -} - -constexpr bool test_all() { - std::array in = {1, 2, 3}; - std::array in2 = {4, 5, 6}; - auto mid = in.begin() + 1; - - std::array output = {7, 8, 9, 10, 11, 12}; - auto out = output.begin(); - auto out2 = output.begin() + 1; - - int x = 2; - int count = 1; - - test(std::ranges::any_of, in, unary_pred); - test(std::ranges::all_of, in, unary_pred); -#if TEST_STD_VER >= 23 - test(std::ranges::ends_with, in, in2, binary_pred); -#endif - test(std::ranges::none_of, in, unary_pred); - test(std::ranges::find_if, in, unary_pred); - test(std::ranges::find_if_not, in, unary_pred); - test(std::ranges::find_first_of, in, in2, binary_pred); - test(std::ranges::adjacent_find, in, binary_pred); - test(std::ranges::mismatch, in, in2, binary_pred); - test(std::ranges::equal, in, in2, binary_pred); - test(std::ranges::lexicographical_compare, in, in2, binary_pred); - test(std::ranges::partition_point, in, unary_pred); - test(std::ranges::lower_bound, in, x, binary_pred); - test(std::ranges::upper_bound, in, x, binary_pred); - test(std::ranges::equal_range, in, x, binary_pred); - test(std::ranges::binary_search, in, x, binary_pred); - - // min - (void)std::ranges::min(1, 2, binary_pred); - (void)std::ranges::min(std::initializer_list{1, 2}, binary_pred); - (void)std::ranges::min(in, binary_pred); - // max - (void)std::ranges::max(1, 2, binary_pred); - (void)std::ranges::max(std::initializer_list{1, 2}, binary_pred); - (void)std::ranges::max(in, binary_pred); - // minmax - (void)std::ranges::minmax(1, 2, binary_pred); - (void)std::ranges::minmax(std::initializer_list{1, 2}, binary_pred); - (void)std::ranges::minmax(in, binary_pred); - - test(std::ranges::min_element, in, binary_pred); - test(std::ranges::max_element, in, binary_pred); - test(std::ranges::minmax_element, in, binary_pred); - test(std::ranges::count_if, in, unary_pred); - test(std::ranges::search, in, in2, binary_pred); - test(std::ranges::search_n, in, count, x, binary_pred); - test(std::ranges::find_end, in, in2, binary_pred); - test(std::ranges::is_partitioned, in, unary_pred); - test(std::ranges::is_sorted, in, binary_pred); - test(std::ranges::is_sorted_until, in, binary_pred); - 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); - (void)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); - test(std::ranges::replace_copy_if, in, out, unary_pred, x); - test(std::ranges::unique_copy, in, out, binary_pred); - test(std::ranges::partition_copy, in, out, out2, unary_pred); - test(std::ranges::partial_sort_copy, in, in2, binary_pred); - test(std::ranges::merge, in, in2, out, binary_pred); -#if TEST_STD_VER > 20 - test(std::ranges::starts_with, in, in2, binary_pred); -#endif - test(std::ranges::set_difference, in, in2, out, binary_pred); - test(std::ranges::set_intersection, in, in2, out, binary_pred); - test(std::ranges::set_symmetric_difference, in, in2, out, binary_pred); - test(std::ranges::set_union, in, in2, out, binary_pred); - test(std::ranges::remove_if, in, unary_pred); - test(std::ranges::unique, in, binary_pred); - test(std::ranges::partition, in, unary_pred); - if (!std::is_constant_evaluated()) - test(std::ranges::stable_partition, in, unary_pred); - test(std::ranges::sort, in, binary_pred); - if (!std::is_constant_evaluated()) - test(std::ranges::stable_sort, in, binary_pred); - test_mid(std::ranges::partial_sort, in, mid, binary_pred); - test_mid(std::ranges::nth_element, in, mid, binary_pred); - if (!std::is_constant_evaluated()) - test_mid(std::ranges::inplace_merge, in, mid, binary_pred); - test(std::ranges::make_heap, in, binary_pred); - test(std::ranges::push_heap, in, binary_pred); - test(std::ranges::pop_heap, in, binary_pred); - test(std::ranges::sort_heap, in, binary_pred); - test(std::ranges::prev_permutation, in, binary_pred); - test(std::ranges::next_permutation, in, binary_pred); - - return true; -} - -int main(int, char**) { - test_all(); - static_assert(test_all()); - - return 0; -} diff --git a/libcxx/test/std/ranges/range.adaptors/robust_against_nonbool.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/robust_against_nonbool.compile.pass.cpp new file mode 100644 index 00000000000000..5cd20bce610c78 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/robust_against_nonbool.compile.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// +// +// Range adaptors that take predicates should support predicates that return a non-boolean +// value as long as the returned type is implicitly convertible to bool. + +#include + +#include "boolean_testable.h" + +template +constexpr void use(View view) { + // Just use the view in a few ways. Our goal here is to trigger the instantiation + // of various functions related to the view and its iterators in the hopes that we + // instantiate functions that might have incorrect implementations w.r.t. predicates. + auto first = std::ranges::begin(view); + auto last = std::ranges::end(view); + ++first; + --first; + (void)(first == last); + (void)(first != last); + (void)std::ranges::empty(view); +} + +using Value = StrictComparable; +using Iterator = StrictBooleanIterator; +using Range = std::ranges::subrange; +auto pred1 = StrictUnaryPredicate; +auto pred2 = StrictBinaryPredicate; + +void f(Range in) { + (void)pred1; + (void)pred2; + +#if TEST_STD_VER >= 23 + { + auto view = std::views::chunk_by(in, pred2); + use(view); + } +#endif + { + auto view = std::views::drop_while(in, pred1); + use(view); + } + { + auto view = std::views::filter(in, pred1); + use(view); + } + { + auto view = std::views::take_while(in, pred1); + use(view); + } +} diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/ranges_robust_against_nonbool.compile.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/ranges_robust_against_nonbool.compile.pass.cpp new file mode 100644 index 00000000000000..acfc3513ec7b72 --- /dev/null +++ b/libcxx/test/std/utilities/memory/specialized.algorithms/ranges_robust_against_nonbool.compile.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// +// +// Make sure we support iterators that return a BooleanTestable in the ranges:: algorithms +// defined in . + +#include + +#include + +#include "boolean_testable.h" + +using Value = StrictComparable; +using Iterator = StrictBooleanIterator; +using Range = std::ranges::subrange; + +void f(Iterator it, Range in, Range out, std::size_t n, Value const& val) { + // uninitialized_copy + { + std::ranges::uninitialized_copy(in, out); + std::ranges::uninitialized_copy(it, it, it, it); + } + // uninitialized_copy_n + { std::ranges::uninitialized_copy_n(it, n, it, it); } + // uninitialized_fill + { + std::ranges::uninitialized_fill(it, it, val); + std::ranges::uninitialized_fill(in, val); + } + // uninitialized_fill_n + { std::ranges::uninitialized_fill_n(it, n, val); } + // uninitialized_move + { + std::ranges::uninitialized_move(it, it, it, it); + std::ranges::uninitialized_move(in, out); + } + // uninitialized_move_n + { std::ranges::uninitialized_move_n(it, n, it, it); } + // uninitialized_default_construct + { + std::ranges::uninitialized_default_construct(it, it); + std::ranges::uninitialized_default_construct(in); + } + // uninitialized_default_construct_n + { std::ranges::uninitialized_default_construct_n(it, n); } + // uninitialized_value_construct + { + std::ranges::uninitialized_value_construct(it, it); + std::ranges::uninitialized_value_construct(in); + } + // uninitialized_value_construct_n + { std::ranges::uninitialized_value_construct_n(it, n); } + // destroy + { + std::ranges::destroy(it, it); + std::ranges::destroy(in); + } + // destroy_n + { std::ranges::destroy_n(it, n); } +} diff --git a/libcxx/test/support/boolean_testable.h b/libcxx/test/support/boolean_testable.h index e810e4e0461dc6..d06511970b9bbe 100644 --- a/libcxx/test/support/boolean_testable.h +++ b/libcxx/test/support/boolean_testable.h @@ -11,53 +11,154 @@ #include "test_macros.h" +#include +#include + #if TEST_STD_VER > 17 -class BooleanTestable { -public: - constexpr operator bool() const { - return value_; - } +struct BooleanTestable { + constexpr operator bool() const { return value_; } friend constexpr BooleanTestable operator==(const BooleanTestable& lhs, const BooleanTestable& rhs) { return lhs.value_ == rhs.value_; } friend constexpr BooleanTestable operator!=(const BooleanTestable& lhs, const BooleanTestable& rhs) { - return !(lhs == rhs); + return lhs.value_ != rhs.value_; } - constexpr BooleanTestable operator!() { - return BooleanTestable{!value_}; + constexpr BooleanTestable&& operator!() && { + value_ = !value_; + return std::move(*this); } // this class should behave like a bool, so the constructor shouldn't be explicit constexpr BooleanTestable(bool value) : value_{value} {} constexpr BooleanTestable(const BooleanTestable&) = delete; - constexpr BooleanTestable(BooleanTestable&&) = delete; + constexpr BooleanTestable(BooleanTestable&&) = delete; private: bool value_; }; +static constexpr BooleanTestable yes(true); +static constexpr BooleanTestable no(false); + template -class StrictComparable { -public: +struct StrictComparable { + StrictComparable() = default; + // this shouldn't be explicit to make it easier to initlaize inside arrays (which it almost always is) constexpr StrictComparable(T value) : value_{value} {} - friend constexpr BooleanTestable operator==(const StrictComparable& lhs, const StrictComparable& rhs) { - return (lhs.value_ == rhs.value_); + friend constexpr BooleanTestable const& operator==(StrictComparable const& a, StrictComparable const& b) { + return a.value_ == b.value_ ? yes : no; } - friend constexpr BooleanTestable operator!=(const StrictComparable& lhs, const StrictComparable& rhs) { - return !(lhs == rhs); + friend constexpr BooleanTestable const& operator!=(StrictComparable const& a, StrictComparable const& b) { + return a.value_ != b.value_ ? yes : no; + } + + friend constexpr BooleanTestable const& operator<(StrictComparable const& a, StrictComparable const& b) { + return a.value_ < b.value_ ? yes : no; + } + friend constexpr BooleanTestable const& operator<=(StrictComparable const& a, StrictComparable const& b) { + return a.value_ <= b.value_ ? yes : no; + } + friend constexpr BooleanTestable const& operator>(StrictComparable const& a, StrictComparable const& b) { + return a.value_ > b.value_ ? yes : no; + } + friend constexpr BooleanTestable const& operator>=(StrictComparable const& a, StrictComparable const& b) { + return a.value_ >= b.value_ ? yes : no; } -private: T value_; }; +auto StrictUnaryPredicate = [](StrictComparable const& x) -> BooleanTestable const& { + return x.value_ < 0 ? yes : no; +}; + +auto StrictBinaryPredicate = + [](StrictComparable const& x, StrictComparable const& y) -> BooleanTestable const& { + return x.value_ < y.value_ ? yes : no; +}; + +template +struct StrictBooleanIterator { + using value_type = typename std::iterator_traits::value_type; + using reference = typename std::iterator_traits::reference; + using difference_type = typename std::iterator_traits::difference_type; + constexpr StrictBooleanIterator() = default; + constexpr explicit StrictBooleanIterator(It it) : iter_(it) {} + constexpr reference operator*() const { return *iter_; } + constexpr reference operator[](difference_type n) const { return iter_[n]; } + constexpr StrictBooleanIterator& operator++() { + ++iter_; + return *this; + } + constexpr StrictBooleanIterator operator++(int) { + auto copy = *this; + ++iter_; + return copy; + } + constexpr StrictBooleanIterator& operator--() { + --iter_; + return *this; + } + constexpr StrictBooleanIterator operator--(int) { + auto copy = *this; + --iter_; + return copy; + } + constexpr StrictBooleanIterator& operator+=(difference_type n) { + iter_ += n; + return *this; + } + constexpr StrictBooleanIterator& operator-=(difference_type n) { + iter_ -= n; + return *this; + } + friend constexpr StrictBooleanIterator operator+(StrictBooleanIterator x, difference_type n) { + x += n; + return x; + } + friend constexpr StrictBooleanIterator operator+(difference_type n, StrictBooleanIterator x) { + x += n; + return x; + } + friend constexpr StrictBooleanIterator operator-(StrictBooleanIterator x, difference_type n) { + x -= n; + return x; + } + friend constexpr difference_type operator-(StrictBooleanIterator x, StrictBooleanIterator y) { + return x.iter_ - y.iter_; + } + constexpr BooleanTestable const& operator==(StrictBooleanIterator const& other) const { + return iter_ == other.iter_ ? yes : no; + } + constexpr BooleanTestable const& operator!=(StrictBooleanIterator const& other) const { + return iter_ != other.iter_ ? yes : no; + } + constexpr BooleanTestable const& operator<(StrictBooleanIterator const& other) const { + return iter_ < other.iter_ ? yes : no; + } + constexpr BooleanTestable const& operator<=(StrictBooleanIterator const& other) const { + return iter_ <= other.iter_ ? yes : no; + } + constexpr BooleanTestable const& operator>(StrictBooleanIterator const& other) const { + return iter_ > other.iter_ ? yes : no; + } + constexpr BooleanTestable const& operator>=(StrictBooleanIterator const& other) const { + return iter_ >= other.iter_ ? yes : no; + } + +private: + It iter_; +}; +static_assert(std::forward_iterator>); +static_assert(std::sentinel_for, StrictBooleanIterator>); + #endif // TEST_STD_VER > 17 #endif // LIBCXX_TEST_SUPPORT_BOOLEAN_TESTABLE_H diff --git a/libcxx/utils/data/ignore_format.txt b/libcxx/utils/data/ignore_format.txt index cf6dca7cd7d3c6..b1488d0372ed73 100644 --- a/libcxx/utils/data/ignore_format.txt +++ b/libcxx/utils/data/ignore_format.txt @@ -7217,7 +7217,6 @@ libcxx/test/support/archetypes.h libcxx/test/support/archetypes.ipp libcxx/test/support/asan_testing.h libcxx/test/support/assert_macros.h -libcxx/test/support/boolean_testable.h libcxx/test/support/callable_types.h libcxx/test/support/charconv_test_helpers.h libcxx/test/support/check_assertion.h