Skip to content

Commit

Permalink
Adapt docs & tests to mutable sorters (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
Morwenn committed Sep 8, 2024
1 parent 4fbc9b6 commit 2bec62b
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 51 deletions.
8 changes: 3 additions & 5 deletions docs/Sorter-adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ constexpr auto sort = indirect_adapter(quick_sort);
```

Most of the library's *sorter adapters* can store the passed *sorters* in their internals, allowing them to use adapt *stateful sorters*. Unless explicitly mentioned otherwise in an adapter's description, it is safe to assume that the *sorter adapters* in the library have the following properties:
* The *sorter adapter* stores a copy of every passed sorters in its internals and uses those copy when needed. If every *original sorter* is empty and default-constructible, then the *sorter adapter* is also empty and default-constructible.
* If the *sorter adapter* adapts a single *sorter*, then it has a member function called `get()` which returns a reference to the internal *sorter* whose reference and `const` qualifications match those of the *sorter adapter* instance. If the *sorter adapter* is empty and default-constructible, then a default-constructed instance of the type of the *original sorter* is returned instead.
* The *sorter adapter* stores a copy of every passed sorters in its internals and uses those copy when needed. If every *adapted sorter* is empty and default-constructible, then the *resulting sorter* is also empty and default-constructible.
* If the *sorter adapter* adapts a single *sorter*, then it has a member function called `get()` which returns a reference to the internal *sorter* whose reference and `const` qualifications match those of the *resulting sorter* instance. If the *resulting adapter* is empty and default-constructible, then a default-constructed instance of the type of the *adapted sorter* is returned instead.
* The `operator()` of the *resulting sorter* has cv-qualifications similar to those of the *adapted sorter*. This is generally achieved by taking an explicit `this` template parameter.
* If the *sorter adapter* is empty and default-constructible, then it can be converted to any function pointer whose signature matches that of its `operator()`.

It is worth noting that in the current state of things, sorters & adapters are expected to have a `const operator()`, and thus don't play nice with *mutable sorters*. There are plans to properly handle *mutable sorters* in the future: you can track [the corresponding issue][issue-104].

## Available sorter adapters

The following sorter adapters and fixed-size sorter adapters are available in the library:
Expand Down Expand Up @@ -321,7 +320,6 @@ When wrapped into [`stable_adapter`][stable-adapter], it has a slightly differen
[hybrid-adapter]: Sorter-adapters.md#hybrid_adapter
[is-always-stable]: Sorter-traits.md#is_always_stable
[is-stable]: Sorter-traits.md#is_stable
[issue-104]: https://github.com/Morwenn/cpp-sort/issues/104
[iterator-category]: Sorter-traits.md#iterator_category
[iterator-tags]: https://en.cppreference.com/w/cpp/iterator/iterator_tags
[low-moves-sorter]: Fixed-size-sorters.md#low_moves_sorter
Expand Down
6 changes: 2 additions & 4 deletions docs/Writing-a-sorter.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,7 @@ Now, let's define a set of rules to apply when writing sorters. These rules don'

**Rule 1.3:** a *sorter implementation* shall provide at least an overload of `operator()` that takes a pair of iterators. Overloads of `operator()` taking an iterable can be provided as well when they add value to the *sorter* (optimization, correctness, better error messages...) but should never totally replace the overload taking a pair of iterators.

**Rule 1.4:** *sorters* shall be immutable and every overload of `operator()` shall explicitly be marked `const` (make sure to check twice: forgetting to `const`-qualify them can cause hundreds of lines of cryptic error messages). Some parts of the library *may* accept mutable sorters, but that's never guaranteed unless specified otherwise.

**Rule 1.5:** *sorter* implementers are encouraged but not required to provide a default instance of their *sorters* for convenience. `inline` variables can be used to avoid ODR-related problems.
**Rule 1.4:** *sorter* implementers are encouraged but not required to provide a default instance of their *sorters* for convenience. `inline` variables can be used to avoid ODR-related problems.

## Category of iterators

Expand Down Expand Up @@ -406,7 +404,7 @@ The library also contains another stability-related type trait, [`is_stable`][is

## Stateful sorters

To date (version 1.5.0), every *sorter* provided by **cpp-sort** is a *stateless sorter*, which means that it is an empty type which does not carry any state between construction and subsequent invocations. However, the library is also designed to handle *stateful sorters*: those are sorters which might not be empty and which might carry a state that can change between invocations (even though the invocation itself isn't allowed to change the state as per Rule 1.4).
To date (version 2.0.0), every *sorter* provided by **cpp-sort** is a *stateless sorter*, which means that it is an empty type which does not carry any state between construction and subsequent invocations. However, the library is also designed to handle *stateful sorters*: those are sorters which might carry a state that can change between invocations, or even when calling the *sorter*.

There are no specific rules to differentiate the way *stateful* and *stateless sorters* are written, but the distinction matters because specific components of the library will act differently when exposed to a *stateful* or *stateless* sorter:
* `sorter_facade` only provides conversions to different kinds of function pointers when the *sorter implementation* is empty (stateless) and default-constructible.
Expand Down
47 changes: 5 additions & 42 deletions tests/utility/adapter_storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <cpp-sort/sorter_traits.h>
#include <cpp-sort/sorters/selection_sorter.h>
#include <cpp-sort/utility/adapter_storage.h>
#include <testing-tools/mutable_sorter.h>

namespace
{
Expand Down Expand Up @@ -101,44 +102,6 @@ namespace
cppsort::sorter_facade<non_empty_sorter_impl>(a, b)
{}
};

////////////////////////////////////////////////////////////
// Mutable sorter

struct mutable_sorter_impl
{
int dummy1=0, dummy2=0;

mutable_sorter_impl() = default;
constexpr mutable_sorter_impl(int a, int b):
dummy1(a), dummy2(b)
{}

template<
typename Iterator,
typename Compare = std::less<>
>
requires (not cppsort::is_projection_iterator_v<Compare, Iterator>)
auto operator()(Iterator first, Iterator last, Compare compare={})
-> void
{
dummy1 = 3;
std::sort(std::move(first), std::move(last), std::move(compare));
dummy2 = 11;
}

using iterator_category = std::random_access_iterator_tag;
using is_always_stable = std::false_type;
};

struct mutable_sorter:
cppsort::sorter_facade<mutable_sorter_impl>
{
mutable_sorter() = default;
mutable_sorter(int a, int b):
cppsort::sorter_facade<mutable_sorter_impl>(a, b)
{}
};
}

TEST_CASE( "test correct adapter_storage behavior", "[adapter_storage]" )
Expand All @@ -165,12 +128,12 @@ TEST_CASE( "test correct adapter_storage behavior", "[adapter_storage]" )

SECTION( "with a mutable sorter" )
{
mutable_sorter original_sorter(5, 8);
mutable_sorter original_sorter;
auto adapted_sorter = dummy_adapter<mutable_sorter>(original_sorter);

adapted_sorter(arr);
CHECK( std::is_sorted(std::begin(arr), std::end(arr)) );
CHECK( adapted_sorter.get().dummy1 == 3 );
CHECK( adapted_sorter.get().dummy2 == 11 );
CHECK( std::is_sorted(arr.begin(), arr.end()) );
CHECK( adapted_sorter.get().before_sort == mutable_state::modified );
CHECK( adapted_sorter.get().after_sort == mutable_state::modified );
}
}

0 comments on commit 2bec62b

Please sign in to comment.