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