Skip to content

Commit 2b69ba2

Browse files
committed
Add utility::is_sorted[_until]
1 parent 48225af commit 2b69ba2

File tree

5 files changed

+214
-0
lines changed

5 files changed

+214
-0
lines changed

docs/Miscellaneous-utilities.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,17 @@ struct dynamic_buffer;
137137

138138
This buffer provider allocates on the heap a number of elements depending on a given *size policy* (a class whose `operator()` takes the size of the collection and returns another size). You can use the function objects from `utility/functional.h` as basic size policies. The buffer construction may throw an instance of [`std::bad_alloc`][std-bad-alloc] if it fails to allocate the required memory.
139139

140+
### `is_sorted` and `is_sorted_until`
141+
142+
```cpp
143+
#include <cpp-sort/utility/is_sorted.h>
144+
#include <cpp-sort/utility/is_sorted_until.h>
145+
```
146+
147+
Simple reimplementations of the standard library algorithms [`std::is_sorted`][std-is-sorted] and [`std::is_sorted_until`][std-is-sorted-until], reimplemented as function objects that follow the library's *unified sorting interface*.
148+
149+
*New in version 2.1.0*
150+
140151
### Miscellaneous function objects
141152

142153
```cpp
@@ -543,6 +554,8 @@ assert(not cppsort::utility::check_strict_weak_ordering(vec, std::less{});)
543554
[std-invoke]: https://en.cppreference.com/w/cpp/utility/functional/invoke
544555
[std-is-arithmetic]: https://en.cppreference.com/w/cpp/types/is_arithmetic
545556
[std-is-member-function-pointer]: https://en.cppreference.com/w/cpp/types/is_member_function_pointer
557+
[std-is-sorted]: https://en.cppreference.com/w/cpp/algorithm/is_sorted.html
558+
[std-is-sorted-until]: https://en.cppreference.com/w/cpp/algorithm/is_sorted_until.html
546559
[std-less]: https://en.cppreference.com/w/cpp/utility/functional/less
547560
[std-less-void]: https://en.cppreference.com/w/cpp/utility/functional/less_void
548561
[std-mem-fn]: https://en.cppreference.com/w/cpp/utility/functional/mem_fn
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (c) 2026 Morwenn
3+
* SPDX-License-Identifier: MIT
4+
*/
5+
#ifndef CPPSORT_UTILITY_CHECK_IS_SORTED_H_
6+
#define CPPSORT_UTILITY_CHECK_IS_SORTED_H_
7+
8+
////////////////////////////////////////////////////////////
9+
// Headers
10+
////////////////////////////////////////////////////////////
11+
#include <functional>
12+
#include <iterator>
13+
#include <utility>
14+
#include <cpp-sort/sorter_facade.h>
15+
#include <cpp-sort/sorter_traits.h>
16+
#include <cpp-sort/utility/functional.h>
17+
#include "../detail/is_sorted_until.h"
18+
#include "../detail/type_traits.h"
19+
20+
namespace cppsort::utility
21+
{
22+
namespace detail
23+
{
24+
struct is_sorted_impl
25+
{
26+
template<
27+
typename ForwardIterator,
28+
typename Compare = std::less<>,
29+
typename Projection = utility::identity,
30+
typename = cppsort::detail::enable_if_t<
31+
is_projection_iterator_v<Projection, ForwardIterator, Compare>
32+
>
33+
>
34+
constexpr auto operator()(ForwardIterator first, ForwardIterator last,
35+
Compare compare={}, Projection projection={}) const
36+
-> bool
37+
{
38+
return cppsort::detail::is_sorted(
39+
first, last,
40+
std::move(compare), std::move(projection)
41+
);
42+
}
43+
44+
////////////////////////////////////////////////////////////
45+
// Sorter traits
46+
47+
using iterator_category = std::forward_iterator_tag;
48+
};
49+
}
50+
51+
struct is_sorted_t:
52+
sorter_facade<detail::is_sorted_impl>
53+
{};
54+
55+
inline constexpr is_sorted_t is_sorted{};
56+
}
57+
58+
#endif // CPPSORT_UTILITY_CHECK_IS_SORTED_H_
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright (c) 2026 Morwenn
3+
* SPDX-License-Identifier: MIT
4+
*/
5+
#ifndef CPPSORT_UTILITY_CHECK_IS_SORTED_UNTIL_H_
6+
#define CPPSORT_UTILITY_CHECK_IS_SORTED_UNTIL_H_
7+
8+
////////////////////////////////////////////////////////////
9+
// Headers
10+
////////////////////////////////////////////////////////////
11+
#include <functional>
12+
#include <iterator>
13+
#include <utility>
14+
#include <cpp-sort/sorter_facade.h>
15+
#include <cpp-sort/sorter_traits.h>
16+
#include <cpp-sort/utility/functional.h>
17+
#include "../detail/is_sorted_until.h"
18+
#include "../detail/type_traits.h"
19+
20+
namespace cppsort::utility
21+
{
22+
namespace detail
23+
{
24+
struct is_sorted_until_impl
25+
{
26+
template<
27+
typename ForwardIterator,
28+
typename Compare = std::less<>,
29+
typename Projection = utility::identity,
30+
typename = cppsort::detail::enable_if_t<
31+
is_projection_iterator_v<Projection, ForwardIterator, Compare>
32+
>
33+
>
34+
constexpr auto operator()(ForwardIterator first, ForwardIterator last,
35+
Compare compare={}, Projection projection={}) const
36+
-> ForwardIterator
37+
{
38+
return cppsort::detail::is_sorted_until(
39+
first, last,
40+
std::move(compare), std::move(projection)
41+
);
42+
}
43+
44+
////////////////////////////////////////////////////////////
45+
// Sorter traits
46+
47+
using iterator_category = std::forward_iterator_tag;
48+
};
49+
}
50+
51+
struct is_sorted_until_t:
52+
sorter_facade<detail::is_sorted_until_impl>
53+
{};
54+
55+
inline constexpr is_sorted_until_t is_sorted_until{};
56+
}
57+
58+
#endif // CPPSORT_UTILITY_CHECK_IS_SORTED_UNTIL_H_

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ add_executable(main-tests
264264
utility/buffer.cpp
265265
utility/chainable_projections.cpp
266266
utility/check_strict_weak_ordering.cpp
267+
utility/is_sorted.cpp
267268
utility/iter_swap.cpp
268269
utility/metric_tools.cpp
269270
utility/quicksort_adversary.cpp

tests/utility/is_sorted.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
* Copyright (c) 2026 Morwenn
3+
* SPDX-License-Identifier: MIT
4+
*/
5+
#include <iterator>
6+
#include <vector>
7+
#include <catch2/catch_test_macros.hpp>
8+
#include <cpp-sort/utility/is_sorted.h>
9+
#include <cpp-sort/utility/is_sorted_until.h>
10+
#include <testing-tools/distributions.h>
11+
12+
namespace utility = cppsort::utility;
13+
14+
TEST_CASE( "is_sorted and is_sorted_until test", "[utility][is_sorted]" )
15+
{
16+
SECTION( "empty collection" )
17+
{
18+
std::vector<int> vec = {};
19+
CHECK( utility::is_sorted(vec) );
20+
CHECK( utility::is_sorted_until(vec) == vec.end() );
21+
}
22+
23+
SECTION( "collection with one element" )
24+
{
25+
std::vector<int> vec = {5};
26+
CHECK( utility::is_sorted(vec) );
27+
CHECK( utility::is_sorted_until(vec) == vec.end() );
28+
}
29+
30+
SECTION( "collection with two elements" )
31+
{
32+
std::vector<int> vec1 = {0, 0};
33+
CHECK( utility::is_sorted(vec1) );
34+
CHECK( utility::is_sorted_until(vec1) == vec1.end() );
35+
36+
std::vector<int> vec2 = {0, 5};
37+
CHECK( utility::is_sorted(vec2) );
38+
CHECK( utility::is_sorted_until(vec2) == vec2.end() );
39+
40+
std::vector<int> vec3 = {5, 0};
41+
CHECK_FALSE( utility::is_sorted(vec3) );
42+
CHECK( utility::is_sorted_until(vec3) == std::next(vec3.begin()) );
43+
}
44+
45+
SECTION( "distribution: ascending" )
46+
{
47+
std::vector<int> vec;
48+
vec.reserve(250);
49+
auto distribution = dist::ascending{};
50+
distribution(std::back_inserter(vec), 250);
51+
CHECK( utility::is_sorted(vec) );
52+
CHECK( utility::is_sorted_until(vec) == vec.end() );
53+
}
54+
55+
SECTION( "distribution: ascending_duplicates" )
56+
{
57+
std::vector<int> vec;
58+
vec.reserve(250);
59+
auto distribution = dist::ascending_duplicates{};
60+
distribution(std::back_inserter(vec), 250);
61+
CHECK( utility::is_sorted(vec) );
62+
CHECK( utility::is_sorted_until(vec) == vec.end() );
63+
}
64+
65+
SECTION( "distribution: all_equal" )
66+
{
67+
std::vector<int> vec;
68+
vec.reserve(250);
69+
auto distribution = dist::all_equal{};
70+
distribution(std::back_inserter(vec), 250);
71+
CHECK( utility::is_sorted(vec) );
72+
CHECK( utility::is_sorted_until(vec) == vec.end() );
73+
}
74+
75+
SECTION( "distribution: descending" )
76+
{
77+
std::vector<int> vec;
78+
vec.reserve(250);
79+
auto distribution = dist::descending{};
80+
distribution(std::back_inserter(vec), 250);
81+
CHECK_FALSE( utility::is_sorted(vec) );
82+
CHECK( utility::is_sorted_until(vec) == std::next(vec.begin()) );
83+
}
84+
}

0 commit comments

Comments
 (0)