| /* | |
| * Copyright (C) 2019 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| package android.util; | |
| import com.android.internal.util.ArrayUtils; | |
| import com.android.internal.util.GrowingArrayUtils; | |
| import libcore.util.EmptyArray; | |
| import java.util.NoSuchElementException; | |
| /** | |
| * A lightweight implementation for a queue with long values. | |
| * Additionally supports getting an element with a specified position from the head of the queue. | |
| * The queue grows in size if needed to accommodate new elements. | |
| * | |
| * @hide | |
| */ | |
| public class LongArrayQueue { | |
| private long[] mValues; | |
| private int mSize; | |
| private int mHead; | |
| private int mTail; | |
| /** | |
| * Initializes a queue with the given starting capacity. | |
| * | |
| * @param initialCapacity the capacity. | |
| */ | |
| public LongArrayQueue(int initialCapacity) { | |
| if (initialCapacity == 0) { | |
| mValues = EmptyArray.LONG; | |
| } else { | |
| mValues = ArrayUtils.newUnpaddedLongArray(initialCapacity); | |
| } | |
| mSize = 0; | |
| mHead = mTail = 0; | |
| } | |
| /** | |
| * Initializes a queue with default starting capacity. | |
| */ | |
| public LongArrayQueue() { | |
| this(16); | |
| } | |
| private void grow() { | |
| if (mSize < mValues.length) { | |
| throw new IllegalStateException("Queue not full yet!"); | |
| } | |
| final int newSize = GrowingArrayUtils.growSize(mSize); | |
| final long[] newArray = ArrayUtils.newUnpaddedLongArray(newSize); | |
| final int r = mValues.length - mHead; // Number of elements on and to the right of head. | |
| System.arraycopy(mValues, mHead, newArray, 0, r); | |
| System.arraycopy(mValues, 0, newArray, r, mHead); | |
| mValues = newArray; | |
| mHead = 0; | |
| mTail = mSize; | |
| } | |
| /** | |
| * Returns the number of elements in the queue. | |
| */ | |
| public int size() { | |
| return mSize; | |
| } | |
| /** | |
| * Removes all elements from this queue. | |
| */ | |
| public void clear() { | |
| mSize = 0; | |
| mHead = mTail = 0; | |
| } | |
| /** | |
| * Adds a value to the tail of the queue. | |
| * | |
| * @param value the value to be added. | |
| */ | |
| public void addLast(long value) { | |
| if (mSize == mValues.length) { | |
| grow(); | |
| } | |
| mValues[mTail] = value; | |
| mTail = (mTail + 1) % mValues.length; | |
| mSize++; | |
| } | |
| /** | |
| * Removes an element from the head of the queue. | |
| * | |
| * @return the element at the head of the queue. | |
| * @throws NoSuchElementException if the queue is empty. | |
| */ | |
| public long removeFirst() { | |
| if (mSize == 0) { | |
| throw new NoSuchElementException("Queue is empty!"); | |
| } | |
| final long ret = mValues[mHead]; | |
| mHead = (mHead + 1) % mValues.length; | |
| mSize--; | |
| return ret; | |
| } | |
| /** | |
| * Returns the element at the given position from the head of the queue, where 0 represents the | |
| * head of the queue. | |
| * | |
| * @param position the position from the head of the queue. | |
| * @return the element found at the given position. | |
| * @throws IndexOutOfBoundsException if {@code position} < {@code 0} or | |
| * {@code position} >= {@link #size()} | |
| */ | |
| public long get(int position) { | |
| if (position < 0 || position >= mSize) { | |
| throw new IndexOutOfBoundsException("Index " + position | |
| + " not valid for a queue of size " + mSize); | |
| } | |
| final int index = (mHead + position) % mValues.length; | |
| return mValues[index]; | |
| } | |
| /** | |
| * Returns the element at the head of the queue, without removing it. | |
| * | |
| * @return the element at the head of the queue. | |
| * @throws NoSuchElementException if the queue is empty | |
| */ | |
| public long peekFirst() { | |
| if (mSize == 0) { | |
| throw new NoSuchElementException("Queue is empty!"); | |
| } | |
| return mValues[mHead]; | |
| } | |
| /** | |
| * Returns the element at the tail of the queue. | |
| * | |
| * @return the element at the tail of the queue. | |
| * @throws NoSuchElementException if the queue is empty. | |
| */ | |
| public long peekLast() { | |
| if (mSize == 0) { | |
| throw new NoSuchElementException("Queue is empty!"); | |
| } | |
| final int index = (mTail == 0) ? mValues.length - 1 : mTail - 1; | |
| return mValues[index]; | |
| } | |
| /** | |
| * {@inheritDoc} | |
| */ | |
| @Override | |
| public String toString() { | |
| if (mSize <= 0) { | |
| return "{}"; | |
| } | |
| final StringBuilder buffer = new StringBuilder(mSize * 64); | |
| buffer.append('{'); | |
| buffer.append(get(0)); | |
| for (int i = 1; i < mSize; i++) { | |
| buffer.append(", "); | |
| buffer.append(get(i)); | |
| } | |
| buffer.append('}'); | |
| return buffer.toString(); | |
| } | |
| } |