Skip to content

Commit

Permalink
Introduce lower_bound_n and upper_bound_n, improve inplace_merge (#169)
Browse files Browse the repository at this point in the history
The inplace_merge algorithm that works for forward iterators when no
heap memory is available was passing next(i, n) to upper_bound and
lower_bound while both of those start by computing the size again from
the passed iterators. Introducing lower_bound_n and upper_bound_n avoids
to cross the subrange twice to compute information we already have.

This change makes the forward iterator version of merge_sort way faster
than it used to be when no heap memory is available.
  • Loading branch information
Morwenn committed Aug 22, 2020
1 parent b0759f0 commit b67a348
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 10 deletions.
6 changes: 2 additions & 4 deletions include/cpp-sort/detail/inplace_merge.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,7 @@ namespace detail
f0_0 = std::move(f0);
n0_0 = n0 / 2;
f0_1 = std::next(f0_0, n0_0);
f1_1 = lower_bound(f1, std::next(f1, n1), proj(*f0_1),
std::move(compare), std::move(projection));
f1_1 = lower_bound_n(f1, n1, proj(*f0_1), std::move(compare), std::move(projection));
f1_0 = detail::rotate(f0_1, std::move(f1), f1_1);
n0_1 = std::distance(f0_1, f1_0);
++f1_0;
Expand All @@ -222,8 +221,7 @@ namespace detail
f0_0 = f0;
n0_1 = n1 / 2;
f1_1 = std::next(f1, n0_1);
f0_1 = upper_bound(f0, std::next(f0, n0), proj(*f1_1),
std::move(compare), std::move(projection));
f0_1 = upper_bound_n(f0, n0, proj(*f1_1), std::move(compare), std::move(projection));
++f1_1;
f1_0 = detail::rotate(f0_1, std::move(f1), f1_1);
n0_0 = std::distance(f0_0, f0_1);
Expand Down
18 changes: 15 additions & 3 deletions include/cpp-sort/detail/lower_bound.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,24 @@
// Headers
////////////////////////////////////////////////////////////
#include <iterator>
#include <utility>
#include <cpp-sort/utility/as_function.h>
#include "bitops.h"
#include "iterator_traits.h"

namespace cppsort
{
namespace detail
{
template<typename ForwardIterator, typename T,
typename Compare, typename Projection>
auto lower_bound(ForwardIterator first, ForwardIterator last, T&& value,
Compare compare, Projection projection)
auto lower_bound_n(ForwardIterator first, difference_type_t<ForwardIterator> size,
T&& value, Compare compare, Projection projection)
-> ForwardIterator
{
auto&& comp = utility::as_function(compare);
auto&& proj = utility::as_function(projection);

auto size = std::distance(first, last);
while (size > 0) {
ForwardIterator it = first;
std::advance(it, half(size));
Expand All @@ -57,6 +58,17 @@ namespace detail
}
return first;
}

template<typename ForwardIterator, typename T,
typename Compare, typename Projection>
auto lower_bound(ForwardIterator first, ForwardIterator last, T&& value,
Compare compare, Projection projection)
-> ForwardIterator
{
return lower_bound_n(first, std::distance(first, last),
std::forward<T>(value),
std::move(compare), std::move(projection));
}
}}

#endif // CPPSORT_DETAIL_LOWER_BOUND_H_
18 changes: 15 additions & 3 deletions include/cpp-sort/detail/upper_bound.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,24 @@
// Headers
////////////////////////////////////////////////////////////
#include <iterator>
#include <utility>
#include <cpp-sort/utility/as_function.h>
#include "bitops.h"
#include "iterator_traits.h"

namespace cppsort
{
namespace detail
{
template<typename ForwardIterator, typename T,
typename Compare, typename Projection>
auto upper_bound(ForwardIterator first, ForwardIterator last, T&& value,
Compare compare, Projection projection)
auto upper_bound_n(ForwardIterator first, difference_type_t<ForwardIterator> size,
T&& value, Compare compare, Projection projection)
-> ForwardIterator
{
auto&& comp = utility::as_function(compare);
auto&& proj = utility::as_function(projection);

auto size = std::distance(first, last);
while (size > 0) {
ForwardIterator it = first;
std::advance(it, half(size));
Expand All @@ -57,6 +58,17 @@ namespace detail
}
return first;
}

template<typename ForwardIterator, typename T,
typename Compare, typename Projection>
auto upper_bound(ForwardIterator first, ForwardIterator last, T&& value,
Compare compare, Projection projection)
-> ForwardIterator
{
return upper_bound_n(first, std::distance(first, last),
std::forward<T>(value),
std::move(compare), std::move(projection));
}
}}

#endif // CPPSORT_DETAIL_UPPER_BOUND_H_

0 comments on commit b67a348

Please sign in to comment.