| // -*- C++ -*- | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef _LIBCPP___ALGORITHM_RADIX_SORT_H | |
| #define _LIBCPP___ALGORITHM_RADIX_SORT_H | |
| // This is an implementation of classic LSD radix sort algorithm, running in linear time and using `O(max(N, M))` | |
| // additional memory, where `N` is size of an input range, `M` - maximum value of | |
| // a radix of the sorted integer type. Type of the radix and its maximum value are determined at compile time | |
| // based on type returned by function `__radix`. The default radix is uint8. | |
| // The algorithm is equivalent to several consecutive calls of counting sort for each | |
| // radix of the sorted numbers from low to high byte. | |
| // The algorithm uses a temporary buffer of size equal to size of the input range. Each `i`-th pass | |
| // of the algorithm sorts values by `i`-th radix and moves values to the temporary buffer (for each even `i`, counted | |
| // from zero), or moves them back to the initial range (for each odd `i`). If there is only one radix in sorted integers | |
| // (e.g. int8), the sorted values are placed to the buffer, and then moved back to the initial range. | |
| // The implementation also has several optimizations: | |
| // - the counters for the counting sort are calculated in one pass for all radices; | |
| // - if all values of a radix are the same, we do not sort that radix, and just move items to the buffer; | |
| // - if two consecutive radices satisfies condition above, we do nothing for these two radices. | |
| #include <__algorithm/for_each.h> | |
| #include <__algorithm/move.h> | |
| #include <__bit/bit_cast.h> | |
| #include <__bit/bit_log2.h> | |
| #include <__config> | |
| #include <__cstddef/size_t.h> | |
| #include <__functional/identity.h> | |
| #include <__iterator/access.h> | |
| #include <__iterator/distance.h> | |
| #include <__iterator/iterator_traits.h> | |
| #include <__iterator/move_iterator.h> | |
| #include <__iterator/next.h> | |
| #include <__iterator/reverse_iterator.h> | |
| #include <__numeric/partial_sum.h> | |
| #include <__type_traits/decay.h> | |
| #include <__type_traits/enable_if.h> | |
| #include <__type_traits/invoke.h> | |
| #include <__type_traits/is_assignable.h> | |
| #include <__type_traits/is_enum.h> | |
| #include <__type_traits/is_integral.h> | |
| #include <__type_traits/is_unsigned.h> | |
| #include <__type_traits/make_unsigned.h> | |
| #include <__type_traits/void_t.h> | |
| #include <__utility/declval.h> | |
| #include <__utility/forward.h> | |
| #include <__utility/integer_sequence.h> | |
| #include <__utility/move.h> | |
| #include <__utility/pair.h> | |
| #include <climits> | |
| #include <cstdint> | |
| #include <initializer_list> | |
| #include <limits> | |
| #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) | |
| # pragma GCC system_header | |
| #endif | |
| _LIBCPP_PUSH_MACROS | |
| #include <__undef_macros> | |
| #if _LIBCPP_STD_VER >= 14 | |
| _LIBCPP_BEGIN_NAMESPACE_STD | |
| template <class _InputIterator, class _OutputIterator> | |
| _LIBCPP_HIDE_FROM_ABI constexpr pair<_OutputIterator, __iterator_value_type<_InputIterator>> | |
| __partial_sum_max(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { | |
| if (__first == __last) | |
| return {__result, 0}; | |
| auto __max = *__first; | |
| __iterator_value_type<_InputIterator> __sum = *__first; | |
| *__result = __sum; | |
| while (++__first != __last) { | |
| if (__max < *__first) { | |
| __max = *__first; | |
| } | |
| __sum = std::move(__sum) + *__first; | |
| *++__result = __sum; | |
| } | |
| return {++__result, __max}; | |
| } | |
| template <class _Value, class _Map, class _Radix> | |
| struct __radix_sort_traits { | |
| using __image_type _LIBCPP_NODEBUG = decay_t<__invoke_result_t<_Map, _Value>>; | |
| static_assert(is_unsigned<__image_type>::value); | |
| using __radix_type _LIBCPP_NODEBUG = decay_t<__invoke_result_t<_Radix, __image_type>>; | |
| static_assert(is_integral<__radix_type>::value); | |
| static constexpr auto __radix_value_range = numeric_limits<__radix_type>::max() + 1; | |
| static constexpr auto __radix_size = std::__bit_log2<uint64_t>(__radix_value_range); | |
| static constexpr auto __radix_count = sizeof(__image_type) * CHAR_BIT / __radix_size; | |
| }; | |
| template <class _Value, class _Map> | |
| struct __counting_sort_traits { | |
| using __image_type _LIBCPP_NODEBUG = decay_t<__invoke_result_t<_Map, _Value>>; | |
| static_assert(is_unsigned<__image_type>::value); | |
| static constexpr const auto __value_range = numeric_limits<__image_type>::max() + 1; | |
| static constexpr auto __radix_size = std::__bit_log2<uint64_t>(__value_range); | |
| }; | |
| template <class _Radix, class _Integer> | |
| _LIBCPP_HIDE_FROM_ABI constexpr auto __nth_radix(size_t __radix_number, _Radix __radix, _Integer __n) { | |
| static_assert(is_unsigned<_Integer>::value); | |
| using __traits = __counting_sort_traits<_Integer, _Radix>; | |
| return __radix(static_cast<_Integer>(__n >> __traits::__radix_size * __radix_number)); | |
| } | |
| template <class _ForwardIterator, class _Map, class _RandomAccessIterator> | |
| _LIBCPP_HIDE_FROM_ABI constexpr void | |
| __collect(_ForwardIterator __first, _ForwardIterator __last, _Map __map, _RandomAccessIterator __counters) { | |
| using __value_type = __iterator_value_type<_ForwardIterator>; | |
| using __traits = __counting_sort_traits<__value_type, _Map>; | |
| std::for_each(__first, __last, [&__counters, &__map](const auto& __preimage) { ++__counters[__map(__preimage)]; }); | |
| const auto __counters_end = __counters + __traits::__value_range; | |
| std::partial_sum(__counters, __counters_end, __counters); | |
| } | |
| template <class _ForwardIterator, class _RandomAccessIterator1, class _Map, class _RandomAccessIterator2> | |
| _LIBCPP_HIDE_FROM_ABI constexpr void | |
| __dispose(_ForwardIterator __first, | |
| _ForwardIterator __last, | |
| _RandomAccessIterator1 __result, | |
| _Map __map, | |
| _RandomAccessIterator2 __counters) { | |
| std::for_each(__first, __last, [&__result, &__counters, &__map](auto&& __preimage) { | |
| auto __index = __counters[__map(__preimage)]++; | |
| __result[__index] = std::move(__preimage); | |
| }); | |
| } | |
| template <class _ForwardIterator, | |
| class _Map, | |
| class _Radix, | |
| class _RandomAccessIterator1, | |
| class _RandomAccessIterator2, | |
| size_t... _Radices> | |
| _LIBCPP_HIDE_FROM_ABI constexpr bool __collect_impl( | |
| _ForwardIterator __first, | |
| _ForwardIterator __last, | |
| _Map __map, | |
| _Radix __radix, | |
| _RandomAccessIterator1 __counters, | |
| _RandomAccessIterator2 __maximums, | |
| index_sequence<_Radices...>) { | |
| using __value_type = __iterator_value_type<_ForwardIterator>; | |
| constexpr auto __radix_value_range = __radix_sort_traits<__value_type, _Map, _Radix>::__radix_value_range; | |
| auto __previous = numeric_limits<__invoke_result_t<_Map, __value_type>>::min(); | |
| auto __is_sorted = true; | |
| std::for_each(__first, __last, [&__counters, &__map, &__radix, &__previous, &__is_sorted](const auto& __value) { | |
| auto __current = __map(__value); | |
| __is_sorted &= (__current >= __previous); | |
| __previous = __current; | |
| (++__counters[_Radices][std::__nth_radix(_Radices, __radix, __current)], ...); | |
| }); | |
| ((__maximums[_Radices] = | |
| std::__partial_sum_max(__counters[_Radices], __counters[_Radices] + __radix_value_range, __counters[_Radices]) | |
| .second), | |
| ...); | |
| return __is_sorted; | |
| } | |
| template <class _ForwardIterator, class _Map, class _Radix, class _RandomAccessIterator1, class _RandomAccessIterator2> | |
| _LIBCPP_HIDE_FROM_ABI constexpr bool | |
| __collect(_ForwardIterator __first, | |
| _ForwardIterator __last, | |
| _Map __map, | |
| _Radix __radix, | |
| _RandomAccessIterator1 __counters, | |
| _RandomAccessIterator2 __maximums) { | |
| using __value_type = __iterator_value_type<_ForwardIterator>; | |
| constexpr auto __radix_count = __radix_sort_traits<__value_type, _Map, _Radix>::__radix_count; | |
| return std::__collect_impl( | |
| __first, __last, __map, __radix, __counters, __maximums, make_index_sequence<__radix_count>()); | |
| } | |
| template <class _BidirectionalIterator, class _RandomAccessIterator1, class _Map, class _RandomAccessIterator2> | |
| _LIBCPP_HIDE_FROM_ABI constexpr void __dispose_backward( | |
| _BidirectionalIterator __first, | |
| _BidirectionalIterator __last, | |
| _RandomAccessIterator1 __result, | |
| _Map __map, | |
| _RandomAccessIterator2 __counters) { | |
| std::for_each(std::make_reverse_iterator(__last), | |
| std::make_reverse_iterator(__first), | |
| [&__result, &__counters, &__map](auto&& __preimage) { | |
| auto __index = --__counters[__map(__preimage)]; | |
| __result[__index] = std::move(__preimage); | |
| }); | |
| } | |
| template <class _ForwardIterator, class _RandomAccessIterator, class _Map> | |
| _LIBCPP_HIDE_FROM_ABI constexpr _RandomAccessIterator | |
| __counting_sort_impl(_ForwardIterator __first, _ForwardIterator __last, _RandomAccessIterator __result, _Map __map) { | |
| using __value_type = __iterator_value_type<_ForwardIterator>; | |
| using __traits = __counting_sort_traits<__value_type, _Map>; | |
| __iterator_difference_type<_RandomAccessIterator> __counters[__traits::__value_range + 1] = {0}; | |
| std::__collect(__first, __last, __map, std::next(std::begin(__counters))); | |
| std::__dispose(__first, __last, __result, __map, std::begin(__counters)); | |
| return __result + __counters[__traits::__value_range]; | |
| } | |
| template < | |
| class _RandomAccessIterator1, | |
| class _RandomAccessIterator2, | |
| class _Map, | |
| class _Radix, | |
| enable_if_t<__radix_sort_traits<__iterator_value_type<_RandomAccessIterator1>, _Map, _Radix>::__radix_count == 1, | |
| int> = 0> | |
| _LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort_impl( | |
| _RandomAccessIterator1 __first, | |
| _RandomAccessIterator1 __last, | |
| _RandomAccessIterator2 __buffer, | |
| _Map __map, | |
| _Radix __radix) { | |
| auto __buffer_end = std::__counting_sort_impl(__first, __last, __buffer, [&__map, &__radix](const auto& __value) { | |
| return __radix(__map(__value)); | |
| }); | |
| std::move(__buffer, __buffer_end, __first); | |
| } | |
| template <class _RandomAccessIterator1, | |
| class _RandomAccessIterator2, | |
| class _Map, | |
| class _Radix, | |
| enable_if_t< | |
| __radix_sort_traits<__iterator_value_type<_RandomAccessIterator1>, _Map, _Radix>::__radix_count % 2 == 0, | |
| int> = 0> | |
| _LIBCPP_HIDE_FROM_ABI constexpr void __radix_sort_impl( | |
| _RandomAccessIterator1 __first, | |
| _RandomAccessIterator1 __last, | |
| _RandomAccessIterator2 __buffer_begin, | |
| _Map __map, | |
| _Radix __radix) { | |
| using __value_type = __iterator_value_type<_RandomAccessIterator1>; | |
| using __traits = __radix_sort_traits<__value_type, _Map, _Radix>; | |
| __iterator_difference_type<_RandomAccessIterator1> | |
| __counters[__traits::__radix_count][__traits::__radix_value_range] = {{0}}; | |
| __iterator_difference_type<_RandomAccessIterator1> __maximums[__traits::__radix_count] = {0}; | |
| const auto __is_sorted = std::__collect(__first, __last, __map, __radix, __counters, __maximums); | |
| if (!__is_sorted) { | |
| const auto __range_size = std::distance(__first, __last); | |
| auto __buffer_end = __buffer_begin + __range_size; | |
| for (size_t __radix_number = 0; __radix_number < __traits::__radix_count; __radix_number += 2) { | |
| const auto __n0th_is_single = __maximums[__radix_number] == __range_size; | |
| const auto __n1th_is_single = __maximums[__radix_number + 1] == __range_size; | |
| if (__n0th_is_single && __n1th_is_single) { | |
| continue; | |
| } | |
| if (__n0th_is_single) { | |
| std::move(__first, __last, __buffer_begin); | |
| } else { | |
| auto __n0th = [__radix_number, &__map, &__radix](const auto& __v) { | |
| return std::__nth_radix(__radix_number, __radix, __map(__v)); | |
| }; | |
| std::__dispose_backward(__first, __last, __buffer_begin, __n0th, __counters[__radix_number]); | |
| } | |
| if (__n1th_is_single) { | |
| std::move(__buffer_begin, __buffer_end, __first); | |
| } else { | |
| auto __n1th = [__radix_number, &__map, &__radix](const auto& __v) { | |
| return std::__nth_radix(__radix_number + 1, __radix, __map(__v)); | |
| }; | |
| std::__dispose_backward(__buffer_begin, __buffer_end, __first, __n1th, __counters[__radix_number + 1]); | |
| } | |
| } | |
| } | |
| } | |
| _LIBCPP_HIDE_FROM_ABI constexpr auto __shift_to_unsigned(bool __b) { return __b; } | |
| template <class _Ip> | |
| _LIBCPP_HIDE_FROM_ABI constexpr auto __shift_to_unsigned(_Ip __n) { | |
| constexpr const auto __min_value = numeric_limits<_Ip>::min(); | |
| return static_cast<make_unsigned_t<_Ip> >(__n ^ __min_value); | |
| } | |
| template <size_t _Size> | |
| struct __unsigned_integer_of_size; | |
| template <> | |
| struct __unsigned_integer_of_size<1> { | |
| using type _LIBCPP_NODEBUG = uint8_t; | |
| }; | |
| template <> | |
| struct __unsigned_integer_of_size<2> { | |
| using type _LIBCPP_NODEBUG = uint16_t; | |
| }; | |
| template <> | |
| struct __unsigned_integer_of_size<4> { | |
| using type _LIBCPP_NODEBUG = uint32_t; | |
| }; | |
| template <> | |
| struct __unsigned_integer_of_size<8> { | |
| using type _LIBCPP_NODEBUG = uint64_t; | |
| }; | |
| # if _LIBCPP_HAS_INT128 | |
| template <> | |
| struct __unsigned_integer_of_size<16> { | |
| using type _LIBCPP_NODEBUG = unsigned __int128; | |
| }; | |
| # endif | |
| template <size_t _Size> | |
| using __unsigned_integer_of_size_t _LIBCPP_NODEBUG = typename __unsigned_integer_of_size<_Size>::type; | |
| template <class _Sc> | |
| using __unsigned_representation_for_t _LIBCPP_NODEBUG = __unsigned_integer_of_size_t<sizeof(_Sc)>; | |
| // The function `__to_ordered_integral` is defined for integers and IEEE 754 floating-point numbers. | |
| // Returns an integer representation such that for any `x` and `y` such that `x < y`, the expression | |
| // `__to_ordered_integral(x) < __to_ordered_integral(y)` is true, where `x`, `y` are integers or IEEE 754 floats. | |
| template <class _Integral, enable_if_t< is_integral<_Integral>::value, int> = 0> | |
| _LIBCPP_HIDE_FROM_ABI constexpr auto __to_ordered_integral(_Integral __n) { | |
| return __n; | |
| } | |
| // An overload for IEEE 754 floating-point numbers | |
| // For the floats conforming to IEEE 754 (IEC 559) standard, we know that: | |
| // 1. The bit representation of positive floats directly reflects their order: | |
| // When comparing floats by magnitude, the number with the larger exponent is greater, and if the exponents are | |
| // equal, the one with the larger mantissa is greater. | |
| // 2. The bit representation of negative floats reflects their reverse order (for the same reasons). | |
| // 3. The most significant bit (sign bit) is zero for positive floats and one for negative floats. Therefore, in the raw | |
| // bit representation, any negative number will be greater than any positive number. | |
| // The only exception from this rule is `NaN`, which is unordered by definition. | |
| // Based on the above, to obtain correctly ordered integral representation of floating-point numbers, we need to: | |
| // 1. Invert the bit representation (including the sign bit) of negative floats to switch from reverse order to direct | |
| // order; | |
| // 2. Invert the sign bit for positive floats. | |
| // Thus, in final integral representation, we have reversed the order for negative floats and made all negative floats | |
| // smaller than all positive numbers (by inverting the sign bit). | |
| template <class _Floating, enable_if_t< numeric_limits<_Floating>::is_iec559, int> = 0> | |
| _LIBCPP_HIDE_FROM_ABI constexpr auto __to_ordered_integral(_Floating __f) { | |
| using __integral_type = __unsigned_representation_for_t<_Floating>; | |
| constexpr auto __bit_count = std::numeric_limits<__integral_type>::digits; | |
| constexpr auto __sign_bit_mask = static_cast<__integral_type>(__integral_type{1} << (__bit_count - 1)); | |
| const auto __u = std::__bit_cast<__integral_type>(__f); | |
| return static_cast<__integral_type>(__u & __sign_bit_mask ? ~__u : __u ^ __sign_bit_mask); | |
| } | |
| // There may exist user-defined comparison for enum, so we cannot compare enums just like integers. | |
| template <class _Enum, enable_if_t< is_enum<_Enum>::value, int> = 0> | |
| _LIBCPP_HIDE_FROM_ABI constexpr auto __to_ordered_integral(_Enum __e) = delete; | |
| // `long double` varies significantly across platforms and compilers, making it practically | |
| // impossible to determine its actual bit width for conversion to an ordered integer. | |
| inline _LIBCPP_HIDE_FROM_ABI constexpr auto __to_ordered_integral(long double) = delete; | |
| template <class _Tp, class = void> | |
| inline const bool __is_ordered_integer_representable_v = false; | |
| template <class _Tp> | |
| inline const bool | |
| __is_ordered_integer_representable_v<_Tp, __void_t<decltype(std::__to_ordered_integral(std::declval<_Tp>()))>> = | |
| true; | |
| struct __low_byte_fn { | |
| template <class _Ip> | |
| _LIBCPP_HIDE_FROM_ABI constexpr uint8_t operator()(_Ip __integer) const { | |
| static_assert(is_unsigned<_Ip>::value); | |
| return static_cast<uint8_t>(__integer & 0xff); | |
| } | |
| }; | |
| template <class _RandomAccessIterator1, class _RandomAccessIterator2, class _Map, class _Radix> | |
| _LIBCPP_HIDE_FROM_ABI constexpr void | |
| __radix_sort(_RandomAccessIterator1 __first, | |
| _RandomAccessIterator1 __last, | |
| _RandomAccessIterator2 __buffer, | |
| _Map __map, | |
| _Radix __radix) { | |
| auto __map_to_unsigned = [__map = std::move(__map)](const auto& __x) { | |
| return std::__shift_to_unsigned(__map(std::__to_ordered_integral(__x))); | |
| }; | |
| std::__radix_sort_impl(__first, __last, __buffer, __map_to_unsigned, __radix); | |
| } | |
| template <class _RandomAccessIterator1, class _RandomAccessIterator2> | |
| _LIBCPP_HIDE_FROM_ABI constexpr void | |
| __radix_sort(_RandomAccessIterator1 __first, _RandomAccessIterator1 __last, _RandomAccessIterator2 __buffer) { | |
| std::__radix_sort(__first, __last, __buffer, __identity{}, __low_byte_fn{}); | |
| } | |
| _LIBCPP_END_NAMESPACE_STD | |
| #endif // _LIBCPP_STD_VER >= 14 | |
| _LIBCPP_POP_MACROS | |
| #endif // _LIBCPP___ALGORITHM_RADIX_SORT_H |