1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.common.lib.collections;
20
21 import java.io.IOException;
22 import java.io.ObjectInputStream;
23 import java.io.ObjectOutputStream;
24 import java.io.Serializable;
25 import java.util.AbstractCollection;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.Iterator;
29 import java.util.NoSuchElementException;
30 import java.util.Queue;
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 public class CircularFifoQueue<E> extends AbstractCollection<E> implements Queue<E>, Serializable {
49
50 private static final long serialVersionUID = -8423413834657610406L;
51
52
53 private transient E[] elements;
54
55
56 private transient int start = 0;
57
58
59
60
61
62
63
64
65 private transient int end = 0;
66
67
68 private transient boolean full = false;
69
70
71 private final int maxElements;
72
73
74
75
76 public CircularFifoQueue() {
77 this(32);
78 }
79
80
81
82
83
84
85
86 @SuppressWarnings("unchecked")
87 public CircularFifoQueue(final int size) {
88 if (size <= 0) {
89 throw new IllegalArgumentException("The size must be greater than 0");
90 }
91 elements = (E[]) new Object[size];
92 maxElements = elements.length;
93 }
94
95
96
97
98
99
100
101
102 public CircularFifoQueue(final Collection<? extends E> coll) {
103 this(coll.size());
104 addAll(coll);
105 }
106
107
108
109
110
111
112
113
114 private void writeObject(final ObjectOutputStream out) throws IOException {
115 out.defaultWriteObject();
116 out.writeInt(size());
117 for (final E e : this) {
118 out.writeObject(e);
119 }
120 }
121
122
123
124
125
126
127
128
129 @SuppressWarnings("unchecked")
130 private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
131 in.defaultReadObject();
132 elements = (E[]) new Object[maxElements];
133 final int size = in.readInt();
134 for (int i = 0; i < size; i++) {
135 elements[i] = (E) in.readObject();
136 }
137 start = 0;
138 full = size == maxElements;
139 if (full) {
140 end = 0;
141 } else {
142 end = size;
143 }
144 }
145
146
147
148
149
150
151
152 @Override
153 public int size() {
154 int size;
155
156 if (end < start) {
157 size = maxElements - start + end;
158 } else if (end == start) {
159 size = full ? maxElements : 0;
160 } else {
161 size = end - start;
162 }
163
164 return size;
165 }
166
167
168
169
170
171
172 @Override
173 public boolean isEmpty() {
174 return size() == 0;
175 }
176
177
178
179
180
181
182
183
184
185 public static boolean isFull() {
186 return false;
187 }
188
189
190
191
192
193
194
195
196 public boolean isAtFullCapacity() {
197 return size() == maxElements;
198 }
199
200
201
202
203
204
205 public int maxSize() {
206 return maxElements;
207 }
208
209
210
211
212 @Override
213 public void clear() {
214 full = false;
215 start = 0;
216 end = 0;
217 Arrays.fill(elements, null);
218 }
219
220
221
222
223
224
225
226
227
228 @Override
229 public boolean add(final E element) {
230 if (null == element) {
231 throw new NullPointerException("Attempted to add null object to queue");
232 }
233
234 if (isAtFullCapacity()) {
235 remove();
236 }
237
238 elements[end++] = element;
239
240 if (end >= maxElements) {
241 end = 0;
242 }
243
244 if (end == start) {
245 full = true;
246 }
247
248 return true;
249 }
250
251
252
253
254
255
256
257
258 public E get(final int index) {
259 final int sz = size();
260 if (index < 0 || index >= sz) {
261 throw new NoSuchElementException(
262 String.format("The specified index (%1$d) is outside the available range [0, %2$d)",
263 index, Integer.valueOf(sz)));
264 }
265
266 final int idx = (start + index) % maxElements;
267 return elements[idx];
268 }
269
270
271
272
273
274
275
276
277
278
279 @Override
280 public boolean offer(final E element) {
281 return add(element);
282 }
283
284 @Override
285 public E poll() {
286 if (isEmpty()) {
287 return null;
288 }
289 return remove();
290 }
291
292 @Override
293 public E element() {
294 if (isEmpty()) {
295 throw new NoSuchElementException("queue is empty");
296 }
297 return peek();
298 }
299
300 @Override
301 public E peek() {
302 if (isEmpty()) {
303 return null;
304 }
305 return elements[start];
306 }
307
308 @Override
309 public E remove() {
310 if (isEmpty()) {
311 throw new NoSuchElementException("queue is empty");
312 }
313
314 final E element = elements[start];
315 if (null != element) {
316 elements[start++] = null;
317
318 if (start >= maxElements) {
319 start = 0;
320 }
321 full = false;
322 }
323 return element;
324 }
325
326
327
328
329
330
331
332
333 private int increment(final int index) {
334 int result = index;
335 result++;
336 if (result >= maxElements) {
337 result = 0;
338 }
339 return result;
340 }
341
342
343
344
345
346
347
348 private int decrement(final int index) {
349 int result = index;
350 result--;
351 if (result < 0) {
352 result = maxElements - 1;
353 }
354 return result;
355 }
356
357
358
359
360
361
362 @Override
363 public Iterator<E> iterator() {
364 return new Iterator<>() {
365
366 private int index = start;
367
368 private int lastReturnedIndex = -1;
369
370 private boolean isFirst = full;
371
372 @Override
373 public boolean hasNext() {
374 return isFirst || index != end;
375 }
376
377 @Override
378 public E next() {
379 if (!hasNext()) {
380 throw new NoSuchElementException();
381 }
382 isFirst = false;
383 lastReturnedIndex = index;
384 index = increment(index);
385 return elements[lastReturnedIndex];
386 }
387
388 @Override
389 public void remove() {
390 if (lastReturnedIndex == -1) {
391 throw new IllegalStateException();
392 }
393
394
395 if (lastReturnedIndex == start) {
396 CircularFifoQueue.this.remove();
397 lastReturnedIndex = -1;
398 return;
399 }
400
401 int pos = lastReturnedIndex + 1;
402 if (start < lastReturnedIndex && pos < end) {
403
404 System.arraycopy(elements, pos, elements, lastReturnedIndex, end - pos);
405 } else {
406
407 while (pos != end) {
408 if (pos >= maxElements) {
409 elements[pos - 1] = elements[0];
410 pos = 0;
411 } else {
412 elements[decrement(pos)] = elements[pos];
413 pos = increment(pos);
414 }
415 }
416 }
417
418 lastReturnedIndex = -1;
419 end = decrement(end);
420 elements[end] = null;
421 full = false;
422 index = decrement(index);
423 }
424
425 };
426 }
427 }