Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(147)

Side by Side Diff: third_party/WebKit/Source/platform/scheduler/base/intrusive_heap.h

Issue 2421283002: Revert of Optimize blink scheduler with an intrusive heap (Closed)
Patch Set: Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_INTRUSIVE_HEAP_H_
6 #define THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_INTRUSIVE_HEAP_H_
7
8 #include <algorithm>
9 #include <vector>
10
11 #include "base/logging.h"
12
13 namespace blink {
14 namespace scheduler {
15
16 template <typename T>
17 class IntrusiveHeap;
18
19 // Intended as an opaque wrapper around |index_|.
20 class HeapHandle {
21 public:
22 HeapHandle() : index_(0u) {}
23
24 bool IsValid() const { return index_ != 0u; }
25
26 private:
27 template <typename T>
28 friend class IntrusiveHeap;
29
30 HeapHandle(size_t index) : index_(index) {}
31
32 size_t index_;
33 };
34
35 // A standard min-heap with the following assumptions:
36 // 1. T has operator <=
37 // 2. T has method void SetHeapHandle(HeapHandle handle)
38 // 3. T is moveable
39 // 4. T is default constructible
40 // 5. The heap size never gets terribly big so reclaiming memory on pop/erase
41 // isn't a priority.
42 //
43 // The reason IntrusiveHeap exists is to provide similar performance to
44 // std::priority_queue while allowing removal of arbitrary elements.
45 template <typename T>
46 class IntrusiveHeap {
47 public:
48 IntrusiveHeap() : nodes_(kMinimumHeapSize), size_(0) {}
49
50 bool empty() const { return size_ == 0; }
51
52 size_t size() const { return size_; }
53
54 void clear() {
55 nodes_.resize(kMinimumHeapSize);
56 size_ = 0;
57 }
58
59 const T& min() const {
60 DCHECK_GE(size_, 1u);
61 return nodes_[1];
62 }
63
64 void pop() {
65 DCHECK_GE(size_, 1u);
66 size_t top_index = size_--;
67 MakeHole(1u);
68 if (!empty())
69 MoveHoleDownAndFillWithLeafElement(1u, std::move(nodes_[top_index]));
70 }
71
72 void insert(T&& element) {
73 size_++;
74 if (size_ >= nodes_.size())
75 nodes_.resize(size_ * 2);
76 // Notionally we have a hole in the tree at index |size_|, move this up
77 // to find the right insertion point.
78 MoveHoleUpAndFillWithElement(size_, std::move(element));
79 }
80
81 void erase(HeapHandle handle) {
82 DCHECK_GT(handle.index_, 0u);
83 DCHECK_LE(handle.index_, size_);
84 size_t top_index = size_--;
85 if (empty() || top_index == handle.index_)
86 return;
87 MakeHole(handle.index_);
88 if (nodes_[handle.index_] <= nodes_[top_index]) {
89 MoveHoleDownAndFillWithLeafElement(handle.index_,
90 std::move(nodes_[top_index]));
91 } else {
92 MoveHoleUpAndFillWithElement(handle.index_, std::move(nodes_[top_index]));
93 }
94 }
95
96 void ReplaceMin(T&& element) {
97 // Note |element| might not be a leaf node so we can't use
98 // MoveHoleDownAndFillWithLeafElement.
99 MoveHoleDownAndFillWithElement(1u, std::move(element));
100 }
101
102 // Caution mutating the heap invalidates the iterators.
103 const T* begin() const { return &nodes_[1u]; }
104 const T* end() const { return &nodes_[size_ + 1]; }
105
106 private:
107 enum {
108 // The majority of sets in the scheduler have 0-3 items in them (a few will
109 // have perhaps up to 100), so this means we usually only have to allocate
110 // memory once.
111 kMinimumHeapSize = 4u
112 };
113
114 size_t MoveHole(size_t new_hole_pos, size_t old_hole_pos) {
115 DCHECK_GT(new_hole_pos, 0u);
116 DCHECK_LE(new_hole_pos, size_);
117 DCHECK_GT(new_hole_pos, 0u);
118 DCHECK_LE(new_hole_pos, size_);
119 DCHECK_NE(old_hole_pos, new_hole_pos);
120 nodes_[old_hole_pos] = std::move(nodes_[new_hole_pos]);
121 nodes_[old_hole_pos].SetHeapHandle(HeapHandle(old_hole_pos));
122 return new_hole_pos;
123 }
124
125 // Notionally creates a hole in the tree at |index|.
126 void MakeHole(size_t index) { nodes_[index].SetHeapHandle(HeapHandle(0u)); }
127
128 void FillHole(size_t hole, T&& element) {
129 nodes_[hole] = std::move(element);
130 nodes_[hole].SetHeapHandle(HeapHandle(hole));
131
132 DCHECK(std::is_heap(begin(), end(), CompareNodes));
133 }
134
135 static bool CompareNodes(const T& a, const T& b) { return b <= a; }
136
137 // Moves the |hole| up the tree and when the right position has been found
138 // |element| is moved in.
139 void MoveHoleUpAndFillWithElement(size_t hole, T&& element) {
140 DCHECK_GT(hole, 0u);
141 DCHECK_LE(hole, size_);
142 while (hole >= 2u) {
143 size_t parent_pos = hole / 2;
144 if (nodes_[parent_pos] <= element)
145 break;
146
147 hole = MoveHole(parent_pos, hole);
148 }
149 FillHole(hole, std::move(element));
150 }
151
152 // Moves the |hole| down the tree and when the right position has been found
153 // |element| is moved in.
154 void MoveHoleDownAndFillWithElement(size_t hole, T&& element) {
155 DCHECK_GT(hole, 0u);
156 DCHECK_LE(hole, size_);
157 size_t child_pos = hole * 2;
158 while (child_pos < size_) {
159 if (nodes_[child_pos + 1] <= nodes_[child_pos])
160 child_pos++;
161
162 if (element <= nodes_[child_pos])
163 break;
164
165 hole = MoveHole(child_pos, hole);
166 child_pos *= 2;
167 }
168 if (child_pos == size_ && !(element <= nodes_[child_pos]))
169 hole = MoveHole(child_pos, hole);
170 FillHole(hole, std::move(element));
171 }
172
173 // Moves the |hole| down the tree and when the right position has been found
174 // |leaf_element| is moved in. Faster than MoveHoleDownAndFillWithElement
175 // (it does one key comparison per level instead of two) but only valid for
176 // leaf elements (i.e. one of the max values).
177 void MoveHoleDownAndFillWithLeafElement(size_t hole, T&& leaf_element) {
178 DCHECK_GT(hole, 0u);
179 DCHECK_LE(hole, size_);
180 size_t child_pos = hole * 2;
181 while (child_pos < size_) {
182 size_t second_child = child_pos + 1;
183 if (nodes_[second_child] <= nodes_[child_pos])
184 child_pos = second_child;
185
186 hole = MoveHole(child_pos, hole);
187 child_pos *= 2;
188 }
189 if (child_pos == size_)
190 hole = MoveHole(child_pos, hole);
191 MoveHoleUpAndFillWithElement(hole, std::move(leaf_element));
192 }
193
194 std::vector<T> nodes_; // NOTE we use 1-based indexing
195 size_t size_;
196 };
197
198 } // namespace scheduler
199 } // namespace blink
200
201 #endif // THIRD_PARTY_WEBKIT_SOURCE_PLATFORM_SCHEDULER_BASE_INTRUSIVE_HEAP_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698