Skip to content

Commit c945bd0

Browse files
committed
[libc++][ranges] Implement modifying heap algorithms:
- `ranges::make_heap`; - `ranges::push_heap`; - `ranges::pop_heap`; - `ranges::sort_heap`. Differential Revision: https://reviews.llvm.org/D128115
1 parent 474c873 commit c945bd0

28 files changed

+1654
-128
lines changed

libcxx/benchmarks/CMakeLists.txt

+5
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,12 @@ set(BENCHMARK_TESTS
166166
algorithms/min_max_element.bench.cpp
167167
algorithms/pop_heap.bench.cpp
168168
algorithms/push_heap.bench.cpp
169+
algorithms/ranges_make_heap.bench.cpp
170+
algorithms/ranges_make_heap_then_sort_heap.bench.cpp
171+
algorithms/ranges_pop_heap.bench.cpp
172+
algorithms/ranges_push_heap.bench.cpp
169173
algorithms/ranges_sort.bench.cpp
174+
algorithms/ranges_sort_heap.bench.cpp
170175
algorithms/ranges_stable_sort.bench.cpp
171176
algorithms/sort.bench.cpp
172177
algorithms/sort_heap.bench.cpp
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include <algorithm>
10+
11+
#include "common.h"
12+
13+
namespace {
14+
template <class ValueType, class Order>
15+
struct RangesMakeHeap {
16+
size_t Quantity;
17+
18+
void run(benchmark::State& state) const {
19+
runOpOnCopies<ValueType>(
20+
state, Quantity, Order(), BatchSize::CountElements,
21+
[](auto& Copy) { std::ranges::make_heap(Copy); });
22+
}
23+
24+
std::string name() const {
25+
return "BM_RangesMakeHeap" + ValueType::name() + Order::name() + "_" +
26+
std::to_string(Quantity);
27+
};
28+
};
29+
} // namespace
30+
31+
int main(int argc, char** argv) {
32+
benchmark::Initialize(&argc, argv);
33+
if (benchmark::ReportUnrecognizedArguments(argc, argv))
34+
return 1;
35+
makeCartesianProductBenchmark<RangesMakeHeap, AllValueTypes, AllOrders>(Quantities);
36+
benchmark::RunSpecifiedBenchmarks();
37+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include <algorithm>
10+
11+
#include "common.h"
12+
13+
namespace {
14+
template <class ValueType, class Order>
15+
struct RangesMakeThenSortHeap {
16+
size_t Quantity;
17+
18+
void run(benchmark::State& state) const {
19+
runOpOnCopies<ValueType>(state, Quantity, Order(), BatchSize::CountElements,
20+
[](auto& Copy) {
21+
std::ranges::make_heap(Copy);
22+
std::ranges::sort_heap(Copy);
23+
});
24+
}
25+
26+
std::string name() const {
27+
return "BM_RangesMakeThenSortHeap" + ValueType::name() + Order::name() + "_" +
28+
std::to_string(Quantity);
29+
};
30+
};
31+
} // namespace
32+
33+
int main(int argc, char** argv) {
34+
benchmark::Initialize(&argc, argv);
35+
if (benchmark::ReportUnrecognizedArguments(argc, argv))
36+
return 1;
37+
makeCartesianProductBenchmark<RangesMakeThenSortHeap, AllValueTypes, AllOrders>(Quantities);
38+
benchmark::RunSpecifiedBenchmarks();
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include <algorithm>
10+
11+
#include "common.h"
12+
13+
namespace {
14+
template <class ValueType>
15+
struct RangesPopHeap {
16+
size_t Quantity;
17+
18+
void run(benchmark::State& state) const {
19+
runOpOnCopies<ValueType>(
20+
state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
21+
for (auto B = Copy.begin(), I = Copy.end(); I != B; --I) {
22+
std::ranges::pop_heap(B, I);
23+
}
24+
});
25+
}
26+
27+
std::string name() const {
28+
return "BM_RangesPopHeap" + ValueType::name() + "_" + std::to_string(Quantity);
29+
};
30+
};
31+
} // namespace
32+
33+
int main(int argc, char** argv) {
34+
benchmark::Initialize(&argc, argv);
35+
if (benchmark::ReportUnrecognizedArguments(argc, argv))
36+
return 1;
37+
makeCartesianProductBenchmark<RangesPopHeap, AllValueTypes>(Quantities);
38+
benchmark::RunSpecifiedBenchmarks();
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include <algorithm>
10+
11+
#include "common.h"
12+
13+
namespace {
14+
template <class ValueType, class Order>
15+
struct RangesPushHeap {
16+
size_t Quantity;
17+
18+
void run(benchmark::State& state) const {
19+
runOpOnCopies<ValueType>(
20+
state, Quantity, Order(), BatchSize::CountElements, [](auto& Copy) {
21+
for (auto I = Copy.begin(), E = Copy.end(); I != E; ++I) {
22+
std::ranges::push_heap(Copy.begin(), I + 1);
23+
}
24+
});
25+
}
26+
27+
bool skip() const { return Order() == ::Order::Heap; }
28+
29+
std::string name() const {
30+
return "BM_RangesPushHeap" + ValueType::name() + Order::name() + "_" +
31+
std::to_string(Quantity);
32+
};
33+
};
34+
} // namespace
35+
36+
int main(int argc, char** argv) {
37+
benchmark::Initialize(&argc, argv);
38+
if (benchmark::ReportUnrecognizedArguments(argc, argv))
39+
return 1;
40+
makeCartesianProductBenchmark<RangesPushHeap, AllValueTypes, AllOrders>(Quantities);
41+
benchmark::RunSpecifiedBenchmarks();
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include <algorithm>
10+
11+
#include "common.h"
12+
13+
namespace {
14+
template <class ValueType>
15+
struct RangesSortHeap {
16+
size_t Quantity;
17+
18+
void run(benchmark::State& state) const {
19+
runOpOnCopies<ValueType>(
20+
state, Quantity, Order::Heap, BatchSize::CountElements,
21+
[](auto& Copy) { std::ranges::sort_heap(Copy); });
22+
}
23+
24+
std::string name() const {
25+
return "BM_RangesSortHeap" + ValueType::name() + "_" + std::to_string(Quantity);
26+
};
27+
};
28+
} // namespace
29+
30+
int main(int argc, char** argv) {
31+
benchmark::Initialize(&argc, argv);
32+
if (benchmark::ReportUnrecognizedArguments(argc, argv))
33+
return 1;
34+
makeCartesianProductBenchmark<RangesSortHeap, AllValueTypes>(Quantities);
35+
benchmark::RunSpecifiedBenchmarks();
36+
}

libcxx/docs/Status/RangesAlgorithms.csv

+4-4
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,10 @@ Permutation,stable_sort,Konstantin Varlamov,`D127834 <https://llvm.org/D127834>`
7878
Permutation,partial_sort,Konstantin Varlamov,n/a,In progress
7979
Permutation,nth_element,Konstantin Varlamov,`D128149 <https://llvm.org/D128149>`_,✅
8080
Permutation,inplace_merge,Not assigned,n/a,Not started
81-
Permutation,make_heap,Not assigned,n/a,Not started
82-
Permutation,push_heap,Not assigned,n/a,Not started
83-
Permutation,pop_heap,Not assigned,n/a,Not started
84-
Permutation,sort_heap,Not assigned,n/a,Not started
81+
Permutation,make_heap,Konstantin Varlamov,`D128115 <https://llvm.org/D128115>`_,✅
82+
Permutation,push_heap,Konstantin Varlamov,`D128115 <https://llvm.org/D128115>`_,✅
83+
Permutation,pop_heap,Konstantin Varlamov,`D128115 <https://llvm.org/D128115>`_,✅
84+
Permutation,sort_heap,Konstantin Varlamov,`D128115 <https://llvm.org/D128115>`_,✅
8585
Permutation,prev_permutation,Not assigned,n/a,Not started
8686
Permutation,next_permutation,Not assigned,n/a,Not started
8787
Uninitialised memory,uninitialized_copy,Konstantin Varlamov,`D116023 <https://llvm.org/D116023>`_,✅

libcxx/include/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ set(files
9292
__algorithm/ranges_is_sorted_until.h
9393
__algorithm/ranges_lexicographical_compare.h
9494
__algorithm/ranges_lower_bound.h
95+
__algorithm/ranges_make_heap.h
9596
__algorithm/ranges_max.h
9697
__algorithm/ranges_max_element.h
9798
__algorithm/ranges_merge.h
@@ -104,13 +105,16 @@ set(files
104105
__algorithm/ranges_move_backward.h
105106
__algorithm/ranges_none_of.h
106107
__algorithm/ranges_nth_element.h
108+
__algorithm/ranges_pop_heap.h
109+
__algorithm/ranges_push_heap.h
107110
__algorithm/ranges_remove.h
108111
__algorithm/ranges_remove_if.h
109112
__algorithm/ranges_replace.h
110113
__algorithm/ranges_replace_if.h
111114
__algorithm/ranges_reverse.h
112115
__algorithm/ranges_set_difference.h
113116
__algorithm/ranges_sort.h
117+
__algorithm/ranges_sort_heap.h
114118
__algorithm/ranges_stable_sort.h
115119
__algorithm/ranges_swap_ranges.h
116120
__algorithm/ranges_transform.h

libcxx/include/__algorithm/make_heap.h

+20-23
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <__algorithm/sift_down.h>
1515
#include <__config>
1616
#include <__iterator/iterator_traits.h>
17+
#include <__utility/move.h>
1718

1819
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
1920
# pragma GCC system_header
@@ -22,36 +23,32 @@
2223
_LIBCPP_BEGIN_NAMESPACE_STD
2324

2425
template <class _Compare, class _RandomAccessIterator>
25-
_LIBCPP_CONSTEXPR_AFTER_CXX11 void
26-
__make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
27-
{
28-
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
29-
difference_type __n = __last - __first;
30-
if (__n > 1)
31-
{
32-
// start from the first parent, there is no need to consider children
33-
for (difference_type __start = (__n - 2) / 2; __start >= 0; --__start)
34-
{
35-
_VSTD::__sift_down<_Compare>(__first, __comp, __n, __first + __start);
36-
}
26+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
27+
void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
28+
using _CompRef = typename __comp_ref_type<_Compare>::type;
29+
_CompRef __comp_ref = __comp;
30+
31+
using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
32+
difference_type __n = __last - __first;
33+
if (__n > 1) {
34+
// start from the first parent, there is no need to consider children
35+
for (difference_type __start = (__n - 2) / 2; __start >= 0; --__start) {
36+
std::__sift_down<_CompRef>(__first, __comp_ref, __n, __first + __start);
3737
}
38+
}
3839
}
3940

4041
template <class _RandomAccessIterator, class _Compare>
41-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
42-
void
43-
make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
44-
{
45-
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
46-
_VSTD::__make_heap<_Comp_ref>(__first, __last, __comp);
42+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
43+
void make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
44+
std::__make_heap(std::move(__first), std::move(__last), __comp);
4745
}
4846

4947
template <class _RandomAccessIterator>
50-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
51-
void
52-
make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
53-
{
54-
_VSTD::make_heap(__first, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
48+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
49+
void make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) {
50+
std::make_heap(std::move(__first), std::move(__last),
51+
__less<typename iterator_traits<_RandomAccessIterator>::value_type>());
5552
}
5653

5754
_LIBCPP_END_NAMESPACE_STD

libcxx/include/__algorithm/pop_heap.h

+30-30
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <__algorithm/comp_ref_type.h>
1414
#include <__algorithm/push_heap.h>
1515
#include <__algorithm/sift_down.h>
16+
#include <__assert>
1617
#include <__config>
1718
#include <__iterator/iterator_traits.h>
1819
#include <__utility/move.h>
@@ -24,44 +25,43 @@
2425
_LIBCPP_BEGIN_NAMESPACE_STD
2526

2627
template <class _Compare, class _RandomAccessIterator>
27-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
28-
void
29-
__pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
30-
typename iterator_traits<_RandomAccessIterator>::difference_type __len)
31-
{
32-
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
28+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
29+
void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp,
30+
typename iterator_traits<_RandomAccessIterator>::difference_type __len) {
31+
_LIBCPP_ASSERT(__len > 0, "The heap given to pop_heap must be non-empty");
3332

34-
if (__len > 1)
35-
{
36-
value_type __top = std::move(*__first); // create a hole at __first
37-
_RandomAccessIterator __hole = std::__floyd_sift_down<_Compare>(__first, __comp, __len);
38-
--__last;
39-
if (__hole == __last) {
40-
*__hole = std::move(__top);
41-
} else {
42-
*__hole = std::move(*__last);
43-
++__hole;
44-
*__last = std::move(__top);
45-
std::__sift_up<_Compare>(__first, __hole, __comp, __hole - __first);
46-
}
33+
using _CompRef = typename __comp_ref_type<_Compare>::type;
34+
_CompRef __comp_ref = __comp;
35+
36+
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
37+
if (__len > 1) {
38+
value_type __top = std::move(*__first); // create a hole at __first
39+
_RandomAccessIterator __hole = std::__floyd_sift_down<_CompRef>(__first, __comp_ref, __len);
40+
--__last;
41+
42+
if (__hole == __last) {
43+
*__hole = std::move(__top);
44+
} else {
45+
*__hole = std::move(*__last);
46+
++__hole;
47+
*__last = std::move(__top);
48+
std::__sift_up<_CompRef>(__first, __hole, __comp_ref, __hole - __first);
4749
}
50+
}
4851
}
4952

5053
template <class _RandomAccessIterator, class _Compare>
51-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
52-
void
53-
pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp)
54-
{
55-
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
56-
_VSTD::__pop_heap<_Comp_ref>(__first, __last, __comp, __last - __first);
54+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
55+
void pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
56+
typename iterator_traits<_RandomAccessIterator>::difference_type __len = __last - __first;
57+
std::__pop_heap(std::move(__first), std::move(__last), __comp, __len);
5758
}
5859

5960
template <class _RandomAccessIterator>
60-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
61-
void
62-
pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
63-
{
64-
_VSTD::pop_heap(__first, __last, __less<typename iterator_traits<_RandomAccessIterator>::value_type>());
61+
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
62+
void pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last) {
63+
std::pop_heap(std::move(__first), std::move(__last),
64+
__less<typename iterator_traits<_RandomAccessIterator>::value_type>());
6565
}
6666

6767
_LIBCPP_END_NAMESPACE_STD

0 commit comments

Comments
 (0)