-dce
[oweals/gnunet.git] / src / util / container_heap.c
index 78881d8081d898aa8b67c357cc17081b7dfa0cd6..c34e220ce9cd4a4a16a471dceaedd7779d244b38 100644 (file)
@@ -1,17 +1,17 @@
 /*
   This file is part of GNUnet.
   (C) 2008, 2009 Christian Grothoff (and other contributing authors)
-  
+
   GNUnet is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published
   by the Free Software Foundation; either version 2, or (at your
   option) any later version.
-  
+
   GNUnet is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.
-  
+
   You should have received a copy of the GNU General Public License
   along with GNUnet; see the file COPYING.  If not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
@@ -28,6 +28,7 @@
 #include "platform.h"
 #include "gnunet_util_lib.h"
 
+#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
 
 #define DEBUG 0
 
  */
 struct GNUNET_CONTAINER_HeapNode
 {
+  /**
+   * Heap this node belongs to.
+   */
+  struct GNUNET_CONTAINER_Heap *heap;
+
   /**
    * Parent node.
    */
@@ -89,7 +95,7 @@ struct GNUNET_CONTAINER_Heap
    * Number of elements in the heap.
    */
   unsigned int size;
-  
+
   /**
    * How is the heap sorted?
    */
@@ -103,15 +109,17 @@ struct GNUNET_CONTAINER_Heap
  * Check if internal invariants hold for the given node.
  *
  * @param node subtree to check
- */ 
+ */
 static void
 check (const struct GNUNET_CONTAINER_HeapNode *node)
-{  
+{
   if (NULL == node)
     return;
   GNUNET_assert (node->tree_size ==
-                ( (node->left_child == NULL) ? 0 : 1 + node->left_child->tree_size) +
-                ( (node->right_child == NULL) ? 0 : 1 + node->right_child->tree_size) );
+                 ((node->left_child ==
+                   NULL) ? 0 : 1 + node->left_child->tree_size) +
+                 ((node->right_child ==
+                   NULL) ? 0 : 1 + node->right_child->tree_size));
   check (node->left_child);
   check (node->right_child);
 }
@@ -182,6 +190,19 @@ GNUNET_CONTAINER_heap_get_size (const struct GNUNET_CONTAINER_Heap *heap)
 }
 
 
+/**
+ * Get the current cost of the node
+ *
+ * @param node the node to get the cost of
+ * @return cost of the node
+ */
+GNUNET_CONTAINER_HeapCostType
+GNUNET_CONTAINER_heap_node_get_cost (const struct GNUNET_CONTAINER_HeapNode
+                                     *node)
+{
+  return node->cost;
+}
+
 /**
  * Iterate over the children of the given node.
  *
@@ -193,26 +214,18 @@ GNUNET_CONTAINER_heap_get_size (const struct GNUNET_CONTAINER_Heap *heap)
  */
 static int
 node_iterator (const struct GNUNET_CONTAINER_Heap *heap,
-              struct GNUNET_CONTAINER_HeapNode *node,
-              GNUNET_CONTAINER_HeapIterator iterator, 
-              void *iterator_cls)
+               struct GNUNET_CONTAINER_HeapNode *node,
+               GNUNET_CONTAINER_HeapIterator iterator, void *iterator_cls)
 {
   if (node == NULL)
     return GNUNET_YES;
-  if (GNUNET_YES != node_iterator (heap,
-                                  node->left_child,
-                                  iterator,
-                                  iterator_cls))
+  if (GNUNET_YES !=
+      node_iterator (heap, node->left_child, iterator, iterator_cls))
     return GNUNET_NO;
-  if (GNUNET_YES != node_iterator (heap,
-                                  node->right_child,
-                                  iterator, 
-                                  iterator_cls))
+  if (GNUNET_YES !=
+      node_iterator (heap, node->right_child, iterator, iterator_cls))
     return GNUNET_NO;
-  return iterator (iterator_cls,
-                  node,
-                  node->element,
-                  node->cost);
+  return iterator (iterator_cls, node, node->element, node->cost);
 }
 
 
@@ -252,13 +265,13 @@ GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *heap)
   if (heap->root == NULL)
     return NULL;
   pos = heap->walk_pos;
-  if (pos == NULL) 
-    pos = heap->root;   
+  if (pos == NULL)
+    pos = heap->root;
   element = pos->element;
-  heap->walk_pos 
-    = (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
-    ? pos->right_child 
-    : pos->left_child;
+  heap->walk_pos =
+      (0 ==
+       GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+                                 2)) ? pos->right_child : pos->left_child;
   return element;
 }
 
@@ -273,51 +286,51 @@ GNUNET_CONTAINER_heap_walk_get_next (struct GNUNET_CONTAINER_Heap *heap)
  */
 static void
 insert_node (struct GNUNET_CONTAINER_Heap *heap,
-            struct GNUNET_CONTAINER_HeapNode *pos,
-            struct GNUNET_CONTAINER_HeapNode *node)
+             struct GNUNET_CONTAINER_HeapNode *pos,
+             struct GNUNET_CONTAINER_HeapNode *node)
 {
   struct GNUNET_CONTAINER_HeapNode *parent;
 
   GNUNET_assert (node->parent == NULL);
-  while ( (heap->order == GNUNET_CONTAINER_HEAP_ORDER_MAX) 
-         ? (pos->cost >= node->cost) 
-         : (pos->cost <= node->cost) )
+  while ((heap->order == GNUNET_CONTAINER_HEAP_ORDER_MAX) ? (pos->cost >=
+                                                             node->cost)
+         : (pos->cost <= node->cost))
+  {
+    /* node is descendent of pos */
+    pos->tree_size += (1 + node->tree_size);
+    if (pos->left_child == NULL)
     {
-      /* node is descendent of pos */
-      pos->tree_size += (1 + node->tree_size);
-      if (pos->left_child == NULL)
-       {
-         pos->left_child = node;
-         node->parent = pos;
-         return;
-       }
-      if (pos->right_child == NULL)
-       {
-         pos->right_child = node;
-         node->parent = pos;
-         return;
-       }
-      /* keep it balanced by descending into smaller subtree */
-      if (pos->left_child->tree_size < pos->right_child->tree_size)
-       pos = pos->left_child;
-      else
-       pos = pos->right_child;
+      pos->left_child = node;
+      node->parent = pos;
+      return;
     }
+    if (pos->right_child == NULL)
+    {
+      pos->right_child = node;
+      node->parent = pos;
+      return;
+    }
+    /* keep it balanced by descending into smaller subtree */
+    if (pos->left_child->tree_size < pos->right_child->tree_size)
+      pos = pos->left_child;
+    else
+      pos = pos->right_child;
+  }
   /* make 'node' parent of 'pos' */
   parent = pos->parent;
   pos->parent = NULL;
   node->parent = parent;
   if (NULL == parent)
-    {
-      heap->root = node;
-    }
+  {
+    heap->root = node;
+  }
   else
-    {
-      if (parent->left_child == pos)
-       parent->left_child = node;
-      else
-       parent->right_child = node;
-    }
+  {
+    if (parent->left_child == pos)
+      parent->left_child = node;
+    else
+      parent->right_child = node;
+  }
   /* insert 'pos' below 'node' */
   insert_node (heap, node, pos);
   CHECK (pos);
@@ -333,13 +346,13 @@ insert_node (struct GNUNET_CONTAINER_Heap *heap,
  * @return node for the new element
  */
 struct GNUNET_CONTAINER_HeapNode *
-GNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *heap,
-                              void *element,
-                             GNUNET_CONTAINER_HeapCostType cost)
+GNUNET_CONTAINER_heap_insert (struct GNUNET_CONTAINER_Heap *heap, void *element,
+                              GNUNET_CONTAINER_HeapCostType cost)
 {
   struct GNUNET_CONTAINER_HeapNode *node;
 
   node = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_HeapNode));
+  node->heap = heap;
   node->element = element;
   node->cost = cost;
   heap->size++;
@@ -370,29 +383,27 @@ GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *heap)
   heap->size--;
   ret = root->element;
   if (root->left_child == NULL)
-    {
-      heap->root = root->right_child;
-      if (root->right_child != NULL)
-       root->right_child->parent = NULL;
-    }
+  {
+    heap->root = root->right_child;
+    if (root->right_child != NULL)
+      root->right_child->parent = NULL;
+  }
   else if (root->right_child == NULL)
-    {
-      heap->root = root->left_child;
-      if (root->left_child != NULL)
-       root->left_child->parent = NULL;
-    }
+  {
+    heap->root = root->left_child;
+    root->left_child->parent = NULL;
+  }
   else
-    {
-      root->left_child->parent = NULL;
-      root->right_child->parent = NULL;
-      heap->root = root->left_child;
-      insert_node (heap, heap->root, root->right_child);
-    }
+  {
+    root->left_child->parent = NULL;
+    root->right_child->parent = NULL;
+    heap->root = root->left_child;
+    insert_node (heap, heap->root, root->right_child);
+  }
   GNUNET_free (root);
 #if DEBUG
-  GNUNET_assert (( (heap->size == 0) && 
-                  (heap->root == NULL) ) ||
-                (heap->size == heap->root->tree_size + 1) );
+  GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) ||
+                 (heap->size == heap->root->tree_size + 1));
   CHECK (heap->root);
 #endif
   return ret;
@@ -406,14 +417,14 @@ GNUNET_CONTAINER_heap_remove_root (struct GNUNET_CONTAINER_Heap *heap)
  * 'size' field of the tree.
  */
 static void
-remove_node (struct GNUNET_CONTAINER_Heap *heap,
-            struct GNUNET_CONTAINER_HeapNode *node)
+remove_node (struct GNUNET_CONTAINER_HeapNode *node)
 {
   struct GNUNET_CONTAINER_HeapNode *ancestor;
+  struct GNUNET_CONTAINER_Heap *heap = node->heap;
 
   /* update 'size' of the ancestors */
   ancestor = node;
-  while (NULL != (ancestor = ancestor->parent))    
+  while (NULL != (ancestor = ancestor->parent))
     ancestor->tree_size--;
 
   /* update 'size' of node itself */
@@ -424,43 +435,43 @@ remove_node (struct GNUNET_CONTAINER_Heap *heap,
 
   /* unlink 'node' itself and insert children in its place */
   if (node->parent == NULL)
+  {
+    if (node->left_child != NULL)
     {
-      if (node->left_child != NULL)
-       {
-         heap->root = node->left_child;
-         node->left_child->parent = NULL;
-         if (node->right_child != NULL)
-           {
-             node->right_child->parent = NULL;
-             insert_node (heap, heap->root, node->right_child);        
-           }
-       }
-      else
-       {
-         heap->root = node->right_child;
-         if (node->right_child != NULL)
-           node->right_child->parent = NULL;
-       }
+      heap->root = node->left_child;
+      node->left_child->parent = NULL;
+      if (node->right_child != NULL)
+      {
+        node->right_child->parent = NULL;
+        insert_node (heap, heap->root, node->right_child);
+      }
     }
-  else
+    else
     {
-      if (node->parent->left_child == node)
-       node->parent->left_child = NULL;
-      else
-       node->parent->right_child = NULL;
-      if (node->left_child != NULL)
-       {
-         node->left_child->parent = NULL;
-         node->parent->tree_size -= (1 + node->left_child->tree_size);
-         insert_node (heap, node->parent, node->left_child);
-       }
+      heap->root = node->right_child;
       if (node->right_child != NULL)
-       {
-         node->right_child->parent = NULL;
-         node->parent->tree_size -= (1 + node->right_child->tree_size);
-         insert_node (heap, node->parent, node->right_child);
-       }
+        node->right_child->parent = NULL;
+    }
+  }
+  else
+  {
+    if (node->parent->left_child == node)
+      node->parent->left_child = NULL;
+    else
+      node->parent->right_child = NULL;
+    if (node->left_child != NULL)
+    {
+      node->left_child->parent = NULL;
+      node->parent->tree_size -= (1 + node->left_child->tree_size);
+      insert_node (heap, node->parent, node->left_child);
+    }
+    if (node->right_child != NULL)
+    {
+      node->right_child->parent = NULL;
+      node->parent->tree_size -= (1 + node->right_child->tree_size);
+      insert_node (heap, node->parent, node->right_child);
     }
+  }
   node->parent = NULL;
   node->left_child = NULL;
   node->right_child = NULL;
@@ -471,21 +482,21 @@ remove_node (struct GNUNET_CONTAINER_Heap *heap,
 
 /**
  * Removes a node from the heap.
- * 
- * @param heap heap to modify
+ *
  * @param node node to remove
  * @return element data stored at the node
  */
 void *
-GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_Heap *heap,
-                                   struct GNUNET_CONTAINER_HeapNode *node)
+GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_HeapNode *node)
 {
   void *ret;
+  struct GNUNET_CONTAINER_Heap *heap;
+
+  heap = node->heap;
   CHECK (heap->root);
   if (heap->walk_pos == node)
     (void) GNUNET_CONTAINER_heap_walk_get_next (heap);
-  remove_node (heap, node);
+  remove_node (node);
   heap->size--;
   ret = node->element;
   if (heap->walk_pos == node)
@@ -493,9 +504,8 @@ GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_Heap *heap,
   GNUNET_free (node);
 #if DEBUG
   CHECK (heap->root);
-  GNUNET_assert (( (heap->size == 0) && 
-                  (heap->root == NULL) ) ||
-                (heap->size == heap->root->tree_size + 1) );
+  GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) ||
+                 (heap->size == heap->root->tree_size + 1));
 #endif
   return ret;
 }
@@ -510,21 +520,19 @@ GNUNET_CONTAINER_heap_remove_node (struct GNUNET_CONTAINER_Heap *heap,
  */
 void
 GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_Heap *heap,
-                                   struct GNUNET_CONTAINER_HeapNode *node, 
-                                  GNUNET_CONTAINER_HeapCostType new_cost)
+                                   struct GNUNET_CONTAINER_HeapNode *node,
+                                   GNUNET_CONTAINER_HeapCostType new_cost)
 {
 #if DEBUG
-  GNUNET_assert ( ( (heap->size == 0) && 
-                   (heap->root == NULL) ) ||
-                 (heap->size == heap->root->tree_size + 1) );
+  GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) ||
+                 (heap->size == heap->root->tree_size + 1));
   CHECK (heap->root);
 #endif
-  remove_node (heap, node);
+  remove_node (node);
 #if DEBUG
   CHECK (heap->root);
-  GNUNET_assert ( ( (heap->size == 1) && 
-                   (heap->root == NULL) ) ||
-                 (heap->size == heap->root->tree_size + 2) );
+  GNUNET_assert (((heap->size == 1) && (heap->root == NULL)) ||
+                 (heap->size == heap->root->tree_size + 2));
 #endif
   node->cost = new_cost;
   if (heap->root == NULL)
@@ -533,9 +541,8 @@ GNUNET_CONTAINER_heap_update_cost (struct GNUNET_CONTAINER_Heap *heap,
     insert_node (heap, heap->root, node);
 #if DEBUG
   CHECK (heap->root);
-  GNUNET_assert ( ( (heap->size == 0) && 
-                   (heap->root == NULL) ) ||
-                 (heap->size == heap->root->tree_size + 1) );
+  GNUNET_assert (((heap->size == 0) && (heap->root == NULL)) ||
+                 (heap->size == heap->root->tree_size + 1));
 #endif
 }