X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fnet%2Fsf%2Fopenrocket%2Flogging%2FCyclicBuffer.java;fp=src%2Fnet%2Fsf%2Fopenrocket%2Flogging%2FCyclicBuffer.java;h=31328ba23f50e866d6518ca190d589cdfc89f999;hb=e298a9509613f232227d16d28310611b33c3aa03;hp=0000000000000000000000000000000000000000;hpb=c71eeba85a8a25e1bd43b27ad09cb2238139b737;p=debian%2Fopenrocket
diff --git a/src/net/sf/openrocket/logging/CyclicBuffer.java b/src/net/sf/openrocket/logging/CyclicBuffer.java
new file mode 100644
index 00000000..31328ba2
--- /dev/null
+++ b/src/net/sf/openrocket/logging/CyclicBuffer.java
@@ -0,0 +1,176 @@
+package net.sf.openrocket.logging;
+
+import java.util.AbstractQueue;
+import java.util.ArrayList;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * A cyclic buffer with a fixed size. When more data is inserted, the newest
+ * data will overwrite the oldest data.
+ *
+ * Though this class implements the Queue interface, it specifically breaks the
+ * contract by overwriting (removing) data without specific removal. It also
+ * currently does not support removing arbitrary elements from the set.
+ *
+ * The methods in this class are synchronized for concurrent modification.
+ * However, iterating over the set is not thread-safe. To obtain a snapshot
+ * of the state of the buffer, use {@link #asList()}.
+ *
+ * @param the object type that is stored.
+ * @author Sampo Niskanen
+ */
+public class CyclicBuffer extends AbstractQueue {
+
+ private final ArrayList buffer;
+ private final int maxSize;
+
+ private int startPosition = 0;
+ private int size = 0;
+ private int overwriteCount = 0;
+
+ private int modCount = 0;
+
+
+ /**
+ * Create a cyclic buffer of the specified size.
+ *
+ * @param size the size of the cyclic buffer.
+ */
+ public CyclicBuffer(int size) {
+ this.buffer = new ArrayList(size);
+ for (int i=0; i iterator() {
+ return new CyclicBufferIterator();
+ }
+
+
+ /**
+ * Return a snapshot of the current buffered objects in the order they
+ * were placed in the buffer. The list is independent of the buffer.
+ *
+ * @return a list of the buffered objects.
+ */
+ public synchronized List asList() {
+ ArrayList list = new ArrayList(size);
+ if (startPosition + size > maxSize) {
+ list.addAll(buffer.subList(startPosition, maxSize));
+ list.addAll(buffer.subList(0, startPosition + size - maxSize));
+ } else {
+ list.addAll(buffer.subList(startPosition, startPosition+size));
+ }
+ return list;
+ }
+
+
+ /**
+ * Return the number of elements that have been overwritten in the buffer.
+ * The overwritten elements are the elements that have been added to the
+ * buffer, have not been explicitly removed but are not present in the list.
+ *
+ * @return the number of overwritten elements this far.
+ */
+ public synchronized int getOverwriteCount() {
+ return overwriteCount;
+ }
+
+
+ private int next(int n) {
+ return (n+1) % maxSize;
+ }
+
+
+ private class CyclicBufferIterator implements Iterator {
+
+ private int expectedModCount;
+ private int n = 0;
+
+ public CyclicBufferIterator() {
+ this.expectedModCount = modCount;
+ }
+
+ @Override
+ public boolean hasNext() {
+ synchronized (CyclicBuffer.this) {
+ if (expectedModCount != modCount) {
+ throw new ConcurrentModificationException("expectedModCount="+
+ expectedModCount+" modCount=" + modCount);
+ }
+ return (n < size);
+ }
+ }
+
+ @Override
+ public E next() {
+ synchronized (CyclicBuffer.this) {
+ if (expectedModCount != modCount) {
+ throw new ConcurrentModificationException("expectedModCount="+
+ expectedModCount+" modCount=" + modCount);
+ }
+ if (n >= size) {
+ throw new NoSuchElementException("n="+n+" size="+size);
+ }
+ n++;
+ return buffer.get((startPosition + n-1) % maxSize);
+ }
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException("random remove not supported");
+ }
+ }
+}