tv: Remove mul_table[][][] and simply use * and <<.
[libfirm] / ir / adt / pqueue.c
1 /*
2  * Copyright (C) 1995-2011 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  */
25 #include "config.h"
26
27 #include "array.h"
28 #include "pqueue.h"
29 #include "error.h"
30
31 /*
32  * Implements a heap.
33  *
34  * Implementation note: It might seem strange that we start indexing at 0
35  * but use 2*i and 2*i+1 to find the left and right sucessor of an index.
36  * The trick is that for index 0 the left successor is 0 again, and the
37  * right successor is 1 in this scheme. For the right successor 1 everything
38  * works like usual. We simply took care in the algorithms that they still
39  * work with the left child of 0 being 0 again. This was possible without
40  * any extra ifs or arithmetic.
41  * Thus we can save the wastage of 1 array position you can see in other
42  * implementations or the ugly (i+1)*2 - 1 and (i+1)*2 for calculating the
43  * left and right child. (At the expense that stuff easily breaks when you make
44  * changes and don't think that the left child of 0 is 0 :-/)
45  *
46  */
47
48 typedef struct pqueue_el_t {
49         void *data;
50         int  priority;
51 } pqueue_el_t;
52
53 struct pqueue_t {
54         pqueue_el_t *elems;
55 };
56
57 /**
58  * Enforces the heap characteristics if the queue
59  * starting from element at position @p pos.
60  */
61 static void pqueue_heapify(pqueue_t *q, size_t pos)
62 {
63         size_t len = ARR_LEN(q->elems);
64
65         while (pos * 2 < len) {
66                 pqueue_el_t tmp;
67                 size_t      exchange = pos;
68
69                 if (q->elems[exchange].priority < q->elems[pos * 2].priority) {
70                         exchange = pos * 2;
71                 }
72
73                 if ((pos * 2 + 1) < len
74                                 && q->elems[exchange].priority < q->elems[pos * 2 + 1].priority) {
75                         exchange = pos * 2 + 1;
76                 }
77
78                 if (exchange == pos)
79                         break;
80
81                 tmp                = q->elems[pos];
82                 q->elems[pos]      = q->elems[exchange];
83                 q->elems[exchange] = tmp;
84
85                 pos = exchange;
86         }
87 }
88
89 /**
90  * Sifts up a newly inserted element at position @p pos.
91  */
92 static void pqueue_sift_up(pqueue_t *q, size_t pos)
93 {
94         while (q->elems[pos].priority > q->elems[pos / 2].priority) {
95                 pqueue_el_t tmp;
96
97                 tmp               = q->elems[pos];
98                 q->elems[pos]     = q->elems[pos / 2];
99                 q->elems[pos / 2] = tmp;
100
101                 pos /= 2;
102         }
103 }
104
105 pqueue_t *new_pqueue(void)
106 {
107         pqueue_t *res = XMALLOC(pqueue_t);
108         res->elems = NEW_ARR_F(pqueue_el_t, 0);
109         return res;
110 }
111
112 void del_pqueue(pqueue_t *q)
113 {
114         DEL_ARR_F(q->elems);
115         free(q);
116 }
117
118 void pqueue_put(pqueue_t *q, void *data, int priority)
119 {
120         pqueue_el_t el;
121
122         el.data     = data;
123         el.priority = priority;
124
125         ARR_APP1(pqueue_el_t, q->elems, el);
126
127         pqueue_sift_up(q, ARR_LEN(q->elems) - 1);
128 }
129
130 void *pqueue_pop_front(pqueue_t *q)
131 {
132         switch (ARR_LEN(q->elems)) {
133                 case 0:
134                         panic("Attempt to retrieve element from empty priority queue.");
135                 case 1:
136                         ARR_SHRINKLEN(q->elems, 0);
137                         return q->elems[0].data;
138                 default: {
139                         void   *data = q->elems[0].data;
140                         size_t len   = ARR_LEN(q->elems) - 1;
141
142                         q->elems[0] = q->elems[len];
143                         ARR_SHRINKLEN(q->elems, len);
144                         pqueue_heapify(q, 0);
145
146                         return data;
147                 }
148         }
149 }
150
151 size_t pqueue_length(const pqueue_t *q)
152 {
153         return ARR_LEN(q->elems);
154 }
155
156 int pqueue_empty(const pqueue_t *q)
157 {
158         return ARR_LEN(q->elems) == 0;
159 }