All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.carrotsearch.hppc.DoubleArrayDeque Maven / Gradle / Ivy

Go to download

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.

There is a newer version: 0.10.0
Show newest version
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 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 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 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; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy