Skip to content

Commit a54e31f

Browse files
committed
[libc++] Optimize heap operations
1 parent d291e45 commit a54e31f

File tree

6 files changed

+75
-67
lines changed

6 files changed

+75
-67
lines changed

libcxx/include/__algorithm/make_heap.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ __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) {
39-
std::__sift_down<_AlgPolicy>(__first, __comp_ref, __n, __first + __start);
40-
}
37+
difference_type __start = __n / 2;
38+
do {
39+
// start from the first parent, there is no need to consider children
40+
std::__sift_down<_AlgPolicy>(__first, __comp_ref, __n, --__start);
41+
} while (__start != 0);
4142
}
4243
}
4344

libcxx/include/__algorithm/partial_sort.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _RandomAccessIterator __part
4545
for (; __i != __last; ++__i) {
4646
if (__comp(*__i, *__first)) {
4747
_IterOps<_AlgPolicy>::iter_swap(__i, __first);
48-
std::__sift_down<_AlgPolicy>(__first, __comp, __len, __first);
48+
std::__sift_down<_AlgPolicy>(__first, __comp, __len, 0);
4949
}
5050
}
5151
std::__sort_heap<_AlgPolicy>(std::move(__first), std::move(__middle), __comp);

libcxx/include/__algorithm/partial_sort_copy.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InputIterator, _Random
6060
for (; __first != __last; ++__first)
6161
if (std::__invoke(__comp, std::__invoke(__proj1, *__first), std::__invoke(__proj2, *__result_first))) {
6262
*__result_first = *__first;
63-
std::__sift_down<_AlgPolicy>(__result_first, __projected_comp, __len, __result_first);
63+
std::__sift_down<_AlgPolicy>(__result_first, __projected_comp, __len, 0);
6464
}
6565
std::__sort_heap<_AlgPolicy>(__result_first, __r, __projected_comp);
6666
}

libcxx/include/__algorithm/pop_heap.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,8 @@ __pop_heap(_RandomAccessIterator __first,
5151
*__hole = std::move(__top);
5252
} else {
5353
*__hole = _IterOps<_AlgPolicy>::__iter_move(__last);
54-
++__hole;
5554
*__last = std::move(__top);
56-
std::__sift_up<_AlgPolicy>(__first, __hole, __comp_ref, __hole - __first);
55+
std::__sift_up<_AlgPolicy>(__first, __hole, __comp_ref);
5756
}
5857
}
5958
}

libcxx/include/__algorithm/push_heap.h

Lines changed: 23 additions & 25 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 __last, _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 = __last - __first;
37+
_LIBCPP_ASSERT_INTERNAL(__parent > 0, "shouldn't be called unless __last - __first > 0");
38+
__parent = (__parent - 1) / 2;
39+
_RandomAccessIterator __parent_i = __first + __parent;
40+
41+
if (__comp(*__parent_i, *__last)) {
42+
value_type __t(_IterOps<_AlgPolicy>::__iter_move(__last));
43+
do {
44+
*__last = _IterOps<_AlgPolicy>::__iter_move(__parent_i);
45+
__last = __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+
*__last = 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
6058
__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);
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/sift_down.h

Lines changed: 44 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,37 +29,39 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
2929
__sift_down(_RandomAccessIterator __first,
3030
_Compare&& __comp,
3131
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
32-
_RandomAccessIterator __start) {
32+
typename iterator_traits<_RandomAccessIterator>::difference_type __start) {
3333
using _Ops = _IterOps<_AlgPolicy>;
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;
45-
_RandomAccessIterator __child_i = __first + __child;
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;
44+
_RandomAccessIterator __child_i = __first + __child, __start_i = __first + __start;
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
54-
if (__comp(*__child_i, *__start))
56+
if (__comp(*__child_i, *__start_i))
5557
// we are, __start is larger than its largest child
5658
return;
5759

58-
value_type __top(_Ops::__iter_move(__start));
60+
value_type __top(_Ops::__iter_move(__start_i));
5961
do {
6062
// we are not in heap-order, swap the parent with its largest child
61-
*__start = _Ops::__iter_move(__child_i);
62-
__start = __child_i;
63+
*__start_i = _Ops::__iter_move(__child_i);
64+
__start_i = __child_i;
6365

6466
if ((__len - 2) / 2 < __child)
6567
break;
@@ -68,45 +70,53 @@ __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
7883
} while (!__comp(*__child_i, __top));
79-
*__start = std::move(__top);
84+
*__start_i = std::move(__top);
8085
}
8186

8287
template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
8388
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator __floyd_sift_down(
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)
110120
return __hole;
111121
}
112122
}

0 commit comments

Comments
 (0)