]> git.proxmox.com Git - mirror_frr.git/blob - lib/pqueue.c
lib: use heap to manage timers
[mirror_frr.git] / lib / pqueue.c
1 /* Priority queue functions.
2 Copyright (C) 2003 Yasuhiro Ohara
3
4 This file is part of GNU Zebra.
5
6 GNU Zebra is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; either version 2, or (at your
9 option) any later version.
10
11 GNU Zebra is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Zebra; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 #include <zebra.h>
22
23 #include "memory.h"
24 #include "pqueue.h"
25
26 /* priority queue using heap sort */
27
28 /* pqueue->cmp() controls the order of sorting (i.e, ascending or
29 descending). If you want the left node to move upper of the heap
30 binary tree, make cmp() to return less than 0. for example, if cmp
31 (10, 20) returns -1, the sorting is ascending order. if cmp (10,
32 20) returns 1, the sorting is descending order. if cmp (10, 20)
33 returns 0, this library does not do sorting (which will not be what
34 you want). To be brief, if the contents of cmp_func (left, right)
35 is left - right, dequeue () returns the smallest node. Otherwise
36 (if the contents is right - left), dequeue () returns the largest
37 node. */
38
39 #define DATA_SIZE (sizeof (void *))
40 #define PARENT_OF(x) ((x - 1) / 2)
41 #define LEFT_OF(x) (2 * x + 1)
42 #define RIGHT_OF(x) (2 * x + 2)
43 #define HAVE_CHILD(x,q) (x < (q)->size / 2)
44
45 void
46 trickle_up (int index, struct pqueue *queue)
47 {
48 void *tmp;
49
50 /* Save current node as tmp node. */
51 tmp = queue->array[index];
52
53 /* Continue until the node reaches top or the place where the parent
54 node should be upper than the tmp node. */
55 while (index > 0 &&
56 (*queue->cmp) (tmp, queue->array[PARENT_OF (index)]) < 0)
57 {
58 /* actually trickle up */
59 queue->array[index] = queue->array[PARENT_OF (index)];
60 if (queue->update != NULL)
61 (*queue->update) (queue->array[index], index);
62 index = PARENT_OF (index);
63 }
64
65 /* Restore the tmp node to appropriate place. */
66 queue->array[index] = tmp;
67 if (queue->update != NULL)
68 (*queue->update) (tmp, index);
69 }
70
71 void
72 trickle_down (int index, struct pqueue *queue)
73 {
74 void *tmp;
75 int which;
76
77 /* Save current node as tmp node. */
78 tmp = queue->array[index];
79
80 /* Continue until the node have at least one (left) child. */
81 while (HAVE_CHILD (index, queue))
82 {
83 /* If right child exists, and if the right child is more proper
84 to be moved upper. */
85 if (RIGHT_OF (index) < queue->size &&
86 (*queue->cmp) (queue->array[LEFT_OF (index)],
87 queue->array[RIGHT_OF (index)]) > 0)
88 which = RIGHT_OF (index);
89 else
90 which = LEFT_OF (index);
91
92 /* If the tmp node should be upper than the child, break. */
93 if ((*queue->cmp) (queue->array[which], tmp) > 0)
94 break;
95
96 /* Actually trickle down the tmp node. */
97 queue->array[index] = queue->array[which];
98 if (queue->update != NULL)
99 (*queue->update) (queue->array[index], index);
100 index = which;
101 }
102
103 /* Restore the tmp node to appropriate place. */
104 queue->array[index] = tmp;
105 if (queue->update != NULL)
106 (*queue->update) (tmp, index);
107 }
108
109 struct pqueue *
110 pqueue_create (void)
111 {
112 struct pqueue *queue;
113
114 queue = XCALLOC (MTYPE_PQUEUE, sizeof (struct pqueue));
115
116 queue->array = XCALLOC (MTYPE_PQUEUE_DATA,
117 DATA_SIZE * PQUEUE_INIT_ARRAYSIZE);
118 queue->array_size = PQUEUE_INIT_ARRAYSIZE;
119
120 /* By default we want nothing to happen when a node changes. */
121 queue->update = NULL;
122 return queue;
123 }
124
125 void
126 pqueue_delete (struct pqueue *queue)
127 {
128 XFREE (MTYPE_PQUEUE_DATA, queue->array);
129 XFREE (MTYPE_PQUEUE, queue);
130 }
131
132 static int
133 pqueue_expand (struct pqueue *queue)
134 {
135 void **newarray;
136
137 newarray = XCALLOC (MTYPE_PQUEUE_DATA, queue->array_size * DATA_SIZE * 2);
138 if (newarray == NULL)
139 return 0;
140
141 memcpy (newarray, queue->array, queue->array_size * DATA_SIZE);
142
143 XFREE (MTYPE_PQUEUE_DATA, queue->array);
144 queue->array = newarray;
145 queue->array_size *= 2;
146
147 return 1;
148 }
149
150 void
151 pqueue_enqueue (void *data, struct pqueue *queue)
152 {
153 if (queue->size + 2 >= queue->array_size && ! pqueue_expand (queue))
154 return;
155
156 queue->array[queue->size] = data;
157 if (queue->update != NULL)
158 (*queue->update) (data, queue->size);
159 trickle_up (queue->size, queue);
160 queue->size ++;
161 }
162
163 void *
164 pqueue_dequeue (struct pqueue *queue)
165 {
166 void *data = queue->array[0];
167 queue->array[0] = queue->array[--queue->size];
168 trickle_down (0, queue);
169 return data;
170 }
171
172 void
173 pqueue_remove_at (int index, struct pqueue *queue)
174 {
175 queue->array[index] = queue->array[--queue->size];
176
177 if (index > 0
178 && (*queue->cmp) (queue->array[index],
179 queue->array[PARENT_OF(index)]) < 0)
180 {
181 trickle_up (index, queue);
182 }
183 else
184 {
185 trickle_down (index, queue);
186 }
187 }