1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.bea.xml.stream.util;
17
18 import java.util.AbstractCollection;
19 import java.util.Arrays;
20 import java.util.ConcurrentModificationException;
21 import java.util.Iterator;
22 import java.util.NoSuchElementException;
23
24 public final class CircularQueue extends AbstractCollection {
25
26
27 private static final int MAX_CAPACITY = 1 << 30;
28 private static final int DEFAULT_CAPACITY = 1 << 8;
29
30 private int size = 0;
31 private int producerIndex = 0;
32 private int consumerIndex = 0;
33
34
35 private int capacity;
36 private int maxCapacity;
37
38
39 private int bitmask;
40
41 private Object[] q;
42
43 public CircularQueue() {
44 this(DEFAULT_CAPACITY);
45 }
46
47
48
49
50
51 public CircularQueue(int c) {
52 this(c, MAX_CAPACITY);
53 }
54
55 public CircularQueue(int c, int mc) {
56 if (c > mc) {
57 throw new IllegalArgumentException("Capacity greater than maximum");
58 }
59
60 if (mc > MAX_CAPACITY) {
61 throw new IllegalArgumentException("Maximum capacity greater than " +
62 "allowed");
63 }
64
65 for (capacity = 1; capacity < c; capacity <<= 1) ;
66 for (maxCapacity = 1; maxCapacity < mc; maxCapacity <<= 1) ;
67
68 bitmask = capacity - 1;
69 q = new Object[capacity];
70 }
71
72
73 private CircularQueue(CircularQueue oldQueue) {
74 size = oldQueue.size;
75 producerIndex = oldQueue.producerIndex;
76 consumerIndex = oldQueue.consumerIndex;
77 capacity = oldQueue.capacity;
78 maxCapacity = oldQueue.maxCapacity;
79 bitmask = oldQueue.bitmask;
80 q = new Object[oldQueue.q.length];
81 System.arraycopy(oldQueue.q, 0, q, 0, q.length);
82 }
83
84 private boolean expandQueue() {
85
86
87
88 if (capacity == maxCapacity) {
89 return false;
90 }
91
92 int old_capacity = capacity;
93 Object[] old_q = q;
94
95 capacity += capacity;
96 bitmask = capacity - 1;
97 q = new Object[capacity];
98
99 System.arraycopy(old_q, consumerIndex, q, 0, old_capacity - consumerIndex);
100
101 if (consumerIndex != 0) {
102 System.arraycopy(old_q, 0, q, old_capacity - consumerIndex,
103 consumerIndex);
104 }
105
106 consumerIndex = 0;
107 producerIndex = size;
108
109 return true;
110 }
111
112 public boolean add(Object obj) {
113 if (size == capacity) {
114
115 if (!expandQueue()) return false;
116 }
117
118 size++;
119 q[producerIndex] = obj;
120
121 producerIndex = (producerIndex + 1) & bitmask;
122
123 return true;
124 }
125
126 public Object remove() {
127 Object obj;
128
129 if (size == 0) return null;
130
131 size--;
132 obj = q[consumerIndex];
133 q[consumerIndex] = null;
134
135 consumerIndex = (consumerIndex + 1) & bitmask;
136
137 return obj;
138 }
139
140 public boolean isEmpty() { return size == 0; }
141
142 public int size() { return size; }
143
144 public int capacity() { return capacity; }
145
146 public Object peek() {
147 if (size == 0) return null;
148 return q[consumerIndex];
149 }
150
151 public void clear() {
152 Arrays.fill(q, null);
153 size = 0;
154 producerIndex = 0;
155 consumerIndex = 0;
156 }
157
158 public Object clone() {
159 return new CircularQueue(this);
160 }
161
162 public String toString() {
163 StringBuffer s = new StringBuffer(super.toString() + " - capacity: '" +
164 capacity() + "' size: '" + size() + "'");
165
166 if (size > 0) {
167 s.append(" elements:");
168 for (int i = 0; i < size; ++i) {
169 s.append('\n');
170 s.append('\t');
171 s.append(q[consumerIndex + i & bitmask].toString());
172 }
173 }
174
175 return s.toString();
176 }
177
178 public Iterator iterator() {
179 return new Iterator() {
180 private final int ci = consumerIndex;
181 private final int pi = producerIndex;
182 private int s = size;
183 private int i = ci;
184
185 public boolean hasNext() {
186 checkForModification();
187 return s > 0;
188 }
189
190 public Object next() {
191 checkForModification();
192 if (s == 0) throw new NoSuchElementException();
193
194 s--;
195 Object r = q[i];
196 i = (i + 1) & bitmask;
197
198 return r;
199 }
200
201 public void remove() {
202 throw new UnsupportedOperationException();
203 }
204
205 private void checkForModification() {
206 if (ci != consumerIndex) throw new ConcurrentModificationException();
207 if (pi != producerIndex) throw new ConcurrentModificationException();
208 }
209 };
210 }
211 }