Skip to content

Commit

Permalink
Sentinel supports for measures of presortedness (#20)
Browse files Browse the repository at this point in the history
  • Loading branch information
Morwenn committed Oct 30, 2022
1 parent b21d910 commit b077a63
Show file tree
Hide file tree
Showing 17 changed files with 153 additions and 126 deletions.
12 changes: 6 additions & 6 deletions docs/Measures-of-presortedness.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ The measures of presortedness in bold in the graph are available in **cpp-sort**

## Measures of presortedness in cpp-sort

In **cpp-sort**, measures of presortedness are implemented as instances of some specific function objects. They take either a range or a pair of iterators and return how much disorder there is in the sequence according to the measure. Just like sorters, measures of presortedness can handle custom comparison and projection functions, and with the same degree of freedom when it comes to how they can be called:
In **cpp-sort**, measures of presortedness are implemented as instances of some specific function objects. They accept either a range or an iterator/sentinel pair, and return how much disorder there is in the sequence according to the measure. The type of the returned variable is the *difference type* of the passed iterator. Just like sorters, measures of presortedness can handle custom comparison and projection functions, and with the same degree of freedom when it comes to how they can be called:

```cpp
using namespace cppsort;
Expand All @@ -47,15 +47,15 @@ auto c = probe::ham(li, std::greater<>{});
auto d = probe::runs(integers, std::negate<>{});
```

Note however that these algorithms can be expensive. Using them before an actual sorting algorithm has no interest at all; they are meant to be profiling tools: when sorting is a critical part of your application, you can use these measures on typical data and check whether it is mostly sorted according to one measure or another, then you may be able to find a sorting algorithm known to be optimal with regard to this specific measure.
Note however that these algorithms can be expensive; calling them before an actual sorting algorithm generally has no interest at all. They are first and foremost meant to be profiling tools: when sorting is a critical part of an application, these measures can be used on typical data and check whether said data is mostly sorted according to one measure or another. Then you may be able to find a sorting algorithm known to be optimal with regard to this specific measure.

Measures of presortedness can be used with the *sorter adapters* from the library. Even though most of the adapters are meaningless with measures of presortedness, some of them can still be used to mitigate space and time:
Measures of presortedness can be used with the library's *sorter adapters*. Even though most of the adapters are meaningless with measures of presortedness, some of them can still be used to mitigate space and time:

```cpp
auto inv = cppsort::indirect_adapter(cppsort::probe::inv);
```

All measures of presortedness live in the subnamespace `cppsort::probe`. Even though all of them are available in their own header, it is possible to include all of them at once with the following include:
All measures of presortedness live in the subnamespace `cppsort::probe`. While all of them are available in their own header, it is possible to include all of them at once with the following include:

```cpp
#include <cpp-sort/probes.h>
Expand Down Expand Up @@ -270,7 +270,7 @@ Some additional measures of presortedness how been described in the literature b

### *Par*

*Par* was described by V. Estivill-Castro and D. Wood in *A New Measure of Presortedness* as follows:
*Par* is described by V. Estivill-Castro and D. Wood in *A New Measure of Presortedness* as follows:

> *Par(X)* = min { *p* | *X* is *p*-sorted }
Expand All @@ -282,7 +282,7 @@ The following definition is also given to determine whether a sequence is *p*-so

> In fact, *Par*(*X*) = *Dis*(*X*), for all *X*.
In their subsequent papers, those authors consistently use *Dis* instead of *Par*, often accompanied by a link to *A New Measure of Presortedness*.
In their subsequent papers, the authors consistently use *Dis* instead of *Par*, often accompanied by a link to *A New Measure of Presortedness*.

### *Radius*

Expand Down
4 changes: 2 additions & 2 deletions include/cpp-sort/detail/is_p_sorted.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

namespace cppsort::detail
{
template<typename ForwardIterator, typename Compare, typename Projection>
auto is_p_sorted(ForwardIterator first, ForwardIterator last, ForwardIterator pth,
template<typename ForwardIterator, typename Sentinel, typename Compare, typename Projection>
auto is_p_sorted(ForwardIterator first, Sentinel last, ForwardIterator pth,
Compare compare, Projection projection)
-> bool
{
Expand Down
6 changes: 4 additions & 2 deletions include/cpp-sort/detail/longest_non_descending_subsequence.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <type_traits>
#include <utility>
#include <vector>
#include <cpp-sort/mstd/ranges.h>
#include <cpp-sort/utility/as_function.h>
#include "functional.h"
#include "iterator_traits.h"
Expand All @@ -26,10 +27,11 @@ namespace cppsort::detail
template<
bool RecomputeSize,
typename ForwardIterator,
typename Sentinel,
typename Compare,
typename Projection
>
auto longest_non_descending_subsequence(ForwardIterator first, ForwardIterator last,
auto longest_non_descending_subsequence(ForwardIterator first, Sentinel last,
difference_type_t<ForwardIterator> size,
Compare compare, Projection projection)
-> std::pair<difference_type_t<ForwardIterator>, difference_type_t<ForwardIterator>>
Expand All @@ -51,7 +53,7 @@ namespace cppsort::detail
// making two passes over the sequence - when the sequence is made
// of random-access iterators, we only compute it once
if constexpr (RecomputeSize && is_random_access) {
size = std::distance(first, last);
size = mstd::distance(first, last);
}

auto&& proj = utility::as_function(projection);
Expand Down
22 changes: 10 additions & 12 deletions include/cpp-sort/probes/block.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
////////////////////////////////////////////////////////////
#include <functional>
#include <iterator>
#include <type_traits>
#include <utility>
#include <vector>
#include <cpp-sort/mstd/iterator.h>
#include <cpp-sort/mstd/ranges.h>
#include <cpp-sort/mstd/type_traits.h>
Expand All @@ -21,20 +19,19 @@
#include <cpp-sort/utility/as_function.h>
#include "../detail/functional.h"
#include "../detail/immovable_vector.h"
#include "../detail/iterator_traits.h"
#include "../detail/pdqsort.h"

namespace cppsort::probe
{
namespace detail
{
template<typename ForwardIterator, typename Compare, typename Projection>
auto block_probe_algo(ForwardIterator first, ForwardIterator last,
cppsort::detail::difference_type_t<ForwardIterator> size,
template<typename ForwardIterator, typename Sentinel, typename Compare, typename Projection>
auto block_probe_algo(ForwardIterator first, Sentinel last,
mstd::iter_difference_t<ForwardIterator> size,
Compare compare, Projection projection)
-> ::cppsort::detail::difference_type_t<ForwardIterator>
-> mstd::iter_difference_t<ForwardIterator>
{
using difference_type = ::cppsort::detail::difference_type_t<ForwardIterator>;
using difference_type = mstd::iter_difference_t<ForwardIterator>;
auto&& comp = utility::as_function(compare);
auto&& proj = utility::as_function(projection);

Expand Down Expand Up @@ -90,7 +87,7 @@ namespace cppsort::probe
>
>
auto operator()(Range&& range, Compare compare={}, Projection projection={}) const
-> decltype(auto)
-> mstd::range_difference_t<Range>
{
return block_probe_algo(mstd::begin(range), mstd::end(range),
mstd::distance(range),
Expand All @@ -99,18 +96,19 @@ namespace cppsort::probe

template<
mstd::forward_iterator Iterator,
mstd::sentinel_for<Iterator> Sentinel,
typename Compare = std::less<>,
typename Projection = std::identity,
typename = mstd::enable_if_t<
is_projection_iterator_v<Projection, Iterator, Compare>
>
>
auto operator()(Iterator first, Iterator last,
auto operator()(Iterator first, Sentinel last,
Compare compare={}, Projection projection={}) const
-> decltype(auto)
-> mstd::iter_difference_t<Iterator>
{
return block_probe_algo(first, last,
std::distance(first, last),
mstd::distance(first, last),
std::move(compare), std::move(projection));
}

Expand Down
33 changes: 17 additions & 16 deletions include/cpp-sort/probes/dis.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include <functional>
#include <iterator>
#include <new>
#include <type_traits>
#include <utility>
#include <cpp-sort/mstd/iterator.h>
#include <cpp-sort/mstd/ranges.h>
Expand All @@ -21,17 +20,16 @@
#include <cpp-sort/sorter_traits.h>
#include "../detail/immovable_vector.h"
#include "../detail/is_p_sorted.h"
#include "../detail/iterator_traits.h"

namespace cppsort::probe
{
namespace detail
{
template<typename ForwardIterator, typename Compare, typename Projection>
auto inplace_dis_probe_algo(ForwardIterator first, ForwardIterator last,
cppsort::detail::difference_type_t<ForwardIterator> size,
template<typename ForwardIterator, typename Sentinel, typename Compare, typename Projection>
auto inplace_dis_probe_algo(ForwardIterator first, Sentinel last,
mstd::iter_difference_t<ForwardIterator> size,
Compare compare, Projection projection)
-> ::cppsort::detail::difference_type_t<ForwardIterator>
-> mstd::iter_difference_t<ForwardIterator>
{
// Simple algorithm in O(n log n) time and O(1) space

Expand All @@ -55,11 +53,11 @@ namespace cppsort::probe

template<typename BidirectionalIterator, typename Compare, typename Projection>
auto allocating_dis_probe_algo(BidirectionalIterator first, BidirectionalIterator last,
cppsort::detail::difference_type_t<BidirectionalIterator> size,
mstd::iter_difference_t<BidirectionalIterator> size,
Compare compare, Projection projection)
-> ::cppsort::detail::difference_type_t<BidirectionalIterator>
-> mstd::iter_difference_t<BidirectionalIterator>
{
using difference_type = ::cppsort::detail::difference_type_t<BidirectionalIterator>;
using difference_type = mstd::iter_difference_t<BidirectionalIterator>;
auto&& comp = utility::as_function(compare);
auto&& proj = utility::as_function(projection);

Expand Down Expand Up @@ -113,9 +111,9 @@ namespace cppsort::probe
typename Projection
>
auto dis_probe_algo(Iterator first, Iterator last,
cppsort::detail::difference_type_t<Iterator> size,
mstd::iter_difference_t<Iterator> size,
Compare compare, Projection projection)
-> ::cppsort::detail::difference_type_t<Iterator>
-> mstd::iter_difference_t<Iterator>
{
try {
return allocating_dis_probe_algo(first, last, size, compare, projection);
Expand All @@ -129,13 +127,14 @@ namespace cppsort::probe

template<
mstd::forward_iterator Iterator,
mstd::sentinel_for<Iterator> Sentinel,
typename Compare,
typename Projection
>
auto dis_probe_algo(Iterator first, Iterator last,
cppsort::detail::difference_type_t<Iterator> size,
auto dis_probe_algo(Iterator first, Sentinel last,
mstd::iter_difference_t<Iterator> size,
Compare compare, Projection projection)
-> ::cppsort::detail::difference_type_t<Iterator>
-> mstd::iter_difference_t<Iterator>
{
return inplace_dis_probe_algo(first, last, size, compare, projection);
}
Expand All @@ -160,17 +159,19 @@ namespace cppsort::probe

template<
mstd::forward_iterator Iterator,
mstd::sentinel_for<Iterator> Sentinel,
typename Compare = std::less<>,
typename Projection = std::identity,
typename = mstd::enable_if_t<
is_projection_iterator_v<Projection, Iterator, Compare>
>
>
auto operator()(Iterator first, Iterator last,
auto operator()(Iterator first, Sentinel last,
Compare compare={}, Projection projection={}) const
-> decltype(auto)
{
return dis_probe_algo(first, last, std::distance(first, last),
return dis_probe_algo(first, last,
mstd::distance(first, last),
std::move(compare), std::move(projection));
}

Expand Down
6 changes: 3 additions & 3 deletions include/cpp-sort/probes/enc.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
////////////////////////////////////////////////////////////
#include <functional>
#include <iterator>
#include <type_traits>
#include <utility>
#include <vector>
#include <cpp-sort/comparators/flip.h>
Expand Down Expand Up @@ -59,15 +58,16 @@ namespace cppsort::probe
{
template<
mstd::forward_iterator Iterator,
mstd::sentinel_for<Iterator> Sentinel,
typename Compare = std::less<>,
typename Projection = std::identity,
typename = mstd::enable_if_t<
is_projection_iterator_v<Projection, Iterator, Compare>
>
>
auto operator()(Iterator first, Iterator last,
auto operator()(Iterator first, Sentinel last,
Compare compare={}, Projection projection={}) const
-> cppsort::detail::difference_type_t<Iterator>
-> mstd::iter_difference_t<Iterator>
{
auto&& comp = utility::as_function(compare);
auto&& proj = utility::as_function(projection);
Expand Down
22 changes: 10 additions & 12 deletions include/cpp-sort/probes/exc.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
////////////////////////////////////////////////////////////
#include <functional>
#include <iterator>
#include <type_traits>
#include <utility>
#include <vector>
#include <cpp-sort/mstd/iterator.h>
Expand All @@ -21,20 +20,18 @@
#include <cpp-sort/utility/as_function.h>
#include "../detail/functional.h"
#include "../detail/immovable_vector.h"
#include "../detail/iterator_traits.h"
#include "../detail/pdqsort.h"

namespace cppsort::probe
{
namespace detail
{
template<typename ForwardIterator, typename Compare, typename Projection>
auto exc_probe_algo(ForwardIterator first, ForwardIterator last,
cppsort::detail::difference_type_t<ForwardIterator> size,
template<typename ForwardIterator, typename Sentinel, typename Compare, typename Projection>
auto exc_probe_algo(ForwardIterator first, Sentinel last,
mstd::iter_difference_t<ForwardIterator> size,
Compare compare, Projection projection)
-> ::cppsort::detail::difference_type_t<ForwardIterator>
-> mstd::iter_difference_t<ForwardIterator>
{
using difference_type = ::cppsort::detail::difference_type_t<ForwardIterator>;
auto&& comp = utility::as_function(compare);
auto&& proj = utility::as_function(projection);

Expand Down Expand Up @@ -65,7 +62,7 @@ namespace cppsort::probe
// Element where the current cycle starts
auto start = first;

difference_type cycles = 0;
mstd::iter_difference_t<ForwardIterator> cycles = 0;
while (start != last) {
// Find the element to put in current's place
auto current = start;
Expand Down Expand Up @@ -116,7 +113,7 @@ namespace cppsort::probe
>
>
auto operator()(Range&& range, Compare compare={}, Projection projection={}) const
-> decltype(auto)
-> mstd::range_difference_t<Range>
{
return exc_probe_algo(mstd::begin(range), mstd::end(range),
mstd::distance(range),
Expand All @@ -125,18 +122,19 @@ namespace cppsort::probe

template<
mstd::forward_iterator Iterator,
mstd::sentinel_for<Iterator> Sentinel,
typename Compare = std::less<>,
typename Projection = std::identity,
typename = mstd::enable_if_t<
is_projection_iterator_v<Projection, Iterator, Compare>
>
>
auto operator()(Iterator first, Iterator last,
auto operator()(Iterator first, Sentinel last,
Compare compare={}, Projection projection={}) const
-> decltype(auto)
-> mstd::iter_difference_t<Iterator>
{
return exc_probe_algo(first, last,
std::distance(first, last),
mstd::distance(first, last),
std::move(compare), std::move(projection));
}

Expand Down
Loading

0 comments on commit b077a63

Please sign in to comment.