package com.carrotsearch.hppc; import static com.carrotsearch.hppc.Containers.*; import com.carrotsearch.hppc.cursors.CharCursor; import com.carrotsearch.hppc.predicates.CharPredicate; import com.carrotsearch.hppc.procedures.CharProcedure; import java.util.*; /** An array-backed {@link CharDeque}. */ @com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java") public class CharArrayDeque extends AbstractCharCollection implements CharDeque, Preallocable, Cloneable, Accountable { /** Reuse the same strategy instance. */ private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY = BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE; /** Internal array for storing elements of the deque. */ public char[] buffer = CharArrayList.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 CharArrayDeque() { this(DEFAULT_EXPECTED_ELEMENTS); } /** * New instance with sane defaults. * * @param expectedElements The expected number of elements guaranteed not to cause buffer * expansion (inclusive). */ public CharArrayDeque(int expectedElements) { this(expectedElements, DEFAULT_SIZING_STRATEGY); } /** * 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 CharArrayDeque(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 CharArrayDeque(CharContainer container) { this(container.size()); addLast(container); } /** {@inheritDoc} */ @Override public void addFirst(char 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(char... elements) { ensureBufferSpace(elements.length); for (char 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(CharContainer container) { int size = container.size(); ensureBufferSpace(size); for (CharCursor 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 (CharCursor cursor : iterable) { addFirst(cursor.value); size++; } return size; } /** {@inheritDoc} */ @Override public void addLast(char 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(char... elements) { ensureBufferSpace(1); for (char 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(CharContainer container) { int size = container.size(); ensureBufferSpace(size); for (CharCursor 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 (CharCursor cursor : iterable) { addLast(cursor.value); size++; } return size; } /** {@inheritDoc} */ @Override public char removeFirst() { assert size() > 0 : "The deque is empty."; final char result = buffer[head]; buffer[head] = ((char) 0); head = oneRight(head, buffer.length); return result; } /** {@inheritDoc} */ @Override public char removeLast() { assert size() > 0 : "The deque is empty."; tail = oneLeft(tail, buffer.length); final char result = buffer[tail]; buffer[tail] = ((char) 0); return result; } /** {@inheritDoc} */ @Override public char getFirst() { assert size() > 0 : "The deque is empty."; return buffer[head]; } /** {@inheritDoc} */ @Override public char getLast() { assert size() > 0 : "The deque is empty."; return buffer[oneLeft(tail, buffer.length)]; } /** {@inheritDoc} */ @Override public int removeFirst(char 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(char e1) { final int last = tail; final int bufLen = buffer.length; for (int i = head; i != last; i = oneRight(i, bufLen)) { if (((e1) == (buffer[i]))) { return i; } } return -1; } /** {@inheritDoc} */ @Override public int removeLast(char 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(char 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 (((e1) == (buffer[i]))) return i; } return -1; } /** {@inheritDoc} */ @Override public int removeAll(char 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 (((e1) == (buffer[from]))) { buffer[from] = ((char) 0); removed++; continue; } if (to != from) { buffer[to] = buffer[from]; buffer[from] = ((char) 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 char[] 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] = ((char) 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] = ((char) 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, ((char) 0)); } else { Arrays.fill(buffer, 0, tail, ((char) 0)); Arrays.fill(buffer, head, buffer.length, ((char) 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 = CharArrayList.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 char[] newBuffer = (new char[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 char[] toArray() { final int size = size(); return toArray((new char[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 char[] toArray(char[] 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 CharArrayDeque clone() { try { CharArrayDeque cloned = (CharArrayDeque) 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; } @Override public long ramBytesAllocated() { // int: head, tail return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + Integer.BYTES * 2 + resizer.ramBytesAllocated() + RamUsageEstimator.shallowSizeOfArray(buffer); } @Override public long ramBytesUsed() { // int: head, tail return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + Integer.BYTES * 2 + resizer.ramBytesUsed() + RamUsageEstimator.shallowUsedSizeOfArray(buffer, size()); } /** An iterator implementation for {@link ObjectArrayDeque#iterator}. */ private final class ValueIterator extends AbstractIterator { private final CharCursor cursor; private int remaining; public ValueIterator() { cursor = new CharCursor(); cursor.index = oneLeft(head, buffer.length); this.remaining = size(); } @Override protected CharCursor 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 CharCursor cursor; private int remaining; public DescendingValueIterator() { cursor = new CharCursor(); cursor.index = tail; this.remaining = size(); } @Override protected CharCursor 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(CharProcedure procedure, int fromIndex, final int toIndex) { final char[] 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 char[] 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(CharProcedure procedure, int fromIndex, final int toIndex) { if (fromIndex == toIndex) return; final char[] 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(CharPredicate predicate, int fromIndex, final int toIndex) { if (fromIndex == toIndex) return; final char[] 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(CharPredicate predicate) { final char[] 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] = ((char) 0); removed++; continue; } if (to != from) { buffer[to] = buffer[from]; buffer[from] = ((char) 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] = ((char) 0); } to = oneRight(to, bufLen); } tail = to; } return removed; } /** {@inheritDoc} */ @Override public boolean contains(char e) { int fromIndex = head; int toIndex = tail; final char[] buffer = this.buffer; for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) { if (((e) == (buffer[i]))) { return true; } } return false; } /** {@inheritDoc} */ @Override public int hashCode() { int h = 1; int fromIndex = head; int toIndex = tail; final char[] 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 (this == obj) || (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj))); } /** Compare order-aligned elements against another {@link CharDeque}. */ protected boolean equalElements(CharArrayDeque other) { int max = size(); if (other.size() != max) { return false; } Iterator i1 = this.iterator(); Iterator i2 = other.iterator(); while (i1.hasNext() && i2.hasNext()) { if (!((i1.next().value) == (i2.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 CharArrayDeque from(char... elements) { final CharArrayDeque coll = new CharArrayDeque(elements.length); coll.addLast(elements); return coll; } }