1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.util;
21
22 import java.io.Serializable;
23 import java.util.AbstractList;
24 import java.util.Arrays;
25 import java.util.List;
26 import java.util.NoSuchElementException;
27 import java.util.Queue;
28
29
30
31
32
33
34
35 public class CircularQueue<E> extends AbstractList<E> implements List<E>, Queue<E>, Serializable {
36
37 private static final long serialVersionUID = 3993421269224511264L;
38
39 private static final int DEFAULT_CAPACITY = 4;
40
41 private final int initialCapacity;
42 private Object[] items;
43 private int mask;
44 private int first = 0;
45 private int last = 0;
46 private boolean full;
47 private int shrinkThreshold;
48
49
50
51
52 public CircularQueue() {
53 this(DEFAULT_CAPACITY);
54 }
55
56 public CircularQueue(int initialCapacity) {
57 int actualCapacity = normalizeCapacity(initialCapacity);
58 items = new Object[actualCapacity];
59 mask = actualCapacity - 1;
60 this.initialCapacity = actualCapacity;
61 this.shrinkThreshold = 0;
62 }
63
64 private static int normalizeCapacity(int initialCapacity) {
65 int actualCapacity = 1;
66 while (actualCapacity < initialCapacity) {
67 actualCapacity <<= 1;
68 if (actualCapacity < 0) {
69 actualCapacity = 1 << 30;
70 break;
71 }
72 }
73 return actualCapacity;
74 }
75
76
77
78
79 public int capacity() {
80 return items.length;
81 }
82
83 @Override
84 public void clear() {
85 if (!isEmpty()) {
86 Arrays.fill(items, null);
87 first = 0;
88 last = 0;
89 full = false;
90 shrinkIfNeeded();
91 }
92 }
93
94 @SuppressWarnings("unchecked")
95 public E poll() {
96 if (isEmpty()) {
97 return null;
98 }
99
100 Object ret = items[first];
101 items[first] = null;
102 decreaseSize();
103
104 if (first == last) {
105 first = last = 0;
106 }
107
108 shrinkIfNeeded();
109 return (E) ret;
110 }
111
112 public boolean offer(E item) {
113 if (item == null) {
114 throw new NullPointerException("item");
115 }
116 expandIfNeeded();
117 items[last] = item;
118 increaseSize();
119 return true;
120 }
121
122 @SuppressWarnings("unchecked")
123 public E peek() {
124 if (isEmpty()) {
125 return null;
126 }
127
128 return (E) items[first];
129 }
130
131 @SuppressWarnings("unchecked")
132 @Override
133 public E get(int idx) {
134 checkIndex(idx);
135 return (E) items[getRealIndex(idx)];
136 }
137
138 @Override
139 public boolean isEmpty() {
140 return (first == last) && !full;
141 }
142
143 @Override
144 public int size() {
145 if (full) {
146 return capacity();
147 }
148
149 if (last >= first) {
150 return last - first;
151 } else {
152 return last - first + capacity();
153 }
154 }
155
156 @Override
157 public String toString() {
158 return "first=" + first + ", last=" + last + ", size=" + size()
159 + ", mask = " + mask;
160 }
161
162 private void checkIndex(int idx) {
163 if (idx < 0 || idx >= size()) {
164 throw new IndexOutOfBoundsException(String.valueOf(idx));
165 }
166 }
167
168 private int getRealIndex(int idx) {
169 return (first + idx) & mask;
170 }
171
172 private void increaseSize() {
173 last = (last + 1) & mask;
174 full = first == last;
175 }
176
177 private void decreaseSize() {
178 first = (first + 1) & mask;
179 full = false;
180 }
181
182 private void expandIfNeeded() {
183 if (full) {
184
185 final int oldLen = items.length;
186 final int newLen = oldLen << 1;
187 Object[] tmp = new Object[newLen];
188
189 if (first < last) {
190 System.arraycopy(items, first, tmp, 0, last - first);
191 } else {
192 System.arraycopy(items, first, tmp, 0, oldLen - first);
193 System.arraycopy(items, 0, tmp, oldLen - first, last);
194 }
195
196 first = 0;
197 last = oldLen;
198 items = tmp;
199 mask = tmp.length - 1;
200 if (newLen >>> 3 > initialCapacity) {
201 shrinkThreshold = newLen >>> 3;
202 }
203 }
204 }
205
206 private void shrinkIfNeeded() {
207 int size = size();
208 if (size < shrinkThreshold) {
209
210 final int oldLen = items.length;
211 int newLen = normalizeCapacity(size);
212 if (size == newLen) {
213 newLen <<= 1;
214 }
215
216 if (newLen >= oldLen) {
217 return;
218 }
219
220 if (newLen < initialCapacity) {
221 if (oldLen == initialCapacity) {
222 return;
223 } else {
224 newLen = initialCapacity;
225 }
226 }
227
228 Object[] tmp = new Object[newLen];
229
230 if (first < last) {
231 System.arraycopy(items, first, tmp, 0, last - first);
232 } else {
233 System.arraycopy(items, first, tmp, 0, oldLen - first);
234 System.arraycopy(items, 0, tmp, oldLen - first, last);
235 }
236
237 first = 0;
238 last = size;
239 items = tmp;
240 mask = tmp.length - 1;
241 shrinkThreshold = 0;
242 }
243 }
244
245 @Override
246 public boolean add(E o) {
247 return offer(o);
248 }
249
250 @SuppressWarnings("unchecked")
251 @Override
252 public E set(int idx, E o) {
253 checkIndex(idx);
254
255 int realIdx = getRealIndex(idx);
256 Object old = items[realIdx];
257 items[realIdx] = o;
258 return (E) old;
259 }
260
261 @Override
262 public void add(int idx, E o) {
263 if (idx == size()) {
264 offer(o);
265 return;
266 }
267
268 checkIndex(idx);
269 expandIfNeeded();
270
271 int realIdx = getRealIndex(idx);
272
273
274 if (first < last) {
275 System
276 .arraycopy(items, realIdx, items, realIdx + 1, last
277 - realIdx);
278 } else {
279 if (realIdx >= first) {
280 System.arraycopy(items, 0, items, 1, last);
281 items[0] = items[items.length - 1];
282 System.arraycopy(items, realIdx, items, realIdx + 1,
283 items.length - realIdx - 1);
284 } else {
285 System.arraycopy(items, realIdx, items, realIdx + 1, last
286 - realIdx);
287 }
288 }
289
290 items[realIdx] = o;
291 increaseSize();
292 }
293
294 @SuppressWarnings("unchecked")
295 @Override
296 public E remove(int idx) {
297 if (idx == 0) {
298 return poll();
299 }
300
301 checkIndex(idx);
302
303 int realIdx = getRealIndex(idx);
304 Object removed = items[realIdx];
305
306
307 if (first < last) {
308 System.arraycopy(items, first, items, first + 1, realIdx - first);
309 } else {
310 if (realIdx >= first) {
311 System.arraycopy(items, first, items, first + 1, realIdx
312 - first);
313 } else {
314 System.arraycopy(items, 0, items, 1, realIdx);
315 items[0] = items[items.length - 1];
316 System.arraycopy(items, first, items, first + 1, items.length
317 - first - 1);
318 }
319 }
320
321 items[first] = null;
322 decreaseSize();
323
324 shrinkIfNeeded();
325 return (E) removed;
326 }
327
328 public E remove() {
329 if (isEmpty()) {
330 throw new NoSuchElementException();
331 }
332 return poll();
333 }
334
335 public E element() {
336 if (isEmpty()) {
337 throw new NoSuchElementException();
338 }
339 return peek();
340 }
341 }