com.carrotsearch.hppc.DoubleArrayDeque Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hppc Show documentation
Show all versions of hppc Show documentation
High Performance Primitive Collections: data structures (maps, sets, lists, stacks, queues) generated for combinations of object and primitive types to conserve JVM memory and speed up execution.
package com.carrotsearch.hppc;
import java.util.*;
import com.carrotsearch.hppc.cursors.DoubleCursor;
import com.carrotsearch.hppc.predicates.DoublePredicate;
import com.carrotsearch.hppc.procedures.DoubleProcedure;
import static com.carrotsearch.hppc.Containers.*;
/**
* An array-backed {@link DoubleDeque}.
*/
@com.carrotsearch.hppc.Generated(
date = "2018-05-21T12:24:05+0200",
value = "KTypeArrayDeque.java")
public class DoubleArrayDeque
extends AbstractDoubleCollection
implements DoubleDeque,
Preallocable,
Cloneable {
/**
* Internal array for storing elements of the deque.
*/
public
double []
buffer = DoubleArrayList.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 DoubleArrayDeque() {
this(DEFAULT_EXPECTED_ELEMENTS);
}
/**
* New instance with sane defaults.
*
* @param expectedElements
* The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public DoubleArrayDeque(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 DoubleArrayDeque(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 DoubleArrayDeque(DoubleContainer container) {
this(container.size());
addLast(container);
}
/**
* {@inheritDoc}
*/
@Override
public void addFirst(double 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(double... elements) {
ensureBufferSpace(elements.length);
for (double 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(DoubleContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (DoubleCursor 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 DoubleCursor> iterable) {
int size = 0;
for (DoubleCursor cursor : iterable) {
addFirst(cursor.value);
size++;
}
return size;
}
/**
* {@inheritDoc}
*/
@Override
public void addLast(double 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(double... elements) {
ensureBufferSpace(1);
for (double 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(DoubleContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (DoubleCursor 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 DoubleCursor> iterable) {
int size = 0;
for (DoubleCursor cursor : iterable) {
addLast(cursor.value);
size++;
}
return size;
}
/**
* {@inheritDoc}
*/
@Override
public double removeFirst() {
assert size() > 0 : "The deque is empty.";
final double result = buffer[head];
buffer[head] = 0d;
head = oneRight(head, buffer.length);
return result;
}
/**
* {@inheritDoc}
*/
@Override
public double removeLast() {
assert size() > 0 : "The deque is empty.";
tail = oneLeft(tail, buffer.length);
final double result = buffer[tail];
buffer[tail] = 0d;
return result;
}
/**
* {@inheritDoc}
*/
@Override
public double getFirst() {
assert size() > 0 : "The deque is empty.";
return buffer[head];
}
/**
* {@inheritDoc}
*/
@Override
public double getLast() {
assert size() > 0 : "The deque is empty.";
return buffer[oneLeft(tail, buffer.length)];
}
/**
* {@inheritDoc}
*/
@Override
public int removeFirst(double 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(double e1) {
final int last = tail;
final int bufLen = buffer.length;
for (int i = head; i != last; i = oneRight(i, bufLen)) {
if ((Double.doubleToLongBits(buffer[i]) == Double.doubleToLongBits( e1))) {
return i;
}
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public int removeLast(double 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(double 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 ((Double.doubleToLongBits(buffer[i]) == Double.doubleToLongBits( e1)))
return i;
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public int removeAll(double 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 ((Double.doubleToLongBits(buffer[from]) == Double.doubleToLongBits( e1))) {
buffer[from] = 0d;
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0d;
}
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 double [] 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] = 0d;
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] = 0d;
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, 0d);
} else {
Arrays.fill(buffer, 0, tail, 0d);
Arrays.fill(buffer, head, buffer.length, 0d);
}
this.head = tail = 0;
}
/**
* Release internal buffers of this deque and reallocate with the default
* buffer.
*/
public void release() {
this.head = tail = 0;
buffer = DoubleArrayList.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 double[] newBuffer = (new double [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 double [] toArray()
{
final int size = size();
return toArray((new double [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 double[] toArray(double[] 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 DoubleArrayDeque clone() {
try {
/* */
DoubleArrayDeque cloned = (DoubleArrayDeque) 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 DoubleCursor cursor;
private int remaining;
public ValueIterator() {
cursor = new DoubleCursor();
cursor.index = oneLeft(head, buffer.length);
this.remaining = size();
}
@Override
protected DoubleCursor 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 DoubleCursor cursor;
private int remaining;
public DescendingValueIterator() {
cursor = new DoubleCursor();
cursor.index = tail;
this.remaining = size();
}
@Override
protected DoubleCursor 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(DoubleProcedure procedure, int fromIndex, final int toIndex) {
final double[] 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 double[] 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(DoubleProcedure procedure, int fromIndex, final int toIndex) {
if (fromIndex == toIndex)
return;
final double[] 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(DoublePredicate predicate, int fromIndex, final int toIndex) {
if (fromIndex == toIndex)
return;
final double[] 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(DoublePredicate predicate) {
final double[] 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] = 0d;
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0d;
}
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] = 0d;
}
to = oneRight(to, bufLen);
}
tail = to;
}
return removed;
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(double e) {
int fromIndex = head;
int toIndex = tail;
final double[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if ((Double.doubleToLongBits(buffer[i]) == Double.doubleToLongBits( e))) {
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
int h = 1;
int fromIndex = head;
int toIndex = tail;
final double[] 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 DoubleDeque}.
*/
protected boolean equalElements(DoubleArrayDeque other) {
int max = size();
if (other.size() != max) {
return false;
}
Iterator i1 = this.iterator();
Iterator extends DoubleCursor> i2 = other.iterator();
while (i1.hasNext() && i2.hasNext()) {
if (!(Double.doubleToLongBits(i2.next().value) == Double.doubleToLongBits( 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 DoubleArrayDeque from(double... elements)
{
final DoubleArrayDeque coll = new DoubleArrayDeque(elements.length);
coll.addLast(elements);
return coll;
}
}