Skip to content

Commit fe55e0f

Browse files
committed
Avoid unnecessary swaps for equal elements in __sift_down
1 parent cede236 commit fe55e0f

File tree

2 files changed

+68
-2
lines changed

2 files changed

+68
-2
lines changed

libcxx/include/__algorithm/sift_down.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ __sift_down(_RandomAccessIterator __first,
5151
}
5252

5353
// check if we are in heap-order
54-
if (__comp(*__child_i, *__start))
54+
if (!__comp(*__start, *__child_i))
5555
// we are, __start is larger than its largest child
5656
return;
5757

@@ -75,7 +75,7 @@ __sift_down(_RandomAccessIterator __first,
7575
}
7676

7777
// check if we are in heap-order
78-
} while (!__comp(*__child_i, __top));
78+
} while (__comp(__top, *__child_i));
7979
*__start = std::move(__top);
8080
}
8181

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
// UNSUPPORTED: c++03
10+
11+
// <algorithm>
12+
13+
// template<class Iter>
14+
// void make_heap(Iter first, Iter last);
15+
16+
// This test ensures that equivalent elements are not moved or copied when the heap is created.
17+
18+
#include <algorithm>
19+
#include <cassert>
20+
#include <vector>
21+
#include <utility>
22+
23+
struct Stats {
24+
int compared = 0;
25+
int copied = 0;
26+
int moved = 0;
27+
} stats;
28+
29+
struct MyPair {
30+
std::pair<int, int> p;
31+
MyPair(int a, int b) : p{a, b} {}
32+
MyPair(const MyPair& other) : p(other.p) { ++stats.copied; }
33+
MyPair(MyPair&& other) : p(other.p) { ++stats.moved; }
34+
MyPair& operator=(const MyPair& other) {
35+
p = other.p;
36+
++stats.copied;
37+
return *this;
38+
}
39+
MyPair& operator=(MyPair&& other) {
40+
p = other.p;
41+
++stats.moved;
42+
return *this;
43+
}
44+
friend bool operator<(const MyPair& lhs, const MyPair& rhs) {
45+
++stats.compared;
46+
return lhs.p.first < rhs.p.first;
47+
}
48+
friend bool operator==(const MyPair& lhs, const MyPair& rhs) { return lhs.p == rhs.p; }
49+
};
50+
51+
int main(int, char**) {
52+
std::vector<MyPair> hp{{42, 1}, {42, 2}, {42, 3}, {42, 4}, {42, 5}, {42, 6}};
53+
std::vector<MyPair> original_hp = hp;
54+
55+
stats = {};
56+
std::make_heap(hp.begin(), hp.end());
57+
58+
assert(stats.copied == 0);
59+
assert(stats.moved == 0);
60+
assert(stats.compared == static_cast<int>(hp.size()) - 1);
61+
62+
assert(hp == original_hp);
63+
assert(std::is_heap(hp.begin(), hp.end()));
64+
65+
return 0;
66+
}

0 commit comments

Comments
 (0)