
com.carrotsearch.hppcrt.lists.ObjectArrayDeque Maven / Gradle / Ivy
package com.carrotsearch.hppcrt.lists;
import java.util.*;
import com.carrotsearch.hppcrt.*;
import com.carrotsearch.hppcrt.cursors.*;
import com.carrotsearch.hppcrt.hash.BitMixer;
import com.carrotsearch.hppcrt.lists.ObjectLinkedList.ValueIterator;
import com.carrotsearch.hppcrt.predicates.*;
import com.carrotsearch.hppcrt.procedures.*;
import com.carrotsearch.hppcrt.sorting.*;
import com.carrotsearch.hppcrt.strategies.*;
/**
* An array-backed deque (double-ended queue) of Objects. A single array is used to store and
* manipulate all elements. Reallocations are governed by a {@link ArraySizingStrategy}
* and may be expensive if they move around really large chunks of memory.
* This dequeue is also a ObjectIndexedContainer, where index 0 is the head of the queue, and
* size() - 1 index is the last element.
* A brief comparison of the API against the Java Collections framework:
*
* Java Collections ArrayDeque and HPPC {@link ObjectArrayDeque}, related methods.
*
*
* {@linkplain ArrayDeque java.util.ArrayDeque}
* {@link ObjectArrayDeque}
*
*
*
* addFirst addFirst
* addLast addLast
* removeFirst removeLast
* getFirst getFirst
* getLast getLast
* removeFirstOccurrence,
* removeLastOccurrence
* removeFirstOccurrence,
* removeLastOccurrence
*
* size size
* Object[] toArray() Object[] toArray()
* iterator {@linkplain #iterator cursor over values}
* other methods inherited from Stack, Queue not implemented
*
*
*/
@javax.annotation.Generated(
date = "2016-01-30T23:09:30+0100",
value = "KTypeArrayDeque.java")
public class ObjectArrayDeque
extends AbstractObjectCollection implements ObjectDeque, ObjectIndexedContainer, Cloneable
{
/**
* Internal array for storing elements.
*
*
* Direct deque iteration from head to tail: iterate buffer[i % buffer.length] for i in [this.head; this.head + size()[
*
*/
public
Object[]
buffer;
/**
* 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. (this is a valid index in buffer !)
*/
public int tail;
/**
* Buffer resizing strategy.
*/
protected final ArraySizingStrategy resizer;
/**
* internal pool of DescendingValueIterator (must be created in constructor)
*/
protected final IteratorPool, DescendingValueIterator> descendingValueIteratorPool;
/**
* internal pool of ValueIterator (must be created in constructor)
*/
protected final IteratorPool, ValueIterator> valueIteratorPool;
/**
* Default constructor.
*/
public ObjectArrayDeque() {
this(Containers.DEFAULT_EXPECTED_ELEMENTS);
}
/**
* Create with default sizing strategy and the given initial capacity.
*
* @see BoundedProportionalArraySizingStrategy
*/
public ObjectArrayDeque(final int initialCapacity) {
this(initialCapacity, new BoundedProportionalArraySizingStrategy());
}
/**
* Create with a custom buffer resizing strategy.
*/
public ObjectArrayDeque(final int initialCapacity, final ArraySizingStrategy resizer) {
assert resizer != null;
this.resizer = resizer;
//Allocate to capacity
ensureBufferSpace(Math.max(Containers.DEFAULT_EXPECTED_ELEMENTS, initialCapacity));
this.valueIteratorPool = new IteratorPool, ValueIterator>(new ObjectFactory() {
@Override
public ValueIterator create() {
return new ValueIterator();
}
@Override
public void initialize(final ValueIterator obj) {
obj.cursor.index = (((ObjectArrayDeque.this.head) >= 1) ? (ObjectArrayDeque.this.head) - 1 : (ObjectArrayDeque.this.buffer.length) - 1);
obj.remaining = ObjectArrayDeque.this.size();
}
@Override
public void reset(final ValueIterator obj) {
obj.cursor.value = null;
}
});
this.descendingValueIteratorPool = new IteratorPool, DescendingValueIterator>(
new ObjectFactory() {
@Override
public DescendingValueIterator create() {
return new DescendingValueIterator();
}
@Override
public void initialize(final DescendingValueIterator obj) {
obj.cursor.index = ObjectArrayDeque.this.tail;
obj.remaining = ObjectArrayDeque.this.size();
}
@Override
public void reset(final DescendingValueIterator obj) {
obj.cursor.value = null;
}
});
}
/**
* Creates a new deque from elements of another container, appending them
* at the end of this deque.
*/
public ObjectArrayDeque(final ObjectContainer extends KType> container) {
this(container.size());
addLast(container);
}
/**
* {@inheritDoc}
*/
@Override
public void addFirst(final KType e1) {
int h = (((this.head) >= 1) ? (this.head) - 1 : (this.buffer.length) - 1);
if (h == this.tail) {
ensureBufferSpace(1);
h = (((this.head) >= 1) ? (this.head) - 1 : (this.buffer.length) - 1);
}
this.buffer[this.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)
*/
public void addFirst(final KType... elements) {
ensureBufferSpace(elements.length);
// For now, naive loop.
for (int i = 0; i < elements.length; i++) {
addFirst(elements[i]);
}
}
/**
* Inserts all elements from the given container to the front of this deque.
*
* @return Returns the number of elements actually added as a result of this
* call.
*/
public int addFirst(final ObjectContainer extends KType> container) {
return addFirst((Iterable extends ObjectCursor extends KType>>) container);
}
/**
* Inserts all elements from the given iterable to the front of this deque.
*
* @return Returns the number of elements actually added as a result of this call.
*/
public int addFirst(final Iterable extends ObjectCursor extends KType>> iterable) {
int size = 0;
for (final ObjectCursor extends KType> cursor : iterable) {
addFirst(cursor.value);
size++;
}
return size;
}
/**
* {@inheritDoc}
*/
@Override
public void addLast(final KType e1) {
int t = (((this.tail) + 1 == (this.buffer.length)) ? 0 : (this.tail) + 1);
if (this.head == t) {
ensureBufferSpace(1);
t = (((this.tail) + 1 == (this.buffer.length)) ? 0 : (this.tail) + 1);
}
this.buffer[this.tail] = e1;
this.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)
*/
public void addLast(final KType... elements) {
ensureBufferSpace(elements.length);
// For now, naive loop.
for (int i = 0; i < elements.length; i++) {
addLast(elements[i]);
}
}
/**
* Inserts all elements from the given container to the end of this deque.
*
* @return Returns the number of elements actually added as a result of this
* call.
*/
public int addLast(final ObjectContainer extends KType> container) {
return addLast((Iterable extends ObjectCursor extends KType>>) container);
}
/**
* Inserts all elements from the given iterable to the end of this deque.
*
* @return Returns the number of elements actually added as a result of this call.
*/
public int addLast(final Iterable extends ObjectCursor extends KType>> iterable) {
int size = 0;
for (final ObjectCursor extends KType> cursor : iterable) {
addLast(cursor.value);
size++;
}
return size;
}
/**
* {@inheritDoc}
*/
@Override
public KType removeFirst() {
assert size() > 0 : "The deque is empty.";
final KType result = ((KType)(this.buffer[this.head]));
this.buffer[this.head] = (null);
this.head = (((this.head) + 1 == (this.buffer.length)) ? 0 : (this.head) + 1);
return result;
}
/**
* {@inheritDoc}
*/
@Override
public KType removeLast() {
assert size() > 0 : "The deque is empty.";
this.tail = (((this.tail) >= 1) ? (this.tail) - 1 : (this.buffer.length) - 1);
final KType result = ((KType)(this.buffer[this.tail]));
this.buffer[this.tail] = (null);
return result;
}
/**
* {@inheritDoc}
*/
@Override
public KType getFirst() {
assert size() > 0 : "The deque is empty.";
return ((KType)(this.buffer[this.head]));
}
/**
* {@inheritDoc}
*/
@Override
public KType getLast() {
assert size() > 0 : "The deque is empty.";
return ((KType)(this.buffer[(((this.tail) >= 1) ? (this.tail) - 1 : (this.buffer.length) - 1)]));
}
/**
* {@inheritDoc}
* The returned position is relative to the head,
* i.e w.r.t the {@link ObjectIndexedContainer}, index 0 is the head of the queue, size() - 1 is the last element position.
*/
@Override
public int removeFirst(final KType e1) {
int pos = -1;
final int index = bufferIndexOf(e1);
if (index >= 0) {
pos = bufferIndexToPosition(index);
removeBufferIndicesRange(index, (((index) + 1 == (this.buffer.length)) ? 0 : (index) + 1));
}
return pos;
}
/**
* Return the index of the first element equal to
* e1
. The index points to the {@link #buffer} array.
*
* @param e1 The element to look for.
* @return Returns the index in {@link #buffer} of the first element equal to e1
* or -1
if not found.
*/
public int bufferIndexOf(final KType e1) {
final int last = this.tail;
final int bufLen = this.buffer.length;
final KType[] buffer = ((KType[])(this.buffer));
for (int i = this.head; i != last; i = (((i) + 1 == (bufLen)) ? 0 : (i) + 1)) {
if (((e1) == null ? (buffer[i]) == null : (e1).equals((buffer[i])))) {
return i;
}
}
return -1;
}
/**
* {@inheritDoc}
* The returned position is relative to the head,
* i.e w.r.t the {@link ObjectIndexedContainer}, index 0 is the head of the queue, size() - 1 is the last element position.
*/
@Override
public int removeLast(final KType e1) {
int pos = -1;
final int index = lastBufferIndexOf(e1);
if (index >= 0) {
pos = bufferIndexToPosition(index);
removeBufferIndicesRange(index, (((index) + 1 == (this.buffer.length)) ? 0 : (index) + 1));
}
return pos;
}
/**
* Return the index of the last element equal to
* e1
. The index points to the {@link #buffer} array.
*
* @param e1 The element to look for.
* @return Returns the index in {@link #buffer} of the first element equal to e1
* or -1
if not found.
*/
public int lastBufferIndexOf(final KType e1) {
final int bufLen = this.buffer.length;
final int last = (((this.head) >= 1) ? (this.head) - 1 : (bufLen) - 1);
final KType[] buffer = ((KType[])(this.buffer));
for (int i = (((this.tail) >= 1) ? (this.tail) - 1 : (bufLen) - 1); i != last; i = (((i) >= 1) ? (i) - 1 : (bufLen) - 1)) {
if (((e1) == null ? (buffer[i]) == null : (e1).equals((buffer[i])))) {
return i;
}
}
return -1;
}
/**
* ObjectIndexedContainer methods
*/
/**
* {@inheritDoc}
* The returned position is relative to the head,
* i.e w.r.t the {@link ObjectIndexedContainer}, index 0 is the head of the queue, size() - 1 is the last element position.
*/
@Override
public int indexOf(final KType e1) {
return bufferIndexToPosition(bufferIndexOf(e1));
}
/**
* {@inheritDoc}
* The returned position is relative to the head,
* i.e w.r.t the {@link ObjectIndexedContainer}, index 0 is the head of the queue, size() - 1 is the last element position.
*/
@Override
public int lastIndexOf(final KType e1) {
return bufferIndexToPosition(lastBufferIndexOf(e1));
}
/**
* {@inheritDoc}
*/
@Override
public int removeAll(final KType e1) {
int removed = 0;
final int last = this.tail;
final int bufLen = this.buffer.length;
final KType[] buffer = ((KType[])(this.buffer));
int from, to;
for (from = to = this.head; from != last; from = (((from) + 1 == (bufLen)) ? 0 : (from) + 1)) {
if (((e1) == null ? (buffer[from]) == null : (e1).equals((buffer[from])))) {
buffer[from] = (null);
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = (null);
}
to = (((to) + 1 == (bufLen)) ? 0 : (to) + 1);
}
this.tail = to;
return removed;
}
/**
* {@inheritDoc}
*/
@Override
public int size() {
if (this.head <= this.tail) {
return this.tail - this.head;
}
return (this.tail - this.head + this.buffer.length);
}
/**
* {@inheritDoc}
*/
@Override
public int capacity() {
//because there is always an empty slot in the buffer
return this.buffer.length - 1;
}
/**
* {@inheritDoc}
* The internal array buffers are not released as a result of this call.
*/
@Override
public void clear() {
if (this.head < this.tail) {
ObjectArrays.blankArray(this.buffer, this.head, this.tail);
} else {
ObjectArrays.blankArray(this.buffer, 0, this.tail);
ObjectArrays.blankArray(this.buffer, this.head, this.buffer.length);
}
this.head = this.tail = 0;
}
/**
* Compact the internal buffer to prepare sorting
* Beware, this changes the relative order of elements, so is only useful to
* not-stable sorts while sorting the WHOLE buffer !
*/
private void compactBeforeSorting() {
if (this.head > this.tail) {
final int size = size();
final int hole = this.head - this.tail;
//pack the separated chunk to the beginning of the buffer
System.arraycopy(this.buffer, this.head, this.buffer, this.tail, this.buffer.length - this.head);
//reset of the positions
this.head = 0;
this.tail = size;
//for GC sake, reset hole elements now at the end of buffer
ObjectArrays.blankArray(this.buffer, this.tail, this.tail + hole);
}
}
/**
* Release internal buffers of this deque and reallocate the smallest buffer possible.
*/
public void release() {
this.head = this.tail = 0;
this.buffer = ((KType[])new Object[(Containers.DEFAULT_EXPECTED_ELEMENTS)]);
}
/**
* Ensures the internal buffer has enough free slots to store
* expectedAdditions
. Increases internal buffer size if needed.
*/
@SuppressWarnings("boxing")
protected void ensureBufferSpace(final int expectedAdditions) {
final int bufferLen = (this.buffer == null ? 0 : this.buffer.length);
final int elementsCount = (this.buffer == null ? 0 : size());
// +1 because there is always one empty slot in a deque.
if (elementsCount + 1 > bufferLen - expectedAdditions) {
int newSize = this.resizer.grow(bufferLen, elementsCount, expectedAdditions);
if (this.buffer == null) {
//first allocation, reserve an additional slot (tail is always a valid index in buffer)
newSize++;
}
try {
final KType[] newBuffer = ((KType[])new Object[(newSize)]);
if (bufferLen > 0) {
toArray(newBuffer);
this.tail = elementsCount;
this.head = 0;
}
this.buffer = newBuffer;
} catch (final OutOfMemoryError e) {
throw new BufferAllocationException(
"Not enough memory to allocate buffers to grow from %d -> %d elements",
e,
bufferLen,
newSize);
}
}
}
/**
* 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.
*/
@Override
public KType[] toArray(final KType[] target) {
assert target.length >= size() : "Target array must be >= " + size();
if (this.head < this.tail) {
// The contents is not wrapped around. Just copy.
System.arraycopy(this.buffer, this.head, target, 0, size());
} else if (this.head > this.tail) {
// The contents is split. Merge elements from the following indexes:
// [head...buffer.length - 1][0, tail - 1]
final int rightCount = this.buffer.length - this.head;
System.arraycopy(this.buffer, this.head, target, 0, rightCount);
System.arraycopy(this.buffer, 0, target, rightCount, this.tail);
}
return target;
}
/**
* Clone this object. The returned clone will reuse the same array resizing strategy.
*/
@Override
public ObjectArrayDeque clone() {
//placeholder container
final ObjectArrayDeque cloned = new ObjectArrayDeque(Containers.DEFAULT_EXPECTED_ELEMENTS, this.resizer);
//copy the full buffer
cloned.buffer = this.buffer.clone();
cloned.head = this.head;
cloned.tail = this.tail;
return cloned;
}
/**
* An iterator implementation for {@link ObjectArrayDeque#iterator}.
*/
public final class ValueIterator extends AbstractIterator>
{
public final ObjectCursor cursor;
private int remaining;
public ValueIterator() {
this.cursor = new ObjectCursor();
this.cursor.index = (((ObjectArrayDeque.this.head) >= 1) ? (ObjectArrayDeque.this.head) - 1 : (ObjectArrayDeque.this.buffer.length) - 1);
this.remaining = ObjectArrayDeque.this.size();
}
@Override
protected ObjectCursor fetch() {
if (this.remaining == 0) {
return done();
}
this.remaining--;
this.cursor.value = ((KType)(ObjectArrayDeque.this.buffer[this.cursor.index = (((this.cursor.index) + 1 == (ObjectArrayDeque.this.buffer.length)) ? 0 : (this.cursor.index) + 1)]));
return this.cursor;
}
}
/**
* An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}.
*/
public final class DescendingValueIterator extends AbstractIterator>
{
public final ObjectCursor cursor;
private int remaining;
public DescendingValueIterator() {
this.cursor = new ObjectCursor();
this.cursor.index = ObjectArrayDeque.this.tail;
this.remaining = ObjectArrayDeque.this.size();
}
@Override
protected ObjectCursor fetch() {
if (this.remaining == 0) {
return done();
}
this.remaining--;
this.cursor.value = ((KType)(ObjectArrayDeque.this.buffer[this.cursor.index = (((this.cursor.index) >= 1) ? (this.cursor.index) - 1 : (ObjectArrayDeque.this.buffer.length) - 1)]));
return this.cursor;
}
}
/**
* Returns an iterator 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 {@link #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);
* }
*
*/
@Override
public ValueIterator iterator() {
//return new ValueIterator();
return this.valueIteratorPool.borrow();
}
/**
* Returns an iterator 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 {@link #buffer}, use the cursor's public
* fields. An example is shown below.
*
*
* for (Iterator i = intDeque.descendingIterator(); i.hasNext(); )
* {
* final IntCursor c = i.next();
* System.out.println("buffer index="
* + c.index + " value=" + c.value);
* }
*
*
*/
@Override
public DescendingValueIterator descendingIterator() {
//return new DescendingValueIterator();
return this.descendingValueIteratorPool.borrow();
}
/**
* {@inheritDoc}
*/
@Override
public > T forEach(final T procedure) {
internalForEach(procedure, this.head, this.tail);
return procedure;
}
/**
* {@inheritDoc}
*/
@Override
public > T forEach(final T procedure, final int fromIndex, final int toIndex) {
checkRangeBounds(fromIndex, toIndex);
if (fromIndex == toIndex) {
return procedure; //nothing to do
}
final int bufferPositionStart = indexToBufferPosition(fromIndex);
final int endBufferPosInclusive = indexToBufferPosition(toIndex - 1); //must be a valid index
internalForEach(procedure, bufferPositionStart, (((endBufferPosInclusive) + 1 == (this.buffer.length)) ? 0 : (endBufferPosInclusive) + 1));
return procedure;
}
/**
* Applies procedure
to a slice of the deque,
* fromIndexBuffer
, inclusive, to toIndexBuffer
,
* exclusive, indices are in {@link #buffer} array.
*/
private void internalForEach(final ObjectProcedure super KType> procedure, final int fromIndexBuffer, final int toIndexBuffer) {
final KType[] buffer = ((KType[])(this.buffer));
for (int i = fromIndexBuffer; i != toIndexBuffer; i = (((i) + 1 == (buffer.length)) ? 0 : (i) + 1)) {
procedure.apply(buffer[i]);
}
}
/**
* {@inheritDoc}
*/
@Override
public > T forEach(final T predicate) {
internalForEach(predicate, this.head, this.tail);
return predicate;
}
/**
* {@inheritDoc}
*/
@Override
public > T forEach(final T predicate, final int fromIndex, final int toIndex) {
checkRangeBounds(fromIndex, toIndex);
if (fromIndex == toIndex) {
return predicate; //nothing to do
}
final int bufferPositionStart = indexToBufferPosition(fromIndex);
final int endBufferPosInclusive = indexToBufferPosition(toIndex - 1); //must be a valid index
internalForEach(predicate, bufferPositionStart, (((endBufferPosInclusive) + 1 == (this.buffer.length)) ? 0 : (endBufferPosInclusive) + 1));
return predicate;
}
/**
* Applies predicate
to a slice of the deque,
* fromIndexBuffer
, inclusive, to toIndexBuffer
,
* exclusive, indices are in {@link #buffer} array.
*/
private void internalForEach(final ObjectPredicate super KType> predicate, final int fromIndexBuffer, final int toIndexBuffer) {
final KType[] buffer = ((KType[])(this.buffer));
for (int i = fromIndexBuffer; i != toIndexBuffer; i = (((i) + 1 == (buffer.length)) ? 0 : (i) + 1)) {
if (!predicate.apply(buffer[i])) {
break;
}
}
}
/**
* Applies procedure
to all elements of this deque, tail to head.
*/
@Override
public > T descendingForEach(final T procedure) {
descendingForEach(procedure, this.head, this.tail);
return procedure;
}
/**
* Applies procedure
to a slice of the deque,
* toIndex
, exclusive, down to fromIndex
, inclusive.
*/
private void descendingForEach(final ObjectProcedure super KType> procedure, final int fromIndex, final int toIndex) {
if (fromIndex == toIndex) {
return;
}
final KType[] buffer = ((KType[])(this.buffer));
int i = toIndex;
do {
i = (((i) >= 1) ? (i) - 1 : (buffer.length) - 1);
procedure.apply(buffer[i]);
} while (i != fromIndex);
}
/**
* {@inheritDoc}
*/
@Override
public > T descendingForEach(final T predicate) {
descendingForEach(predicate, this.head, this.tail);
return predicate;
}
/**
* Applies predicate
to a slice of the deque,
* toIndex
, exclusive, down to fromIndex
, inclusive
* or until the predicate returns false
.
* Indices are in {@link #buffer} array.
*/
private void descendingForEach(final ObjectPredicate super KType> predicate, final int fromIndex, final int toIndex) {
if (fromIndex == toIndex) {
return;
}
final KType[] buffer = ((KType[])(this.buffer));
int i = toIndex;
do {
i = (((i) >= 1) ? (i) - 1 : (buffer.length) - 1);
if (!predicate.apply(buffer[i])) {
break;
}
} while (i != fromIndex);
}
/**
* {@inheritDoc}
*/
@Override
public int removeAll(final ObjectPredicate super KType> predicate) {
int removed = 0;
final int last = this.tail;
final int bufLen = this.buffer.length;
final KType[] buffer = ((KType[])(this.buffer));
int from, to;
from = to = this.head;
try {
for (from = to = this.head; from != last; from = (((from) + 1 == (bufLen)) ? 0 : (from) + 1)) {
if (predicate.apply(buffer[from])) {
buffer[from] = (null);
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = (null);
}
to = (((to) + 1 == (bufLen)) ? 0 : (to) + 1);
}
} finally {
// Keep the deque in consistent state even if the predicate throws an exception.
for (; from != last; from = (((from) + 1 == (bufLen)) ? 0 : (from) + 1)) {
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = (null);
}
to = (((to) + 1 == (bufLen)) ? 0 : (to) + 1);
}
this.tail = to;
}
return removed;
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(final KType e) {
final int fromIndex = this.head;
final int toIndex = this.tail;
final KType[] buffer = ((KType[])(this.buffer));
for (int i = fromIndex; i != toIndex; i = (((i) + 1 == (buffer.length)) ? 0 : (i) + 1)) {
if (((e) == null ? (buffer[i]) == null : (e).equals((buffer[i])))) {
return true;
}
}
return false;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode() {
int h = 1;
final int fromIndex = this.head;
final int toIndex = this.tail;
final KType[] buffer = ((KType[])(this.buffer));
for (int i = fromIndex; i != toIndex; i = (((i) + 1 == (buffer.length)) ? 0 : (i) + 1)) {
h = 31 * h + BitMixer.mix(buffer[i]);
}
return h;
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
public boolean equals(final Object obj) {
if (obj != null) {
if (obj == this) {
return true;
}
if (obj instanceof ObjectLinkedList>) { //Access by index is slow, iterate by iterator when the other is a linked list
final ObjectLinkedList> other = (ObjectLinkedList>) obj;
if (other.size() != this.size()) {
return false;
}
final ValueIterator it = this.iterator();
final ObjectLinkedList.ValueIterator itOther = (ObjectLinkedList.ValueIterator) other.iterator();
while (it.hasNext()) {
final KType myVal = it.next().value;
final KType otherVal = itOther.next().value;
if (!((myVal) == null ? (otherVal) == null : (myVal).equals((otherVal)))) {
//recycle
it.release();
itOther.release();
return false;
}
} //end while
itOther.release();
return true;
}
else if (obj instanceof ObjectIndexedContainer>) {
//we can compare with any ObjectIndexedContainer :
final ObjectIndexedContainer> other = (ObjectIndexedContainer>) obj;
return other.size() == this.size() && allIndexesEqual(this, (ObjectIndexedContainer) other, this.size());
}
}
return false;
}
/**
* Compare index-aligned ObjectIndexedContainer objects
*/
private boolean allIndexesEqual(final ObjectIndexedContainer b1, final ObjectIndexedContainer b2,
final int length) {
for (int i = 0; i < length; i++) {
final KType o1 = b1.get(i);
final KType o2 = b2.get(i);
if (!((o1) == null ? (o2) == null : (o1).equals((o2)))) {
return false;
}
}
return true;
}
/**
* Returns a new object of this class with no need to declare generic type (shortcut
* instead of using a constructor).
*/
public static/* */ /* */
ObjectArrayDeque newInstance() {
return new ObjectArrayDeque();
}
/**
* Returns a new object of this class with no need to declare generic type (shortcut
* instead of using a constructor).
*/
public static/* */ /* */
ObjectArrayDeque newInstance(final int initialCapacity) {
return new ObjectArrayDeque(initialCapacity);
}
/**
* Create a new deque by pushing a variable number of arguments to the end of it.
*/
public static/* */ /* */
ObjectArrayDeque from(final KType... elements) {
final ObjectArrayDeque coll = new ObjectArrayDeque(elements.length);
coll.addLast(elements);
return coll;
}
/**
* Create a new deque by pushing a variable number of arguments to the end of it.
*/
public static/* */ /* */
ObjectArrayDeque from(final ObjectContainer container) {
return new ObjectArrayDeque(container);
}
////////////////////////////
/**
* In-place sort the dequeue from [beginIndex, endIndex[
* by natural ordering (smaller first)
* @param beginIndex the start index to be sorted
* @param endIndex the end index to be sorted (excluded)
*
* This sort is NOT stable.
*
* @throws ClassCastException if the deque contains elements that are not mutually Comparable.
*/
public void sort(final int beginIndex, final int endIndex) {
checkRangeBounds(beginIndex, endIndex);
if (beginIndex == endIndex) {
return; //nothing to do
}
//Fast path : if the actual indices matching [beginIndex; endIndex[
//in the underlying buffer are in increasing order (means there is no folding of buffer in the interval),
// use quicksort array version directly.
final int bufferPosStart = indexToBufferPosition(beginIndex);
final int bufferPosEndInclusive = indexToBufferPosition(endIndex - 1); //must be a valid index
if (bufferPosEndInclusive > bufferPosStart) {
ObjectSort.quicksort(this.buffer, bufferPosStart, bufferPosEndInclusive + 1);
} else {
//Use the slower ObjectIndexedContainer sort
ObjectSort.quicksort(this, beginIndex, endIndex);
}
}
/**
* In-place sort the dequeue from [beginIndex, endIndex[
* using a Comparator
*
* This sort is NOT stable.
*
* @param beginIndex the start index to be sorted
* @param endIndex the end index to be sorted (excluded)
*/
public void sort(final int beginIndex, final int endIndex,
final Comparator super KType>
comp) {
checkRangeBounds(beginIndex, endIndex);
if (beginIndex == endIndex) {
return; //nothing to do
}
//Fast path : if the actual indices matching [beginIndex; endIndex[
//in the underlying buffer are in increasing order (means there is no folding of buffer in the interval),
// use quicksort array version directly.
final int bufferPosStart = indexToBufferPosition(beginIndex);
final int bufferPosEndInclusive = indexToBufferPosition(endIndex - 1); //must be valid indices
if (bufferPosEndInclusive > bufferPosStart) {
ObjectSort.quicksort(((KType[])(this.buffer)), bufferPosStart, bufferPosEndInclusive + 1, comp);
} else {
//Use the slower ObjectIndexedContainer sort
ObjectSort.quicksort(this, beginIndex, endIndex, comp);
}
}
/**
* In-place sort the whole dequeue by natural ordering (smaller first)
*
* This sort is NOT stable.
*
* @throws ClassCastException if the deque contains elements that are not mutually Comparable.
*/
public void sort() {
if (size() > 1) {
compactBeforeSorting();
ObjectSort.quicksort(this.buffer, this.head, this.tail);
}
}
////////////////////////////
/**
* In-place sort the whole dequeue
* using a Comparator
*
* This sort is NOT stable.
*
*/
public void sort(
final Comparator super KType>
comp) {
if (size() > 1) {
compactBeforeSorting();
ObjectSort.quicksort(((KType[])(this.buffer)), this.head, this.tail, comp);
}
}
/**
* ObjectIndexedContainer methods
*/
/**
* {@inheritDoc}
*/
@Override
public void add(final KType e1) {
addLast(e1);
}
/**
* This operation is not supported on array deques, throwing UnsupportedOperationException.
* @throws UnsupportedOperationException
*/
@Override
public void insert(final int index, final KType e1) {
throw new UnsupportedOperationException(
"insert(final int index, final KType e1) operation is not supported on KTypeArrayDeque");
}
/**
* {@inheritDoc}
* The position is relative to the head,
* i.e w.r.t the {@link ObjectIndexedContainer}, index 0 is the head of the queue, size() - 1 is the last element position.
*/
@Override
public KType set(final int index, final KType e1) {
final int indexInBuffer = indexToBufferPosition(index);
final KType previous = ((KType)(this.buffer[indexInBuffer]));
this.buffer[indexInBuffer] = e1;
return previous;
}
/**
* {@inheritDoc}
* The position is relative to the head,
* i.e w.r.t the {@link ObjectIndexedContainer}, index 0 is the head of the queue, size() - 1 is the last element position.
*/
@Override
public KType get(final int index) {
return ((KType)(this.buffer[indexToBufferPosition(index)]));
}
/**
* {@inheritDoc}
* The position is relative to the head,
* i.e w.r.t the {@link ObjectIndexedContainer}, index 0 is the head of the queue, size() - 1 is the last element position.
*/
@Override
public KType remove(final int index) {
final int indexInBuffer = indexToBufferPosition(index);
final KType previous = ((KType)(this.buffer[indexInBuffer]));
removeBufferIndicesRange(indexInBuffer, (((indexInBuffer) + 1 == (this.buffer.length)) ? 0 : (indexInBuffer) + 1));
return previous;
}
/**
* Remove all elements in [fromBufferIndex; toBufferIndex[ indices in {@link #buffer}.
* @param fromBufferIndex
* @param toBufferIndex
*/
private void removeBufferIndicesRange(final int fromBufferIndex, final int toBufferIndex) {
final int bufLen = this.buffer.length;
final KType[] buffer = ((KType[])(this.buffer));
if (fromBufferIndex == toBufferIndex) {
//nothing to do
return;
}
long nbToBeRemoved = (long) toBufferIndex - fromBufferIndex;
//fold the value
if (nbToBeRemoved < 0) {
nbToBeRemoved += bufLen;
}
final int last = this.tail;
long removed = 0;
int from, to;
for (from = to = fromBufferIndex; from != last; from = (((from) + 1 == (bufLen)) ? 0 : (from) + 1)) {
if (removed < nbToBeRemoved) {
buffer[from] = (null);
removed++;
continue;
}
buffer[to] = buffer[from];
buffer[from] = (null);
to = (((to) + 1 == (bufLen)) ? 0 : (to) + 1);
} //end for
this.tail = to;
}
/**
* {@inheritDoc}
* The position is relative to the head,
* i.e w.r.t the {@link ObjectIndexedContainer}, index 0 is the head of the queue, size() - 1 is the last element position.
*/
@Override
public void removeRange(final int fromIndex, final int toIndex) {
checkRangeBounds(fromIndex, toIndex);
if (fromIndex == toIndex) {
return; //nothing to do
}
final int bufferPositionStart = indexToBufferPosition(fromIndex);
final int bufferPositionEndInclusive = indexToBufferPosition(toIndex - 1); //must be a valid index
removeBufferIndicesRange(bufferPositionStart, (((bufferPositionEndInclusive) + 1 == (this.buffer.length)) ? 0 : (bufferPositionEndInclusive) + 1));
}
/**
* Convert the internal {@link #buffer} index to equivalent {@link #ObjectIndexedContainer}
* position.
* @param bufferIndex
* @return
*/
private int bufferIndexToPosition(final int bufferIndex) {
int pos = -1;
if (bufferIndex >= 0) {
pos = bufferIndex - this.head;
if (pos < 0) {
//fold it
pos += this.buffer.length;
}
}
return pos;
}
/**
* Convert the {@link #ObjectIndexedContainer}
* index to the internal position in buffer{@link #buffer}.
* @param index a valid index towards {@link #ObjectIndexedContainer}.
* @return
*/
private int indexToBufferPosition(final int index) {
//since the buffer is circular, we could have out-of-bounds access without JRE throwing an ArrayOutOfBoundsException,
//so it is safer to do it this way.
if (index < 0 || index >= size()) {
throw new IndexOutOfBoundsException("Index " + index + " out of bounds [" + 0 + ", size=" + size() + "[.");
}
//Convert to long to prevent overflow
long bufferPos = (long) index + this.head;
if (bufferPos >= this.buffer.length) {
//fold it
bufferPos -= this.buffer.length;
}
return (int) bufferPos;
}
private void checkRangeBounds(final int beginIndex, final int endIndex) {
if (beginIndex > endIndex) {
throw new IllegalArgumentException("Index beginIndex " + beginIndex + " is > endIndex " + endIndex);
}
if (beginIndex < 0) {
throw new IndexOutOfBoundsException("Index beginIndex < 0");
}
if (endIndex > size()) {
throw new IndexOutOfBoundsException("Index endIndex " + endIndex + " out of bounds [" + 0 + ", " + size() + "].");
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy