зеркало из https://github.com/microsoft/STL.git
Implement ranges heap algorithms (#930)
`ranges::is_heap`, `ranges::is_heap_until`, `ranges::make_heap`, `ranges::push_heap`, `ranges::pop_heap`, and `ranges::sort_heap`.
This commit is contained in:
Родитель
3d7fa78426
Коммит
585583b54c
|
@ -208,17 +208,70 @@ namespace ranges {
|
|||
|
||||
// FUNCTION TEMPLATE _Rewrap_subrange
|
||||
template <class _Result, class _Wrapped, class _Unwrapped>
|
||||
_NODISCARD constexpr _Result _Rewrap_subrange(_Wrapped& _First, subrange<_Unwrapped>&& _UResult) {
|
||||
// conditionally computes a wrapped subrange from a wrapped iterator and unwrapped subrange
|
||||
_STL_INTERNAL_STATIC_ASSERT(is_same_v<_Unwrapped_t<_Wrapped>, _Unwrapped>);
|
||||
_NODISCARD constexpr _Result _Rewrap_subrange(_Wrapped& _Val, subrange<_Unwrapped>&& _UResult) {
|
||||
// conditionally computes a wrapped subrange from a wrapped iterator or range and unwrapped subrange
|
||||
if constexpr (is_same_v<_Result, dangling>) {
|
||||
return dangling{};
|
||||
} else {
|
||||
_STL_INTERNAL_STATIC_ASSERT(is_same_v<_Result, subrange<_Wrapped>>);
|
||||
auto _Last = _First;
|
||||
_Seek_wrapped(_First, _UResult.begin());
|
||||
_Seek_wrapped(_Last, _UResult.end());
|
||||
} else if constexpr (is_same_v<_Result, subrange<_Unwrapped>>) {
|
||||
return _STD move(_UResult);
|
||||
} else if constexpr (range<_Wrapped>) {
|
||||
_STL_INTERNAL_STATIC_ASSERT(forward_range<_Wrapped>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(is_same_v<_Unwrapped, _Unwrapped_t<iterator_t<_Wrapped>>>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(is_same_v<_Result, subrange<iterator_t<_Wrapped>>>);
|
||||
|
||||
auto _First = _RANGES begin(_Val);
|
||||
auto _Last = _First;
|
||||
_First._Seek_to(_UResult.begin());
|
||||
_Last._Seek_to(_UResult.end());
|
||||
return _Result{_STD move(_First), _STD move(_Last)};
|
||||
} else {
|
||||
_STL_INTERNAL_STATIC_ASSERT(is_same_v<_Unwrapped, _Unwrapped_t<_Wrapped>>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(is_same_v<_Result, subrange<_Wrapped>>);
|
||||
|
||||
auto _Last = _Val;
|
||||
_Val._Seek_to(_UResult.begin());
|
||||
_Last._Seek_to(_UResult.end());
|
||||
return _Result{_STD move(_Val), _STD move(_Last)};
|
||||
}
|
||||
}
|
||||
|
||||
// FUNCTION TEMPLATE _Rewrap_iterator
|
||||
template <forward_range _Rng, class _It>
|
||||
_NODISCARD constexpr iterator_t<_Rng> _Rewrap_iterator(_Rng&& _Range, _It&& _Val) {
|
||||
_STL_INTERNAL_STATIC_ASSERT(is_same_v<remove_cvref_t<_It>, _Unwrapped_t<iterator_t<_Rng>>>);
|
||||
|
||||
if constexpr (is_same_v<remove_cvref_t<_It>, iterator_t<_Rng>>) {
|
||||
return _STD forward<_It>(_Val);
|
||||
} else {
|
||||
auto _Result = _RANGES begin(_Range);
|
||||
_Result._Seek_to(_STD forward<_It>(_Val));
|
||||
return _Result;
|
||||
}
|
||||
}
|
||||
|
||||
// FUNCTION TEMPLATE _Get_final_iterator_unwrapped
|
||||
template <forward_iterator _Wrapped, sentinel_for<_Wrapped> _Se>
|
||||
_NODISCARD constexpr auto _Get_final_iterator_unwrapped(const _Unwrapped_t<_Wrapped>& _UFirst, _Se&& _Last) {
|
||||
// find the iterator in [_UFirst, _Get_unwrapped(_Last)) which equals _Get_unwrapped(_Last) [possibly O(N)]
|
||||
auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
if constexpr (is_same_v<_Se, _Wrapped>) {
|
||||
return _ULast;
|
||||
} else if constexpr (sized_sentinel_for<_Se, _Wrapped>) {
|
||||
return _RANGES next(_UFirst, _ULast - _UFirst);
|
||||
} else {
|
||||
return _RANGES next(_UFirst, _STD move(_ULast));
|
||||
}
|
||||
}
|
||||
|
||||
template <forward_range _Rng>
|
||||
_NODISCARD constexpr auto _Get_final_iterator_unwrapped(_Rng& _Range) {
|
||||
// find the (unwrapped) iterator in _Range which equals _Uend(_Range) [possibly O(N)]
|
||||
if constexpr (common_range<_Rng>) {
|
||||
return _Uend(_Range);
|
||||
} else if constexpr (sized_range<_Rng>) {
|
||||
return _RANGES next(_Ubegin(_Range), _RANGES distance(_Range));
|
||||
} else {
|
||||
return _RANGES next(_Ubegin(_Range), _Uend(_Range));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1972,20 +2025,18 @@ namespace ranges {
|
|||
requires indirectly_comparable<iterator_t<_Rng1>, iterator_t<_Rng2>, _Pr, _Pj1, _Pj2>
|
||||
_NODISCARD constexpr borrowed_subrange_t<_Rng1> operator()(
|
||||
_Rng1&& _Range1, _Rng2&& _Range2, _Pr _Pred = {}, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const {
|
||||
auto _First1 = _RANGES begin(_Range1);
|
||||
|
||||
if constexpr (sized_range<_Rng1> && sized_range<_Rng2>) {
|
||||
const auto _Count1 = _RANGES distance(_Range1);
|
||||
const auto _Count2 = _RANGES distance(_Range2);
|
||||
auto _UResult = _Search_sized(_Get_unwrapped(_First1), _Uend(_Range1), _Count1,
|
||||
auto _UResult = _Search_sized(_Ubegin(_Range1), _Uend(_Range1), _Count1,
|
||||
_Ubegin(_Range2), _Uend(_Range2), _Count2,
|
||||
_Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
return _Rewrap_subrange<borrowed_subrange_t<_Rng1>>(_First1, _STD move(_UResult));
|
||||
return _Rewrap_subrange<borrowed_subrange_t<_Rng1>>(_Range1, _STD move(_UResult));
|
||||
} else {
|
||||
auto _UResult = _Search_unsized(_Get_unwrapped(_First1), _Uend(_Range1),
|
||||
auto _UResult = _Search_unsized(_Ubegin(_Range1), _Uend(_Range1),
|
||||
_Ubegin(_Range2), _Uend(_Range2),
|
||||
_Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
return _Rewrap_subrange<borrowed_subrange_t<_Rng1>>(_First1, _STD move(_UResult));
|
||||
return _Rewrap_subrange<borrowed_subrange_t<_Rng1>>(_Range1, _STD move(_UResult));
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
|
@ -2721,20 +2772,19 @@ namespace ranges {
|
|||
requires indirectly_comparable<iterator_t<_Rng1>, iterator_t<_Rng2>, _Pr, _Pj1, _Pj2>
|
||||
_NODISCARD constexpr borrowed_subrange_t<_Rng1> operator()(
|
||||
_Rng1&& _Range1, _Rng2&& _Range2, _Pr _Pred = {}, _Pj1 _Proj1 = {}, _Pj2 _Proj2 = {}) const {
|
||||
auto _First1 = _RANGES begin(_Range1);
|
||||
if constexpr (random_access_range<_Rng1> && sized_range<_Rng1>
|
||||
&& random_access_range<_Rng2> && sized_range<_Rng2>) {
|
||||
auto _UResult = _Random_access_sized_ranges(_Get_unwrapped(_First1), _RANGES distance(_Range1),
|
||||
auto _UResult = _Random_access_sized_ranges(_Ubegin(_Range1), _RANGES distance(_Range1),
|
||||
_Ubegin(_Range2), _RANGES distance(_Range2), _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
return _Rewrap_subrange<borrowed_subrange_t<_Rng1>>(_First1, _STD move(_UResult));
|
||||
return _Rewrap_subrange<borrowed_subrange_t<_Rng1>>(_Range1, _STD move(_UResult));
|
||||
} else if constexpr (_Bidi_common_range<_Rng1> && _Bidi_common_range<_Rng2>) {
|
||||
auto _UResult = _Bidi_common_ranges(_Get_unwrapped(_First1), _Uend(_Range1),
|
||||
auto _UResult = _Bidi_common_ranges(_Ubegin(_Range1), _Uend(_Range1),
|
||||
_Ubegin(_Range2), _Uend(_Range2), _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
return _Rewrap_subrange<borrowed_subrange_t<_Rng1>>(_First1, _STD move(_UResult));
|
||||
return _Rewrap_subrange<borrowed_subrange_t<_Rng1>>(_Range1, _STD move(_UResult));
|
||||
} else {
|
||||
auto _UResult = _Forward_ranges(_Get_unwrapped(_First1), _Uend(_Range1),
|
||||
auto _UResult = _Forward_ranges(_Ubegin(_Range1), _Uend(_Range1),
|
||||
_Ubegin(_Range2), _Uend(_Range2), _Pass_fn(_Pred), _Pass_fn(_Proj1), _Pass_fn(_Proj2));
|
||||
return _Rewrap_subrange<borrowed_subrange_t<_Rng1>>(_First1, _STD move(_UResult));
|
||||
return _Rewrap_subrange<borrowed_subrange_t<_Rng1>>(_Range1, _STD move(_UResult));
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
|
@ -4117,12 +4167,87 @@ _CONSTEXPR20 void push_heap(_RanIt _First, _RanIt _Last) {
|
|||
_STD push_heap(_First, _Last, less<>());
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::push_heap
|
||||
template <class _It, class _Pr, class _Pj>
|
||||
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) {
|
||||
// percolate _Hole to _Top or where _Val belongs, using _Pred and _Proj
|
||||
_STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>);
|
||||
|
||||
while (_Top < _Hole) {
|
||||
const auto _Idx = static_cast<iter_difference_t<_It>>((_Hole - 1) >> 1); // shift for codegen
|
||||
if (!_STD invoke(_Pred, _STD invoke(_Proj, *(_First + _Idx)), _STD invoke(_Proj, _Val))) {
|
||||
break;
|
||||
}
|
||||
|
||||
// move _Hole up to parent
|
||||
*(_First + _Hole) = _RANGES iter_move(_First + _Idx);
|
||||
_Hole = _Idx;
|
||||
}
|
||||
|
||||
*(_First + _Hole) = _STD move(_Val); // drop _Val into final hole
|
||||
}
|
||||
|
||||
class _Push_heap_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 {
|
||||
_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);
|
||||
_Push_heap_unchecked(_STD move(_UFirst), _STD move(_ULast), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _First;
|
||||
}
|
||||
|
||||
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 {
|
||||
if constexpr (common_range<_Rng>) {
|
||||
_Push_heap_unchecked(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _RANGES end(_Range);
|
||||
} else {
|
||||
auto _ULast = _Get_final_iterator_unwrapped(_Range);
|
||||
_Push_heap_unchecked(_Ubegin(_Range), _ULast, _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _Rewrap_iterator(_Range, _STD move(_ULast));
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
private:
|
||||
template <class _It, class _Pr, class _Pj>
|
||||
static constexpr void _Push_heap_unchecked(_It _First, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
_STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(sortable<_It, _Pr, _Pj>);
|
||||
|
||||
const auto _Count = _Last - _First;
|
||||
if (_Count < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
--_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);
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _Push_heap_fn push_heap{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATE pop_heap
|
||||
template <class _RanIt, class _Ty, class _Pr>
|
||||
_CONSTEXPR20 void _Pop_heap_hole_by_index(
|
||||
_RanIt _First, _Iter_diff_t<_RanIt> _Hole, _Iter_diff_t<_RanIt> _Bottom, _Ty&& _Val, _Pr _Pred) {
|
||||
// percolate _Hole to _Bottom, then push _Val, using _Pred
|
||||
_STL_INTERNAL_CHECK(_Bottom != 0);
|
||||
_STL_INTERNAL_CHECK(_Bottom > 0);
|
||||
|
||||
using _Diff = _Iter_diff_t<_RanIt>;
|
||||
const _Diff _Top = _Hole;
|
||||
_Diff _Idx = _Hole;
|
||||
|
@ -4180,13 +4305,115 @@ _CONSTEXPR20 void pop_heap(_RanIt _First, _RanIt _Last) {
|
|||
_STD pop_heap(_First, _Last, less<>());
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::pop_heap
|
||||
template <class _It, class _Pr, class _Pj>
|
||||
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) {
|
||||
// percolate _Hole to _Bottom, then push _Val, using _Pred and _Proj
|
||||
_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);
|
||||
|
||||
using _Diff = iter_difference_t<_It>;
|
||||
const _Diff _Top = _Hole;
|
||||
_Diff _Idx = _Hole;
|
||||
|
||||
// Check whether _Idx can have a child before calculating that child's index, since
|
||||
// calculating the child's index can trigger integer overflows
|
||||
const _Diff _Max_sequence_non_leaf = (_Bottom - 1) >> 1; // shift for codegen
|
||||
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)))) {
|
||||
--_Idx;
|
||||
--_Mid;
|
||||
}
|
||||
*(_First + _Hole) = _RANGES iter_move(_Mid);
|
||||
_Hole = _Idx;
|
||||
}
|
||||
|
||||
if (_Idx == _Max_sequence_non_leaf && _Bottom % 2 == 0) { // only child at bottom, move _Hole down to it
|
||||
*(_First + _Hole) = _RANGES iter_move(_First + (_Bottom - 1));
|
||||
_Hole = _Bottom - 1;
|
||||
}
|
||||
|
||||
_RANGES _Push_heap_by_index(_STD move(_First), _Hole, _Top, _STD move(_Val), _Pred, _Proj);
|
||||
}
|
||||
|
||||
template <class _It, class _Pr, class _Pj>
|
||||
constexpr void _Pop_heap_hole_unchecked(
|
||||
_It _First, const _It _Last, const _It _Dest, iter_value_t<_It>&& _Val, _Pr _Pred, _Pj _Proj) {
|
||||
// pop *_First to *_Dest and reheap, using _Pred and _Proj
|
||||
_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);
|
||||
}
|
||||
|
||||
template <class _It, class _Pr, class _Pj>
|
||||
constexpr void _Pop_heap_unchecked(_It _First, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
// pop *_First to *(_Last - 1) and reheap, using _Pred and _Proj
|
||||
_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);
|
||||
}
|
||||
|
||||
class _Pop_heap_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 {
|
||||
_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);
|
||||
_RANGES _Pop_heap_unchecked(_STD move(_UFirst), _STD move(_ULast), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _First;
|
||||
}
|
||||
|
||||
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 {
|
||||
if constexpr (common_range<_Rng>) {
|
||||
_RANGES _Pop_heap_unchecked(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _RANGES end(_Range);
|
||||
} else {
|
||||
auto _ULast = _Get_final_iterator_unwrapped(_Range);
|
||||
_RANGES _Pop_heap_unchecked(_Ubegin(_Range), _ULast, _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _Rewrap_iterator(_Range, _STD move(_ULast));
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
inline constexpr _Pop_heap_fn pop_heap{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// 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, using _Pred
|
||||
using _Diff = _Iter_diff_t<_RanIt>;
|
||||
_Diff _Bottom = _Last - _First;
|
||||
for (_Diff _Hole = _Bottom >> 1; 0 < _Hole;) { // shift for codegen
|
||||
for (_Diff _Hole = _Bottom >> 1; _Hole > 0;) { // shift for codegen
|
||||
// reheap top half, bottom to top
|
||||
--_Hole;
|
||||
_Iter_value_t<_RanIt> _Val = _STD move(*(_First + _Hole));
|
||||
|
@ -4205,6 +4432,60 @@ _CONSTEXPR20 void make_heap(_RanIt _First, _RanIt _Last) { // make [_First, _Las
|
|||
_STD make_heap(_First, _Last, less<>());
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::make_heap
|
||||
class _Make_heap_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 {
|
||||
_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);
|
||||
_Make_heap_unchecked(_STD move(_UFirst), _STD move(_ULast), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _First;
|
||||
}
|
||||
|
||||
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 {
|
||||
if constexpr (common_range<_Rng>) {
|
||||
_Make_heap_unchecked(_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));
|
||||
return _Rewrap_iterator(_Range, _STD move(_ULast));
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
private:
|
||||
template <class _It, class _Pr, class _Pj>
|
||||
static constexpr void _Make_heap_unchecked(_It _First, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
// make nontrivial [_First, _Last) into a heap, using _Pred and _Proj
|
||||
_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{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
|
||||
// FUNCTION TEMPLATES is_heap AND is_heap_until
|
||||
template <class _RanIt, class _Pr>
|
||||
_CONSTEXPR20 _RanIt _Is_heap_until_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) {
|
||||
|
@ -4269,13 +4550,98 @@ _NODISCARD bool is_heap(_ExPo&& _Exec, _RanIt _First, _RanIt _Last) noexcept /*
|
|||
// test if range is a heap ordered by operator<
|
||||
return _STD is_heap(_STD forward<_ExPo>(_Exec), _First, _Last, less{});
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::is_heap
|
||||
template <class _It, class _Pr, class _Pj>
|
||||
_NODISCARD constexpr _It _Is_heap_until_unchecked(
|
||||
_It _First, const iter_difference_t<_It> _Size, _Pr _Pred, _Pj _Proj) {
|
||||
// find extent of counted range that is a heap ordered with respect to _Pred and _Proj
|
||||
_STL_INTERNAL_STATIC_ASSERT(random_access_iterator<_It>);
|
||||
_STL_INTERNAL_STATIC_ASSERT(indirect_strict_weak_order<_Pr, projected<_It, _Pj>>);
|
||||
|
||||
if (_Size == 0) {
|
||||
return _First;
|
||||
}
|
||||
|
||||
using _Diff = iter_difference_t<_It>;
|
||||
_Diff _Off = 1;
|
||||
for (; _Off < _Size; ++_Off) {
|
||||
const auto _Mid1 = _First + static_cast<_Diff>((_Off - 1) >> 1); // shift for codegen
|
||||
auto _Mid2 = _First + _Off;
|
||||
if (_STD invoke(_Pred, _STD invoke(_Proj, *_Mid1), _STD invoke(_Proj, *_Mid2))) {
|
||||
return _Mid2;
|
||||
}
|
||||
}
|
||||
|
||||
return _First + _Off;
|
||||
}
|
||||
|
||||
class _Is_heap_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
template <random_access_iterator _It, sentinel_for<_It> _Se, class _Pj = identity,
|
||||
indirect_strict_weak_order<projected<_It, _Pj>> _Pr = ranges::less>
|
||||
_NODISCARD constexpr bool operator()(_It _First, _Se _Last, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
||||
const auto _Size = _RANGES distance(_UFirst, _ULast);
|
||||
const auto _UResult =
|
||||
_RANGES _Is_heap_until_unchecked(_STD move(_UFirst), _Size, _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _UResult == _ULast;
|
||||
}
|
||||
|
||||
template <random_access_range _Rng, class _Pj = identity,
|
||||
indirect_strict_weak_order<projected<iterator_t<_Rng>, _Pj>> _Pr = ranges::less>
|
||||
_NODISCARD constexpr bool operator()(_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
const auto _Size = _RANGES distance(_Range);
|
||||
const auto _UResult =
|
||||
_RANGES _Is_heap_until_unchecked(_Ubegin(_Range), _Size, _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _UResult == _Uend(_Range);
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _Is_heap_fn is_heap{_Not_quite_object::_Construct_tag{}};
|
||||
|
||||
// VARIABLE ranges::is_heap_until
|
||||
class _Is_heap_until_fn : private _Not_quite_object {
|
||||
public:
|
||||
using _Not_quite_object::_Not_quite_object;
|
||||
|
||||
template <random_access_iterator _It, sentinel_for<_It> _Se, class _Pj = identity,
|
||||
indirect_strict_weak_order<projected<_It, _Pj>> _Pr = ranges::less>
|
||||
_NODISCARD constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
_Adl_verify_range(_First, _Last);
|
||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
||||
const auto _Size = _RANGES distance(_UFirst, _Get_unwrapped(_STD move(_Last)));
|
||||
auto _UResult =
|
||||
_RANGES _Is_heap_until_unchecked(_STD move(_UFirst), _Size, _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
_Seek_wrapped(_First, _STD move(_UResult));
|
||||
return _First;
|
||||
}
|
||||
|
||||
template <random_access_range _Rng, class _Pj = identity,
|
||||
indirect_strict_weak_order<projected<iterator_t<_Rng>, _Pj>> _Pr = ranges::less>
|
||||
_NODISCARD constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred = {}, _Pj _Proj = {}) const {
|
||||
const auto _Size = _RANGES distance(_Range);
|
||||
auto _UResult = _RANGES _Is_heap_until_unchecked(_Ubegin(_Range), _Size, _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _Rewrap_iterator(_Range, _STD move(_UResult));
|
||||
}
|
||||
};
|
||||
|
||||
inline constexpr _Is_heap_until_fn is_heap_until{_Not_quite_object::_Construct_tag{}};
|
||||
} // namespace ranges
|
||||
#endif // __cpp_lib_concepts
|
||||
#endif // _HAS_CXX17
|
||||
|
||||
// FUNCTION TEMPLATE sort_heap
|
||||
template <class _RanIt, class _Pr>
|
||||
_CONSTEXPR20 void _Sort_heap_unchecked(_RanIt _First, _RanIt _Last, _Pr _Pred) {
|
||||
// order heap by repeatedly popping, using _Pred
|
||||
for (; 2 <= _Last - _First; --_Last) {
|
||||
for (; _Last - _First >= 2; --_Last) {
|
||||
_Pop_heap_unchecked(_First, _Last, _Pred);
|
||||
}
|
||||
}
|
||||
|
@ -4301,6 +4667,51 @@ _CONSTEXPR20 void sort_heap(_RanIt _First, _RanIt _Last) { // order heap by repe
|
|||
|
||||
#ifdef __cpp_lib_concepts
|
||||
namespace ranges {
|
||||
// VARIABLE ranges::sort_heap
|
||||
class _Sort_heap_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 {
|
||||
_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);
|
||||
_Sort_heap_unchecked(_STD move(_UFirst), _STD move(_ULast), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||
return _First;
|
||||
}
|
||||
|
||||
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 {
|
||||
if constexpr (common_range<_Rng>) {
|
||||
_Sort_heap_unchecked(_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));
|
||||
return _Rewrap_iterator(_Range, _STD move(_ULast));
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
private:
|
||||
template <class _It, class _Pr, class _Pj>
|
||||
static constexpr void _Sort_heap_unchecked(const _It _First, _It _Last, _Pr _Pred, _Pj _Proj) {
|
||||
// order heap by repeatedly popping, using _Pred and _Proj
|
||||
_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{}};
|
||||
|
||||
// VARIABLE ranges::lower_bound
|
||||
template <class _It, class _Ty, class _Pr, class _Pj>
|
||||
_NODISCARD constexpr _It _Lower_bound_unchecked(
|
||||
|
|
|
@ -193,8 +193,7 @@ private:
|
|||
}
|
||||
|
||||
if (_Off < 0) {
|
||||
#pragma warning(suppress : 4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
_STL_VERIFY(_Idx >= -static_cast<size_t>(_Off), "cannot seek array iterator before begin");
|
||||
_STL_VERIFY(_Idx >= size_t{0} - static_cast<size_t>(_Off), "cannot seek array iterator before begin");
|
||||
}
|
||||
|
||||
if (_Off > 0) {
|
||||
|
@ -204,7 +203,7 @@ private:
|
|||
|
||||
_CONSTEXPR17 _Array_const_iterator& operator+=(const ptrdiff_t _Off) noexcept {
|
||||
_Verify_offset(_Off);
|
||||
_Idx += _Off;
|
||||
_Idx += static_cast<size_t>(_Off);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
|
@ -582,8 +582,8 @@ public:
|
|||
}
|
||||
|
||||
if (_Off < 0) {
|
||||
#pragma warning(suppress : 4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
_STL_VERIFY(_Myindex >= -static_cast<size_t>(_Off), "cannot seek checked_array_iterator before begin");
|
||||
_STL_VERIFY(
|
||||
_Myindex >= size_t{0} - static_cast<size_t>(_Off), "cannot seek checked_array_iterator before begin");
|
||||
}
|
||||
|
||||
if (_Off > 0) {
|
||||
|
@ -619,9 +619,8 @@ public:
|
|||
}
|
||||
|
||||
if (_Off < 0) {
|
||||
#pragma warning(suppress : 4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
_STL_VERIFY(
|
||||
_Mysize - _Myindex >= -static_cast<size_t>(_Off), "cannot seek checked_array_iterator after end");
|
||||
_STL_VERIFY(_Mysize - _Myindex >= size_t{0} - static_cast<size_t>(_Off),
|
||||
"cannot seek checked_array_iterator after end");
|
||||
}
|
||||
|
||||
_Myindex -= _Off;
|
||||
|
@ -681,9 +680,8 @@ public:
|
|||
|
||||
constexpr void _Verify_offset(const difference_type _Off) const noexcept {
|
||||
if (_Off < 0) {
|
||||
#pragma warning(suppress : 4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
_STL_VERIFY(
|
||||
_Myindex >= -static_cast<size_t>(_Off), "cannot seek checked_array_iterator iterator before begin");
|
||||
_STL_VERIFY(_Myindex >= size_t{0} - static_cast<size_t>(_Off),
|
||||
"cannot seek checked_array_iterator iterator before begin");
|
||||
}
|
||||
|
||||
if (_Off > 0) {
|
||||
|
|
|
@ -1033,8 +1033,8 @@ public:
|
|||
}
|
||||
|
||||
if (_Off < 0) {
|
||||
#pragma warning(suppress : 4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
_STL_VERIFY(_Myoff >= -static_cast<size_t>(_Off), "cannot seek string_view iterator before begin");
|
||||
_STL_VERIFY(
|
||||
_Myoff >= size_t{0} - static_cast<size_t>(_Off), "cannot seek string_view iterator before begin");
|
||||
}
|
||||
|
||||
if (_Off > 0) {
|
||||
|
@ -1073,8 +1073,8 @@ public:
|
|||
}
|
||||
|
||||
if (_Off < 0) {
|
||||
#pragma warning(suppress : 4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
_STL_VERIFY(_Mysize - _Myoff >= -static_cast<size_t>(_Off), "cannot seek string_view iterator after end");
|
||||
_STL_VERIFY(_Mysize - _Myoff >= size_t{0} - static_cast<size_t>(_Off),
|
||||
"cannot seek string_view iterator after end");
|
||||
}
|
||||
|
||||
_Myoff -= _Off;
|
||||
|
@ -1903,7 +1903,6 @@ public:
|
|||
const auto _Rawptr = _Unfancy(_Ptr);
|
||||
|
||||
if (_Off < 0) {
|
||||
#pragma warning(suppress : 4146) // unary minus operator applied to unsigned type, result still unsigned
|
||||
_STL_VERIFY(_Contptr - _Rawptr <= _Off, "cannot seek string iterator before begin");
|
||||
}
|
||||
|
||||
|
|
|
@ -254,6 +254,7 @@ tests\P0896R4_ranges_alg_find_if
|
|||
tests\P0896R4_ranges_alg_find_if_not
|
||||
tests\P0896R4_ranges_alg_for_each
|
||||
tests\P0896R4_ranges_alg_for_each_n
|
||||
tests\P0896R4_ranges_alg_heap
|
||||
tests\P0896R4_ranges_alg_is_permutation
|
||||
tests\P0896R4_ranges_alg_is_sorted
|
||||
tests\P0896R4_ranges_alg_minmax
|
||||
|
|
|
@ -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,219 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
// Covers ranges::push_heap, ranges::pop_heap, ranges::make_heap, ranges::is_heap, ranges::is_heap_until, and
|
||||
// ranges::sort_heap
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
#include <ranges>
|
||||
#include <utility>
|
||||
|
||||
#include <range_algorithm_support.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define ASSERT(...) assert((__VA_ARGS__))
|
||||
|
||||
// Validate dangling story
|
||||
STATIC_ASSERT(same_as<decltype(ranges::push_heap(borrowed<false>{})), ranges::dangling>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::push_heap(borrowed<true>{})), int*>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::pop_heap(borrowed<false>{})), ranges::dangling>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::pop_heap(borrowed<true>{})), int*>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::make_heap(borrowed<false>{})), ranges::dangling>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::make_heap(borrowed<true>{})), int*>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::sort_heap(borrowed<false>{})), ranges::dangling>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::sort_heap(borrowed<true>{})), int*>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::is_heap_until(borrowed<false>{})), ranges::dangling>);
|
||||
STATIC_ASSERT(same_as<decltype(ranges::is_heap_until(borrowed<true>{})), int*>);
|
||||
|
||||
using P = pair<int, int>;
|
||||
|
||||
struct empty_ranges {
|
||||
template <ranges::random_access_range Range>
|
||||
static constexpr void call() {
|
||||
// Validate empty ranges (only make_heap and sort_heap accept empty ranges)
|
||||
const Range range{};
|
||||
|
||||
ASSERT(ranges::make_heap(range, ranges::less{}, get_first) == ranges::end(range));
|
||||
ASSERT(ranges::make_heap(ranges::begin(range), ranges::end(range), ranges::less{}, get_first)
|
||||
== ranges::end(range));
|
||||
|
||||
ASSERT(ranges::sort_heap(range, ranges::less{}, get_first) == ranges::end(range));
|
||||
ASSERT(ranges::sort_heap(ranges::begin(range), ranges::end(range), ranges::less{}, get_first)
|
||||
== ranges::end(range));
|
||||
}
|
||||
};
|
||||
|
||||
struct is_heap_test {
|
||||
template <ranges::random_access_range Range>
|
||||
static constexpr void call() {
|
||||
// Validate is_heap and is_heap_until
|
||||
using ranges::is_heap, ranges::is_heap_until, ranges::less, ranges::swap;
|
||||
|
||||
array buff = {
|
||||
P{1668617627, 0},
|
||||
P{1429106719, 1},
|
||||
P{-47163201, 2},
|
||||
P{-441494788, 3},
|
||||
P{-1200257975, 4},
|
||||
P{-1459960308, 5},
|
||||
P{-912489821, 6},
|
||||
P{-2095681771, 7},
|
||||
P{-1298559576, 8},
|
||||
P{-1260655766, 9},
|
||||
};
|
||||
const Range wrapped{buff};
|
||||
|
||||
ASSERT(is_heap(wrapped, less{}, get_first));
|
||||
ASSERT(is_heap(wrapped.begin(), wrapped.end(), less{}, get_first));
|
||||
|
||||
ASSERT(is_heap_until(wrapped, less{}, get_first) == wrapped.end());
|
||||
ASSERT(is_heap_until(wrapped.begin(), wrapped.end(), less{}, get_first) == wrapped.end());
|
||||
|
||||
swap(buff[0], buff[1]);
|
||||
|
||||
ASSERT(!is_heap(wrapped, less{}, get_first));
|
||||
ASSERT(!is_heap(wrapped.begin(), wrapped.end(), less{}, get_first));
|
||||
|
||||
ASSERT(is_heap_until(wrapped, less{}, get_first) == wrapped.begin() + 1);
|
||||
ASSERT(is_heap_until(wrapped.begin(), wrapped.end(), less{}, get_first) == wrapped.begin() + 1);
|
||||
}
|
||||
};
|
||||
|
||||
struct make_and_sort_heap_test {
|
||||
static constexpr array initial_values = {
|
||||
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 Range>
|
||||
static constexpr void call() {
|
||||
// Validate make_heap and sort_heap
|
||||
using ranges::make_heap, ranges::sort_heap, ranges::is_heap, ranges::is_sorted, ranges::less, ranges::swap;
|
||||
|
||||
{
|
||||
auto buff = initial_values;
|
||||
const Range wrapped{buff};
|
||||
|
||||
ASSERT(!is_heap(wrapped, less{}, get_first));
|
||||
|
||||
make_heap(wrapped, less{}, get_first);
|
||||
ASSERT(is_heap(wrapped, less{}, get_first));
|
||||
|
||||
sort_heap(wrapped, less{}, get_first);
|
||||
ASSERT(is_sorted(wrapped, less{}, get_first));
|
||||
}
|
||||
|
||||
{
|
||||
auto buff = initial_values;
|
||||
const Range wrapped{buff};
|
||||
|
||||
ASSERT(!is_heap(wrapped.begin(), wrapped.end(), less{}, get_first));
|
||||
|
||||
make_heap(wrapped.begin(), wrapped.end(), less{}, get_first);
|
||||
ASSERT(is_heap(wrapped.begin(), wrapped.end(), less{}, get_first));
|
||||
|
||||
sort_heap(wrapped.begin(), wrapped.end(), less{}, get_first);
|
||||
ASSERT(is_sorted(wrapped.begin(), wrapped.end(), less{}, get_first));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct push_and_pop_heap_test {
|
||||
static constexpr array initial_values = {
|
||||
P{1668617627, 0},
|
||||
P{1429106719, 1},
|
||||
P{-47163201, 2},
|
||||
P{-441494788, 3},
|
||||
P{-1200257975, 4},
|
||||
P{-1459960308, 5},
|
||||
P{-912489821, 6},
|
||||
P{-2095681771, 7},
|
||||
P{-1298559576, 8},
|
||||
P{-1260655766, 9},
|
||||
};
|
||||
STATIC_ASSERT(ranges::is_heap(initial_values, ranges::less{}, get_first));
|
||||
|
||||
static constexpr array expectedPushed = {
|
||||
P{1668617627, 0},
|
||||
P{1429106719, 1},
|
||||
P{-47163201, 2},
|
||||
P{-1260655766, 9},
|
||||
P{-441494788, 3},
|
||||
P{-1459960308, 5},
|
||||
P{-912489821, 6},
|
||||
P{-2095681771, 7},
|
||||
P{-1298559576, 8},
|
||||
P{-1200257975, 4},
|
||||
};
|
||||
STATIC_ASSERT(ranges::is_heap(expectedPushed, ranges::less{}, get_first));
|
||||
|
||||
static constexpr array expectedPopped = {
|
||||
P{1429106719, 1},
|
||||
P{-441494788, 3},
|
||||
P{-47163201, 2},
|
||||
P{-1260655766, 9},
|
||||
P{-1200257975, 4},
|
||||
P{-1459960308, 5},
|
||||
P{-912489821, 6},
|
||||
P{-2095681771, 7},
|
||||
P{-1298559576, 8},
|
||||
P{1668617627, 0},
|
||||
};
|
||||
STATIC_ASSERT(ranges::is_heap(expectedPopped.begin(), expectedPopped.end() - 1, ranges::less{}, get_first));
|
||||
|
||||
template <ranges::random_access_range Range>
|
||||
static constexpr void call() {
|
||||
// Validate push_heap and pop_heap
|
||||
using ranges::push_heap, ranges::pop_heap, ranges::equal, ranges::is_heap, ranges::less;
|
||||
|
||||
{
|
||||
auto buff = initial_values;
|
||||
const Range wrapped{buff};
|
||||
|
||||
pop_heap(wrapped, less{}, get_first);
|
||||
ASSERT(equal(wrapped, expectedPopped));
|
||||
|
||||
push_heap(wrapped, less{}, get_first);
|
||||
ASSERT(equal(wrapped, expectedPushed));
|
||||
}
|
||||
|
||||
{
|
||||
auto buff = initial_values;
|
||||
const Range wrapped{buff};
|
||||
|
||||
pop_heap(wrapped.begin(), wrapped.end(), less{}, get_first);
|
||||
ASSERT(is_heap(expectedPopped.begin(), expectedPopped.end() - 1, less{}, get_first));
|
||||
ASSERT(equal(wrapped.begin(), wrapped.end(), expectedPopped.begin(), expectedPopped.end()));
|
||||
|
||||
push_heap(wrapped.begin(), wrapped.end(), less{}, get_first);
|
||||
ASSERT(is_heap(expectedPushed, less{}, get_first));
|
||||
ASSERT(equal(wrapped.begin(), wrapped.end(), expectedPushed.begin(), expectedPushed.end()));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
STATIC_ASSERT((test_random<empty_ranges, P>(), true));
|
||||
test_random<empty_ranges, P>();
|
||||
|
||||
STATIC_ASSERT((test_random<is_heap_test, P>(), true));
|
||||
test_random<is_heap_test, P>();
|
||||
|
||||
STATIC_ASSERT((test_random<make_and_sort_heap_test, P>(), true));
|
||||
test_random<make_and_sort_heap_test, P>();
|
||||
|
||||
STATIC_ASSERT((test_random<push_and_pop_heap_test, P>(), true));
|
||||
test_random<push_and_pop_heap_test, P>();
|
||||
}
|
Загрузка…
Ссылка в новой задаче