Skip to content

Commit

Permalink
refs #185 Если размер сортируемого массива небольшой, то эффективнее …
Browse files Browse the repository at this point in the history
…взять меньшие счётчики
  • Loading branch information
izvolov committed Feb 16, 2025
1 parent 8d11c7e commit 310c74f
Show file tree
Hide file tree
Showing 5 changed files with 204 additions and 14 deletions.
32 changes: 29 additions & 3 deletions include/burst/algorithm/detail/counting_sort.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,13 @@ namespace burst
});
}

template <typename ForwardIterator, typename RandomAccessIterator, typename Map>
template
<
typename Counter,
typename ForwardIterator,
typename RandomAccessIterator,
typename Map
>
RandomAccessIterator
counting_sort_impl
(
Expand All @@ -138,15 +144,35 @@ namespace burst
using value_type = iterator_value_t<ForwardIterator>;
using traits = counting_sort_traits<value_type, Map>;

using difference_type = iterator_difference_t<RandomAccessIterator>;
using counter_type = Counter;
// Единица для дополнительного нуля в начале массива.
difference_type counters[traits::value_range + 1] = {0};
counter_type counters[traits::value_range + 1] = {0};

collect(first, last, map, std::next(std::begin(counters)));
dispose(first, last, result, map, std::begin(counters));

return result + burst::cback(counters);
}

template <typename ForwardIterator, typename RandomAccessIterator, typename Map>
RandomAccessIterator
counting_sort_impl
(
ForwardIterator first,
ForwardIterator last,
RandomAccessIterator result,
Map map
)
{
return
counting_sort_impl<iterator_difference_t<RandomAccessIterator>>
(
first,
last,
result,
map
);
}
} // namespace detail
} // namespace burst

Expand Down
13 changes: 7 additions & 6 deletions include/burst/algorithm/detail/radix_sort.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ namespace burst
Вызывает сортировку подсчётом из входного диапазона в буфер, а потом переносит
результат из буфера обратно во входной диапазон.
*/
template <typename RandomAccessIterator1, typename RandomAccessIterator2, typename Map, typename Radix>
template <typename Counter, typename RandomAccessIterator1, typename RandomAccessIterator2, typename Map, typename Radix>
typename std::enable_if
<
radix_sort_traits
Expand All @@ -100,8 +100,9 @@ namespace burst
>
::type radix_sort_impl (RandomAccessIterator1 first, RandomAccessIterator1 last, RandomAccessIterator2 buffer, Map map, Radix radix)
{
using counter_type = Counter;
auto buffer_end =
counting_sort_impl(move_assign_please(first), move_assign_please(last), buffer,
counting_sort_impl<counter_type>(move_assign_please(first), move_assign_please(last), buffer,
[& map, & radix] (const auto & value)
{
return radix(map(value));
Expand Down Expand Up @@ -196,7 +197,7 @@ namespace burst
Таким образом, в итоге во входном диапазоне оказывается отсортированная
последовательность.
*/
template <typename RandomAccessIterator1, typename RandomAccessIterator2, typename Map, typename Radix>
template <typename Counter, typename RandomAccessIterator1, typename RandomAccessIterator2, typename Map, typename Radix>
typename std::enable_if
<
radix_sort_traits
Expand All @@ -213,9 +214,9 @@ namespace burst
using value_type = iterator_value_t<RandomAccessIterator1>;
using traits = radix_sort_traits<value_type, Map, Radix>;

using difference_type = iterator_difference_t<RandomAccessIterator1>;
difference_type counters[traits::radix_count][traits::radix_value_range] = {{0}};
difference_type maximums[traits::radix_count] = {0};
using counter_type = Counter;
counter_type counters[traits::radix_count][traits::radix_value_range] = {{0}};
counter_type maximums[traits::radix_count] = {0};
const auto is_sorted = collect(first, last, map, radix, counters, maximums);
if (not is_sorted)
{
Expand Down
38 changes: 37 additions & 1 deletion include/burst/algorithm/radix_sort/radix_sort_seq.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@
#include <burst/functional/identity.hpp>
#include <burst/functional/low_byte.hpp>
#include <burst/integer/to_unsigned.hpp>
#include <burst/type_traits/iterator_difference.hpp>

#include <cstdint>
#include <iterator>
#include <limits>
#include <type_traits>
#include <utility>

namespace burst
Expand Down Expand Up @@ -106,7 +110,39 @@ namespace burst
Radix radix
)
{
detail::radix_sort_impl(first, last, buffer, compose(to_unsigned, std::move(map)), radix);
using difference_type = iterator_difference_t<RandomAccessIterator1>;
using min_type =
typename std::conditional
<
sizeof(std::int32_t) < sizeof(difference_type),
std::int32_t,
difference_type
>
::type;

using std::distance;
if (distance(first, last) <= std::numeric_limits<min_type>::max())
{
detail::radix_sort_impl<min_type>
(
first,
last,
buffer,
compose(to_unsigned, std::move(map)),
radix
);
}
else
{
detail::radix_sort_impl<difference_type>
(
first,
last,
buffer,
compose(to_unsigned, std::move(map)),
radix
);
}
}

template <typename RandomAccessIterator1, typename RandomAccessIterator2, typename Map>
Expand Down
29 changes: 25 additions & 4 deletions test/burst/algorithm/radix_sort.cpp
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
#include <utility/io/pair.hpp>
#include <utility/random_vector.hpp>
#include <utility/silly_iterator.hpp>

#include <burst/algorithm/radix_sort.hpp>

#include <doctest/doctest.h>

#include <boost/iterator/indirect_iterator.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/range/rbegin.hpp>
#include <boost/range/rend.hpp>

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <iterator>
#include <limits>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <string>
#include <thread>
#include <unordered_set>
Expand Down Expand Up @@ -563,4 +563,25 @@ TEST_SUITE("radix_sort")
CHECK(thread_ids.size() == 1);
CHECK(thread_ids.find(std::this_thread::get_id()) != thread_ids.end());
}

// Тест нужен для обеспечения 100%-й метрики покрытия кода тестами.
TEST_CASE_TEMPLATE("Если размер сортируемого массива превышает максимальное значение "
"32-битного числа, то алгоритм идёт через ветку с int64-счётчиками",
integer_type, std::int8_t, std::int16_t)
{
const auto begin = utility::silly_iterator<integer_type>(0);
const auto end = utility::silly_iterator<integer_type>(std::int64_t{1} << 32);

CHECK_THROWS_AS
(
burst::radix_sort(begin, end, begin,
[] (auto x)
{
// И тут же выходит, потому что реальную сортировку производить чудовищно долго.
throw std::runtime_error("stop");
return x;
}),
std::runtime_error
);
}
}
106 changes: 106 additions & 0 deletions test/utility/silly_iterator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#ifndef BURST_TEST__UTILITY__SILLY_ITERATOR_HPP
#define BURST_TEST__UTILITY__SILLY_ITERATOR_HPP

#include <boost/iterator/iterator_facade.hpp>

#include <cstdint>
#include <memory>

namespace utility
{
/*!
\brief
Дурацкий итератор
\details
Сущность с интерфейсом итератора произвольного доступа.
Умеет продвигаться на любое расстояние и правильно определять расстояние между двумя
итераторами, но при разыменовании всегда возвращает одно и то же значение.
*/
template <typename Value>
struct silly_iterator:
public
boost::iterator_facade
<
silly_iterator<Value>,
Value,
boost::random_access_traversal_tag,
Value &,
std::int64_t
>
{
private:
using base_type =
boost::iterator_facade
<
silly_iterator<Value>,
Value,
boost::random_access_traversal_tag,
Value &,
std::int64_t
>;

public:
silly_iterator ():
m_pos(0),
m_value(std::make_unique<Value>(0))
{
}

explicit silly_iterator (std::int64_t pos):
m_pos(pos),
m_value(std::make_unique<Value>(0))
{
}

silly_iterator (const silly_iterator & that):
m_pos(that.m_pos),
m_value(std::make_unique<Value>(0))
{
}

silly_iterator & operator = (const silly_iterator & that)
{
m_pos = that.m_pos;
return *this;
}

~silly_iterator () = default;

void increment ()
{
++m_pos;
}

void decrement ()
{
--m_pos;
}

void advance (typename base_type::difference_type n)
{
m_pos += n;
}

bool equal (const silly_iterator & that) const
{
return this->m_pos == that.m_pos;
}

typename base_type::difference_type distance_to (const silly_iterator & that) const
{
return that.m_pos - this->m_pos;
}

typename base_type::reference dereference () const
{
return *m_value;
}

private:
std::int64_t m_pos;
std::unique_ptr<Value> m_value;
};
}

#endif // BURST_TEST__UTILITY__SILLY_ITERATOR_HPP

0 comments on commit 310c74f

Please sign in to comment.