1 /*** 2 This file is part of avahi. 3 4 avahi is free software; you can redistribute it and/or modify it 5 under the terms of the GNU Lesser General Public License as 6 published by the Free Software Foundation; either version 2.1 of the 7 License, or (at your option) any later version. 8 9 avahi is distributed in the hope that it will be useful, but WITHOUT 10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 11 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General 12 Public License for more details. 13 14 You should have received a copy of the GNU Lesser General Public 15 License along with avahi; if not, write to the Free Software 16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 17 USA. 18 ***/ 19 20 #ifdef HAVE_CONFIG_H 21 #include <config.h> 22 #endif 23 24 #include <assert.h> 25 #include <stdlib.h> 26 27 #include "avahi-common/avahi-malloc.h" 28 29 #include "prioq.h" 30 31 AvahiPrioQueue* avahi_prio_queue_new(AvahiPQCompareFunc compare) { 32 AvahiPrioQueue *q; 33 assert(compare); 34 35 if (!(q = avahi_new(AvahiPrioQueue, 1))) 36 return NULL; /* OOM */ 37 38 q->root = q->last = NULL; 39 q->n_nodes = 0; 40 q->compare = compare; 41 42 return q; 43 } 44 45 void avahi_prio_queue_free(AvahiPrioQueue *q) { 46 assert(q); 47 48 while (q->last) 49 avahi_prio_queue_remove(q, q->last); 50 51 assert(!q->n_nodes); 52 avahi_free(q); 53 } 54 55 static AvahiPrioQueueNode* get_node_at_xy(AvahiPrioQueue *q, unsigned x, unsigned y) { 56 unsigned r; 57 AvahiPrioQueueNode *n; 58 assert(q); 59 60 n = q->root; 61 assert(n); 62 63 for (r = 0; r < y; r++) { 64 assert(n); 65 66 if ((x >> (y-r-1)) & 1) 67 n = n->right; 68 else 69 n = n->left; 70 } 71 72 assert(n->x == x); 73 assert(n->y == y); 74 75 return n; 76 } 77 78 static void exchange_nodes(AvahiPrioQueue *q, AvahiPrioQueueNode *a, AvahiPrioQueueNode *b) { 79 AvahiPrioQueueNode *l, *r, *p, *ap, *an, *bp, *bn; 80 unsigned t; 81 assert(q); 82 assert(a); 83 assert(b); 84 assert(a != b); 85 86 /* Swap positions */ 87 t = a->x; a->x = b->x; b->x = t; 88 t = a->y; a->y = b->y; b->y = t; 89 90 if (a->parent == b) { 91 /* B is parent of A */ 92 93 p = b->parent; 94 b->parent = a; 95 96 if ((a->parent = p)) { 97 if (a->parent->left == b) 98 a->parent->left = a; 99 else 100 a->parent->right = a; 101 } else 102 q->root = a; 103 104 if (b->left == a) { 105 if ((b->left = a->left)) 106 b->left->parent = b; 107 a->left = b; 108 109 r = a->right; 110 if ((a->right = b->right)) 111 a->right->parent = a; 112 if ((b->right = r)) 113 b->right->parent = b; 114 115 } else { 116 if ((b->right = a->right)) 117 b->right->parent = b; 118 a->right = b; 119 120 l = a->left; 121 if ((a->left = b->left)) 122 a->left->parent = a; 123 if ((b->left = l)) 124 b->left->parent = b; 125 } 126 } else if (b->parent == a) { 127 /* A ist parent of B */ 128 129 p = a->parent; 130 a->parent = b; 131 132 if ((b->parent = p)) { 133 if (b->parent->left == a) 134 b->parent->left = b; 135 else 136 b->parent->right = b; 137 } else 138 q->root = b; 139 140 if (a->left == b) { 141 if ((a->left = b->left)) 142 a->left->parent = a; 143 b->left = a; 144 145 r = a->right; 146 if ((a->right = b->right)) 147 a->right->parent = a; 148 if ((b->right = r)) 149 b->right->parent = b; 150 } else { 151 if ((a->right = b->right)) 152 a->right->parent = a; 153 b->right = a; 154 155 l = a->left; 156 if ((a->left = b->left)) 157 a->left->parent = a; 158 if ((b->left = l)) 159 b->left->parent = b; 160 } 161 } else { 162 AvahiPrioQueueNode *apl = NULL, *bpl = NULL; 163 164 /* Swap parents */ 165 ap = a->parent; 166 bp = b->parent; 167 168 if (ap) 169 apl = ap->left; 170 if (bp) 171 bpl = bp->left; 172 173 if ((a->parent = bp)) { 174 if (bpl == b) 175 bp->left = a; 176 else 177 bp->right = a; 178 } else 179 q->root = a; 180 181 if ((b->parent = ap)) { 182 if (apl == a) 183 ap->left = b; 184 else 185 ap->right = b; 186 } else 187 q->root = b; 188 189 /* Swap children */ 190 l = a->left; 191 r = a->right; 192 193 if ((a->left = b->left)) 194 a->left->parent = a; 195 196 if ((b->left = l)) 197 b->left->parent = b; 198 199 if ((a->right = b->right)) 200 a->right->parent = a; 201 202 if ((b->right = r)) 203 b->right->parent = b; 204 } 205 206 /* Swap siblings */ 207 ap = a->prev; an = a->next; 208 bp = b->prev; bn = b->next; 209 210 if (a->next == b) { 211 /* A is predecessor of B */ 212 a->prev = b; 213 b->next = a; 214 215 if ((a->next = bn)) 216 a->next->prev = a; 217 else 218 q->last = a; 219 220 if ((b->prev = ap)) 221 b->prev->next = b; 222 223 } else if (b->next == a) { 224 /* B is predecessor of A */ 225 a->next = b; 226 b->prev = a; 227 228 if ((a->prev = bp)) 229 a->prev->next = a; 230 231 if ((b->next = an)) 232 b->next->prev = b; 233 else 234 q->last = b; 235 236 } else { 237 /* A is no neighbour of B */ 238 239 if ((a->prev = bp)) 240 a->prev->next = a; 241 242 if ((a->next = bn)) 243 a->next->prev = a; 244 else 245 q->last = a; 246 247 if ((b->prev = ap)) 248 b->prev->next = b; 249 250 if ((b->next = an)) 251 b->next->prev = b; 252 else 253 q->last = b; 254 } 255 } 256 257 /* Move a node to the correct position */ 258 void avahi_prio_queue_shuffle(AvahiPrioQueue *q, AvahiPrioQueueNode *n) { 259 assert(q); 260 assert(n); 261 assert(n->queue == q); 262 263 /* Move up until the position is OK */ 264 while (n->parent && q->compare(n->parent->data, n->data) > 0) 265 exchange_nodes(q, n, n->parent); 266 267 /* Move down until the position is OK */ 268 for (;;) { 269 AvahiPrioQueueNode *min; 270 271 if (!(min = n->left)) { 272 /* No children */ 273 assert(!n->right); 274 break; 275 } 276 277 if (n->right && q->compare(n->right->data, min->data) < 0) 278 min = n->right; 279 280 /* min now contains the smaller one of our two children */ 281 282 if (q->compare(n->data, min->data) <= 0) 283 /* Order OK */ 284 break; 285 286 exchange_nodes(q, n, min); 287 } 288 } 289 290 AvahiPrioQueueNode* avahi_prio_queue_put(AvahiPrioQueue *q, void* data) { 291 AvahiPrioQueueNode *n; 292 assert(q); 293 294 if (!(n = avahi_new(AvahiPrioQueueNode, 1))) 295 return NULL; /* OOM */ 296 297 n->queue = q; 298 n->data = data; 299 300 if (q->last) { 301 assert(q->root); 302 assert(q->n_nodes); 303 304 n->y = q->last->y; 305 n->x = q->last->x+1; 306 307 if (n->x >= ((unsigned) 1 << n->y)) { 308 n->x = 0; 309 n->y++; 310 } 311 312 q->last->next = n; 313 n->prev = q->last; 314 315 assert(n->y > 0); 316 n->parent = get_node_at_xy(q, n->x/2, n->y-1); 317 318 if (n->x & 1) 319 n->parent->right = n; 320 else 321 n->parent->left = n; 322 } else { 323 assert(!q->root); 324 assert(!q->n_nodes); 325 326 n->y = n->x = 0; 327 q->root = n; 328 n->prev = n->parent = NULL; 329 } 330 331 n->next = n->left = n->right = NULL; 332 q->last = n; 333 q->n_nodes++; 334 335 avahi_prio_queue_shuffle(q, n); 336 337 return n; 338 } 339 340 void avahi_prio_queue_remove(AvahiPrioQueue *q, AvahiPrioQueueNode *n) { 341 assert(q); 342 assert(n); 343 assert(q == n->queue); 344 345 if (n != q->last) { 346 AvahiPrioQueueNode *replacement = q->last; 347 exchange_nodes(q, replacement, n); 348 avahi_prio_queue_remove(q, n); 349 avahi_prio_queue_shuffle(q, replacement); 350 return; 351 } 352 353 assert(n == q->last); 354 assert(!n->next); 355 assert(!n->left); 356 assert(!n->right); 357 358 q->last = n->prev; 359 360 if (n->prev) { 361 n->prev->next = NULL; 362 assert(n->parent); 363 } else 364 assert(!n->parent); 365 366 if (n->parent) { 367 assert(n->prev); 368 if (n->parent->left == n) { 369 assert(n->parent->right == NULL); 370 n->parent->left = NULL; 371 } else { 372 assert(n->parent->right == n); 373 assert(n->parent->left != NULL); 374 n->parent->right = NULL; 375 } 376 } else { 377 assert(q->root == n); 378 assert(!n->prev); 379 assert(q->n_nodes == 1); 380 q->root = NULL; 381 } 382 383 avahi_free(n); 384 385 assert(q->n_nodes > 0); 386 q->n_nodes--; 387 } 388 389