Skip to content

Commit 53ef8e0

Browse files
committed
[libc++] Optimize make_heap() and sift_down()
1 parent d291e45 commit 53ef8e0

File tree

2 files changed

+42
-30
lines changed

2 files changed

+42
-30
lines changed

libcxx/include/__algorithm/make_heap.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compar
3434
using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
3535
difference_type __n = __last - __first;
3636
if (__n > 1) {
37-
// start from the first parent, there is no need to consider children
38-
for (difference_type __start = (__n - 2) / 2; __start >= 0; --__start) {
37+
difference_type __start = __n / 2;
38+
do {
39+
// start from the first parent, there is no need to consider children
40+
--__start;
3941
std::__sift_down<_AlgPolicy>(__first, __comp_ref, __n, __first + __start);
40-
}
42+
} while (__start != 0);
4143
}
4244
}
4345

libcxx/include/__algorithm/sift_down.h

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,22 @@ __sift_down(_RandomAccessIterator __first,
3434

3535
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
3636
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
37-
// left-child of __start is at 2 * __start + 1
38-
// right-child of __start is at 2 * __start + 2
39-
difference_type __child = __start - __first;
4037

41-
if (__len < 2 || (__len - 2) / 2 < __child)
38+
if (__len < 2)
4239
return;
4340

44-
__child = 2 * __child + 1;
41+
// left-child of __start is at 2 * __start + 1
42+
// right-child of __start is at 2 * __start + 2
43+
difference_type __child = 2 * (__start - __first) + 1;
4544
_RandomAccessIterator __child_i = __first + __child;
4645

47-
if ((__child + 1) < __len && __comp(*__child_i, *(__child_i + difference_type(1)))) {
48-
// right-child exists and is greater than left-child
49-
++__child_i;
50-
++__child;
46+
if ((__child + 1) < __len) {
47+
_RandomAccessIterator __right_i = _Ops::next(__child_i);
48+
if (__comp(*__child_i, *__right_i)) {
49+
// right-child exists and is greater than left-child
50+
__child_i = __right_i;
51+
++__child;
52+
}
5153
}
5254

5355
// check if we are in heap-order
@@ -68,10 +70,13 @@ __sift_down(_RandomAccessIterator __first,
6870
__child = 2 * __child + 1;
6971
__child_i = __first + __child;
7072

71-
if ((__child + 1) < __len && __comp(*__child_i, *(__child_i + difference_type(1)))) {
72-
// right-child exists and is greater than left-child
73-
++__child_i;
74-
++__child;
73+
if ((__child + 1) < __len) {
74+
_RandomAccessIterator __right_i = _Ops::next(__child_i);
75+
if (__comp(*__child_i, *__right_i)) {
76+
// right-child exists and is greater than left-child
77+
__child_i = __right_i;
78+
++__child;
79+
}
7580
}
7681

7782
// check if we are in heap-order
@@ -84,29 +89,34 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator __floy
8489
_RandomAccessIterator __first,
8590
_Compare&& __comp,
8691
typename iterator_traits<_RandomAccessIterator>::difference_type __len) {
87-
using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
88-
_LIBCPP_ASSERT_INTERNAL(__len >= 2, "shouldn't be called unless __len >= 2");
92+
_LIBCPP_ASSERT_INTERNAL(__len > 1, "shouldn't be called unless __len > 1");
8993

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

94-
while (true) {
95-
__child_i += difference_type(__child + 1);
96-
__child = 2 * __child + 1;
96+
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
9797

98-
if ((__child + 1) < __len && __comp(*__child_i, *(__child_i + difference_type(1)))) {
99-
// right-child exists and is greater than left-child
100-
++__child_i;
101-
++__child;
98+
difference_type __child = 1;
99+
_RandomAccessIterator __hole = __first, __child_i = __first;
100+
101+
while (true) {
102+
__child_i += __child;
103+
__child *= 2;
104+
105+
if (__child < __len) {
106+
_RandomAccessIterator __right_i = _Ops::next(__child_i);
107+
if (__comp(*__child_i, *__right_i)) {
108+
// right-child exists and is greater than left-child
109+
__child_i = __right_i;
110+
++__child;
111+
}
102112
}
103113

104114
// swap __hole with its largest child
105-
*__hole = _IterOps<_AlgPolicy>::__iter_move(__child_i);
115+
*__hole = _Ops::__iter_move(__child_i);
106116
__hole = __child_i;
107117

108118
// if __hole is now a leaf, we're done
109-
if (__child > (__len - 2) / 2)
119+
if (__child > __len / 2 - 2)
110120
return __hole;
111121
}
112122
}

0 commit comments

Comments
 (0)