std::is_sorted(3)

πŸ“¦ version 2024.07.05, in nixpkgs unstable, opensuse-leap 16.0

Hey bestie!! Welcome to std::is_sorted(3) from the C++ Standard Libary β€” this is the manual page that checks if a range is sorted, and it's lowkey iconic. πŸ¦‹βœ¨

πŸ’– NAME πŸ’–

std::is_sorted β€” std::is_sorted, periodt. That's the name, bestie, and we're moving on. πŸ’…

🌸 Synopsis 🌸

Defined in header <algorithm>

template< class ForwardIt >                              (1) (since C++11)
bool is_sorted( ForwardIt first, ForwardIt last );
(constexpr since C++20)

template< class ExecutionPolicy, class ForwardIt >
bool is_sorted( ExecutionPolicy&& policy,                (2) (since C++17)
                ForwardIt first, ForwardIt last );

template< class ForwardIt, class Compare >               (3) (since C++11)
bool is_sorted( ForwardIt first, ForwardIt last, Compare comp );
(constexpr since C++20)

template< class ExecutionPolicy, class ForwardIt, class Compare >
bool is_sorted( ExecutionPolicy&& policy,                (4) (since C++17)
                ForwardIt first, ForwardIt last, Compare comp );

Checks if the elements in range [first, last) are sorted in non-descending order. No notes, that's the whole vibe check. 🫢

  • 1) β€” checks if the elements are sorted with respect to operator< (until C++20) or std::less{} (since C++20).
  • 3) β€” checks if the elements are sorted with respect to comp.
  • 2,4) β€” same as (1,3), but executed according to policy. These overloads participate in overload resolution only if std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> is true (until C++20); std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> is true (since C++20).

✨ Parameters ✨

  • first, last β€” the range of elements to examine.
  • policy β€” the execution policy to use. See execution policy for details.
  • comp β€” comparison function object (i.e. an object that satisfies the requirements of Compare) which returns true if the first argument is less than (i.e. is ordered before) the second.

The signature of the comparison function should be equivalent to the following:

bool cmp(const Type1& a, const Type2& b);

While the signature does not need to have const&, the function must not modify the objects passed to it and must be able to accept all values of type (possibly const) Type1 and Type2 regardless of value category (thus, Type1& is not allowed, nor is Type1 unless for Type1 a move is equivalent to a copy (since C++11)). The types Type1 and Type2 must be such that an object of type ForwardIt can be dereferenced and then implicitly converted to both of them.

πŸ¦‹ Type requirements πŸ¦‹

  • ForwardIt must meet the requirements of LegacyForwardIterator.
  • Compare must meet the requirements of Compare.

πŸŽ€ Return value πŸŽ€

true if the elements in the range are sorted in non-descending order, false otherwise. That's it, bestie β€” sorted or not sorted, no in-between. πŸ’€

πŸ”₯ Complexity πŸ”₯

Given N as std::distance(first, last):

  • 1,2) β€” O(N) comparisons using operator< (until C++20) or std::less{} (since C++20).
  • 3,4) β€” O(N) applications of the comparator comp.

😭 Exceptions 😭

The overloads with a template parameter named ExecutionPolicy report errors as follows:

  • If execution of a function invoked as part of the algorithm throws an exception and ExecutionPolicy is one of the standard policies, std::terminate is called. For any other ExecutionPolicy, the behavior is implementation-defined.
  • If the algorithm fails to allocate memory, std::bad_alloc is thrown.
This is the "do not play with me" section, bestie. Read it before you send your execution policy into the group chat. πŸ™ˆ

πŸ‘‘ Possible implementation πŸ‘‘

Wanna peek at the real ones? See also the implementations in libstdc++ and libc++. πŸ‘€

is_sorted (1)

template<class ForwardIt>
bool is_sorted(ForwardIt first, ForwardIt last)
{
    return std::is_sorted_until(first, last) == last;
}

is_sorted (3)

template<class ForwardIt, class Compare>
bool is_sorted(ForwardIt first, ForwardIt last, Compare comp)
{
    return std::is_sorted_until(first, last, comp) == last;
}

πŸ’… Notes πŸ’…

std::is_sorted returns true for empty ranges and ranges of length one. So yes, the empty-vector girlies are always sorted, no cap. πŸ“

🌈 Example 🌈

// Run this code

#include <algorithm>
#include <cassert>
#include <functional>
#include <iterator>
#include <vector>

int main()
{
    std::vector<int> v;
    assert(std::is_sorted(v.cbegin(), v.cend()) && "an empty range is always sorted");
    v.push_back(42);
    assert(std::is_sorted(v.cbegin(), v.cend()) && "a range of size 1 is always sorted");

    int data[] = {3, 1, 4, 1, 5};
    assert(not std::is_sorted(std::begin(data), std::end(data)));

    std::sort(std::begin(data), std::end(data));
    assert(std::is_sorted(std::begin(data), std::end(data)));
    assert(not std::is_sorted(std::begin(data), std::end(data), std::greater<>{}));
}

⭐ See also ⭐

  • is_sorted_until β€” finds the largest sorted subrange (C++11) (function template)
  • ranges::is_sorted β€” checks whether a range is sorted into ascending order (C++20) (niebloid)

Source/version/date tea β˜•: http://cppreference.com, 2024.06.10, and this iconic page is std::is_sorted(3). Bye bestie, stay sorted! πŸ’–βœ¨

πŸ“¦ where this page comes from