|
16 | 16 | */
|
17 | 17 | package org.apache.lucene.search;
|
18 | 18 |
|
19 |
| -import java.util.Arrays; |
20 |
| -import java.util.Iterator; |
21 | 19 | import org.apache.lucene.util.PriorityQueue;
|
22 | 20 |
|
23 | 21 | /**
|
|
27 | 25 | *
|
28 | 26 | * @lucene.internal
|
29 | 27 | */
|
30 |
| -public final class DisiPriorityQueue implements Iterable<DisiWrapper> { |
31 |
| - |
32 |
| - static int leftNode(int node) { |
33 |
| - return ((node + 1) << 1) - 1; |
34 |
| - } |
35 |
| - |
36 |
| - static int rightNode(int leftNode) { |
37 |
| - return leftNode + 1; |
38 |
| - } |
39 |
| - |
40 |
| - static int parentNode(int node) { |
41 |
| - return ((node + 1) >>> 1) - 1; |
| 28 | +public abstract sealed class DisiPriorityQueue implements Iterable<DisiWrapper> |
| 29 | + permits DisiPriorityQueue2, DisiPriorityQueueN { |
| 30 | + |
| 31 | + /** Create a {@link DisiPriorityQueue} of the given maximum size. */ |
| 32 | + public static DisiPriorityQueue ofMaxSize(int maxSize) { |
| 33 | + if (maxSize <= 2) { |
| 34 | + return new DisiPriorityQueue2(); |
| 35 | + } else { |
| 36 | + return new DisiPriorityQueueN(maxSize); |
| 37 | + } |
42 | 38 | }
|
43 | 39 |
|
44 |
| - private final DisiWrapper[] heap; |
45 |
| - private int size; |
| 40 | + /** Return the number of entries in this heap. */ |
| 41 | + public abstract int size(); |
46 | 42 |
|
47 |
| - public DisiPriorityQueue(int maxSize) { |
48 |
| - heap = new DisiWrapper[maxSize]; |
49 |
| - size = 0; |
50 |
| - } |
51 |
| - |
52 |
| - public int size() { |
53 |
| - return size; |
54 |
| - } |
55 |
| - |
56 |
| - public DisiWrapper top() { |
57 |
| - return heap[0]; |
58 |
| - } |
| 43 | + /** Return top value in this heap, or null if the heap is empty. */ |
| 44 | + public abstract DisiWrapper top(); |
59 | 45 |
|
60 | 46 | /** Return the 2nd least value in this heap, or null if the heap contains less than 2 values. */
|
61 |
| - public DisiWrapper top2() { |
62 |
| - switch (size()) { |
63 |
| - case 0: |
64 |
| - case 1: |
65 |
| - return null; |
66 |
| - case 2: |
67 |
| - return heap[1]; |
68 |
| - default: |
69 |
| - if (heap[1].doc <= heap[2].doc) { |
70 |
| - return heap[1]; |
71 |
| - } else { |
72 |
| - return heap[2]; |
73 |
| - } |
74 |
| - } |
75 |
| - } |
| 47 | + public abstract DisiWrapper top2(); |
76 | 48 |
|
77 | 49 | /** Get the list of scorers which are on the current doc. */
|
78 |
| - public DisiWrapper topList() { |
79 |
| - final DisiWrapper[] heap = this.heap; |
80 |
| - final int size = this.size; |
81 |
| - DisiWrapper list = heap[0]; |
82 |
| - list.next = null; |
83 |
| - if (size >= 3) { |
84 |
| - list = topList(list, heap, size, 1); |
85 |
| - list = topList(list, heap, size, 2); |
86 |
| - } else if (size == 2 && heap[1].doc == list.doc) { |
87 |
| - list = prepend(heap[1], list); |
88 |
| - } |
89 |
| - return list; |
90 |
| - } |
91 |
| - |
92 |
| - // prepend w1 (iterator) to w2 (list) |
93 |
| - private DisiWrapper prepend(DisiWrapper w1, DisiWrapper w2) { |
94 |
| - w1.next = w2; |
95 |
| - return w1; |
96 |
| - } |
97 |
| - |
98 |
| - private DisiWrapper topList(DisiWrapper list, DisiWrapper[] heap, int size, int i) { |
99 |
| - final DisiWrapper w = heap[i]; |
100 |
| - if (w.doc == list.doc) { |
101 |
| - list = prepend(w, list); |
102 |
| - final int left = leftNode(i); |
103 |
| - final int right = left + 1; |
104 |
| - if (right < size) { |
105 |
| - list = topList(list, heap, size, left); |
106 |
| - list = topList(list, heap, size, right); |
107 |
| - } else if (left < size && heap[left].doc == list.doc) { |
108 |
| - list = prepend(heap[left], list); |
109 |
| - } |
110 |
| - } |
111 |
| - return list; |
112 |
| - } |
| 50 | + public abstract DisiWrapper topList(); |
113 | 51 |
|
114 |
| - public DisiWrapper add(DisiWrapper entry) { |
115 |
| - final DisiWrapper[] heap = this.heap; |
116 |
| - final int size = this.size; |
117 |
| - heap[size] = entry; |
118 |
| - upHeap(size); |
119 |
| - this.size = size + 1; |
120 |
| - return heap[0]; |
121 |
| - } |
| 52 | + /** Add a {@link DisiWrapper} to this queue and return the top entry. */ |
| 53 | + public abstract DisiWrapper add(DisiWrapper entry); |
122 | 54 |
|
| 55 | + /** Bulk add. */ |
123 | 56 | public void addAll(DisiWrapper[] entries, int offset, int len) {
|
124 |
| - // Nothing to do if empty: |
125 |
| - if (len == 0) { |
126 |
| - return; |
127 |
| - } |
128 |
| - |
129 |
| - // Fail early if we're going to over-fill: |
130 |
| - if (size + len > heap.length) { |
131 |
| - throw new IndexOutOfBoundsException( |
132 |
| - "Cannot add " |
133 |
| - + len |
134 |
| - + " elements to a queue with remaining capacity " |
135 |
| - + (heap.length - size)); |
136 |
| - } |
137 |
| - |
138 |
| - // Copy the entries over to our heap array: |
139 |
| - System.arraycopy(entries, offset, heap, size, len); |
140 |
| - size += len; |
141 |
| - |
142 |
| - // Heapify in bulk: |
143 |
| - final int firstLeafIndex = size >>> 1; |
144 |
| - for (int rootIndex = firstLeafIndex - 1; rootIndex >= 0; rootIndex--) { |
145 |
| - int parentIndex = rootIndex; |
146 |
| - DisiWrapper parent = heap[parentIndex]; |
147 |
| - while (parentIndex < firstLeafIndex) { |
148 |
| - int childIndex = leftNode(parentIndex); |
149 |
| - int rightChildIndex = rightNode(childIndex); |
150 |
| - DisiWrapper child = heap[childIndex]; |
151 |
| - if (rightChildIndex < size && heap[rightChildIndex].doc < child.doc) { |
152 |
| - child = heap[rightChildIndex]; |
153 |
| - childIndex = rightChildIndex; |
154 |
| - } |
155 |
| - if (child.doc >= parent.doc) { |
156 |
| - break; |
157 |
| - } |
158 |
| - heap[parentIndex] = child; |
159 |
| - parentIndex = childIndex; |
160 |
| - } |
161 |
| - heap[parentIndex] = parent; |
| 57 | + for (int i = 0; i < len; ++i) { |
| 58 | + add(entries[offset + i]); |
162 | 59 | }
|
163 | 60 | }
|
164 | 61 |
|
165 |
| - public DisiWrapper pop() { |
166 |
| - final DisiWrapper[] heap = this.heap; |
167 |
| - final DisiWrapper result = heap[0]; |
168 |
| - final int i = --size; |
169 |
| - heap[0] = heap[i]; |
170 |
| - heap[i] = null; |
171 |
| - downHeap(i); |
172 |
| - return result; |
173 |
| - } |
| 62 | + /** Remove the top entry and return it. */ |
| 63 | + public abstract DisiWrapper pop(); |
174 | 64 |
|
175 |
| - public DisiWrapper updateTop() { |
176 |
| - downHeap(size); |
177 |
| - return heap[0]; |
178 |
| - } |
| 65 | + /** Rebalance this heap and return the top entry. */ |
| 66 | + public abstract DisiWrapper updateTop(); |
179 | 67 |
|
180 |
| - DisiWrapper updateTop(DisiWrapper topReplacement) { |
181 |
| - heap[0] = topReplacement; |
182 |
| - return updateTop(); |
183 |
| - } |
| 68 | + /** |
| 69 | + * Replace the top entry with the given entry, rebalance the heap, and return the new top entry. |
| 70 | + */ |
| 71 | + abstract DisiWrapper updateTop(DisiWrapper topReplacement); |
184 | 72 |
|
185 | 73 | /** Clear the heap. */
|
186 |
| - public void clear() { |
187 |
| - Arrays.fill(heap, null); |
188 |
| - size = 0; |
189 |
| - } |
190 |
| - |
191 |
| - void upHeap(int i) { |
192 |
| - final DisiWrapper node = heap[i]; |
193 |
| - final int nodeDoc = node.doc; |
194 |
| - int j = parentNode(i); |
195 |
| - while (j >= 0 && nodeDoc < heap[j].doc) { |
196 |
| - heap[i] = heap[j]; |
197 |
| - i = j; |
198 |
| - j = parentNode(j); |
199 |
| - } |
200 |
| - heap[i] = node; |
201 |
| - } |
202 |
| - |
203 |
| - void downHeap(int size) { |
204 |
| - int i = 0; |
205 |
| - final DisiWrapper node = heap[0]; |
206 |
| - int j = leftNode(i); |
207 |
| - if (j < size) { |
208 |
| - int k = rightNode(j); |
209 |
| - if (k < size && heap[k].doc < heap[j].doc) { |
210 |
| - j = k; |
211 |
| - } |
212 |
| - if (heap[j].doc < node.doc) { |
213 |
| - do { |
214 |
| - heap[i] = heap[j]; |
215 |
| - i = j; |
216 |
| - j = leftNode(i); |
217 |
| - k = rightNode(j); |
218 |
| - if (k < size && heap[k].doc < heap[j].doc) { |
219 |
| - j = k; |
220 |
| - } |
221 |
| - } while (j < size && heap[j].doc < node.doc); |
222 |
| - heap[i] = node; |
223 |
| - } |
224 |
| - } |
225 |
| - } |
226 |
| - |
227 |
| - @Override |
228 |
| - public Iterator<DisiWrapper> iterator() { |
229 |
| - return Arrays.asList(heap).subList(0, size).iterator(); |
230 |
| - } |
| 74 | + public abstract void clear(); |
231 | 75 | }
|
0 commit comments