diff options
Diffstat (limited to 'litmus/binheap.c')
-rw-r--r-- | litmus/binheap.c | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/litmus/binheap.c b/litmus/binheap.c new file mode 100644 index 000000000000..f76260e64b0b --- /dev/null +++ b/litmus/binheap.c | |||
@@ -0,0 +1,387 @@ | |||
1 | #include <litmus/binheap.h> | ||
2 | |||
3 | |||
4 | int binheap_is_in_this_heap(struct binheap_node *node, | ||
5 | struct binheap_handle* heap) | ||
6 | { | ||
7 | if(!binheap_is_in_heap(node)) { | ||
8 | return 0; | ||
9 | } | ||
10 | |||
11 | while(node->parent != NULL) { | ||
12 | node = node->parent; | ||
13 | } | ||
14 | |||
15 | return (node == heap->root); | ||
16 | } | ||
17 | |||
18 | /* Update the node reference pointers. Same logic as Litmus binomial heap. */ | ||
19 | static void __update_ref(struct binheap_node *parent, | ||
20 | struct binheap_node *child) | ||
21 | { | ||
22 | *(parent->ref_ptr) = child; | ||
23 | *(child->ref_ptr) = parent; | ||
24 | |||
25 | swap(parent->ref_ptr, child->ref_ptr); | ||
26 | } | ||
27 | |||
28 | /* Swaps data between two nodes. */ | ||
29 | static void __binheap_swap(struct binheap_node *parent, | ||
30 | struct binheap_node *child) | ||
31 | { | ||
32 | swap(parent->data, child->data); | ||
33 | __update_ref(parent, child); | ||
34 | } | ||
35 | |||
36 | |||
37 | /* Swaps memory and data between two nodes. Actual nodes swap instead of | ||
38 | * just data. Needed when we delete nodes from the heap. | ||
39 | */ | ||
40 | static void __binheap_swap_safe(struct binheap_handle *handle, | ||
41 | struct binheap_node *a, | ||
42 | struct binheap_node *b) | ||
43 | { | ||
44 | swap(a->data, b->data); | ||
45 | __update_ref(a, b); | ||
46 | |||
47 | if((a->parent != NULL) && (a->parent == b->parent)) { | ||
48 | /* special case: shared parent */ | ||
49 | swap(a->parent->left, a->parent->right); | ||
50 | } | ||
51 | else { | ||
52 | /* Update pointers to swap parents. */ | ||
53 | |||
54 | if(a->parent) { | ||
55 | if(a == a->parent->left) { | ||
56 | a->parent->left = b; | ||
57 | } | ||
58 | else { | ||
59 | a->parent->right = b; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | if(b->parent) { | ||
64 | if(b == b->parent->left) { | ||
65 | b->parent->left = a; | ||
66 | } | ||
67 | else { | ||
68 | b->parent->right = a; | ||
69 | } | ||
70 | } | ||
71 | |||
72 | swap(a->parent, b->parent); | ||
73 | } | ||
74 | |||
75 | /* swap children */ | ||
76 | |||
77 | if(a->left) { | ||
78 | a->left->parent = b; | ||
79 | |||
80 | if(a->right) { | ||
81 | a->right->parent = b; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | if(b->left) { | ||
86 | b->left->parent = a; | ||
87 | |||
88 | if(b->right) { | ||
89 | b->right->parent = a; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | swap(a->left, b->left); | ||
94 | swap(a->right, b->right); | ||
95 | |||
96 | |||
97 | /* update next/last/root pointers */ | ||
98 | |||
99 | if(a == handle->next) { | ||
100 | handle->next = b; | ||
101 | } | ||
102 | else if(b == handle->next) { | ||
103 | handle->next = a; | ||
104 | } | ||
105 | |||
106 | if(a == handle->last) { | ||
107 | handle->last = b; | ||
108 | } | ||
109 | else if(b == handle->last) { | ||
110 | handle->last = a; | ||
111 | } | ||
112 | |||
113 | if(a == handle->root) { | ||
114 | handle->root = b; | ||
115 | } | ||
116 | else if(b == handle->root) { | ||
117 | handle->root = a; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | |||
122 | /** | ||
123 | * Update the pointer to the last node in the complete binary tree. | ||
124 | * Called internally after the root node has been deleted. | ||
125 | */ | ||
126 | static void __binheap_update_last(struct binheap_handle *handle) | ||
127 | { | ||
128 | struct binheap_node *temp = handle->last; | ||
129 | |||
130 | /* find a "bend" in the tree. */ | ||
131 | while(temp->parent && (temp == temp->parent->left)) { | ||
132 | temp = temp->parent; | ||
133 | } | ||
134 | |||
135 | /* step over to sibling if we're not at root */ | ||
136 | if(temp->parent != NULL) { | ||
137 | temp = temp->parent->left; | ||
138 | } | ||
139 | |||
140 | /* now travel right as far as possible. */ | ||
141 | while(temp->right != NULL) { | ||
142 | temp = temp->right; | ||
143 | } | ||
144 | |||
145 | /* take one step to the left if we're not at the bottom-most level. */ | ||
146 | if(temp->left != NULL) { | ||
147 | temp = temp->left; | ||
148 | } | ||
149 | |||
150 | //BUG_ON(!(temp->left == NULL && temp->right == NULL)); | ||
151 | |||
152 | handle->last = temp; | ||
153 | } | ||
154 | |||
155 | /** | ||
156 | * Update the pointer to the node that will take the next inserted node. | ||
157 | * Called internally after a node has been inserted. | ||
158 | */ | ||
159 | static void __binheap_update_next(struct binheap_handle *handle) | ||
160 | { | ||
161 | struct binheap_node *temp = handle->next; | ||
162 | |||
163 | /* find a "bend" in the tree. */ | ||
164 | while(temp->parent && (temp == temp->parent->right)) { | ||
165 | temp = temp->parent; | ||
166 | } | ||
167 | |||
168 | /* step over to sibling if we're not at root */ | ||
169 | if(temp->parent != NULL) { | ||
170 | temp = temp->parent->right; | ||
171 | } | ||
172 | |||
173 | /* now travel left as far as possible. */ | ||
174 | while(temp->left != NULL) { | ||
175 | temp = temp->left; | ||
176 | } | ||
177 | |||
178 | handle->next = temp; | ||
179 | } | ||
180 | |||
181 | |||
182 | |||
183 | /* bubble node up towards root */ | ||
184 | static void __binheap_bubble_up( | ||
185 | struct binheap_handle *handle, | ||
186 | struct binheap_node *node) | ||
187 | { | ||
188 | /* Note: NULL data pointers are used internally for arbitrary delete */ | ||
189 | while((node->parent != NULL) && | ||
190 | ((node->data == BINHEAP_POISON) /* let BINHEAP_POISON data bubble to the top */ || | ||
191 | handle->compare(node, node->parent))) { | ||
192 | __binheap_swap(node->parent, node); | ||
193 | node = node->parent; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | |||
198 | /* bubble node down, swapping with min-child */ | ||
199 | static void __binheap_bubble_down(struct binheap_handle *handle) | ||
200 | { | ||
201 | struct binheap_node *node = handle->root; | ||
202 | |||
203 | while(node->left != NULL) { | ||
204 | if(node->right && handle->compare(node->right, node->left)) { | ||
205 | if(handle->compare(node->right, node)) { | ||
206 | __binheap_swap(node, node->right); | ||
207 | node = node->right; | ||
208 | } | ||
209 | else { | ||
210 | break; | ||
211 | } | ||
212 | } | ||
213 | else { | ||
214 | if(handle->compare(node->left, node)) { | ||
215 | __binheap_swap(node, node->left); | ||
216 | node = node->left; | ||
217 | } | ||
218 | else { | ||
219 | break; | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | |||
225 | |||
226 | |||
227 | void __binheap_add(struct binheap_node *new_node, | ||
228 | struct binheap_handle *handle, | ||
229 | void *data) | ||
230 | { | ||
231 | new_node->data = data; | ||
232 | new_node->ref = new_node; | ||
233 | new_node->ref_ptr = &(new_node->ref); | ||
234 | |||
235 | if(!binheap_empty(handle)) { | ||
236 | /* insert left side first */ | ||
237 | if(handle->next->left == NULL) { | ||
238 | handle->next->left = new_node; | ||
239 | new_node->parent = handle->next; | ||
240 | new_node->left = NULL; | ||
241 | new_node->right = NULL; | ||
242 | |||
243 | handle->last = new_node; | ||
244 | |||
245 | __binheap_bubble_up(handle, new_node); | ||
246 | } | ||
247 | else { | ||
248 | /* left occupied. insert right. */ | ||
249 | handle->next->right = new_node; | ||
250 | new_node->parent = handle->next; | ||
251 | new_node->left = NULL; | ||
252 | new_node->right = NULL; | ||
253 | |||
254 | handle->last = new_node; | ||
255 | |||
256 | __binheap_update_next(handle); | ||
257 | __binheap_bubble_up(handle, new_node); | ||
258 | } | ||
259 | } | ||
260 | else { | ||
261 | /* first node in heap */ | ||
262 | |||
263 | new_node->parent = NULL; | ||
264 | new_node->left = NULL; | ||
265 | new_node->right = NULL; | ||
266 | |||
267 | handle->root = new_node; | ||
268 | handle->next = new_node; | ||
269 | handle->last = new_node; | ||
270 | } | ||
271 | } | ||
272 | |||
273 | |||
274 | |||
275 | /** | ||
276 | * Removes the root node from the heap. The node is removed after coalescing | ||
277 | * the binheap_node with its original data pointer at the root of the tree. | ||
278 | * | ||
279 | * The 'last' node in the tree is then swapped up to the root and bubbled | ||
280 | * down. | ||
281 | */ | ||
282 | void __binheap_delete_root(struct binheap_handle *handle, | ||
283 | struct binheap_node *container) | ||
284 | { | ||
285 | struct binheap_node *root = handle->root; | ||
286 | |||
287 | if(root != container) { | ||
288 | /* coalesce */ | ||
289 | __binheap_swap_safe(handle, root, container); | ||
290 | root = container; | ||
291 | } | ||
292 | |||
293 | if(handle->last != root) { | ||
294 | /* swap 'last' node up to root and bubble it down. */ | ||
295 | |||
296 | struct binheap_node *to_move = handle->last; | ||
297 | |||
298 | if(to_move->parent != root) { | ||
299 | handle->next = to_move->parent; | ||
300 | |||
301 | if(handle->next->right == to_move) { | ||
302 | /* disconnect from parent */ | ||
303 | to_move->parent->right = NULL; | ||
304 | handle->last = handle->next->left; | ||
305 | } | ||
306 | else { | ||
307 | /* find new 'last' before we disconnect */ | ||
308 | __binheap_update_last(handle); | ||
309 | |||
310 | /* disconnect from parent */ | ||
311 | to_move->parent->left = NULL; | ||
312 | } | ||
313 | } | ||
314 | else { | ||
315 | /* 'last' is direct child of root */ | ||
316 | |||
317 | handle->next = to_move; | ||
318 | |||
319 | if(to_move == to_move->parent->right) { | ||
320 | to_move->parent->right = NULL; | ||
321 | handle->last = to_move->parent->left; | ||
322 | } | ||
323 | else { | ||
324 | to_move->parent->left = NULL; | ||
325 | handle->last = to_move; | ||
326 | } | ||
327 | } | ||
328 | to_move->parent = NULL; | ||
329 | |||
330 | /* reconnect as root. We can't just swap data ptrs since root node | ||
331 | * may be freed after this function returns. | ||
332 | */ | ||
333 | to_move->left = root->left; | ||
334 | to_move->right = root->right; | ||
335 | if(to_move->left != NULL) { | ||
336 | to_move->left->parent = to_move; | ||
337 | } | ||
338 | if(to_move->right != NULL) { | ||
339 | to_move->right->parent = to_move; | ||
340 | } | ||
341 | |||
342 | handle->root = to_move; | ||
343 | |||
344 | /* bubble down */ | ||
345 | __binheap_bubble_down(handle); | ||
346 | } | ||
347 | else { | ||
348 | /* removing last node in tree */ | ||
349 | handle->root = NULL; | ||
350 | handle->next = NULL; | ||
351 | handle->last = NULL; | ||
352 | } | ||
353 | |||
354 | /* mark as removed */ | ||
355 | container->parent = BINHEAP_POISON; | ||
356 | } | ||
357 | |||
358 | |||
359 | /** | ||
360 | * Delete an arbitrary node. Bubble node to delete up to the root, | ||
361 | * and then delete to root. | ||
362 | */ | ||
363 | void __binheap_delete(struct binheap_node *node_to_delete, | ||
364 | struct binheap_handle *handle) | ||
365 | { | ||
366 | struct binheap_node *target = node_to_delete->ref; | ||
367 | void *temp_data = target->data; | ||
368 | |||
369 | /* temporarily set data to null to allow node to bubble up to the top. */ | ||
370 | target->data = BINHEAP_POISON; | ||
371 | |||
372 | __binheap_bubble_up(handle, target); | ||
373 | __binheap_delete_root(handle, node_to_delete); | ||
374 | |||
375 | node_to_delete->data = temp_data; /* restore node data pointer */ | ||
376 | node_to_delete->parent = BINHEAP_POISON; /* poison the node */ | ||
377 | } | ||
378 | |||
379 | /** | ||
380 | * Bubble up a node whose pointer has decreased in value. | ||
381 | */ | ||
382 | void __binheap_decrease(struct binheap_node *orig_node, | ||
383 | struct binheap_handle *handle) | ||
384 | { | ||
385 | struct binheap_node *target = orig_node->ref; | ||
386 | __binheap_bubble_up(handle, target); | ||
387 | } | ||