Skip to content

Commit

Permalink
Replace utility::identity with std::identity (issue #130)
Browse files Browse the repository at this point in the history
  • Loading branch information
Morwenn committed Nov 6, 2020
1 parent 02c4fe6 commit 777e82c
Show file tree
Hide file tree
Showing 124 changed files with 319 additions and 468 deletions.
34 changes: 17 additions & 17 deletions benchmarks/benchmarking-tools/distributions.h
Expand Up @@ -4,6 +4,7 @@
*/
#include <algorithm>
#include <ctime>
#include <functional>
#include <iterator>
#include <numeric>
#include <random>
Expand All @@ -12,7 +13,6 @@
#include <cpp-sort/detail/bitops.h>
#include <cpp-sort/detail/type_traits.h>
#include <cpp-sort/utility/as_function.h>
#include <cpp-sort/utility/functional.h>

// Pseudo-random number generator, used by some distributions
thread_local std::mt19937_64 distributions_prng(std::time(nullptr));
Expand Down Expand Up @@ -58,7 +58,7 @@ struct base_distribution
struct shuffled:
base_distribution<shuffled>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -78,7 +78,7 @@ struct shuffled:
struct shuffled_16_values:
base_distribution<shuffled_16_values>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -98,7 +98,7 @@ struct shuffled_16_values:
struct all_equal:
base_distribution<all_equal>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -114,7 +114,7 @@ struct all_equal:
struct ascending:
base_distribution<ascending>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -130,7 +130,7 @@ struct ascending:
struct descending:
base_distribution<descending>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -146,7 +146,7 @@ struct descending:
struct pipe_organ:
base_distribution<pipe_organ>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -165,7 +165,7 @@ struct pipe_organ:
struct push_front:
base_distribution<push_front>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -184,7 +184,7 @@ struct push_front:
struct push_middle:
base_distribution<push_middle>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -205,7 +205,7 @@ struct push_middle:
struct ascending_sawtooth:
base_distribution<ascending_sawtooth>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -222,7 +222,7 @@ struct ascending_sawtooth:
struct ascending_sawtooth_bad:
base_distribution<ascending_sawtooth_bad>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -239,7 +239,7 @@ struct ascending_sawtooth_bad:
struct descending_sawtooth:
base_distribution<descending_sawtooth>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -256,7 +256,7 @@ struct descending_sawtooth:
struct descending_sawtooth_bad:
base_distribution<descending_sawtooth_bad>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -273,7 +273,7 @@ struct descending_sawtooth_bad:
struct alternating:
base_distribution<alternating>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -289,7 +289,7 @@ struct alternating:
struct alternating_16_values:
base_distribution<alternating_16_values>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -314,7 +314,7 @@ struct inversions:
factor(factor)
{}

template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand All @@ -340,7 +340,7 @@ struct inversions:
struct vergesort_killer:
base_distribution<vergesort_killer>
{
template<typename OutputIterator, typename Projection=cppsort::utility::identity>
template<typename OutputIterator, typename Projection=std::identity>
auto operator()(OutputIterator out, std::size_t size, Projection projection={}) const
-> void
{
Expand Down
1 change: 0 additions & 1 deletion docs/Comparators-and-projections.md
Expand Up @@ -8,7 +8,6 @@ Several of the [miscellaneous utilities][utilities] provided by the library are
- [`as_comparison` and `as_projection`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#as_comparison-and-as_projection) are used to make it explicit whether an ambiguous function object should be used for comparison or for projection.
- [`as_function`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#as_function) can be used to turn any [*Callable*][callable] into an object invokable with regular parentheses.
- [`is_probably_branchless_comparison` and `is_probably_branchless_projection`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#branchless-traits) are type traits that can be used to mark whether functions are likely to be branchless when called with a specific type.
- [`identity`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects) is the default projection returning the argument it is passed without modifying it.

### LWG3031

Expand Down
2 changes: 1 addition & 1 deletion docs/Fixed-size-sorters.md
Expand Up @@ -8,7 +8,7 @@ It is possible to include all the fixed-sized sorters at once with the following
#include <cpp-sort/fixed_sorters.h>
```

The following fixed-size sorters are available and should work with any type for which `std::less<>` and `utility::identity` work:
The following fixed-size sorters are available and should work with any type for which `std::less<>` and `std::identity` work:

### `low_comparisons_sorter`

Expand Down
18 changes: 1 addition & 17 deletions docs/Miscellaneous-utilities.md
Expand Up @@ -92,7 +92,7 @@ constexpr bool is_probably_branchless_projection_v
```

This trait tells whether the projection function `Projection` is likely to generate branchless code when called with an instance of `T`. By default it considers that the following projection functions are likely to be branchless:
* `cppsort::utility::identity` for any type
* [`std::identity`](https://en.cppreference.com/w/cpp/utility/functional/identity) for any type
* Any type that satisfies [`std::is_member_function_pointer`](http://en.cppreference.com/w/cpp/types/is_member_function_pointer) provided it is called with an instance of the appropriate class

These traits can be specialized for user-defined types. If one of the traits is specialized to consider that a user-defined type is likely to be branchless with a comparison/projection function, cv-qualified and reference-qualified versions of the same user-defined type will also be considered to produce branchless code when compared/projected with the same function.
Expand Down Expand Up @@ -127,22 +127,6 @@ This buffer provider allocates on the heap a number of elements depending on a g

This header provides the class `projection_base` and the mechanism used to compose projections with `operator|`. See [[Chainable projections]] for more information.

Also available in this header, the struct `identity` is a function object that can type any value of any movable type and return it as is. It is used as a default for every projection parameter in the library so that sorters view the values as they are by default, without a modification.

```cpp
struct identity:
projection_base
{
template<typename T>
constexpr auto operator()(T&& t) const noexcept
-> T&&;

using is_transparent = /* implementation-defined */;
};
```

It is equivalent to the proposed `std::identity` from the [Ranges TS](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4560.pdf) and will probably be replaced by the standard function object the day it makes its way into the standard.

This header also provides additional function objects implementing basic unary operations. These functions objects are designed to be used as *size policies* with `dynamic_buffer` and similar classes. The following function objects are available:
* `half`: returns the passed value divided by 2.
* `log`: returns the base 10 logarithm of the passed value.
Expand Down
18 changes: 9 additions & 9 deletions docs/Sorter-facade.md
Expand Up @@ -72,7 +72,7 @@ auto operator()(Iterator first, Iterator last,
-> /* implementation-defined */;
```
These overloads will generally forward the parameters to the corresponding `operator()` in the wrapped *sorter implementation*. It does some additional magic to forward `compare` and `projection` to the most suitable `operator()` overload in the *sorter implementation* and to complete the call with instances of [`std::less<>`](http://en.cppreference.com/w/cpp/utility/functional/less_void) and/or [`utility::identity`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects) when additional parameters are needed. Basically, it ensures that everything can be done if `Sorter` has a single `operator()` taking a pair of iterators, a comparison function and a projection function.
These overloads will generally forward the parameters to the corresponding `operator()` in the wrapped *sorter implementation*. It does some additional magic to forward `compare` and `projection` to the most suitable `operator()` overload in the *sorter implementation* and to complete the call with instances of [`std::less<>`](http://en.cppreference.com/w/cpp/utility/functional/less_void) and/or [`std::identity`](https://en.cppreference.com/w/cpp/utility/functional/identity) when additional parameters are needed. Basically, it ensures that everything can be done if `Sorter` has a single `operator()` taking a pair of iterators, a comparison function and a projection function.
Provided you have a sorting function with a standard iterator interface, creating the corresponding sorter becomes trivial thanks to `sorter_facade`. For instance, here is a simple sorter wrapping a [`selection_sort`](https://en.wikipedia.org/wiki/Selection_sort):
Expand All @@ -82,7 +82,7 @@ struct selection_sorter_impl
template<
typename RandomAccessIterator,
typename Compare = std::less<>,
typename Projection = cppsort::utility::identity
typename Projection = std::identity
>
auto operator()(RandomAccessIterator first, RandomAccessIterator last,
Compare compare={}, Projection projection={}) const
Expand Down Expand Up @@ -119,7 +119,7 @@ auto operator()(Iterable&& iterable, Compare compare, Projection projection) con
-> /* implementation-defined */;
```
These overloads will generally forward the parameters to the corresponding `operator()` overloads in the wrapped *sorter implementation* if they exist, or try to call an equivalent `operator()` taking a pair of iterators in the wrapped sorter by using `utility::begin` and `utility::end` on the iterable to sort. It also does some additional magic to forward `compare` and `projection` to the most suitable `operator()` overload in `sorter` and to complete the call with instances of [`std::less<>`](http://en.cppreference.com/w/cpp/utility/functional/less_void) and/or [`utility::identity`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects) when additional parameters are needed. Basically, it ensures that everything can be done if `Sorter` has a single `operator()` taking a pair of iterators, a comparison function and a projection function.
These overloads will generally forward the parameters to the corresponding `operator()` overloads in the wrapped *sorter implementation* if they exist, or try to call an equivalent `operator()` taking a pair of iterators in the wrapped sorter by using `utility::begin` and `utility::end` on the iterable to sort. It also does some additional magic to forward `compare` and `projection` to the most suitable `operator()` overload in `sorter` and to complete the call with instances of [`std::less<>`](http://en.cppreference.com/w/cpp/utility/functional/less_void) and/or [`std::identity`](https://en.cppreference.com/w/cpp/utility/functional/identity) when additional parameters are needed. Basically, it ensures that everything can be done if `Sorter` has a single `operator()` taking a pair of iterators, a comparison function and a projection function.
It will always call the most suitable iterable `operator()` overload in the wrapped *sorter implementation* if there is one, and dispatch the call to an overload taking a pair of iterators when it cannot do otherwise.
Expand All @@ -129,21 +129,21 @@ Some *sorter implementations* are able to handle custom comparison functions but
The reverse operation (baking a comparison function into a projection function) is not doable and simply does not make sense most of the time, so `sorter_facade` does not provide it for projection-only *sorter implementations*.
### Universal support for `std::less<>` and `utility::identity`
### Universal support for `std::less<>` and `std::identity`
**cpp-sort** considers that every collection sorted without a specific comparison nor projection function shoud work *as if* it was sorted with `std::less<>` and `utility::identity`. However, some sorters do not provide overloads for `operator()` taking comparison and/or projection functions. `sorter_facade` provides the following overloads so that every sorter can be passed `std::less<>` and/or `utility::identity` even if does not handle other comparisons or projections:
**cpp-sort** considers that every collection sorted without a specific comparison nor projection function shoud work *as if* it was sorted with `std::less<>` and `std::identity`. However, some sorters do not provide overloads for `operator()` taking comparison and/or projection functions. `sorter_facade` provides the following overloads so that every sorter can be passed `std::less<>` and/or `std::identity` even if does not handle other comparisons or projections:
```cpp
template<typename Iterable>
auto operator()(Iterable&& iterable, std::less<>) const
-> /* implementation-defined */;
template<typename Iterable>
auto operator()(Iterable&& iterable, utility::identity) const
auto operator()(Iterable&& iterable, std::identity) const
-> /* implementation-defined */;
template<typename Iterable>
auto operator()(Iterable&& iterable, std::less<>, utility::identity) const
auto operator()(Iterable&& iterable, std::less<>, std::identity) const
-> /* implementation-defined */;
template<typename Iterable, typename Projection>
Expand All @@ -155,12 +155,12 @@ auto operator()(Iterator first, Iterator last, std::less<>) const
-> /* implementation-defined */;
template<typename Iterator>
auto operator()(Iterator first, Iterator last, utility::identity) const
auto operator()(Iterator first, Iterator last, std::identity) const
-> /* implementation-defined */;
template<typename Iterator>
auto operator()(Iterator first, Iterator last,
std::less<>, utility::identity) const
std::less<>, std::identity) const
-> /* implementation-defined */;
template<typename Iterator, typename Projection>
Expand Down
4 changes: 2 additions & 2 deletions docs/Writing-a-bubble_sorter.md
Expand Up @@ -241,7 +241,7 @@ struct bubble_sorter_impl
template<
typename ForwardIterator,
typename StrictWeakOrdering = std::less<>,
typename Projection = cppsort::utility::identity,
typename Projection = std::identity,
typename = std::enable_if_t<cppsort::is_projection_iterator_v<
Projection, ForwardIterator, StrictWeakOrdering
>>
Expand All @@ -259,7 +259,7 @@ struct bubble_sorter_impl
};
```
We can see several improvements compared to the previous version: first of all, we added an optional projection parameter which defauts to [`utility::identity`](https://github.com/Morwenn/cpp-sort/wiki/Miscellaneous-utilities#miscellaneous-function-objects). This is a function object that returns a value as is so that the default behaviour of the algorithm is to run *as if* projections didn't exist. It is very likely to be optimized aways by the compiler anyway.
We can see several improvements compared to the previous version: first of all, we added an optional projection parameter which defauts to [`std::identity`](https://en.cppreference.com/w/cpp/utility/functional/identity). This is a function object that returns a value as is so that the default behaviour of the algorithm is to run *as if* projections didn't exist. It is very likely to be optimized aways by the compiler anyway.
The second modification is one I wish we could do without (yet another thing that concepts would make more expressive): [`is_projection_iterator_v`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-traits#is_projection-and-is_projection_iterator) is a trait that checks whether a projection function can be used on a dereferenced iterator. It also optionally checks that a given comparison function can be called with the result of two such projections. This trait exists to ensure that a sorter's `operator()` won't be called when these conditions are not satisfied, which may be crucial when aggregating sorters with [`hybrid_adapter`](https://github.com/Morwenn/cpp-sort/wiki/Sorter-adapters#hybrid_adapter).
Expand Down

0 comments on commit 777e82c

Please sign in to comment.