// Copyright (c) 2001 Dustin Sallings <dustin@spy.net>
package net.spy.util;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* A circular buffer. Ring buffers may have new entries appended to them,
* but may not otherwise be modified. Individual entries may not be
* accessed directly, only via the iterator.
*/
public class RingBuffer<T> extends AbstractCollection<T>
implements Serializable {
final T[] buf;
int start=0;
int end=0;
private boolean wrapped=false;
private int size=0;
private static final long serialVersionUID=823830283278235L;
/**
* Get an instance of RingBuffer.
*/
@SuppressWarnings("unchecked")
public RingBuffer(int s) {
super();
buf=(T[])new Object[s];
Arrays.fill(buf, null);
}
/**
* Get a RingBuffer at a particular size filled from the given
* Collection.
*
* @param s the maximum number of objects to be held in the ring
* @param fill a Collection whose elements will be used to fill the buffer
*/
public RingBuffer(int s, Collection<? extends T> fill) {
this(s);
for(T ob : fill) {
add(ob);
}
}
/**
* Add an object to the ring buffer (if it's full, it'll cycle the
* oldest one out).
*
* @param o the object to add
* @return true
*/
@Override
public boolean add(T o) {
if(end>=buf.length) {
// Will get set to 0
end=0;
wrapped=true;
}
buf[end]=o;
end++;
if(wrapped) {
start++;
if(start>=buf.length) {
start=0;
}
} else {
size++;
}
return (true);
}
/**
* Check to see if the ring buffer has wrapped.
*
* @return true if the ring buffer has wrapped
*/
public boolean hasWrapped() {
return(wrapped);
}
/**
* String me.
*/
@Override
public String toString() {
StringBuilder sb=new StringBuilder(256);
sb.append("{RingBuffer cap=");
sb.append(getCapacity());
sb.append(" s=");
sb.append(start);
sb.append(", e=");
sb.append(end);
sb.append(" [");
for(T ob : buf) {
sb.append(ob);
sb.append(" ");
}
sb.append("]\n\t");
ArrayList<T> a=new ArrayList<T>(this);
sb.append(a.toString());
sb.append("}");
return(sb.toString());
}
/**
* Get the number of objects in this RingBuffer.
*/
@Override
public int size() {
return(size);
}
/**
* Get the total capacity of this RingBuffer.
* @return the number of objects this RingBuffer will hold
*/
public int getCapacity() {
return(buf.length);
}
/**
* Get the iterator for this ring buffer.
*
* @return an iterator
*/
@Override
public Iterator<T> iterator() {
return (new RingBufferIterator());
}
// Iterator implementation
class RingBufferIterator extends Object
implements Iterator<T>, Serializable {
private int pos=0;
private int startPos=0;
private int remaining=0;
public RingBufferIterator() {
super();
pos=start;
startPos=start;
remaining=size();
}
public boolean hasNext() {
if(start != startPos) {
throw new ConcurrentModificationException(
"Looks like additions have been made to the "
+ "RingBuffer since the creation of this iterator.");
}
return(remaining > 0);
}
public T next() {
if(!hasNext()) {
throw new NoSuchElementException("Your buffer runneth under.");
}
remaining--;
if(pos==buf.length) {
pos=0;
}
return(buf[pos++]);
}
public void remove() {
throw new UnsupportedOperationException("Nope.");
}
}
}