1 package net.sf.openrocket.logging;
3 import java.util.AbstractQueue;
4 import java.util.ArrayList;
5 import java.util.ConcurrentModificationException;
6 import java.util.Iterator;
8 import java.util.NoSuchElementException;
11 * A cyclic buffer with a fixed size. When more data is inserted, the newest
12 * data will overwrite the oldest data.
14 * Though this class implements the Queue interface, it specifically breaks the
15 * contract by overwriting (removing) data without specific removal. It also
16 * currently does not support removing arbitrary elements from the set.
18 * The methods in this class are synchronized for concurrent modification.
19 * However, iterating over the set is not thread-safe. To obtain a snapshot
20 * of the state of the buffer, use {@link #asList()}.
22 * @param <E> the object type that is stored.
23 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
25 public class CyclicBuffer<E> extends AbstractQueue<E> {
27 private final ArrayList<E> buffer;
28 private final int maxSize;
30 private int startPosition = 0;
32 private int overwriteCount = 0;
34 private int modCount = 0;
38 * Create a cyclic buffer of the specified size.
40 * @param size the size of the cyclic buffer.
42 public CyclicBuffer(int size) {
43 this.buffer = new ArrayList<E>(size);
44 for (int i=0; i<size; i++) {
45 this.buffer.add(null);
53 public synchronized boolean offer(E e) {
54 buffer.set((startPosition + size) % maxSize, e);
58 startPosition = next(startPosition);
68 public synchronized E peek() {
71 return buffer.get(startPosition);
76 public synchronized E poll() {
80 E element = buffer.get(startPosition);
81 startPosition = next(startPosition);
90 public synchronized int size() {
96 public synchronized Iterator<E> iterator() {
97 return new CyclicBufferIterator();
102 * Return a snapshot of the current buffered objects in the order they
103 * were placed in the buffer. The list is independent of the buffer.
105 * @return a list of the buffered objects.
107 public synchronized List<E> asList() {
108 ArrayList<E> list = new ArrayList<E>(size);
109 if (startPosition + size > maxSize) {
110 list.addAll(buffer.subList(startPosition, maxSize));
111 list.addAll(buffer.subList(0, startPosition + size - maxSize));
113 list.addAll(buffer.subList(startPosition, startPosition+size));
120 * Return the number of elements that have been overwritten in the buffer.
121 * The overwritten elements are the elements that have been added to the
122 * buffer, have not been explicitly removed but are not present in the list.
124 * @return the number of overwritten elements this far.
126 public synchronized int getOverwriteCount() {
127 return overwriteCount;
131 private int next(int n) {
132 return (n+1) % maxSize;
136 private class CyclicBufferIterator implements Iterator<E> {
138 private int expectedModCount;
141 public CyclicBufferIterator() {
142 this.expectedModCount = modCount;
146 public boolean hasNext() {
147 synchronized (CyclicBuffer.this) {
148 if (expectedModCount != modCount) {
149 throw new ConcurrentModificationException("expectedModCount="+
150 expectedModCount+" modCount=" + modCount);
158 synchronized (CyclicBuffer.this) {
159 if (expectedModCount != modCount) {
160 throw new ConcurrentModificationException("expectedModCount="+
161 expectedModCount+" modCount=" + modCount);
164 throw new NoSuchElementException("n="+n+" size="+size);
167 return buffer.get((startPosition + n-1) % maxSize);
172 public void remove() {
173 throw new UnsupportedOperationException("random remove not supported");