license note added, cleaned up per-file doxygen comments and include guards, cleaned...
[libfirm] / ir / adt / pqueue.c
1 /*
2  * Copyrigth (C) 1995-2007 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @author  Christian Wuerdig, Matthias Braun
23  * @brief   Priority Queue implementation based on the heap datastructure
24  * @version $Id$
25  */
26 #include "array.h"
27 #include "pqueue.h"
28
29 /*
30  * Implements a heap.
31  *
32  * Implementation note: It might seem strange that we start indexing at 0
33  * but use 2*i and 2*i+1 to find the left and right sucessor of an index.
34  * The trick is that for index 0 the left successor is 0 again, and the
35  * right successor is 1 in this scheme. For the right successor 1 everything
36  * works like usual. We simply took care in the algorithms that they still
37  * work with the left child of 0 being 0 again. This was possible without
38  * any extra ifs or arithmetic.
39  * Thus we can save the wastage of 1 array position you can see in other
40  * implementations or the ugly (i+1)*2 - 1 and (i+1)*2 for calculating the
41  * left and right child. (At the expense that stuff easily breaks when you make
42  * changes and don't think that the left child of 0 is 0 :-/)
43  *
44  */
45
46 typedef struct _pqueue_el_t {
47         void *data;
48         int  key;
49 } pqueue_el_t;
50
51 struct _pqueue_t {
52         pqueue_el_t *elems;
53 };
54
55 /**
56  * Enforces the heap characteristics if the queue
57  * starting from element at position @p pos.
58  */
59 static void pqueue_heapify(pqueue *q, int pos) {
60         int len = ARR_LEN(q->elems);
61
62         while (pos * 2 < len) {
63                 pqueue_el_t tmp;
64                 int         exchange = pos;
65
66                 if (q->elems[exchange].key < q->elems[pos * 2].key) {
67                         exchange = pos * 2;
68                 }
69
70                 if ((pos * 2 + 1) < len && q->elems[exchange].key < q->elems[pos * 2 + 1].key) {
71                         exchange = pos * 2 + 1;
72                 }
73
74                 if (exchange == pos)
75                         break;
76
77                 tmp                = q->elems[pos];
78                 q->elems[pos]      = q->elems[exchange];
79                 q->elems[exchange] = tmp;
80
81                 pos = exchange;
82         }
83 }
84
85 /**
86  * Sifts up a newly inserted element at position @p pos.
87  */
88 static void pqueue_sift_up(pqueue *q, int pos) {
89         while(q->elems[pos].key > q->elems[pos / 2].key) {
90                 pqueue_el_t tmp;
91
92                 tmp               = q->elems[pos];
93                 q->elems[pos]     = q->elems[pos / 2];
94                 q->elems[pos / 2] = tmp;
95
96                 pos /= 2;
97         }
98 }
99
100 /**
101  * Creates a new priority queue.
102  * @return A priority queue of initial length 0.
103  */
104 pqueue *new_pqueue(void) {
105         pqueue *res = xmalloc(sizeof(*res));
106         res->elems = NEW_ARR_F(pqueue_el_t, 0);
107         return res;
108 }
109
110 /**
111  * Frees all memory allocated by the priority queue.
112  * @param q   The priority queue to destroy.
113  */
114 void del_pqueue(pqueue *q) {
115         DEL_ARR_F(q->elems);
116         free(q);
117 }
118
119 /**
120  * Inserts a new element into a priority queue.
121  * @param q      The priority queue the element should be inserted to.
122  * @param data   The actual data which should be stored in the queue.
123  * @param key    The priority for the data.
124  */
125 void pqueue_put(pqueue *q, void *data, int key) {
126         pqueue_el_t el;
127
128         el.data = data;
129         el.key  = key;
130
131         ARR_APP1(pqueue_el_t, q->elems, el);
132
133         pqueue_sift_up(q, ARR_LEN(q->elems) - 1);
134 }
135
136 /**
137  * Returns and removes the first element, ie. that one with the highest priority, from the queue.
138  * @param q   The priority queue.
139  * @return The first element of the queue. Asserts if queue is empty.
140  */
141 void *pqueue_get(pqueue *q) {
142         switch(ARR_LEN(q->elems)) {
143                 case 0:
144                         assert(0 && "Attempt to retrieve element from empty priority queue.");
145                         return NULL;
146                         break;
147                 case 1:
148                         ARR_SHRINKLEN(q->elems, 0);
149                         return q->elems[0].data;
150                         break;
151                 default: {
152                         void *data = q->elems[0].data;
153                         int  len   = ARR_LEN(q->elems) - 1;
154
155                         q->elems[0] = q->elems[len];
156                         ARR_SHRINKLEN(q->elems, len);
157                         pqueue_heapify(q, 0);
158
159                         return data;
160                 }
161         }
162 }
163
164 /**
165  * Get the length of the priority queue.
166  * @param q   The priority queue.
167  * @return The length of the queue.
168  */
169 int pqueue_length(pqueue *q) {
170         return ARR_LEN(q->elems);
171 }
172
173 /**
174  * Returns true if queue is empty.
175  * @param q   The priority queue.
176  * @return 1 if the queue is empty, 0 otherwise.
177  */
178 int pqueue_empty(pqueue *q) {
179         return ARR_LEN(q->elems) == 0;
180 }