package org.httpkit;
import java.util.Arrays;
import java.util.Queue;
/**
* Copy and modified from java.util.PriorityQueue. Remove unused method. Modify
* {@code remove} to return the removed element
* <p/>
* used by timer and the client
*
* @param <E>
*/
@SuppressWarnings("unchecked")
public class PriorityQueue<E> {
private static final int DEFAULT_INITIAL_CAPACITY = 11;
/**
* Priority queue represented as a balanced binary heap: the two children of
* queue[n] are queue[2*n+1] and queue[2*(n+1)]. The priority queue is
* ordered by comparator, or by the elements' natural ordering, if
* comparator is null: For each node n in the heap and each descendant d of
* n, n <= d. The element with the lowest value is in queue[0], assuming the
* queue is nonempty.
*/
private transient Object[] queue;
/**
* The number of elements in the priority queue.
*/
private int size = 0;
/**
* Creates a {@code PriorityQueue} with the specified initial capacity that
* orders its elements according to their {@linkplain Comparable natural
* ordering}.
* <p/>
* the initial capacity for this priority queue
*
* @throws IllegalArgumentException if {@code initialCapacity} is less than 1
*/
public PriorityQueue() {
this.queue = new Object[DEFAULT_INITIAL_CAPACITY];
}
/**
* The maximum size of array to allocate. Some VMs reserve some header words
* in an array. Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* Increases the capacity of the array.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// Double size if small; else grow by 50%
int newCapacity = oldCapacity
+ ((oldCapacity < 64) ? (oldCapacity + 2) : (oldCapacity >> 1));
// overflow-conscious code
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
queue = Arrays.copyOf(queue, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
/**
* Inserts the specified element into this priority queue.
*
* @return {@code true} (as specified by {@link Queue#offer})
* @throws ClassCastException if the specified element cannot be compared with elements
* currently in this priority queue according to the priority
* queue's ordering
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
int i = size;
if (i >= queue.length)
grow(i + 1);
size = i + 1;
if (i == 0)
queue[0] = e;
else
siftUp(i, e);
return true;
}
/**
* Retrieves, but does not remove, the head of this queue, or returns null
* if this queue is empty.
*
* @return
*/
public E peek() {
if (size == 0)
return null;
return (E) queue[0];
}
/**
* Removes a single instance of the specified element from this queue, if it
* is present. More formally, removes an element {@code e} such that
* {@code o.equals(e)}, if this queue contains one or more such elements.
* Returns {@code true} if and only if this queue contained the specified
* element (or equivalently, if this queue changed as a result of the call).
*
* @param o element to be removed from this queue, if present
* @return Element removed
*/
public E remove(Object o) {
for (int i = 0; i < size; i++) {
if (queue[i].equals(o)) {
E e = (E) queue[i];
removeAt(i);
return e;
}
}
return null;
}
public int size() {
return size;
}
/**
* Retrieves and removes the head of this queue, or returns null if this
* queue is empty.
*/
public E poll() {
if (size == 0)
return null;
int s = --size;
E result = (E) queue[0];
E x = (E) queue[s];
queue[s] = null;
if (s != 0)
siftDown(0, x);
return result;
}
/**
* Removes the ith element from queue.
* <p/>
* Normally this method leaves the elements at up to i-1, inclusive,
* untouched. Under these circumstances, it returns null. Occasionally, in
* order to maintain the heap invariant, it must swap a later element of the
* list with one earlier than i. Under these circumstances, this method
* returns the element that was previously at the end of the list and is now
* at some position before i. This fact is used by iterator.remove so as to
* avoid missing traversing elements.
*/
private E removeAt(int i) {
assert i >= 0 && i < size;
int s = --size;
if (s == i) // removed last element
queue[i] = null;
else {
E moved = (E) queue[s];
queue[s] = null;
siftDown(i, moved);
if (queue[i] == moved) {
siftUp(i, moved);
if (queue[i] != moved)
return moved;
}
}
return null;
}
/**
* Inserts item x at position k, maintaining heap invariant by promoting x
* up the tree until it is greater than or equal to its parent, or is the
* root.
* <p/>
* To simplify and speed up coercions and comparisons. the Comparable and
* Comparator versions are separated into different methods that are
* otherwise identical. (Similarly for siftDown.)
*
* @param k the position to fill
* @param x the item to insert
*/
private void siftUp(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>) x;
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (key.compareTo((E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = key;
}
/**
* Inserts item x at position k, maintaining heap invariant by demoting x
* down the tree repeatedly until it is less than or equal to its children
* or is a leaf.
*
* @param k the position to fill
* @param x the item to insert
*/
private void siftDown(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>) x;
int half = size >>> 1; // loop while a non-leaf
while (k < half) {
int child = (k << 1) + 1; // assume left child is least
Object c = queue[child];
int right = child + 1;
if (right < size && ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
c = queue[child = right];
if (key.compareTo((E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = key;
}
@Override
public String toString() {
return "size=" + size;
}
}