aboutsummaryrefslogtreecommitdiffstats
path: root/src/java
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2013-08-24 03:14:14 +0200
committerSven Gothel <[email protected]>2013-08-24 03:14:14 +0200
commitf9f881e59c78e3036cb3f956bc97cfc3197f620d (patch)
tree9362ac0e063eb48ed7c563d0ad83953bc828ed9b /src/java
parent30475c6bbeb9a5d48899b281ead8bb305679028d (diff)
*Ringbuffer: Remove Ringbuffer<T>.AllocEmptyArray interface to favor a more simple approach; Split 'grow' into 'growEmpty' and 'growFull'
- java.lang.reflect.Array can instantiate an array w/ a given array-type and length - array-type is Class<? extends T[]> - We either deduct the array-type via array.getClass(), or pass it (ctor for empty Ringbuffer). - Split 'growBuffer(T[] newElements, int amount, ..)' into: - 'growEmptyBuffer(T[] newElements)' - 'growFullBuffer(int amount)' Allowing a more clean API w/ simpler semantics.
Diffstat (limited to 'src/java')
-rw-r--r--src/java/com/jogamp/common/util/LFRingbuffer.java157
-rw-r--r--src/java/com/jogamp/common/util/Ringbuffer.java39
-rw-r--r--src/java/com/jogamp/common/util/SyncedRingbuffer.java137
3 files changed, 189 insertions, 144 deletions
diff --git a/src/java/com/jogamp/common/util/LFRingbuffer.java b/src/java/com/jogamp/common/util/LFRingbuffer.java
index a6b441a..f704047 100644
--- a/src/java/com/jogamp/common/util/LFRingbuffer.java
+++ b/src/java/com/jogamp/common/util/LFRingbuffer.java
@@ -29,6 +29,7 @@
package com.jogamp.common.util;
import java.io.PrintStream;
+import java.lang.reflect.Array;
/**
* Simple implementation of {@link Ringbuffer},
@@ -51,7 +52,7 @@ import java.io.PrintStream;
* <ul>
* <li>{@link #resetFull(Object[])}</li>
* <li>{@link #clear()}</li>
- * <li>{@link #growBuffer(Object[], int, AllocEmptyArray)}</li>
+ * <li>{@link #growEmptyBuffer(Object[])}</li>
* </ul>
* User needs to synchronize above methods w/ the lock-free
* w/ {@link #get() get*(..)} and {@link #put(Object) put*(..)} methods,
@@ -99,10 +100,7 @@ public class LFRingbuffer<T> implements Ringbuffer<T> {
* <pre>
* Integer[] source = new Integer[10];
* // fill source with content ..
- * Ringbuffer<Integer> rb = new LFRingbuffer<Integer>(source, new Ringbuffer.AllocEmptyArray<Integer>() {
- * public Integer[] newArray(int size) {
- * return new Integer[size];
- * } } );
+ * Ringbuffer<Integer> rb = new LFRingbuffer<Integer>(source);
* </pre>
* </p>
* <p>
@@ -113,12 +111,12 @@ public class LFRingbuffer<T> implements Ringbuffer<T> {
* and copy all elements from array <code>copyFrom</code> into the internal array.
* </p>
* @param copyFrom mandatory source array determining ring buffer's net {@link #capacity()} and initial content.
- * @param allocEmptyArray implementation hook to allocate a new empty array of generic type T
* @throws IllegalArgumentException if <code>copyFrom</code> is <code>null</code>
*/
- public LFRingbuffer(T[] copyFrom, AllocEmptyArray<T> allocEmptyArray) throws IllegalArgumentException {
+ @SuppressWarnings("unchecked")
+ public LFRingbuffer(T[] copyFrom) throws IllegalArgumentException {
capacityPlusOne = copyFrom.length + 1;
- array = allocEmptyArray.newArray(capacityPlusOne);
+ array = (T[]) newArray(copyFrom.getClass(), capacityPlusOne);
resetImpl(true, copyFrom);
}
@@ -127,10 +125,7 @@ public class LFRingbuffer<T> implements Ringbuffer<T> {
* <p>
* Example for a 10 element Integer array:
* <pre>
- * Ringbuffer<Integer> rb = new LFRingbuffer<Integer>(10, new Ringbuffer.AllocEmptyArray<Integer>() {
- * public Integer[] newArray(int size) {
- * return new Integer[size];
- * } } );
+ * Ringbuffer<Integer> rb = new LFRingbuffer<Integer>(10, Integer[].class);
* </pre>
* </p>
* <p>
@@ -139,15 +134,15 @@ public class LFRingbuffer<T> implements Ringbuffer<T> {
* <p>
* Implementation will allocate an internal array of size <code>capacity</code> <i>plus one</i>.
* </p>
+ * @param arrayType the array type of the created empty internal array.
* @param capacity the initial net capacity of the ring buffer
- * @param allocEmptyArray implementation hook to allocate a new empty array of generic type T
*/
- public LFRingbuffer(int capacity, AllocEmptyArray<T> allocEmptyArray) {
+ public LFRingbuffer(Class<? extends T[]> arrayType, int capacity) {
capacityPlusOne = capacity+1;
- array = allocEmptyArray.newArray(capacityPlusOne);
- resetImpl(false, null);
+ array = (T[]) newArray(arrayType, capacityPlusOne);
+ resetImpl(false, null /* empty, nothing to copy */ );
}
-
+
@Override
public final T[] getInternalArray() { return array; }
@@ -177,7 +172,7 @@ public class LFRingbuffer<T> implements Ringbuffer<T> {
}
System.arraycopy(copyFrom, 0, array, 0, copyFrom.length);
array[capacityPlusOne-1] = null; // null 'plus-one' field!
- } else if( full ) {
+ } else if ( full ) {
throw new IllegalArgumentException("copyFrom array is null");
}
readPos = capacityPlusOne - 1;
@@ -337,65 +332,95 @@ public class LFRingbuffer<T> implements Ringbuffer<T> {
}
}
}
-
+
@Override
- public void growBuffer(T[] newElements, int amount, AllocEmptyArray<T> allocEmptyArray) throws IllegalStateException, IllegalArgumentException {
+ public final void growEmptyBuffer(final T[] newElements) throws IllegalStateException, IllegalArgumentException {
synchronized( syncGlobal ) {
- final boolean isFull = capacityPlusOne - 1 == size;
- final boolean isEmpty = 0 == size;
- if( !isFull && !isEmpty ) {
- throw new IllegalStateException("Buffer neither full nor empty: "+this);
+ if( null == newElements ) {
+ throw new IllegalArgumentException("newElements is null");
}
- if( isEmpty ) {
- if( readPos != writePos ) {
- throw new InternalError("R/W pos not equal at empty: "+this);
- }
- } else /* isFull */ {
- final int wp1 = ( writePos + 1 ) % capacityPlusOne;
- if( wp1 != readPos ) {
- throw new InternalError("R != W+1 pos at full: "+this);
- }
+ @SuppressWarnings("unchecked")
+ final Class<? extends T[]> arrayTypeInternal = (Class<? extends T[]>) array.getClass();
+ @SuppressWarnings("unchecked")
+ final Class<? extends T[]> arrayTypeNew = (Class<? extends T[]>) newElements.getClass();
+ if( arrayTypeInternal != arrayTypeNew ) {
+ throw new IllegalArgumentException("newElements array-type mismatch, internal "+arrayTypeInternal+", newElements "+arrayTypeNew);
+ }
+ if( 0 != size ) {
+ throw new IllegalStateException("Buffer is not empty: "+this);
}
- if( null != newElements && amount < newElements.length ) {
- throw new IllegalArgumentException("amount "+amount+" < newElements "+newElements.length);
+ if( readPos != writePos ) {
+ throw new InternalError("R/W pos not equal: "+this);
}
- final int newCapacity = capacityPlusOne + amount;
+ if( readPos != writePos ) {
+ throw new InternalError("R/W pos not equal at empty: "+this);
+ }
+
+ final int growAmount = newElements.length;
+ final int newCapacity = capacityPlusOne + growAmount;
final T[] oldArray = array;
- final T[] newArray = allocEmptyArray.newArray(newCapacity);
+ final T[] newArray = (T[]) newArray(arrayTypeInternal, newCapacity);
+
+ // writePos == readPos
+ writePos += growAmount; // warp writePos to the end of the new data location
- if( isFull ) {
- // writePos == readPos - 1
- readPos = ( writePos + 1 + amount ) % newCapacity; // warp readPos to the end of the new data location
-
- if(writePos >= 0) {
- System.arraycopy(oldArray, 0, newArray, 0, writePos+1);
- }
- if( null != newElements && newElements.length > 0 ) {
- System.arraycopy(newElements, 0, newArray, writePos+1, newElements.length);
- }
- final int tail = capacityPlusOne-1-writePos;
- if( tail > 0 ) {
- System.arraycopy(oldArray, writePos+1, newArray, readPos, tail);
- }
- } else /* if ( isEmpty ) */ {
- // writePos == readPos
- writePos += amount; // warp writePos to the end of the new data location
-
- if( readPos >= 0 ) {
- System.arraycopy(oldArray, 0, newArray, 0, readPos+1);
- }
- if( null != newElements && newElements.length > 0 ) {
- System.arraycopy(newElements, 0, newArray, readPos+1, newElements.length);
- }
- final int tail = capacityPlusOne-1-readPos;
- if( tail > 0 ) {
- System.arraycopy(oldArray, readPos+1, newArray, writePos+1, tail);
- }
- size = amount;
+ if( readPos >= 0 ) {
+ System.arraycopy(oldArray, 0, newArray, 0, readPos+1);
+ }
+ if( growAmount > 0 ) {
+ System.arraycopy(newElements, 0, newArray, readPos+1, growAmount);
}
+ final int tail = capacityPlusOne-1-readPos;
+ if( tail > 0 ) {
+ System.arraycopy(oldArray, readPos+1, newArray, writePos+1, tail);
+ }
+ size = growAmount;
capacityPlusOne = newCapacity;
array = newArray;
}
}
+
+ @Override
+ public final void growFullBuffer(final int growAmount) throws IllegalStateException, IllegalArgumentException {
+ synchronized ( syncGlobal ) {
+ if( 0 > growAmount ) {
+ throw new IllegalArgumentException("amount "+growAmount+" < 0 ");
+ }
+ if( capacityPlusOne-1 != size ) {
+ throw new IllegalStateException("Buffer is not full: "+this);
+ }
+ final int wp1 = ( writePos + 1 ) % capacityPlusOne;
+ if( wp1 != readPos ) {
+ throw new InternalError("R != W+1 pos at full: "+this);
+ }
+ @SuppressWarnings("unchecked")
+ final Class<? extends T[]> arrayTypeInternal = (Class<? extends T[]>) array.getClass();
+
+ final int newCapacity = capacityPlusOne + growAmount;
+ final T[] oldArray = array;
+ final T[] newArray = (T[]) newArray(arrayTypeInternal, newCapacity);
+
+ // writePos == readPos - 1
+ readPos = ( writePos + 1 + growAmount ) % newCapacity; // warp readPos to the end of the new data location
+
+ if(writePos >= 0) {
+ System.arraycopy(oldArray, 0, newArray, 0, writePos+1);
+ }
+ final int tail = capacityPlusOne-1-writePos;
+ if( tail > 0 ) {
+ System.arraycopy(oldArray, writePos+1, newArray, readPos, tail);
+ }
+
+ capacityPlusOne = newCapacity;
+ array = newArray;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> T[] newArray(Class<? extends T[]> arrayType, int length) {
+ return ((Object)arrayType == (Object)Object[].class)
+ ? (T[]) new Object[length]
+ : (T[]) Array.newInstance(arrayType.getComponentType(), length);
+ }
} \ No newline at end of file
diff --git a/src/java/com/jogamp/common/util/Ringbuffer.java b/src/java/com/jogamp/common/util/Ringbuffer.java
index 733a235..e524768 100644
--- a/src/java/com/jogamp/common/util/Ringbuffer.java
+++ b/src/java/com/jogamp/common/util/Ringbuffer.java
@@ -44,18 +44,6 @@ import java.io.PrintStream;
*/
public interface Ringbuffer<T> {
- /**
- * Implementation hook for {@link #growBuffer(Object[], int, AllocEmptyArray)}
- * to pass an implementation of {@link #newArray(int)}.
- * @param <T> type of array
- */
- public static interface AllocEmptyArray<T> {
- /**
- * Returns a new allocated empty array of generic type T with given size.
- */
- public T[] newArray(int size);
- }
-
/** Returns a short string representation incl. size/capacity and internal r/w index (impl. dependent). */
public String toString();
@@ -190,25 +178,28 @@ public interface Ringbuffer<T> {
public void waitForFreeSlots(int count) throws InterruptedException;
/**
- * Grows a full or empty ring buffer, increasing it's capacity about the amount.
+ * Grows an empty ring buffer, increasing it's capacity about the amount.
* <p>
* Growing an empty ring buffer increases it's size about the amount, i.e. renders it not empty.
* The new elements are inserted at the read position, able to be read out via {@link #get()} etc.
* </p>
+ *
+ * @param newElements array of new full elements the empty buffer shall grow about.
+ * @throws IllegalStateException if buffer is not empty
+ * @throws IllegalArgumentException if newElements is null
+ */
+ public void growEmptyBuffer(T[] newElements) throws IllegalStateException, IllegalArgumentException;
+
+ /**
+ * Grows a full ring buffer, increasing it's capacity about the amount.
* <p>
* Growing a full ring buffer leaves the size intact, i.e. renders it not full.
- * The new elements are inserted at the write position, able to be written to via {@link #put(Object)} etc.
+ * New <code>null</code> elements are inserted at the write position, able to be written to via {@link #put(Object)} etc.
* </p>
- *
- * @param newElements array of new empty elements the buffer shall grow about, maybe <code>null</code>.
- * If not <code>null</code>, array size must be <= <code>amount</code>
* @param amount the amount of elements the buffer shall grow about
- * @param allocEmptyArray implementation hook to allocate a new empty array of generic type T
- * @throws IllegalStateException if buffer is neither full nor empty
- * @throws IllegalArgumentException if newElements is given but is > amount
+ *
+ * @throws IllegalStateException if buffer is not full
+ * @throws IllegalArgumentException if amount is < 0
*/
- public void growBuffer(T[] newElements, int amount,
- AllocEmptyArray<T> allocEmptyArray) throws IllegalStateException,
- IllegalArgumentException;
-
+ public void growFullBuffer(int amount) throws IllegalStateException, IllegalArgumentException;
} \ No newline at end of file
diff --git a/src/java/com/jogamp/common/util/SyncedRingbuffer.java b/src/java/com/jogamp/common/util/SyncedRingbuffer.java
index b8ddbd6..747629b 100644
--- a/src/java/com/jogamp/common/util/SyncedRingbuffer.java
+++ b/src/java/com/jogamp/common/util/SyncedRingbuffer.java
@@ -29,6 +29,7 @@
package com.jogamp.common.util;
import java.io.PrintStream;
+import java.lang.reflect.Array;
/**
* Simple synchronized implementation of {@link Ringbuffer}.
@@ -77,10 +78,7 @@ public class SyncedRingbuffer<T> implements Ringbuffer<T> {
* <pre>
* Integer[] source = new Integer[10];
* // fill source with content ..
- * Ringbuffer<Integer> rb = new SyncedRingbuffer<Integer>(source, new Ringbuffer.AllocEmptyArray<Integer>() {
- * public Integer[] newArray(int size) {
- * return new Integer[size];
- * } } );
+ * Ringbuffer<Integer> rb = new SyncedRingbuffer<Integer>(source);
* </pre>
* </p>
* <p>
@@ -91,12 +89,12 @@ public class SyncedRingbuffer<T> implements Ringbuffer<T> {
* and copy all elements from array <code>copyFrom</code> into the internal array.
* </p>
* @param copyFrom mandatory source array determining ring buffer's net {@link #capacity()} and initial content.
- * @param allocEmptyArray implementation hook to allocate a new empty array of generic type T
* @throws IllegalArgumentException if <code>copyFrom</code> is <code>null</code>
*/
- public SyncedRingbuffer(T[] copyFrom, AllocEmptyArray<T> allocEmptyArray) throws IllegalArgumentException {
+ @SuppressWarnings("unchecked")
+ public SyncedRingbuffer(T[] copyFrom) throws IllegalArgumentException {
capacity = copyFrom.length;
- array = allocEmptyArray.newArray(capacity);
+ array = (T[]) newArray(copyFrom.getClass(), capacity);
resetImpl(true, copyFrom);
}
@@ -105,10 +103,7 @@ public class SyncedRingbuffer<T> implements Ringbuffer<T> {
* <p>
* Example for a 10 element Integer array:
* <pre>
- * Ringbuffer<Integer> rb = new SyncedRingbuffer<Integer>(10, new Ringbuffer.AllocEmptyArray<Integer>() {
- * public Integer[] newArray(int size) {
- * return new Integer[size];
- * } } );
+ * Ringbuffer<Integer> rb = new SyncedRingbuffer<Integer>(10, Integer[].class);
* </pre>
* </p>
* <p>
@@ -117,13 +112,13 @@ public class SyncedRingbuffer<T> implements Ringbuffer<T> {
* <p>
* Implementation will allocate an internal array of size <code>capacity</code>.
* </p>
+ * @param arrayType the array type of the created empty internal array.
* @param capacity the initial net capacity of the ring buffer
- * @param allocEmptyArray implementation hook to allocate a new empty array of generic type T
*/
- public SyncedRingbuffer(int capacity, AllocEmptyArray<T> allocEmptyArray) {
+ public SyncedRingbuffer(Class<? extends T[]> arrayType, int capacity) {
this.capacity = capacity;
- this.array = allocEmptyArray.newArray(capacity);
- resetImpl(false, null);
+ this.array = (T[]) newArray(arrayType, capacity);
+ resetImpl(false, null /* empty, nothing to copy */ );
}
@Override
@@ -160,7 +155,7 @@ public class SyncedRingbuffer<T> implements Ringbuffer<T> {
throw new IllegalArgumentException("copyFrom array length "+copyFrom.length+" != capacity "+this);
}
System.arraycopy(copyFrom, 0, array, 0, copyFrom.length);
- } else if( full ) {
+ } else if ( full ) {
throw new IllegalArgumentException("copyFrom array is null");
}
readPos = 0;
@@ -325,57 +320,91 @@ public class SyncedRingbuffer<T> implements Ringbuffer<T> {
}
}
+
@Override
- public void growBuffer(T[] newElements, int amount, AllocEmptyArray<T> allocEmptyArray) throws IllegalStateException, IllegalArgumentException {
+ public final void growEmptyBuffer(final T[] newElements) throws IllegalStateException, IllegalArgumentException {
synchronized ( syncGlobal ) {
- final boolean isFull = capacity == size;
- final boolean isEmpty = 0 == size;
- if( !isFull && !isEmpty ) {
- throw new IllegalStateException("Buffer neither full nor empty: "+this);
+ if( null == newElements ) {
+ throw new IllegalArgumentException("newElements is null");
+ }
+ @SuppressWarnings("unchecked")
+ final Class<? extends T[]> arrayTypeInternal = (Class<? extends T[]>) array.getClass();
+ @SuppressWarnings("unchecked")
+ final Class<? extends T[]> arrayTypeNew = (Class<? extends T[]>) newElements.getClass();
+ if( arrayTypeInternal != arrayTypeNew ) {
+ throw new IllegalArgumentException("newElements array-type mismatch, internal "+arrayTypeInternal+", newElements "+arrayTypeNew);
+ }
+ if( 0 != size ) {
+ throw new IllegalStateException("Buffer is not empty: "+this);
}
if( readPos != writePos ) {
throw new InternalError("R/W pos not equal: "+this);
}
- if( null != newElements && amount < newElements.length ) {
- throw new IllegalArgumentException("amount "+amount+" < newElements "+newElements.length);
+
+ final int growAmount = newElements.length;
+ final int newCapacity = capacity + growAmount;
+ final T[] oldArray = array;
+ final T[] newArray = (T[]) newArray(arrayTypeInternal, newCapacity);
+
+ // writePos == readPos
+ writePos += growAmount; // warp writePos to the end of the new data location
+
+ if( readPos > 0 ) {
+ System.arraycopy(oldArray, 0, newArray, 0, readPos);
+ }
+ if( growAmount > 0 ) {
+ System.arraycopy(newElements, 0, newArray, readPos, growAmount);
+ }
+ final int tail = capacity-readPos;
+ if( tail > 0 ) {
+ System.arraycopy(oldArray, readPos, newArray, writePos, tail);
+ }
+ size = growAmount;
+
+ capacity = newCapacity;
+ array = newArray;
+ }
+ }
+
+ @Override
+ public final void growFullBuffer(final int growAmount) throws IllegalStateException, IllegalArgumentException {
+ synchronized ( syncGlobal ) {
+ if( 0 > growAmount ) {
+ throw new IllegalArgumentException("amount "+growAmount+" < 0 ");
+ }
+ if( capacity != size ) {
+ throw new IllegalStateException("Buffer is not full: "+this);
+ }
+ if( readPos != writePos ) {
+ throw new InternalError("R/W pos not equal: "+this);
}
- final int newCapacity = capacity + amount;
+ @SuppressWarnings("unchecked")
+ final Class<? extends T[]> arrayTypeInternal = (Class<? extends T[]>) array.getClass();
+
+ final int newCapacity = capacity + growAmount;
final T[] oldArray = array;
- final T[] newArray = allocEmptyArray.newArray(newCapacity);
+ final T[] newArray = (T[]) newArray(arrayTypeInternal, newCapacity);
- if( isFull ) {
- // writePos == readPos
- readPos += amount; // warp readPos to the end of the new data location
-
- if(writePos > 0) {
- System.arraycopy(oldArray, 0, newArray, 0, writePos);
- }
- if( null != newElements && newElements.length > 0 ) {
- System.arraycopy(newElements, 0, newArray, writePos, newElements.length);
- }
- final int tail = capacity-writePos;
- if( tail > 0 ) {
- System.arraycopy(oldArray, writePos, newArray, readPos, tail);
- }
- } else /* if ( isEmpty ) */ {
- // writePos == readPos
- writePos += amount; // warp writePos to the end of the new data location
-
- if( readPos > 0 ) {
- System.arraycopy(oldArray, 0, newArray, 0, readPos);
- }
- if( null != newElements && newElements.length > 0 ) {
- System.arraycopy(newElements, 0, newArray, readPos, newElements.length);
- }
- final int tail = capacity-readPos;
- if( tail > 0 ) {
- System.arraycopy(oldArray, readPos, newArray, writePos, tail);
- }
- size = amount;
+ // writePos == readPos
+ readPos += growAmount; // warp readPos to the end of the new data location
+
+ if(writePos > 0) {
+ System.arraycopy(oldArray, 0, newArray, 0, writePos);
+ }
+ final int tail = capacity-writePos;
+ if( tail > 0 ) {
+ System.arraycopy(oldArray, writePos, newArray, readPos, tail);
}
capacity = newCapacity;
array = newArray;
}
}
+
+ @SuppressWarnings("unchecked")
+ private static <T> T[] newArray(Class<? extends T[]> arrayType, int length) {
+ return ((Object)arrayType == (Object)Object[].class)
+ ? (T[]) new Object[length]
+ : (T[]) Array.newInstance(arrayType.getComponentType(), length);
+ }
}