Skip to content

Commit

Permalink
stable_adapter: 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 23, 2020
1 parent 318e848 commit c4bc1cf
Showing 1 changed file with 76 additions and 39 deletions.
115 changes: 76 additions & 39 deletions include/cpp-sort/adapters/stable_adapter.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 @@ -38,6 +38,7 @@
#include <cpp-sort/utility/adapter_storage.h>
#include <cpp-sort/utility/as_function.h>
#include <cpp-sort/utility/functional.h>
#include <cpp-sort/utility/size.h>
#include "../detail/associate_iterator.h"
#include "../detail/checkers.h"
#include "../detail/iterator_traits.h"
Expand Down Expand Up @@ -105,61 +106,97 @@ namespace cppsort
return { compare, projection };
}

////////////////////////////////////////////////////////////
// make_stable_and_sort

template<
typename ForwardIterator,
typename Compare,
typename Projection,
typename Sorter
>
auto make_stable_and_sort(ForwardIterator first, difference_type_t<ForwardIterator> size,
Compare&& compare, Projection&& projection, Sorter&& sorter)
-> decltype(auto)
{
using difference_type = difference_type_t<ForwardIterator>;
using value_t = association<ForwardIterator, difference_type>;

////////////////////////////////////////////////////////////
// Bind index to iterator

std::unique_ptr<value_t, operator_deleter> iterators(
static_cast<value_t*>(::operator new(size * sizeof(value_t))),
operator_deleter(size * sizeof(value_t))
);
destruct_n<value_t> d(0);
std::unique_ptr<value_t, destruct_n<value_t>&> h2(iterators.get(), d);

// Associate iterators to their position
auto ptr = iterators.get();
for (difference_type count = 0 ; count != size ; ++count) {
::new(ptr) value_t(first, count);
++d;
++first;
++ptr;
}

////////////////////////////////////////////////////////////
// Sort but takes the index into account to ensure stability

return std::forward<Sorter>(sorter)(
make_associate_iterator(iterators.get()),
make_associate_iterator(iterators.get() + size),
make_stable_compare(std::move(compare), std::move(projection))
);
}

////////////////////////////////////////////////////////////
// Adapter

template<typename Sorter>
struct stable_adapter_impl:
struct make_stable_impl:
utility::adapter_storage<Sorter>,
check_iterator_category<Sorter>
{
stable_adapter_impl() = default;
make_stable_impl() = default;

constexpr explicit stable_adapter_impl(Sorter&& sorter):
constexpr explicit make_stable_impl(Sorter&& sorter):
utility::adapter_storage<Sorter>(std::move(sorter))
{}

template<
typename Iterator,
typename ForwardIterable,
typename Compare = std::less<>,
typename Projection = utility::identity,
typename = std::enable_if_t<is_projection_iterator_v<
Projection, Iterator, Compare
>>
typename = std::enable_if_t<
is_projection_v<Projection, ForwardIterable, Compare>
>
>
auto operator()(Iterator first, Iterator last,
auto operator()(ForwardIterable&& iterable,
Compare compare={}, Projection projection={}) const
-> decltype(auto)
{
using difference_type = difference_type_t<Iterator>;
using value_t = association<Iterator, difference_type>;

////////////////////////////////////////////////////////////
// Bind index to iterator

auto size = std::distance(first, last);
std::unique_ptr<value_t, operator_deleter> iterators(
static_cast<value_t*>(::operator new(size * sizeof(value_t))),
operator_deleter(size * sizeof(value_t))
);
destruct_n<value_t> d(0);
std::unique_ptr<value_t, destruct_n<value_t>&> h2(iterators.get(), d);

// Associate iterators to their position
difference_type count = 0;
for (auto ptr = iterators.get() ; first != last ; ++d, (void) ++first, ++ptr)
{
::new(ptr) value_t(first, count++);
}

////////////////////////////////////////////////////////////
// Sort but takes the index into account to ensure stability
return make_stable_and_sort(std::begin(iterable), utility::size(iterable),
std::move(compare), std::move(projection),
this->get());
}

return this->get()(
make_associate_iterator(iterators.get()),
make_associate_iterator(iterators.get() + size),
make_stable_compare(std::move(compare), std::move(projection))
);
template<
typename ForwardIterator,
typename Compare = std::less<>,
typename Projection = utility::identity,
typename = std::enable_if_t<
is_projection_iterator_v<Projection, ForwardIterator, Compare>
>
>
auto operator()(ForwardIterator first, ForwardIterator last,
Compare compare={}, Projection projection={}) const
-> decltype(auto)
{
return make_stable_and_sort(first, std::distance(first, last),
std::move(compare), std::move(projection),
this->get());
}

////////////////////////////////////////////////////////////
Expand All @@ -172,12 +209,12 @@ namespace cppsort
// Expose the underlying mechanism
template<typename Sorter>
struct make_stable:
sorter_facade<detail::stable_adapter_impl<Sorter>>
sorter_facade<detail::make_stable_impl<Sorter>>
{
make_stable() = default;

constexpr explicit make_stable(Sorter sorter):
sorter_facade<detail::stable_adapter_impl<Sorter>>(std::move(sorter))
sorter_facade<detail::make_stable_impl<Sorter>>(std::move(sorter))
{}
};

Expand Down

0 comments on commit c4bc1cf

Please sign in to comment.