Skip to content

Commit bc3e007

Browse files
committed
[libc++] Optimize heap operations
1 parent 40fce32 commit bc3e007

File tree

7 files changed

+69
-69
lines changed

7 files changed

+69
-69
lines changed

libcxx/include/__algorithm/make_heap.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compar
4545
if (__n > 1) {
4646
// start from the first parent, there is no need to consider children
4747

48-
for (__diff_t __start = (__sift_down_n - 2) / 2; __start >= 0; --__start) {
49-
std::__sift_down<_AlgPolicy, __assume_both_children>(__first, __comp_ref, __sift_down_n, __start);
48+
for (__diff_t __start = __sift_down_n / 2; __start != 0;) {
49+
std::__sift_down<_AlgPolicy, __assume_both_children>(__first, __comp_ref, __sift_down_n, --__start);
5050
}
5151
if _LIBCPP_CONSTEXPR (__assume_both_children)
52-
std::__sift_up<_AlgPolicy>(__first, __last, __comp, __n);
52+
std::__sift_up<_AlgPolicy>(__first, --__last, __comp);
5353
}
5454
}
5555

libcxx/include/__algorithm/partial_sort_copy.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,17 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InputIterator, _Random
5252
_RandomAccessIterator __r = __result_first;
5353
auto&& __projected_comp = std::__make_projected(__comp, __proj2);
5454

55-
if (__r != __result_last) {
55+
if (__result_first != __result_last) {
5656
for (; __first != __last && __r != __result_last; ++__first, (void)++__r)
5757
*__r = *__first;
5858
std::__make_heap<_AlgPolicy>(__result_first, __r, __projected_comp);
5959
typename iterator_traits<_RandomAccessIterator>::difference_type __len = __r - __result_first;
60-
for (; __first != __last; ++__first)
60+
for (; __first != __last; ++__first) {
6161
if (std::__invoke(__comp, std::__invoke(__proj1, *__first), std::__invoke(__proj2, *__result_first))) {
6262
*__result_first = *__first;
6363
std::__sift_down<_AlgPolicy, false>(__result_first, __projected_comp, __len, 0);
6464
}
65+
}
6566
std::__sort_heap<_AlgPolicy>(__result_first, __r, __projected_comp);
6667
}
6768

libcxx/include/__algorithm/pop_heap.h

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,28 +33,20 @@ _LIBCPP_BEGIN_NAMESPACE_STD
3333
template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
3434
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
3535
__pop_heap(_RandomAccessIterator __first,
36-
_RandomAccessIterator __last,
37-
_Compare& __comp,
36+
_RandomAccessIterator __bottom,
37+
_Compare&& __comp,
3838
typename iterator_traits<_RandomAccessIterator>::difference_type __len) {
39-
// Calling `pop_heap` on an empty range is undefined behavior, but in practice it will be a no-op.
40-
_LIBCPP_ASSERT_PEDANTIC(__len > 0, "The heap given to pop_heap must be non-empty");
39+
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
4140

42-
__comp_ref_type<_Compare> __comp_ref = __comp;
41+
value_type __top = _IterOps<_AlgPolicy>::__iter_move(__first); // create a hole at __first
42+
_RandomAccessIterator __hole = std::__floyd_sift_down<_AlgPolicy>(__first, __comp, __len);
4343

44-
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
45-
if (__len > 1) {
46-
value_type __top = _IterOps<_AlgPolicy>::__iter_move(__first); // create a hole at __first
47-
_RandomAccessIterator __hole = std::__floyd_sift_down<_AlgPolicy>(__first, __comp_ref, __len);
48-
--__last;
49-
50-
if (__hole == __last) {
51-
*__hole = std::move(__top);
52-
} else {
53-
*__hole = _IterOps<_AlgPolicy>::__iter_move(__last);
54-
++__hole;
55-
*__last = std::move(__top);
56-
std::__sift_up<_AlgPolicy>(__first, __hole, __comp_ref, __hole - __first);
57-
}
44+
if (__hole == __bottom) {
45+
*__hole = std::move(__top);
46+
} else {
47+
*__hole = _IterOps<_AlgPolicy>::__iter_move(__bottom);
48+
*__bottom = std::move(__top);
49+
std::__sift_up<_AlgPolicy>(__first, __hole, __comp);
5850
}
5951
}
6052

@@ -65,7 +57,13 @@ pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare _
6557
static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable.");
6658

6759
typename iterator_traits<_RandomAccessIterator>::difference_type __len = __last - __first;
68-
std::__pop_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp, __len);
60+
61+
__comp_ref_type<_Compare> __comp_ref = __comp;
62+
63+
// Calling `pop_heap` on an empty range is undefined behavior, but in practice it will be a no-op.
64+
_LIBCPP_ASSERT_PEDANTIC(__len > 0, "The heap given to pop_heap must be non-empty");
65+
if (__len > 1)
66+
std::__pop_heap<_ClassicAlgPolicy>(std::move(__first), std::move(--__last), __comp_ref, __len);
6967
}
7068

7169
template <class _RandomAccessIterator>

libcxx/include/__algorithm/push_heap.h

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,37 +29,35 @@ _LIBCPP_BEGIN_NAMESPACE_STD
2929

3030
template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
3131
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
32-
__sift_up(_RandomAccessIterator __first,
33-
_RandomAccessIterator __last,
34-
_Compare&& __comp,
35-
typename iterator_traits<_RandomAccessIterator>::difference_type __len) {
36-
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
37-
38-
if (__len > 1) {
39-
__len = (__len - 2) / 2;
40-
_RandomAccessIterator __ptr = __first + __len;
41-
42-
if (__comp(*__ptr, *--__last)) {
43-
value_type __t(_IterOps<_AlgPolicy>::__iter_move(__last));
44-
do {
45-
*__last = _IterOps<_AlgPolicy>::__iter_move(__ptr);
46-
__last = __ptr;
47-
if (__len == 0)
48-
break;
49-
__len = (__len - 1) / 2;
50-
__ptr = __first + __len;
51-
} while (__comp(*__ptr, __t));
52-
53-
*__last = std::move(__t);
54-
}
32+
__sift_up(_RandomAccessIterator __first, _RandomAccessIterator __bottom, _Compare&& __comp) {
33+
using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
34+
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
35+
36+
difference_type __parent = __bottom - __first;
37+
_LIBCPP_ASSERT_INTERNAL(__parent > 0, "shouldn't be called unless __bottom - __first > 0");
38+
__parent = (__parent - 1) / 2;
39+
_RandomAccessIterator __parent_i = __first + __parent;
40+
41+
if (__comp(*__parent_i, *__bottom)) {
42+
value_type __t(_IterOps<_AlgPolicy>::__iter_move(__bottom));
43+
do {
44+
*__bottom = _IterOps<_AlgPolicy>::__iter_move(__parent_i);
45+
__bottom = __parent_i;
46+
if (__parent == 0)
47+
break;
48+
__parent = (__parent - 1) / 2;
49+
__parent_i = __first + __parent;
50+
} while (__comp(*__parent_i, __t));
51+
52+
*__bottom = std::move(__t);
5553
}
5654
}
5755

5856
template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
5957
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
60-
__push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
61-
typename iterator_traits<_RandomAccessIterator>::difference_type __len = __last - __first;
62-
std::__sift_up<_AlgPolicy, __comp_ref_type<_Compare> >(std::move(__first), std::move(__last), __comp, __len);
58+
__push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare&& __comp) {
59+
if (__first != __last)
60+
std::__sift_up<_AlgPolicy, __comp_ref_type<_Compare> >(std::move(__first), std::move(--__last), __comp);
6361
}
6462

6563
template <class _RandomAccessIterator, class _Compare>

libcxx/include/__algorithm/ranges_pop_heap.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ struct __pop_heap {
4848
auto __len = __last_iter - __first;
4949

5050
auto&& __projected_comp = std::__make_projected(__comp, __proj);
51-
std::__pop_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp, __len);
51+
52+
if (__len > 1)
53+
std::__pop_heap<_RangeAlgPolicy>(std::move(__first), ranges::prev(__last_iter), __projected_comp, __len);
5254

5355
return __last_iter;
5456
}

libcxx/include/__algorithm/sift_down.h

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ __sift_down(_RandomAccessIterator __first,
3838
// right-child of __start is at 2 * __start + 2
3939
difference_type __child = __start;
4040

41-
if (__len < 2 || (__len - 2) / 2 < __child)
41+
if (__len < 2)
4242
return;
4343

4444
__child = 2 * __child + 1;
@@ -62,7 +62,7 @@ __sift_down(_RandomAccessIterator __first,
6262
__first[__start] = _Ops::__iter_move(__first + __child);
6363
__start = __child;
6464

65-
if ((__len - 2) / 2 < __child)
65+
if (__len / 2 - 1 < __child)
6666
break;
6767

6868
// recompute the child based off of the updated parent
@@ -85,31 +85,32 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator __floy
8585
_RandomAccessIterator __first,
8686
_Compare&& __comp,
8787
typename iterator_traits<_RandomAccessIterator>::difference_type __len) {
88-
using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
89-
_LIBCPP_ASSERT_INTERNAL(__len >= 2, "shouldn't be called unless __len >= 2");
88+
_LIBCPP_ASSERT_INTERNAL(__len > 1, "shouldn't be called unless __len > 1");
9089

91-
_RandomAccessIterator __hole = __first;
92-
_RandomAccessIterator __child_i = __first;
93-
difference_type __child = 0;
90+
using _Ops = _IterOps<_AlgPolicy>;
9491

95-
while (true) {
96-
__child_i += difference_type(__child + 1);
97-
__child = 2 * __child + 1;
92+
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
93+
94+
difference_type __child = 1;
95+
_RandomAccessIterator __hole = __first, __child_i = __first;
9896

99-
if ((__child + 1) < __len && __comp(*__child_i, *(__child_i + difference_type(1)))) {
97+
do {
98+
__child_i += __child;
99+
__child *= 2;
100+
101+
if (__child < __len && __comp(*__child_i, *(__child_i + difference_type(1)))) {
100102
// right-child exists and is greater than left-child
101103
++__child_i;
102104
++__child;
103105
}
104106

105107
// swap __hole with its largest child
106-
*__hole = _IterOps<_AlgPolicy>::__iter_move(__child_i);
108+
*__hole = _Ops::__iter_move(__child_i);
107109
__hole = __child_i;
108110

109111
// if __hole is now a leaf, we're done
110-
if (__child > (__len - 2) / 2)
111-
return __hole;
112-
}
112+
} while (__child <= __len / 2);
113+
return __hole;
113114
}
114115

115116
_LIBCPP_END_NAMESPACE_STD

libcxx/include/__algorithm/sort_heap.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compar
3636
__comp_ref_type<_Compare> __comp_ref = __comp;
3737

3838
using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
39-
for (difference_type __n = __last - __first; __n > 1; --__last, (void)--__n)
40-
std::__pop_heap<_AlgPolicy>(__first, __last, __comp_ref, __n);
39+
for (difference_type __n = __last - __first; __n > 1; --__n)
40+
std::__pop_heap<_AlgPolicy>(__first, --__last, __comp_ref, __n);
4141
std::__check_strict_weak_ordering_sorted(__first, __saved_last, __comp_ref);
4242
}
4343

0 commit comments

Comments
 (0)