diff options
author | Sven Gothel <[email protected]> | 2013-08-24 03:14:14 +0200 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2013-08-24 03:14:14 +0200 |
commit | f9f881e59c78e3036cb3f956bc97cfc3197f620d (patch) | |
tree | 9362ac0e063eb48ed7c563d0ad83953bc828ed9b /src/java/com/jogamp/common/util/LFRingbuffer.java | |
parent | 30475c6bbeb9a5d48899b281ead8bb305679028d (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/com/jogamp/common/util/LFRingbuffer.java')
-rw-r--r-- | src/java/com/jogamp/common/util/LFRingbuffer.java | 157 |
1 files changed, 91 insertions, 66 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 |