GNUnet 0.28.0-dev.3-20-gf1136b0b8
 
Loading...
Searching...
No Matches
container_heap.c File Reference

Implementation of a heap. More...

#include "platform.h"
#include "gnunet_util_lib.h"
Include dependency graph for container_heap.c:

Go to the source code of this file.

Data Structures

struct  GNUNET_CONTAINER_HeapNode
 Node in the heap. More...
 
struct  GNUNET_CONTAINER_Heap
 Handle to a node in a heap. More...
 

Macros

#define LOG(kind, ...)
 
#define EXTRA_CHECKS   0
 
#define CHECK(n)   do {} while (0)
 

Functions

struct GNUNET_CONTAINER_HeapGNUNET_CONTAINER_heap_create (enum GNUNET_CONTAINER_HeapOrder order)
 Create a new heap.
 
void GNUNET_CONTAINER_heap_destroy (struct GNUNET_CONTAINER_Heap *heap)
 Destroys the heap.
 
void * GNUNET_CONTAINER_heap_peek (const struct GNUNET_CONTAINER_Heap *heap)
 Get element stored at the root of heap.
 
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_heap_peek2 (const struct GNUNET_CONTAINER_Heap *heap, void **element, GNUNET_CONTAINER_HeapCostType *cost)
 Get element and cost stored at the root of heap.
 
unsigned int GNUNET_CONTAINER_heap_get_size (const struct GNUNET_CONTAINER_Heap *heap)
 Get the current size of the heap.
 
GNUNET_CONTAINER_HeapCostType GNUNET_CONTAINER_heap_node_get_cost (const struct GNUNET_CONTAINER_HeapNode *node)
 Get the current cost of the node.
 
static int node_iterator (const struct GNUNET_CONTAINER_Heap *heap, struct GNUNET_CONTAINER_HeapNode *node, GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls)
 Iterate over the children of the given node.
 
void GNUNET_CONTAINER_heap_iterate (const struct GNUNET_CONTAINER_Heap *heap, GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls)
 Iterate over all entries in the heap.
 
void * GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *heap)
 Perform a random walk of the tree.
 
static void insert_node (struct GNUNET_CONTAINER_Heap *heap, struct GNUNET_CONTAINER_HeapNode *pos, struct GNUNET_CONTAINER_HeapNode *node)
 Insert the given node 'node' into the subtree starting at 'pos' (while keeping the tree somewhat balanced).
 
struct GNUNET_CONTAINER_HeapNodeGNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *heap, void *element, GNUNET_CONTAINER_HeapCostType cost)
 Inserts a new element into the heap.
 
void * GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *heap)
 Remove root of the heap.
 
static void remove_node (struct GNUNET_CONTAINER_HeapNode *node)
 Remove the given node 'node' from the tree and update the 'tree_size' fields accordingly.
 
void * GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node)
 Removes a node from the heap.
 
void GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_HeapNode *node, GNUNET_CONTAINER_HeapCostType new_cost)
 Updates the cost of any node in the tree.
 

Detailed Description

Implementation of a heap.

Author
Nathan Evans
Christian Grothoff

Definition in file container_heap.c.

Macro Definition Documentation

◆ LOG

#define LOG (   kind,
  ... 
)
Value:
GNUNET_log_from (kind, "util-container-heap", \
__VA_ARGS__)
#define GNUNET_log_from(kind, comp,...)

Definition at line 32 of file container_heap.c.

40{
44 struct GNUNET_CONTAINER_Heap *heap;
45
50
55
60
64 void *element;
65
70
75 unsigned int tree_size;
76};
77
82{
87
92
96 unsigned int size;
97
102};
103
104
105#if EXTRA_CHECKS
111static void
112check (const struct GNUNET_CONTAINER_HeapNode *node)
113{
114 if (NULL == node)
115 return;
116 GNUNET_assert (node->tree_size ==
117 ((node->left_child ==
118 NULL) ? 0 : 1 + node->left_child->tree_size)
119 + ((node->right_child ==
120 NULL) ? 0 : 1 + node->right_child->tree_size));
121 check (node->left_child);
122 check (node->right_child);
123}
124
125
126#define CHECK(n) check (n)
127#else
128#define CHECK(n) do {} while (0)
129#endif
130
131
134{
135 struct GNUNET_CONTAINER_Heap *heap;
136
137 heap = GNUNET_new (struct GNUNET_CONTAINER_Heap);
138 heap->order = order;
139 return heap;
140}
141
142
143void
145{
146 GNUNET_break (heap->size == 0);
147 GNUNET_free (heap);
148}
149
150
151void *
153{
154 if (heap->root == NULL)
155 return NULL;
156 return heap->root->element;
157}
158
159
171 void **element,
173{
174 if (NULL == heap->root)
175 return GNUNET_NO;
176 if (NULL != element)
177 *element = heap->root->element;
178 if (NULL != cost)
179 *cost = heap->root->cost;
180 return GNUNET_YES;
181}
182
183
184unsigned int
186{
187 return heap->size;
188}
189
190
193 *node)
194{
195 return node->cost;
196}
197
198
208static int
209node_iterator (const struct GNUNET_CONTAINER_Heap *heap,
210 struct GNUNET_CONTAINER_HeapNode *node,
211 GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls)
212{
213 if (node == NULL)
214 return GNUNET_YES;
215 if (GNUNET_YES !=
216 node_iterator (heap, node->left_child, iterator, iterator_cls))
217 return GNUNET_NO;
218 if (GNUNET_YES !=
219 node_iterator (heap, node->right_child, iterator, iterator_cls))
220 return GNUNET_NO;
221 return iterator (iterator_cls, node, node->element, node->cost);
222}
223
224
225void
228 void *iterator_cls)
229{
230 (void) node_iterator (heap, heap->root, iterator, iterator_cls);
231}
232
233
234void *
236{
237 struct GNUNET_CONTAINER_HeapNode *pos;
238 void *element;
239
240 if (heap->root == NULL)
241 return NULL;
242 pos = heap->walk_pos;
243 if (pos == NULL)
244 pos = heap->root;
245 element = pos->element;
246 heap->walk_pos =
247 (0 ==
249 return element;
250}
251
252
261static void
263 struct GNUNET_CONTAINER_HeapNode *pos,
264 struct GNUNET_CONTAINER_HeapNode *node)
265{
267
268 GNUNET_assert (node->parent == NULL);
269 while ((heap->order == GNUNET_CONTAINER_HEAP_ORDER_MAX) ? (pos->cost >=
270 node->cost)
271 : (pos->cost <= node->cost))
272 {
273 /* node is descendent of pos */
274 pos->tree_size += (1 + node->tree_size);
275 if (pos->left_child == NULL)
276 {
277 pos->left_child = node;
278 node->parent = pos;
279 return;
280 }
281 if (pos->right_child == NULL)
282 {
283 pos->right_child = node;
284 node->parent = pos;
285 return;
286 }
287 /* keep it balanced by descending into smaller subtree */
288 if (pos->left_child->tree_size < pos->right_child->tree_size)
289 pos = pos->left_child;
290 else
291 pos = pos->right_child;
292 }
293 /* make 'node' parent of 'pos' */
294 parent = pos->parent;
295 pos->parent = NULL;
296 node->parent = parent;
297 if (NULL == parent)
298 {
299 heap->root = node;
300 }
301 else
302 {
303 if (parent->left_child == pos)
304 parent->left_child = node;
305 else
306 parent->right_child = node;
307 }
308 /* insert 'pos' below 'node' */
309 insert_node (heap, node, pos);
310 CHECK (pos);
311}
312
313
317{
318 struct GNUNET_CONTAINER_HeapNode *node;
319
321 node->heap = heap;
322 node->element = element;
323 node->cost = cost;
324 heap->size++;
325 if (NULL == heap->root)
326 heap->root = node;
327 else
328 insert_node (heap, heap->root, node);
330 CHECK (heap->root);
331 return node;
332}
333
334
341void *
343{
344 void *ret;
345 struct GNUNET_CONTAINER_HeapNode *root;
346
347 if (NULL == (root = heap->root))
348 return NULL;
349 heap->size--;
350 ret = root->element;
351 if (root->left_child == NULL)
352 {
353 heap->root = root->right_child;
354 if (root->right_child != NULL)
355 root->right_child->parent = NULL;
356 }
357 else if (root->right_child == NULL)
358 {
359 heap->root = root->left_child;
360 root->left_child->parent = NULL;
361 }
362 else
363 {
364 root->left_child->parent = NULL;
365 root->right_child->parent = NULL;
366 heap->root = root->left_child;
368 }
369 if (heap->walk_pos == root)
371 GNUNET_free (root);
372#if EXTRA_CHECKS
373 GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) ||
374 (heap->size == heap->root->tree_size + 1));
375 CHECK (heap->root);
376#endif
377 return ret;
378}
379
380
387static void
389{
390 struct GNUNET_CONTAINER_HeapNode *ancestor;
391 struct GNUNET_CONTAINER_Heap *heap = node->heap;
392
393 /* update 'size' of the ancestors */
394 ancestor = node;
395 while (NULL != (ancestor = ancestor->parent))
396 ancestor->tree_size--;
397
398 /* update 'size' of node itself */
399 if (node->left_child != NULL)
400 node->tree_size -= (1 + node->left_child->tree_size);
401 if (node->right_child != NULL)
402 node->tree_size -= (1 + node->right_child->tree_size);
403
404 /* unlink 'node' itself and insert children in its place */
405 if (node->parent == NULL)
406 {
407 if (node->left_child != NULL)
408 {
409 heap->root = node->left_child;
410 node->left_child->parent = NULL;
411 if (node->right_child != NULL)
412 {
413 node->right_child->parent = NULL;
414 insert_node (heap, heap->root, node->right_child);
415 }
416 }
417 else
418 {
419 heap->root = node->right_child;
420 if (node->right_child != NULL)
421 node->right_child->parent = NULL;
422 }
423 }
424 else
425 {
426 if (node->parent->left_child == node)
427 node->parent->left_child = NULL;
428 else
429 node->parent->right_child = NULL;
430 if (node->left_child != NULL)
431 {
432 node->left_child->parent = NULL;
433 node->parent->tree_size -= (1 + node->left_child->tree_size);
434 insert_node (heap, node->parent, node->left_child);
435 }
436 if (node->right_child != NULL)
437 {
438 node->right_child->parent = NULL;
439 node->parent->tree_size -= (1 + node->right_child->tree_size);
440 insert_node (heap, node->parent, node->right_child);
441 }
442 }
443 node->parent = NULL;
444 node->left_child = NULL;
445 node->right_child = NULL;
446 GNUNET_assert (node->tree_size == 0);
447 CHECK (heap->root);
448}
449
450
457void *
459{
460 void *ret;
461 struct GNUNET_CONTAINER_Heap *heap;
462
463 heap = node->heap;
464 CHECK (heap->root);
465 if (heap->walk_pos == node)
467 remove_node (node);
468 heap->size--;
469 ret = node->element;
470 if (heap->walk_pos == node)
471 heap->walk_pos = NULL;
472 GNUNET_free (node);
473#if EXTRA_CHECKS
474 CHECK (heap->root);
475 GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) ||
476 (heap->size == heap->root->tree_size + 1));
477#endif
478 return ret;
479}
480
481
482void
485{
486 struct GNUNET_CONTAINER_Heap *heap = node->heap;
487
488 remove_node (node);
489 node->cost = new_cost;
490 if (NULL == heap->root)
491 heap->root = node;
492 else
493 insert_node (heap,
494 heap->root,
495 node);
496}
497
498
499/* end of heap.c */
static void remove_node(struct GNUNET_CONTAINER_HeapNode *node)
Remove the given node 'node' from the tree and update the 'tree_size' fields accordingly.
static void insert_node(struct GNUNET_CONTAINER_Heap *heap, struct GNUNET_CONTAINER_HeapNode *pos, struct GNUNET_CONTAINER_HeapNode *node)
Insert the given node 'node' into the subtree starting at 'pos' (while keeping the tree somewhat bala...
static int node_iterator(const struct GNUNET_CONTAINER_Heap *heap, struct GNUNET_CONTAINER_HeapNode *node, GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls)
Iterate over the children of the given node.
#define CHECK(n)
static int ret
Final status code.
Definition gnunet-arm.c:93
uint32_t GNUNET_CRYPTO_random_u32(uint32_t i)
Produce a random value.
void * GNUNET_CONTAINER_heap_remove_node(struct GNUNET_CONTAINER_HeapNode *node)
Removes a node from the heap.
void * GNUNET_CONTAINER_heap_peek(const struct GNUNET_CONTAINER_Heap *heap)
Get element stored at the root of heap.
GNUNET_CONTAINER_HeapOrder
Heap type, either max or min.
GNUNET_CONTAINER_HeapCostType GNUNET_CONTAINER_heap_node_get_cost(const struct GNUNET_CONTAINER_HeapNode *node)
Get the current cost of the node.
void * GNUNET_CONTAINER_heap_remove_root(struct GNUNET_CONTAINER_Heap *heap)
Remove root of the heap.
void GNUNET_CONTAINER_heap_update_cost(struct GNUNET_CONTAINER_HeapNode *node, GNUNET_CONTAINER_HeapCostType new_cost)
Updates the cost of any node in the tree.
struct GNUNET_CONTAINER_HeapNode * GNUNET_CONTAINER_heap_insert(struct GNUNET_CONTAINER_Heap *heap, void *element, GNUNET_CONTAINER_HeapCostType cost)
Inserts a new element into the heap.
enum GNUNET_GenericReturnValue(* GNUNET_CONTAINER_HeapIterator)(void *cls, struct GNUNET_CONTAINER_HeapNode *node, void *element, GNUNET_CONTAINER_HeapCostType cost)
Iterator for heap.
unsigned int GNUNET_CONTAINER_heap_get_size(const struct GNUNET_CONTAINER_Heap *heap)
Get the current size of the heap.
void GNUNET_CONTAINER_heap_iterate(const struct GNUNET_CONTAINER_Heap *heap, GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls)
Iterate over all entries in the heap.
uint64_t GNUNET_CONTAINER_HeapCostType
Cost by which elements in a heap can be ordered.
struct GNUNET_CONTAINER_Heap * GNUNET_CONTAINER_heap_create(enum GNUNET_CONTAINER_HeapOrder order)
Create a new heap.
void GNUNET_CONTAINER_heap_destroy(struct GNUNET_CONTAINER_Heap *heap)
Destroys the heap.
void * GNUNET_CONTAINER_heap_walk_get_next(struct GNUNET_CONTAINER_Heap *heap)
Perform a random walk of the tree.
@ GNUNET_CONTAINER_HEAP_ORDER_MAX
Heap with the maximum cost at the root.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_heap_peek2(const struct GNUNET_CONTAINER_Heap *heap, void **element, GNUNET_CONTAINER_HeapCostType *cost)
Get element and cost stored at the root of heap.
GNUNET_GenericReturnValue
Named constants for return values.
@ GNUNET_YES
@ GNUNET_NO
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
void * element
Our element.
struct GNUNET_CONTAINER_HeapNode * parent
Parent node.
struct GNUNET_CONTAINER_Heap * heap
Heap this node belongs to.
struct GNUNET_CONTAINER_HeapNode * left_child
Left child.
GNUNET_CONTAINER_HeapCostType cost
Cost for this element.
unsigned int tree_size
Number of elements below this node in the heap (excluding this node itself).
struct GNUNET_CONTAINER_HeapNode * right_child
Right child.
Handle to a node in a heap.
struct GNUNET_CONTAINER_HeapNode * root
Root of the heap.
unsigned int size
Number of elements in the heap.
struct GNUNET_CONTAINER_HeapNode * walk_pos
Current position of our random walk.
enum GNUNET_CONTAINER_HeapOrder order
How is the heap sorted?

◆ EXTRA_CHECKS

#define EXTRA_CHECKS   0

Definition at line 35 of file container_heap.c.

◆ CHECK

#define CHECK (   n)    do {} while (0)

Definition at line 129 of file container_heap.c.

Function Documentation

◆ node_iterator()

static int node_iterator ( const struct GNUNET_CONTAINER_Heap heap,
struct GNUNET_CONTAINER_HeapNode node,
GNUNET_CONTAINER_HeapIterator  iterator,
void *  iterator_cls 
)
static

Iterate over the children of the given node.

Parameters
heapargument to give to iterator
nodenode to iterate over
iteratorfunction to call on each node
iterator_clsclosure for iterator
Returns
GNUNET_YES to continue to iterate

Definition at line 210 of file container_heap.c.

213{
214 if (node == NULL)
215 return GNUNET_YES;
216 if (GNUNET_YES !=
217 node_iterator (heap, node->left_child, iterator, iterator_cls))
218 return GNUNET_NO;
219 if (GNUNET_YES !=
220 node_iterator (heap, node->right_child, iterator, iterator_cls))
221 return GNUNET_NO;
222 return iterator (iterator_cls, node, node->element, node->cost);
223}

References GNUNET_CONTAINER_HeapNode::cost, GNUNET_CONTAINER_HeapNode::element, GNUNET_NO, GNUNET_YES, GNUNET_CONTAINER_HeapNode::left_child, node_iterator(), and GNUNET_CONTAINER_HeapNode::right_child.

Referenced by GNUNET_CONTAINER_heap_iterate(), and node_iterator().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ insert_node()

static void insert_node ( struct GNUNET_CONTAINER_Heap heap,
struct GNUNET_CONTAINER_HeapNode pos,
struct GNUNET_CONTAINER_HeapNode node 
)
static

Insert the given node 'node' into the subtree starting at 'pos' (while keeping the tree somewhat balanced).

Parameters
heapheap to modify
posexisting tree
nodenode to insert (which may be a subtree itself)

Definition at line 263 of file container_heap.c.

266{
268
269 GNUNET_assert (node->parent == NULL);
270 while ((heap->order == GNUNET_CONTAINER_HEAP_ORDER_MAX) ? (pos->cost >=
271 node->cost)
272 : (pos->cost <= node->cost))
273 {
274 /* node is descendent of pos */
275 pos->tree_size += (1 + node->tree_size);
276 if (pos->left_child == NULL)
277 {
278 pos->left_child = node;
279 node->parent = pos;
280 return;
281 }
282 if (pos->right_child == NULL)
283 {
284 pos->right_child = node;
285 node->parent = pos;
286 return;
287 }
288 /* keep it balanced by descending into smaller subtree */
289 if (pos->left_child->tree_size < pos->right_child->tree_size)
290 pos = pos->left_child;
291 else
292 pos = pos->right_child;
293 }
294 /* make 'node' parent of 'pos' */
295 parent = pos->parent;
296 pos->parent = NULL;
297 node->parent = parent;
298 if (NULL == parent)
299 {
300 heap->root = node;
301 }
302 else
303 {
304 if (parent->left_child == pos)
305 parent->left_child = node;
306 else
307 parent->right_child = node;
308 }
309 /* insert 'pos' below 'node' */
310 insert_node (heap, node, pos);
311 CHECK (pos);
312}

References CHECK, GNUNET_CONTAINER_HeapNode::cost, GNUNET_assert, GNUNET_CONTAINER_HEAP_ORDER_MAX, GNUNET_CONTAINER_HeapNode::heap, insert_node(), GNUNET_CONTAINER_HeapNode::left_child, GNUNET_CONTAINER_Heap::order, GNUNET_CONTAINER_HeapNode::parent, GNUNET_CONTAINER_HeapNode::right_child, GNUNET_CONTAINER_Heap::root, and GNUNET_CONTAINER_HeapNode::tree_size.

Referenced by GNUNET_CONTAINER_heap_insert(), GNUNET_CONTAINER_heap_remove_root(), GNUNET_CONTAINER_heap_update_cost(), insert_node(), and remove_node().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_node()

static void remove_node ( struct GNUNET_CONTAINER_HeapNode node)
static

Remove the given node 'node' from the tree and update the 'tree_size' fields accordingly.

Preserves the children of 'node' and does NOT change the overall 'size' field of the tree.

Definition at line 389 of file container_heap.c.

390{
391 struct GNUNET_CONTAINER_HeapNode *ancestor;
392 struct GNUNET_CONTAINER_Heap *heap = node->heap;
393
394 /* update 'size' of the ancestors */
395 ancestor = node;
396 while (NULL != (ancestor = ancestor->parent))
397 ancestor->tree_size--;
398
399 /* update 'size' of node itself */
400 if (node->left_child != NULL)
401 node->tree_size -= (1 + node->left_child->tree_size);
402 if (node->right_child != NULL)
403 node->tree_size -= (1 + node->right_child->tree_size);
404
405 /* unlink 'node' itself and insert children in its place */
406 if (node->parent == NULL)
407 {
408 if (node->left_child != NULL)
409 {
410 heap->root = node->left_child;
411 node->left_child->parent = NULL;
412 if (node->right_child != NULL)
413 {
414 node->right_child->parent = NULL;
415 insert_node (heap, heap->root, node->right_child);
416 }
417 }
418 else
419 {
420 heap->root = node->right_child;
421 if (node->right_child != NULL)
422 node->right_child->parent = NULL;
423 }
424 }
425 else
426 {
427 if (node->parent->left_child == node)
428 node->parent->left_child = NULL;
429 else
430 node->parent->right_child = NULL;
431 if (node->left_child != NULL)
432 {
433 node->left_child->parent = NULL;
434 node->parent->tree_size -= (1 + node->left_child->tree_size);
435 insert_node (heap, node->parent, node->left_child);
436 }
437 if (node->right_child != NULL)
438 {
439 node->right_child->parent = NULL;
440 node->parent->tree_size -= (1 + node->right_child->tree_size);
441 insert_node (heap, node->parent, node->right_child);
442 }
443 }
444 node->parent = NULL;
445 node->left_child = NULL;
446 node->right_child = NULL;
447 GNUNET_assert (node->tree_size == 0);
448 CHECK (heap->root);
449}

References CHECK, GNUNET_assert, GNUNET_CONTAINER_HeapNode::heap, insert_node(), GNUNET_CONTAINER_HeapNode::left_child, GNUNET_CONTAINER_HeapNode::parent, GNUNET_CONTAINER_HeapNode::right_child, GNUNET_CONTAINER_Heap::root, and GNUNET_CONTAINER_HeapNode::tree_size.

Referenced by GNUNET_CONTAINER_heap_remove_node(), and GNUNET_CONTAINER_heap_update_cost().

Here is the call graph for this function:
Here is the caller graph for this function: