Skip to content

Commit 333fd5b

Browse files
committed
Replace List with Pairing Heap in Task Queue
1 parent 8af74c6 commit 333fd5b

File tree

7 files changed

+770
-12
lines changed

7 files changed

+770
-12
lines changed
Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
/*
2+
* Copyright (c) 2015 Roc Streaming authors
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
7+
*/
8+
9+
//! @file roc_core/pairing_heap.h
10+
//! @brief Intrusive pairing heap.
11+
12+
#ifndef ROC_CORE_PAIRING_HEAP_H_
13+
#define ROC_CORE_PAIRING_HEAP_H_
14+
15+
#include "roc_core/noncopyable.h"
16+
#include "roc_core/ownership_policy.h"
17+
#include "roc_core/pairing_heap_node.h"
18+
#include "roc_core/panic.h"
19+
#include "roc_core/stddefs.h"
20+
21+
namespace roc {
22+
namespace core {
23+
24+
//! Intrusive pairing heap.
25+
//!
26+
//! Does not perform allocations.
27+
//! Provides O(1) size check, membership check, insertion, and removal.
28+
//!
29+
//! @tparam T defines object type, it should inherit PairingHeapNode.
30+
//!
31+
//! @tparam OwnershipPolicy defines ownership policy which is used to acquire an
32+
//! element ownership when it's added to the pairing heap and release ownership when it's
33+
//! removed from the pairing heap.
34+
template <class T, template <class TT> class OwnershipPolicy = RefCountedOwnership>
35+
class PairingHeap : public NonCopyable<> {
36+
public:
37+
//! Pointer type.
38+
//! @remarks
39+
//! either raw or smart pointer depending on the ownership policy.
40+
typedef typename OwnershipPolicy<T>::Pointer Pointer;
41+
42+
//! Initialize empty pairing heap.
43+
PairingHeap()
44+
: size_(0) {
45+
root_.leftmost_child = &root_;
46+
root_.prev = &root_;
47+
root_.next = &root_;
48+
root_.pairing_heap = this;
49+
}
50+
51+
//! Parse through pairing heap to release ownership of containing objects.
52+
~PairingHeap() {
53+
if ((root_.leftmost_child != &root_ && root_.leftmost_child != NULL)
54+
|| size_ > 0) {
55+
ReleasePairingHeapNode(root_.leftmost_child);
56+
}
57+
58+
root_.pairing_heap = NULL;
59+
}
60+
61+
//! Release ownership of containing objects.
62+
void ReleasePairingHeapNode(PairingHeapNode::PairingHeapNodeData* data) {
63+
roc_panic_if(data == NULL);
64+
check_is_member_(data, this);
65+
66+
if (data->leftmost_child != NULL) {
67+
ReleasePairingHeapNode(data->leftmost_child);
68+
}
69+
70+
if (data->next != NULL) {
71+
ReleasePairingHeapNode(data->next);
72+
}
73+
74+
data->pairing_heap = NULL;
75+
76+
OwnershipPolicy<T>::release(*container_of_(data));
77+
}
78+
79+
//! Get number of elements in pairing heap.
80+
size_t size() const {
81+
return size_;
82+
}
83+
84+
//! Check if element belongs to pairing heap.
85+
bool contains(const T& element) {
86+
const PairingHeapNode::PairingHeapNodeData* data =
87+
element.pairing_heap_node_data();
88+
return (data->pairing_heap == this);
89+
}
90+
91+
//! Get first pairing heap element.
92+
//! @returns
93+
//! first element or NULL if pairing heap is empty.
94+
Pointer top() const {
95+
if (size_ == 0) {
96+
return NULL;
97+
}
98+
return container_of_(root_.leftmost_child);
99+
}
100+
101+
//! Get pairing heap element next to given one.
102+
//!
103+
//! @returns
104+
//! pairing heap element following @p element if @p element is not
105+
//! the last sibling, or NULL otherwise.
106+
//!
107+
//! @pre
108+
//! @p element should be member of this pairing heap.
109+
Pointer next_sibling_of(T& element) const {
110+
PairingHeapNode::PairingHeapNodeData* data = element.pairing_heap_node_data();
111+
check_is_member_(data, this);
112+
113+
if (data->next == NULL) {
114+
return NULL;
115+
}
116+
return container_of_(data->next);
117+
}
118+
119+
//! Get pairing heap element previous to given one.
120+
//!
121+
//! @returns
122+
//! pairing heap element before @p element if @p element has a previous element, or
123+
//! NULL otherwise.
124+
//!
125+
//! @pre
126+
//! @p element should be member of this pairing heap.
127+
Pointer prev_sibling_of(T& element) const {
128+
PairingHeapNode::PairingHeapNodeData* data = element.pairing_heap_node_data();
129+
check_is_member_(data, this);
130+
131+
if (data->prev == NULL) {
132+
return NULL;
133+
}
134+
return container_of_(data->prev);
135+
}
136+
137+
//! Get pairing heap element child of given one.
138+
//!
139+
//! @returns
140+
//! pairing heap element child of @p element if @p element has a child element, or
141+
//! NULL otherwise.
142+
//!
143+
//! @pre
144+
//! @p element should be member of this pairing heap.
145+
Pointer child_of(T& element) const {
146+
PairingHeapNode::PairingHeapNodeData* data = element.pairing_heap_node_data();
147+
check_is_member_(data, this);
148+
149+
if (data->leftmost_child == NULL) {
150+
return NULL;
151+
}
152+
return container_of_(data->leftmost_child);
153+
}
154+
155+
//! Inserts first element to pairing heap.
156+
//!
157+
//! @remarks
158+
//! - appends @p element to pairing heap
159+
//! - acquires ownership of @p element
160+
//!
161+
//! @pre
162+
//! @p element should not be member of any pairing heap and should be the first
163+
//! element in the heap.
164+
void push(T& element) {
165+
insert_as_child(element, NULL);
166+
}
167+
168+
//! Insert element into pairing heap as a child of an existing element.
169+
//!
170+
//! @remarks
171+
//! - inserts @p new_child as a child of @p parent element
172+
//! - acquires ownership of @p new_child
173+
//!
174+
//! @pre
175+
//! @p new_child should not be member of any pairing heap.
176+
//! @p parent should be member of this pairing heap.
177+
void push_as_child(T& new_child, T& parent) {
178+
insert_as_child(new_child, &parent);
179+
}
180+
181+
//! Insert element into pairing heap as a parent of an existing element.
182+
//!
183+
//! @remarks
184+
//! - inserts @p new_parent as parent of @p child element
185+
//! - acquires ownership of @p new_parent
186+
//!
187+
//! @pre
188+
//! @p new_parent should not be member of any pairing heap.
189+
//! @p child should be member of this pairing heap.
190+
void push_as_parent(T& new_parent, T& child) {
191+
insert_as_parent(new_parent, &child);
192+
}
193+
194+
//! Merge two pairing heap elements by parenting first given element to second given
195+
//! element.
196+
//!
197+
//! @returns
198+
//! the @p parent_element pairing heap element
199+
//!
200+
//! @pre
201+
//! @p parent_element and @p child_element should be members of this pairing heap.
202+
Pointer merge(T& parent_element, T& child_element) const {
203+
PairingHeapNode::PairingHeapNodeData* parent =
204+
parent_element.pairing_heap_node_data();
205+
PairingHeapNode::PairingHeapNodeData* child =
206+
child_element.pairing_heap_node_data();
207+
208+
check_is_member_(parent, this);
209+
check_is_member_(child, this);
210+
211+
if (child->prev->leftmost_child == child) {
212+
child->prev->leftmost_child = parent;
213+
parent->prev = child->prev;
214+
child->prev = parent;
215+
} else {
216+
if (parent->next == child) {
217+
parent->next = child->next;
218+
if (child->next != NULL) {
219+
child->next->prev = parent;
220+
}
221+
} else {
222+
parent->prev = child->prev;
223+
}
224+
}
225+
226+
if (parent->leftmost_child != NULL) {
227+
parent->leftmost_child->prev = child;
228+
}
229+
230+
child->next = parent->leftmost_child;
231+
parent->leftmost_child = child;
232+
233+
return container_of_(parent);
234+
}
235+
236+
//! Remove element from pairing heap.
237+
//!
238+
//! @remarks
239+
//! - removes @p element from pairing heap
240+
//! - releases ownership of @p element
241+
//!
242+
//! @pre
243+
//! @p element should be member of this pairing heap.
244+
void remove(T& element) {
245+
PairingHeapNode::PairingHeapNodeData* data = element.pairing_heap_node_data();
246+
check_is_member_(data, this);
247+
248+
PairingHeapNode::PairingHeapNodeData* data_child = data->leftmost_child;
249+
250+
if (data_child != NULL) {
251+
data_child->prev = data->prev;
252+
data_child->next = data->next;
253+
254+
if (data->prev->leftmost_child == data) {
255+
data->prev->leftmost_child = data_child;
256+
} else {
257+
data->prev->next = data_child;
258+
}
259+
} else {
260+
if (data->prev->leftmost_child == data) {
261+
data->prev->leftmost_child = data->next;
262+
} else {
263+
if (data->prev == &root_) {
264+
data->prev->next = &root_;
265+
} else {
266+
data->prev->next = data->next;
267+
}
268+
}
269+
}
270+
271+
data->pairing_heap = NULL;
272+
273+
size_--;
274+
275+
OwnershipPolicy<T>::release(element);
276+
}
277+
278+
private:
279+
static inline T* container_of_(PairingHeapNode::PairingHeapNodeData* data) {
280+
return static_cast<T*>(data->container_of());
281+
}
282+
283+
static void check_is_member_(const PairingHeapNode::PairingHeapNodeData* data,
284+
const PairingHeap* pairing_heap) {
285+
if (data->pairing_heap != pairing_heap) {
286+
roc_panic("pairing heap element is member of wrong pairing heap: expected "
287+
"%p, got %p",
288+
(const void*)pairing_heap, (const void*)data->pairing_heap);
289+
}
290+
}
291+
292+
void insert_as_child(T& new_child, T* parent) {
293+
PairingHeapNode::PairingHeapNodeData* data_new =
294+
new_child.pairing_heap_node_data();
295+
check_is_member_(data_new, NULL);
296+
297+
PairingHeapNode::PairingHeapNodeData* data_parent;
298+
if (parent != NULL) {
299+
data_parent = parent->pairing_heap_node_data();
300+
check_is_member_(data_parent, this);
301+
302+
if (data_parent->leftmost_child != NULL) {
303+
data_new->next = data_parent->leftmost_child;
304+
data_parent->leftmost_child->prev = data_new;
305+
}
306+
307+
} else {
308+
data_parent = &root_;
309+
}
310+
311+
data_new->prev = data_parent;
312+
data_parent->leftmost_child = data_new;
313+
314+
data_new->pairing_heap = this;
315+
316+
size_++;
317+
318+
OwnershipPolicy<T>::acquire(new_child);
319+
}
320+
321+
void insert_as_parent(T& new_parent, T* child) {
322+
PairingHeapNode::PairingHeapNodeData* data_new =
323+
new_parent.pairing_heap_node_data();
324+
check_is_member_(data_new, NULL);
325+
326+
PairingHeapNode::PairingHeapNodeData* data_child =
327+
child->pairing_heap_node_data();
328+
329+
data_new->prev = data_child->prev;
330+
data_new->leftmost_child = data_child;
331+
332+
data_child->prev->leftmost_child = data_new;
333+
data_child->prev = data_new;
334+
335+
data_new->pairing_heap = this;
336+
337+
size_++;
338+
339+
OwnershipPolicy<T>::acquire(new_parent);
340+
}
341+
342+
PairingHeapNode::PairingHeapNodeData root_;
343+
size_t size_;
344+
};
345+
346+
} // namespace core
347+
} // namespace roc
348+
349+
#endif // ROC_CORE_PAIRING_HEAP_H_

0 commit comments

Comments
 (0)