-
Notifications
You must be signed in to change notification settings - Fork 57
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
298 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
/* | ||
* Copyright (c) 2023 Morwenn | ||
* SPDX-License-Identifier: MIT | ||
*/ | ||
#ifndef CPPSORT_METRICS_MOVES_H_ | ||
#define CPPSORT_METRICS_MOVES_H_ | ||
|
||
//////////////////////////////////////////////////////////// | ||
// Headers | ||
//////////////////////////////////////////////////////////// | ||
#include <functional> | ||
#include <utility> | ||
#include <cpp-sort/fwd.h> | ||
#include <cpp-sort/sorter_facade.h> | ||
#include <cpp-sort/sorter_traits.h> | ||
#include <cpp-sort/utility/adapter_storage.h> | ||
#include <cpp-sort/utility/metrics_tools.h> | ||
#include <cpp-sort/utility/size.h> | ||
#include "../detail/checkers.h" | ||
#include "../detail/immovable_vector.h" | ||
#include "../detail/iterator_traits.h" | ||
#include "../detail/type_traits.h" | ||
|
||
namespace cppsort | ||
{ | ||
namespace metrics | ||
{ | ||
namespace detail | ||
{ | ||
template<typename T, typename CountType> | ||
struct move_counting_wrapper | ||
{ | ||
// Wrapped value, readily accessible | ||
T value; | ||
// Moves counter | ||
CountType* count; | ||
|
||
move_counting_wrapper(T&& value, CountType& counter): | ||
value(std::move(value)), | ||
count(&counter) | ||
{ | ||
// Do not increment the counter when constructing from value | ||
} | ||
|
||
move_counting_wrapper(move_counting_wrapper&& other): | ||
value(std::move(other.value)), | ||
count(other.count) | ||
{ | ||
++(*count); | ||
} | ||
|
||
auto operator=(move_counting_wrapper&& other) | ||
-> move_counting_wrapper& | ||
{ | ||
value = std::move(other.value); | ||
count = other.count; | ||
++(*count); | ||
return *this; | ||
} | ||
|
||
// Not copyable | ||
move_counting_wrapper(const move_counting_wrapper&) = delete; | ||
move_counting_wrapper& operator=(const move_counting_wrapper&) = delete; | ||
}; | ||
|
||
template<typename CountType, typename ForwardIterator, typename Size, | ||
typename Compare, typename Projection, typename Sorter> | ||
auto count_moves(ForwardIterator first, ForwardIterator last, Size size, | ||
Compare compare, Projection projection, Sorter&& sorter) | ||
-> CountType | ||
{ | ||
using utility::iter_move; | ||
using wrapper_t = move_counting_wrapper< | ||
cppsort::detail::rvalue_type_t<ForwardIterator>, | ||
CountType | ||
>; | ||
|
||
// Use an immovable_vector to ensure that no move is performed | ||
// hile filling the vector | ||
CountType count(0); | ||
cppsort::detail::immovable_vector<wrapper_t> vec(size); | ||
for (auto it = first; it != last; ++it) { | ||
vec.emplace_back(iter_move(it), count); | ||
} | ||
|
||
std::forward<Sorter>(sorter)( | ||
vec.begin(), vec.end(), std::move(compare), | ||
utility::as_projection(&wrapper_t::value) | std::move(projection) | ||
); | ||
|
||
auto vec_it = vec.begin(); | ||
for (auto it = first; it != last; ++it, ++vec_it) { | ||
*it = std::move(vec_it->value); | ||
} | ||
|
||
return count; | ||
} | ||
} | ||
|
||
//////////////////////////////////////////////////////////// | ||
// Tag | ||
|
||
struct moves_tag {}; | ||
|
||
//////////////////////////////////////////////////////////// | ||
// Metric | ||
|
||
namespace detail | ||
{ | ||
template<typename Sorter, typename CountType> | ||
struct moves_impl: | ||
utility::adapter_storage<Sorter>, | ||
cppsort::detail::check_iterator_category<Sorter>, | ||
cppsort::detail::check_is_always_stable<Sorter> | ||
{ | ||
using tag_t = moves_tag; | ||
using metric_t = utility::metric<CountType, tag_t>; | ||
|
||
moves_impl() = default; | ||
|
||
constexpr explicit moves_impl(Sorter&& sorter): | ||
utility::adapter_storage<Sorter>(std::move(sorter)) | ||
{} | ||
|
||
template< | ||
typename ForwardIterator, | ||
typename Compare = std::less<>, | ||
typename Projection = utility::identity, | ||
typename = cppsort::detail::enable_if_t<is_projection_iterator_v< | ||
Projection, ForwardIterator, Compare | ||
>> | ||
> | ||
auto operator()(ForwardIterator first, ForwardIterator last, | ||
Compare compare={}, Projection projection={}) const | ||
-> metric_t | ||
{ | ||
auto count = detail::count_moves<CountType>( | ||
first, last, | ||
std::distance(first, last), | ||
std::move(compare), std::move(projection), | ||
this->get() | ||
); | ||
return metric_t(count); | ||
} | ||
|
||
template< | ||
typename ForwardIterable, | ||
typename Compare = std::less<>, | ||
typename Projection = utility::identity, | ||
typename = cppsort::detail::enable_if_t< | ||
is_projection_v<Projection, ForwardIterable, Compare> | ||
> | ||
> | ||
auto operator()(ForwardIterable&& iterable, | ||
Compare compare={}, Projection projection={}) const | ||
{ | ||
auto count = detail::count_moves<CountType>( | ||
std::begin(iterable), std::end(iterable), | ||
utility::size(iterable), | ||
std::move(compare), std::move(projection), | ||
this->get() | ||
); | ||
return metric_t(count); | ||
} | ||
}; | ||
} | ||
|
||
template<typename Sorter, typename CountType> | ||
struct moves: | ||
sorter_facade<detail::moves_impl<Sorter, CountType>> | ||
{ | ||
moves() = default; | ||
|
||
constexpr explicit moves(Sorter sorter): | ||
sorter_facade<detail::moves_impl<Sorter, CountType>>(std::move(sorter)) | ||
{} | ||
}; | ||
}} | ||
|
||
namespace cppsort | ||
{ | ||
//////////////////////////////////////////////////////////// | ||
// is_stable specialization | ||
|
||
template<typename Sorter, typename CountType, typename... Args> | ||
struct is_stable<metrics::moves<Sorter, CountType>(Args...)>: | ||
is_stable<Sorter(Args...)> | ||
{}; | ||
} | ||
|
||
#endif // CPPSORT_METRICS_MOVES_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* Copyright (c) 2023 Morwenn | ||
* SPDX-License-Identifier: MIT | ||
*/ | ||
#include <algorithm> | ||
#include <cstddef> | ||
#include <functional> | ||
#include <iterator> | ||
#include <vector> | ||
#include <catch2/catch_test_macros.hpp> | ||
#include <cpp-sort/metrics/moves.h> | ||
#include <cpp-sort/sorters/heap_sorter.h> | ||
#include <testing-tools/algorithm.h> | ||
#include <testing-tools/distributions.h> | ||
#include <testing-tools/span.h> | ||
#include <testing-tools/wrapper.h> | ||
|
||
using wrapper = generic_wrapper<int>; | ||
|
||
TEST_CASE( "basic metrics::moves tests", | ||
"[metrics][heap_sorter]" ) | ||
{ | ||
cppsort::metrics::moves<cppsort::heap_sorter> sorter; | ||
|
||
SECTION( "without projections" ) | ||
{ | ||
std::vector<int> collection; | ||
auto distribution = dist::descending_plateau{}; | ||
distribution(std::back_inserter(collection), 65); | ||
|
||
auto res = sorter(collection); | ||
CHECK( res == 463 ); | ||
CHECK( std::is_sorted(collection.begin(), collection.end()) ); | ||
} | ||
|
||
SECTION( "with projections" ) | ||
{ | ||
std::vector<wrapper> collection; | ||
auto distribution = dist::descending_plateau{}; | ||
distribution(std::back_inserter(collection), 80); | ||
|
||
auto res = sorter(collection, &wrapper::value); | ||
CHECK( res == 573 ); | ||
CHECK( helpers::is_sorted(collection.begin(), collection.end(), | ||
std::less<>{}, &wrapper::value) ); | ||
} | ||
} | ||
|
||
TEST_CASE( "metrics::moves with span", | ||
"[metrics][span][heap_sorter]" ) | ||
{ | ||
cppsort::metrics::moves<cppsort::heap_sorter> sorter; | ||
|
||
SECTION( "without projections" ) | ||
{ | ||
std::vector<int> collection; | ||
auto distribution = dist::descending_plateau{}; | ||
distribution(std::back_inserter(collection), 65); | ||
|
||
auto res = sorter(make_span(collection)); | ||
CHECK( res == 463 ); | ||
CHECK( std::is_sorted(collection.begin(), collection.end()) ); | ||
} | ||
|
||
SECTION( "with projections" ) | ||
{ | ||
std::vector<wrapper> collection; | ||
auto distribution = dist::descending_plateau{}; | ||
distribution(std::back_inserter(collection), 80); | ||
|
||
auto res = sorter(make_span(collection), &wrapper::value); | ||
CHECK( res == 573 ); | ||
CHECK( helpers::is_sorted(collection.begin(), collection.end(), | ||
std::less<>{}, &wrapper::value) ); | ||
} | ||
} |