|
| 1 | +/* |
| 2 | + * Copyright (C) 2010-2023 Sebastiano Vigna |
| 3 | + * |
| 4 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | + * you may not use this file except in compliance with the License. |
| 6 | + * You may obtain a copy of the License at |
| 7 | + * |
| 8 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | + * |
| 10 | + * Unless required by applicable law or agreed to in writing, software |
| 11 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | + * See the License for the specific language governing permissions and |
| 14 | + * limitations under the License. |
| 15 | + */ |
| 16 | + |
| 17 | + |
| 18 | +package PACKAGE; |
| 19 | + |
| 20 | +#if KEY_CLASS_Object |
| 21 | +import java.util.Arrays; |
| 22 | +import java.util.Comparator; |
| 23 | +#endif |
| 24 | + |
| 25 | +import java.io.Serializable; |
| 26 | +import it.unimi.dsi.fastutil.HashCommon; |
| 27 | +import it.unimi.dsi.fastutil.PriorityQueue; |
| 28 | + |
| 29 | +import java.util.NoSuchElementException; |
| 30 | + |
| 31 | +/** A type-specific array-based FIFO queue, supporting also deque operations. |
| 32 | + * |
| 33 | + * <p>Instances of this class represent a FIFO queue using a backing |
| 34 | + * array in a circular way. |
| 35 | + * |
| 36 | + * <p>This class provides additional methods that implement a <em>deque</em> (double-ended queue). |
| 37 | + */ |
| 38 | + |
| 39 | +public class FIXED_ARRAY_FIFO_QUEUE KEY_GENERIC implements PRIORITY_QUEUE KEY_GENERIC, Serializable { |
| 40 | + private static final long serialVersionUID = 0L; |
| 41 | + |
| 42 | + /** The backing array. */ |
| 43 | + protected transient KEY_GENERIC_TYPE array[]; |
| 44 | + |
| 45 | + /** The current (cached) length of {@link #array}. */ |
| 46 | + protected transient int length; |
| 47 | + |
| 48 | + /** The start position in {@link #array}. It is always strictly smaller than {@link #length}.*/ |
| 49 | + protected transient int start; |
| 50 | + |
| 51 | + /** The end position in {@link #array}. It is always strictly smaller than {@link #length}. |
| 52 | + * Might be actually smaller than {@link #start} because {@link #array} is used cyclically. */ |
| 53 | + protected transient int end; |
| 54 | + |
| 55 | + /** Creates a new empty queue with given capacity. |
| 56 | + * |
| 57 | + * @implNote Because of inner limitations of the JVM, the initial |
| 58 | + * capacity cannot exceed {@link it.unimi.dsi.fastutil.Arrays#MAX_ARRAY_SIZE} − 1. |
| 59 | + * |
| 60 | + * @param capacity the initial capacity of this queue. |
| 61 | + */ |
| 62 | + SUPPRESS_WARNINGS_KEY_UNCHECKED |
| 63 | + public FIXED_ARRAY_FIFO_QUEUE(final int capacity) { |
| 64 | + if (capacity > it.unimi.dsi.fastutil.Arrays.MAX_ARRAY_SIZE - 1) throw new IllegalArgumentException("Initial capacity (" + capacity + ") exceeds " + (it.unimi.dsi.fastutil.Arrays.MAX_ARRAY_SIZE - 1)); |
| 65 | + if (capacity < 0) throw new IllegalArgumentException("Initial capacity (" + capacity + ") is negative"); |
| 66 | + // We never build a queue with a zero-sized backing array; moreover, to |
| 67 | + // avoid resizing at the given capacity we need one additional element. |
| 68 | + array = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[Math.max(1, capacity + 1)]; |
| 69 | + length = array.length; |
| 70 | + } |
| 71 | + |
| 72 | + /** {@inheritDoc} |
| 73 | + * @implSpec This implementation returns {@code null} (FIFO queues have no comparator). */ |
| 74 | + @Override |
| 75 | + public KEY_COMPARATOR KEY_SUPER_GENERIC comparator() { |
| 76 | + return null; |
| 77 | + } |
| 78 | + |
| 79 | + @Override |
| 80 | + public KEY_GENERIC_TYPE DEQUEUE() { |
| 81 | + if (start == end) throw new NoSuchElementException(); |
| 82 | + final KEY_GENERIC_TYPE t = array[start]; |
| 83 | +#if KEYS_REFERENCE |
| 84 | + array[start] = null; // Clean-up for the garbage collector. |
| 85 | +#endif |
| 86 | + if (++start == length) start = 0; |
| 87 | + return t; |
| 88 | + } |
| 89 | + |
| 90 | + @Override |
| 91 | + public KEY_GENERIC_TYPE DEQUEUE(KEY_GENERIC_TYPE x) { |
| 92 | + if (start == end) return x; |
| 93 | + final KEY_GENERIC_TYPE t = array[start]; |
| 94 | +#if KEYS_REFERENCE |
| 95 | + array[start] = null; // Clean-up for the garbage collector. |
| 96 | +#endif |
| 97 | + if (++start == length) start = 0; |
| 98 | + return t; |
| 99 | + } |
| 100 | + |
| 101 | + @Override |
| 102 | + public KEY_GENERIC_TYPE DEQUEUE_LAST() { |
| 103 | + if (start == end) throw new NoSuchElementException(); |
| 104 | + if (end == 0) end = length; |
| 105 | + final KEY_GENERIC_TYPE t = array[--end]; |
| 106 | +#if KEYS_REFERENCE |
| 107 | + array[end] = null; // Clean-up for the garbage collector. |
| 108 | +#endif |
| 109 | + return t; |
| 110 | + } |
| 111 | + |
| 112 | + @Override |
| 113 | + public KEY_GENERIC_TYPE DEQUEUE_LAST(KEY_GENERIC_TYPE x) { |
| 114 | + if (start == end) return x; |
| 115 | + if (end == 0) end = length; |
| 116 | + final KEY_GENERIC_TYPE t = array[--end]; |
| 117 | +#if KEYS_REFERENCE |
| 118 | + array[end] = null; // Clean-up for the garbage collector. |
| 119 | +#endif |
| 120 | + return t; |
| 121 | + } |
| 122 | + |
| 123 | + SUPPRESS_WARNINGS_KEY_UNCHECKED |
| 124 | + private final void resize(final int size, final int newLength) { |
| 125 | + final KEY_GENERIC_TYPE[] newArray = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[newLength]; |
| 126 | + if (start >= end) { |
| 127 | + if (size != 0) { |
| 128 | + System.arraycopy(array, start, newArray, 0, length - start); |
| 129 | + System.arraycopy(array, 0, newArray, length - start, end); |
| 130 | + } |
| 131 | + } |
| 132 | + else System.arraycopy(array, start, newArray, 0, end - start); |
| 133 | + start = 0; |
| 134 | + end = size; |
| 135 | + array = newArray; |
| 136 | + length = newLength; |
| 137 | + } |
| 138 | + |
| 139 | + @Override |
| 140 | + public boolean enqueue(KEY_GENERIC_TYPE x) { |
| 141 | + final int next = end++; |
| 142 | + if (end == start) return false; |
| 143 | + array[next] = x; |
| 144 | + if (end == length) end = 0; |
| 145 | + return true; |
| 146 | + } |
| 147 | + |
| 148 | + @Override |
| 149 | + public boolean enqueueFirst(KEY_GENERIC_TYPE x) { |
| 150 | + if (start == 0) start = length; |
| 151 | + final int next = --start; |
| 152 | + if (end == start) return false; |
| 153 | + array[next] = x; |
| 154 | + return true; |
| 155 | + } |
| 156 | + |
| 157 | + @Override |
| 158 | + public KEY_GENERIC_TYPE FIRST() { |
| 159 | + if (start == end) throw new NoSuchElementException(); |
| 160 | + return array[start]; |
| 161 | + } |
| 162 | + |
| 163 | + @Override |
| 164 | + public KEY_GENERIC_TYPE FIRST(KEY_GENERIC_TYPE x) { |
| 165 | + if (start == end) return x; |
| 166 | + return array[start]; |
| 167 | + } |
| 168 | + |
| 169 | + |
| 170 | + @Override |
| 171 | + public KEY_GENERIC_TYPE LAST() { |
| 172 | + if (start == end) throw new NoSuchElementException(); |
| 173 | + return array[(end == 0 ? length : end) - 1]; |
| 174 | + } |
| 175 | + |
| 176 | + @Override |
| 177 | + public KEY_GENERIC_TYPE LAST(KEY_GENERIC_TYPE x) { |
| 178 | + if (start == end) return x; |
| 179 | + return array[(end == 0 ? length : end) - 1]; |
| 180 | + } |
| 181 | + |
| 182 | + @Override |
| 183 | + public void clear() { |
| 184 | +#if KEYS_REFERENCE |
| 185 | + if (start <= end) Arrays.fill(array, start, end, null); |
| 186 | + else { |
| 187 | + Arrays.fill(array, start, length, null); |
| 188 | + Arrays.fill(array, 0, end, null); |
| 189 | + } |
| 190 | +#endif |
| 191 | + start = end = 0; |
| 192 | + } |
| 193 | + |
| 194 | + @Override |
| 195 | + public int size() { |
| 196 | + final int apparentLength = end - start; |
| 197 | + return apparentLength >= 0 ? apparentLength : length + apparentLength; |
| 198 | + } |
| 199 | + |
| 200 | + public int capacity() { |
| 201 | + return array.length - 1; |
| 202 | + } |
| 203 | + |
| 204 | + private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { |
| 205 | + s.defaultWriteObject(); |
| 206 | + int size = size(); |
| 207 | + s.writeInt(size); |
| 208 | + for(int i = start; size-- != 0;) { |
| 209 | + s.WRITE_KEY(array[i++]); |
| 210 | + if (i == length) i = 0; |
| 211 | + } |
| 212 | + } |
| 213 | + |
| 214 | + SUPPRESS_WARNINGS_KEY_UNCHECKED |
| 215 | + private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { |
| 216 | + s.defaultReadObject(); |
| 217 | + end = s.readInt(); |
| 218 | + array = KEY_GENERIC_ARRAY_CAST new KEY_TYPE[length = HashCommon.nextPowerOfTwo(end + 1)]; |
| 219 | + for(int i = 0; i < end; i++) array[i] = KEY_GENERIC_CAST s.READ_KEY(); |
| 220 | + } |
| 221 | +} |
0 commit comments