/* ntp_data_structures.c * * This file contains the data structures used by the ntp configuration * code and the discrete event simulator. * * Written By: Sachin Kamboj * University of Delaware * Newark, DE 19711 * Copyright (c) 2006 */ #include /* Needed for malloc */ #include "ntp_data_structures.h" #include "ntp_stdlib.h" /* Priority Queue * -------------- * Define a priority queue in which the relative priority of the elements * is determined by a function 'get_order' which is supplied to the * priority_queue */ queue *create_priority_queue(int (*get_order)(void *, void *)) { queue *my_queue = (queue *) emalloc(sizeof(queue)); my_queue->get_order = get_order; my_queue->front = NULL; my_queue->no_of_elements = 0; return my_queue; } /* Define a function to "destroy" a priority queue, freeing-up * all the allocated resources in the process */ void destroy_queue(queue *my_queue) { node *temp = NULL; /* Empty out the queue elements if they are not already empty */ while (my_queue->front != NULL) { temp = my_queue->front; my_queue->front = my_queue->front->node_next; free(temp); } /* Now free the queue */ free(my_queue); } /* Define a function to allocate memory for one element * of the queue. The allocated memory consists of size * bytes plus the number of bytes needed for bookkeeping */ void *get_node(size_t size) { node *new_node = emalloc(sizeof(*new_node) + size); new_node->node_next = NULL; return new_node + 1; } /* Define a function to free the allocated memory for a queue node */ void free_node(void *my_node) { node *old_node = my_node; free(old_node - 1); } void * next_node( void *pv ) { node *pn; pn = pv; pn--; if (pn->node_next == NULL) return NULL; return pn->node_next + 1; } /* Define a function to check if the queue is empty. */ int empty(queue *my_queue) { return (!my_queue || !my_queue->front); } void * queue_head( queue *q ) { if (NULL == q || NULL == q->front) return NULL; return q->front + 1; } /* Define a function to add an element to the priority queue. * The element is added according to its priority - * relative priority is given by the get_order function */ queue *enqueue(queue *my_queue, void *my_node) { node *new_node = ((node *) my_node) - 1; node *i = NULL; node *j = my_queue->front; while (j != NULL && ((*my_queue->get_order)(new_node + 1, j + 1) > 0)) { i = j; j = j->node_next; } if (i == NULL) { /* Insert at beginning of the queue */ new_node->node_next = my_queue->front; my_queue->front = new_node; } else { /* Insert Elsewhere, including the end */ new_node->node_next = i->node_next; i->node_next = new_node; } ++my_queue->no_of_elements; return my_queue; } /* Define a function to dequeue the first element from the priority * queue and return it */ void *dequeue(queue *my_queue) { node *my_node = my_queue->front; if (my_node != NULL) { my_queue->front = my_node->node_next; --my_queue->no_of_elements; return (void *)(my_node + 1); } else return NULL; } /* Define a function that returns the number of elements in the * priority queue */ int get_no_of_elements(queue *my_queue) { return my_queue->no_of_elements; } /* Define a function to append a queue onto another. * Note: there is a faster way (O(1) as opposed to O(n)) * to do this for simple (FIFO) queues, but we can't rely on * that for priority queues. (Given the current representation) * * I don't anticipate this to be a problem. If it does turn * out to be a bottleneck, I will consider replacing the * current implementation with a binomial or fibonacci heap. */ void append_queue(queue *q1, queue *q2) { while (!empty(q2)) enqueue(q1, dequeue(q2)); destroy_queue(q2); } /* FIFO Queue * ---------- * Use the priority queue to create a traditional FIFO queue. * The only extra function needed is the create_queue */ /* C is not Lisp and does not allow anonymous lambda functions :-(. * So define a get_fifo_order function here */ int get_fifo_order(void *el1, void *el2) { return 1; } /* Define a function to create a FIFO queue */ queue *create_queue() { return create_priority_queue(get_fifo_order); }