Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions libcxx/include/__algorithm/ranges_stable_sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
struct __stable_sort {
template <class _Iter, class _Sent, class _Comp, class _Proj>
_LIBCPP_HIDE_FROM_ABI static _Iter __stable_sort_fn_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) {
_LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_SINCE_CXX26 _Iter
__stable_sort_fn_impl(_Iter __first, _Sent __last, _Comp& __comp, _Proj& __proj) {
auto __last_iter = ranges::next(__first, __last);

auto&& __projected_comp = std::__make_projected(__comp, __proj);
Expand All @@ -52,13 +53,14 @@ struct __stable_sort {

template <random_access_iterator _Iter, sentinel_for<_Iter> _Sent, class _Comp = ranges::less, class _Proj = identity>
requires sortable<_Iter, _Comp, _Proj>
_LIBCPP_HIDE_FROM_ABI _Iter operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 _Iter
operator()(_Iter __first, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
return __stable_sort_fn_impl(std::move(__first), std::move(__last), __comp, __proj);
}

template <random_access_range _Range, class _Comp = ranges::less, class _Proj = identity>
requires sortable<iterator_t<_Range>, _Comp, _Proj>
_LIBCPP_HIDE_FROM_ABI borrowed_iterator_t<_Range>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX26 borrowed_iterator_t<_Range>
operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const {
return __stable_sort_fn_impl(ranges::begin(__r), ranges::end(__r), __comp, __proj);
}
Expand Down
275 changes: 138 additions & 137 deletions libcxx/include/algorithm

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
// template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
// class Proj = identity>
// requires sortable<I, Comp, Proj>
// I ranges::stable_sort(I first, S last, Comp comp = {}, Proj proj = {}); // since C++20
// constexpr I // constexpr since C++26
// ranges::stable_sort(I first, S last, Comp comp = {}, Proj proj = {}); // since C++20
//
// template<random_access_range R, class Comp = ranges::less, class Proj = identity>
// requires sortable<iterator_t<R>, Comp, Proj>
// borrowed_iterator_t<R>
// constexpr borrowed_iterator_t<R> // constexpr since C++26
// ranges::stable_sort(R&& r, Comp comp = {}, Proj proj = {}); // since C++20

#include <algorithm>
Expand Down Expand Up @@ -57,7 +58,7 @@ static_assert(!HasStableSortR<UncheckedRange<int*>, BadComparator>);
static_assert(!HasStableSortR<UncheckedRange<const int*>>); // Doesn't satisfy `sortable`.

template <class Iter, class Sent, std::size_t N>
void test_one(std::array<int, N> input, std::array<int, N> expected) {
TEST_CONSTEXPR_CXX26 void test_one(std::array<int, N> input, std::array<int, N> expected) {
{ // (iterator, sentinel) overload.
auto sorted = input;
auto b = Iter(sorted.data());
Expand All @@ -81,7 +82,7 @@ void test_one(std::array<int, N> input, std::array<int, N> expected) {
}

template <class Iter, class Sent>
void test_iterators_2() {
TEST_CONSTEXPR_CXX26 void test_iterators_2() {
// Empty sequence.
test_one<Iter, Sent, 0>({}, {});
// 1-element sequence.
Expand All @@ -105,25 +106,25 @@ void test_iterators_2() {
}

template <class Iter>
void test_iterators_1() {
TEST_CONSTEXPR_CXX26 void test_iterators_1() {
test_iterators_2<Iter, Iter>();
test_iterators_2<Iter, sentinel_wrapper<Iter>>();
}

void test_iterators() {
TEST_CONSTEXPR_CXX26 void test_iterators() {
test_iterators_1<random_access_iterator<int*>>();
test_iterators_1<contiguous_iterator<int*>>();
test_iterators_1<int*>();
}

void test() {
TEST_CONSTEXPR_CXX26 bool test() {
test_iterators();

struct OrderedValue {
int value;
double original_order;
bool operator==(const OrderedValue&) const = default;
auto operator<=>(const OrderedValue& rhs) const { return value <=> rhs.value; }
TEST_CONSTEXPR_CXX26 auto operator<=>(const OrderedValue& rhs) const { return value <=> rhs.value; }
};

{ // The sort is stable (equivalent elements remain in the same order).
Expand Down Expand Up @@ -214,10 +215,10 @@ void test() {
{ // `std::invoke` is used in the implementation.
struct S {
int i;
S(int i_) : i(i_) {}
TEST_CONSTEXPR_CXX26 S(int i_) : i(i_) {}

bool comparator(const S& rhs) const { return i < rhs.i; }
const S& projection() const { return *this; }
TEST_CONSTEXPR_CXX26 bool comparator(const S& rhs) const { return i < rhs.i; }
TEST_CONSTEXPR_CXX26 const S& projection() const { return *this; }

bool operator==(const S&) const = default;
};
Expand All @@ -242,8 +243,6 @@ void test() {
std::ranges::stable_sort(std::array{1, 2, 3});
}

// TODO: Enable the tests once the implementation switched to use iter_move/iter_swap
/*
{ // ProxyIterator
{
std::array in = {2, 1, 3};
Expand All @@ -260,12 +259,15 @@ void test() {
assert((in == std::array{1, 2, 3}));
}
}
*/

return true;
}

int main(int, char**) {
test();
// Note: `stable_sort` is not `constexpr`.
#if TEST_STD_VER >= 26
static_assert(test());
#endif

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,12 @@ constexpr bool test_all() {
if (!std::is_constant_evaluated())
dangling_1st(std::ranges::stable_partition, in, unary_pred);
dangling_1st(std::ranges::sort, in);
#if TEST_STD_VER < 26
if (!std::is_constant_evaluated())
#endif
{
dangling_1st(std::ranges::stable_sort, in);
}
dangling_1st(std::ranges::partial_sort, in, mid);
dangling_1st(std::ranges::nth_element, in, mid);
if (!std::is_constant_evaluated())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,12 @@ constexpr bool test_all() {
if (!std::is_constant_evaluated())
test(std::ranges::stable_partition, in, &Foo::unary_pred, &Bar::val);
test(std::ranges::sort, in, &Foo::binary_pred, &Bar::val);
#if TEST_STD_VER < 26
if (!std::is_constant_evaluated())
#endif
{
test(std::ranges::stable_sort, in, &Foo::binary_pred, &Bar::val);
}
test_mid(std::ranges::partial_sort, in, mid, &Foo::binary_pred, &Bar::val);
test_mid(std::ranges::nth_element, in, mid, &Foo::binary_pred, &Bar::val);
if (!std::is_constant_evaluated())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,12 @@ constexpr void run_tests() {
if (!std::is_constant_evaluated())
test(std::ranges::stable_partition, in, unary_pred);
test(std::ranges::sort, in);
#if TEST_STD_VER < 26
if (!std::is_constant_evaluated())
#endif
{
test(std::ranges::stable_sort, in);
}
test_mid(std::ranges::partial_sort, in, mid);
test_mid(std::ranges::nth_element, in, mid);
if (!std::is_constant_evaluated())
Expand Down
4 changes: 4 additions & 0 deletions libcxx/test/support/test_iterators.h
Original file line number Diff line number Diff line change
Expand Up @@ -1208,6 +1208,10 @@ struct Proxy {

constexpr const T&& getData() const&& { return static_cast<const T&&>(data); }

// Explicitly declare the copy constructor as defaulted to avoid deprecation of the implicitly declared one
// because of the user-provided copy assignment operator.
Proxy(const Proxy&) = default;

template <class U>
requires std::constructible_from<T, U&&>
constexpr Proxy(U&& u) : data{std::forward<U>(u)} {}
Expand Down