GlueGen: src/java/com/jogamp/common/util/SyncedRingbuffer.java Source File

GlueGen v2.6.0-rc-20250721 GlueGen, Native Binding Generator for Java™ (public API).

SyncedRingbuffer.java
Go to the documentation of this file.
1/**
2 * Copyright 2013 JogAmp Community. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
27 */
28
29package com.jogamp.common.util;
30
31import java.io.PrintStream;
32import java.lang.reflect.Array;
33
34/**
35 * Simple synchronized implementation of {@link Ringbuffer}.
36 * <p>
37 * All methods utilize global synchronization.
38 * </p>
39 * <p>
40 * Characteristics:
41 * <ul>
42 * <li>Read position points to the next read element.</li>
43 * <li>Write position points to the next write element.</li>
44 * </ul>
45 * <table border="1">
46 * <tr><td>Empty</td><td>writePos == readPos</td><td>size == 0</td></tr>
47 * <tr><td>Full</td><td>writePos == readPos</td><td>size == capacity</td></tr>
48 * </table>
49 * </p>
50 */
51 public class SyncedRingbuffer<T> implements Ringbuffer<T> {
52
53 private final Object syncGlobal = new Object();
54 private /* final */ T[] array; // not final due to grow
55 private /* final */ int capacity; // not final due to grow
56 private int readPos;
57 private int writePos;
58 private int size;
59
60 @Override
61 public final String toString() {
62 return "SyncedRingbuffer<?>[filled "+size+" / "+capacity+", writePos "+writePos+", readPos "+readPos+"]";
63 }
64
65 @Override
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]);
70 }
71 stream.println("}");
72 }
73
74 /**
75 * Create a full ring buffer instance w/ the given array's net capacity and content.
76 * <p>
77 * Example for a 10 element Integer array:
78 * <pre>
79 * Integer[] source = new Integer[10];
80 * // fill source with content ..
81 * Ringbuffer<Integer> rb = new SyncedRingbuffer<Integer>(source);
82 * </pre>
83 * </p>
84 * <p>
85 * {@link #isFull()} returns true on the newly created full ring buffer.
86 * </p>
87 * <p>
88 * Implementation will allocate an internal array with size of array <code>copyFrom</code>
89 * and copy all elements from array <code>copyFrom</code> into the internal array.
90 * </p>
91 * @param copyFrom mandatory source array determining ring buffer's net {@link #capacity()} and initial content.
92 * @throws IllegalArgumentException if <code>copyFrom</code> is <code>null</code>
93 */
94 @SuppressWarnings("unchecked")
95 public SyncedRingbuffer(final T[] copyFrom) throws IllegalArgumentException {
96 capacity = copyFrom.length;
97 array = (T[]) newArray(copyFrom.getClass(), capacity);
98 resetImpl(true, copyFrom);
99 }
100
101 /**
102 * Create an empty ring buffer instance w/ the given net <code>capacity</code>.
103 * <p>
104 * Example for a 10 element Integer array:
105 * <pre>
106 * Ringbuffer<Integer> rb = new SyncedRingbuffer<Integer>(10, Integer[].class);
107 * </pre>
108 * </p>
109 * <p>
110 * {@link #isEmpty()} returns true on the newly created empty ring buffer.
111 * </p>
112 * <p>
113 * Implementation will allocate an internal array of size <code>capacity</code>.
114 * </p>
115 * @param arrayType the array type of the created empty internal array.
116 * @param capacity the initial net capacity of the ring buffer
117 */
118 public SyncedRingbuffer(final Class<? extends T[]> arrayType, final int capacity) {
119 this.capacity = capacity;
120 this.array = newArray(arrayType, capacity);
121 resetImpl(false, null /* empty, nothing to copy */ );
122 }
123
124 @Override
125 public final int capacity() { return capacity; }
126
127 /**
128 * {@inheritDoc}
129 * <p>
130 * Implementation sets read and write position to zero.
131 * </p>
132 */
133 @Override
134 public final void clear() {
135 synchronized ( syncGlobal ) {
136 resetImpl(false, null);
137 for(int i=0; i<capacity; i++) {
138 this.array[i] = null;
139 }
140 }
141 }
142
143 @Override
144 public final void resetFull(final T[] copyFrom) throws IllegalArgumentException {
145 resetImpl(true, copyFrom);
146 }
147
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);
153 }
154 System.arraycopy(copyFrom, 0, array, 0, copyFrom.length);
155 } else if ( full ) {
156 throw new IllegalArgumentException("copyFrom array is null");
157 }
158 readPos = 0;
159 writePos = 0;
160 size = full ? capacity : 0;
161 }
162 }
163
164 @Override
165 public final int size() {
166 synchronized ( syncGlobal ) {
167 return size;
168 }
169 }
170
171 @Override
172 public final int getFreeSlots() {
173 synchronized ( syncGlobal ) {
174 return capacity - size;
175 }
176 }
177
178 @Override
179 public final boolean isEmpty() {
180 synchronized ( syncGlobal ) {
181 return 0 == size;
182 }
183 }
184
185 @Override
186 public final boolean isFull() {
187 synchronized ( syncGlobal ) {
188 return capacity == size;
189 }
190 }
191
192 /**
193 * {@inheritDoc}
194 * <p>
195 * Implementation returns the element at the current read position and advances it, if not empty.
196 * </p>
197 */
198 @Override
199 public final T get() {
200 try {
201 return getImpl(false, false);
202 } catch (final InterruptedException ie) { throw new RuntimeException(ie); }
203 }
204
205 /**
206 * {@inheritDoc}
207 * <p>
208 * Implementation returns the element at the current read position and advances it, if not empty.
209 * </p>
210 */
211 @Override
212 public final T getBlocking() throws InterruptedException {
213 return getImpl(true, false);
214 }
215
216 @Override
217 public final T peek() {
218 try {
219 return getImpl(false, true);
220 } catch (final InterruptedException ie) { throw new RuntimeException(ie); }
221 }
222 @Override
223 public final T peekBlocking() throws InterruptedException {
224 return getImpl(true, true);
225 }
226
227 private final T getImpl(final boolean blocking, final boolean peek) throws InterruptedException {
228 synchronized( syncGlobal ) {
229 if( 0 == size ) {
230 if( blocking ) {
231 while( 0 == size ) {
232 syncGlobal.wait();
233 }
234 } else {
235 return null;
236 }
237 }
238 final int localReadPos = readPos;
239 final T r = array[localReadPos];
240 if( !peek ) {
241 array[localReadPos] = null;
242 size--;
243 readPos = (localReadPos + 1) % capacity;
244 syncGlobal.notifyAll(); // notify waiting putter
245 }
246 return r;
247 }
248 }
249
250 /**
251 * {@inheritDoc}
252 * <p>
253 * Implementation stores the element at the current write position and advances it, if not full.
254 * </p>
255 */
256 @Override
257 public final boolean put(final T e) {
258 try {
259 return putImpl(e, false, false);
260 } catch (final InterruptedException ie) { throw new RuntimeException(ie); }
261 }
262
263 /**
264 * {@inheritDoc}
265 * <p>
266 * Implementation stores the element at the current write position and advances it, if not full.
267 * </p>
268 */
269 @Override
270 public final void putBlocking(final T e) throws InterruptedException {
271 if( !putImpl(e, false, true) ) {
272 throw new InternalError("Blocking put failed: "+this);
273 }
274 }
275
276 /**
277 * {@inheritDoc}
278 * <p>
279 * Implementation keeps the element at the current write position and advances it, if not full.
280 * </p>
281 */
282 @Override
283 public final boolean putSame(final boolean blocking) throws InterruptedException {
284 return putImpl(null, true, blocking);
285 }
286
287 private final boolean putImpl(final T e, final boolean sameRef, final boolean blocking) throws InterruptedException {
288 synchronized( syncGlobal ) {
289 if( capacity == size ) {
290 if( blocking ) {
291 while( capacity == size ) {
292 syncGlobal.wait();
293 }
294 } else {
295 return false;
296 }
297 }
298 final int localWritePos = writePos;
299 if( !sameRef ) {
300 array[localWritePos] = e;
301 }
302 size++;
303 writePos = (localWritePos + 1) % capacity;
304 syncGlobal.notifyAll(); // notify waiting getter
305 return true;
306 }
307 }
308
309 @Override
310 public final void waitForFreeSlots(final int count) throws InterruptedException {
311 synchronized ( syncGlobal ) {
312 if( capacity - size < count ) {
313 while( capacity - size < count ) {
314 syncGlobal.wait();
315 }
316 }
317 }
318 }
319
320
321 @Override
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");
326 }
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);
333 }
334 if( 0 != size ) {
335 throw new IllegalStateException("Buffer is not empty: "+this);
336 }
337 if( readPos != writePos ) {
338 throw new InternalError("R/W pos not equal: "+this);
339 }
340
341 final int growAmount = newElements.length;
342 final int newCapacity = capacity + growAmount;
343 final T[] oldArray = array;
344 final T[] newArray = newArray(arrayTypeInternal, newCapacity);
345
346 // writePos == readPos
347 writePos += growAmount; // warp writePos to the end of the new data location
348
349 if( readPos > 0 ) {
350 System.arraycopy(oldArray, 0, newArray, 0, readPos);
351 }
352 if( growAmount > 0 ) {
353 System.arraycopy(newElements, 0, newArray, readPos, growAmount);
354 }
355 final int tail = capacity-readPos;
356 if( tail > 0 ) {
357 System.arraycopy(oldArray, readPos, newArray, writePos, tail);
358 }
359 size = growAmount;
360
361 capacity = newCapacity;
362 array = newArray;
363 }
364 }
365
366 @Override
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 ");
371 }
372 if( capacity != size ) {
373 throw new IllegalStateException("Buffer is not full: "+this);
374 }
375 if( readPos != writePos ) {
376 throw new InternalError("R/W pos not equal: "+this);
377 }
378 @SuppressWarnings("unchecked")
379 final Class<? extends T[]> arrayTypeInternal = (Class<? extends T[]>) array.getClass();
380
381 final int newCapacity = capacity + growAmount;
382 final T[] oldArray = array;
383 final T[] newArray = newArray(arrayTypeInternal, newCapacity);
384
385 // writePos == readPos
386 readPos += growAmount; // warp readPos to the end of the new data location
387
388 if(writePos > 0) {
389 System.arraycopy(oldArray, 0, newArray, 0, writePos);
390 }
391 final int tail = capacity-writePos;
392 if( tail > 0 ) {
393 System.arraycopy(oldArray, writePos, newArray, readPos, tail);
394 }
395
396 capacity = newCapacity;
397 array = newArray;
398 }
399 }
400
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);
406 }
407}
com.jogamp.common.util.SyncedRingbuffer
Simple synchronized implementation of Ringbuffer.
Definition: SyncedRingbuffer.java:51
com.jogamp.common.util.SyncedRingbuffer.put
final boolean put(final T e)
Enqueues the given element.Returns true if successful, otherwise false in case buffer is full....
Definition: SyncedRingbuffer.java:257
com.jogamp.common.util.SyncedRingbuffer.putSame
final boolean putSame(final boolean blocking)
Enqueues the same element at it's write position, if not full.Returns true if successful,...
Definition: SyncedRingbuffer.java:283
com.jogamp.common.util.SyncedRingbuffer.waitForFreeSlots
final void waitForFreeSlots(final int count)
Blocks until at least count free slots become available.
Definition: SyncedRingbuffer.java:310
com.jogamp.common.util.SyncedRingbuffer.growEmptyBuffer
final void growEmptyBuffer(final T[] newElements)
Grows an empty ring buffer, increasing it's capacity about the amount.
Definition: SyncedRingbuffer.java:322
com.jogamp.common.util.SyncedRingbuffer.putBlocking
final void putBlocking(final T e)
Enqueues the given element.Method blocks until a free slot becomes available via get.
Definition: SyncedRingbuffer.java:270
com.jogamp.common.util.SyncedRingbuffer.size
final int size()
Returns the number of elements in this ring buffer.
Definition: SyncedRingbuffer.java:165
com.jogamp.common.util.SyncedRingbuffer.capacity
final int capacity()
Returns the net capacity of this ring buffer.
Definition: SyncedRingbuffer.java:125
com.jogamp.common.util.SyncedRingbuffer.peekBlocking
final T peekBlocking()
Peeks the next element at the read position w/o modifying pointer, but w/ blocking.
Definition: SyncedRingbuffer.java:223
com.jogamp.common.util.SyncedRingbuffer.toString
final String toString()
Returns a short string representation incl.
Definition: SyncedRingbuffer.java:61
com.jogamp.common.util.SyncedRingbuffer.clear
final void clear()
Resets the read and write position according to an empty ring buffer and set all ring buffer slots to...
Definition: SyncedRingbuffer.java:134
com.jogamp.common.util.SyncedRingbuffer.isFull
final boolean isFull()
Returns true if this ring buffer is full, otherwise false.
Definition: SyncedRingbuffer.java:186
com.jogamp.common.util.SyncedRingbuffer.getFreeSlots
final int getFreeSlots()
Returns the number of free slots available to put.
Definition: SyncedRingbuffer.java:172
com.jogamp.common.util.SyncedRingbuffer.dump
final void dump(final PrintStream stream, final String prefix)
Debug functionality - Dumps the contents of the internal array.
Definition: SyncedRingbuffer.java:66
com.jogamp.common.util.SyncedRingbuffer.growFullBuffer
final void growFullBuffer(final int growAmount)
Grows a full ring buffer, increasing it's capacity about the amount.
Definition: SyncedRingbuffer.java:367
com.jogamp.common.util.SyncedRingbuffer.peek
final T peek()
Peeks the next element at the read position w/o modifying pointer, nor blocking.
Definition: SyncedRingbuffer.java:217
com.jogamp.common.util.SyncedRingbuffer.getBlocking
final T getBlocking()
Dequeues the oldest enqueued element.The returned ring buffer slot will be set to null to release the...
Definition: SyncedRingbuffer.java:212
com.jogamp.common.util.SyncedRingbuffer.isEmpty
final boolean isEmpty()
Returns true if this ring buffer is empty, otherwise false.
Definition: SyncedRingbuffer.java:179
com.jogamp.common.util.SyncedRingbuffer.SyncedRingbuffer
SyncedRingbuffer(final Class<? extends T[]> arrayType, final int capacity)
Create an empty ring buffer instance w/ the given net capacity.
Definition: SyncedRingbuffer.java:118
com.jogamp.common.util.SyncedRingbuffer.resetFull
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 ...
Definition: SyncedRingbuffer.java:144
com.jogamp.common.util.Ringbuffer
Ring buffer interface, a.k.a circular buffer.
Definition: Ringbuffer.java:45