aboutsummaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/jogamp/opengl/util/av/SyncedRingbuffer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/jogamp/opengl/util/av/SyncedRingbuffer.java')
-rw-r--r--src/jogl/classes/jogamp/opengl/util/av/SyncedRingbuffer.java286
1 files changed, 286 insertions, 0 deletions
diff --git a/src/jogl/classes/jogamp/opengl/util/av/SyncedRingbuffer.java b/src/jogl/classes/jogamp/opengl/util/av/SyncedRingbuffer.java
new file mode 100644
index 000000000..5f5d69cf8
--- /dev/null
+++ b/src/jogl/classes/jogamp/opengl/util/av/SyncedRingbuffer.java
@@ -0,0 +1,286 @@
+/**
+ * Copyright 2013 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``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 JogAmp Community 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.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+
+package jogamp.opengl.util.av;
+
+/**
+ * Simple synchronized ring buffer implementation.
+ * <p>
+ * Caller can chose whether to block until get / put is able to proceed or not.
+ * </p>
+ * <p>
+ * Caller can chose whether to pass an empty array and clear references at get,
+ * or using a preset array for circular access of same objects.
+ * </p>
+ * <p>
+ * Circular write position is equal to the read position if buffer is full or if buffer is empty.
+ * </p>
+ */
+public class SyncedRingbuffer<T> {
+
+ protected final Object sync = new Object();
+ protected final T[] array;
+ protected final int capacity;
+ protected int readPos;
+ protected int writePos;
+ protected int size;
+
+ public final String toString() {
+ return "SyncedRingbuffer<?>[filled "+size+" / "+capacity+", writePos "+writePos+", readPos "+readPos+"]";
+ }
+
+ /**
+ * Create instance w/ the given array and it's capacity, e.g.:
+ * <pre>
+ * SyncedRingbuffer r = new SyncedRingbuffer<Integer>(new Integer[10]);
+ * </pre>
+ * <p>
+ * The array may either be clear, or preset w/ elements!
+ * </p>
+ * @param full if true, given array is assumed to be full, i.e. {@link #isFull()} will return true.
+ * @param array
+ */
+ public SyncedRingbuffer(T[] array, boolean full) {
+ this.array = array;
+ this.capacity = array.length;
+ clearImpl(false);
+ if(full) {
+ size = capacity;
+ }
+ }
+
+ public final int capacity() {
+ return capacity;
+ }
+
+ /**
+ * Resets all ring buffer pointer to zero.
+ * <p>
+ * {@link #isEmpty()} will return <code>true</code> after calling this method.
+ * </p>
+ * <p>
+ * If <code>clearRefs</code> is true, all ring buffer slots will be set to <code>null</code>.
+ * </p>
+ * @param clearRefs if true, all ring buffer slots will be flushed, otherwise they remain intact.
+ */
+ public final void clear(boolean clearRefs) {
+ synchronized ( sync ) {
+ clearImpl(clearRefs);
+ }
+ }
+
+ private final void clearImpl(boolean clearRefs) {
+ readPos = 0;
+ writePos = 0;
+ size = 0;
+ if( clearRefs ) {
+ for(int i=0; i<capacity; i++) {
+ this.array[i] = null;
+ }
+ }
+ }
+
+ /** Returns the number of elements in this ring buffer. */
+ public final int size() {
+ synchronized ( sync ) {
+ return size;
+ }
+ }
+
+ /** Returns the number of free slots available to put. */
+ public final int getFreeSlots() {
+ synchronized ( sync ) {
+ return capacity - size;
+ }
+ }
+
+ /** Returns true if this ring buffer is empty, otherwise false. */
+ public final boolean isEmpty() {
+ synchronized ( sync ) {
+ return 0 == size;
+ }
+ }
+
+ /** Returns true if this ring buffer is full, otherwise false. */
+ public final boolean isFull() {
+ synchronized ( sync ) {
+ return capacity == size;
+ }
+ }
+
+ /**
+ * Returns the oldest put element if available, otherwise null.
+ * <p>
+ * Impl. returns the element at the current read position
+ * and advances the read position - if available.
+ * </p>
+ * <p>
+ * If <code>clearRef</code> is true, the returned ring buffer slot will be set to <code>null</code>.
+ * </p>
+ * <p>
+ * Method is non blocking and returns immediately;.
+ * </p>
+ * @param clearRef if true, the returned ring buffer slot will be flushed, otherwise it remains intact.
+ * @return the oldest put element if available, otherwise null.
+ */
+ public final T get(boolean clearRef) {
+ try {
+ return getImpl(clearRef, false, false);
+ } catch (InterruptedException ie) { throw new RuntimeException(ie); }
+ }
+
+ /**
+ * Returns the oldest put element.
+ * <p>
+ * Impl. returns the element at the current read position
+ * and advances the read position.
+ * </p>
+ * <p>
+ * If <code>clearRef</code> is true, the returned ring buffer slot will be set to <code>null</code>.
+ * </p>
+ * <p>
+ * Methods blocks until an element becomes available via put.
+ * </p>
+ * @param clearRef if true, the returned ring buffer slot will be flushed, otherwise it remains intact.
+ * @return the oldest put element
+ * @throws InterruptedException
+ */
+ public final T getBlocking(boolean clearRef) throws InterruptedException {
+ return getImpl(clearRef, true, false);
+ }
+
+ public final T peek() throws InterruptedException {
+ return getImpl(false, false, true);
+ }
+ public final T peekBlocking() throws InterruptedException {
+ return getImpl(false, true, true);
+ }
+
+ private final T getImpl(boolean clearRef, boolean blocking, boolean peek) throws InterruptedException {
+ synchronized ( sync ) {
+ if( 0 == size ) {
+ if( blocking ) {
+ while( 0 == size ) {
+ sync.wait();
+ }
+ } else {
+ return null;
+ }
+ }
+ final T r = array[readPos];
+ if( !peek ) {
+ if( clearRef ) {
+ array[readPos] = null;
+ }
+ readPos = (readPos + 1) % capacity;
+ size--;
+ sync.notifyAll(); // notify waiting putter
+ }
+ return r;
+ }
+ }
+
+ /**
+ * Puts the element <code>e</code> at the current write position
+ * and advances the write position.
+ * <p>
+ * Returns true if successful, otherwise false in case buffer is full.
+ * </p>
+ * <p>
+ * Method is non blocking and returns immediately;.
+ * </p>
+ */
+ public final boolean put(T e) {
+ try {
+ return putImpl(e, false, false);
+ } catch (InterruptedException ie) { throw new RuntimeException(ie); }
+ }
+
+ /**
+ * Puts the element <code>e</code> at the current write position
+ * and advances the write position.
+ * <p>
+ * Method blocks until a free slot becomes available via get.
+ * </p>
+ * @throws InterruptedException
+ */
+ public final void putBlocking(T e) throws InterruptedException {
+ if( !putImpl(e, false, true) ) {
+ throw new InternalError("Blocking put failed: "+this);
+ }
+ }
+
+ /**
+ * Keeps the element at the current write position intact
+ * and advances the write position.
+ * <p>
+ * Returns true if successful, otherwise false in case buffer is full.
+ * </p>
+ * <p>
+ * If <code>blocking</code> is true, method blocks until a free slot becomes available via get.
+ * </p>
+ * @param blocking if true, wait until a free slot becomes available via get.
+ * @throws InterruptedException
+ */
+ public final boolean putSame(boolean blocking) throws InterruptedException {
+ return putImpl(null, true, blocking);
+ }
+
+ private final boolean putImpl(T e, boolean sameRef, boolean blocking) throws InterruptedException {
+ synchronized ( sync ) {
+ if( capacity <= size ) {
+ if( blocking ) {
+ while( capacity <= size ) {
+ sync.wait();
+ }
+ } else {
+ return false;
+ }
+ }
+ if( !sameRef ) {
+ array[ writePos ] = e;
+ }
+ writePos = (writePos + 1) % capacity;
+ size++;
+ sync.notifyAll(); // notify waiting getter
+ return true;
+ }
+ }
+
+ public final void waitForFreeSlots(int count) throws InterruptedException {
+ synchronized ( sync ) {
+ if( capacity - size < count ) {
+ while( capacity - size < count ) {
+ System.err.println("XXXX AAA XXX");
+ sync.wait();
+ }
+ }
+ }
+ }
+
+}