com.carrotsearch.hppc.IntArrayDeque Maven / Gradle / Ivy
The newest version!
package com.carrotsearch.hppc;
import java.util.*;
import com.carrotsearch.hppc.cursors.IntCursor;
import com.carrotsearch.hppc.predicates.IntPredicate;
import com.carrotsearch.hppc.procedures.IntProcedure;
import static com.carrotsearch.hppc.Containers.*;
/**
* An array-backed {@link IntDeque}.
*/
@com.carrotsearch.hppc.Generated(
date = "2018-05-21T12:24:04+0200",
value = "KTypeArrayDeque.java")
public class IntArrayDeque
extends AbstractIntCollection
implements IntDeque,
Preallocable,
Cloneable {
/**
* Internal array for storing elements of the deque.
*/
public
int []
buffer = IntArrayList.EMPTY_ARRAY;
/**
* The index of the element at the head of the deque or an arbitrary number
* equal to tail if the deque is empty.
*/
public int head;
/**
* The index at which the next element would be added to the tail of the
* deque.
*/
public int tail;
/**
* Buffer resizing strategy.
*/
protected final ArraySizingStrategy resizer;
/**
* New instance with sane defaults.
*/
public IntArrayDeque() {
this(DEFAULT_EXPECTED_ELEMENTS);
}
/**
* New instance with sane defaults.
*
* @param expectedElements
* The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public IntArrayDeque(int expectedElements) {
this(expectedElements, new BoundedProportionalArraySizingStrategy());
}
/**
* New instance with sane defaults.
*
* @param expectedElements
* The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*
* @param resizer
* Underlying buffer sizing strategy.
*/
public IntArrayDeque(int expectedElements, ArraySizingStrategy resizer) {
assert resizer != null;
this.resizer = resizer;
ensureCapacity(expectedElements);
}
/**
* Creates a new deque from elements of another container, appending elements at
* the end of the deque in the iteration order.
*/
public IntArrayDeque(IntContainer container) {
this(container.size());
addLast(container);
}
/**
* {@inheritDoc}
*/
@Override
public void addFirst(int e1) {
int h = oneLeft(head, buffer.length);
if (h == tail) {
ensureBufferSpace(1);
h = oneLeft(head, buffer.length);
}
buffer[head = h] = e1;
}
/**
* Vararg-signature method for adding elements at the front of this deque.
*
* This method is handy, but costly if used in tight loops (anonymous
* array passing)
*
* @param elements The elements to add.
*/
/* */
public final void addFirst(int... elements) {
ensureBufferSpace(elements.length);
for (int k : elements) {
addFirst(k);
}
}
/**
* Inserts all elements from the given container to the front of this deque.
*
* @param container The container to iterate over.
*
* @return Returns the number of elements actually added as a result of this
* call.
*/
public int addFirst(IntContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (IntCursor cursor : container) {
addFirst(cursor.value);
}
return size;
}
/**
* Inserts all elements from the given iterable to the front of this deque.
*
* @param iterable The iterable to iterate over.
*
* @return Returns the number of elements actually added as a result of this
* call.
*/
public int addFirst(Iterable extends IntCursor> iterable) {
int size = 0;
for (IntCursor cursor : iterable) {
addFirst(cursor.value);
size++;
}
return size;
}
/**
* {@inheritDoc}
*/
@Override
public void addLast(int e1) {
int t = oneRight(tail, buffer.length);
if (head == t) {
ensureBufferSpace(1);
t = oneRight(tail, buffer.length);
}
buffer[tail] = e1;
tail = t;
}
/**
* Vararg-signature method for adding elements at the end of this deque.
*
*
* This method is handy, but costly if used in tight loops (anonymous array
* passing)
*
*
* @param elements The elements to iterate over.
*/
/* */
public final void addLast(int... elements) {
ensureBufferSpace(1);
for (int k : elements) {
addLast(k);
}
}
/**
* Inserts all elements from the given container to the end of this deque.
*
* @param container The container to iterate over.
*
* @return Returns the number of elements actually added as a result of this
* call.
*/
public int addLast(IntContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (IntCursor cursor : container) {
addLast(cursor.value);
}
return size;
}
/**
* Inserts all elements from the given iterable to the end of this deque.
*
* @param iterable The iterable to iterate over.
*
* @return Returns the number of elements actually added as a result of this
* call.
*/
public int addLast(Iterable extends IntCursor> iterable) {
int size = 0;
for (IntCursor cursor : iterable) {
addLast(cursor.value);
size++;
}
return size;
}
/**
* {@inheritDoc}
*/
@Override
public int removeFirst() {
assert size() > 0 : "The deque is empty.";
final int result = buffer[head];
buffer[head] = 0;
head = oneRight(head, buffer.length);
return result;
}
/**
* {@inheritDoc}
*/
@Override
public int removeLast() {
assert size() > 0 : "The deque is empty.";
tail = oneLeft(tail, buffer.length);
final int result = buffer[tail];
buffer[tail] = 0;
return result;
}
/**
* {@inheritDoc}
*/
@Override
public int getFirst() {
assert size() > 0 : "The deque is empty.";
return buffer[head];
}
/**
* {@inheritDoc}
*/
@Override
public int getLast() {
assert size() > 0 : "The deque is empty.";
return buffer[oneLeft(tail, buffer.length)];
}
/**
* {@inheritDoc}
*/
@Override
public int removeFirst(int e1) {
final int index = bufferIndexOf(e1);
if (index >= 0)
removeAtBufferIndex(index);
return index;
}
/**
* Return the index of the first (counting from head) element equal to
* e1
. The index points to the {@link #buffer} array.
*
* @param e1
* The element to look for.
* @return Returns the index of the first element equal to e1
or
* -1
if not found.
*/
public int bufferIndexOf(int e1) {
final int last = tail;
final int bufLen = buffer.length;
for (int i = head; i != last; i = oneRight(i, bufLen)) {
if (((buffer[i]) == ( e1))) {
return i;
}
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public int removeLast(int e1) {
final int index = lastBufferIndexOf(e1);
if (index >= 0) {
removeAtBufferIndex(index);
}
return index;
}
/**
* Return the index of the last (counting from tail) element equal to
* e1
. The index points to the {@link #buffer} array.
*
* @param e1
* The element to look for.
* @return Returns the index of the first element equal to e1
or
* -1
if not found.
*/
public int lastBufferIndexOf(int e1) {
final int bufLen = buffer.length;
final int last = oneLeft(head, bufLen);
for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) {
if (((buffer[i]) == ( e1)))
return i;
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public int removeAll(int e1) {
int removed = 0;
final int last = tail;
final int bufLen = buffer.length;
int from, to;
for (from = to = head; from != last; from = oneRight(from, bufLen)) {
if (((buffer[from]) == ( e1))) {
buffer[from] = 0;
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0;
}
to = oneRight(to, bufLen);
}
tail = to;
return removed;
}
/**
* Removes the element at index
in the internal {#link
* {@link #buffer} array, returning its value.
*
* @param index
* Index of the element to remove. The index must be located between
* {@link #head} and {@link #tail} in modulo {@link #buffer}
* arithmetic.
*/
public void removeAtBufferIndex(int index) {
assert (head <= tail
? index >= head && index < tail
: index >= head || index < tail) : "Index out of range (head="
+ head + ", tail=" + tail + ", index=" + index + ").";
// Cache fields in locals (hopefully moved to registers).
final int [] buffer = this.buffer;
final int bufLen = buffer.length;
final int lastIndex = bufLen - 1;
final int head = this.head;
final int tail = this.tail;
final int leftChunk = Math.abs(index - head) % bufLen;
final int rightChunk = Math.abs(tail - index) % bufLen;
if (leftChunk < rightChunk) {
if (index >= head) {
System.arraycopy(buffer, head, buffer, head + 1, leftChunk);
} else {
System.arraycopy(buffer, 0, buffer, 1, index);
buffer[0] = buffer[lastIndex];
System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head);
}
buffer[head] = 0;
this.head = oneRight(head, bufLen);
} else {
if (index < tail) {
System.arraycopy(buffer, index + 1, buffer, index, rightChunk);
} else {
System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index);
buffer[lastIndex] = buffer[0];
System.arraycopy(buffer, 1, buffer, 0, tail);
}
buffer[tail] = 0;
this.tail = oneLeft(tail, bufLen);
}
}
/**
* {@inheritDoc}
*/
@Override
public boolean isEmpty() {
return size() == 0;
}
/**
* {@inheritDoc}
*/
@Override
public int size() {
if (head <= tail)
return tail - head;
else
return (tail - head + buffer.length);
}
/**
* {@inheritDoc}
*
*
* The internal array buffers are not released as a result of this call.
*
*
* @see #release()
*/
@Override
public void clear() {
if (head < tail) {
Arrays.fill(buffer, head, tail, 0);
} else {
Arrays.fill(buffer, 0, tail, 0);
Arrays.fill(buffer, head, buffer.length, 0);
}
this.head = tail = 0;
}
/**
* Release internal buffers of this deque and reallocate with the default
* buffer.
*/
public void release() {
this.head = tail = 0;
buffer = IntArrayList.EMPTY_ARRAY;
ensureBufferSpace(0);
}
/**
* Ensure this container can hold at least the given number of elements
* without resizing its buffers.
*
* @param expectedElements
* The total number of elements, inclusive.
*/
@Override
public void ensureCapacity(int expectedElements) {
ensureBufferSpace(expectedElements - size());
}
/**
* Ensures the internal buffer has enough free slots to store
* expectedAdditions
. Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(int expectedAdditions) {
final int bufferLen = buffer.length;
final int elementsCount = size();
if (elementsCount + expectedAdditions >= bufferLen) {
final int emptySlot = 1; // deque invariant: always an empty slot.
final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions);
assert newSize >= (elementsCount + expectedAdditions + emptySlot) : "Resizer failed to"
+ " return sensible new size: " + newSize + " <= " + (elementsCount + expectedAdditions);
try {
final int[] newBuffer = (new int [newSize]);
if (bufferLen > 0) {
toArray(newBuffer);
tail = elementsCount;
head = 0;
}
this.buffer = newBuffer;
} catch (OutOfMemoryError e) {
throw new BufferAllocationException(
"Not enough memory to allocate new buffers: %,d -> %,d",
e, bufferLen, newSize);
}
}
}
/**
* {@inheritDoc}
*/
@Override
public int [] toArray()
{
final int size = size();
return toArray((new int [size]));
}
/**
* Copies elements of this deque to an array. The content of the
* target
array is filled from index 0 (head of the queue) to
* index size() - 1
(tail of the queue).
*
* @param target
* The target array must be large enough to hold all elements.
* @return Returns the target argument for chaining.
*/
public int[] toArray(int[] target) {
assert target.length >= size() : "Target array must be >= " + size();
if (head < tail) {
// The contents is not wrapped around. Just copy.
System.arraycopy(buffer, head, target, 0, size());
} else if (head > tail) {
// The contents is split. Merge elements from the following indexes:
// [head...buffer.length - 1][0, tail - 1]
final int rightCount = buffer.length - head;
System.arraycopy(buffer, head, target, 0, rightCount);
System.arraycopy(buffer, 0, target, rightCount, tail);
}
return target;
}
/**
* Clone this object. The returned clone will reuse the same hash function and
* array resizing strategy.
*/
@Override
public IntArrayDeque clone() {
try {
/* */
IntArrayDeque cloned = (IntArrayDeque) super.clone();
cloned.buffer = buffer.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/**
* Move one index to the left, wrapping around buffer.
*/
protected static int oneLeft(int index, int modulus) {
if (index >= 1) {
return index - 1;
}
return modulus - 1;
}
/**
* Move one index to the right, wrapping around buffer.
*/
protected static int oneRight(int index, int modulus) {
if (index + 1 == modulus) {
return 0;
}
return index + 1;
}
/**
* An iterator implementation for {@link ObjectArrayDeque#iterator}.
*/
private final class ValueIterator extends AbstractIterator {
private final IntCursor cursor;
private int remaining;
public ValueIterator() {
cursor = new IntCursor();
cursor.index = oneLeft(head, buffer.length);
this.remaining = size();
}
@Override
protected IntCursor fetch() {
if (remaining == 0) {
return done();
}
remaining--;
cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)];
return cursor;
}
}
/**
* An iterator implementation for
* {@link ObjectArrayDeque#descendingIterator()}.
*/
private final class DescendingValueIterator extends AbstractIterator {
private final IntCursor cursor;
private int remaining;
public DescendingValueIterator() {
cursor = new IntCursor();
cursor.index = tail;
this.remaining = size();
}
@Override
protected IntCursor fetch() {
if (remaining == 0)
return done();
remaining--;
cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)];
return cursor;
}
}
/**
* Returns a cursor over the values of this deque (in head to tail order). The
* iterator is implemented as a cursor and it returns the same cursor
* instance on every call to {@link Iterator#next()} (to avoid boxing of
* primitive types). To read the current value (or index in the deque's
* buffer) use the cursor's public fields. An example is shown below.
*
*
* for (IntValueCursor c : intDeque) {
* System.out.println("buffer index=" + c.index + " value=" + c.value);
* }
*
*/
public Iterator iterator() {
return new ValueIterator();
}
/**
* Returns a cursor over the values of this deque (in tail to head order). The
* iterator is implemented as a cursor and it returns the same cursor
* instance on every call to {@link Iterator#next()} (to avoid boxing of
* primitive types). To read the current value (or index in the deque's
* buffer) use the cursor's public fields. An example is shown below.
*
*
* for (Iterator<IntCursor> i = intDeque.descendingIterator(); i.hasNext();) {
* final IntCursor c = i.next();
* System.out.println("buffer index=" + c.index + " value=" + c.value);
* }
*
*/
public Iterator descendingIterator() {
return new DescendingValueIterator();
}
/**
* {@inheritDoc}
*/
@Override
public T forEach(T procedure) {
forEach(procedure, head, tail);
return procedure;
}
/**
* Applies procedure
to a slice of the deque,
* fromIndex
, inclusive, to toIndex
, exclusive.
*/
private void forEach(IntProcedure procedure, int fromIndex, final int toIndex) {
final int[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
procedure.apply(buffer[i]);
}
}
/**
* {@inheritDoc}
*/
@Override
public T forEach(T predicate) {
int fromIndex = head;
int toIndex = tail;
final int[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if (!predicate.apply(buffer[i])) {
break;
}
}
return predicate;
}
/**
* Applies procedure
to all elements of this deque, tail to head.
*/
@Override
public T descendingForEach(T procedure) {
descendingForEach(procedure, head, tail);
return procedure;
}
/**
* Applies procedure
to a slice of the deque,
* toIndex
, exclusive, down to fromIndex
, inclusive.
*/
private void descendingForEach(IntProcedure procedure, int fromIndex, final int toIndex) {
if (fromIndex == toIndex)
return;
final int[] buffer = this.buffer;
int i = toIndex;
do {
i = oneLeft(i, buffer.length);
procedure.apply(buffer[i]);
} while (i != fromIndex);
}
/**
* {@inheritDoc}
*/
@Override
public T descendingForEach(T predicate) {
descendingForEach(predicate, head, tail);
return predicate;
}
/**
* Applies predicate
to a slice of the deque,
* toIndex
, exclusive, down to fromIndex
, inclusive
* or until the predicate returns false
.
*/
private void descendingForEach(IntPredicate predicate, int fromIndex, final int toIndex) {
if (fromIndex == toIndex)
return;
final int[] buffer = this.buffer;
int i = toIndex;
do {
i = oneLeft(i, buffer.length);
if (!predicate.apply(buffer[i])) {
break;
}
} while (i != fromIndex);
}
/**
* {@inheritDoc}
*/
@Override
public int removeAll(IntPredicate predicate) {
final int[] buffer = this.buffer;
final int last = tail;
final int bufLen = buffer.length;
int removed = 0;
int from, to;
from = to = head;
try {
for (from = to = head; from != last; from = oneRight(from, bufLen)) {
if (predicate.apply(buffer[from])) {
buffer[from] = 0;
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0;
}
to = oneRight(to, bufLen);
}
} finally {
// Keep the deque in consistent state even if the predicate throws an exception.
for (; from != last; from = oneRight(from, bufLen)) {
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0;
}
to = oneRight(to, bufLen);
}
tail = to;
}
return removed;
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(int e) {
int fromIndex = head;
int toIndex = tail;
final int[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if (((buffer[i]) == ( e))) {
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
int h = 1;
int fromIndex = head;
int toIndex = tail;
final int[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
h = 31 * h + BitMixer.mix(this.buffer[i]);
}
return h;
}
/**
* Returns true
only if the other object is an instance of
* the same class and with the same elements.
*/
@Override
public boolean equals(Object obj)
{
return obj != null &&
getClass() == obj.getClass() &&
equalElements(getClass().cast(obj));
}
/**
* Compare order-aligned elements against another {@link IntDeque}.
*/
protected boolean equalElements(IntArrayDeque other) {
int max = size();
if (other.size() != max) {
return false;
}
Iterator i1 = this.iterator();
Iterator extends IntCursor> i2 = other.iterator();
while (i1.hasNext() && i2.hasNext()) {
if (!((i2.next().value) == ( i1.next().value))) {
return false;
}
}
return !i1.hasNext() &&
!i2.hasNext();
}
/**
* Create a new deque by pushing a variable number of arguments to the end of it.
*/
/* */
public static IntArrayDeque from(int... elements)
{
final IntArrayDeque coll = new IntArrayDeque(elements.length);
coll.addLast(elements);
return coll;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy