Skip to content

Commit

Permalink
Various probes: don't recompute size when already known (#169)
Browse files Browse the repository at this point in the history
  • Loading branch information
Morwenn committed Aug 25, 2020
1 parent e96f40f commit 2967a13
Show file tree
Hide file tree
Showing 4 changed files with 299 additions and 199 deletions.
183 changes: 101 additions & 82 deletions include/cpp-sort/probes/exc.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <cpp-sort/sorter_traits.h>
#include <cpp-sort/utility/as_function.h>
#include <cpp-sort/utility/functional.h>
#include <cpp-sort/utility/size.h>
#include <cpp-sort/utility/static_const.h>
#include "../detail/indirect_compare.h"
#include "../detail/iterator_traits.h"
Expand All @@ -47,8 +48,105 @@ namespace 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,
Compare compare, Projection projection)
-> ::cppsort::detail::difference_type_t<ForwardIterator>
{
using difference_type = ::cppsort::detail::difference_type_t<ForwardIterator>;
auto&& comp = utility::as_function(compare);
auto&& proj = utility::as_function(projection);

if (size < 2) {
return 0;
}

////////////////////////////////////////////////////////////
// Indirectly sort the iterators

// Copy the iterators in a vector
std::vector<ForwardIterator> iterators;
iterators.reserve(size);
for (auto it = first ; it != last ; ++it) {
iterators.push_back(it);
}

// Sort the iterators on pointed values
pdqsort(
iterators.begin(), iterators.end(),
cppsort::detail::indirect_compare<Compare, Projection>(std::move(compare),
std::move(projection)),
utility::identity{}
);

////////////////////////////////////////////////////////////
// Count the number of cycles

std::vector<bool> sorted(size, false);

// Element where the current cycle starts
auto start = first;

difference_type cycles = 0;
while (start != last) {
// Find the element to put in current's place
auto current = start;
auto next_pos = std::distance(first, current);
auto next = iterators[next_pos];
sorted[next_pos] = true;

// Process the current cycle
if (next != current) {
while (next != start) {
// If an element is in the place of another element that compares
// equivalent, it means that this element was actually already in
// a suitable place, so we count one more cycle as if it was an
// already suitably placed element, this handles collections with
// several elements which compare equivalent
if (not comp(proj(*next), proj(*current)) &&
not comp(proj(*current), proj(*next))) {
++cycles;
}
// Locate the next element of the cycle
current = next;
auto next_pos = std::distance(first, next);
next = iterators[next_pos];
sorted[next_pos] = true;
}
}

++cycles;

// Find the next cycle
auto&& sorted_it = sorted.begin() + std::distance(first, start);
do {
++start;
++sorted_it;
} while (start != last && *sorted_it);
}
return size - cycles;
}

struct exc_impl
{
template<
typename ForwardIterable,
typename Compare = std::less<>,
typename Projection = utility::identity,
typename = std::enable_if_t<
is_projection_v<Projection, ForwardIterable, Compare>
>
>
auto operator()(ForwardIterable&& iterable,
Compare compare={}, Projection projection={}) const
-> decltype(auto)
{
return exc_probe_algo(std::begin(iterable), std::end(iterable),
utility::size(iterable),
std::move(compare), std::move(projection));
}

template<
typename ForwardIterator,
typename Compare = std::less<>,
Expand All @@ -59,89 +157,10 @@ namespace probe
>
auto operator()(ForwardIterator first, ForwardIterator last,
Compare compare={}, Projection projection={}) const
-> cppsort::detail::difference_type_t<ForwardIterator>
-> decltype(auto)
{
using difference_type = cppsort::detail::difference_type_t<ForwardIterator>;
auto&& comp = ::cppsort::utility::as_function(compare);
auto&& proj = ::cppsort::utility::as_function(projection);

auto size = std::distance(first, last);
if (size < 2)
{
return 0;
}

////////////////////////////////////////////////////////////
// Indirectly sort the iterators

// Copy the iterators in a vector
std::vector<ForwardIterator> iterators;
iterators.reserve(size);
for (ForwardIterator it = first ; it != last ; ++it)
{
iterators.push_back(it);
}

// Sort the iterators on pointed values
pdqsort(
iterators.begin(), iterators.end(),
cppsort::detail::indirect_compare<Compare, Projection>(std::move(compare),
std::move(projection)),
utility::identity{}
);

////////////////////////////////////////////////////////////
// Count the number of cycles

std::vector<bool> sorted(size, false);

// Element where the current cycle starts
ForwardIterator start = first;

difference_type cycles = 0;
while (start != last)
{
// Find the element to put in current's place
ForwardIterator current = start;
auto next_pos = std::distance(first, current);
ForwardIterator next = iterators[next_pos];
sorted[next_pos] = true;

// Process the current cycle
if (next != current)
{
while (next != start)
{
// If an element is in the place of another element that compares
// equivalent, it means that this element was actually already in
// a suitable place, so we count one more cycle as if it was an
// already suitably placed element, this handles collections with
// several elements which compare equivalent
if (not comp(proj(*next), proj(*current)) &&
not comp(proj(*current), proj(*next)))
{
++cycles;
}
// Locate the next element of the cycle
current = next;
auto next_pos = std::distance(first, next);
next = iterators[next_pos];
sorted[next_pos] = true;
}
}

++cycles;

// Find the next cycle
auto&& sorted_it = sorted.begin() + std::distance(first, start);
do
{
++start;
++sorted_it;
}
while (start != last && *sorted_it);
}
return size - cycles;
return exc_probe_algo(first, last, std::distance(first, last),
std::move(compare), std::move(projection));
}
};
}
Expand Down
109 changes: 68 additions & 41 deletions include/cpp-sort/probes/ham.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2016-2019 Morwenn
* Copyright (c) 2016-2020 Morwenn
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -36,6 +36,7 @@
#include <cpp-sort/sorter_traits.h>
#include <cpp-sort/utility/as_function.h>
#include <cpp-sort/utility/functional.h>
#include <cpp-sort/utility/size.h>
#include <cpp-sort/utility/static_const.h>
#include "../detail/indirect_compare.h"
#include "../detail/iterator_traits.h"
Expand All @@ -47,8 +48,71 @@ namespace probe
{
namespace detail
{
template<typename ForwardIterator, typename Compare, typename Projection>
auto ham_probe_algo(ForwardIterator first, ForwardIterator last,
cppsort::detail::difference_type_t<ForwardIterator> size,
Compare compare, Projection projection)
-> ::cppsort::detail::difference_type_t<ForwardIterator>
{
using difference_type = ::cppsort::detail::difference_type_t<ForwardIterator>;
auto&& comp = utility::as_function(compare);
auto&& proj = utility::as_function(projection);

if (size < 2) {
return 0;
}

////////////////////////////////////////////////////////////
// Indirectly sort the iterators

// Copy the iterators in a vector
std::vector<ForwardIterator> iterators;
iterators.reserve(size);
for (ForwardIterator it = first ; it != last ; ++it) {
iterators.push_back(it);
}

// Sort the iterators on pointed values
cppsort::detail::pdqsort(
iterators.begin(), iterators.end(),
cppsort::detail::indirect_compare<Compare, Projection>(std::move(compare),
std::move(projection)),
utility::identity{}
);

////////////////////////////////////////////////////////////
// Count the number of values not in place

difference_type count = 0;
for (auto&& it: iterators) {
if (comp(proj(*first), proj(*it)) ||
comp(proj(*it), proj(*first))) {
++count;
}
++first;
}
return count;
}

struct ham_impl
{
template<
typename ForwardIterable,
typename Compare = std::less<>,
typename Projection = utility::identity,
typename = std::enable_if_t<
is_projection_v<Projection, ForwardIterable, Compare>
>
>
auto operator()(ForwardIterable&& iterable,
Compare compare={}, Projection projection={}) const
-> decltype(auto)
{
return ham_probe_algo(std::begin(iterable), std::end(iterable),
utility::size(iterable),
std::move(compare), std::move(projection));
}

template<
typename ForwardIterator,
typename Compare = std::less<>,
Expand All @@ -59,47 +123,10 @@ namespace probe
>
auto operator()(ForwardIterator first, ForwardIterator last,
Compare compare={}, Projection projection={}) const
-> cppsort::detail::difference_type_t<ForwardIterator>
-> decltype(auto)
{
using difference_type = cppsort::detail::difference_type_t<ForwardIterator>;
auto&& comp = utility::as_function(compare);
auto&& proj = utility::as_function(projection);

auto size = std::distance(first, last);
if (size < 2) {
return 0;
}

////////////////////////////////////////////////////////////
// Indirectly sort the iterators

// Copy the iterators in a vector
std::vector<ForwardIterator> iterators;
iterators.reserve(size);
for (ForwardIterator it = first ; it != last ; ++it) {
iterators.push_back(it);
}

// Sort the iterators on pointed values
cppsort::detail::pdqsort(
iterators.begin(), iterators.end(),
cppsort::detail::indirect_compare<Compare, Projection>(std::move(compare),
std::move(projection)),
utility::identity{}
);

////////////////////////////////////////////////////////////
// Count the number of values not in place

difference_type count = 0;
for (auto&& it: iterators) {
if (comp(proj(*first), proj(*it)) ||
comp(proj(*it), proj(*first))) {
++count;
}
++first;
}
return count;
return ham_probe_algo(first, last, std::distance(first, last),
std::move(compare), std::move(projection));
}
};
}
Expand Down

0 comments on commit 2967a13

Please sign in to comment.