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