29package com.jogamp.common.util;
31import java.io.PrintStream;
32import java.lang.reflect.Array;
75 private final Object syncRead =
new Object();
76 private final Object syncWrite =
new Object();
77 private final Object syncGlobal =
new Object();
78 private volatile T[] array;
79 private volatile int capacityPlusOne;
80 private volatile int readPos;
81 private volatile int writePos;
82 private volatile int size;
86 return "LFRingbuffer<?>[filled "+size+
" / "+(capacityPlusOne-1)+
", writePos "+writePos+
", readPos "+readPos+
"]";
90 public final void dump(
final PrintStream stream,
final String prefix) {
91 stream.println(prefix+
" "+
toString()+
" {");
92 for(
int i=0; i<capacityPlusOne; i++) {
93 stream.println(
"\t["+i+
"]: "+array[i]);
118 @SuppressWarnings(
"unchecked")
119 public
LFRingbuffer(final T[] copyFrom) throws IllegalArgumentException {
120 capacityPlusOne = copyFrom.length + 1;
121 array = (T[]) newArray(copyFrom.getClass(), capacityPlusOne);
122 resetImpl(
true, copyFrom);
144 array = newArray(arrayType, capacityPlusOne);
145 resetImpl(
false,
null );
149 public final int capacity() {
return capacityPlusOne-1; }
153 synchronized ( syncGlobal ) {
154 resetImpl(
false,
null);
155 for(
int i=0; i<capacityPlusOne; i++) {
156 this.array[i] =
null;
162 public final void resetFull(
final T[] copyFrom)
throws IllegalArgumentException {
163 resetImpl(
true, copyFrom);
166 private final void resetImpl(
final boolean full,
final T[] copyFrom)
throws IllegalArgumentException {
167 synchronized ( syncGlobal ) {
168 if(
null != copyFrom ) {
169 if( copyFrom.length != capacityPlusOne-1 ) {
170 throw new IllegalArgumentException(
"copyFrom array length "+copyFrom.length+
" != capacity "+
this);
172 System.arraycopy(copyFrom, 0, array, 0, copyFrom.length);
173 array[capacityPlusOne-1] =
null;
175 throw new IllegalArgumentException(
"copyFrom array is null");
177 readPos = capacityPlusOne - 1;
179 writePos = readPos - 1;
180 size = capacityPlusOne - 1;
195 public final boolean isEmpty() {
return 0 == size; }
198 public final boolean isFull() {
return capacityPlusOne - 1 == size; }
207 public final T
get() {
209 return getImpl(
false,
false);
210 }
catch (
final InterruptedException ie) {
throw new RuntimeException(ie); }
221 return getImpl(
true,
false);
227 return getImpl(
false,
true);
228 }
catch (
final InterruptedException ie) {
throw new RuntimeException(ie); }
232 return getImpl(
true,
true);
235 private final T getImpl(
final boolean blocking,
final boolean peek)
throws InterruptedException {
236 int localReadPos = readPos;
237 if( localReadPos == writePos ) {
239 synchronized( syncRead ) {
240 while( localReadPos == writePos ) {
248 localReadPos = (localReadPos + 1) % capacityPlusOne;
249 final T r = array[localReadPos];
251 array[localReadPos] =
null;
252 synchronized ( syncWrite ) {
254 readPos = localReadPos;
255 syncWrite.notifyAll();
268 public final boolean put(
final T e) {
270 return putImpl(e,
false,
false);
271 }
catch (
final InterruptedException ie) {
throw new RuntimeException(ie); }
281 public final void putBlocking(
final T e)
throws InterruptedException {
282 if( !putImpl(e,
false,
true) ) {
283 throw new InternalError(
"Blocking put failed: "+
this);
294 public final boolean putSame(
final boolean blocking)
throws InterruptedException {
295 return putImpl(
null,
true, blocking);
298 private final boolean putImpl(
final T e,
final boolean sameRef,
final boolean blocking)
throws InterruptedException {
299 int localWritePos = writePos;
300 localWritePos = (localWritePos + 1) % capacityPlusOne;
301 if( localWritePos == readPos ) {
303 synchronized( syncWrite ) {
304 while( localWritePos == readPos ) {
313 array[localWritePos] = e;
315 synchronized ( syncRead ) {
317 writePos = localWritePos;
318 syncRead.notifyAll();
326 synchronized ( syncRead ) {
327 if( capacityPlusOne - 1 - size < count ) {
328 while( capacityPlusOne - 1 - size < count ) {
336 public final void growEmptyBuffer(
final T[] newElements)
throws IllegalStateException, IllegalArgumentException {
337 synchronized( syncGlobal ) {
338 if(
null == newElements ) {
339 throw new IllegalArgumentException(
"newElements is null");
341 @SuppressWarnings(
"unchecked")
342 final Class<? extends T[]> arrayTypeInternal = (Class<? extends T[]>) array.getClass();
343 @SuppressWarnings(
"unchecked")
344 final Class<? extends T[]> arrayTypeNew = (Class<? extends T[]>) newElements.getClass();
345 if( arrayTypeInternal != arrayTypeNew ) {
346 throw new IllegalArgumentException(
"newElements array-type mismatch, internal "+arrayTypeInternal+
", newElements "+arrayTypeNew);
349 throw new IllegalStateException(
"Buffer is not empty: "+
this);
351 if( readPos != writePos ) {
352 throw new InternalError(
"R/W pos not equal: "+
this);
354 if( readPos != writePos ) {
355 throw new InternalError(
"R/W pos not equal at empty: "+
this);
358 final int growAmount = newElements.length;
359 final int newCapacity = capacityPlusOne + growAmount;
360 final T[] oldArray = array;
361 final T[] newArray = newArray(arrayTypeInternal, newCapacity);
364 writePos += growAmount;
367 System.arraycopy(oldArray, 0, newArray, 0, readPos+1);
369 if( growAmount > 0 ) {
370 System.arraycopy(newElements, 0, newArray, readPos+1, growAmount);
372 final int tail = capacityPlusOne-1-readPos;
374 System.arraycopy(oldArray, readPos+1, newArray, writePos+1, tail);
378 capacityPlusOne = newCapacity;
384 public final void growFullBuffer(
final int growAmount)
throws IllegalStateException, IllegalArgumentException {
385 synchronized ( syncGlobal ) {
386 if( 0 > growAmount ) {
387 throw new IllegalArgumentException(
"amount "+growAmount+
" < 0 ");
389 if( capacityPlusOne-1 != size ) {
390 throw new IllegalStateException(
"Buffer is not full: "+
this);
392 final int wp1 = ( writePos + 1 ) % capacityPlusOne;
393 if( wp1 != readPos ) {
394 throw new InternalError(
"R != W+1 pos at full: "+
this);
396 @SuppressWarnings(
"unchecked")
397 final Class<? extends T[]> arrayTypeInternal = (Class<? extends T[]>) array.getClass();
399 final int newCapacity = capacityPlusOne + growAmount;
400 final T[] oldArray = array;
401 final T[] newArray = newArray(arrayTypeInternal, newCapacity);
404 readPos = ( writePos + 1 + growAmount ) % newCapacity;
407 System.arraycopy(oldArray, 0, newArray, 0, writePos+1);
409 final int tail = capacityPlusOne-1-writePos;
411 System.arraycopy(oldArray, writePos+1, newArray, readPos, tail);
414 capacityPlusOne = newCapacity;
419 @SuppressWarnings(
"unchecked")
420 private static <T> T[] newArray(final Class<? extends T[]> arrayType, final
int length) {
421 return ((Object)arrayType == (Object)Object[].
class)
422 ? (T[])
new Object[length]
423 : (T[]) Array.newInstance(arrayType.getComponentType(), length);
Simple implementation of Ringbuffer, exposing lock-free get*(..) and put*(..) methods.
final String toString()
Returns a short string representation incl.
final void resetFull(final T[] copyFrom)
Resets the read and write position according to a full ring buffer and fill all slots w/ elements of ...
final int getFreeSlots()
Returns the number of free slots available to put.
final boolean putSame(final boolean blocking)
Enqueues the same element at it's write position, if not full.Returns true if successful,...
final int capacity()
Returns the net capacity of this ring buffer.
final void waitForFreeSlots(final int count)
Blocks until at least count free slots become available.
final boolean put(final T e)
Enqueues the given element.Returns true if successful, otherwise false in case buffer is full....
final T getBlocking()
Dequeues the oldest enqueued element.The returned ring buffer slot will be set to null to release the...
final int size()
Returns the number of elements in this ring buffer.
final void clear()
Resets the read and write position according to an empty ring buffer and set all ring buffer slots to...
final T peek()
Peeks the next element at the read position w/o modifying pointer, nor blocking.
final void putBlocking(final T e)
Enqueues the given element.Method blocks until a free slot becomes available via get.
final void dump(final PrintStream stream, final String prefix)
Debug functionality - Dumps the contents of the internal array.
final boolean isEmpty()
Returns true if this ring buffer is empty, otherwise false.
final T peekBlocking()
Peeks the next element at the read position w/o modifying pointer, but w/ blocking.
final void growEmptyBuffer(final T[] newElements)
Grows an empty ring buffer, increasing it's capacity about the amount.
final boolean isFull()
Returns true if this ring buffer is full, otherwise false.
LFRingbuffer(final Class<? extends T[]> arrayType, final int capacity)
Create an empty ring buffer instance w/ the given net capacity.
final void growFullBuffer(final int growAmount)
Grows a full ring buffer, increasing it's capacity about the amount.
Ring buffer interface, a.k.a circular buffer.