29package com.jogamp.common.util;
31import java.io.PrintStream;
32import java.lang.reflect.Array;
53 private final Object syncGlobal =
new Object();
62 return "SyncedRingbuffer<?>[filled "+size+
" / "+capacity+
", writePos "+writePos+
", readPos "+readPos+
"]";
66 public final void dump(
final PrintStream stream,
final String prefix) {
67 stream.println(prefix+
" "+
toString()+
" {");
68 for(
int i=0; i<capacity; i++) {
69 stream.println(
"\t["+i+
"]: "+array[i]);
94 @SuppressWarnings(
"unchecked")
96 capacity = copyFrom.length;
97 array = (T[]) newArray(copyFrom.getClass(), capacity);
98 resetImpl(
true, copyFrom);
119 this.capacity = capacity;
120 this.array = newArray(arrayType, capacity);
121 resetImpl(
false,
null );
135 synchronized ( syncGlobal ) {
136 resetImpl(
false,
null);
137 for(
int i=0; i<capacity; i++) {
138 this.array[i] =
null;
144 public final void resetFull(
final T[] copyFrom)
throws IllegalArgumentException {
145 resetImpl(
true, copyFrom);
148 private final void resetImpl(
final boolean full,
final T[] copyFrom)
throws IllegalArgumentException {
149 synchronized ( syncGlobal ) {
150 if(
null != copyFrom ) {
151 if( copyFrom.length != capacity() ) {
152 throw new IllegalArgumentException(
"copyFrom array length "+copyFrom.length+
" != capacity "+
this);
154 System.arraycopy(copyFrom, 0, array, 0, copyFrom.length);
156 throw new IllegalArgumentException(
"copyFrom array is null");
160 size = full ? capacity : 0;
166 synchronized ( syncGlobal ) {
173 synchronized ( syncGlobal ) {
174 return capacity - size;
180 synchronized ( syncGlobal ) {
187 synchronized ( syncGlobal ) {
188 return capacity == size;
199 public final T
get() {
201 return getImpl(
false,
false);
202 }
catch (
final InterruptedException ie) {
throw new RuntimeException(ie); }
213 return getImpl(
true,
false);
219 return getImpl(
false,
true);
220 }
catch (
final InterruptedException ie) {
throw new RuntimeException(ie); }
224 return getImpl(
true,
true);
227 private final T getImpl(
final boolean blocking,
final boolean peek)
throws InterruptedException {
228 synchronized( syncGlobal ) {
238 final int localReadPos = readPos;
239 final T r = array[localReadPos];
241 array[localReadPos] =
null;
243 readPos = (localReadPos + 1) % capacity;
244 syncGlobal.notifyAll();
257 public final boolean put(
final T e) {
259 return putImpl(e,
false,
false);
260 }
catch (
final InterruptedException ie) {
throw new RuntimeException(ie); }
270 public final void putBlocking(
final T e)
throws InterruptedException {
271 if( !putImpl(e,
false,
true) ) {
272 throw new InternalError(
"Blocking put failed: "+
this);
283 public final boolean putSame(
final boolean blocking)
throws InterruptedException {
284 return putImpl(
null,
true, blocking);
287 private final boolean putImpl(
final T e,
final boolean sameRef,
final boolean blocking)
throws InterruptedException {
288 synchronized( syncGlobal ) {
289 if( capacity == size ) {
291 while( capacity == size ) {
298 final int localWritePos = writePos;
300 array[localWritePos] = e;
303 writePos = (localWritePos + 1) % capacity;
304 syncGlobal.notifyAll();
311 synchronized ( syncGlobal ) {
312 if( capacity - size < count ) {
313 while( capacity - size < count ) {
322 public final void growEmptyBuffer(
final T[] newElements)
throws IllegalStateException, IllegalArgumentException {
323 synchronized ( syncGlobal ) {
324 if(
null == newElements ) {
325 throw new IllegalArgumentException(
"newElements is null");
327 @SuppressWarnings(
"unchecked")
328 final Class<? extends T[]> arrayTypeInternal = (Class<? extends T[]>) array.getClass();
329 @SuppressWarnings(
"unchecked")
330 final Class<? extends T[]> arrayTypeNew = (Class<? extends T[]>) newElements.getClass();
331 if( arrayTypeInternal != arrayTypeNew ) {
332 throw new IllegalArgumentException(
"newElements array-type mismatch, internal "+arrayTypeInternal+
", newElements "+arrayTypeNew);
335 throw new IllegalStateException(
"Buffer is not empty: "+
this);
337 if( readPos != writePos ) {
338 throw new InternalError(
"R/W pos not equal: "+
this);
341 final int growAmount = newElements.length;
342 final int newCapacity = capacity + growAmount;
343 final T[] oldArray = array;
344 final T[] newArray = newArray(arrayTypeInternal, newCapacity);
347 writePos += growAmount;
350 System.arraycopy(oldArray, 0, newArray, 0, readPos);
352 if( growAmount > 0 ) {
353 System.arraycopy(newElements, 0, newArray, readPos, growAmount);
355 final int tail = capacity-readPos;
357 System.arraycopy(oldArray, readPos, newArray, writePos, tail);
361 capacity = newCapacity;
367 public final void growFullBuffer(
final int growAmount)
throws IllegalStateException, IllegalArgumentException {
368 synchronized ( syncGlobal ) {
369 if( 0 > growAmount ) {
370 throw new IllegalArgumentException(
"amount "+growAmount+
" < 0 ");
372 if( capacity != size ) {
373 throw new IllegalStateException(
"Buffer is not full: "+
this);
375 if( readPos != writePos ) {
376 throw new InternalError(
"R/W pos not equal: "+
this);
378 @SuppressWarnings(
"unchecked")
379 final Class<? extends T[]> arrayTypeInternal = (Class<? extends T[]>) array.getClass();
381 final int newCapacity = capacity + growAmount;
382 final T[] oldArray = array;
383 final T[] newArray = newArray(arrayTypeInternal, newCapacity);
386 readPos += growAmount;
389 System.arraycopy(oldArray, 0, newArray, 0, writePos);
391 final int tail = capacity-writePos;
393 System.arraycopy(oldArray, writePos, newArray, readPos, tail);
396 capacity = newCapacity;
401 @SuppressWarnings(
"unchecked")
402 private static <T> T[] newArray(final Class<? extends T[]> arrayType, final
int length) {
403 return ((Object)arrayType == (Object)Object[].
class)
404 ? (T[])
new Object[length]
405 : (T[]) Array.newInstance(arrayType.getComponentType(), length);
Simple synchronized implementation of Ringbuffer.
final boolean put(final T e)
Enqueues the given element.Returns true if successful, otherwise false in case buffer is full....
final boolean putSame(final boolean blocking)
Enqueues the same element at it's write position, if not full.Returns true if successful,...
final void waitForFreeSlots(final int count)
Blocks until at least count free slots become available.
final void growEmptyBuffer(final T[] newElements)
Grows an empty ring buffer, increasing it's capacity about the amount.
final void putBlocking(final T e)
Enqueues the given element.Method blocks until a free slot becomes available via get.
final int size()
Returns the number of elements in this ring buffer.
final int capacity()
Returns the net capacity of this ring buffer.
final T peekBlocking()
Peeks the next element at the read position w/o modifying pointer, but w/ blocking.
final String toString()
Returns a short string representation incl.
final void clear()
Resets the read and write position according to an empty ring buffer and set all ring buffer slots to...
final boolean isFull()
Returns true if this ring buffer is full, otherwise false.
final int getFreeSlots()
Returns the number of free slots available to put.
final void dump(final PrintStream stream, final String prefix)
Debug functionality - Dumps the contents of the internal array.
final void growFullBuffer(final int growAmount)
Grows a full ring buffer, increasing it's capacity about the amount.
final T peek()
Peeks the next element at the read position w/o modifying pointer, nor blocking.
final T getBlocking()
Dequeues the oldest enqueued element.The returned ring buffer slot will be set to null to release the...
final boolean isEmpty()
Returns true if this ring buffer is empty, otherwise false.
SyncedRingbuffer(final Class<? extends T[]> arrayType, final int capacity)
Create an empty ring buffer instance w/ the given net capacity.
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 ...
Ring buffer interface, a.k.a circular buffer.