package libcsp.csp.util; import libcsp.csp.CSPManager; import libcsp.csp.ImmortalEntry; /** * Queue for holding and processing elements in FIFO order. T will either be * Socket, Packet or Connection * * @author Mikkel Todberg, Jeppe Lund Andersen * * @param <T> * T will either be Socket, Packet or Connection */ public class Queue<T extends IDispose> { /* * Maximum capacity of the queue and a count of the used spaces */ public byte capacity; public byte count; /* * Handles to the start, head and tail element of the queue */ protected Element start; protected Element head; protected Element tail; /* * Structure for each element in the queue. Holds the the value and a * reference to the next element (if there is no more room in the queue the * next field is null) */ protected final class Element { public T value; public Element next; } /* * Instantiates the supplied number of queue elements with value fields set * to null and chains them together in a linked list using the next fields */ public Queue(byte capacity) { this.capacity = capacity; this.count = 0; Element prev = null; Element element; for (int i = 0; i < capacity; i++) { element = new Element(); if (i == 0) { start = element; head = element; tail = element; } else { prev.next = element; } prev = element; } } /* * Continuously attempt to dequeue the head value of the queue until the * dequeue operation succeeds or the supplied timeout occurs */ public T dequeue(long timeout) { T value = null; boolean waitForever = (timeout == ImmortalEntry.TIMEOUT_NONE); timeout = System.currentTimeMillis() + timeout; do { value = dequeue(); } while (((System.currentTimeMillis() < timeout) || waitForever) && (value == null)); return value; } /* Enqueues a new value in the tail of the queue */ public synchronized void enqueue(T value) { if (count != capacity) { tail.value = value; tail = (tail.next == null ? start : tail.next); count++; } } /* Dequeues a value in the head of the queue */ private synchronized T dequeue() { T value = null; if (count != 0) { value = head.value; head.value = null; head = (head.next == null ? start : head.next); count--; } return value; } /* Checks whether or not the queue is full */ public synchronized boolean isFull() { return capacity == count ? true : false; } /* Clears all values and resets the queue */ public synchronized void reset() { Element element = null; for (byte i = 0; i < count; i++) { if (i == 0) { element = head; } if (element.value != null) { element.value.dispose(); element.value = null; } element = (element.next == null ? start : element.next); } count = 0; head = start; tail = head; } }