std::ranges...le_partition(3)
okay so bestie, welcome to the std::ranges::stable_partition page from the C++ Standard Library π
this is that (3) manpage energy, but make it group chat β¨
π NAME π
std::ranges::stable_partition β std::ranges::stable_partition π (yes, the page really said the name twice, and honestly? iconic.)
β¨ Synopsis β¨
Defined in header <algorithm>.
Call signature
template< std::bidirectional_iterator I, std::sentinel_for<I> S,
class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
requires std::permutable<I>
ranges::subrange<I>
stable_partition( I first, S last, Pred pred, Proj proj = {} );
Overload (1) β since C++20, constexpr since C++26.
template< ranges::bidirectional_range R, class Proj = std::identity,
std::indirect_unary_predicate<
std::projected<ranges::iterator_t<R>, Proj>> Pred >
requires std::permutable<ranges::iterator_t<R>>
ranges::borrowed_subrange_t<R>
stable_partition( R&& r, Pred pred, Proj proj = {} );
Overload (2) β since C++20, constexpr since C++26.
- Reorders the elements in the range
[first, last)in such a way that the projectionprojof all elements for which the predicatepredreturnstrueprecede the projectionprojof elements for which predicatepredreturnsfalse. The algorithm is stable, i.e. the relative order of elements is preserved. - Same as (1), but uses
ras the range, as if usingranges::begin(r)asfirstandranges::end(r)aslast.
The function-like entities described on this page are niebloids, that is:
- Explicit template argument lists cannot be specified when calling any of them.
- None of them are visible to argument-dependent lookup.
- When any of them are found by normal unqualified lookup as the name to the left of the function-call operator, argument-dependent lookup is inhibited.
In practice, they may be implemented as function objects, or with special compiler extensions.
πΈ Parameters πΈ
first,lastβ the range of elements to reorder.rβ the range of elements to reorder.predβ predicate to apply to the projected elements.projβ projection to apply to the elements.
π Return value π
- An object equal to
{pivot, last}, wherepivotis an iterator to the first element of the second group. - Same as (1) if
ris an lvalue or of aborrowed_rangetype. Otherwise returnsstd::ranges::dangling.
π¦ Complexity π¦
Given N = ranges::distance(first, last), the complexity is at worst NΒ·log(N) swaps, and only O(N) swaps in case an extra memory buffer is used. Exactly N applications of the predicate pred and projection proj.
π Notes π
This function attempts to allocate a temporary buffer. If the allocation fails, the less efficient algorithm is chosen.
π§ͺ Feature-test macro π§ͺ
The feature-test macro table says:
__cpp_lib_constexpr_algorithmsβ value202306Lβ feature:constexpr stable sorting. (TheStdcell is blank in the original, bestie, donβt @ me.)
π§ Possible implementation π§
This implementation does not use extra memory buffer and as such can be less efficient. See also the implementation in MSVC STL and libstdc++.
struct stable_partition_fn {
template<std::bidirectional_iterator I, std::sentinel_for<I> S,
class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
requires std::permutable<I>
constexpr ranges::subrange<I>
operator()(I first, S last, Pred pred, Proj proj = {}) const
{
first = ranges::find_if_not(first, last, pred, proj);
I mid = first;
while (mid != last)
{
mid = ranges::find_if(mid, last, pred, proj);
if (mid == last)
break;
I last2 = ranges::find_if_not(mid, last, pred, proj);
ranges::rotate(first, mid, last2);
first = ranges::next(first, ranges::distance(mid, last2));
mid = last2;
}
return {std::move(first), std::move(mid)};
}
template<ranges::bidirectional_range R, class Proj = std::identity,
std::indirect_unary_predicate<
std::projected<ranges::iterator_t<R>, Proj>> Pred>
requires std::permutable<ranges::iterator_t<R>>
constexpr ranges::borrowed_subrange_t<R>
operator()(R&& r, Pred pred, Proj proj = {}) const
{
return (*this)(ranges::begin(r), ranges::end(r),
std::move(pred), std::move(proj));
} };
inline constexpr stable_partition_fn stable_partition {};
π Example π
// Run this code
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
namespace rng = std::ranges;
template<std::permutable I, std::sentinel_for<I> S>
constexpr void stable_sort(I first, S last)
{
if (first == last)
return;
auto pivot = *rng::next(first, rng::distance(first, last) / 2, last);
auto left = [pivot](const auto& em) { return em < pivot; };
auto tail1 = rng::stable_partition(first, last, left);
auto right = [pivot](const auto& em) { return !(pivot < em); };
auto tail2 = rng::stable_partition(tail1, right);
stable_sort(first, tail1.begin());
stable_sort(tail2.begin(), tail2.end());
}
void print(const auto rem, auto first, auto last, bool end = true)
{
std::cout << rem;
for (; first != last; ++first)
std::cout << *first << ' ';
std::cout << (end ? "\n" : "");
}
int main()
{
const auto original = {9, 6, 5, 2, 3, 1, 7, 8};
std::vector<int> vi {};
auto even = [](int x) { return 0 == (x % 2); };
print("Original vector:\t", original.begin(), original.end(), "\n");
vi = original;
const auto ret1 = rng::stable_partition(vi, even);
print("Stable partitioned:\t", vi.begin(), ret1.begin(), 0);
print("β ", ret1.begin(), ret1.end());
vi = original;
const auto ret2 = rng::partition(vi, even);
print("Partitioned:\t\t", vi.begin(), ret2.begin(), 0);
print("β ", ret2.begin(), ret2.end());
vi = {16, 30, 44, 30, 15, 24, 10, 18, 12, 35};
print("Unsorted vector: ", vi.begin(), vi.end());
stable_sort(rng::begin(vi), rng::end(vi));
print("Sorted vector: ", vi.begin(), vi.end());
}
β Possible output β
Original vector: 9 6 5 2 3 1 7 8
Stable partitioned: 6 2 8 β 9 5 3 1 7
Partitioned: 8 6 2 β 5 3 1 7 9
Unsorted vector: 16 30 44 30 15 24 10 18 12 35
Sorted vector: 10 12 15 16 18 24 30 30 35 44
π See also π
ranges::partitionβ divides a range of elements into two groups (C++20) (niebloid).ranges::partition_copyβ copies a range dividing the elements into two groups (C++20) (niebloid).ranges::is_partitionedβ determines if the range is partitioned by the given predicate (C++20) (niebloid).stable_partitionβ divides elements into two groups while preserving their relative order (function template).
source/version: http://cppreference.com Β· date: 2024.06.10 Β· manual page: std::ranges::stable_partition(3) β thatβs the whole tea, bye bestie! π«Άπ
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms