package org.cdlib.xtf.util; /** * Copyright (c) 2004, Regents of the University of California * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the University of California nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * A simple queue of fixed size, that provides very fast insertion, deletion, * and scanning. * * @author Martin Haye */ public class CircularQueue { /** Max # of entries in the queue */ private int maxSize; /** The current queue entries */ private Object[] entries; /** Points to the current bottom entry */ private int bottom; /** Number of entries currently in the queue */ private int count; /** * Construct a queue that can hold, at most, 'maxSize' entries. * * @param maxSize Maximum number of entries in the queue */ public CircularQueue(int maxSize) { this.maxSize = maxSize; entries = new Object[maxSize]; } // constructor /** * Add an object to the end of the queue. If the queue is full, the first * object is removed to make room. * * @param obj Object to add. */ public final void addTail(Object obj) { if (count == maxSize) removeHead(); int next = (bottom + count >= maxSize) ? (bottom + count - maxSize) : (bottom + count); entries[next] = obj; count++; } // addTail() /** * Add an object to the start of the queue. If the queue is full, the last * object is removed to make room. * * @param obj Object to add. */ public final void addHead(Object obj) { if (count == maxSize) removeTail(); bottom = (bottom == 0) ? (maxSize - 1) : (bottom - 1); entries[bottom] = obj; count++; } // addTail() /** * Removes and returns the first object in the queue. * * @return The object that was at the head, or null if the queue is empty. */ public final Object removeHead() { if (count == 0) return null; int first = bottom; if (bottom == maxSize - 1) bottom = 0; else bottom++; count--; return entries[first]; } // removeHead() /** * Removes and returns the last object in the queue. * * @return The object that was at the tail, or null if the queue is empty. */ public final Object removeTail() { if (count == 0) return null; int last = bottom + count - 1; if (last == maxSize) last = 0; count--; return entries[last]; } // removeHead() /** * Peek into the queue but do not remove the object. * * @param distance How far to peek into the queue (zero means peek at the * head, one to peek at head+1, etc.) * * @return The object at the specified position, or null if queue is empty */ public final Object peek(int distance) { if (count == 0) return null; if (distance >= count) return null; int n = bottom + distance; if (n >= maxSize) n -= maxSize; return entries[n]; } // peek() /** * Removes all entries from the queue. */ public final void clear() { bottom = count = 0; } // clear() /** * Counts how many items are currently in the queue * * @return Number of items in the queue */ public final int count() { return count; } // count() /** * Checks whether the queue is currently empty * * @return true if empty, false if anything is queued */ public final boolean isEmpty() { return (count == 0); } // isEmpty() /** * Checks whether the queue is currently full * * @return true if full, false if there is room for more entries */ public final boolean isFull() { return count == maxSize; } // isFull() /** * Basic regression test */ public static final Tester tester = new Tester("CircularQueue") { protected void testImpl() { CircularQueue queue = new CircularQueue(3); Object one = Integer.valueOf(1); Object two = Integer.valueOf(2); Object three = Integer.valueOf(3); Object four = Integer.valueOf(4); assert queue.count() == 0; assert queue.isEmpty(); assert queue.removeHead() == null; assert queue.removeTail() == null; assert queue.peek(0) == null; assert queue.peek(1) == null; queue.addTail(one); queue.addTail(two); assert !queue.isEmpty(); assert queue.count() == 2; assert queue.peek(0) == one; assert queue.peek(1) == two; queue.addTail(three); queue.addTail(four); assert queue.count() == 3; assert queue.peek(0) == two; assert queue.peek(1) == three; assert queue.peek(2) == four; assert queue.peek(3) == null; queue.addHead(one); assert queue.count() == 3; assert queue.peek(0) == one; assert queue.peek(1) == two; assert queue.peek(2) == three; assert queue.peek(3) == null; assert queue.removeHead() == one; assert queue.removeTail() == three; assert queue.count() == 1; assert queue.peek(0) == two; assert queue.peek(1) == null; queue.addHead(one); queue.addTail(three); assert queue.count() == 3; assert queue.peek(0) == one; assert queue.peek(1) == two; assert queue.peek(2) == three; assert queue.peek(3) == null; } // testImpl() }; } // class CircularQueue