Line data Source code
1 : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2 :
3 : /***
4 : This file is part of systemd.
5 :
6 : Copyright 2013 Lennart Poettering
7 :
8 : systemd is free software; you can redistribute it and/or modify it
9 : under the terms of the GNU Lesser General Public License as published by
10 : the Free Software Foundation; either version 2.1 of the License, or
11 : (at your option) any later version.
12 :
13 : systemd is distributed in the hope that it will be useful, but
14 : WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : Lesser General Public License for more details.
17 :
18 : You should have received a copy of the GNU Lesser General Public License
19 : along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 : ***/
21 :
22 : #include "util.h"
23 : #include "prioq.h"
24 :
25 : struct prioq_item {
26 : void *data;
27 : unsigned *idx;
28 : };
29 :
30 : struct Prioq {
31 : compare_func_t compare_func;
32 : unsigned n_items, n_allocated;
33 :
34 : struct prioq_item *items;
35 : };
36 :
37 2071 : Prioq *prioq_new(compare_func_t compare_func) {
38 : Prioq *q;
39 :
40 2071 : q = new0(Prioq, 1);
41 2071 : if (!q)
42 0 : return q;
43 :
44 2071 : q->compare_func = compare_func;
45 2071 : return q;
46 : }
47 :
48 13389 : Prioq* prioq_free(Prioq *q) {
49 13389 : if (!q)
50 11318 : return NULL;
51 :
52 2071 : free(q->items);
53 2071 : free(q);
54 :
55 2071 : return NULL;
56 : }
57 :
58 1224 : int prioq_ensure_allocated(Prioq **q, compare_func_t compare_func) {
59 1224 : assert(q);
60 :
61 1224 : if (*q)
62 205 : return 0;
63 :
64 1019 : *q = prioq_new(compare_func);
65 1019 : if (!*q)
66 0 : return -ENOMEM;
67 :
68 1019 : return 0;
69 : }
70 :
71 78274 : static void swap(Prioq *q, unsigned j, unsigned k) {
72 : void *saved_data;
73 : unsigned *saved_idx;
74 :
75 78274 : assert(q);
76 78274 : assert(j < q->n_items);
77 78274 : assert(k < q->n_items);
78 :
79 78274 : assert(!q->items[j].idx || *(q->items[j].idx) == j);
80 78274 : assert(!q->items[k].idx || *(q->items[k].idx) == k);
81 :
82 78274 : saved_data = q->items[j].data;
83 78274 : saved_idx = q->items[j].idx;
84 78274 : q->items[j].data = q->items[k].data;
85 78274 : q->items[j].idx = q->items[k].idx;
86 78274 : q->items[k].data = saved_data;
87 78274 : q->items[k].idx = saved_idx;
88 :
89 78274 : if (q->items[j].idx)
90 33966 : *q->items[j].idx = j;
91 :
92 78274 : if (q->items[k].idx)
93 33966 : *q->items[k].idx = k;
94 78274 : }
95 :
96 28536 : static unsigned shuffle_up(Prioq *q, unsigned idx) {
97 28536 : assert(q);
98 :
99 68031 : while (idx > 0) {
100 : unsigned k;
101 :
102 28617 : k = (idx-1)/2;
103 :
104 28617 : if (q->compare_func(q->items[k].data, q->items[idx].data) < 0)
105 17658 : break;
106 :
107 10959 : swap(q, idx, k);
108 10959 : idx = k;
109 : }
110 :
111 28536 : return idx;
112 : }
113 :
114 13803 : static unsigned shuffle_down(Prioq *q, unsigned idx) {
115 13803 : assert(q);
116 :
117 : for (;;) {
118 : unsigned j, k, s;
119 :
120 81118 : k = (idx+1)*2; /* right child */
121 81118 : j = k-1; /* left child */
122 :
123 81118 : if (j >= q->n_items)
124 12606 : break;
125 :
126 68512 : if (q->compare_func(q->items[j].data, q->items[idx].data) < 0)
127 :
128 : /* So our left child is smaller than we are, let's
129 : * remember this fact */
130 65674 : s = j;
131 : else
132 2838 : s = idx;
133 :
134 136922 : if (k < q->n_items &&
135 68410 : q->compare_func(q->items[k].data, q->items[s].data) < 0)
136 :
137 : /* So our right child is smaller than we are, let's
138 : * remember this fact */
139 33475 : s = k;
140 :
141 : /* s now points to the smallest of the three items */
142 :
143 68512 : if (s == idx)
144 : /* No swap necessary, we're done */
145 1197 : break;
146 :
147 67315 : swap(q, idx, s);
148 67315 : idx = s;
149 67315 : }
150 :
151 13803 : return idx;
152 : }
153 :
154 14733 : int prioq_put(Prioq *q, void *data, unsigned *idx) {
155 : struct prioq_item *i;
156 : unsigned k;
157 :
158 14733 : assert(q);
159 :
160 14733 : if (q->n_items >= q->n_allocated) {
161 : unsigned n;
162 : struct prioq_item *j;
163 :
164 2094 : n = MAX((q->n_items+1) * 2, 16u);
165 2094 : j = realloc(q->items, sizeof(struct prioq_item) * n);
166 2094 : if (!j)
167 0 : return -ENOMEM;
168 :
169 2094 : q->items = j;
170 2094 : q->n_allocated = n;
171 : }
172 :
173 14733 : k = q->n_items++;
174 14733 : i = q->items + k;
175 14733 : i->data = data;
176 14733 : i->idx = idx;
177 :
178 14733 : if (idx)
179 10427 : *idx = k;
180 :
181 14733 : shuffle_up(q, k);
182 :
183 14733 : return 0;
184 : }
185 :
186 14729 : static void remove_item(Prioq *q, struct prioq_item *i) {
187 : struct prioq_item *l;
188 :
189 14729 : assert(q);
190 14729 : assert(i);
191 :
192 14729 : l = q->items + q->n_items - 1;
193 :
194 14729 : if (i == l)
195 : /* Last entry, let's just remove it */
196 5456 : q->n_items--;
197 : else {
198 : unsigned k;
199 :
200 : /* Not last entry, let's replace the last entry with
201 : * this one, and reshuffle */
202 :
203 9273 : k = i - q->items;
204 :
205 9273 : i->data = l->data;
206 9273 : i->idx = l->idx;
207 9273 : if (i->idx)
208 4978 : *i->idx = k;
209 9273 : q->n_items--;
210 :
211 9273 : k = shuffle_down(q, k);
212 9273 : shuffle_up(q, k);
213 : }
214 14729 : }
215 :
216 11881 : _pure_ static struct prioq_item* find_item(Prioq *q, void *data, unsigned *idx) {
217 : struct prioq_item *i;
218 :
219 11881 : assert(q);
220 :
221 11881 : if (idx) {
222 23762 : if (*idx == PRIOQ_IDX_NULL ||
223 11881 : *idx > q->n_items)
224 0 : return NULL;
225 :
226 11881 : i = q->items + *idx;
227 11881 : if (i->data != data)
228 0 : return NULL;
229 :
230 11881 : return i;
231 : } else {
232 0 : for (i = q->items; i < q->items + q->n_items; i++)
233 0 : if (i->data == data)
234 0 : return i;
235 0 : return NULL;
236 : }
237 : }
238 :
239 7351 : int prioq_remove(Prioq *q, void *data, unsigned *idx) {
240 : struct prioq_item *i;
241 :
242 7351 : if (!q)
243 0 : return 0;
244 :
245 7351 : i = find_item(q, data, idx);
246 7351 : if (!i)
247 0 : return 0;
248 :
249 7351 : remove_item(q, i);
250 7351 : return 1;
251 : }
252 :
253 4530 : int prioq_reshuffle(Prioq *q, void *data, unsigned *idx) {
254 : struct prioq_item *i;
255 : unsigned k;
256 :
257 4530 : assert(q);
258 :
259 4530 : i = find_item(q, data, idx);
260 4530 : if (!i)
261 0 : return 0;
262 :
263 4530 : k = i - q->items;
264 4530 : k = shuffle_down(q, k);
265 4530 : shuffle_up(q, k);
266 4530 : return 1;
267 : }
268 :
269 99253 : void *prioq_peek(Prioq *q) {
270 :
271 99253 : if (!q)
272 73711 : return NULL;
273 :
274 25542 : if (q->n_items <= 0)
275 5189 : return NULL;
276 :
277 20353 : return q->items[0].data;
278 : }
279 :
280 7398 : void *prioq_pop(Prioq *q) {
281 : void *data;
282 :
283 7398 : if (!q)
284 10 : return NULL;
285 :
286 7388 : if (q->n_items <= 0)
287 10 : return NULL;
288 :
289 7378 : data = q->items[0].data;
290 7378 : remove_item(q, q->items);
291 7378 : return data;
292 : }
293 :
294 7168 : unsigned prioq_size(Prioq *q) {
295 :
296 7168 : if (!q)
297 0 : return 0;
298 :
299 7168 : return q->n_items;
300 : }
301 :
302 2 : bool prioq_isempty(Prioq *q) {
303 :
304 2 : if (!q)
305 0 : return true;
306 :
307 2 : return q->n_items <= 0;
308 : }
|