Skip to content

Commit

Permalink
Make indirect_adapter work with spread_sorter (#204)
Browse files Browse the repository at this point in the history
indirect_adapter did work with projection-only sorters, but not when
passed only a projection. This commit solves it by adding nauseating
amounts of SFINAE, cursing the status quo for the generations to come.
  • Loading branch information
Morwenn committed Mar 3, 2022
1 parent 58f4ecc commit 0a39821
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 6 deletions.
33 changes: 28 additions & 5 deletions include/cpp-sort/adapters/indirect_adapter.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2021 Morwenn
* Copyright (c) 2015-2022 Morwenn
* SPDX-License-Identifier: MIT
*/
#ifndef CPPSORT_ADAPTERS_INDIRECT_ADAPTER_H_
Expand Down Expand Up @@ -39,7 +39,9 @@ namespace cppsort
ForwardIterator first, ForwardIterator last,
difference_type_t<ForwardIterator> size,
Compare compare, Projection projection)
-> decltype(auto)
-> decltype(cppsort::detail::indiesort(std::forward<Sorter>(sorter),
first, last, size,
std::move(compare), std::move(projection)))
{
return cppsort::detail::indiesort(std::forward<Sorter>(sorter),
first, last, size,
Expand All @@ -51,7 +53,21 @@ namespace cppsort
RandomAccessIterator first, RandomAccessIterator last,
difference_type_t<RandomAccessIterator> size,
Compare compare, Projection projection)
-> decltype(auto)
#ifdef __cpp_lib_uncaught_exceptions
-> decltype(std::forward<Sorter>(sorter)(
(RandomAccessIterator*)0, (RandomAccessIterator*)0,
std::move(compare), indirect(projection)
))
#else
-> std::enable_if_t<
has_comparison_projection_sort_iterator<
Sorter,
RandomAccessIterator*,
Compare,
indirect_t<Projection>
>::value
>
#endif
{
using utility::iter_move;

Expand Down Expand Up @@ -142,7 +158,11 @@ namespace cppsort
>
auto operator()(ForwardIterable&& iterable,
Compare compare={}, Projection projection={}) const
-> decltype(auto)
-> decltype(sort_indirectly(iterator_category_t<remove_cvref_t<decltype(std::begin(iterable))>>{},
this->get(),
std::begin(iterable), std::end(iterable),
cppsort::utility::size(iterable),
std::move(compare), std::move(projection)))
{
auto size = cppsort::utility::size(iterable);
return sort_indirectly(iterator_category_t<remove_cvref_t<decltype(std::begin(iterable))>>{},
Expand All @@ -161,7 +181,10 @@ namespace cppsort
>
auto operator()(ForwardIterator first, ForwardIterator last,
Compare compare={}, Projection projection={}) const
-> decltype(auto)
-> decltype(sort_indirectly(iterator_category_t<ForwardIterator>{},
this->get(), first, last,
std::distance(first, last),
std::move(compare), std::move(projection)))
{
auto size = std::distance(first, last);
return sort_indirectly(iterator_category_t<ForwardIterator>{},
Expand Down
17 changes: 16 additions & 1 deletion include/cpp-sort/detail/indiesort.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,22 @@ namespace detail
auto indiesort(Sorter&& sorter, ForwardIterator first, ForwardIterator last,
difference_type_t<ForwardIterator> size,
Compare compare, Projection projection)
-> decltype(auto)
#ifdef __cpp_lib_uncaught_exceptions
-> decltype(std::forward<Sorter>(sorter)(
(it_and_index<ForwardIterator>*)0, (it_and_index<ForwardIterator>*)0,
std::move(compare),
&it_and_index<ForwardIterator>::original_location | indirect(projection)
))
#else
-> std::enable_if_t<
has_comparison_projection_sort_iterator<
Sorter,
it_and_index<ForwardIterator>*,
Compare,
decltype(&it_and_index<ForwardIterator>::original_location | indirect(projection))
>::value
>
#endif
{
using utility::iter_move;

Expand Down
14 changes: 14 additions & 0 deletions tests/adapters/indirect_adapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <catch2/catch_test_macros.hpp>
#include <cpp-sort/adapters/indirect_adapter.h>
#include <cpp-sort/sorters/quick_sorter.h>
#include <cpp-sort/sorters/spread_sorter.h>
#include <testing-tools/algorithm.h>
#include <testing-tools/distributions.h>
#include <testing-tools/span.h>
Expand Down Expand Up @@ -90,3 +91,16 @@ TEST_CASE( "indirect_adapter with temporary span",
CHECK( std::is_sorted(collection.begin(), collection.end()) );
}
}


TEST_CASE( "indirect_adapter over non-comparison sorter",
"[indirect_adapter][spread_sorter]" )
{
std::vector<int> collection; collection.reserve(221);
auto distribution = dist::shuffled{};
distribution(std::back_inserter(collection), 221, -32);

cppsort::indirect_adapter<cppsort::spread_sorter> sorter;
sorter(collection, std::negate<>{});
CHECK( std::is_sorted(collection.begin(), collection.end(), std::greater<>{}) );
}

0 comments on commit 0a39821

Please sign in to comment.