From 46dd1c79c38fae966b32549e67eed41dbe0beaf1 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Sat, 25 Jul 2020 12:59:33 -0700 Subject: [PATCH 1/4] partial_sort_copy bugfix Instead of assuming that the `_Val` argument to the heap helper functions is an rvalue of some type, perfect-forward it all the way into `_Push_heap_by_index` where it's finally written into the hole in the heap. This allows `partial_sort_copy` to pass in ` reference to an element in its input range which is then correctly written into the output range in `_Push_heap_by_index`. I update the `std::ranges` heap helpers similarly, and make their constraints explicit. The helpers with a `_Val` argument now accept a distinct projection to be applied to `_Val`, which will enable the implementation of `std::ranges::partial_sort_copy`. Drive-by: Replace `_unchecked` in the names of `ranges::_Make_heap_fn::_Make_heap_unchecked` and `ranges::_Sort_heap_fn::_Sort_heap_unchecked` with `_common` to be consistent with the names of other internal helpers that require the sentinel and iterator to have the same type. Promote both functions from class scope to namespace scope as need to support implementation of `partial_sort` and `partial_sort_copy`. Fixes #1086. --- stl/inc/algorithm | 130 +++++++++--------- tests/std/test.lst | 1 + .../tests/GH_001086_partial_sort_copy/env.lst | 4 + .../GH_001086_partial_sort_copy/test.cpp | 63 +++++++++ 4 files changed, 136 insertions(+), 62 deletions(-) create mode 100644 tests/std/tests/GH_001086_partial_sort_copy/env.lst create mode 100644 tests/std/tests/GH_001086_partial_sort_copy/test.cpp diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 9f5ea0f97cf..dd367caf086 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -5294,7 +5294,7 @@ _CONSTEXPR20 void _Push_heap_by_index( _Hole = _Idx; } - *(_First + _Hole) = _STD move(_Val); // drop _Val into final hole + *(_First + _Hole) = _STD forward<_Ty>(_Val); // drop _Val into final hole } template @@ -5320,16 +5320,17 @@ _CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last) { #ifdef __cpp_lib_concepts namespace ranges { // VARIABLE ranges::push_heap - template + // clang-format off + template + requires sortable<_It, _Pr, _Pj1> && indirectly_writable<_It, _Ty> + && indirect_strict_weak_order<_Pr, projected<_It, _Pj1>, projected*, _Pj2>> constexpr void _Push_heap_by_index(const _It _First, iter_difference_t<_It> _Hole, - const iter_difference_t<_It> _Top, iter_value_t<_It>&& _Val, _Pr _Pred, _Pj _Proj) { + const iter_difference_t<_It> _Top, _Ty&& _Val, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) { + // clang-format on // percolate _Hole to _Top or where _Val belongs - _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); - _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); - while (_Top < _Hole) { const auto _Idx = static_cast>((_Hole - 1) >> 1); // shift for codegen - if (!_STD invoke(_Pred, _STD invoke(_Proj, *(_First + _Idx)), _STD invoke(_Proj, _Val))) { + if (!_STD invoke(_Pred, _STD invoke(_Proj1, *(_First + _Idx)), _STD invoke(_Proj2, _Val))) { break; } @@ -5338,7 +5339,7 @@ namespace ranges { _Hole = _Idx; } - *(_First + _Hole) = _STD move(_Val); // drop _Val into final hole + *(_First + _Hole) = _STD forward<_Ty>(_Val); // drop _Val into final hole } class _Push_heap_fn : private _Not_quite_object { @@ -5383,7 +5384,7 @@ namespace ranges { --_Last; iter_value_t<_It> _Val = _RANGES iter_move(_Last); - _RANGES _Push_heap_by_index(_STD move(_First), _Count - 1, 0, _STD move(_Val), _Pred, _Proj); + _RANGES _Push_heap_by_index(_STD move(_First), _Count - 1, 0, _STD move(_Val), _Pred, _Proj, _Proj); } }; @@ -5419,7 +5420,7 @@ _CONSTEXPR20 void _Pop_heap_hole_by_index( _Hole = _Bottom - 1; } - _Push_heap_by_index(_First, _Hole, _Top, _STD move(_Val), _Pred); + _Push_heap_by_index(_First, _Hole, _Top, _STD forward<_Ty>(_Val), _Pred); } template @@ -5429,7 +5430,8 @@ _CONSTEXPR20 void _Pop_heap_hole_unchecked(_RanIt _First, _RanIt _Last, _RanIt _ // precondition: _First != _Dest *_Dest = _STD move(*_First); using _Diff = _Iter_diff_t<_RanIt>; - _Pop_heap_hole_by_index(_First, static_cast<_Diff>(0), static_cast<_Diff>(_Last - _First), _STD move(_Val), _Pred); + _Pop_heap_hole_by_index( + _First, static_cast<_Diff>(0), static_cast<_Diff>(_Last - _First), _STD forward<_Ty>(_Val), _Pred); } template @@ -5458,12 +5460,14 @@ _CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last) { #ifdef __cpp_lib_concepts namespace ranges { // VARIABLE ranges::pop_heap - template + // clang-format off + template + requires sortable<_It, _Pr, _Pj1> && indirectly_writable<_It, _Ty> + && indirect_strict_weak_order<_Pr, projected<_It, _Pj1>, projected*, _Pj2>> constexpr void _Pop_heap_hole_by_index(_It _First, iter_difference_t<_It> _Hole, - const iter_difference_t<_It> _Bottom, iter_value_t<_It>&& _Val, _Pr _Pred, _Pj _Proj) { + const iter_difference_t<_It> _Bottom, _Ty&& _Val, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) { + // clang-format on // percolate _Hole to _Bottom, then push _Val - _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); - _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); _STL_INTERNAL_CHECK(_Hole >= 0); _STL_INTERNAL_CHECK(_Bottom > 0); @@ -5477,7 +5481,7 @@ namespace ranges { while (_Idx < _Max_sequence_non_leaf) { // move _Hole down to larger child _Idx = 2 * _Idx + 2; auto _Mid = _First + _Idx; - if (_STD invoke(_Pred, _STD invoke(_Proj, *_Mid), _STD invoke(_Proj, *_RANGES prev(_Mid)))) { + if (_STD invoke(_Pred, _STD invoke(_Proj1, *_Mid), _STD invoke(_Proj1, *_RANGES prev(_Mid)))) { --_Idx; --_Mid; } @@ -5490,36 +5494,38 @@ namespace ranges { _Hole = _Bottom - 1; } - _RANGES _Push_heap_by_index(_STD move(_First), _Hole, _Top, _STD move(_Val), _Pred, _Proj); + _RANGES _Push_heap_by_index(_STD move(_First), _Hole, _Top, _STD forward<_Ty>(_Val), _Pred, _Proj1, _Proj2); } - template + // clang-format off + template + requires sortable<_It, _Pr, _Pj1> && indirectly_writable<_It, _Ty> + && indirect_strict_weak_order<_Pr, projected<_It, _Pj1>, projected*, _Pj2>> constexpr void _Pop_heap_hole_unchecked( - _It _First, const _It _Last, const _It _Dest, iter_value_t<_It>&& _Val, _Pr _Pred, _Pj _Proj) { + _It _First, const _It _Last, const _It _Dest, _Ty&& _Val, _Pr _Pred, _Pj1 _Proj1, _Pj2 _Proj2) { + // clang-format on // pop *_First to *_Dest and reheap - _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); - _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); _STL_INTERNAL_CHECK(_First != _Last); _STL_INTERNAL_CHECK(_First != _Dest); *_Dest = _RANGES iter_move(_First); const auto _Count = _Last - _First; - _RANGES _Pop_heap_hole_by_index(_STD move(_First), 0, _Count, _STD move(_Val), _Pred, _Proj); + _RANGES _Pop_heap_hole_by_index(_STD move(_First), 0, _Count, _STD forward<_Ty>(_Val), _Pred, _Proj1, _Proj2); } - template + // clang-format off + template + requires sortable<_It, _Pr, _Pj> constexpr void _Pop_heap_unchecked(_It _First, _It _Last, _Pr _Pred, _Pj _Proj) { + // clang-format on // pop *_First to *(_Last - 1) and reheap - _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); - _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); - if (_Last - _First < 2) { return; } --_Last; iter_value_t<_It> _Val = _RANGES iter_move(_Last); - _RANGES _Pop_heap_hole_unchecked(_STD move(_First), _Last, _Last, _STD move(_Val), _Pred, _Proj); + _RANGES _Pop_heap_hole_unchecked(_STD move(_First), _Last, _Last, _STD move(_Val), _Pred, _Proj, _Proj); } class _Pop_heap_fn : private _Not_quite_object { @@ -5585,6 +5591,22 @@ _CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last) { // make [_First, _Las #ifdef __cpp_lib_concepts namespace ranges { // VARIABLE ranges::make_heap + // clang-format off + template + requires sortable<_It, _Pr, _Pj> + static 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 + using _Diff = iter_difference_t<_It>; + const _Diff _Bottom = _Last - _First; + for (_Diff _Hole = _Bottom >> 1; _Hole > 0;) { // shift for codegen + // reheap top half, bottom to top + --_Hole; + iter_value_t<_It> _Val = _RANGES iter_move(_First + _Hole); + _RANGES _Pop_heap_hole_by_index(_First, _Hole, _Bottom, _STD move(_Val), _Pred, _Proj, _Proj); + } + } + class _Make_heap_fn : private _Not_quite_object { public: using _Not_quite_object::_Not_quite_object; @@ -5597,7 +5619,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped(_STD move(_First)); auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last)); _Seek_wrapped(_First, _ULast); - _Make_heap_unchecked(_STD move(_UFirst), _STD move(_ULast), _Pass_fn(_Pred), _Pass_fn(_Proj)); + _Make_heap_common(_STD move(_UFirst), _STD move(_ULast), _Pass_fn(_Pred), _Pass_fn(_Proj)); return _First; } @@ -5605,31 +5627,15 @@ namespace ranges { requires sortable, _Pr, _Pj> constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const { if constexpr (common_range<_Rng>) { - _Make_heap_unchecked(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); + _Make_heap_common(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); return _RANGES end(_Range); } else { auto _ULast = _Get_final_iterator_unwrapped(_Range); - _Make_heap_unchecked(_Ubegin(_Range), _ULast, _Pass_fn(_Pred), _Pass_fn(_Proj)); + _Make_heap_common(_Ubegin(_Range), _ULast, _Pass_fn(_Pred), _Pass_fn(_Proj)); return _Rewrap_iterator(_Range, _STD move(_ULast)); } } // clang-format on - private: - template - static constexpr void _Make_heap_unchecked(_It _First, _It _Last, _Pr _Pred, _Pj _Proj) { - // make nontrivial [_First, _Last) into a heap - _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); - _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); - - using _Diff = iter_difference_t<_It>; - const _Diff _Bottom = _Last - _First; - for (_Diff _Hole = _Bottom >> 1; _Hole > 0;) { // shift for codegen - // reheap top half, bottom to top - --_Hole; - iter_value_t<_It> _Val = _RANGES iter_move(_First + _Hole); - _RANGES _Pop_heap_hole_by_index(_First, _Hole, _Bottom, _STD move(_Val), _Pred, _Proj); - } - } }; inline constexpr _Make_heap_fn make_heap{_Not_quite_object::_Construct_tag{}}; @@ -5818,6 +5824,17 @@ _CONSTEXPR20 void sort_heap(_RanIt _First, _RanIt _Last) { // order heap by repe #ifdef __cpp_lib_concepts namespace ranges { // VARIABLE ranges::sort_heap + template + static constexpr void _Sort_heap_common(const _It _First, _It _Last, _Pr _Pred, _Pj _Proj) { + // order heap by repeatedly popping + _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); + + for (; _Last - _First >= 2; --_Last) { + _RANGES _Pop_heap_unchecked(_First, _Last, _Pred, _Proj); + } + } + class _Sort_heap_fn : private _Not_quite_object { public: using _Not_quite_object::_Not_quite_object; @@ -5830,7 +5847,7 @@ namespace ranges { auto _UFirst = _Get_unwrapped(_STD move(_First)); auto _ULast = _Get_final_iterator_unwrapped<_It>(_UFirst, _STD move(_Last)); _Seek_wrapped(_First, _ULast); - _Sort_heap_unchecked(_STD move(_UFirst), _STD move(_ULast), _Pass_fn(_Pred), _Pass_fn(_Proj)); + _Sort_heap_common(_STD move(_UFirst), _STD move(_ULast), _Pass_fn(_Pred), _Pass_fn(_Proj)); return _First; } @@ -5838,26 +5855,15 @@ namespace ranges { requires sortable, _Pr, _Pj> constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const { if constexpr (common_range<_Rng>) { - _Sort_heap_unchecked(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); + _Sort_heap_common(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj)); return _RANGES end(_Range); } else { auto _ULast = _Get_final_iterator_unwrapped(_Range); - _Sort_heap_unchecked(_Ubegin(_Range), _ULast, _Pass_fn(_Pred), _Pass_fn(_Proj)); + _Sort_heap_common(_Ubegin(_Range), _ULast, _Pass_fn(_Pred), _Pass_fn(_Proj)); return _Rewrap_iterator(_Range, _STD move(_ULast)); } } // clang-format on - private: - template - static constexpr void _Sort_heap_unchecked(const _It _First, _It _Last, _Pr _Pred, _Pj _Proj) { - // order heap by repeatedly popping - _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); - _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); - - for (; _Last - _First >= 2; --_Last) { - _RANGES _Pop_heap_unchecked(_First, _Last, _Pred, _Proj); - } - } }; inline constexpr _Sort_heap_fn sort_heap{_Not_quite_object::_Construct_tag{}}; @@ -6963,8 +6969,8 @@ _CONSTEXPR20 _RanIt partial_sort_copy(_InIt _First1, _InIt _Last1, _RanIt _First if (_DEBUG_LT_PRED(_Pred, *_UFirst1, *_UFirst2)) { // replace top with new largest: using _Diff = _Iter_diff_t<_RanIt>; - _Pop_heap_hole_by_index(_UFirst2, static_cast<_Diff>(0), static_cast<_Diff>(_UMid2 - _UFirst2), - static_cast<_Iter_value_t<_InIt>>(*_UFirst1), _Pass_fn(_Pred)); + _Pop_heap_hole_by_index( + _UFirst2, static_cast<_Diff>(0), static_cast<_Diff>(_UMid2 - _UFirst2), *_UFirst1, _Pass_fn(_Pred)); } } diff --git a/tests/std/test.lst b/tests/std/test.lst index c30028652af..517e084b628 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -161,6 +161,7 @@ tests\GH_000685_condition_variable_any tests\GH_000690_overaligned_function tests\GH_000890_pow_template tests\GH_001010_filesystem_error_encoding +tests\GH_001086_partial_sort_copy tests\LWG2597_complex_branch_cut tests\LWG3018_shared_ptr_function tests\P0024R2_parallel_algorithms_adjacent_difference diff --git a/tests/std/tests/GH_001086_partial_sort_copy/env.lst b/tests/std/tests/GH_001086_partial_sort_copy/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_001086_partial_sort_copy/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_001086_partial_sort_copy/test.cpp b/tests/std/tests/GH_001086_partial_sort_copy/test.cpp new file mode 100644 index 00000000000..a91ce95c1b2 --- /dev/null +++ b/tests/std/tests/GH_001086_partial_sort_copy/test.cpp @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +// GH-1086: "std::partial_sort_copy performs an unconstrained operation" +// partial_sort_copy was constructing an object of the source range's value type +// from the result of dereferencing an iterator, which is not allowed by the +// specification of the algorithm. + +#include +#include + +using namespace std; + +struct wrapper { + wrapper() = default; + constexpr explicit wrapper(int i) : x{i} {} + + bool operator<(const wrapper& that) const { + return x < that.x; + } + + int x; +}; + +struct source : wrapper { + source() = default; + + using wrapper::wrapper; + + source(const source&) = delete; + source& operator=(const source&) = delete; +}; + +struct target : wrapper { + target() = default; + + using wrapper::wrapper; + + target(target&&) = default; + target& operator=(target&&) = default; + + target& operator=(const source& w) { + x = w.x; + return *this; + } +}; + +int main() { + source src[4]; + constexpr auto src_size = static_cast(std::size(src)); + target dst[2]; + constexpr auto dst_size = static_cast(std::size(dst)); + + for (int i = 0; i < src_size; ++i) { + src[i].x = src_size - 1 - i; + } + + partial_sort_copy(begin(src), end(src), begin(dst), end(dst)); + + for (int i = 0; i < dst_size; ++i) { + assert(dst[i].x == i); + } +} From f0f9857fe7ac27de44eab2a7780358603e3a873d Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Sat, 25 Jul 2020 20:22:26 -0700 Subject: [PATCH 2/4] STL's review comments --- stl/inc/algorithm | 8 ++++---- tests/std/tests/GH_001086_partial_sort_copy/test.cpp | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index dd367caf086..5f46db92f18 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -5824,12 +5824,12 @@ _CONSTEXPR20 void sort_heap(_RanIt _First, _RanIt _Last) { // order heap by repe #ifdef __cpp_lib_concepts namespace ranges { // VARIABLE ranges::sort_heap - template + // clang-format off + template + requires sortable<_It, _Pr, _Pj> static constexpr void _Sort_heap_common(const _It _First, _It _Last, _Pr _Pred, _Pj _Proj) { // order heap by repeatedly popping - _STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>); - _STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>); - + // clang-format on for (; _Last - _First >= 2; --_Last) { _RANGES _Pop_heap_unchecked(_First, _Last, _Pred, _Proj); } diff --git a/tests/std/tests/GH_001086_partial_sort_copy/test.cpp b/tests/std/tests/GH_001086_partial_sort_copy/test.cpp index a91ce95c1b2..d9b21673ba8 100644 --- a/tests/std/tests/GH_001086_partial_sort_copy/test.cpp +++ b/tests/std/tests/GH_001086_partial_sort_copy/test.cpp @@ -8,6 +8,7 @@ #include #include +#include using namespace std; @@ -46,10 +47,10 @@ struct target : wrapper { }; int main() { - source src[4]; - constexpr auto src_size = static_cast(std::size(src)); + constexpr int src_size = 4; + source src[src_size]; + constexpr int dst_size = 2; target dst[2]; - constexpr auto dst_size = static_cast(std::size(dst)); for (int i = 0; i < src_size; ++i) { src[i].x = src_size - 1 - i; From d67a7d00c607f3690c7863b27e66e0d52bc82c04 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Tue, 28 Jul 2020 06:52:29 -0700 Subject: [PATCH 3/4] Address final? review comments --- stl/inc/algorithm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 60a129ef1cd..469f12124de 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -5884,6 +5884,7 @@ namespace ranges { --_Last; iter_value_t<_It> _Val = _RANGES iter_move(_Last); + // NB: if _Proj is a _Ref_fn, this aliases the _Proj1 and _Proj2 parameters of _Push_heap_by_index _RANGES _Push_heap_by_index(_STD move(_First), _Count - 1, 0, _STD move(_Val), _Pred, _Proj, _Proj); } }; @@ -6025,6 +6026,7 @@ namespace ranges { --_Last; iter_value_t<_It> _Val = _RANGES iter_move(_Last); + // NB: if _Proj is a _Ref_fn, this aliases the _Proj1 and _Proj2 parameters of _Pop_heap_hole_unchecked _RANGES _Pop_heap_hole_unchecked(_STD move(_First), _Last, _Last, _STD move(_Val), _Pred, _Proj, _Proj); } @@ -6094,7 +6096,7 @@ namespace ranges { // clang-format off template requires sortable<_It, _Pr, _Pj> - static constexpr void _Make_heap_common(_It _First, _It _Last, _Pr _Pred, _Pj _Proj) { + 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 using _Diff = iter_difference_t<_It>; @@ -6103,6 +6105,7 @@ namespace ranges { // reheap top half, bottom to top --_Hole; iter_value_t<_It> _Val = _RANGES iter_move(_First + _Hole); + // NB: if _Proj is a _Ref_fn, this aliases the _Proj1 and _Proj2 parameters of _Pop_heap_hole_by_index _RANGES _Pop_heap_hole_by_index(_First, _Hole, _Bottom, _STD move(_Val), _Pred, _Proj, _Proj); } } @@ -6327,7 +6330,7 @@ namespace ranges { // clang-format off template requires sortable<_It, _Pr, _Pj> - static constexpr void _Sort_heap_common(const _It _First, _It _Last, _Pr _Pred, _Pj _Proj) { + constexpr void _Sort_heap_common(const _It _First, _It _Last, _Pr _Pred, _Pj _Proj) { // order heap by repeatedly popping // clang-format on for (; _Last - _First >= 2; --_Last) { From c1336c8fd2dae4350b535d6dca9adf7749e2ce21 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 29 Jul 2020 02:40:02 -0700 Subject: [PATCH 4/4] Use dst_size --- tests/std/tests/GH_001086_partial_sort_copy/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/GH_001086_partial_sort_copy/test.cpp b/tests/std/tests/GH_001086_partial_sort_copy/test.cpp index d9b21673ba8..fc5e54a56ed 100644 --- a/tests/std/tests/GH_001086_partial_sort_copy/test.cpp +++ b/tests/std/tests/GH_001086_partial_sort_copy/test.cpp @@ -50,7 +50,7 @@ int main() { constexpr int src_size = 4; source src[src_size]; constexpr int dst_size = 2; - target dst[2]; + target dst[dst_size]; for (int i = 0; i < src_size; ++i) { src[i].x = src_size - 1 - i;