Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
"new ruby host method"
[simgrid.git] / src / xbt / heap.c
1 /*      $Id$     */
2
3 /* a generic and efficient heap                                             */
4
5 /* Copyright (c) 2004 Arnaud Legrand. All rights reserved.                  */
6
7 /* This program is free software; you can redistribute it and/or modify it
8  * under the terms of the license (GNU LGPL) which comes with this package. */
9
10 #include "xbt/sysdep.h"
11 #include "xbt/log.h"
12 #include "heap_private.h"
13
14 #include <stdio.h>
15
16
17 /** @addtogroup XBT_heap
18  *  \brief This section describes the API to generic heap with O(log(n)) access.
19  */
20
21 /**
22  * @brief Creates a new heap.
23  * \param init_size initial size of the heap
24  * \param free_func function to call on each element when you want to free
25  *             the whole heap (or NULL if nothing to do).
26  *
27  * Creates a new heap.
28  */
29 XBT_INLINE xbt_heap_t xbt_heap_new(int init_size, void_f_pvoid_t const free_func)
30 {
31   xbt_heap_t H = xbt_new0(struct xbt_heap, 1);
32   H->size = init_size;
33   H->count = 0;
34   H->items = (xbt_heapItem_t) xbt_new0(struct xbt_heapItem, init_size);
35   H->free = free_func;
36   return H;
37 }
38
39 /**
40  * @brief Set the update callback function.
41  * @param H the heap we're working on
42  * \param update_callback function to call on each element to update its index when needed.
43  */
44 XBT_INLINE void xbt_heap_set_update_callback(xbt_heap_t H,
45                                   void (*update_callback) (void *, int))
46 {
47   H->update_callback = update_callback;
48 }
49
50
51 /**
52  * @brief kilkil a heap and its content
53  * @param H poor victim
54  */
55 void xbt_heap_free(xbt_heap_t H)
56 {
57   int i;
58   if (H->free)
59     for (i = 0; i < H->count; i++)
60       (*(H->free)) (H->items[i].content);
61   free(H->items);
62   free(H);
63   return;
64 }
65
66 /**
67  * @brief returns the number of elements in the heap
68  * @param H the heap we're working on
69  * @return the number of elements in the heap
70  */
71 XBT_INLINE int xbt_heap_size(xbt_heap_t H)
72 {
73   return (H->count);
74 }
75
76 /**
77  * @brief Add an element into the heap.
78  * \param H the heap we're working on
79  * \param content the object you want to add to the heap
80  * \param key the key associated to this object
81  *
82  * The element with the smallest key is automatically moved at the top of the heap.
83  */
84 void xbt_heap_push(xbt_heap_t H, void *content, double key)
85 {
86   int count = ++(H->count);
87
88   int size = H->size;
89   xbt_heapItem_t item;
90
91   if (count > size) {
92     H->size = 2 * size + 1;
93     H->items =
94       (void *) realloc(H->items, (H->size) * sizeof(struct xbt_heapItem));
95   }
96
97   item = &(H->items[count - 1]);
98   item->key = key;
99   item->content = content;
100   xbt_heap_increaseKey(H, count - 1);
101   return;
102 }
103
104 /**
105  * @brief Extracts from the heap and returns the element with the smallest key.
106  * \param H the heap we're working on
107  * \return the element with the smallest key
108  *
109  * Extracts from the heap and returns the element with the smallest
110  * key. The element with the next smallest key is automatically moved
111  * at the top of the heap.
112  */
113 void *xbt_heap_pop(xbt_heap_t H)
114 {
115   void *max;
116
117   if (H->count == 0)
118     return NULL;
119
120   max = CONTENT(H, 0);
121
122   H->items[0] = H->items[(H->count) - 1];
123   (H->count)--;
124   xbt_heap_maxHeapify(H);
125   if (H->count < H->size / 4 && H->size > 16) {
126     H->size = H->size / 2 + 1;
127     H->items =
128       (void *) realloc(H->items, (H->size) * sizeof(struct xbt_heapItem));
129   }
130
131   H->update_callback ? H->update_callback(max, -1) : NULL;
132   return max;
133 }
134
135 /**
136  * @brief Extracts from the heap and returns the element at position i.
137  * \param H the heap we're working on
138  * \param i     element position
139  * \return the element at position i if ok, NULL otherwise
140  *
141  * Extracts from the heap and returns the element at position i. The head is automatically reorded.
142  */
143 void *xbt_heap_remove(xbt_heap_t H, int i)
144 {
145   if ((i < 0) || (i > H->count - 1))
146     return NULL;
147   /* put element i at head */
148   if (i > 0) {
149     KEY(H, i) = MIN_KEY_VALUE;
150     xbt_heap_increaseKey(H, i);
151   }
152
153   return xbt_heap_pop(H);
154 }
155
156 /**
157  * @brief returns the smallest key in the heap (heap unchanged)
158  * \param H the heap we're working on
159  *
160  * \return the smallest key in the heap without modifying the heap.
161  */
162 XBT_INLINE double xbt_heap_maxkey(xbt_heap_t H)
163 {
164   xbt_assert0(H->count != 0, "Empty heap");
165   return KEY(H, 0);
166 }
167
168 /**
169  * @brief returns the value associated to the smallest key in the heap (heap unchanged)
170  * \param H the heap we're working on
171  *
172  * \return the value associated to the smallest key in the heap
173  * without modifying the heap.
174  */
175 void *xbt_heap_maxcontent(xbt_heap_t H)
176 {
177   xbt_assert0(H->count != 0, "Empty heap");
178   return CONTENT(H, 0);
179 }
180
181 /* <<<< private >>>>
182  * \param H the heap we're working on
183  *
184  * Restores the heap property once an element has been deleted.
185  */
186 static void xbt_heap_maxHeapify(xbt_heap_t H)
187 {
188   int i = 0;
189   while (1) {
190     int greatest = i;
191     int l = LEFT(i);
192     int r = RIGHT(i);
193     int count = H->count;
194     if (l < count && KEY(H, l) < KEY(H, i))
195       greatest = l;
196     if (r < count && KEY(H, r) < KEY(H, greatest))
197       greatest = r;
198     if (greatest != i) {
199       struct xbt_heapItem tmp = H->items[i];
200       H->items[i] = H->items[greatest];
201       H->items[greatest] = tmp;
202       H->update_callback ? H->update_callback(CONTENT(H, i), i) : NULL;
203       i = greatest;
204     } else {
205       H->update_callback ? H->update_callback(CONTENT(H, i), i) : NULL;
206       return;
207     }
208   }
209 }
210
211 /* <<<< private >>>>
212  * \param H the heap we're working on
213  * \param i an item position in the heap
214  *
215  * Moves up an item at position i to its correct position. Works only
216  * when called from xbt_heap_push. Do not use otherwise.
217  */
218 static void xbt_heap_increaseKey(xbt_heap_t H, int i)
219 {
220   while (i > 0 && KEY(H, PARENT(i)) > KEY(H, i)) {
221     struct xbt_heapItem tmp = H->items[i];
222     H->items[i] = H->items[PARENT(i)];
223     H->items[PARENT(i)] = tmp;
224     H->update_callback ? H->update_callback(CONTENT(H, i), i) : NULL;
225     i = PARENT(i);
226   }
227   H->update_callback ? H->update_callback(CONTENT(H, i), i) : NULL;
228   return;
229 }
230