From 4dd3e115b2d883cbb185fb159b6086e9dced0e7e Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 22 Jan 2020 20:31:42 -0800 Subject: [PATCH 1/4] Improve handling of the _Count variable in _Sort_unchecked that we were forced to initialize in the constexpr algorithms review by eliminating the variable entirely. --- stl/inc/algorithm | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 77777c5b4b5..684b0fff87b 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -27,7 +27,7 @@ _END_EXTERN_C _STD_BEGIN // COMMON SORT PARAMETERS -const int _ISORT_MAX = 32; // maximum size for insertion sort +constexpr int _ISORT_MAX = 32; // maximum size for insertion sort // STRUCT TEMPLATE _Optimistic_temporary_buffer template @@ -3520,11 +3520,22 @@ _CONSTEXPR20 pair<_RanIt, _RanIt> _Partition_by_median_guess_unchecked(_RanIt _F template _CONSTEXPR20_ICE void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t<_RanIt> _Ideal, _Pr _Pred) { // order [_First, _Last), using _Pred - _Iter_diff_t<_RanIt> _Count = 0; - while (_ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal) { // divide and conquer by quicksort + for (;;) { + if (_Last - _First < _ISORT_MAX) { // small + _Insertion_sort_unchecked(_First, _Last, _Pred); + return; + } + + if (_Ideal <= 0) { // heap sort if too many divisions + _Make_heap_unchecked(_First, _Last, _Pred); + _Sort_heap_unchecked(_First, _Last, _Pred); + return; + } + + // divide and conquer by quicksort auto _Mid = _Partition_by_median_guess_unchecked(_First, _Last, _Pred); - _Ideal = _Ideal / 2 + _Ideal / 4; // allow 1.5 log2(N) divisions + _Ideal = (_Ideal >> 1) + (_Ideal >> 2); // allow 1.5 log2(N) divisions if (_Mid.first - _First < _Last - _Mid.second) { // loop on second half _Sort_unchecked(_First, _Mid.first, _Ideal, _Pred); @@ -3534,13 +3545,6 @@ _CONSTEXPR20_ICE void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t< _Last = _Mid.first; } } - - if (_ISORT_MAX < _Count) { // heap sort if too many divisions - _Make_heap_unchecked(_First, _Last, _Pred); - _Sort_heap_unchecked(_First, _Last, _Pred); - } else if (2 <= _Count) { - _Insertion_sort_unchecked(_First, _Last, _Pred); // small - } } template From e96eaf36f355ea14325cfa9c1958a1910a0453a0 Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 22 Jan 2020 21:40:46 -0800 Subject: [PATCH 2/4] Compare less-equal for _ISORT_MAX, guard _Insertion_sort_unchecked for 2, add _INLINE_VAR to _ISORT_MAX. --- stl/inc/algorithm | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 684b0fff87b..da28e66ace1 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -27,7 +27,7 @@ _END_EXTERN_C _STD_BEGIN // COMMON SORT PARAMETERS -constexpr int _ISORT_MAX = 32; // maximum size for insertion sort +_INLINE_VAR constexpr int _ISORT_MAX = 32; // maximum size for insertion sort // STRUCT TEMPLATE _Optimistic_temporary_buffer template @@ -3521,8 +3521,13 @@ template _CONSTEXPR20_ICE void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t<_RanIt> _Ideal, _Pr _Pred) { // order [_First, _Last), using _Pred for (;;) { - if (_Last - _First < _ISORT_MAX) { // small - _Insertion_sort_unchecked(_First, _Last, _Pred); + const _Iter_diff_t<_RanIt> _Count = _Last - _First; + + if (_Count <= _ISORT_MAX) { + if (2 <= _Count) { + _Insertion_sort_unchecked(_First, _Last, _Pred); + } + return; } From c8a45a3f2e845d4fbeb81c2edaa54dd9d8a2d59d Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 22 Jan 2020 22:00:24 -0800 Subject: [PATCH 3/4] Zombie _Insertion_sort_unchecked, add _Insertion_sort_unchecked2 with _First != _Last precondition since all callers already had count. --- stl/inc/algorithm | 57 ++++++++++++++++++++++++++++------------------- stl/inc/execution | 9 +++++--- 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index da28e66ace1..42bd2e63fe9 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3394,23 +3394,22 @@ void inplace_merge(_ExPo&&, _BidIt _First, _BidIt _Mid, _BidIt _Last) noexcept / // FUNCTION TEMPLATE sort template -_CONSTEXPR20_ICE _BidIt _Insertion_sort_unchecked(_BidIt _First, const _BidIt _Last, _Pr _Pred) { +_CONSTEXPR20_ICE _BidIt _Insertion_sort_unchecked2(_BidIt _First, const _BidIt _Last, _Pr _Pred) { // insertion sort [_First, _Last), using _Pred - if (_First != _Last) { - for (_BidIt _Next = _First; ++_Next != _Last;) { // order next element - _BidIt _Next1 = _Next; - _Iter_value_t<_BidIt> _Val = _STD move(*_Next); - - if (_DEBUG_LT_PRED(_Pred, _Val, *_First)) { // found new earliest element, move to front - _Move_backward_unchecked(_First, _Next, ++_Next1); - *_First = _STD move(_Val); - } else { // look for insertion point after first - for (_BidIt _First1 = _Next1; _DEBUG_LT_PRED(_Pred, _Val, *--_First1); _Next1 = _First1) { - *_Next1 = _STD move(*_First1); // move hole down - } - - *_Next1 = _STD move(_Val); // insert element in hole + _STL_INTERNAL_CHECK(_First != _Last); + for (_BidIt _Next = _First; ++_Next != _Last;) { // order next element + _BidIt _Next1 = _Next; + _Iter_value_t<_BidIt> _Val = _STD move(*_Next); + + if (_DEBUG_LT_PRED(_Pred, _Val, *_First)) { // found new earliest element, move to front + _Move_backward_unchecked(_First, _Next, ++_Next1); + *_First = _STD move(_Val); + } else { // look for insertion point after first + for (_BidIt _First1 = _Next1; _DEBUG_LT_PRED(_Pred, _Val, *--_First1); _Next1 = _First1) { + *_Next1 = _STD move(*_First1); // move hole down } + + *_Next1 = _STD move(_Val); // insert element in hole } } @@ -3525,7 +3524,7 @@ _CONSTEXPR20_ICE void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t< if (_Count <= _ISORT_MAX) { if (2 <= _Count) { - _Insertion_sort_unchecked(_First, _Last, _Pred); + _Insertion_sort_unchecked2(_First, _Last, _Pred); } return; @@ -3676,10 +3675,12 @@ void _Insertion_sort_isort_max_chunks(_BidIt _First, const _BidIt _Last, _Iter_d // pre: _Count == distance(_First, _Last) constexpr auto _Diffsort_max = static_cast<_Iter_diff_t<_BidIt>>(_ISORT_MAX); for (; _Diffsort_max < _Count; _Count -= _Diffsort_max) { // sort chunks - _First = _Insertion_sort_unchecked(_First, _STD next(_First, _Diffsort_max), _Pred); + _First = _Insertion_sort_unchecked2(_First, _STD next(_First, _Diffsort_max), _Pred); } - _Insertion_sort_unchecked(_First, _Last, _Pred); // sort partial last chunk + if (2 <= _Count) { + _Insertion_sort_unchecked2(_First, _Last, _Pred); // sort partial last chunk + } } template @@ -3719,7 +3720,9 @@ void _Stable_sort_unchecked(const _BidIt _First, const _BidIt _Last, const _Iter // sort preserving order of equivalents, using _Pred using _Diff = _Iter_diff_t<_BidIt>; if (_Count <= _ISORT_MAX) { - _Insertion_sort_unchecked(_First, _Last, _Pred); // small + if (2 < _Count) { + _Insertion_sort_unchecked2(_First, _Last, _Pred); // small + } } else { // sort halves and merge const auto _Half_count = static_cast<_Diff>(_Count / 2); const auto _Half_count_ceil = static_cast<_Diff>(_Count - _Half_count); @@ -3746,7 +3749,7 @@ void stable_sort(const _BidIt _First, const _BidIt _Last, _Pr _Pred) { const auto _Count = _STD distance(_UFirst, _ULast); if (_Count <= _ISORT_MAX) { if (_Count > 1) { - _Insertion_sort_unchecked(_UFirst, _ULast, _Pass_fn(_Pred)); + _Insertion_sort_unchecked2(_UFirst, _ULast, _Pass_fn(_Pred)); } return; @@ -3893,7 +3896,17 @@ _CONSTEXPR20_ICE void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last, _Pr return; // nothing to do } - while (_ISORT_MAX < _ULast - _UFirst) { // divide and conquer, ordering partition containing Nth + for (;;) { + const _Iter_diff_t<_RanIt> _Count = _Last - _First; + if (_Count <= _ISORT_MAX) { + if (2 <= _Count) { + _Insertion_sort_unchecked2(_UFirst, _ULast, _Pass_fn(_Pred)); // sort any remainder + } + + return; + } + + // divide and conquer, ordering partition containing Nth auto _UMid = _Partition_by_median_guess_unchecked(_UFirst, _ULast, _Pass_fn(_Pred)); if (_UMid.second <= _UNth) { @@ -3904,8 +3917,6 @@ _CONSTEXPR20_ICE void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last, _Pr _ULast = _UMid.first; } } - - _Insertion_sort_unchecked(_UFirst, _ULast, _Pass_fn(_Pred)); // sort any remainder } template diff --git a/stl/inc/execution b/stl/inc/execution index 15c210a8871..e0949aa0e43 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -2673,8 +2673,11 @@ bool _Process_sort_work_item(const _RanIt _Basis, _Pr _Pred, _Sort_work_item<_Ra const auto _Last = _First + _Size; const auto _Ideal = _Wi._Ideal; if (_Size <= _Diffsort_max) { - _Insertion_sort_unchecked(_First, _Last, _Pred); - _Work_complete += _Size; + if (2 <= _Size) { + _Insertion_sort_unchecked2(_First, _Last, _Pred); + _Work_complete += _Size; + } + return false; } @@ -3015,7 +3018,7 @@ void stable_sort(_ExPo&&, const _BidIt _First, const _BidIt _Last, _Pr _Pred) no const auto _Count = _STD distance(_UFirst, _ULast); if (_Count <= _ISORT_MAX) { if (_Count > 1) { - _Insertion_sort_unchecked(_UFirst, _ULast, _Pass_fn(_Pred)); + _Insertion_sort_unchecked2(_UFirst, _ULast, _Pass_fn(_Pred)); } return; From aa50d180e9837c2375d6a6faf1b03ee2b8cb99ef Mon Sep 17 00:00:00 2001 From: Billy Robert O'Neal III Date: Wed, 22 Jan 2020 23:15:40 -0800 Subject: [PATCH 4/4] WIP --- stl/inc/algorithm | 16 ++++++++-------- stl/inc/execution | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 42bd2e63fe9..afd23b21b74 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -2709,7 +2709,7 @@ _CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last, _Pr _Pred) { auto _ULast = _Get_unwrapped(_Last); using _Diff = _Iter_diff_t<_RanIt>; _Diff _Count = _ULast - _UFirst; - if (2 <= _Count) { + if (1 < _Count) { _Iter_value_t<_RanIt> _Val = _STD move(*--_ULast); _Push_heap_by_index(_UFirst, --_Count, _Diff(0), _STD move(_Val), _Pass_fn(_Pred)); } @@ -2764,7 +2764,7 @@ _CONSTEXPR20 void _Pop_heap_hole_unchecked(_RanIt _First, _RanIt _Last, _RanIt _ template _CONSTEXPR20 void _Pop_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { // pop *_First to *(_Last - 1) and reheap, using _Pred - if (2 <= _Last - _First) { + if (1 < _Last - _First) { --_Last; _Iter_value_t<_RanIt> _Val = _STD move(*_Last); _Pop_heap_hole_unchecked(_First, _Last, _Last, _STD move(_Val), _Pred); @@ -2879,7 +2879,7 @@ _NODISCARD bool is_heap(_ExPo&& _Exec, _RanIt _First, _RanIt _Last) noexcept /* template _CONSTEXPR20 void _Sort_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) { // order heap by repeatedly popping, using _Pred - for (; 2 <= _Last - _First; --_Last) { + for (; 1 < _Last - _First; --_Last) { _Pop_heap_unchecked(_First, _Last, _Pred); } } @@ -3523,7 +3523,7 @@ _CONSTEXPR20_ICE void _Sort_unchecked(_RanIt _First, _RanIt _Last, _Iter_diff_t< const _Iter_diff_t<_RanIt> _Count = _Last - _First; if (_Count <= _ISORT_MAX) { - if (2 <= _Count) { + if (1 < _Count) { _Insertion_sort_unchecked2(_First, _Last, _Pred); } @@ -3678,7 +3678,7 @@ void _Insertion_sort_isort_max_chunks(_BidIt _First, const _BidIt _Last, _Iter_d _First = _Insertion_sort_unchecked2(_First, _STD next(_First, _Diffsort_max), _Pred); } - if (2 <= _Count) { + if (1 < _Count) { _Insertion_sort_unchecked2(_First, _Last, _Pred); // sort partial last chunk } } @@ -3720,7 +3720,7 @@ void _Stable_sort_unchecked(const _BidIt _First, const _BidIt _Last, const _Iter // sort preserving order of equivalents, using _Pred using _Diff = _Iter_diff_t<_BidIt>; if (_Count <= _ISORT_MAX) { - if (2 < _Count) { + if (1 < _Count) { _Insertion_sort_unchecked2(_First, _Last, _Pred); // small } } else { // sort halves and merge @@ -3748,7 +3748,7 @@ void stable_sort(const _BidIt _First, const _BidIt _Last, _Pr _Pred) { const auto _ULast = _Get_unwrapped(_Last); const auto _Count = _STD distance(_UFirst, _ULast); if (_Count <= _ISORT_MAX) { - if (_Count > 1) { + if (1 < _Count) { _Insertion_sort_unchecked2(_UFirst, _ULast, _Pass_fn(_Pred)); } @@ -3899,7 +3899,7 @@ _CONSTEXPR20_ICE void nth_element(_RanIt _First, _RanIt _Nth, _RanIt _Last, _Pr for (;;) { const _Iter_diff_t<_RanIt> _Count = _Last - _First; if (_Count <= _ISORT_MAX) { - if (2 <= _Count) { + if (1 < _Count) { _Insertion_sort_unchecked2(_UFirst, _ULast, _Pass_fn(_Pred)); // sort any remainder } diff --git a/stl/inc/execution b/stl/inc/execution index e0949aa0e43..c2fc6a321f7 100644 --- a/stl/inc/execution +++ b/stl/inc/execution @@ -2673,11 +2673,11 @@ bool _Process_sort_work_item(const _RanIt _Basis, _Pr _Pred, _Sort_work_item<_Ra const auto _Last = _First + _Size; const auto _Ideal = _Wi._Ideal; if (_Size <= _Diffsort_max) { - if (2 <= _Size) { + if (1 < _Size) { _Insertion_sort_unchecked2(_First, _Last, _Pred); - _Work_complete += _Size; } + _Work_complete += _Size; return false; }