1*6777b538SAndroid Build Coastguard Worker // Copyright 2019 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/containers/intrusive_heap.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
8*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h"
9*6777b538SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
10*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/rand_util.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/test/bind.h"
14*6777b538SAndroid Build Coastguard Worker #include "testing/gmock/include/gmock/gmock.h"
15*6777b538SAndroid Build Coastguard Worker #include "testing/gtest/include/gtest/gtest.h"
16*6777b538SAndroid Build Coastguard Worker
17*6777b538SAndroid Build Coastguard Worker namespace base {
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Worker namespace {
20*6777b538SAndroid Build Coastguard Worker
21*6777b538SAndroid Build Coastguard Worker using IntrusiveHeapInt = IntrusiveHeap<WithHeapHandle<int>>;
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker // Validates whether or not the given heap satisfies the heap invariant.
24*6777b538SAndroid Build Coastguard Worker template <class H>
ExpectHeap(const H & heap)25*6777b538SAndroid Build Coastguard Worker void ExpectHeap(const H& heap) {
26*6777b538SAndroid Build Coastguard Worker const auto& less = heap.value_comp();
27*6777b538SAndroid Build Coastguard Worker const auto& handle_access = heap.heap_handle_access();
28*6777b538SAndroid Build Coastguard Worker
29*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < heap.size(); ++i) {
30*6777b538SAndroid Build Coastguard Worker size_t left = intrusive_heap::LeftIndex(i);
31*6777b538SAndroid Build Coastguard Worker size_t right = left + 1;
32*6777b538SAndroid Build Coastguard Worker
33*6777b538SAndroid Build Coastguard Worker if (left < heap.size())
34*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(less(heap[i], heap[left]));
35*6777b538SAndroid Build Coastguard Worker if (right < heap.size())
36*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(less(heap[i], heap[right]));
37*6777b538SAndroid Build Coastguard Worker
38*6777b538SAndroid Build Coastguard Worker intrusive_heap::CheckInvalidOrEqualTo(handle_access.GetHeapHandle(&heap[i]),
39*6777b538SAndroid Build Coastguard Worker i);
40*6777b538SAndroid Build Coastguard Worker }
41*6777b538SAndroid Build Coastguard Worker }
42*6777b538SAndroid Build Coastguard Worker
43*6777b538SAndroid Build Coastguard Worker // A small set of canonical elements, and the a function for validating the
44*6777b538SAndroid Build Coastguard Worker // heap that should be created by those elements. This is used in various
45*6777b538SAndroid Build Coastguard Worker // constructor/insertion tests.
46*6777b538SAndroid Build Coastguard Worker #define CANONICAL_ELEMENTS 3, 1, 2, 4, 5, 6, 7, 0
ExpectCanonical(const IntrusiveHeapInt & heap)47*6777b538SAndroid Build Coastguard Worker void ExpectCanonical(const IntrusiveHeapInt& heap) {
48*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
49*6777b538SAndroid Build Coastguard Worker
50*6777b538SAndroid Build Coastguard Worker // Manual implementation of a max-heap inserting the elements defined by
51*6777b538SAndroid Build Coastguard Worker // CANONICAL_ELEMENTS:
52*6777b538SAndroid Build Coastguard Worker // 3
53*6777b538SAndroid Build Coastguard Worker // 3 1
54*6777b538SAndroid Build Coastguard Worker // 3 1 2
55*6777b538SAndroid Build Coastguard Worker // 3 1 2 4 -> 3 4 2 1 -> 4 3 2 1
56*6777b538SAndroid Build Coastguard Worker // 4 3 2 1 5 -> 4 5 2 1 3 -> 5 4 2 1 3
57*6777b538SAndroid Build Coastguard Worker // 5 4 2 1 3 6 -> 5 4 6 1 3 2 -> 6 4 5 1 3 2
58*6777b538SAndroid Build Coastguard Worker // 6 4 5 1 3 2 7 -> 6 4 7 1 3 2 5 -> 7 4 6 1 3 2 5
59*6777b538SAndroid Build Coastguard Worker // 7 4 6 1 3 2 5 0
60*6777b538SAndroid Build Coastguard Worker std::vector<int> expected{7, 4, 6, 1, 3, 2, 5, 0};
61*6777b538SAndroid Build Coastguard Worker std::vector<int> actual;
62*6777b538SAndroid Build Coastguard Worker for (const auto& element : heap)
63*6777b538SAndroid Build Coastguard Worker actual.push_back(element.value());
64*6777b538SAndroid Build Coastguard Worker ASSERT_THAT(actual, testing::ContainerEq(expected));
65*6777b538SAndroid Build Coastguard Worker }
66*6777b538SAndroid Build Coastguard Worker
67*6777b538SAndroid Build Coastguard Worker // Initializes the given heap to be the "canonical" heap from the point of view
68*6777b538SAndroid Build Coastguard Worker // of these tests.
MakeCanonical(IntrusiveHeapInt * heap)69*6777b538SAndroid Build Coastguard Worker void MakeCanonical(IntrusiveHeapInt* heap) {
70*6777b538SAndroid Build Coastguard Worker static constexpr int kInts[] = {CANONICAL_ELEMENTS};
71*6777b538SAndroid Build Coastguard Worker heap->clear();
72*6777b538SAndroid Build Coastguard Worker heap->insert(kInts, kInts + std::size(kInts));
73*6777b538SAndroid Build Coastguard Worker ExpectCanonical(*heap);
74*6777b538SAndroid Build Coastguard Worker }
75*6777b538SAndroid Build Coastguard Worker
76*6777b538SAndroid Build Coastguard Worker // A handful of helper functions and classes related to building an exhaustive
77*6777b538SAndroid Build Coastguard Worker // stress test for IntrusiveHeap, with all combinations of default-constructible
78*6777b538SAndroid Build Coastguard Worker // supports-move-operations and supports-copy-operations value types.
79*6777b538SAndroid Build Coastguard Worker
80*6777b538SAndroid Build Coastguard Worker // IntrusiveHeap supports 3 types of operations: those that cause the heap to
81*6777b538SAndroid Build Coastguard Worker // get smaller (deletions), those that keep the heap the same size (updates,
82*6777b538SAndroid Build Coastguard Worker // replaces, etc), and those that cause the heap to get bigger (insertions).
83*6777b538SAndroid Build Coastguard Worker enum OperationTypes : int {
84*6777b538SAndroid Build Coastguard Worker kGrowing,
85*6777b538SAndroid Build Coastguard Worker kShrinking,
86*6777b538SAndroid Build Coastguard Worker kSameSize,
87*6777b538SAndroid Build Coastguard Worker kOperationTypesCount
88*6777b538SAndroid Build Coastguard Worker };
89*6777b538SAndroid Build Coastguard Worker
90*6777b538SAndroid Build Coastguard Worker // The operations that cause a heap to get bigger.
91*6777b538SAndroid Build Coastguard Worker enum GrowingOperations : int { kInsert, kEmplace, kGrowingOperationsCount };
92*6777b538SAndroid Build Coastguard Worker
93*6777b538SAndroid Build Coastguard Worker // The operations that cause a heap to get smaller. Some of these are only
94*6777b538SAndroid Build Coastguard Worker // supported by move-only value types.
95*6777b538SAndroid Build Coastguard Worker enum ShrinkingOperations : int {
96*6777b538SAndroid Build Coastguard Worker kTake,
97*6777b538SAndroid Build Coastguard Worker kTakeTop,
98*6777b538SAndroid Build Coastguard Worker kErase,
99*6777b538SAndroid Build Coastguard Worker kPop,
100*6777b538SAndroid Build Coastguard Worker kShrinkingOperationsCount
101*6777b538SAndroid Build Coastguard Worker };
102*6777b538SAndroid Build Coastguard Worker
103*6777b538SAndroid Build Coastguard Worker // The operations that keep a heap the same size.
104*6777b538SAndroid Build Coastguard Worker enum SameSizeOperations : int {
105*6777b538SAndroid Build Coastguard Worker kReplace,
106*6777b538SAndroid Build Coastguard Worker kReplaceTop,
107*6777b538SAndroid Build Coastguard Worker kUpdate,
108*6777b538SAndroid Build Coastguard Worker kSameSizeOperationsCount
109*6777b538SAndroid Build Coastguard Worker };
110*6777b538SAndroid Build Coastguard Worker
111*6777b538SAndroid Build Coastguard Worker // Randomly selects an operation for the GrowingOperations enum, applies it to
112*6777b538SAndroid Build Coastguard Worker // the given heap, and validates that the operation completed as expected.
113*6777b538SAndroid Build Coastguard Worker template <typename T>
DoGrowingOperation(IntrusiveHeap<T> * heap)114*6777b538SAndroid Build Coastguard Worker void DoGrowingOperation(IntrusiveHeap<T>* heap) {
115*6777b538SAndroid Build Coastguard Worker GrowingOperations op = static_cast<GrowingOperations>(
116*6777b538SAndroid Build Coastguard Worker base::RandInt(0, kGrowingOperationsCount - 1));
117*6777b538SAndroid Build Coastguard Worker
118*6777b538SAndroid Build Coastguard Worker int value = base::RandInt(0, 1000);
119*6777b538SAndroid Build Coastguard Worker size_t old_size = heap->size();
120*6777b538SAndroid Build Coastguard Worker typename IntrusiveHeap<T>::const_iterator it;
121*6777b538SAndroid Build Coastguard Worker
122*6777b538SAndroid Build Coastguard Worker switch (op) {
123*6777b538SAndroid Build Coastguard Worker case kInsert: {
124*6777b538SAndroid Build Coastguard Worker it = heap->insert(T(value));
125*6777b538SAndroid Build Coastguard Worker break;
126*6777b538SAndroid Build Coastguard Worker }
127*6777b538SAndroid Build Coastguard Worker
128*6777b538SAndroid Build Coastguard Worker case kEmplace: {
129*6777b538SAndroid Build Coastguard Worker it = heap->emplace(value);
130*6777b538SAndroid Build Coastguard Worker break;
131*6777b538SAndroid Build Coastguard Worker }
132*6777b538SAndroid Build Coastguard Worker
133*6777b538SAndroid Build Coastguard Worker case kGrowingOperationsCount:
134*6777b538SAndroid Build Coastguard Worker NOTREACHED();
135*6777b538SAndroid Build Coastguard Worker }
136*6777b538SAndroid Build Coastguard Worker
137*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(old_size + 1, heap->size());
138*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(value, it->value());
139*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(it->GetHeapHandle().index(), heap->ToIndex(it));
140*6777b538SAndroid Build Coastguard Worker }
141*6777b538SAndroid Build Coastguard Worker
142*6777b538SAndroid Build Coastguard Worker // Helper struct for determining with the given value type T is movable or not.
143*6777b538SAndroid Build Coastguard Worker // Used to determine whether or not the "take" operations can be used.
144*6777b538SAndroid Build Coastguard Worker template <typename T>
145*6777b538SAndroid Build Coastguard Worker struct NotMovable {
146*6777b538SAndroid Build Coastguard Worker static constexpr bool value = !std::is_nothrow_move_constructible_v<T> &&
147*6777b538SAndroid Build Coastguard Worker std::is_copy_constructible_v<T>;
148*6777b538SAndroid Build Coastguard Worker };
149*6777b538SAndroid Build Coastguard Worker
150*6777b538SAndroid Build Coastguard Worker // Invokes "take" if the type is movable, otherwise invokes erase.
151*6777b538SAndroid Build Coastguard Worker template <typename T, bool kNotMovable = NotMovable<T>::value>
152*6777b538SAndroid Build Coastguard Worker struct Take;
153*6777b538SAndroid Build Coastguard Worker template <typename T>
154*6777b538SAndroid Build Coastguard Worker struct Take<T, true> {
Dobase::__anon39cfb4090111::Take155*6777b538SAndroid Build Coastguard Worker static void Do(IntrusiveHeap<T>* heap, size_t index) { heap->erase(index); }
156*6777b538SAndroid Build Coastguard Worker };
157*6777b538SAndroid Build Coastguard Worker template <typename T>
158*6777b538SAndroid Build Coastguard Worker struct Take<T, false> {
Dobase::__anon39cfb4090111::Take159*6777b538SAndroid Build Coastguard Worker static void Do(IntrusiveHeap<T>* heap, size_t index) {
160*6777b538SAndroid Build Coastguard Worker int value = heap->at(index).value();
161*6777b538SAndroid Build Coastguard Worker T t = heap->take(index);
162*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(value, t.value());
163*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(t.GetHeapHandle().IsValid());
164*6777b538SAndroid Build Coastguard Worker }
165*6777b538SAndroid Build Coastguard Worker };
166*6777b538SAndroid Build Coastguard Worker
167*6777b538SAndroid Build Coastguard Worker // Invokes "take_top" if the type is movable, otherwise invokes pop.
168*6777b538SAndroid Build Coastguard Worker template <typename T, bool kNotMovable = NotMovable<T>::value>
169*6777b538SAndroid Build Coastguard Worker struct TakeTop;
170*6777b538SAndroid Build Coastguard Worker template <typename T>
171*6777b538SAndroid Build Coastguard Worker struct TakeTop<T, true> {
Dobase::__anon39cfb4090111::TakeTop172*6777b538SAndroid Build Coastguard Worker static void Do(IntrusiveHeap<T>* heap) { heap->pop(); }
173*6777b538SAndroid Build Coastguard Worker };
174*6777b538SAndroid Build Coastguard Worker template <typename T>
175*6777b538SAndroid Build Coastguard Worker struct TakeTop<T, false> {
Dobase::__anon39cfb4090111::TakeTop176*6777b538SAndroid Build Coastguard Worker static void Do(IntrusiveHeap<T>* heap) {
177*6777b538SAndroid Build Coastguard Worker int value = heap->at(0).value();
178*6777b538SAndroid Build Coastguard Worker T t = heap->take_top();
179*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(value, t.value());
180*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(t.GetHeapHandle().IsValid());
181*6777b538SAndroid Build Coastguard Worker }
182*6777b538SAndroid Build Coastguard Worker };
183*6777b538SAndroid Build Coastguard Worker
184*6777b538SAndroid Build Coastguard Worker // Randomly selects a shrinking operations, applies it to the given |heap| and
185*6777b538SAndroid Build Coastguard Worker // validates that the operation completed as expected and resulted in a valid
186*6777b538SAndroid Build Coastguard Worker // heap. The "take" operations will only be invoked for a value type T that
187*6777b538SAndroid Build Coastguard Worker // supports move operations, otherwise they will be mapped to erase/pop.
188*6777b538SAndroid Build Coastguard Worker template <typename T>
DoShrinkingOperation(IntrusiveHeap<T> * heap)189*6777b538SAndroid Build Coastguard Worker void DoShrinkingOperation(IntrusiveHeap<T>* heap) {
190*6777b538SAndroid Build Coastguard Worker ShrinkingOperations op = static_cast<ShrinkingOperations>(
191*6777b538SAndroid Build Coastguard Worker base::RandInt(0, kShrinkingOperationsCount - 1));
192*6777b538SAndroid Build Coastguard Worker
193*6777b538SAndroid Build Coastguard Worker size_t old_size = heap->size();
194*6777b538SAndroid Build Coastguard Worker size_t index = static_cast<size_t>(base::RandInt(0, old_size - 1));
195*6777b538SAndroid Build Coastguard Worker
196*6777b538SAndroid Build Coastguard Worker switch (op) {
197*6777b538SAndroid Build Coastguard Worker case kTake: {
198*6777b538SAndroid Build Coastguard Worker Take<T>::Do(heap, index);
199*6777b538SAndroid Build Coastguard Worker break;
200*6777b538SAndroid Build Coastguard Worker }
201*6777b538SAndroid Build Coastguard Worker
202*6777b538SAndroid Build Coastguard Worker case kTakeTop: {
203*6777b538SAndroid Build Coastguard Worker TakeTop<T>::Do(heap);
204*6777b538SAndroid Build Coastguard Worker break;
205*6777b538SAndroid Build Coastguard Worker }
206*6777b538SAndroid Build Coastguard Worker
207*6777b538SAndroid Build Coastguard Worker case kErase: {
208*6777b538SAndroid Build Coastguard Worker heap->erase(index);
209*6777b538SAndroid Build Coastguard Worker break;
210*6777b538SAndroid Build Coastguard Worker }
211*6777b538SAndroid Build Coastguard Worker
212*6777b538SAndroid Build Coastguard Worker case kPop: {
213*6777b538SAndroid Build Coastguard Worker heap->pop();
214*6777b538SAndroid Build Coastguard Worker break;
215*6777b538SAndroid Build Coastguard Worker }
216*6777b538SAndroid Build Coastguard Worker
217*6777b538SAndroid Build Coastguard Worker case kShrinkingOperationsCount:
218*6777b538SAndroid Build Coastguard Worker NOTREACHED();
219*6777b538SAndroid Build Coastguard Worker }
220*6777b538SAndroid Build Coastguard Worker
221*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(old_size - 1, heap->size());
222*6777b538SAndroid Build Coastguard Worker }
223*6777b538SAndroid Build Coastguard Worker
224*6777b538SAndroid Build Coastguard Worker // Randomly selects a same size operation, applies it to the given |heap| and
225*6777b538SAndroid Build Coastguard Worker // validates that the operation completed as expected and resulted in a valid
226*6777b538SAndroid Build Coastguard Worker // heap.
227*6777b538SAndroid Build Coastguard Worker template <typename T>
DoSameSizeOperation(IntrusiveHeap<T> * heap)228*6777b538SAndroid Build Coastguard Worker void DoSameSizeOperation(IntrusiveHeap<T>* heap) {
229*6777b538SAndroid Build Coastguard Worker SameSizeOperations op = static_cast<SameSizeOperations>(
230*6777b538SAndroid Build Coastguard Worker base::RandInt(0, kSameSizeOperationsCount - 1));
231*6777b538SAndroid Build Coastguard Worker
232*6777b538SAndroid Build Coastguard Worker size_t old_size = heap->size();
233*6777b538SAndroid Build Coastguard Worker size_t index = static_cast<size_t>(base::RandInt(0, old_size - 1));
234*6777b538SAndroid Build Coastguard Worker if (op == kReplaceTop)
235*6777b538SAndroid Build Coastguard Worker index = 0;
236*6777b538SAndroid Build Coastguard Worker int new_value = base::RandInt(0, 1000);
237*6777b538SAndroid Build Coastguard Worker typename IntrusiveHeap<T>::const_iterator it;
238*6777b538SAndroid Build Coastguard Worker
239*6777b538SAndroid Build Coastguard Worker switch (op) {
240*6777b538SAndroid Build Coastguard Worker case kReplace: {
241*6777b538SAndroid Build Coastguard Worker it = heap->Replace(index, T(new_value));
242*6777b538SAndroid Build Coastguard Worker break;
243*6777b538SAndroid Build Coastguard Worker }
244*6777b538SAndroid Build Coastguard Worker
245*6777b538SAndroid Build Coastguard Worker case kReplaceTop: {
246*6777b538SAndroid Build Coastguard Worker it = heap->ReplaceTop(T(new_value));
247*6777b538SAndroid Build Coastguard Worker break;
248*6777b538SAndroid Build Coastguard Worker }
249*6777b538SAndroid Build Coastguard Worker
250*6777b538SAndroid Build Coastguard Worker case kUpdate: {
251*6777b538SAndroid Build Coastguard Worker it = heap->Modify(
252*6777b538SAndroid Build Coastguard Worker index, [&new_value](T& element) { element.set_value(new_value); });
253*6777b538SAndroid Build Coastguard Worker break;
254*6777b538SAndroid Build Coastguard Worker }
255*6777b538SAndroid Build Coastguard Worker
256*6777b538SAndroid Build Coastguard Worker case kSameSizeOperationsCount:
257*6777b538SAndroid Build Coastguard Worker NOTREACHED();
258*6777b538SAndroid Build Coastguard Worker }
259*6777b538SAndroid Build Coastguard Worker
260*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(old_size, heap->size());
261*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(new_value, it->value());
262*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(it->GetHeapHandle().index(), heap->ToIndex(it));
263*6777b538SAndroid Build Coastguard Worker }
264*6777b538SAndroid Build Coastguard Worker
265*6777b538SAndroid Build Coastguard Worker // Randomly selects an operation, applies it to the given |heap| and validates
266*6777b538SAndroid Build Coastguard Worker // that the operation completed as expected and resulted in a valid heap.
267*6777b538SAndroid Build Coastguard Worker template <typename T>
DoRandomHeapOperation(IntrusiveHeap<T> * heap)268*6777b538SAndroid Build Coastguard Worker void DoRandomHeapOperation(IntrusiveHeap<T>* heap) {
269*6777b538SAndroid Build Coastguard Worker static constexpr int kMinHeapSize = 10u;
270*6777b538SAndroid Build Coastguard Worker static constexpr int kMaxHeapSize = 100u;
271*6777b538SAndroid Build Coastguard Worker
272*6777b538SAndroid Build Coastguard Worker OperationTypes operation_type =
273*6777b538SAndroid Build Coastguard Worker static_cast<OperationTypes>(base::RandInt(0, kOperationTypesCount - 1));
274*6777b538SAndroid Build Coastguard Worker
275*6777b538SAndroid Build Coastguard Worker // Keep the heap size bounded by forcing growing and shrinking operations when
276*6777b538SAndroid Build Coastguard Worker // it exceeds the bounds.
277*6777b538SAndroid Build Coastguard Worker if (heap->size() < kMinHeapSize) {
278*6777b538SAndroid Build Coastguard Worker operation_type = kGrowing;
279*6777b538SAndroid Build Coastguard Worker } else if (heap->size() > kMaxHeapSize) {
280*6777b538SAndroid Build Coastguard Worker operation_type = kShrinking;
281*6777b538SAndroid Build Coastguard Worker }
282*6777b538SAndroid Build Coastguard Worker
283*6777b538SAndroid Build Coastguard Worker switch (operation_type) {
284*6777b538SAndroid Build Coastguard Worker case kGrowing:
285*6777b538SAndroid Build Coastguard Worker DoGrowingOperation(heap);
286*6777b538SAndroid Build Coastguard Worker break;
287*6777b538SAndroid Build Coastguard Worker case kShrinking:
288*6777b538SAndroid Build Coastguard Worker DoShrinkingOperation(heap);
289*6777b538SAndroid Build Coastguard Worker break;
290*6777b538SAndroid Build Coastguard Worker case kSameSize:
291*6777b538SAndroid Build Coastguard Worker DoSameSizeOperation(heap);
292*6777b538SAndroid Build Coastguard Worker break;
293*6777b538SAndroid Build Coastguard Worker case kOperationTypesCount:
294*6777b538SAndroid Build Coastguard Worker NOTREACHED();
295*6777b538SAndroid Build Coastguard Worker }
296*6777b538SAndroid Build Coastguard Worker }
297*6777b538SAndroid Build Coastguard Worker
298*6777b538SAndroid Build Coastguard Worker // A stress test that is only applicable to value types T that support move
299*6777b538SAndroid Build Coastguard Worker // operations.
300*6777b538SAndroid Build Coastguard Worker template <typename T>
MoveStressTest()301*6777b538SAndroid Build Coastguard Worker void MoveStressTest() {
302*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<T> heap({2, 4, 6, 8});
303*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(4u, heap.size());
304*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap.empty());
305*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
306*6777b538SAndroid Build Coastguard Worker
307*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<T> heap2(std::move(heap));
308*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(4u, heap2.size());
309*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap2.empty());
310*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap2);
311*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0u, heap.size());
312*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap.empty());
313*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
314*6777b538SAndroid Build Coastguard Worker
315*6777b538SAndroid Build Coastguard Worker heap = std::move(heap2);
316*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(4u, heap.size());
317*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap.empty());
318*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
319*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0u, heap2.size());
320*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap2.empty());
321*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap2);
322*6777b538SAndroid Build Coastguard Worker }
323*6777b538SAndroid Build Coastguard Worker
324*6777b538SAndroid Build Coastguard Worker // A stress that that is only applicable to value types T that support copy
325*6777b538SAndroid Build Coastguard Worker // operations.
326*6777b538SAndroid Build Coastguard Worker template <typename T>
CopyStressTest()327*6777b538SAndroid Build Coastguard Worker void CopyStressTest() {
328*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<T> heap({2, 4, 6, 8});
329*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(4u, heap.size());
330*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap.empty());
331*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
332*6777b538SAndroid Build Coastguard Worker
333*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<T> heap2(heap);
334*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(4u, heap2.size());
335*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap2.empty());
336*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap2);
337*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(4u, heap.size());
338*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap.empty());
339*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
340*6777b538SAndroid Build Coastguard Worker
341*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<T> heap3({1, 3, 5});
342*6777b538SAndroid Build Coastguard Worker heap3.clear();
343*6777b538SAndroid Build Coastguard Worker heap3 = heap;
344*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(4u, heap3.size());
345*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap3.empty());
346*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
347*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(4u, heap.size());
348*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap.empty());
349*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
350*6777b538SAndroid Build Coastguard Worker
351*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap == heap2);
352*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap != heap2);
353*6777b538SAndroid Build Coastguard Worker }
354*6777b538SAndroid Build Coastguard Worker
355*6777b538SAndroid Build Coastguard Worker // A stress test that is applicable to all value types, whether or not they
356*6777b538SAndroid Build Coastguard Worker // support copy and/or move operations.
357*6777b538SAndroid Build Coastguard Worker template <typename T>
GeneralStressTest()358*6777b538SAndroid Build Coastguard Worker void GeneralStressTest() {
359*6777b538SAndroid Build Coastguard Worker std::vector<int> vector{2, 4, 6, 8};
360*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<T> heap(vector.begin(), vector.end());
361*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(4u, heap.size());
362*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap.empty());
363*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
364*6777b538SAndroid Build Coastguard Worker
365*6777b538SAndroid Build Coastguard Worker heap.clear();
366*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0u, heap.size());
367*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap.empty());
368*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
369*6777b538SAndroid Build Coastguard Worker
370*6777b538SAndroid Build Coastguard Worker // Create an element and get a handle to it.
371*6777b538SAndroid Build Coastguard Worker auto it = heap.insert(T(34));
372*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(1u, heap.size());
373*6777b538SAndroid Build Coastguard Worker HeapHandle* handle = it->handle();
374*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0u, handle->index());
375*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
376*6777b538SAndroid Build Coastguard Worker
377*6777b538SAndroid Build Coastguard Worker // Add some other elements.
378*6777b538SAndroid Build Coastguard Worker heap.insert(T(12));
379*6777b538SAndroid Build Coastguard Worker heap.emplace(14);
380*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(3u, heap.size());
381*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
382*6777b538SAndroid Build Coastguard Worker
383*6777b538SAndroid Build Coastguard Worker // The handle should have tracked the element it is associated with.
384*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(34, heap[*handle].value());
385*6777b538SAndroid Build Coastguard Worker
386*6777b538SAndroid Build Coastguard Worker // Replace with a value that shouldn't need moving in the heap.
387*6777b538SAndroid Build Coastguard Worker size_t index = handle->index();
388*6777b538SAndroid Build Coastguard Worker handle = heap.Replace(*handle, T(40))->handle();
389*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(3u, heap.size());
390*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
391*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(index, handle->index());
392*6777b538SAndroid Build Coastguard Worker
393*6777b538SAndroid Build Coastguard Worker // Replace with a value that should cause the entry to move.
394*6777b538SAndroid Build Coastguard Worker handle = heap.Replace(handle->index(), T(1))->handle();
395*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(3u, heap.size());
396*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
397*6777b538SAndroid Build Coastguard Worker EXPECT_NE(index, handle->index());
398*6777b538SAndroid Build Coastguard Worker
399*6777b538SAndroid Build Coastguard Worker // Replace the top element.
400*6777b538SAndroid Build Coastguard Worker heap.ReplaceTop(T(65));
401*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(3u, heap.size());
402*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
403*6777b538SAndroid Build Coastguard Worker
404*6777b538SAndroid Build Coastguard Worker // Insert several more elements.
405*6777b538SAndroid Build Coastguard Worker std::vector<int> elements({13, 17, 19, 23, 29, 31, 37, 41});
406*6777b538SAndroid Build Coastguard Worker heap.insert(elements.begin(), elements.end());
407*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(11u, heap.size());
408*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
409*6777b538SAndroid Build Coastguard Worker
410*6777b538SAndroid Build Coastguard Worker // Invasively change an element that is already inside the heap, and then
411*6777b538SAndroid Build Coastguard Worker // repair the heap.
412*6777b538SAndroid Build Coastguard Worker T* element = const_cast<T*>(&heap[7]);
413*6777b538SAndroid Build Coastguard Worker element->set_value(97);
414*6777b538SAndroid Build Coastguard Worker heap.Update(7u);
415*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
416*6777b538SAndroid Build Coastguard Worker
417*6777b538SAndroid Build Coastguard Worker // Safely modify an element that is already inside the heap.
418*6777b538SAndroid Build Coastguard Worker heap.Modify(7u, [](T& element) { element.set_value(128); });
419*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
420*6777b538SAndroid Build Coastguard Worker
421*6777b538SAndroid Build Coastguard Worker // Do some more updates that are no-ops, just to explore all the flavours of
422*6777b538SAndroid Build Coastguard Worker // ToIndex.
423*6777b538SAndroid Build Coastguard Worker handle = heap[5].handle();
424*6777b538SAndroid Build Coastguard Worker heap.Update(*handle);
425*6777b538SAndroid Build Coastguard Worker heap.Update(heap.begin() + 6);
426*6777b538SAndroid Build Coastguard Worker heap.Update(heap.rbegin() + 8);
427*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
428*6777b538SAndroid Build Coastguard Worker
429*6777b538SAndroid Build Coastguard Worker handle = heap[5].handle();
430*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(handle);
431*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(5u, handle->index());
432*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(5u, heap.ToIndex(*handle));
433*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(5u, heap.ToIndex(heap.begin() + 5));
434*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(5u, heap.ToIndex(heap.cbegin() + 5));
435*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(5u, heap.ToIndex(heap.rbegin() + 5));
436*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(5u, heap.ToIndex(heap.crbegin() + 5));
437*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(HeapHandle::kInvalidIndex, heap.ToIndex(heap.end()));
438*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(HeapHandle::kInvalidIndex, heap.ToIndex(heap.cend()));
439*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(HeapHandle::kInvalidIndex, heap.ToIndex(heap.rend()));
440*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(HeapHandle::kInvalidIndex, heap.ToIndex(heap.crend()));
441*6777b538SAndroid Build Coastguard Worker
442*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(&heap[0], &heap.at(0));
443*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(&heap[0], &heap.front());
444*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(&heap[0], &heap.top());
445*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(&heap[heap.size() - 1], &heap.back());
446*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(&heap[0], heap.data());
447*6777b538SAndroid Build Coastguard Worker
448*6777b538SAndroid Build Coastguard Worker // Do a bunch of random operations on a heap as a stress test.
449*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < 1000; ++i) {
450*6777b538SAndroid Build Coastguard Worker DoRandomHeapOperation(&heap);
451*6777b538SAndroid Build Coastguard Worker ExpectHeap(heap);
452*6777b538SAndroid Build Coastguard Worker }
453*6777b538SAndroid Build Coastguard Worker }
454*6777b538SAndroid Build Coastguard Worker
455*6777b538SAndroid Build Coastguard Worker // A basic value type that wraps an integer. This is default constructible, and
456*6777b538SAndroid Build Coastguard Worker // supports both move and copy operations.
457*6777b538SAndroid Build Coastguard Worker class Value : public InternalHeapHandleStorage {
458*6777b538SAndroid Build Coastguard Worker public:
Value(int value)459*6777b538SAndroid Build Coastguard Worker explicit Value(int value) : value_(value) {}
Value()460*6777b538SAndroid Build Coastguard Worker Value() : value_(-1) {}
Value(Value && other)461*6777b538SAndroid Build Coastguard Worker Value(Value&& other) noexcept
462*6777b538SAndroid Build Coastguard Worker : InternalHeapHandleStorage(std::move(other)),
463*6777b538SAndroid Build Coastguard Worker value_(std::exchange(other.value_, -1)) {}
Value(const Value & other)464*6777b538SAndroid Build Coastguard Worker Value(const Value& other) : value_(other.value_) {
465*6777b538SAndroid Build Coastguard Worker HeapHandle h = other.GetHeapHandle();
466*6777b538SAndroid Build Coastguard Worker if (h.IsValid())
467*6777b538SAndroid Build Coastguard Worker SetHeapHandle(h);
468*6777b538SAndroid Build Coastguard Worker }
~Value()469*6777b538SAndroid Build Coastguard Worker ~Value() override {}
470*6777b538SAndroid Build Coastguard Worker
operator =(Value && other)471*6777b538SAndroid Build Coastguard Worker Value& operator=(Value&& other) noexcept {
472*6777b538SAndroid Build Coastguard Worker InternalHeapHandleStorage::operator=(std::move(other));
473*6777b538SAndroid Build Coastguard Worker value_ = std::exchange(other.value_, -1);
474*6777b538SAndroid Build Coastguard Worker return *this;
475*6777b538SAndroid Build Coastguard Worker }
operator =(const Value & other)476*6777b538SAndroid Build Coastguard Worker Value& operator=(const Value& other) {
477*6777b538SAndroid Build Coastguard Worker value_ = other.value_;
478*6777b538SAndroid Build Coastguard Worker return *this;
479*6777b538SAndroid Build Coastguard Worker }
480*6777b538SAndroid Build Coastguard Worker
value() const481*6777b538SAndroid Build Coastguard Worker int value() const { return value_; }
set_value(int value)482*6777b538SAndroid Build Coastguard Worker void set_value(int value) { value_ = value; }
483*6777b538SAndroid Build Coastguard Worker
operator ==(const Value & rhs) const484*6777b538SAndroid Build Coastguard Worker bool operator==(const Value& rhs) const { return value_ == rhs.value_; }
operator !=(const Value & rhs) const485*6777b538SAndroid Build Coastguard Worker bool operator!=(const Value& rhs) const { return value_ != rhs.value_; }
operator <=(const Value & rhs) const486*6777b538SAndroid Build Coastguard Worker bool operator<=(const Value& rhs) const { return value_ <= rhs.value_; }
operator >=(const Value & rhs) const487*6777b538SAndroid Build Coastguard Worker bool operator>=(const Value& rhs) const { return value_ >= rhs.value_; }
operator <(const Value & rhs) const488*6777b538SAndroid Build Coastguard Worker bool operator<(const Value& rhs) const { return value_ < rhs.value_; }
operator >(const Value & rhs) const489*6777b538SAndroid Build Coastguard Worker bool operator>(const Value& rhs) const { return value_ > rhs.value_; }
490*6777b538SAndroid Build Coastguard Worker
491*6777b538SAndroid Build Coastguard Worker private:
492*6777b538SAndroid Build Coastguard Worker int value_;
493*6777b538SAndroid Build Coastguard Worker };
494*6777b538SAndroid Build Coastguard Worker
495*6777b538SAndroid Build Coastguard Worker // Macro for creating versions of Value that selectively enable/disable
496*6777b538SAndroid Build Coastguard Worker // default-constructors, move-operations and copy-operations.
497*6777b538SAndroid Build Coastguard Worker #define DEFINE_VALUE_TYPE(name, default_construct, move, copy) \
498*6777b538SAndroid Build Coastguard Worker class name : public Value { \
499*6777b538SAndroid Build Coastguard Worker public: \
500*6777b538SAndroid Build Coastguard Worker explicit name(int value) : Value(value) {} \
501*6777b538SAndroid Build Coastguard Worker name() = default_construct; \
502*6777b538SAndroid Build Coastguard Worker name(name&&) noexcept = move; \
503*6777b538SAndroid Build Coastguard Worker name(const name&) = copy; \
504*6777b538SAndroid Build Coastguard Worker name& operator=(name&&) noexcept = move; \
505*6777b538SAndroid Build Coastguard Worker name& operator=(const name&) = copy; \
506*6777b538SAndroid Build Coastguard Worker };
507*6777b538SAndroid Build Coastguard Worker
DEFINE_VALUE_TYPE(Value_DMC,default,default,default)508*6777b538SAndroid Build Coastguard Worker DEFINE_VALUE_TYPE(Value_DMC, default, default, default)
509*6777b538SAndroid Build Coastguard Worker DEFINE_VALUE_TYPE(Value_DmC, default, delete, default)
510*6777b538SAndroid Build Coastguard Worker DEFINE_VALUE_TYPE(Value_DMc, default, default, delete)
511*6777b538SAndroid Build Coastguard Worker DEFINE_VALUE_TYPE(Value_dMC, delete, default, default)
512*6777b538SAndroid Build Coastguard Worker DEFINE_VALUE_TYPE(Value_dmC, delete, delete, default)
513*6777b538SAndroid Build Coastguard Worker DEFINE_VALUE_TYPE(Value_dMc, delete, default, delete)
514*6777b538SAndroid Build Coastguard Worker
515*6777b538SAndroid Build Coastguard Worker // Used to validate that the generated value types work as expected wrt
516*6777b538SAndroid Build Coastguard Worker // default-constructors, move-operations and copy-operations.
517*6777b538SAndroid Build Coastguard Worker template <typename ValueType, bool D, bool M, bool C>
518*6777b538SAndroid Build Coastguard Worker void ValidateValueType() {
519*6777b538SAndroid Build Coastguard Worker static_assert(std::is_default_constructible_v<ValueType> == D, "oops");
520*6777b538SAndroid Build Coastguard Worker static_assert(std::is_move_constructible_v<ValueType> == M, "oops");
521*6777b538SAndroid Build Coastguard Worker static_assert(std::is_move_assignable_v<ValueType> == M, "oops");
522*6777b538SAndroid Build Coastguard Worker static_assert(std::is_copy_constructible_v<ValueType> == C, "oops");
523*6777b538SAndroid Build Coastguard Worker static_assert(std::is_copy_assignable_v<ValueType> == C, "oops");
524*6777b538SAndroid Build Coastguard Worker }
525*6777b538SAndroid Build Coastguard Worker
526*6777b538SAndroid Build Coastguard Worker // A small test element that provides its own HeapHandle storage and implements
527*6777b538SAndroid Build Coastguard Worker // the contract expected of the DefaultHeapHandleAccessor.
528*6777b538SAndroid Build Coastguard Worker struct TestElement {
529*6777b538SAndroid Build Coastguard Worker int key;
530*6777b538SAndroid Build Coastguard Worker raw_ptr<HeapHandle> handle;
531*6777b538SAndroid Build Coastguard Worker
532*6777b538SAndroid Build Coastguard Worker // Make this a min-heap by return > instead of <.
operator <base::__anon39cfb4090111::TestElement533*6777b538SAndroid Build Coastguard Worker bool operator<(const TestElement& other) const { return key > other.key; }
534*6777b538SAndroid Build Coastguard Worker
SetHeapHandlebase::__anon39cfb4090111::TestElement535*6777b538SAndroid Build Coastguard Worker void SetHeapHandle(HeapHandle h) {
536*6777b538SAndroid Build Coastguard Worker if (handle)
537*6777b538SAndroid Build Coastguard Worker *handle = h;
538*6777b538SAndroid Build Coastguard Worker }
539*6777b538SAndroid Build Coastguard Worker
ClearHeapHandlebase::__anon39cfb4090111::TestElement540*6777b538SAndroid Build Coastguard Worker void ClearHeapHandle() {
541*6777b538SAndroid Build Coastguard Worker if (handle)
542*6777b538SAndroid Build Coastguard Worker handle->reset();
543*6777b538SAndroid Build Coastguard Worker }
544*6777b538SAndroid Build Coastguard Worker
GetHeapHandlebase::__anon39cfb4090111::TestElement545*6777b538SAndroid Build Coastguard Worker HeapHandle GetHeapHandle() const {
546*6777b538SAndroid Build Coastguard Worker if (handle)
547*6777b538SAndroid Build Coastguard Worker return *handle;
548*6777b538SAndroid Build Coastguard Worker return HeapHandle::Invalid();
549*6777b538SAndroid Build Coastguard Worker }
550*6777b538SAndroid Build Coastguard Worker };
551*6777b538SAndroid Build Coastguard Worker
552*6777b538SAndroid Build Coastguard Worker } // namespace
553*6777b538SAndroid Build Coastguard Worker
554*6777b538SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
555*6777b538SAndroid Build Coastguard Worker // TEST SUITE 1
556*6777b538SAndroid Build Coastguard Worker //
557*6777b538SAndroid Build Coastguard Worker // Explicit tests of a simple heap using WithHeapHandle<>.
558*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,Constructors)559*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, Constructors) {
560*6777b538SAndroid Build Coastguard Worker {
561*6777b538SAndroid Build Coastguard Worker // Default constructor.
562*6777b538SAndroid Build Coastguard Worker IntrusiveHeapInt heap;
563*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap.empty());
564*6777b538SAndroid Build Coastguard Worker }
565*6777b538SAndroid Build Coastguard Worker
566*6777b538SAndroid Build Coastguard Worker {
567*6777b538SAndroid Build Coastguard Worker // Constructor with iterators.
568*6777b538SAndroid Build Coastguard Worker std::vector<int> ints{CANONICAL_ELEMENTS};
569*6777b538SAndroid Build Coastguard Worker IntrusiveHeapInt heap(ints.begin(), ints.end());
570*6777b538SAndroid Build Coastguard Worker ExpectCanonical(heap);
571*6777b538SAndroid Build Coastguard Worker
572*6777b538SAndroid Build Coastguard Worker // Move constructor.
573*6777b538SAndroid Build Coastguard Worker IntrusiveHeapInt heap2(std::move(heap));
574*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap.empty());
575*6777b538SAndroid Build Coastguard Worker ExpectCanonical(heap2);
576*6777b538SAndroid Build Coastguard Worker }
577*6777b538SAndroid Build Coastguard Worker
578*6777b538SAndroid Build Coastguard Worker {
579*6777b538SAndroid Build Coastguard Worker // Constructor with initializer list.
580*6777b538SAndroid Build Coastguard Worker IntrusiveHeapInt heap{CANONICAL_ELEMENTS};
581*6777b538SAndroid Build Coastguard Worker ExpectCanonical(heap);
582*6777b538SAndroid Build Coastguard Worker }
583*6777b538SAndroid Build Coastguard Worker }
584*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,Assignment)585*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, Assignment) {
586*6777b538SAndroid Build Coastguard Worker IntrusiveHeapInt heap{CANONICAL_ELEMENTS};
587*6777b538SAndroid Build Coastguard Worker
588*6777b538SAndroid Build Coastguard Worker // Move assignment.
589*6777b538SAndroid Build Coastguard Worker IntrusiveHeapInt heap2;
590*6777b538SAndroid Build Coastguard Worker heap2 = std::move(heap);
591*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap.empty());
592*6777b538SAndroid Build Coastguard Worker ExpectCanonical(heap2);
593*6777b538SAndroid Build Coastguard Worker }
594*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,Swap)595*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, Swap) {
596*6777b538SAndroid Build Coastguard Worker IntrusiveHeapInt heap{CANONICAL_ELEMENTS};
597*6777b538SAndroid Build Coastguard Worker IntrusiveHeapInt heap2;
598*6777b538SAndroid Build Coastguard Worker swap(heap, heap2);
599*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap.empty());
600*6777b538SAndroid Build Coastguard Worker ExpectCanonical(heap2);
601*6777b538SAndroid Build Coastguard Worker heap.swap(heap2);
602*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap2.empty());
603*6777b538SAndroid Build Coastguard Worker ExpectCanonical(heap);
604*6777b538SAndroid Build Coastguard Worker }
605*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,ElementAccess)606*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, ElementAccess) {
607*6777b538SAndroid Build Coastguard Worker IntrusiveHeapInt heap{CANONICAL_ELEMENTS};
608*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(heap.front(), heap[0]);
609*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(heap.back(), heap[7]);
610*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(heap.top(), heap[0]);
611*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < heap.size(); ++i) {
612*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(heap[i], heap.at(i));
613*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(heap[i], heap.data()[i]);
614*6777b538SAndroid Build Coastguard Worker }
615*6777b538SAndroid Build Coastguard Worker }
616*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,SizeManagement)617*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, SizeManagement) {
618*6777b538SAndroid Build Coastguard Worker IntrusiveHeapInt heap;
619*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap.empty());
620*6777b538SAndroid Build Coastguard Worker EXPECT_LE(heap.size(), heap.capacity());
621*6777b538SAndroid Build Coastguard Worker
622*6777b538SAndroid Build Coastguard Worker MakeCanonical(&heap);
623*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap.empty());
624*6777b538SAndroid Build Coastguard Worker EXPECT_LE(heap.size(), heap.capacity());
625*6777b538SAndroid Build Coastguard Worker }
626*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,Iterators)627*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, Iterators) {
628*6777b538SAndroid Build Coastguard Worker IntrusiveHeapInt heap;
629*6777b538SAndroid Build Coastguard Worker MakeCanonical(&heap);
630*6777b538SAndroid Build Coastguard Worker
631*6777b538SAndroid Build Coastguard Worker size_t i = 0;
632*6777b538SAndroid Build Coastguard Worker for (auto it = heap.begin(); it != heap.end(); ++it) {
633*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(i, heap.ToIndex(it));
634*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(&(*it), heap.data() + i);
635*6777b538SAndroid Build Coastguard Worker ++i;
636*6777b538SAndroid Build Coastguard Worker }
637*6777b538SAndroid Build Coastguard Worker
638*6777b538SAndroid Build Coastguard Worker i = heap.size() - 1;
639*6777b538SAndroid Build Coastguard Worker for (auto rit = heap.rbegin(); rit != heap.rend(); ++rit) {
640*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(i, heap.ToIndex(rit));
641*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(&(*rit), heap.data() + i);
642*6777b538SAndroid Build Coastguard Worker --i;
643*6777b538SAndroid Build Coastguard Worker }
644*6777b538SAndroid Build Coastguard Worker }
645*6777b538SAndroid Build Coastguard Worker
646*6777b538SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
647*6777b538SAndroid Build Coastguard Worker // TEST SUITE 2
648*6777b538SAndroid Build Coastguard Worker //
649*6777b538SAndroid Build Coastguard Worker // Exhaustive stress tests with different value types, exploring all
650*6777b538SAndroid Build Coastguard Worker // possibilities of default-constrible, movable and copyable value types.
651*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,MoveOnlyNoDefaultConstructorTest)652*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, MoveOnlyNoDefaultConstructorTest) {
653*6777b538SAndroid Build Coastguard Worker using ValueType = Value_dMc;
654*6777b538SAndroid Build Coastguard Worker ValidateValueType<ValueType, false, true, false>();
655*6777b538SAndroid Build Coastguard Worker MoveStressTest<ValueType>();
656*6777b538SAndroid Build Coastguard Worker GeneralStressTest<ValueType>();
657*6777b538SAndroid Build Coastguard Worker }
658*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,CopyOnlyNoDefaultConstructorTest)659*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, CopyOnlyNoDefaultConstructorTest) {
660*6777b538SAndroid Build Coastguard Worker using ValueType = Value_dmC;
661*6777b538SAndroid Build Coastguard Worker ValidateValueType<ValueType, false, false, true>();
662*6777b538SAndroid Build Coastguard Worker // We cannot perform CopyStressTest nor GeneralStressTest here, because
663*6777b538SAndroid Build Coastguard Worker // Value_dmC has deleted move constructor and assignment operator. See
664*6777b538SAndroid Build Coastguard Worker // crbug.com/1022576.
665*6777b538SAndroid Build Coastguard Worker }
666*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,CopyAndMoveNoDefaultConstructorTest)667*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, CopyAndMoveNoDefaultConstructorTest) {
668*6777b538SAndroid Build Coastguard Worker using ValueType = Value_dMC;
669*6777b538SAndroid Build Coastguard Worker ValidateValueType<ValueType, false, true, true>();
670*6777b538SAndroid Build Coastguard Worker CopyStressTest<ValueType>();
671*6777b538SAndroid Build Coastguard Worker MoveStressTest<ValueType>();
672*6777b538SAndroid Build Coastguard Worker GeneralStressTest<ValueType>();
673*6777b538SAndroid Build Coastguard Worker }
674*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,MoveOnlyWithDefaultConstructorTest)675*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, MoveOnlyWithDefaultConstructorTest) {
676*6777b538SAndroid Build Coastguard Worker using ValueType = Value_DMc;
677*6777b538SAndroid Build Coastguard Worker ValidateValueType<ValueType, true, true, false>();
678*6777b538SAndroid Build Coastguard Worker MoveStressTest<ValueType>();
679*6777b538SAndroid Build Coastguard Worker GeneralStressTest<ValueType>();
680*6777b538SAndroid Build Coastguard Worker }
681*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,CopyOnlyWithDefaultConstructorTest)682*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, CopyOnlyWithDefaultConstructorTest) {
683*6777b538SAndroid Build Coastguard Worker using ValueType = Value_DmC;
684*6777b538SAndroid Build Coastguard Worker ValidateValueType<ValueType, true, false, true>();
685*6777b538SAndroid Build Coastguard Worker // We cannot perform CopyStressTest nor GeneralStressTest here, because
686*6777b538SAndroid Build Coastguard Worker // Value_DmC has deleted move constructor and assignment operator. See
687*6777b538SAndroid Build Coastguard Worker // crbug.com/1022576.
688*6777b538SAndroid Build Coastguard Worker }
689*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,CopyAndMoveWithDefaultConstructorTest)690*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, CopyAndMoveWithDefaultConstructorTest) {
691*6777b538SAndroid Build Coastguard Worker using ValueType = Value_DMC;
692*6777b538SAndroid Build Coastguard Worker ValidateValueType<ValueType, true, true, true>();
693*6777b538SAndroid Build Coastguard Worker CopyStressTest<ValueType>();
694*6777b538SAndroid Build Coastguard Worker MoveStressTest<ValueType>();
695*6777b538SAndroid Build Coastguard Worker GeneralStressTest<ValueType>();
696*6777b538SAndroid Build Coastguard Worker }
697*6777b538SAndroid Build Coastguard Worker
698*6777b538SAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
699*6777b538SAndroid Build Coastguard Worker // TEST SUITE 3
700*6777b538SAndroid Build Coastguard Worker //
701*6777b538SAndroid Build Coastguard Worker // Tests individual functions on a custom type that provides heap handle storage
702*6777b538SAndroid Build Coastguard Worker // externally through raw pointers.
703*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,Basic)704*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, Basic) {
705*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
706*6777b538SAndroid Build Coastguard Worker
707*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap.empty());
708*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0u, heap.size());
709*6777b538SAndroid Build Coastguard Worker }
710*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,Clear)711*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, Clear) {
712*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
713*6777b538SAndroid Build Coastguard Worker HeapHandle index1;
714*6777b538SAndroid Build Coastguard Worker
715*6777b538SAndroid Build Coastguard Worker heap.insert({11, &index1});
716*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(1u, heap.size());
717*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index1.IsValid());
718*6777b538SAndroid Build Coastguard Worker
719*6777b538SAndroid Build Coastguard Worker heap.clear();
720*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0u, heap.size());
721*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index1.IsValid());
722*6777b538SAndroid Build Coastguard Worker }
723*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,Destructor)724*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, Destructor) {
725*6777b538SAndroid Build Coastguard Worker HeapHandle index1;
726*6777b538SAndroid Build Coastguard Worker
727*6777b538SAndroid Build Coastguard Worker {
728*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
729*6777b538SAndroid Build Coastguard Worker
730*6777b538SAndroid Build Coastguard Worker heap.insert({11, &index1});
731*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(1u, heap.size());
732*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index1.IsValid());
733*6777b538SAndroid Build Coastguard Worker }
734*6777b538SAndroid Build Coastguard Worker
735*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index1.IsValid());
736*6777b538SAndroid Build Coastguard Worker }
737*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,Min)738*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, Min) {
739*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
740*6777b538SAndroid Build Coastguard Worker
741*6777b538SAndroid Build Coastguard Worker heap.insert({9, nullptr});
742*6777b538SAndroid Build Coastguard Worker heap.insert({10, nullptr});
743*6777b538SAndroid Build Coastguard Worker heap.insert({8, nullptr});
744*6777b538SAndroid Build Coastguard Worker heap.insert({2, nullptr});
745*6777b538SAndroid Build Coastguard Worker heap.insert({7, nullptr});
746*6777b538SAndroid Build Coastguard Worker heap.insert({15, nullptr});
747*6777b538SAndroid Build Coastguard Worker heap.insert({22, nullptr});
748*6777b538SAndroid Build Coastguard Worker heap.insert({3, nullptr});
749*6777b538SAndroid Build Coastguard Worker
750*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap.empty());
751*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(8u, heap.size());
752*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(2, heap.top().key);
753*6777b538SAndroid Build Coastguard Worker }
754*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,MinDuplicates)755*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, MinDuplicates) {
756*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
757*6777b538SAndroid Build Coastguard Worker
758*6777b538SAndroid Build Coastguard Worker heap.insert({2, nullptr});
759*6777b538SAndroid Build Coastguard Worker heap.insert({2, nullptr});
760*6777b538SAndroid Build Coastguard Worker heap.insert({3, nullptr});
761*6777b538SAndroid Build Coastguard Worker
762*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap.empty());
763*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(3u, heap.size());
764*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(2, heap.top().key);
765*6777b538SAndroid Build Coastguard Worker }
766*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,InsertAscending)767*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, InsertAscending) {
768*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
769*6777b538SAndroid Build Coastguard Worker
770*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 50; i++)
771*6777b538SAndroid Build Coastguard Worker heap.insert({i, nullptr});
772*6777b538SAndroid Build Coastguard Worker
773*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0, heap.top().key);
774*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(50u, heap.size());
775*6777b538SAndroid Build Coastguard Worker }
776*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,InsertDescending)777*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, InsertDescending) {
778*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
779*6777b538SAndroid Build Coastguard Worker
780*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 50; i++)
781*6777b538SAndroid Build Coastguard Worker heap.insert({50 - i, nullptr});
782*6777b538SAndroid Build Coastguard Worker
783*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(1, heap.top().key);
784*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(50u, heap.size());
785*6777b538SAndroid Build Coastguard Worker }
786*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,HeapIndex)787*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, HeapIndex) {
788*6777b538SAndroid Build Coastguard Worker HeapHandle index5;
789*6777b538SAndroid Build Coastguard Worker HeapHandle index4;
790*6777b538SAndroid Build Coastguard Worker HeapHandle index3;
791*6777b538SAndroid Build Coastguard Worker HeapHandle index2;
792*6777b538SAndroid Build Coastguard Worker HeapHandle index1;
793*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
794*6777b538SAndroid Build Coastguard Worker
795*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index1.IsValid());
796*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index2.IsValid());
797*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index3.IsValid());
798*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index4.IsValid());
799*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index5.IsValid());
800*6777b538SAndroid Build Coastguard Worker
801*6777b538SAndroid Build Coastguard Worker heap.insert({15, &index5});
802*6777b538SAndroid Build Coastguard Worker heap.insert({14, &index4});
803*6777b538SAndroid Build Coastguard Worker heap.insert({13, &index3});
804*6777b538SAndroid Build Coastguard Worker heap.insert({12, &index2});
805*6777b538SAndroid Build Coastguard Worker heap.insert({11, &index1});
806*6777b538SAndroid Build Coastguard Worker
807*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index1.IsValid());
808*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index2.IsValid());
809*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index3.IsValid());
810*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index4.IsValid());
811*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index5.IsValid());
812*6777b538SAndroid Build Coastguard Worker
813*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap.empty());
814*6777b538SAndroid Build Coastguard Worker }
815*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,HeapIndexDuplicates)816*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, HeapIndexDuplicates) {
817*6777b538SAndroid Build Coastguard Worker HeapHandle index2;
818*6777b538SAndroid Build Coastguard Worker HeapHandle index1;
819*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
820*6777b538SAndroid Build Coastguard Worker
821*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index1.IsValid());
822*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index2.IsValid());
823*6777b538SAndroid Build Coastguard Worker
824*6777b538SAndroid Build Coastguard Worker heap.insert({2, &index2});
825*6777b538SAndroid Build Coastguard Worker heap.insert({2, &index1});
826*6777b538SAndroid Build Coastguard Worker
827*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index1.IsValid());
828*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index2.IsValid());
829*6777b538SAndroid Build Coastguard Worker
830*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(2U, heap.size());
831*6777b538SAndroid Build Coastguard Worker }
832*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,Pop)833*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, Pop) {
834*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
835*6777b538SAndroid Build Coastguard Worker HeapHandle index1;
836*6777b538SAndroid Build Coastguard Worker HeapHandle index2;
837*6777b538SAndroid Build Coastguard Worker
838*6777b538SAndroid Build Coastguard Worker heap.insert({11, &index1});
839*6777b538SAndroid Build Coastguard Worker heap.insert({12, &index2});
840*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(2u, heap.size());
841*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index1.IsValid());
842*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index2.IsValid());
843*6777b538SAndroid Build Coastguard Worker
844*6777b538SAndroid Build Coastguard Worker heap.pop();
845*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(1u, heap.size());
846*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index1.IsValid());
847*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index2.IsValid());
848*6777b538SAndroid Build Coastguard Worker
849*6777b538SAndroid Build Coastguard Worker heap.pop();
850*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0u, heap.size());
851*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index1.IsValid());
852*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index2.IsValid());
853*6777b538SAndroid Build Coastguard Worker }
854*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,PopMany)855*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, PopMany) {
856*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
857*6777b538SAndroid Build Coastguard Worker
858*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 500; i++)
859*6777b538SAndroid Build Coastguard Worker heap.insert({i, nullptr});
860*6777b538SAndroid Build Coastguard Worker
861*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap.empty());
862*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(500u, heap.size());
863*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 500; i++) {
864*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(i, heap.top().key);
865*6777b538SAndroid Build Coastguard Worker heap.pop();
866*6777b538SAndroid Build Coastguard Worker }
867*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap.empty());
868*6777b538SAndroid Build Coastguard Worker }
869*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,Erase)870*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, Erase) {
871*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
872*6777b538SAndroid Build Coastguard Worker
873*6777b538SAndroid Build Coastguard Worker HeapHandle index12;
874*6777b538SAndroid Build Coastguard Worker
875*6777b538SAndroid Build Coastguard Worker heap.insert({15, nullptr});
876*6777b538SAndroid Build Coastguard Worker heap.insert({14, nullptr});
877*6777b538SAndroid Build Coastguard Worker heap.insert({13, nullptr});
878*6777b538SAndroid Build Coastguard Worker heap.insert({12, &index12});
879*6777b538SAndroid Build Coastguard Worker heap.insert({11, nullptr});
880*6777b538SAndroid Build Coastguard Worker
881*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(5u, heap.size());
882*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(index12.IsValid());
883*6777b538SAndroid Build Coastguard Worker heap.erase(index12);
884*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(4u, heap.size());
885*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(index12.IsValid());
886*6777b538SAndroid Build Coastguard Worker
887*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(11, heap.top().key);
888*6777b538SAndroid Build Coastguard Worker heap.pop();
889*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(13, heap.top().key);
890*6777b538SAndroid Build Coastguard Worker heap.pop();
891*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(14, heap.top().key);
892*6777b538SAndroid Build Coastguard Worker heap.pop();
893*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(15, heap.top().key);
894*6777b538SAndroid Build Coastguard Worker heap.pop();
895*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap.empty());
896*6777b538SAndroid Build Coastguard Worker }
897*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,ReplaceTop)898*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, ReplaceTop) {
899*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
900*6777b538SAndroid Build Coastguard Worker
901*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 500; i++)
902*6777b538SAndroid Build Coastguard Worker heap.insert({500 - i, nullptr});
903*6777b538SAndroid Build Coastguard Worker
904*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(1, heap.top().key);
905*6777b538SAndroid Build Coastguard Worker
906*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 500; i++)
907*6777b538SAndroid Build Coastguard Worker heap.ReplaceTop({1000 + i, nullptr});
908*6777b538SAndroid Build Coastguard Worker
909*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(1000, heap.top().key);
910*6777b538SAndroid Build Coastguard Worker }
911*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,ReplaceTopWithNonLeafNode)912*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, ReplaceTopWithNonLeafNode) {
913*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
914*6777b538SAndroid Build Coastguard Worker
915*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 50; i++) {
916*6777b538SAndroid Build Coastguard Worker heap.insert({i, nullptr});
917*6777b538SAndroid Build Coastguard Worker heap.insert({200 + i, nullptr});
918*6777b538SAndroid Build Coastguard Worker }
919*6777b538SAndroid Build Coastguard Worker
920*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(0, heap.top().key);
921*6777b538SAndroid Build Coastguard Worker
922*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 50; i++)
923*6777b538SAndroid Build Coastguard Worker heap.ReplaceTop({100 + i, nullptr});
924*6777b538SAndroid Build Coastguard Worker
925*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 50; i++) {
926*6777b538SAndroid Build Coastguard Worker EXPECT_EQ((100 + i), heap.top().key);
927*6777b538SAndroid Build Coastguard Worker heap.pop();
928*6777b538SAndroid Build Coastguard Worker }
929*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 50; i++) {
930*6777b538SAndroid Build Coastguard Worker EXPECT_EQ((200 + i), heap.top().key);
931*6777b538SAndroid Build Coastguard Worker heap.pop();
932*6777b538SAndroid Build Coastguard Worker }
933*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap.empty());
934*6777b538SAndroid Build Coastguard Worker }
935*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,ReplaceTopCheckAllFinalPositions)936*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, ReplaceTopCheckAllFinalPositions) {
937*6777b538SAndroid Build Coastguard Worker HeapHandle index[100];
938*6777b538SAndroid Build Coastguard Worker HeapHandle top_index;
939*6777b538SAndroid Build Coastguard Worker
940*6777b538SAndroid Build Coastguard Worker for (int j = -1; j <= 201; j += 2) {
941*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
942*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < 100; i++) {
943*6777b538SAndroid Build Coastguard Worker heap.insert({static_cast<int>(i) * 2, &index[i]});
944*6777b538SAndroid Build Coastguard Worker }
945*6777b538SAndroid Build Coastguard Worker
946*6777b538SAndroid Build Coastguard Worker heap.ReplaceTop({j, &top_index});
947*6777b538SAndroid Build Coastguard Worker
948*6777b538SAndroid Build Coastguard Worker int prev = -2;
949*6777b538SAndroid Build Coastguard Worker while (!heap.empty()) {
950*6777b538SAndroid Build Coastguard Worker DCHECK_GT(heap.top().key, prev);
951*6777b538SAndroid Build Coastguard Worker DCHECK(heap.top().key == j || (heap.top().key % 2) == 0);
952*6777b538SAndroid Build Coastguard Worker DCHECK_NE(heap.top().key, 0);
953*6777b538SAndroid Build Coastguard Worker prev = heap.top().key;
954*6777b538SAndroid Build Coastguard Worker heap.pop();
955*6777b538SAndroid Build Coastguard Worker }
956*6777b538SAndroid Build Coastguard Worker }
957*6777b538SAndroid Build Coastguard Worker }
958*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,ReplaceUp)959*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, ReplaceUp) {
960*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
961*6777b538SAndroid Build Coastguard Worker HeapHandle index[10];
962*6777b538SAndroid Build Coastguard Worker
963*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < 10; i++) {
964*6777b538SAndroid Build Coastguard Worker heap.insert({static_cast<int>(i) * 2, &index[i]});
965*6777b538SAndroid Build Coastguard Worker }
966*6777b538SAndroid Build Coastguard Worker
967*6777b538SAndroid Build Coastguard Worker heap.Replace(index[5], {17, &index[5]});
968*6777b538SAndroid Build Coastguard Worker
969*6777b538SAndroid Build Coastguard Worker std::vector<int> results;
970*6777b538SAndroid Build Coastguard Worker while (!heap.empty()) {
971*6777b538SAndroid Build Coastguard Worker results.push_back(heap.top().key);
972*6777b538SAndroid Build Coastguard Worker heap.pop();
973*6777b538SAndroid Build Coastguard Worker }
974*6777b538SAndroid Build Coastguard Worker
975*6777b538SAndroid Build Coastguard Worker EXPECT_THAT(results, testing::ElementsAre(0, 2, 4, 6, 8, 12, 14, 16, 17, 18));
976*6777b538SAndroid Build Coastguard Worker }
977*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,ReplaceUpButDoesntMove)978*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, ReplaceUpButDoesntMove) {
979*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
980*6777b538SAndroid Build Coastguard Worker HeapHandle index[10];
981*6777b538SAndroid Build Coastguard Worker
982*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < 10; i++) {
983*6777b538SAndroid Build Coastguard Worker heap.insert({static_cast<int>(i) * 2, &index[i]});
984*6777b538SAndroid Build Coastguard Worker }
985*6777b538SAndroid Build Coastguard Worker
986*6777b538SAndroid Build Coastguard Worker heap.Replace(index[5], {11, &index[5]});
987*6777b538SAndroid Build Coastguard Worker
988*6777b538SAndroid Build Coastguard Worker std::vector<int> results;
989*6777b538SAndroid Build Coastguard Worker while (!heap.empty()) {
990*6777b538SAndroid Build Coastguard Worker results.push_back(heap.top().key);
991*6777b538SAndroid Build Coastguard Worker heap.pop();
992*6777b538SAndroid Build Coastguard Worker }
993*6777b538SAndroid Build Coastguard Worker
994*6777b538SAndroid Build Coastguard Worker EXPECT_THAT(results, testing::ElementsAre(0, 2, 4, 6, 8, 11, 12, 14, 16, 18));
995*6777b538SAndroid Build Coastguard Worker }
996*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,ReplaceDown)997*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, ReplaceDown) {
998*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
999*6777b538SAndroid Build Coastguard Worker HeapHandle index[10];
1000*6777b538SAndroid Build Coastguard Worker
1001*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < 10; i++) {
1002*6777b538SAndroid Build Coastguard Worker heap.insert({static_cast<int>(i) * 2, &index[i]});
1003*6777b538SAndroid Build Coastguard Worker }
1004*6777b538SAndroid Build Coastguard Worker
1005*6777b538SAndroid Build Coastguard Worker heap.Replace(index[5], {1, &index[5]});
1006*6777b538SAndroid Build Coastguard Worker
1007*6777b538SAndroid Build Coastguard Worker std::vector<int> results;
1008*6777b538SAndroid Build Coastguard Worker while (!heap.empty()) {
1009*6777b538SAndroid Build Coastguard Worker results.push_back(heap.top().key);
1010*6777b538SAndroid Build Coastguard Worker heap.pop();
1011*6777b538SAndroid Build Coastguard Worker }
1012*6777b538SAndroid Build Coastguard Worker
1013*6777b538SAndroid Build Coastguard Worker EXPECT_THAT(results, testing::ElementsAre(0, 1, 2, 4, 6, 8, 12, 14, 16, 18));
1014*6777b538SAndroid Build Coastguard Worker }
1015*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,ReplaceDownButDoesntMove)1016*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, ReplaceDownButDoesntMove) {
1017*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
1018*6777b538SAndroid Build Coastguard Worker HeapHandle index[10];
1019*6777b538SAndroid Build Coastguard Worker
1020*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < 10; i++) {
1021*6777b538SAndroid Build Coastguard Worker heap.insert({static_cast<int>(i) * 2, &index[i]});
1022*6777b538SAndroid Build Coastguard Worker }
1023*6777b538SAndroid Build Coastguard Worker
1024*6777b538SAndroid Build Coastguard Worker heap.Replace(index[5], {9, &index[5]});
1025*6777b538SAndroid Build Coastguard Worker
1026*6777b538SAndroid Build Coastguard Worker std::vector<int> results;
1027*6777b538SAndroid Build Coastguard Worker while (!heap.empty()) {
1028*6777b538SAndroid Build Coastguard Worker results.push_back(heap.top().key);
1029*6777b538SAndroid Build Coastguard Worker heap.pop();
1030*6777b538SAndroid Build Coastguard Worker }
1031*6777b538SAndroid Build Coastguard Worker
1032*6777b538SAndroid Build Coastguard Worker EXPECT_THAT(results, testing::ElementsAre(0, 2, 4, 6, 8, 9, 12, 14, 16, 18));
1033*6777b538SAndroid Build Coastguard Worker }
1034*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,ReplaceCheckAllFinalPositions)1035*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, ReplaceCheckAllFinalPositions) {
1036*6777b538SAndroid Build Coastguard Worker HeapHandle index[100];
1037*6777b538SAndroid Build Coastguard Worker
1038*6777b538SAndroid Build Coastguard Worker for (int j = -1; j <= 201; j += 2) {
1039*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
1040*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < 100; i++) {
1041*6777b538SAndroid Build Coastguard Worker heap.insert({static_cast<int>(i) * 2, &index[i]});
1042*6777b538SAndroid Build Coastguard Worker }
1043*6777b538SAndroid Build Coastguard Worker
1044*6777b538SAndroid Build Coastguard Worker heap.Replace(index[40], {j, &index[40]});
1045*6777b538SAndroid Build Coastguard Worker
1046*6777b538SAndroid Build Coastguard Worker int prev = -2;
1047*6777b538SAndroid Build Coastguard Worker while (!heap.empty()) {
1048*6777b538SAndroid Build Coastguard Worker DCHECK_GT(heap.top().key, prev);
1049*6777b538SAndroid Build Coastguard Worker DCHECK(heap.top().key == j || (heap.top().key % 2) == 0);
1050*6777b538SAndroid Build Coastguard Worker DCHECK_NE(heap.top().key, 80);
1051*6777b538SAndroid Build Coastguard Worker prev = heap.top().key;
1052*6777b538SAndroid Build Coastguard Worker heap.pop();
1053*6777b538SAndroid Build Coastguard Worker }
1054*6777b538SAndroid Build Coastguard Worker }
1055*6777b538SAndroid Build Coastguard Worker }
1056*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,At)1057*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, At) {
1058*6777b538SAndroid Build Coastguard Worker HeapHandle index[10];
1059*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
1060*6777b538SAndroid Build Coastguard Worker
1061*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 10; i++)
1062*6777b538SAndroid Build Coastguard Worker heap.insert({static_cast<int>(i ^ (i + 1)), &index[i]});
1063*6777b538SAndroid Build Coastguard Worker
1064*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 10; i++) {
1065*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(heap.at(index[i]).key, i ^ (i + 1));
1066*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(heap.at(index[i]).handle, &index[i]);
1067*6777b538SAndroid Build Coastguard Worker }
1068*6777b538SAndroid Build Coastguard Worker }
1069*6777b538SAndroid Build Coastguard Worker
IsEven(int i)1070*6777b538SAndroid Build Coastguard Worker bool IsEven(int i) {
1071*6777b538SAndroid Build Coastguard Worker return i % 2 == 0;
1072*6777b538SAndroid Build Coastguard Worker }
1073*6777b538SAndroid Build Coastguard Worker
TEST(IntrusiveHeapTest,EraseIf)1074*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, EraseIf) {
1075*6777b538SAndroid Build Coastguard Worker HeapHandle index[10];
1076*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<TestElement> heap;
1077*6777b538SAndroid Build Coastguard Worker
1078*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 10; i++)
1079*6777b538SAndroid Build Coastguard Worker heap.insert({i, &index[i]});
1080*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(heap.size(), 10u);
1081*6777b538SAndroid Build Coastguard Worker
1082*6777b538SAndroid Build Coastguard Worker // Remove all even elements.
1083*6777b538SAndroid Build Coastguard Worker heap.EraseIf([](const TestElement& element) { return IsEven(element.key); });
1084*6777b538SAndroid Build Coastguard Worker ASSERT_EQ(heap.size(), 5u);
1085*6777b538SAndroid Build Coastguard Worker
1086*6777b538SAndroid Build Coastguard Worker // Handles were correctly updated.
1087*6777b538SAndroid Build Coastguard Worker for (int i = 0; i < 10; i++)
1088*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(IsEven(i), !index[i].IsValid());
1089*6777b538SAndroid Build Coastguard Worker
1090*6777b538SAndroid Build Coastguard Worker // Now iterate over all elements of the heap and check their handles.
1091*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < heap.size(); i++) {
1092*6777b538SAndroid Build Coastguard Worker auto it = heap.begin();
1093*6777b538SAndroid Build Coastguard Worker std::advance(it, i);
1094*6777b538SAndroid Build Coastguard Worker
1095*6777b538SAndroid Build Coastguard Worker // Retrieve the value of the element at this position.
1096*6777b538SAndroid Build Coastguard Worker int value = it->key;
1097*6777b538SAndroid Build Coastguard Worker
1098*6777b538SAndroid Build Coastguard Worker // Its handle should have the correct index.
1099*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(index[value].index(), i);
1100*6777b538SAndroid Build Coastguard Worker }
1101*6777b538SAndroid Build Coastguard Worker
1102*6777b538SAndroid Build Coastguard Worker std::vector<int> results;
1103*6777b538SAndroid Build Coastguard Worker while (!heap.empty()) {
1104*6777b538SAndroid Build Coastguard Worker results.push_back(heap.top().key);
1105*6777b538SAndroid Build Coastguard Worker heap.pop();
1106*6777b538SAndroid Build Coastguard Worker }
1107*6777b538SAndroid Build Coastguard Worker
1108*6777b538SAndroid Build Coastguard Worker EXPECT_THAT(results, testing::ElementsAre(1, 3, 5, 7, 9));
1109*6777b538SAndroid Build Coastguard Worker }
1110*6777b538SAndroid Build Coastguard Worker
1111*6777b538SAndroid Build Coastguard Worker // A comparator class whose sole purpose is to allow the insertion of a
1112*6777b538SAndroid Build Coastguard Worker // ScopedClosureRunner inside the heap. The ordering does not matter.
1113*6777b538SAndroid Build Coastguard Worker class Comparator {
1114*6777b538SAndroid Build Coastguard Worker public:
operator ()(const WithHeapHandle<ScopedClosureRunner> & lhs,const WithHeapHandle<ScopedClosureRunner> & rhs)1115*6777b538SAndroid Build Coastguard Worker bool operator()(const WithHeapHandle<ScopedClosureRunner>& lhs,
1116*6777b538SAndroid Build Coastguard Worker const WithHeapHandle<ScopedClosureRunner>& rhs) {
1117*6777b538SAndroid Build Coastguard Worker // Treat all closures as equal.
1118*6777b538SAndroid Build Coastguard Worker return true;
1119*6777b538SAndroid Build Coastguard Worker }
1120*6777b538SAndroid Build Coastguard Worker };
1121*6777b538SAndroid Build Coastguard Worker
1122*6777b538SAndroid Build Coastguard Worker // Tests that inserting another element from the destructor of an object removed
1123*6777b538SAndroid Build Coastguard Worker // during EraseIf() doesn't crash.
TEST(IntrusiveHeapTest,EraseIf_Reentrancy)1124*6777b538SAndroid Build Coastguard Worker TEST(IntrusiveHeapTest, EraseIf_Reentrancy) {
1125*6777b538SAndroid Build Coastguard Worker IntrusiveHeap<WithHeapHandle<ScopedClosureRunner>, Comparator> heap;
1126*6777b538SAndroid Build Coastguard Worker
1127*6777b538SAndroid Build Coastguard Worker // The task that will post a new element inside the heap upon destruction of
1128*6777b538SAndroid Build Coastguard Worker // the first.
1129*6777b538SAndroid Build Coastguard Worker OnceClosure insert_task = BindLambdaForTesting([&]() {
1130*6777b538SAndroid Build Coastguard Worker // Insert a null callback so it can be differentiated.
1131*6777b538SAndroid Build Coastguard Worker heap.insert(OnceClosure());
1132*6777b538SAndroid Build Coastguard Worker });
1133*6777b538SAndroid Build Coastguard Worker heap.insert(ScopedClosureRunner(std::move(insert_task)));
1134*6777b538SAndroid Build Coastguard Worker
1135*6777b538SAndroid Build Coastguard Worker // The heap contains the non-null closure.
1136*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(heap.size(), 1u);
1137*6777b538SAndroid Build Coastguard Worker EXPECT_TRUE(heap.top().value());
1138*6777b538SAndroid Build Coastguard Worker
1139*6777b538SAndroid Build Coastguard Worker // Erase the only element using EraseIf().
1140*6777b538SAndroid Build Coastguard Worker heap.EraseIf([](const auto& element) { return true; });
1141*6777b538SAndroid Build Coastguard Worker
1142*6777b538SAndroid Build Coastguard Worker // Now the heap contains the null closure.
1143*6777b538SAndroid Build Coastguard Worker EXPECT_EQ(heap.size(), 1u);
1144*6777b538SAndroid Build Coastguard Worker EXPECT_FALSE(heap.top().value());
1145*6777b538SAndroid Build Coastguard Worker }
1146*6777b538SAndroid Build Coastguard Worker
1147*6777b538SAndroid Build Coastguard Worker } // namespace base
1148