[libcxx-commits] [libcxx] 065202f - [libc++][ranges] Implement `std::ranges::partition_{point, copy}`.
Konstantin Varlamov via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jul 20 11:42:19 PDT 2022
Author: Konstantin Varlamov
Date: 2022-07-20T11:39:07-07:00
New Revision: 065202f3ca9d32e32a1d9b2995e779ced64950b2
URL: https://github.com/llvm/llvm-project/commit/065202f3ca9d32e32a1d9b2995e779ced64950b2
DIFF: https://github.com/llvm/llvm-project/commit/065202f3ca9d32e32a1d9b2995e779ced64950b2.diff
LOG: [libc++][ranges] Implement `std::ranges::partition_{point,copy}`.
Reviewed By: #libc, huixie90, ldionne
Differential Revision: https://reviews.llvm.org/D130070
Added:
libcxx/test/support/counting_projection.h
Modified:
libcxx/docs/Status/RangesAlgorithms.csv
libcxx/include/__algorithm/ranges_partition_copy.h
libcxx/include/__algorithm/ranges_partition_point.h
libcxx/include/algorithm
libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp
libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition_copy.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition_point.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_stable_partition.pass.cpp
libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp
libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp
libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.pass.cpp
libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.pass.cpp
libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp
libcxx/test/support/counting_predicates.h
Removed:
################################################################################
diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv
index a853c414396c4..849a9a2a2b4df 100644
--- a/libcxx/docs/Status/RangesAlgorithms.csv
+++ b/libcxx/docs/Status/RangesAlgorithms.csv
@@ -10,7 +10,7 @@ Search,adjacent_find,Nikolas Klauser,`D126610 <https://llvm.org/D126610>`_,✅
Search,mismatch,Nikolas Klauser,`D117817 <https://llvm.org/D117817>`_,✅
Search,equal,Nikolas Klauser,`D123681 <https://llvm.org/D123681>`_,✅
Search,lexicographical_compare,Nikolas Klauser,`D127130 <https://llvm.org/D127130>`_,✅
-Search,partition_point,Konstantin Varlamov,n/a,In progress
+Search,partition_point,Konstantin Varlamov,`D130070 <https://llvm.org/D130070>`_,✅
Search,lower_bound,Nikolas Klauser,`D121964 <https://llvm.org/D121964>`_,✅
Search,upper_bound,Nikolas Klauser,`D121964 <https://llvm.org/D121964>`_,✅
Search,equal_range,Christopher Di Bella,n/a,Not started
@@ -58,7 +58,7 @@ Write,reverse_copy,Nikolas Klauser,`D127211 <https://llvm.org/D127211>`_,✅
Write,rotate_copy,Nikolas Klauser,`D127211 <https://llvm.org/D127211>`_,✅
Write,sample,Not assigned,n/a,Not started
Write,unique_copy,Not assigned,n/a,Not started
-Write,partition_copy,Konstantin Varlamov,n/a,In progress
+Write,partition_copy,Konstantin Varlamov,`D130070 <https://llvm.org/D130070>`_,✅
Write,partial_sort_copy,Konstantin Varlamov,n/a,In progress
Merge,merge,Hui Xie,`D128611 <https://llvm.org/D128611>`_,✅
Merge,set_
diff erence,Hui Xie,`D128983 <https://llvm.org/D128983>`_,✅
diff --git a/libcxx/include/__algorithm/ranges_partition_copy.h b/libcxx/include/__algorithm/ranges_partition_copy.h
index f55089b94ea5e..7201a8cbfe451 100644
--- a/libcxx/include/__algorithm/ranges_partition_copy.h
+++ b/libcxx/include/__algorithm/ranges_partition_copy.h
@@ -10,20 +10,17 @@
#define _LIBCPP___ALGORITHM_RANGES_PARTITION_COPY_H
#include <__algorithm/in_out_out_result.h>
-#include <__algorithm/make_projected.h>
-#include <__algorithm/partition_copy.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
-#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
-#include <__utility/forward.h>
#include <__utility/move.h>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -42,6 +39,27 @@ namespace __partition_copy {
struct __fn {
+ // TODO(ranges): delegate to the classic algorithm.
+ template <class _InIter, class _Sent, class _OutIter1, class _OutIter2, class _Proj, class _Pred>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ static partition_copy_result<
+ __uncvref_t<_InIter>, __uncvref_t<_OutIter1>, __uncvref_t<_OutIter2>
+ > __partition_copy_fn_impl( _InIter&& __first, _Sent&& __last, _OutIter1&& __out_true, _OutIter2&& __out_false,
+ _Pred& __pred, _Proj& __proj) {
+ for (; __first != __last; ++__first) {
+ if (std::invoke(__pred, std::invoke(__proj, *__first))) {
+ *__out_true = *__first;
+ ++__out_true;
+
+ } else {
+ *__out_false = *__first;
+ ++__out_false;
+ }
+ }
+
+ return {std::move(__first), std::move(__out_true), std::move(__out_false)};
+ }
+
template <input_iterator _InIter, sentinel_for<_InIter> _Sent,
weakly_incrementable _OutIter1, weakly_incrementable _OutIter2,
class _Proj = identity, indirect_unary_predicate<projected<_InIter, _Proj>> _Pred>
@@ -50,9 +68,8 @@ struct __fn {
partition_copy_result<_InIter, _OutIter1, _OutIter2>
operator()(_InIter __first, _Sent __last, _OutIter1 __out_true, _OutIter2 __out_false,
_Pred __pred, _Proj __proj = {}) const {
- // TODO: implement
- (void)__first; (void)__last; (void)__out_true; (void)__out_false; (void)__pred; (void)__proj;
- return {};
+ return __partition_copy_fn_impl(
+ std::move(__first), std::move(__last), std::move(__out_true), std::move(__out_false), __pred, __proj);
}
template <input_range _Range, weakly_incrementable _OutIter1, weakly_incrementable _OutIter2,
@@ -61,9 +78,8 @@ struct __fn {
_LIBCPP_HIDE_FROM_ABI constexpr
partition_copy_result<borrowed_iterator_t<_Range>, _OutIter1, _OutIter2>
operator()(_Range&& __range, _OutIter1 __out_true, _OutIter2 __out_false, _Pred __pred, _Proj __proj = {}) const {
- // TODO: implement
- (void)__range; (void)__out_true; (void)__out_false; (void)__pred; (void)__proj;
- return {};
+ return __partition_copy_fn_impl(
+ ranges::begin(__range), ranges::end(__range), std::move(__out_true), std::move(__out_false), __pred, __proj);
}
};
diff --git a/libcxx/include/__algorithm/ranges_partition_point.h b/libcxx/include/__algorithm/ranges_partition_point.h
index 336b29f63284d..6614a0bb50fd1 100644
--- a/libcxx/include/__algorithm/ranges_partition_point.h
+++ b/libcxx/include/__algorithm/ranges_partition_point.h
@@ -9,19 +9,18 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_PARTITION_POINT_H
#define _LIBCPP___ALGORITHM_RANGES_PARTITION_POINT_H
-#include <__algorithm/make_projected.h>
-#include <__algorithm/partition_point.h>
+#include <__algorithm/half_positive.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
-#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
+#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
+#include <__iterator/next.h>
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
-#include <__utility/forward.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -37,22 +36,40 @@ namespace __partition_point {
struct __fn {
+ // TODO(ranges): delegate to the classic algorithm.
+ template <class _Iter, class _Sent, class _Proj, class _Pred>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ static _Iter __partition_point_fn_impl(_Iter&& __first, _Sent&& __last, _Pred& __pred, _Proj& __proj) {
+ auto __len = ranges::distance(__first, __last);
+
+ while (__len != 0) {
+ auto __half_len = std::__half_positive(__len);
+ auto __mid = ranges::next(__first, __half_len);
+
+ if (std::invoke(__pred, std::invoke(__proj, *__mid))) {
+ __first = ++__mid;
+ __len -= __half_len + 1;
+
+ } else {
+ __len = __half_len;
+ }
+ }
+
+ return __first;
+ }
+
template <forward_iterator _Iter, sentinel_for<_Iter> _Sent, class _Proj = identity,
indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
_LIBCPP_HIDE_FROM_ABI constexpr
_Iter operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const {
- // TODO: implement
- (void)__first; (void)__last; (void)__pred; (void)__proj;
- return {};
+ return __partition_point_fn_impl(std::move(__first), std::move(__last), __pred, __proj);
}
template <forward_range _Range, class _Proj = identity,
indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
_LIBCPP_HIDE_FROM_ABI constexpr
borrowed_iterator_t<_Range> operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const {
- // TODO: implement
- (void)__range; (void)__pred; (void)__proj;
- return {};
+ return __partition_point_fn_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj);
}
};
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index 71d507adac25c..88c7665d712b3 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -581,6 +581,34 @@ namespace ranges {
constexpr ranges::move_result<borrowed_iterator_t<R>, O>
ranges::move(R&& r, O result); // since C++20
+ template<class I, class O1, class O2>
+ using partition_copy_result = in_out_out_result<I, O1, O2>; // since C++20
+
+ template<input_iterator I, sentinel_for<I> S,
+ weakly_incrementable O1, weakly_incrementable O2,
+ class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
+ requires indirectly_copyable<I, O1> && indirectly_copyable<I, O2>
+ constexpr partition_copy_result<I, O1, O2>
+ partition_copy(I first, S last, O1 out_true, O2 out_false, Pred pred,
+ Proj proj = {}); // Since C++20
+
+ template<input_range R, weakly_incrementable O1, weakly_incrementable O2,
+ class Proj = identity,
+ indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
+ requires indirectly_copyable<iterator_t<R>, O1> &&
+ indirectly_copyable<iterator_t<R>, O2>
+ constexpr partition_copy_result<borrowed_iterator_t<R>, O1, O2>
+ partition_copy(R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {}); // Since C++20
+
+ template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
+ indirect_unary_predicate<projected<I, Proj>> Pred>
+ constexpr I partition_point(I first, S last, Pred pred, Proj proj = {}); // Since C++20
+
+ template<forward_range R, class Proj = identity,
+ indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
+ constexpr borrowed_iterator_t<R>
+ partition_point(R&& r, Pred pred, Proj proj = {}); // Since C++20
+
template<class I1, class I2, class O>
using merge_result = in_in_out_result<I1, I2, O>; // since C++20
@@ -1531,6 +1559,8 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_nth_element.h>
#include <__algorithm/ranges_partial_sort.h>
#include <__algorithm/ranges_partition.h>
+#include <__algorithm/ranges_partition_copy.h>
+#include <__algorithm/ranges_partition_point.h>
#include <__algorithm/ranges_pop_heap.h>
#include <__algorithm/ranges_push_heap.h>
#include <__algorithm/ranges_remove.h>
diff --git a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp
index 07450d29541e5..51e4386969fb9 100644
--- a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_comparators.pass.cpp
@@ -177,10 +177,10 @@ constexpr bool all_the_algorithms()
//(void)std::ranges::partial_sort_copy(a, b, Less(&copies)); assert(copies == 0);
(void)std::ranges::partition(first, last, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::partition(a, UnaryTrue(&copies)); assert(copies == 0);
- //(void)std::ranges::partition_copy(first, last, first2, last2, UnaryTrue(&copies)); assert(copies == 0);
- //(void)std::ranges::partition_copy(a, first2, last2, UnaryTrue(&copies)); assert(copies == 0);
- //(void)std::ranges::partition_point(first, last, UnaryTrue(&copies)); assert(copies == 0);
- //(void)std::ranges::partition_point(a, UnaryTrue(&copies)); assert(copies == 0);
+ (void)std::ranges::partition_copy(first, last, first2, last2, UnaryTrue(&copies)); assert(copies == 0);
+ (void)std::ranges::partition_copy(a, first2, last2, UnaryTrue(&copies)); assert(copies == 0);
+ (void)std::ranges::partition_point(first, last, UnaryTrue(&copies)); assert(copies == 0);
+ (void)std::ranges::partition_point(a, UnaryTrue(&copies)); assert(copies == 0);
(void)std::ranges::pop_heap(first, last, Less(&copies)); assert(copies == 0);
(void)std::ranges::pop_heap(a, Less(&copies)); assert(copies == 0);
//(void)std::ranges::prev_permutation(first, last, Less(&copies)); assert(copies == 0);
diff --git a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp
index f29eb72d1946f..b5bc34029efb5 100644
--- a/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp
+++ b/libcxx/test/libcxx/algorithms/ranges_robust_against_copying_projections.pass.cpp
@@ -160,10 +160,10 @@ constexpr bool all_the_algorithms()
//(void)std::ranges::partial_sort_copy(a, b, Less(), Proj(&copies), Proj(&copies)); assert(copies == 0);
(void)std::ranges::partition(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::partition(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
- //(void)std::ranges::partition_copy(first, last, first2, last2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
- //(void)std::ranges::partition_copy(a, first2, last2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
- //(void)std::ranges::partition_point(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
- //(void)std::ranges::partition_point(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
+ (void)std::ranges::partition_copy(first, last, first2, last2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
+ (void)std::ranges::partition_copy(a, first2, last2, UnaryTrue(), Proj(&copies)); assert(copies == 0);
+ (void)std::ranges::partition_point(first, last, UnaryTrue(), Proj(&copies)); assert(copies == 0);
+ (void)std::ranges::partition_point(a, UnaryTrue(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::pop_heap(first, last, Less(), Proj(&copies)); assert(copies == 0);
(void)std::ranges::pop_heap(a, Less(), Proj(&copies)); assert(copies == 0);
//(void)std::ranges::prev_permutation(first, last, Less(), Proj(&copies)); assert(copies == 0);
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition.pass.cpp
index 4938f5f52e972..b7a532f7e0a6e 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition.pass.cpp
@@ -72,7 +72,7 @@ static_assert(HasPartitionRange<R<int*>, UnaryPred>);
// !forward_range<R>
static_assert(!HasPartitionRange<ForwardRangeNotDerivedFrom, UnaryPred>);
-static_assert(!HasPartitionRange<ForwardIteratorNotIncrementable, UnaryPred>);
+static_assert(!HasPartitionRange<ForwardRangeNotIncrementable, UnaryPred>);
// !indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
static_assert(!HasPartitionRange<R<int*>, IndirectUnaryPredicateNotPredicate>);
@@ -147,6 +147,10 @@ constexpr void test_iterators_2() {
test_one<Iter, Sent, 6>({4, 6, 8, 1, 3, 5}, is_odd, 3);
// Repeating pattern.
test_one<Iter, Sent, 6>({1, 2, 1, 2, 1, 2}, is_odd, 3);
+
+ auto is_negative = [](int x) { return x < 0; };
+ // Different comparator.
+ test_one<Iter, Sent, 5>({-3, 5, 7, -6, 2}, is_negative, 2);
}
template <class Iter>
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition_copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition_copy.pass.cpp
index 0ecb40592437a..d08caa7c0504e 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition_copy.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition_copy.pass.cpp
@@ -32,16 +32,268 @@
#include <concepts>
#include <functional>
#include <ranges>
+#include <utility>
#include "almost_satisfies_types.h"
+#include "counting_predicates.h"
+#include "counting_projection.h"
#include "test_iterators.h"
-// TODO: SFINAE tests.
+struct UnaryPred { bool operator()(int) const; };
+
+// Test constraints of the (iterator, sentinel) overload.
+// ======================================================
+
+template <class InIter = int*, class Sent = int*, class Output1 = int*, class Output2 = int*, class Pred = UnaryPred>
+concept HasPartitionCopyIter =
+ requires(InIter&& input, Sent&& sent, Output1&& output1, Output2&& output2, Pred&& pred) {
+ std::ranges::partition_copy(std::forward<InIter>(input), std::forward<Sent>(sent),
+ std::forward<Output1>(output1), std::forward<Output2>(output2), std::forward<Pred>(pred));
+ };
+
+static_assert(HasPartitionCopyIter<int*, int*, int*, int*, UnaryPred>);
+
+// !input_iterator<I>
+static_assert(!HasPartitionCopyIter<InputIteratorNotDerivedFrom>);
+static_assert(!HasPartitionCopyIter<InputIteratorNotIndirectlyReadable>);
+static_assert(!HasPartitionCopyIter<InputIteratorNotInputOrOutputIterator>);
+
+// !sentinel_for<S, I>
+static_assert(!HasPartitionCopyIter<int*, SentinelForNotSemiregular>);
+static_assert(!HasPartitionCopyIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
+
+// !weakly_incrementable<O1>
+static_assert(!HasPartitionCopyIter<int*, int*, WeaklyIncrementableNotMovable>);
+
+// !weakly_incrementable<O2>
+static_assert(!HasPartitionCopyIter<int*, int*, int*, WeaklyIncrementableNotMovable>);
+
+// !indirect_unary_predicate<projected<I, Proj>>
+static_assert(!HasPartitionCopyIter<int*, int*, int*, int*, IndirectUnaryPredicateNotPredicate>);
+static_assert(!HasPartitionCopyIter<int*, int*, int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
+
+struct Uncopyable {
+ Uncopyable(int&&);
+ Uncopyable(const int&) = delete;
+};
+// !indirectly_copyable<I, O1>
+static_assert(!HasPartitionCopyIter<int*, int*, Uncopyable*>);
+// !indirectly_copyable<I, O2>
+static_assert(!HasPartitionCopyIter<int*, int*, int*, Uncopyable*>);
+
+// Test constraints of the (range) overload.
+// =========================================
+
+template <class InputRange, class Output1 = int*, class Output2 = int*, class Pred = UnaryPred>
+concept HasPartitionCopyRange =
+ requires(InputRange&& input, Output1&& output1, Output2&& output2, Pred&& pred) {
+ std::ranges::partition_copy(std::forward<InputRange>(input),
+ std::forward<Output1>(output1), std::forward<Output2>(output2), std::forward<Pred>(pred));
+ };
+
+template <class T>
+using R = UncheckedRange<T>;
+
+static_assert(HasPartitionCopyRange<R<int*>, int*, int*, UnaryPred>);
+
+// !input_iterator<I>
+static_assert(!HasPartitionCopyRange<InputRangeNotDerivedFrom>);
+static_assert(!HasPartitionCopyRange<InputRangeNotIndirectlyReadable>);
+static_assert(!HasPartitionCopyRange<InputRangeNotInputOrOutputIterator>);
+
+// !weakly_incrementable<O1>
+static_assert(!HasPartitionCopyRange<R<int*>, WeaklyIncrementableNotMovable>);
+
+// !weakly_incrementable<O2>
+static_assert(!HasPartitionCopyRange<R<int*>, int*, WeaklyIncrementableNotMovable>);
+
+// !indirect_unary_predicate<projected<I, Proj>>
+static_assert(!HasPartitionCopyRange<R<int*>, int*, int*, IndirectUnaryPredicateNotPredicate>);
+static_assert(!HasPartitionCopyRange<R<int*>, int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
+
+// !indirectly_copyable<I, O1>
+static_assert(!HasPartitionCopyRange<R<int*>, Uncopyable*>);
+// !indirectly_copyable<I, O2>
+static_assert(!HasPartitionCopyRange<R<int*>, int*, Uncopyable*>);
+
+static_assert(std::is_same_v<std::ranges::partition_copy_result<int, int, int>,
+ std::ranges::in_out_out_result<int, int, int>>);
+
+template <class Iter, class Sent, class OutIter1, class OutIter2, size_t N1, size_t N2, size_t N3, class Pred>
+constexpr void test_one(std::array<int, N1> input, Pred pred, std::array<int, N2> expected_true,
+ std::array<int, N3> expected_false) {
+ static_assert(N2 + N3 == N1);
+ using ResultT = std::ranges::partition_copy_result<Iter, OutIter1, OutIter2>;
+
+ auto begin = input.data();
+ auto end = input.data() + input.size();
+
+ { // (iterator, sentinel) overload.
+ std::array<int, N2> out1;
+ std::array<int, N3> out2;
+
+ std::same_as<ResultT> decltype(auto) result = std::ranges::partition_copy(
+ Iter(begin), Sent(Iter(end)), OutIter1(out1.begin()), OutIter2(out2.begin()), pred);
+
+ assert(base(result.in) == input.data() + input.size());
+ assert(base(result.out1) == out1.data() + expected_true.size());
+ assert(base(result.out2) == out2.data() + expected_false.size());
+
+ assert(std::ranges::equal(out1, expected_true));
+ assert(std::ranges::equal(out2, expected_false));
+ }
+
+ { // (range) overload.
+ std::ranges::subrange range{Iter(begin), Sent(Iter(end))};
+ std::array<int, N2> out1;
+ std::array<int, N3> out2;
+
+ std::same_as<ResultT> decltype(auto) result = std::ranges::partition_copy(
+ range, OutIter1(out1.begin()), OutIter2(out2.begin()), pred);
+
+ assert(base(result.in) == input.data() + input.size());
+ assert(base(result.out1) == out1.data() + expected_true.size());
+ assert(base(result.out2) == out2.data() + expected_false.size());
+
+ assert(std::ranges::equal(out1, expected_true));
+ assert(std::ranges::equal(out2, expected_false));
+ }
+}
+
+template <class InIter, class Sent, class Out1, class Out2>
+constexpr void test_iterators_in_sent_out1_out2() {
+ auto is_odd = [](int x) { return x % 2 != 0; };
+
+ // Empty sequence.
+ test_one<InIter, Sent, Out1, Out2, 0, 0, 0>({}, is_odd, {}, {});
+ // 1-element sequence, the element satisfies the predicate.
+ test_one<InIter, Sent, Out1, Out2, 1, 1, 0>({1}, is_odd, {1}, {});
+ // 1-element sequence, the element doesn't satisfy the predicate.
+ test_one<InIter, Sent, Out1, Out2, 1, 0, 1>({2}, is_odd, {}, {2});
+ // 2-element sequence, not in order.
+ test_one<InIter, Sent, Out1, Out2, 2, 1, 1>({2, 1}, is_odd, {1}, {2});
+ // 2-element sequence, already in order.
+ test_one<InIter, Sent, Out1, Out2, 2, 1, 1>({1, 2}, is_odd, {1}, {2});
+ // 3-element sequence.
+ test_one<InIter, Sent, Out1, Out2, 3, 2, 1>({2, 1, 3}, is_odd, {1, 3}, {2});
+ // Longer sequence.
+ test_one<InIter, Sent, Out1, Out2, 8, 4, 4>({2, 1, 3, 6, 8, 4, 11, 5}, is_odd, {1, 3, 11, 5}, {2, 6, 8, 4});
+ // Longer sequence with duplicates.
+ test_one<InIter, Sent, Out1, Out2, 8, 3, 5>({2, 1, 3, 6, 2, 8, 1, 6}, is_odd, {1, 3, 1}, {2, 6, 2, 8, 6});
+ // All elements are the same and satisfy the predicate.
+ test_one<InIter, Sent, Out1, Out2, 3, 3, 0>({1, 1, 1}, is_odd, {1, 1, 1}, {});
+ // All elements are the same and don't satisfy the predicate.
+ test_one<InIter, Sent, Out1, Out2, 3, 0, 3>({2, 2, 2}, is_odd, {}, {2, 2, 2});
+ // Already partitioned.
+ test_one<InIter, Sent, Out1, Out2, 6, 3, 3>({1, 3, 5, 4, 6, 8}, is_odd, {1, 3, 5}, {4, 6, 8});
+ // Reverse-partitioned.
+ test_one<InIter, Sent, Out1, Out2, 6, 3, 3>({4, 6, 8, 1, 3, 5}, is_odd, {1, 3, 5}, {4, 6, 8});
+ // Repeating pattern.
+ test_one<InIter, Sent, Out1, Out2, 6, 3, 3>({1, 2, 1, 2, 1, 2}, is_odd, {1, 1, 1}, {2, 2, 2});
+
+ auto is_negative = [](int x) { return x < 0; };
+ // Different comparator.
+ test_one<InIter, Sent, Out1, Out2, 5, 2, 3>({-3, 5, 7, -6, 2}, is_negative, {-3, -6}, {5, 7, 2});
+}
+
+template <class InIter, class Sent, class Out1>
+constexpr void test_iterators_in_sent_out1() {
+ test_iterators_in_sent_out1_out2<InIter, Sent, Out1, cpp20_output_iterator<int*>>();
+ test_iterators_in_sent_out1_out2<InIter, Sent, Out1, random_access_iterator<int*>>();
+ test_iterators_in_sent_out1_out2<InIter, Sent, Out1, int*>();
+}
+
+template <class InIter, class Sent>
+constexpr void test_iterators_in_sent() {
+ test_iterators_in_sent_out1<InIter, Sent, cpp17_output_iterator<int*>>();
+ test_iterators_in_sent_out1<InIter, Sent, cpp20_output_iterator<int*>>();
+ test_iterators_in_sent_out1<InIter, Sent, random_access_iterator<int*>>();
+ test_iterators_in_sent_out1<InIter, Sent, int*>();
+}
+
+template <class InIter>
+constexpr void test_iterators_in() {
+ if constexpr (std::sentinel_for<InIter, InIter>) {
+ test_iterators_in_sent<InIter, InIter>();
+ }
+ test_iterators_in_sent<InIter, sentinel_wrapper<InIter>>();
+}
+
+constexpr void test_iterators() {
+ // Note: deliberately testing with only the weakest and "strongest" iterator types to minimize combinatorial
+ // explosion.
+ test_iterators_in<cpp20_input_iterator<int*>>();
+ test_iterators_in<int*>();
+}
constexpr bool test() {
- // TODO: main tests.
- // TODO: A custom comparator works.
- // TODO: A custom projection works.
+ test_iterators();
+
+ { // A custom projection works.
+ const std::array in = {1, 3, 9, -2, -5, -8};
+ auto is_negative = [](int x) { return x < 0; };
+ auto negate = [](int x) { return -x; };
+ const std::array expected_negative = {-2, -5, -8};
+ const std::array expected_positive = {1, 3, 9};
+
+ { // (iterator, sentinel) overload.
+ {
+ std::array<int, 3> out1, out2;
+ std::ranges::partition_copy(in.begin(), in.end(), out1.begin(), out2.begin(), is_negative);
+ assert(out1 == expected_negative);
+ assert(out2 == expected_positive);
+ }
+ {
+ std::array<int, 3> out1, out2;
+ std::ranges::partition_copy(in.begin(), in.end(), out1.begin(), out2.begin(), is_negative, negate);
+ assert(out1 == expected_positive);
+ assert(out2 == expected_negative);
+ }
+ }
+
+ { // (range) overload.
+ {
+ std::array<int, 3> out1, out2;
+ std::ranges::partition_copy(in, out1.begin(), out2.begin(), is_negative);
+ assert(out1 == expected_negative);
+ assert(out2 == expected_positive);
+ }
+ {
+ std::array<int, 3> out1, out2;
+ std::ranges::partition_copy(in, out1.begin(), out2.begin(), is_negative, negate);
+ assert(out1 == expected_positive);
+ assert(out2 == expected_negative);
+ }
+ }
+ }
+
+ { // Complexity: Exactly `last - first` applications of `pred` and `proj`.
+ {
+ const std::array in = {-2, -5, -8, -11, -10, -5, 1, 3, 9, 6, 8, 2, 4, 2};
+ auto is_negative = [](int x) { return x < 0; };
+ std::array<int, 6> out1;
+ std::array<int, 8> out2;
+
+ int pred_count = 0, proj_count = 0;
+ counting_predicate pred(is_negative, pred_count);
+ counting_projection proj(proj_count);
+ auto expected = static_cast<int>(in.size());
+
+ {
+ std::ranges::partition_copy(in.begin(), in.end(), out1.begin(), out2.begin(), pred, proj);
+ assert(pred_count == expected);
+ assert(proj_count == expected);
+ pred_count = proj_count = 0;
+ }
+
+ {
+ std::ranges::partition_copy(in, out1.begin(), out2.begin(), pred, proj);
+ assert(pred_count == expected);
+ assert(proj_count == expected);
+ pred_count = proj_count = 0;
+ }
+ }
+ }
return true;
}
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition_point.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition_point.pass.cpp
index 97d1bc8ff2255..5dffcaf2e2370 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition_point.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_partition_point.pass.cpp
@@ -25,16 +25,152 @@
#include <concepts>
#include <functional>
#include <ranges>
+#include <utility>
#include "almost_satisfies_types.h"
#include "test_iterators.h"
-// TODO: SFINAE tests.
+struct UnaryPred { bool operator()(int) const; };
+
+// Test constraints of the (iterator, sentinel) overload.
+// ======================================================
+
+template <class Iter = int*, class Sent = int*, class Pred = UnaryPred>
+concept HasPartitionPointIter =
+ requires(Iter&& iter, Sent&& sent, Pred&& pred) {
+ std::ranges::partition_point(std::forward<Iter>(iter), std::forward<Sent>(sent), std::forward<Pred>(pred));
+ };
+
+static_assert(HasPartitionPointIter<int*, int*, UnaryPred>);
+
+// !forward_iterator<I>
+static_assert(!HasPartitionPointIter<ForwardIteratorNotDerivedFrom>);
+static_assert(!HasPartitionPointIter<ForwardIteratorNotIncrementable>);
+
+// !sentinel_for<S, I>
+static_assert(!HasPartitionPointIter<int*, SentinelForNotSemiregular>);
+static_assert(!HasPartitionPointIter<int*, SentinelForNotWeaklyEqualityComparableWith>);
+
+// !indirect_unary_predicate<projected<I, Proj>>
+static_assert(!HasPartitionPointIter<int*, int*, IndirectUnaryPredicateNotPredicate>);
+static_assert(!HasPartitionPointIter<int*, int*, IndirectUnaryPredicateNotCopyConstructible>);
+
+// Test constraints of the (range) overload.
+// =========================================
+
+template <class Range, class Pred>
+concept HasPartitionPointRange =
+ requires(Range&& range, Pred&& pred) {
+ std::ranges::partition_point(std::forward<Range>(range), std::forward<Pred>(pred));
+ };
+
+template <class T>
+using R = UncheckedRange<T>;
+
+static_assert(HasPartitionPointRange<R<int*>, UnaryPred>);
+
+// !forward_range<R>
+static_assert(!HasPartitionPointRange<ForwardRangeNotDerivedFrom, UnaryPred>);
+static_assert(!HasPartitionPointRange<ForwardRangeNotIncrementable, UnaryPred>);
+
+// !indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
+static_assert(!HasPartitionPointRange<R<int*>, IndirectUnaryPredicateNotPredicate>);
+static_assert(!HasPartitionPointRange<R<int*>, IndirectUnaryPredicateNotCopyConstructible>);
+
+template <class Iter, class Sent, size_t N, class Pred>
+constexpr void test_one(std::array<int, N> input, Pred pred, size_t partition_point) {
+ assert(std::ranges::is_partitioned(input, pred));
+
+ auto begin = Iter(input.data());
+ auto end = Sent(Iter(input.data() + input.size()));
+ auto neg_pred = [&](int x) { return !pred(x); };
+
+ { // (iterator, sentinel) overload.
+ std::same_as<Iter> decltype(auto) result = std::ranges::partition_point(begin, end, pred);
+
+ assert(base(result) == input.data() + partition_point);
+ assert(std::ranges::all_of(begin, result, pred));
+ assert(std::ranges::all_of(result, end, neg_pred));
+ }
+
+ { // (range) overload.
+ auto range = std::ranges::subrange(begin, end);
+ std::same_as<Iter> decltype(auto) result = std::ranges::partition_point(range, pred);
+
+ assert(base(result) == input.data() + partition_point);
+ assert(std::ranges::all_of(begin, result, pred));
+ assert(std::ranges::all_of(result, end, neg_pred));
+ }
+}
+
+template <class Iter, class Sent>
+constexpr void test_iterators_2() {
+ auto is_odd = [](int x) { return x % 2 != 0; };
+
+ // Empty sequence.
+ test_one<Iter, Sent, 0>({}, is_odd, 0);
+ // 1-element sequence, the element satisfies the predicate.
+ test_one<Iter, Sent, 1>({1}, is_odd, 1);
+ // 1-element sequence, the element doesn't satisfy the predicate.
+ test_one<Iter, Sent, 1>({2}, is_odd, 0);
+ // 2-element sequence.
+ test_one<Iter, Sent, 2>({1, 2}, is_odd, 1);
+ // 3-element sequence.
+ test_one<Iter, Sent, 3>({3, 1, 2}, is_odd, 2);
+ // Longer sequence.
+ test_one<Iter, Sent, 8>({1, 3, 11, 5, 6, 2, 8, 4}, is_odd, 4);
+ // Longer sequence with duplicates.
+ test_one<Iter, Sent, 8>({1, 3, 3, 4, 6, 2, 8, 2}, is_odd, 3);
+ // All elements are the same and satisfy the predicate.
+ test_one<Iter, Sent, 3>({1, 1, 1}, is_odd, 3);
+ // All elements are the same and don't satisfy the predicate.
+ test_one<Iter, Sent, 3>({2, 2, 2}, is_odd, 0);
+ // All non-satisfying and all satisfying elements are the same.
+ test_one<Iter, Sent, 6>({1, 1, 1, 2, 2, 2}, is_odd, 3);
+
+ auto is_negative = [](int x) { return x < 0; };
+ // Different comparator.
+ test_one<Iter, Sent, 5>({-3, -6, 5, 7, 2}, is_negative, 2);
+}
+
+template <class Iter>
+constexpr void test_iterators_1() {
+ test_iterators_2<Iter, Iter>();
+ test_iterators_2<Iter, sentinel_wrapper<Iter>>();
+}
+
+constexpr void test_iterators() {
+ test_iterators_1<forward_iterator<int*>>();
+ test_iterators_1<bidirectional_iterator<int*>>();
+ test_iterators_1<random_access_iterator<int*>>();
+ test_iterators_1<contiguous_iterator<int*>>();
+ test_iterators_1<int*>();
+}
constexpr bool test() {
- // TODO: main tests.
- // TODO: A custom comparator works.
- // TODO: A custom projection works.
+ test_iterators();
+
+ { // A custom projection works.
+ const std::array in = {1, 3, 4, 6, 8};
+ auto is_odd = [](int x) { return x % 2 != 0; };
+ auto x2 = [](int x) { return x * 2; };
+ auto expected_no_proj = in.begin() + 2;
+ auto expected_with_proj = in.begin();
+
+ { // (iterator, sentinel) overload.
+ auto result_no_proj = std::ranges::partition_point(in.begin(), in.end(), is_odd);
+ assert(result_no_proj == expected_no_proj);
+ auto result_with_proj = std::ranges::partition_point(in.begin(), in.end(), is_odd, x2);
+ assert(result_with_proj == expected_with_proj);
+ }
+
+ { // (range) overload.
+ auto result_no_proj = std::ranges::partition_point(in, is_odd);
+ assert(result_no_proj == expected_no_proj);
+ auto result_with_proj = std::ranges::partition_point(in, is_odd, x2);
+ assert(result_with_proj == expected_with_proj);
+ }
+ }
return true;
}
diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_stable_partition.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_stable_partition.pass.cpp
index 6fcaa8e621cb2..e9971e3e084be 100644
--- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_stable_partition.pass.cpp
+++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.partitions/ranges_stable_partition.pass.cpp
@@ -151,6 +151,10 @@ void test_iterators_2() {
test_one<Iter, Sent, 6>({4, 6, 8, 1, 3, 5}, is_odd, 3, {1, 3, 5, 4, 6, 8});
// Repeating pattern.
test_one<Iter, Sent, 6>({1, 2, 1, 2, 1, 2}, is_odd, 3, {1, 1, 1, 2, 2, 2});
+
+ auto is_negative = [](int x) { return x < 0; };
+ // Different comparator.
+ test_one<Iter, Sent, 5>({-3, 5, 7, -6, 2}, is_negative, 2, {-3, -6, 5, 7, 2});
}
template <class Iter>
diff --git a/libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp b/libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp
index 623f75a1fd010..a694376ca6ec1 100644
--- a/libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_result_alias_declarations.compile.pass.cpp
@@ -47,11 +47,11 @@ static_assert(std::is_same_v<in_out_result<int, long>, uninitialized_move_n_resu
static_assert(std::is_same_v<in_in_out_result<int, long, char>, binary_transform_result<int, long, char>>);
static_assert(std::is_same_v<in_in_out_result<int, long, char>, merge_result<int, long, char>>);
-// static_assert(std::is_same_v<in_in_out_result<int, long, char>, set_symmetric_
diff erence_result<int, long, char>>);
-// static_assert(std::is_same_v<in_in_out_result<int, long, char>, set_union_result<int, long, char>>);
-// static_assert(std::is_same_v<in_in_out_result<int, long, char>, set_intersection_result<int, long, char>>);
+static_assert(std::is_same_v<in_in_out_result<int, long, char>, set_symmetric_
diff erence_result<int, long, char>>);
+static_assert(std::is_same_v<in_in_out_result<int, long, char>, set_union_result<int, long, char>>);
+static_assert(std::is_same_v<in_in_out_result<int, long, char>, set_intersection_result<int, long, char>>);
-// static_assert(std::is_same_v<in_out_out_result<int, long, char>, partition_copy_result<int, long, char>>);
+static_assert(std::is_same_v<in_out_out_result<int, long, char>, partition_copy_result<int, long, char>>);
static_assert(std::is_same_v<min_max_result<int>, minmax_result<int>>);
static_assert(std::is_same_v<min_max_result<int>, minmax_element_result<int>>);
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp
index 21b6f440b05f9..52d9f26280fbb 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_dangling.pass.cpp
@@ -75,7 +75,7 @@ constexpr bool test_all() {
using std::ranges::move_result;
//using std::ranges::move_backward_result;
//using std::ranges::partial_sort_copy_result;
- //using std::ranges::partition_copy_result;
+ using std::ranges::partition_copy_result;
//using std::ranges::remove_copy_result;
//using std::ranges::remove_copy_if_result;
using std::ranges::reverse_copy_result;
@@ -100,7 +100,7 @@ constexpr bool test_all() {
std::array output = {7, 8, 9, 10, 11, 12};
auto out = output.begin();
- //auto out2 = output.begin() + 1;
+ auto out2 = output.begin() + 1;
int x = 2;
size_t count = 1;
@@ -113,7 +113,7 @@ constexpr bool test_all() {
dangling_1st<mismatch_result<dangling, int*>>(std::ranges::mismatch, in, in2);
dangling_2nd<mismatch_result<int*, dangling>>(std::ranges::mismatch, in, in2);
dangling_both<mismatch_result<dangling, dangling>>(std::ranges::mismatch, in, in2);
- //dangling_1st(std::ranges::partition_point, in, unary_pred);
+ dangling_1st(std::ranges::partition_point, in, unary_pred);
dangling_1st(std::ranges::lower_bound, in, x);
dangling_1st(std::ranges::upper_bound, in, x);
//dangling_1st(std::ranges::equal_range, in, x);
@@ -157,7 +157,7 @@ constexpr bool test_all() {
dangling_1st<reverse_copy_result<dangling, int*>>(std::ranges::reverse_copy, in, out);
dangling_1st<rotate_copy_result<dangling, int*>>(std::ranges::rotate_copy, in, mid, out);
//dangling_1st<unique_copy_result<dangling, int*>>(std::ranges::unique_copy, in, out);
- //dangling_1st<partition_copy_result<dangling, int*, int*>>std::ranges::partition_copy(in, out, out2, unary_pred);
+ dangling_1st<partition_copy_result<dangling, int*, int*>>(std::ranges::partition_copy, in, out, out2, unary_pred);
//dangling_1st<partial_sort_copy_result<dangling, int*>>(std::ranges::partial_sort_copy, in, in2);
//dangling_2nd<partial_sort_copy_result<int*, dangling>>(std::ranges::partial_sort_copy, in, in2);
//dangling_both<partial_sort_copy_result<dangling, dangling>>(std::ranges::partial_sort_copy, in, in2);
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
index f2ffab78cbd20..9fc9c1f8d0f28 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_nonbool_predicates.pass.cpp
@@ -62,7 +62,7 @@ constexpr bool test_all() {
std::array output = {7, 8, 9, 10, 11, 12};
auto out = output.begin();
- //auto out2 = output.begin() + 1;
+ auto out2 = output.begin() + 1;
int x = 2;
int count = 1;
@@ -77,7 +77,7 @@ constexpr bool test_all() {
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, unary_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);
@@ -116,7 +116,7 @@ constexpr bool test_all() {
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::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);
test(std::ranges::set_
diff erence, in, in2, out, binary_pred);
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.pass.cpp
index 84b8269739e67..e70ae510889c8 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_omitting_invoke.pass.cpp
@@ -63,7 +63,7 @@ constexpr bool test_all() {
std::array output = {Bar{Foo{7}}, Bar{Foo{8}}, Bar{Foo{9}}, Bar{Foo{10}}, Bar{Foo{11}}, Bar{Foo{12}}};
auto out = output.begin();
- //auto out2 = output.begin() + 1;
+ auto out2 = output.begin() + 1;
Bar a{Foo{1}};
Bar b{Foo{2}};
@@ -83,7 +83,7 @@ constexpr bool test_all() {
test(std::ranges::mismatch, in, in2, &Foo::binary_pred, &Bar::val, &Bar::val);
test(std::ranges::equal, in, in2, &Foo::binary_pred, &Bar::val, &Bar::val);
test(std::ranges::lexicographical_compare, in, in2, &Foo::binary_pred, &Bar::val, &Bar::val);
- //test(std::ranges::partition_point, in, &Foo::unary_pred, &Bar::val);
+ test(std::ranges::partition_point, in, &Foo::unary_pred, &Bar::val);
test(std::ranges::lower_bound, in, x, &Foo::binary_pred, &Bar::val);
test(std::ranges::upper_bound, in, x, &Foo::binary_pred, &Bar::val);
//test(std::ranges::equal_range, in, x, &Foo::binary_pred, &Bar::val);
@@ -142,7 +142,7 @@ constexpr bool test_all() {
// `rotate_copy` has neither a projection nor a predicate.
// `sample` has no requirement that the given generator be invoked via `std::invoke`.
//test(std::ranges::unique_copy, in, out, &Foo::binary_pred, &Bar::val);
- //test(std::ranges::partition_copy, in, out, out2, &Foo::unary_pred, &Bar::val);
+ test(std::ranges::partition_copy, in, out, out2, &Foo::unary_pred, &Bar::val);
//test(std::ranges::partial_sort_copy, in, in2, &Foo::binary_pred, &Bar::val);
test(std::ranges::merge, in, in2, out, &Foo::binary_pred, &Bar::val, &Bar::val);
test(std::ranges::set_
diff erence, in, in2, out, &Foo::binary_pred, &Bar::val, &Bar::val);
diff --git a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
index 895fea9603aec..cfa54db5bc808 100644
--- a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
+++ b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp
@@ -59,7 +59,7 @@ constexpr void run_tests() {
std::array output = {T{4}, T{5}, T{6}, T{7}, T{8}, T{9}};
ProxyIterator out{output.begin()};
- //auto out2 = output.begin() + 1;
+ ProxyIterator out2{output.begin() + 1};
T num{2};
Proxy<T&> x{num};
@@ -82,7 +82,7 @@ constexpr void run_tests() {
test(std::ranges::mismatch, in, in2);
test(std::ranges::equal, in, in2);
test(std::ranges::lexicographical_compare, in, in2);
- //test(std::ranges::partition_point, unary_pred);
+ test(std::ranges::partition_point, in, unary_pred);
test(std::ranges::lower_bound, in, x);
test(std::ranges::upper_bound, in, x);
//test(std::ranges::equal_range, in, x);
@@ -136,7 +136,7 @@ constexpr void run_tests() {
test(std::ranges::reverse_copy, in, out);
test_mid(std::ranges::rotate_copy, in, mid, out);
//test(std::ranges::unique_copy, in, out);
- //test(std::ranges::partition_copy, in, out, out2, unary_pred);
+ test(std::ranges::partition_copy, in, out, out2, unary_pred);
//test_mid(std::ranges::partial_sort_copy, in, in2);
test(std::ranges::merge, in, in2, out);
test(std::ranges::set_
diff erence, in, in2, out);
diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp
index 077fe65ccc855..6ac3ca96669e1 100644
--- a/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp
+++ b/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp
@@ -113,8 +113,8 @@ static_assert(test(std::ranges::nth_element, a, a+5));
static_assert(test(std::ranges::partial_sort, a, a+5));
//static_assert(test(std::ranges::partial_sort_copy, a, a));
static_assert(test(std::ranges::partition, a, odd));
-//static_assert(test(std::ranges::partition_copy, a, a, a, odd));
-//static_assert(test(std::ranges::partition_point, a, odd));
+static_assert(test(std::ranges::partition_copy, a, a, a, odd));
+static_assert(test(std::ranges::partition_point, a, odd));
static_assert(test(std::ranges::pop_heap, a));
//static_assert(test(std::ranges::prev_permutation, a));
static_assert(test(std::ranges::push_heap, a));
diff --git a/libcxx/test/support/counting_predicates.h b/libcxx/test/support/counting_predicates.h
index 1868d30b471e9..3f86bf2a3993e 100644
--- a/libcxx/test/support/counting_predicates.h
+++ b/libcxx/test/support/counting_predicates.h
@@ -10,6 +10,8 @@
#define TEST_SUPPORT_COUNTING_PREDICATES_H
#include <cstddef>
+#include <utility>
+#include "test_macros.h"
template <typename Predicate, typename Arg>
struct unary_counting_predicate {
@@ -49,4 +51,27 @@ struct binary_counting_predicate {
mutable size_t count_;
};
+#if TEST_STD_VER > 14
+
+template <class Predicate>
+class counting_predicate {
+ Predicate pred_;
+ int* count_ = nullptr;
+
+public:
+ constexpr counting_predicate() = default;
+ constexpr counting_predicate(Predicate pred, int& count) : pred_(std::move(pred)), count_(&count) {}
+
+ template <class... Args>
+ constexpr decltype(auto) operator()(Args&& ...args) const {
+ ++(*count_);
+ return pred_(std::forward<Args>(args)...);
+ }
+};
+
+template <class Predicate>
+counting_predicate(Predicate pred, int& count) -> counting_predicate<Predicate>;
+
+#endif // TEST_STD_VER > 14
+
#endif // TEST_SUPPORT_COUNTING_PREDICATES_H
diff --git a/libcxx/test/support/counting_projection.h b/libcxx/test/support/counting_projection.h
new file mode 100644
index 0000000000000..714058c1c045d
--- /dev/null
+++ b/libcxx/test/support/counting_projection.h
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 TEST_SUPPORT_COUNTING_PROJECTION_H
+#define TEST_SUPPORT_COUNTING_PROJECTION_H
+
+#include <functional>
+#include <utility>
+#include "test_macros.h"
+
+#if TEST_STD_VER > 14
+
+template <class Proj = std::identity>
+class counting_projection {
+ Proj proj_;
+ int* count_ = nullptr;
+
+public:
+ constexpr counting_projection() = default;
+ constexpr counting_projection(int& count) : count_(&count) {}
+ constexpr counting_projection(Proj proj, int& count) : proj_(std::move(proj)), count_(&count) {}
+
+ template <class T>
+ constexpr decltype(auto) operator()(T&& value) const {
+ ++(*count_);
+ return proj_(std::forward<T>(value));
+ }
+};
+
+counting_projection(int& count) -> counting_projection<std::identity>;
+template <class Proj>
+counting_projection(Proj proj, int& count) -> counting_projection<Proj>;
+
+#endif // TEST_STD_VER > 14
+
+#endif // TEST_SUPPORT_COUNTING_PROJECTION_H
More information about the libcxx-commits
mailing list