1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.util.internal;
17
18 import java.util.AbstractQueue;
19 import java.util.Arrays;
20 import java.util.Comparator;
21 import java.util.Iterator;
22 import java.util.NoSuchElementException;
23
24 import static io.netty.util.internal.PriorityQueueNode.INDEX_NOT_IN_QUEUE;
25
26
27
28
29
30
31 public final class DefaultPriorityQueue<T extends PriorityQueueNode> extends AbstractQueue<T>
32 implements PriorityQueue<T> {
33 private static final PriorityQueueNode[] EMPTY_ARRAY = new PriorityQueueNode[0];
34 private final Comparator<T> comparator;
35 private T[] queue;
36 private int size;
37
38 @SuppressWarnings("unchecked")
39 public DefaultPriorityQueue(Comparator<T> comparator, int initialSize) {
40 this.comparator = ObjectUtil.checkNotNull(comparator, "comparator");
41 queue = (T[]) (initialSize != 0 ? new PriorityQueueNode[initialSize] : EMPTY_ARRAY);
42 }
43
44 @Override
45 public int size() {
46 return size;
47 }
48
49 @Override
50 public boolean isEmpty() {
51 return size == 0;
52 }
53
54 @Override
55 public boolean contains(Object o) {
56 if (!(o instanceof PriorityQueueNode)) {
57 return false;
58 }
59 PriorityQueueNode node = (PriorityQueueNode) o;
60 return contains(node, node.priorityQueueIndex(this));
61 }
62
63 @Override
64 public boolean containsTyped(T node) {
65 return contains(node, node.priorityQueueIndex(this));
66 }
67
68 @Override
69 public void clear() {
70 for (int i = 0; i < size; ++i) {
71 T node = queue[i];
72 if (node != null) {
73 node.priorityQueueIndex(this, INDEX_NOT_IN_QUEUE);
74 queue[i] = null;
75 }
76 }
77 size = 0;
78 }
79
80 @Override
81 public void clearIgnoringIndexes() {
82 size = 0;
83 }
84
85 @Override
86 public boolean offer(T e) {
87 if (e.priorityQueueIndex(this) != INDEX_NOT_IN_QUEUE) {
88 throw new IllegalArgumentException("e.priorityQueueIndex(): " + e.priorityQueueIndex(this) +
89 " (expected: " + INDEX_NOT_IN_QUEUE + ") + e: " + e);
90 }
91
92
93 if (size >= queue.length) {
94
95
96 queue = Arrays.copyOf(queue, queue.length + ((queue.length < 64) ?
97 (queue.length + 2) :
98 (queue.length >>> 1)));
99 }
100
101 bubbleUp(size++, e);
102 return true;
103 }
104
105 @Override
106 public T poll() {
107 if (size == 0) {
108 return null;
109 }
110 T result = queue[0];
111 result.priorityQueueIndex(this, INDEX_NOT_IN_QUEUE);
112
113 T last = queue[--size];
114 queue[size] = null;
115 if (size != 0) {
116 bubbleDown(0, last);
117 }
118
119 return result;
120 }
121
122 @Override
123 public T peek() {
124 return (size == 0) ? null : queue[0];
125 }
126
127 @SuppressWarnings("unchecked")
128 @Override
129 public boolean remove(Object o) {
130 final T node;
131 try {
132 node = (T) o;
133 } catch (ClassCastException e) {
134 return false;
135 }
136 return removeTyped(node);
137 }
138
139 @Override
140 public boolean removeTyped(T node) {
141 int i = node.priorityQueueIndex(this);
142 if (!contains(node, i)) {
143 return false;
144 }
145
146 node.priorityQueueIndex(this, INDEX_NOT_IN_QUEUE);
147 if (--size == 0 || size == i) {
148
149 queue[i] = null;
150 return true;
151 }
152
153
154 T moved = queue[i] = queue[size];
155 queue[size] = null;
156
157
158
159 if (comparator.compare(node, moved) < 0) {
160 bubbleDown(i, moved);
161 } else {
162 bubbleUp(i, moved);
163 }
164 return true;
165 }
166
167 @Override
168 public void priorityChanged(T node) {
169 int i = node.priorityQueueIndex(this);
170 if (!contains(node, i)) {
171 return;
172 }
173
174
175 if (i == 0) {
176 bubbleDown(i, node);
177 } else {
178
179 int iParent = (i - 1) >>> 1;
180 T parent = queue[iParent];
181 if (comparator.compare(node, parent) < 0) {
182 bubbleUp(i, node);
183 } else {
184 bubbleDown(i, node);
185 }
186 }
187 }
188
189 @Override
190 public Object[] toArray() {
191 return Arrays.copyOf(queue, size);
192 }
193
194 @SuppressWarnings("unchecked")
195 @Override
196 public <X> X[] toArray(X[] a) {
197 if (a.length < size) {
198 return (X[]) Arrays.copyOf(queue, size, a.getClass());
199 }
200 System.arraycopy(queue, 0, a, 0, size);
201 if (a.length > size) {
202 a[size] = null;
203 }
204 return a;
205 }
206
207
208
209
210 @Override
211 public Iterator<T> iterator() {
212 return new PriorityQueueIterator();
213 }
214
215 private final class PriorityQueueIterator implements Iterator<T> {
216 private int index;
217
218 @Override
219 public boolean hasNext() {
220 return index < size;
221 }
222
223 @Override
224 public T next() {
225 if (index >= size) {
226 throw new NoSuchElementException();
227 }
228
229 return queue[index++];
230 }
231
232 @Override
233 public void remove() {
234 throw new UnsupportedOperationException("remove");
235 }
236 }
237
238 private boolean contains(PriorityQueueNode node, int i) {
239 return i >= 0 && i < size && node.equals(queue[i]);
240 }
241
242 private void bubbleDown(int k, T node) {
243 final int half = size >>> 1;
244 while (k < half) {
245
246 int iChild = (k << 1) + 1;
247 T child = queue[iChild];
248
249
250 int rightChild = iChild + 1;
251 if (rightChild < size && comparator.compare(child, queue[rightChild]) > 0) {
252 child = queue[iChild = rightChild];
253 }
254
255
256 if (comparator.compare(node, child) <= 0) {
257 break;
258 }
259
260
261 queue[k] = child;
262 child.priorityQueueIndex(this, k);
263
264
265 k = iChild;
266 }
267
268
269 queue[k] = node;
270 node.priorityQueueIndex(this, k);
271 }
272
273 private void bubbleUp(int k, T node) {
274 while (k > 0) {
275 int iParent = (k - 1) >>> 1;
276 T parent = queue[iParent];
277
278
279
280 if (comparator.compare(node, parent) >= 0) {
281 break;
282 }
283
284
285 queue[k] = parent;
286 parent.priorityQueueIndex(this, k);
287
288
289 k = iParent;
290 }
291
292
293 queue[k] = node;
294 node.priorityQueueIndex(this, k);
295 }
296 }