diff options
Diffstat (limited to 'src/util/container_heap.c')
-rw-r--r-- | src/util/container_heap.c | 244 |
1 files changed, 118 insertions, 126 deletions
diff --git a/src/util/container_heap.c b/src/util/container_heap.c index a7e79cc7e..c1d478e06 100644 --- a/src/util/container_heap.c +++ b/src/util/container_heap.c | |||
@@ -94,7 +94,7 @@ struct GNUNET_CONTAINER_Heap | |||
94 | * Number of elements in the heap. | 94 | * Number of elements in the heap. |
95 | */ | 95 | */ |
96 | unsigned int size; | 96 | unsigned int size; |
97 | 97 | ||
98 | /** | 98 | /** |
99 | * How is the heap sorted? | 99 | * How is the heap sorted? |
100 | */ | 100 | */ |
@@ -108,15 +108,17 @@ struct GNUNET_CONTAINER_Heap | |||
108 | * Check if internal invariants hold for the given node. | 108 | * Check if internal invariants hold for the given node. |
109 | * | 109 | * |
110 | * @param node subtree to check | 110 | * @param node subtree to check |
111 | */ | 111 | */ |
112 | static void | 112 | static void |
113 | check (const struct GNUNET_CONTAINER_HeapNode *node) | 113 | check (const struct GNUNET_CONTAINER_HeapNode *node) |
114 | { | 114 | { |
115 | if (NULL == node) | 115 | if (NULL == node) |
116 | return; | 116 | return; |
117 | GNUNET_assert (node->tree_size == | 117 | GNUNET_assert (node->tree_size == |
118 | ( (node->left_child == NULL) ? 0 : 1 + node->left_child->tree_size) + | 118 | ((node->left_child == |
119 | ( (node->right_child == NULL) ? 0 : 1 + node->right_child->tree_size) ); | 119 | NULL) ? 0 : 1 + node->left_child->tree_size) + |
120 | ((node->right_child == | ||
121 | NULL) ? 0 : 1 + node->right_child->tree_size)); | ||
120 | check (node->left_child); | 122 | check (node->left_child); |
121 | check (node->right_child); | 123 | check (node->right_child); |
122 | } | 124 | } |
@@ -194,7 +196,8 @@ GNUNET_CONTAINER_heap_get_size (const struct GNUNET_CONTAINER_Heap *heap) | |||
194 | * @return cost of the node | 196 | * @return cost of the node |
195 | */ | 197 | */ |
196 | GNUNET_CONTAINER_HeapCostType | 198 | GNUNET_CONTAINER_HeapCostType |
197 | GNUNET_CONTAINER_heap_node_get_cost (const struct GNUNET_CONTAINER_HeapNode *node) | 199 | GNUNET_CONTAINER_heap_node_get_cost (const struct GNUNET_CONTAINER_HeapNode |
200 | *node) | ||
198 | { | 201 | { |
199 | return node->cost; | 202 | return node->cost; |
200 | } | 203 | } |
@@ -210,26 +213,18 @@ GNUNET_CONTAINER_heap_node_get_cost (const struct GNUNET_CONTAINER_HeapNode *nod | |||
210 | */ | 213 | */ |
211 | static int | 214 | static int |
212 | node_iterator (const struct GNUNET_CONTAINER_Heap *heap, | 215 | node_iterator (const struct GNUNET_CONTAINER_Heap *heap, |
213 | struct GNUNET_CONTAINER_HeapNode *node, | 216 | struct GNUNET_CONTAINER_HeapNode *node, |
214 | GNUNET_CONTAINER_HeapIterator iterator, | 217 | GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls) |
215 | void *iterator_cls) | ||
216 | { | 218 | { |
217 | if (node == NULL) | 219 | if (node == NULL) |
218 | return GNUNET_YES; | 220 | return GNUNET_YES; |
219 | if (GNUNET_YES != node_iterator (heap, | 221 | if (GNUNET_YES != node_iterator (heap, |
220 | node->left_child, | 222 | node->left_child, iterator, iterator_cls)) |
221 | iterator, | ||
222 | iterator_cls)) | ||
223 | return GNUNET_NO; | 223 | return GNUNET_NO; |
224 | if (GNUNET_YES != node_iterator (heap, | 224 | if (GNUNET_YES != node_iterator (heap, |
225 | node->right_child, | 225 | node->right_child, iterator, iterator_cls)) |
226 | iterator, | ||
227 | iterator_cls)) | ||
228 | return GNUNET_NO; | 226 | return GNUNET_NO; |
229 | return iterator (iterator_cls, | 227 | return iterator (iterator_cls, node, node->element, node->cost); |
230 | node, | ||
231 | node->element, | ||
232 | node->cost); | ||
233 | } | 228 | } |
234 | 229 | ||
235 | 230 | ||
@@ -269,13 +264,12 @@ GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *heap) | |||
269 | if (heap->root == NULL) | 264 | if (heap->root == NULL) |
270 | return NULL; | 265 | return NULL; |
271 | pos = heap->walk_pos; | 266 | pos = heap->walk_pos; |
272 | if (pos == NULL) | 267 | if (pos == NULL) |
273 | pos = heap->root; | 268 | pos = heap->root; |
274 | element = pos->element; | 269 | element = pos->element; |
275 | heap->walk_pos | 270 | heap->walk_pos |
276 | = (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2)) | 271 | = (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2)) |
277 | ? pos->right_child | 272 | ? pos->right_child : pos->left_child; |
278 | : pos->left_child; | ||
279 | return element; | 273 | return element; |
280 | } | 274 | } |
281 | 275 | ||
@@ -290,51 +284,50 @@ GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *heap) | |||
290 | */ | 284 | */ |
291 | static void | 285 | static void |
292 | insert_node (struct GNUNET_CONTAINER_Heap *heap, | 286 | insert_node (struct GNUNET_CONTAINER_Heap *heap, |
293 | struct GNUNET_CONTAINER_HeapNode *pos, | 287 | struct GNUNET_CONTAINER_HeapNode *pos, |
294 | struct GNUNET_CONTAINER_HeapNode *node) | 288 | struct GNUNET_CONTAINER_HeapNode *node) |
295 | { | 289 | { |
296 | struct GNUNET_CONTAINER_HeapNode *parent; | 290 | struct GNUNET_CONTAINER_HeapNode *parent; |
297 | 291 | ||
298 | GNUNET_assert (node->parent == NULL); | 292 | GNUNET_assert (node->parent == NULL); |
299 | while ( (heap->order == GNUNET_CONTAINER_HEAP_ORDER_MAX) | 293 | while ((heap->order == GNUNET_CONTAINER_HEAP_ORDER_MAX) |
300 | ? (pos->cost >= node->cost) | 294 | ? (pos->cost >= node->cost) : (pos->cost <= node->cost)) |
301 | : (pos->cost <= node->cost) ) | 295 | { |
296 | /* node is descendent of pos */ | ||
297 | pos->tree_size += (1 + node->tree_size); | ||
298 | if (pos->left_child == NULL) | ||
302 | { | 299 | { |
303 | /* node is descendent of pos */ | 300 | pos->left_child = node; |
304 | pos->tree_size += (1 + node->tree_size); | 301 | node->parent = pos; |
305 | if (pos->left_child == NULL) | 302 | return; |
306 | { | ||
307 | pos->left_child = node; | ||
308 | node->parent = pos; | ||
309 | return; | ||
310 | } | ||
311 | if (pos->right_child == NULL) | ||
312 | { | ||
313 | pos->right_child = node; | ||
314 | node->parent = pos; | ||
315 | return; | ||
316 | } | ||
317 | /* keep it balanced by descending into smaller subtree */ | ||
318 | if (pos->left_child->tree_size < pos->right_child->tree_size) | ||
319 | pos = pos->left_child; | ||
320 | else | ||
321 | pos = pos->right_child; | ||
322 | } | 303 | } |
304 | if (pos->right_child == NULL) | ||
305 | { | ||
306 | pos->right_child = node; | ||
307 | node->parent = pos; | ||
308 | return; | ||
309 | } | ||
310 | /* keep it balanced by descending into smaller subtree */ | ||
311 | if (pos->left_child->tree_size < pos->right_child->tree_size) | ||
312 | pos = pos->left_child; | ||
313 | else | ||
314 | pos = pos->right_child; | ||
315 | } | ||
323 | /* make 'node' parent of 'pos' */ | 316 | /* make 'node' parent of 'pos' */ |
324 | parent = pos->parent; | 317 | parent = pos->parent; |
325 | pos->parent = NULL; | 318 | pos->parent = NULL; |
326 | node->parent = parent; | 319 | node->parent = parent; |
327 | if (NULL == parent) | 320 | if (NULL == parent) |
328 | { | 321 | { |
329 | heap->root = node; | 322 | heap->root = node; |
330 | } | 323 | } |
331 | else | 324 | else |
332 | { | 325 | { |
333 | if (parent->left_child == pos) | 326 | if (parent->left_child == pos) |
334 | parent->left_child = node; | 327 | parent->left_child = node; |
335 | else | 328 | else |
336 | parent->right_child = node; | 329 | parent->right_child = node; |
337 | } | 330 | } |
338 | /* insert 'pos' below 'node' */ | 331 | /* insert 'pos' below 'node' */ |
339 | insert_node (heap, node, pos); | 332 | insert_node (heap, node, pos); |
340 | CHECK (pos); | 333 | CHECK (pos); |
@@ -351,8 +344,7 @@ insert_node (struct GNUNET_CONTAINER_Heap *heap, | |||
351 | */ | 344 | */ |
352 | struct GNUNET_CONTAINER_HeapNode * | 345 | struct GNUNET_CONTAINER_HeapNode * |
353 | GNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *heap, | 346 | GNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *heap, |
354 | void *element, | 347 | void *element, GNUNET_CONTAINER_HeapCostType cost) |
355 | GNUNET_CONTAINER_HeapCostType cost) | ||
356 | { | 348 | { |
357 | struct GNUNET_CONTAINER_HeapNode *node; | 349 | struct GNUNET_CONTAINER_HeapNode *node; |
358 | 350 | ||
@@ -388,28 +380,28 @@ GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *heap) | |||
388 | heap->size--; | 380 | heap->size--; |
389 | ret = root->element; | 381 | ret = root->element; |
390 | if (root->left_child == NULL) | 382 | if (root->left_child == NULL) |
391 | { | 383 | { |
392 | heap->root = root->right_child; | 384 | heap->root = root->right_child; |
393 | if (root->right_child != NULL) | 385 | if (root->right_child != NULL) |
394 | root->right_child->parent = NULL; | 386 | root->right_child->parent = NULL; |
395 | } | 387 | } |
396 | else if (root->right_child == NULL) | 388 | else if (root->right_child == NULL) |
397 | { | 389 | { |
398 | heap->root = root->left_child; | 390 | heap->root = root->left_child; |
399 | root->left_child->parent = NULL; | 391 | root->left_child->parent = NULL; |
400 | } | 392 | } |
401 | else | 393 | else |
402 | { | 394 | { |
403 | root->left_child->parent = NULL; | 395 | root->left_child->parent = NULL; |
404 | root->right_child->parent = NULL; | 396 | root->right_child->parent = NULL; |
405 | heap->root = root->left_child; | 397 | heap->root = root->left_child; |
406 | insert_node (heap, heap->root, root->right_child); | 398 | insert_node (heap, heap->root, root->right_child); |
407 | } | 399 | } |
408 | GNUNET_free (root); | 400 | GNUNET_free (root); |
409 | #if DEBUG | 401 | #if DEBUG |
410 | GNUNET_assert (( (heap->size == 0) && | 402 | GNUNET_assert (((heap->size == 0) && |
411 | (heap->root == NULL) ) || | 403 | (heap->root == NULL)) || |
412 | (heap->size == heap->root->tree_size + 1) ); | 404 | (heap->size == heap->root->tree_size + 1)); |
413 | CHECK (heap->root); | 405 | CHECK (heap->root); |
414 | #endif | 406 | #endif |
415 | return ret; | 407 | return ret; |
@@ -430,7 +422,7 @@ remove_node (struct GNUNET_CONTAINER_HeapNode *node) | |||
430 | 422 | ||
431 | /* update 'size' of the ancestors */ | 423 | /* update 'size' of the ancestors */ |
432 | ancestor = node; | 424 | ancestor = node; |
433 | while (NULL != (ancestor = ancestor->parent)) | 425 | while (NULL != (ancestor = ancestor->parent)) |
434 | ancestor->tree_size--; | 426 | ancestor->tree_size--; |
435 | 427 | ||
436 | /* update 'size' of node itself */ | 428 | /* update 'size' of node itself */ |
@@ -441,43 +433,43 @@ remove_node (struct GNUNET_CONTAINER_HeapNode *node) | |||
441 | 433 | ||
442 | /* unlink 'node' itself and insert children in its place */ | 434 | /* unlink 'node' itself and insert children in its place */ |
443 | if (node->parent == NULL) | 435 | if (node->parent == NULL) |
436 | { | ||
437 | if (node->left_child != NULL) | ||
444 | { | 438 | { |
445 | if (node->left_child != NULL) | 439 | heap->root = node->left_child; |
446 | { | 440 | node->left_child->parent = NULL; |
447 | heap->root = node->left_child; | 441 | if (node->right_child != NULL) |
448 | node->left_child->parent = NULL; | 442 | { |
449 | if (node->right_child != NULL) | 443 | node->right_child->parent = NULL; |
450 | { | 444 | insert_node (heap, heap->root, node->right_child); |
451 | node->right_child->parent = NULL; | 445 | } |
452 | insert_node (heap, heap->root, node->right_child); | ||
453 | } | ||
454 | } | ||
455 | else | ||
456 | { | ||
457 | heap->root = node->right_child; | ||
458 | if (node->right_child != NULL) | ||
459 | node->right_child->parent = NULL; | ||
460 | } | ||
461 | } | 446 | } |
462 | else | 447 | else |
463 | { | 448 | { |
464 | if (node->parent->left_child == node) | 449 | heap->root = node->right_child; |
465 | node->parent->left_child = NULL; | ||
466 | else | ||
467 | node->parent->right_child = NULL; | ||
468 | if (node->left_child != NULL) | ||
469 | { | ||
470 | node->left_child->parent = NULL; | ||
471 | node->parent->tree_size -= (1 + node->left_child->tree_size); | ||
472 | insert_node (heap, node->parent, node->left_child); | ||
473 | } | ||
474 | if (node->right_child != NULL) | 450 | if (node->right_child != NULL) |
475 | { | 451 | node->right_child->parent = NULL; |
476 | node->right_child->parent = NULL; | 452 | } |
477 | node->parent->tree_size -= (1 + node->right_child->tree_size); | 453 | } |
478 | insert_node (heap, node->parent, node->right_child); | 454 | else |
479 | } | 455 | { |
456 | if (node->parent->left_child == node) | ||
457 | node->parent->left_child = NULL; | ||
458 | else | ||
459 | node->parent->right_child = NULL; | ||
460 | if (node->left_child != NULL) | ||
461 | { | ||
462 | node->left_child->parent = NULL; | ||
463 | node->parent->tree_size -= (1 + node->left_child->tree_size); | ||
464 | insert_node (heap, node->parent, node->left_child); | ||
465 | } | ||
466 | if (node->right_child != NULL) | ||
467 | { | ||
468 | node->right_child->parent = NULL; | ||
469 | node->parent->tree_size -= (1 + node->right_child->tree_size); | ||
470 | insert_node (heap, node->parent, node->right_child); | ||
480 | } | 471 | } |
472 | } | ||
481 | node->parent = NULL; | 473 | node->parent = NULL; |
482 | node->left_child = NULL; | 474 | node->left_child = NULL; |
483 | node->right_child = NULL; | 475 | node->right_child = NULL; |
@@ -498,7 +490,7 @@ GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node) | |||
498 | void *ret; | 490 | void *ret; |
499 | struct GNUNET_CONTAINER_Heap *heap; | 491 | struct GNUNET_CONTAINER_Heap *heap; |
500 | 492 | ||
501 | heap = node->heap; | 493 | heap = node->heap; |
502 | CHECK (heap->root); | 494 | CHECK (heap->root); |
503 | if (heap->walk_pos == node) | 495 | if (heap->walk_pos == node) |
504 | (void) GNUNET_CONTAINER_heap_walk_get_next (heap); | 496 | (void) GNUNET_CONTAINER_heap_walk_get_next (heap); |
@@ -510,9 +502,9 @@ GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node) | |||
510 | GNUNET_free (node); | 502 | GNUNET_free (node); |
511 | #if DEBUG | 503 | #if DEBUG |
512 | CHECK (heap->root); | 504 | CHECK (heap->root); |
513 | GNUNET_assert (( (heap->size == 0) && | 505 | GNUNET_assert (((heap->size == 0) && |
514 | (heap->root == NULL) ) || | 506 | (heap->root == NULL)) || |
515 | (heap->size == heap->root->tree_size + 1) ); | 507 | (heap->size == heap->root->tree_size + 1)); |
516 | #endif | 508 | #endif |
517 | return ret; | 509 | return ret; |
518 | } | 510 | } |
@@ -527,21 +519,21 @@ GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node) | |||
527 | */ | 519 | */ |
528 | void | 520 | void |
529 | GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_Heap *heap, | 521 | GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_Heap *heap, |
530 | struct GNUNET_CONTAINER_HeapNode *node, | 522 | struct GNUNET_CONTAINER_HeapNode *node, |
531 | GNUNET_CONTAINER_HeapCostType new_cost) | 523 | GNUNET_CONTAINER_HeapCostType new_cost) |
532 | { | 524 | { |
533 | #if DEBUG | 525 | #if DEBUG |
534 | GNUNET_assert ( ( (heap->size == 0) && | 526 | GNUNET_assert (((heap->size == 0) && |
535 | (heap->root == NULL) ) || | 527 | (heap->root == NULL)) || |
536 | (heap->size == heap->root->tree_size + 1) ); | 528 | (heap->size == heap->root->tree_size + 1)); |
537 | CHECK (heap->root); | 529 | CHECK (heap->root); |
538 | #endif | 530 | #endif |
539 | remove_node (node); | 531 | remove_node (node); |
540 | #if DEBUG | 532 | #if DEBUG |
541 | CHECK (heap->root); | 533 | CHECK (heap->root); |
542 | GNUNET_assert ( ( (heap->size == 1) && | 534 | GNUNET_assert (((heap->size == 1) && |
543 | (heap->root == NULL) ) || | 535 | (heap->root == NULL)) || |
544 | (heap->size == heap->root->tree_size + 2) ); | 536 | (heap->size == heap->root->tree_size + 2)); |
545 | #endif | 537 | #endif |
546 | node->cost = new_cost; | 538 | node->cost = new_cost; |
547 | if (heap->root == NULL) | 539 | if (heap->root == NULL) |
@@ -550,9 +542,9 @@ GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_Heap *heap, | |||
550 | insert_node (heap, heap->root, node); | 542 | insert_node (heap, heap->root, node); |
551 | #if DEBUG | 543 | #if DEBUG |
552 | CHECK (heap->root); | 544 | CHECK (heap->root); |
553 | GNUNET_assert ( ( (heap->size == 0) && | 545 | GNUNET_assert (((heap->size == 0) && |
554 | (heap->root == NULL) ) || | 546 | (heap->root == NULL)) || |
555 | (heap->size == heap->root->tree_size + 1) ); | 547 | (heap->size == heap->root->tree_size + 1)); |
556 | #endif | 548 | #endif |
557 | } | 549 | } |
558 | 550 | ||