1*2b15cb3dSCy Schubert /* ntp_prio_q.c
2*2b15cb3dSCy Schubert *
3*2b15cb3dSCy Schubert * This file contains the priority queue implementation used by the
4*2b15cb3dSCy Schubert * discrete event simulator.
5*2b15cb3dSCy Schubert *
6*2b15cb3dSCy Schubert * Written By: Sachin Kamboj
7*2b15cb3dSCy Schubert * University of Delaware
8*2b15cb3dSCy Schubert * Newark, DE 19711
9*2b15cb3dSCy Schubert * Copyright (c) 2006
10*2b15cb3dSCy Schubert */
11*2b15cb3dSCy Schubert #ifdef HAVE_CONFIG_H
12*2b15cb3dSCy Schubert # include <config.h>
13*2b15cb3dSCy Schubert #endif
14*2b15cb3dSCy Schubert
15*2b15cb3dSCy Schubert #include <ntp_stdlib.h>
16*2b15cb3dSCy Schubert #include <ntp_prio_q.h>
17*2b15cb3dSCy Schubert
18*2b15cb3dSCy Schubert /* Priority Queue
19*2b15cb3dSCy Schubert * --------------
20*2b15cb3dSCy Schubert * Define a priority queue in which the relative priority of the elements
21*2b15cb3dSCy Schubert * is determined by a function 'get_order' which is supplied to the
22*2b15cb3dSCy Schubert * priority_queue
23*2b15cb3dSCy Schubert */
debug_create_priority_queue(q_order_func get_order,const char * sourcefile,int line_num)24*2b15cb3dSCy Schubert queue *debug_create_priority_queue(
25*2b15cb3dSCy Schubert q_order_func get_order
26*2b15cb3dSCy Schubert #ifdef _CRTDBG_MAP_ALLOC
27*2b15cb3dSCy Schubert , const char * sourcefile
28*2b15cb3dSCy Schubert , int line_num
29*2b15cb3dSCy Schubert #endif
30*2b15cb3dSCy Schubert )
31*2b15cb3dSCy Schubert {
32*2b15cb3dSCy Schubert queue *my_queue;
33*2b15cb3dSCy Schubert
34*2b15cb3dSCy Schubert #ifndef _CRTDBG_MAP_ALLOC
35*2b15cb3dSCy Schubert my_queue = emalloc(sizeof(queue));
36*2b15cb3dSCy Schubert #else
37*2b15cb3dSCy Schubert /* preserve original callsite __FILE__ and __LINE__ for leak report */
38*2b15cb3dSCy Schubert my_queue = debug_erealloc(NULL, sizeof(queue), sourcefile, line_num);
39*2b15cb3dSCy Schubert #endif
40*2b15cb3dSCy Schubert my_queue->get_order = get_order;
41*2b15cb3dSCy Schubert my_queue->front = NULL;
42*2b15cb3dSCy Schubert my_queue->no_of_elements = 0;
43*2b15cb3dSCy Schubert
44*2b15cb3dSCy Schubert return my_queue;
45*2b15cb3dSCy Schubert }
46*2b15cb3dSCy Schubert
47*2b15cb3dSCy Schubert
48*2b15cb3dSCy Schubert /* Define a function to "destroy" a priority queue, freeing-up
49*2b15cb3dSCy Schubert * all the allocated resources in the process
50*2b15cb3dSCy Schubert */
51*2b15cb3dSCy Schubert
destroy_queue(queue * my_queue)52*2b15cb3dSCy Schubert void destroy_queue(
53*2b15cb3dSCy Schubert queue *my_queue
54*2b15cb3dSCy Schubert )
55*2b15cb3dSCy Schubert {
56*2b15cb3dSCy Schubert node *temp = NULL;
57*2b15cb3dSCy Schubert
58*2b15cb3dSCy Schubert /* Empty out the queue elements if they are not already empty */
59*2b15cb3dSCy Schubert while (my_queue->front != NULL) {
60*2b15cb3dSCy Schubert temp = my_queue->front;
61*2b15cb3dSCy Schubert my_queue->front = my_queue->front->node_next;
62*2b15cb3dSCy Schubert free(temp);
63*2b15cb3dSCy Schubert }
64*2b15cb3dSCy Schubert
65*2b15cb3dSCy Schubert /* Now free the queue */
66*2b15cb3dSCy Schubert free(my_queue);
67*2b15cb3dSCy Schubert }
68*2b15cb3dSCy Schubert
69*2b15cb3dSCy Schubert
70*2b15cb3dSCy Schubert /* Define a function to allocate memory for one element
71*2b15cb3dSCy Schubert * of the queue. The allocated memory consists of size
72*2b15cb3dSCy Schubert * bytes plus the number of bytes needed for bookkeeping
73*2b15cb3dSCy Schubert */
74*2b15cb3dSCy Schubert
debug_get_node(size_t size,const char * sourcefile,int line_num)75*2b15cb3dSCy Schubert void *debug_get_node(
76*2b15cb3dSCy Schubert size_t size
77*2b15cb3dSCy Schubert #ifdef _CRTDBG_MAP_ALLOC
78*2b15cb3dSCy Schubert , const char * sourcefile
79*2b15cb3dSCy Schubert , int line_num
80*2b15cb3dSCy Schubert #endif
81*2b15cb3dSCy Schubert )
82*2b15cb3dSCy Schubert {
83*2b15cb3dSCy Schubert node *new_node;
84*2b15cb3dSCy Schubert
85*2b15cb3dSCy Schubert #ifndef _CRTDBG_MAP_ALLOC
86*2b15cb3dSCy Schubert new_node = emalloc(sizeof(*new_node) + size);
87*2b15cb3dSCy Schubert #else
88*2b15cb3dSCy Schubert new_node = debug_erealloc(NULL, sizeof(*new_node) + size,
89*2b15cb3dSCy Schubert sourcefile, line_num);
90*2b15cb3dSCy Schubert #endif
91*2b15cb3dSCy Schubert new_node->node_next = NULL;
92*2b15cb3dSCy Schubert
93*2b15cb3dSCy Schubert return new_node + 1;
94*2b15cb3dSCy Schubert }
95*2b15cb3dSCy Schubert
96*2b15cb3dSCy Schubert /* Define a function to free the allocated memory for a queue node */
free_node(void * my_node)97*2b15cb3dSCy Schubert void free_node(
98*2b15cb3dSCy Schubert void *my_node
99*2b15cb3dSCy Schubert )
100*2b15cb3dSCy Schubert {
101*2b15cb3dSCy Schubert node *old_node = my_node;
102*2b15cb3dSCy Schubert
103*2b15cb3dSCy Schubert free(old_node - 1);
104*2b15cb3dSCy Schubert }
105*2b15cb3dSCy Schubert
106*2b15cb3dSCy Schubert
107*2b15cb3dSCy Schubert void *
next_node(void * pv)108*2b15cb3dSCy Schubert next_node(
109*2b15cb3dSCy Schubert void *pv
110*2b15cb3dSCy Schubert )
111*2b15cb3dSCy Schubert {
112*2b15cb3dSCy Schubert node *pn;
113*2b15cb3dSCy Schubert
114*2b15cb3dSCy Schubert pn = pv;
115*2b15cb3dSCy Schubert pn--;
116*2b15cb3dSCy Schubert
117*2b15cb3dSCy Schubert if (pn->node_next == NULL)
118*2b15cb3dSCy Schubert return NULL;
119*2b15cb3dSCy Schubert
120*2b15cb3dSCy Schubert return pn->node_next + 1;
121*2b15cb3dSCy Schubert }
122*2b15cb3dSCy Schubert
123*2b15cb3dSCy Schubert
124*2b15cb3dSCy Schubert /* Define a function to check if the queue is empty. */
empty(queue * my_queue)125*2b15cb3dSCy Schubert int empty(
126*2b15cb3dSCy Schubert queue *my_queue
127*2b15cb3dSCy Schubert )
128*2b15cb3dSCy Schubert {
129*2b15cb3dSCy Schubert return (!my_queue || !my_queue->front);
130*2b15cb3dSCy Schubert }
131*2b15cb3dSCy Schubert
132*2b15cb3dSCy Schubert
133*2b15cb3dSCy Schubert void *
queue_head(queue * q)134*2b15cb3dSCy Schubert queue_head(
135*2b15cb3dSCy Schubert queue *q
136*2b15cb3dSCy Schubert )
137*2b15cb3dSCy Schubert {
138*2b15cb3dSCy Schubert if (NULL == q || NULL == q->front)
139*2b15cb3dSCy Schubert return NULL;
140*2b15cb3dSCy Schubert
141*2b15cb3dSCy Schubert return q->front + 1;
142*2b15cb3dSCy Schubert }
143*2b15cb3dSCy Schubert
144*2b15cb3dSCy Schubert
145*2b15cb3dSCy Schubert /* Define a function to add an element to the priority queue.
146*2b15cb3dSCy Schubert * The element is added according to its priority -
147*2b15cb3dSCy Schubert * relative priority is given by the get_order function
148*2b15cb3dSCy Schubert */
enqueue(queue * my_queue,void * my_node)149*2b15cb3dSCy Schubert queue *enqueue(
150*2b15cb3dSCy Schubert queue * my_queue,
151*2b15cb3dSCy Schubert void * my_node
152*2b15cb3dSCy Schubert )
153*2b15cb3dSCy Schubert {
154*2b15cb3dSCy Schubert node *new_node = (node *)my_node - 1;
155*2b15cb3dSCy Schubert node *i = NULL;
156*2b15cb3dSCy Schubert node *j = my_queue->front;
157*2b15cb3dSCy Schubert
158*2b15cb3dSCy Schubert while (j != NULL &&
159*2b15cb3dSCy Schubert (*my_queue->get_order)(new_node + 1, j + 1) > 0) {
160*2b15cb3dSCy Schubert i = j;
161*2b15cb3dSCy Schubert j = j->node_next;
162*2b15cb3dSCy Schubert }
163*2b15cb3dSCy Schubert
164*2b15cb3dSCy Schubert if (i == NULL) { /* Insert at beginning of the queue */
165*2b15cb3dSCy Schubert new_node->node_next = my_queue->front;
166*2b15cb3dSCy Schubert my_queue->front = new_node;
167*2b15cb3dSCy Schubert } else { /* Insert Elsewhere, including the end */
168*2b15cb3dSCy Schubert new_node->node_next = i->node_next;
169*2b15cb3dSCy Schubert i->node_next = new_node;
170*2b15cb3dSCy Schubert }
171*2b15cb3dSCy Schubert
172*2b15cb3dSCy Schubert ++my_queue->no_of_elements;
173*2b15cb3dSCy Schubert return my_queue;
174*2b15cb3dSCy Schubert }
175*2b15cb3dSCy Schubert
176*2b15cb3dSCy Schubert
177*2b15cb3dSCy Schubert /* Define a function to dequeue the first element from the priority
178*2b15cb3dSCy Schubert * queue and return it
179*2b15cb3dSCy Schubert */
dequeue(queue * my_queue)180*2b15cb3dSCy Schubert void *dequeue(
181*2b15cb3dSCy Schubert queue *my_queue
182*2b15cb3dSCy Schubert )
183*2b15cb3dSCy Schubert {
184*2b15cb3dSCy Schubert node *my_node = my_queue->front;
185*2b15cb3dSCy Schubert
186*2b15cb3dSCy Schubert if (my_node != NULL) {
187*2b15cb3dSCy Schubert my_queue->front = my_node->node_next;
188*2b15cb3dSCy Schubert --my_queue->no_of_elements;
189*2b15cb3dSCy Schubert return my_node + 1;
190*2b15cb3dSCy Schubert } else
191*2b15cb3dSCy Schubert return NULL;
192*2b15cb3dSCy Schubert }
193*2b15cb3dSCy Schubert
194*2b15cb3dSCy Schubert
195*2b15cb3dSCy Schubert /* Define a function that returns the number of elements in the
196*2b15cb3dSCy Schubert * priority queue
197*2b15cb3dSCy Schubert */
get_no_of_elements(queue * my_queue)198*2b15cb3dSCy Schubert int get_no_of_elements(
199*2b15cb3dSCy Schubert queue *my_queue
200*2b15cb3dSCy Schubert )
201*2b15cb3dSCy Schubert {
202*2b15cb3dSCy Schubert return my_queue->no_of_elements;
203*2b15cb3dSCy Schubert }
204*2b15cb3dSCy Schubert
205*2b15cb3dSCy Schubert
206*2b15cb3dSCy Schubert /* Define a function to append a queue onto another.
207*2b15cb3dSCy Schubert * Note: there is a faster way (O(1) as opposed to O(n))
208*2b15cb3dSCy Schubert * to do this for simple (FIFO) queues, but we can't rely on
209*2b15cb3dSCy Schubert * that for priority queues. (Given the current representation)
210*2b15cb3dSCy Schubert *
211*2b15cb3dSCy Schubert * I don't anticipate this to be a problem. If it does turn
212*2b15cb3dSCy Schubert * out to be a bottleneck, I will consider replacing the
213*2b15cb3dSCy Schubert * current implementation with a binomial or fibonacci heap.
214*2b15cb3dSCy Schubert */
append_queue(queue * q1,queue * q2)215*2b15cb3dSCy Schubert void append_queue(
216*2b15cb3dSCy Schubert queue *q1,
217*2b15cb3dSCy Schubert queue *q2
218*2b15cb3dSCy Schubert )
219*2b15cb3dSCy Schubert {
220*2b15cb3dSCy Schubert while (!empty(q2))
221*2b15cb3dSCy Schubert enqueue(q1, dequeue(q2));
222*2b15cb3dSCy Schubert destroy_queue(q2);
223*2b15cb3dSCy Schubert }
224*2b15cb3dSCy Schubert
225*2b15cb3dSCy Schubert
226*2b15cb3dSCy Schubert /* FIFO Queue
227*2b15cb3dSCy Schubert * ----------
228*2b15cb3dSCy Schubert * Use the priority queue to create a traditional FIFO queue.
229*2b15cb3dSCy Schubert * The only extra function needed is the create_queue
230*2b15cb3dSCy Schubert */
231*2b15cb3dSCy Schubert
232*2b15cb3dSCy Schubert /* C is not Lisp and does not allow anonymous lambda functions :-(.
233*2b15cb3dSCy Schubert * So define a get_fifo_order function here
234*2b15cb3dSCy Schubert */
get_fifo_order(const void * el1,const void * el2)235*2b15cb3dSCy Schubert int get_fifo_order(const void *el1, const void *el2)
236*2b15cb3dSCy Schubert {
237*2b15cb3dSCy Schubert return 1;
238*2b15cb3dSCy Schubert }
239