Java tutorial
/* Copyright 2004 BEA Systems, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.util.AbstractCollection; import java.util.Arrays; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.NoSuchElementException; public final class CircularQueue extends AbstractCollection { // This is the largest capacity allowed by this implementation private static final int MAX_CAPACITY = 1 << 30; private static final int DEFAULT_CAPACITY = 1 << 8; private int size = 0; private int producerIndex = 0; private int consumerIndex = 0; // capacity must be a power of 2 at all times private int capacity; private int maxCapacity; // we mask with capacity -1. This variable caches that values private int bitmask; private Object[] q; public CircularQueue() { this(DEFAULT_CAPACITY); } // Construct a queue which has at least the specified capacity. If // the value specified is a power of two then the queue will be // exactly the specified size. Otherwise the queue will be the // first power of two which is greater than the specified value. public CircularQueue(int c) { this(c, MAX_CAPACITY); } public CircularQueue(int c, int mc) { if (c > mc) { throw new IllegalArgumentException("Capacity greater than maximum"); } if (mc > MAX_CAPACITY) { throw new IllegalArgumentException("Maximum capacity greater than " + "allowed"); } for (capacity = 1; capacity < c; capacity <<= 1) ; for (maxCapacity = 1; maxCapacity < mc; maxCapacity <<= 1) ; bitmask = capacity - 1; q = new Object[capacity]; } // Constructor used by clone() private CircularQueue(CircularQueue oldQueue) { size = oldQueue.size; producerIndex = oldQueue.producerIndex; consumerIndex = oldQueue.consumerIndex; capacity = oldQueue.capacity; maxCapacity = oldQueue.maxCapacity; bitmask = oldQueue.bitmask; q = new Object[oldQueue.q.length]; System.arraycopy(oldQueue.q, 0, q, 0, q.length); } private boolean expandQueue() { // double the size of the queue // This design assumes that this is a rare case if (capacity == maxCapacity) { return false; } int old_capacity = capacity; Object[] old_q = q; capacity += capacity; bitmask = capacity - 1; q = new Object[capacity]; System.arraycopy(old_q, consumerIndex, q, 0, old_capacity - consumerIndex); if (consumerIndex != 0) { System.arraycopy(old_q, 0, q, old_capacity - consumerIndex, consumerIndex); } consumerIndex = 0; producerIndex = size; return true; } public boolean add(Object obj) { if (size == capacity) { // no room if (!expandQueue()) return false; } size++; q[producerIndex] = obj; producerIndex = (producerIndex + 1) & bitmask; return true; } public Object remove() { Object obj; if (size == 0) return null; size--; obj = q[consumerIndex]; q[consumerIndex] = null; // allow gc to collect consumerIndex = (consumerIndex + 1) & bitmask; return obj; } public boolean isEmpty() { return size == 0; } public int size() { return size; } public int capacity() { return capacity; } public Object peek() { if (size == 0) return null; return q[consumerIndex]; } public void clear() { Arrays.fill(q, null); size = 0; producerIndex = 0; consumerIndex = 0; } public Object clone() { return new CircularQueue(this); } public String toString() { StringBuffer s = new StringBuffer( super.toString() + " - capacity: '" + capacity() + "' size: '" + size() + "'"); if (size > 0) { s.append(" elements:"); for (int i = 0; i < size; ++i) { s.append('\n'); s.append('\t'); s.append(q[consumerIndex + i & bitmask].toString()); } } return s.toString(); } public Iterator iterator() { return new Iterator() { private final int ci = consumerIndex; private final int pi = producerIndex; private int s = size; private int i = ci; public boolean hasNext() { checkForModification(); return s > 0; } public Object next() { checkForModification(); if (s == 0) throw new NoSuchElementException(); s--; Object r = q[i]; i = (i + 1) & bitmask; return r; } public void remove() { throw new UnsupportedOperationException(); } private void checkForModification() { if (ci != consumerIndex) throw new ConcurrentModificationException(); if (pi != producerIndex) throw new ConcurrentModificationException(); } }; } }