зеркало из https://github.com/microsoft/STL.git
Implement ranges::sort (#1127)
This commit is contained in:
Родитель
3224307ff6
Коммит
4ce746ca4e
|
@ -1925,7 +1925,7 @@ namespace ranges {
|
|||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
auto _ULast = _Get_final_iterator_unwrapped<_It1>(_UFirst, _STD move(_Last));
|
||||
_Seek_wrapped(_First, _ULast);
|
||||
_Result = _RANGES _Move_backward_common(_STD move(_UFirst), _STD move(_ULast), _STD move(_Result));
|
||||
_Result = _Move_backward_common(_STD move(_UFirst), _STD move(_ULast), _STD move(_Result));
|
||||
return {_STD move(_First), _STD move(_Result)};
|
||||
}
|
||||
|
||||
|
@ -1933,7 +1933,7 @@ namespace ranges {
|
|||
requires indirectly_movable<iterator_t<_Rng>, _It>
|
||||
constexpr move_backward_result<borrowed_iterator_t<_Rng>, _It> operator()(_Rng&& _Range, _It _Result) const {
|
||||
auto _ULast = _Get_final_iterator_unwrapped(_Range);
|
||||
_Result = _RANGES _Move_backward_common(_Ubegin(_Range), _ULast, _STD move(_Result));
|
||||
_Result = _Move_backward_common(_Ubegin(_Range), _ULast, _STD move(_Result));
|
||||
return {_Rewrap_iterator(_Range, _STD move(_ULast)), _STD move(_Result)};
|
||||
}
|
||||
// clang-format on
|
||||
|
@ -6402,7 +6402,7 @@ namespace ranges {
|
|||
// FUNCTION TEMPLATE make_heap
|
||||
template <class _RanIt, class _Pr>
|
||||
_CONSTEXPR20 void _Make_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) {
|
||||
// make nontrivial [_First, _Last) into a heap
|
||||
// make [_First, _Last) into a heap
|
||||
using _Diff = _Iter_diff_t<_RanIt>;
|
||||
_Diff _Bottom = _Last - _First;
|
||||
for (_Diff _Hole = _Bottom >> 1; _Hole > 0;) { // shift for codegen
|
||||
|
@ -6431,8 +6431,8 @@ namespace ranges {
|
|||
template <random_access_iterator _It, class _Pr, class _Pj>
|
||||
requires sortable<_It, _Pr, _Pj>
|
||||
constexpr void _Make_heap_common(_It _First, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
// make nontrivial [_First, _Last) into a heap with respect to _Pred and _Proj
|
||||
// clang-format on
|
||||
// make [_First, _Last) into a heap with respect to _Pred and _Proj
|
||||
using _Diff = iter_difference_t<_It>;
|
||||
const _Diff _Bottom = _Last - _First;
|
||||
for (_Diff _Hole = _Bottom >> 1; _Hole > 0;) { // shift for codegen
|
||||
|
@ -6452,6 +6452,7 @@ namespace ranges {
|
|||
template <random_access_iterator _It, sentinel_for<_It> _Se, class _Pr = ranges::less, class _Pj = identity>
|
||||
requires sortable<_It, _Pr, _Pj>
|
||||
constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
// clang-format on
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last));
|
||||
|
@ -6460,9 +6461,11 @@ namespace ranges {
|
|||
return _First;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <random_access_range _Rng, class _Pr = ranges::less, class _Pj = identity>
|
||||
requires sortable<iterator_t<_Rng>, _Pr, _Pj>
|
||||
constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
// clang-format on
|
||||
if constexpr (common_range<_Rng>) {
|
||||
_Make_heap_common(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _RANGES end(_Range);
|
||||
|
@ -6472,7 +6475,6 @@ namespace ranges {
|
|||
return _Rewrap_iterator(_Range, _STD move(_ULast));
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Make_heap_fn make_heap{_Not_quite_object::_Construct_tag{}};
|
||||
|
@ -6665,8 +6667,8 @@ namespace ranges {
|
|||
template <random_access_iterator _It, class _Pr, class _Pj>
|
||||
requires sortable<_It, _Pr, _Pj>
|
||||
constexpr void _Sort_heap_common(const _It _First, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
// order heap by repeatedly popping
|
||||
// clang-format on
|
||||
// order heap by repeatedly popping
|
||||
for (; _Last - _First >= 2; --_Last) {
|
||||
_RANGES _Pop_heap_unchecked(_First, _Last, _Pred, _Proj);
|
||||
}
|
||||
|
@ -6680,6 +6682,7 @@ namespace ranges {
|
|||
template <random_access_iterator _It, sentinel_for<_It> _Se, class _Pr = ranges::less, class _Pj = identity>
|
||||
requires sortable<_It, _Pr, _Pj>
|
||||
constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
// clang-format on
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last));
|
||||
|
@ -6688,9 +6691,11 @@ namespace ranges {
|
|||
return _First;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <random_access_range _Rng, class _Pr = ranges::less, class _Pj = identity>
|
||||
requires sortable<iterator_t<_Rng>, _Pr, _Pj>
|
||||
constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
// clang-format on
|
||||
if constexpr (common_range<_Rng>) {
|
||||
_Sort_heap_common(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _RANGES end(_Range);
|
||||
|
@ -6700,7 +6705,6 @@ namespace ranges {
|
|||
return _Rewrap_iterator(_Range, _STD move(_ULast));
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Sort_heap_fn sort_heap{_Not_quite_object::_Construct_tag{}};
|
||||
|
@ -7628,6 +7632,7 @@ void sort(_ExPo&& _Exec, const _RanIt _First, const _RanIt _Last) noexcept /* te
|
|||
// order [_First, _Last)
|
||||
_STD sort(_STD forward<_ExPo>(_Exec), _First, _Last, less{});
|
||||
}
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
|
@ -7635,6 +7640,7 @@ namespace ranges {
|
|||
template <bidirectional_iterator _It, class _Pr, class _Pj>
|
||||
requires sortable<_It, _Pr, _Pj>
|
||||
constexpr void _Insertion_sort_common(const _It _First, const _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
// clang-format on
|
||||
// insertion sort [_First, _Last)
|
||||
|
||||
if (_First == _Last) { // empty range is sorted
|
||||
|
@ -7643,7 +7649,7 @@ namespace ranges {
|
|||
|
||||
for (auto _Mid = _First; ++_Mid != _Last;) { // order next element
|
||||
iter_value_t<_It> _Val = _RANGES iter_move(_Mid);
|
||||
auto _Hole = _Mid;
|
||||
auto _Hole = _Mid;
|
||||
|
||||
for (auto _Prev = _Hole;;) {
|
||||
--_Prev;
|
||||
|
@ -7660,9 +7666,11 @@ namespace ranges {
|
|||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <random_access_iterator _It, class _Pr, class _Pj>
|
||||
requires sortable<_It, _Pr, _Pj>
|
||||
constexpr void _Med3_unchecked(_It _First, _It _Mid, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
constexpr void _Med3_common(_It _First, _It _Mid, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
// clang-format on
|
||||
// sort median of three elements to middle
|
||||
if (_STD invoke(_Pred, _STD invoke(_Proj, *_Mid), _STD invoke(_Proj, *_First))) {
|
||||
_RANGES iter_swap(_Mid, _First);
|
||||
|
@ -7680,33 +7688,37 @@ namespace ranges {
|
|||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <random_access_iterator _It, class _Pr, class _Pj>
|
||||
requires sortable<_It, _Pr, _Pj>
|
||||
constexpr void _Guess_median_unchecked(_It _First, _It _Mid, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
constexpr void _Guess_median_common(_It _First, _It _Mid, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
// clang-format on
|
||||
// sort median element to middle
|
||||
using _Diff = iter_difference_t<_It>;
|
||||
const _Diff _Count = _Last - _First;
|
||||
if (_Count > 40) { // Tukey's ninther
|
||||
const _Diff _Step = (_Count + 1) >> 3; // +1 can't overflow because range was made inclusive in caller
|
||||
const _Diff _Two_step = _Step << 1; // note: intentionally discards low-order bit
|
||||
_Med3_unchecked(_First, _First + _Step, _First + _Two_step, _Pred, _Proj);
|
||||
_Med3_unchecked(_Mid - _Step, _Mid, _Mid + _Step, _Pred, _Proj);
|
||||
_Med3_unchecked(_Last - _Two_step, _Last - _Step, _Last, _Pred, _Proj);
|
||||
_Med3_unchecked(_First + _Step, _Mid, _Last - _Step, _Pred, _Proj);
|
||||
_Med3_common(_First, _First + _Step, _First + _Two_step, _Pred, _Proj);
|
||||
_Med3_common(_Mid - _Step, _Mid, _Mid + _Step, _Pred, _Proj);
|
||||
_Med3_common(_Last - _Two_step, _Last - _Step, _Last, _Pred, _Proj);
|
||||
_Med3_common(_First + _Step, _Mid, _Last - _Step, _Pred, _Proj);
|
||||
} else {
|
||||
_Med3_unchecked(_First, _Mid, _Last, _Pred, _Proj);
|
||||
_Med3_common(_First, _Mid, _Last, _Pred, _Proj);
|
||||
}
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <random_access_iterator _It, class _Pr, class _Pj>
|
||||
requires sortable<_It, _Pr, _Pj>
|
||||
_NODISCARD constexpr subrange<_It> _Partition_by_median_guess_unchecked(
|
||||
_NODISCARD constexpr subrange<_It> _Partition_by_median_guess_common(
|
||||
_It _First, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
// clang-format on
|
||||
// Choose a pivot, partition [_First, _Last) into elements less than pivot, elements equal to pivot, and
|
||||
// elements greater than pivot; return the equal partition as a subrange.
|
||||
|
||||
_It _Mid = _First + ((_Last - _First) >> 1); // shift for codegen
|
||||
_RANGES _Guess_median_unchecked(_First, _Mid, _RANGES prev(_Last), _Pred, _Proj);
|
||||
_Guess_median_common(_First, _Mid, _RANGES prev(_Last), _Pred, _Proj);
|
||||
_It _Pfirst = _Mid;
|
||||
_It _Plast = _RANGES next(_Pfirst);
|
||||
|
||||
|
@ -7716,8 +7728,7 @@ namespace ranges {
|
|||
--_Pfirst;
|
||||
}
|
||||
|
||||
while (_Plast < _Last
|
||||
&& !_STD invoke(_Pred, _STD invoke(_Proj, *_Plast), _STD invoke(_Proj, *_Pfirst))
|
||||
while (_Plast < _Last && !_STD invoke(_Pred, _STD invoke(_Proj, *_Plast), _STD invoke(_Proj, *_Pfirst))
|
||||
&& !_STD invoke(_Pred, _STD invoke(_Proj, *_Pfirst), _STD invoke(_Proj, *_Plast))) {
|
||||
++_Plast;
|
||||
}
|
||||
|
@ -7775,10 +7786,76 @@ namespace ranges {
|
|||
}
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
// VARIABLE ranges::sort
|
||||
class _Sort_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
// clang-format off
|
||||
template <random_access_iterator _It, sentinel_for<_It> _Se, class _Pr = ranges::less, class _Pj = identity>
|
||||
requires sortable<_It, _Pr, _Pj>
|
||||
constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
// clang-format on
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last));
|
||||
_Seek_wrapped(_First, _ULast);
|
||||
const auto _Count = _ULast - _UFirst;
|
||||
_Sort_common(_STD move(_UFirst), _STD move(_ULast), _Count, _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _First;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
template <random_access_range _Rng, class _Pr = ranges::less, class _Pj = identity>
|
||||
requires sortable<iterator_t<_Rng>, _Pr, _Pj>
|
||||
constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
// clang-format on
|
||||
auto _UFirst = _Ubegin(_Range);
|
||||
auto _ULast = _Get_final_iterator_unwrapped(_Range);
|
||||
const auto _Count = _ULast - _UFirst;
|
||||
_Sort_common(_STD move(_UFirst), _ULast, _Count, _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _Rewrap_iterator(_Range, _STD move(_ULast));
|
||||
}
|
||||
|
||||
private:
|
||||
template <class _It, class _Pr, class _Pj>
|
||||
static constexpr void _Sort_common(_It _First, _It _Last, iter_difference_t<_It> _Ideal, _Pr _Pred, _Pj _Proj) {
|
||||
// sort [_First, _Last) with respect to _Pred and _Proj
|
||||
_STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>);
|
||||
|
||||
for (;;) {
|
||||
if (_Last - _First <= _ISORT_MAX) { // small
|
||||
_Insertion_sort_common(_STD move(_First), _STD move(_Last), _Pred, _Proj);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_Ideal <= 0) { // heap sort if too many divisions
|
||||
_Make_heap_common(_First, _Last, _Pred, _Proj);
|
||||
_Sort_heap_common(_STD move(_First), _STD move(_Last), _Pred, _Proj);
|
||||
return;
|
||||
}
|
||||
|
||||
// divide and conquer by quicksort
|
||||
auto [_Mid_first, _Mid_last] = _Partition_by_median_guess_common(_First, _Last, _Pred, _Proj);
|
||||
|
||||
_Ideal = (_Ideal >> 1) + (_Ideal >> 2); // allow 1.5 log2(N) divisions
|
||||
|
||||
if (_Mid_first - _First < _Last - _Mid_last) { // loop on second half
|
||||
_Sort_common(_First, _STD move(_Mid_first), _Ideal, _Pred, _Proj);
|
||||
_First = _STD move(_Mid_last);
|
||||
} else { // loop on first half
|
||||
_Sort_common(_STD move(_Mid_last), _Last, _Ideal, _Pred, _Proj);
|
||||
_Last = _STD move(_Mid_first);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _Sort_fn sort{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
// FUNCTION TEMPLATE stable_sort
|
||||
template <class _FwdIt, class _Ty, class _Pr>
|
||||
|
@ -8184,7 +8261,7 @@ namespace ranges {
|
|||
}
|
||||
|
||||
while (_ISORT_MAX < _Last - _First) { // divide and conquer, ordering partition containing Nth
|
||||
subrange<_It> _Mid = _RANGES _Partition_by_median_guess_unchecked(_First, _Last, _Pred, _Proj);
|
||||
subrange<_It> _Mid = _Partition_by_median_guess_common(_First, _Last, _Pred, _Proj);
|
||||
|
||||
if (_Mid.end() <= _Nth) {
|
||||
_First = _Mid.end();
|
||||
|
@ -8196,7 +8273,7 @@ namespace ranges {
|
|||
}
|
||||
|
||||
// sort any remainder
|
||||
_RANGES _Insertion_sort_common(_STD move(_First), _STD move(_Last), _STD move(_Pred), _STD move(_Proj));
|
||||
_Insertion_sort_common(_STD move(_First), _STD move(_Last), _STD move(_Pred), _STD move(_Proj));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -298,6 +298,7 @@ tests\P0896R4_ranges_alg_set_intersection
|
|||
tests\P0896R4_ranges_alg_set_symmetric_difference
|
||||
tests\P0896R4_ranges_alg_set_union
|
||||
tests\P0896R4_ranges_alg_shuffle
|
||||
tests\P0896R4_ranges_alg_sort
|
||||
tests\P0896R4_ranges_alg_swap_ranges
|
||||
tests\P0896R4_ranges_alg_transform_binary
|
||||
tests\P0896R4_ranges_alg_transform_unary
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# Copyright (c) Microsoft Corporation.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
using namespace std;
|
||||
using P = pair<int, int>;
|
||||
|
||||
// Validate dangling story
|
||||
STATIC_ASSERT(same_as<decltype(ranges::sort(borrowed<false>{})), ranges::dangling>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::sort(borrowed<true>{})), int*>);
|
||||
|
||||
struct instantiator {
|
||||
static constexpr array input = {P{-1200257975, 0}, P{-1260655766, 1}, P{-1298559576, 2}, P{-1459960308, 3},
|
||||
P{-2095681771, 4}, P{-441494788, 5}, P{-47163201, 6}, P{-912489821, 7}, P{1429106719, 8}, P{1668617627, 9}};
|
||||
|
||||
template <ranges::random_access_range R>
|
||||
static constexpr void call() {
|
||||
#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163
|
||||
if constexpr (!ranges::contiguous_range<R>)
|
||||
#endif // TRANSITION, VSO-938163
|
||||
{
|
||||
using ranges::sort, ranges::is_sorted, ranges::iterator_t, ranges::less;
|
||||
|
||||
{ // Validate range overload
|
||||
auto buff = input;
|
||||
const R range{buff};
|
||||
const same_as<iterator_t<R>> auto result = sort(range, less{}, get_first);
|
||||
assert(result == range.end());
|
||||
assert(is_sorted(range, less{}, get_first));
|
||||
}
|
||||
|
||||
{ // Validate iterator overload
|
||||
auto buff = input;
|
||||
const R range{buff};
|
||||
const same_as<iterator_t<R>> auto result = sort(range.begin(), range.end(), less{}, get_first);
|
||||
assert(result == range.end());
|
||||
assert(is_sorted(range.begin(), range.end(), less{}, get_first));
|
||||
}
|
||||
|
||||
{ // Validate empty range
|
||||
const R range{};
|
||||
const same_as<iterator_t<R>> auto result = sort(range, less{}, get_first);
|
||||
assert(result == range.end());
|
||||
assert(is_sorted(range, less{}, get_first));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((test_random<instantiator, P>(), true));
|
||||
test_random<instantiator, P>();
|
||||
}
|
Загрузка…
Ссылка в новой задаче