com.carrotsearch.hppcrt.lists.CharArrayList Maven / Gradle / Ivy
Show all versions of hppcrt Show documentation
package com.carrotsearch.hppcrt.lists;
import java.util.*;
import com.carrotsearch.hppcrt.*;
import com.carrotsearch.hppcrt.cursors.*;
import com.carrotsearch.hppcrt.predicates.*;
import com.carrotsearch.hppcrt.procedures.*;
import com.carrotsearch.hppcrt.sorting.*;
import com.carrotsearch.hppcrt.strategies.*;
/**
* An array-backed list of chars. 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.
*
* See {@link ObjectArrayList} class for API similarities and differences against Java
* Collections.
*/
@javax.annotation.Generated(date = "2015-02-27T19:21:04+0100", value = "HPPC-RT generated from: CharArrayList.java")
public class CharArrayList
extends AbstractCharCollection implements CharIndexedContainer, Cloneable
{
/**
* Default capacity if no other capacity is given in the constructor.
*/
public final static int DEFAULT_CAPACITY = 5;
/**
* Internal static instance of an empty buffer.
*/
private final static Object EMPTY =
new char [0];
/**
* Internal array for storing the list. The array may be larger than the current size
* ({@link #size()}).
*
*
* Direct list iteration: iterate buffer[i] for i in [0; size()[
*
*/
public char[] buffer;
/**
* Current number of elements stored in {@link #buffer}.
*/
protected int elementsCount;
/**
* Buffer resizing strategy.
*/
protected final ArraySizingStrategy resizer;
/**
* internal pool of ValueIterator (must be created in constructor)
*/
protected final IteratorPool valueIteratorPool;
/**
* Create with default sizing strategy and initial capacity for storing
* {@value #DEFAULT_CAPACITY} elements.
*
* @see BoundedProportionalArraySizingStrategy
*/
public CharArrayList()
{
this(CharArrayList.DEFAULT_CAPACITY);
}
/**
* Create with default sizing strategy and the given initial capacity.
*
* @see BoundedProportionalArraySizingStrategy
*/
public CharArrayList(final int initialCapacity)
{
this(initialCapacity, new BoundedProportionalArraySizingStrategy());
}
/**
* Create with a custom buffer resizing strategy.
*/
public CharArrayList(final int initialCapacity, final ArraySizingStrategy resizer)
{
assert initialCapacity >= 0 : "initialCapacity must be >= 0: " + initialCapacity;
assert resizer != null;
this.resizer = resizer;
final int internalSize = resizer.round(initialCapacity);
//allocate internal buffer
this.buffer = (new char[internalSize]);
this.valueIteratorPool = new IteratorPool(
new ObjectFactory() {
@Override
public ValueIterator create()
{
return new ValueIterator();
}
@Override
public void initialize(final ValueIterator obj)
{
obj.cursor.index = -1;
obj.size = CharArrayList.this.size();
obj.buffer = CharArrayList.this.buffer;
}
@Override
public void reset(final ValueIterator obj) {
// for GC sake
obj.buffer = null;
}
});
}
/**
* Creates a new list from elements of another container.
*/
public CharArrayList(final CharContainer container)
{
this(container.size());
addAll(container);
}
/**
* {@inheritDoc}
*/
@Override
public void add(final char e1)
{
ensureBufferSpace(1);
this.buffer[this.elementsCount++] = e1;
}
/**
* Appends two elements at the end of the list. To add more than two elements,
* use add
(vararg-version) or access the buffer directly (tight
* loop).
*/
public void add(final char e1, final char e2)
{
ensureBufferSpace(2);
this.buffer[this.elementsCount++] = e1;
this.buffer[this.elementsCount++] = e2;
}
/**
* Add all elements from a range of given array to the list.
*/
public void add(final char[] elements, final int start, final int length)
{
assert length >= 0 : "Length must be >= 0";
ensureBufferSpace(length);
System.arraycopy(elements, start, this.buffer, this.elementsCount, length);
this.elementsCount += length;
}
/**
* Vararg-signature method for adding elements at the end of the list.
* This method is handy, but costly if used in tight loops (anonymous
* array passing)
*/
public void add(final char... elements)
{
add(elements, 0, elements.length);
}
/**
* Adds all elements from another container.
*/
public int addAll(final CharContainer container)
{
return addAll((Iterable extends CharCursor>) container);
}
/**
* Adds all elements from another iterable.
*/
public int addAll(final Iterable extends CharCursor> iterable)
{
int size = 0;
for (final CharCursor cursor : iterable)
{
add(cursor.value);
size++;
}
return size;
}
/**
* {@inheritDoc}
*/
@Override
public void insert(final int index, final char e1)
{
assert (index >= 0 && index <= size()) : "Index " + index + " out of bounds [" + 0 + ", " + size() + "].";
ensureBufferSpace(1);
System.arraycopy(this.buffer, index, this.buffer, index + 1, this.elementsCount - index);
this.buffer[index] = e1;
this.elementsCount++;
}
/**
* {@inheritDoc}
*/
@Override
public char get(final int index)
{
assert (index >= 0 && index < size()) : "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
return this.buffer[index];
}
/**
* {@inheritDoc}
*/
@Override
public char set(final int index, final char e1)
{
assert (index >= 0 && index < size()) : "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
final char v = this.buffer[index];
this.buffer[index] = e1;
return v;
}
/**
* {@inheritDoc}
*/
@Override
public char remove(final int index)
{
assert (index >= 0 && index < size()) : "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
final char v = this.buffer[index];
if (index + 1 < this.elementsCount) {
System.arraycopy(this.buffer, index + 1, this.buffer, index, this.elementsCount - index - 1);
}
this.elementsCount--;
return v;
}
/**
* {@inheritDoc}
*/
@Override
public void removeRange(final int fromIndex, final int toIndex)
{
assert (fromIndex >= 0 && fromIndex <= size()) : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size()) : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: "
+ fromIndex + ", " + toIndex;
System.arraycopy(this.buffer, toIndex, this.buffer, fromIndex, this.elementsCount - toIndex);
final int count = toIndex - fromIndex;
this.elementsCount -= count;
}
/**
* {@inheritDoc}
*/
@Override
public int removeFirstOccurrence(final char e1)
{
final int index = indexOf(e1);
if (index >= 0) {
remove(index);
}
return index;
}
/**
* {@inheritDoc}
*/
@Override
public int removeLastOccurrence(final char e1)
{
final int index = lastIndexOf(e1);
if (index >= 0) {
remove(index);
}
return index;
}
/**
* {@inheritDoc}
*/
@Override
public int removeAllOccurrences(final char e1)
{
int to = 0;
final char[] buffer = this.buffer;
for (int from = 0; from < this.elementsCount; from++)
{
if ((e1 == buffer[from]))
{
continue;
}
if (to != from)
{
buffer[to] = buffer[from];
}
to++;
}
final int deleted = this.elementsCount - to;
this.elementsCount = to;
return deleted;
}
/**
* {@inheritDoc}
*/
@Override
public boolean contains(final char e1)
{
return indexOf(e1) >= 0;
}
/**
* {@inheritDoc}
*/
@Override
public int indexOf(final char e1)
{
final char[] buffer = this.buffer;
for (int i = 0; i < this.elementsCount; i++) {
if ((e1 == buffer[i])) {
return i;
}
}
return -1;
}
/**
* {@inheritDoc}
*/
@Override
public int lastIndexOf(final char e1)
{
final char[] buffer = this.buffer;
for (int i = this.elementsCount - 1; i >= 0; i--) {
if ((e1 == buffer[i])) {
return i;
}
}
return -1;
}
/**
* Increases the capacity of this instance, if necessary, to ensure
* that it can hold at least the number of elements specified by
* the minimum capacity argument.
*/
public void ensureCapacity(final int minCapacity)
{
if (minCapacity > this.buffer.length) {
ensureBufferSpace(minCapacity - size());
}
}
/**
* Ensures the internal buffer has enough free slots to store
* expectedAdditions
. Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(final int expectedAdditions)
{
final int bufferLen = (this.buffer == null ? 0 : this.buffer.length);
if (this.elementsCount > bufferLen - expectedAdditions)
{
final int newSize = this.resizer.grow(bufferLen, this.elementsCount, expectedAdditions);
assert newSize >= this.elementsCount + expectedAdditions : "Resizer failed to" +
" return sensible new size: " + newSize + " <= "
+ (this.elementsCount + expectedAdditions);
final char[] newBuffer = (new char[newSize]);
if (bufferLen > 0)
{
System.arraycopy(this.buffer, 0, newBuffer, 0, this.buffer.length);
}
this.buffer = newBuffer;
}
}
/**
* Truncate or expand the list to the new size. If the list is truncated, the buffer
* will not be reallocated (use {@link #trimToSize()} if you need a truncated buffer).
* If the list is expanded, the elements beyond the current size are initialized with JVM-defaults
* (zero or null
values).
*/
public void resize(final int newSize)
{
if (newSize <= this.buffer.length)
{
if (newSize < this.elementsCount)
{
//there is no point in resetting to "null" elements
//that becomes non-observable anyway. Still,
//resetting is needed for GC in case of Objects because they may become "free"
//if not referenced anywhere else.
}
else
{
//in all cases, the contract of resize if that new elements
//are set to default values.
Arrays.fill(this.buffer, this.elementsCount, newSize,
('\u0000'));
}
}
else
{
ensureCapacity(newSize);
}
this.elementsCount = newSize;
}
/**
* {@inheritDoc}
*/
@Override
public int size()
{
return this.elementsCount;
}
/**
* {@inheritDoc}
*/
@Override
public int capacity() {
return this.buffer.length;
}
/**
* Trim the internal buffer to the current size.
*/
/* */
public void trimToSize()
{
if (size() != this.buffer.length) {
this.buffer = (char[]) toArray();
}
}
/**
* Sets the number of stored elements to zero.
*/
@Override
public void clear()
{
this.elementsCount = 0;
}
/**
* Sets the number of stored elements to zero and releases the internal storage array.
*/
/* */
public void release()
{
this.buffer = (char[]) CharArrayList.EMPTY;
this.elementsCount = 0;
}
/**
* {@inheritDoc}
*/
@Override
public char[] toArray(final char[] target)
{
System.arraycopy(this.buffer, 0, target, 0, this.elementsCount);
return target;
}
/**
* Clone this object. The returned clone will use the same resizing strategy.
* It also realizes a trim-to- this.size() in the process.
*/
@Override
public CharArrayList clone()
{
/* */
final CharArrayList cloned = new CharArrayList(this.size(), this.resizer);
cloned.defaultValue = this.defaultValue;
//add all in order, by construction.
cloned.addAll(this);
return cloned;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
int h = 1;
final int max = this.elementsCount;
final char[] buffer = this.buffer;
for (int i = 0; i < max; i++)
{
h = 31 * h + Internals.rehash(buffer[i]);
}
return h;
}
/**
* {@inheritDoc}
*/
@Override
/* */
public boolean equals(final Object obj)
{
if (obj != null)
{
if (obj == this) {
return true;
}
if (obj instanceof CharArrayList)
{
final CharArrayList other = (CharArrayList) obj;
return other.size() == this.size() &&
rangeEquals(other.buffer, this.buffer, size());
}
else if (obj instanceof CharIndexedContainer)
{
final CharIndexedContainer other = (CharIndexedContainer) obj;
return other.size() == this.size() &&
allIndexesEqual(this, (CharIndexedContainer) other, this.size());
}
}
return false;
}
/**
* Compare a range of values in two arrays.
*/
private boolean rangeEquals(char [] b1, char [] b2, int length)
{
for (int i = 0; i < length; i++)
{
if (!(b1[i] == b2[i]))
{
return false;
}
}
return true;
}
/**
* Compare index-aligned CharIndexedContainer objects
*/
final protected boolean allIndexesEqual(
final CharIndexedContainer b1,
final CharIndexedContainer b2, final int length)
{
for (int i = 0; i < length; i++)
{
final char o1 = b1.get(i);
final char o2 = b2.get(i);
if (!(o1 == o2))
{
return false;
}
}
return true;
}
/**
* An iterator implementation for {@link ObjectArrayList#iterator}.
*/
public final class ValueIterator extends AbstractIterator
{
public final CharCursor cursor;
private char[] buffer;
private int size;
public ValueIterator()
{
this.cursor = new CharCursor();
this.cursor.index = -1;
this.size = CharArrayList.this.size();
this.buffer = CharArrayList.this.buffer;
}
@Override
protected CharCursor fetch()
{
if (this.cursor.index + 1 == this.size) {
return done();
}
this.cursor.value = this.buffer[++this.cursor.index];
return this.cursor;
}
}
/**
* {@inheritDoc}
* @return
*/
@Override
public ValueIterator iterator()
{
//return new ValueIterator(buffer, size());
return this.valueIteratorPool.borrow();
}
/**
* {@inheritDoc}
*/
@Override
public T forEach(final T procedure)
{
return forEach(procedure, 0, size());
}
/**
* Applies procedure
to a slice of the list,
* fromIndex
, inclusive, to toIndex
,
* exclusive.
*/
public T forEach(final T procedure,
final int fromIndex, final int toIndex)
{
assert (fromIndex >= 0 && fromIndex <= size()) : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size()) : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: "
+ fromIndex + ", " + toIndex;
final char[] buffer = this.buffer;
for (int i = fromIndex; i < toIndex; i++)
{
procedure.apply(buffer[i]);
}
return procedure;
}
/**
* {@inheritDoc}
*/
@Override
public int removeAll(final CharPredicate predicate)
{
final int elementsCount = this.elementsCount;
final char[] buffer = this.buffer;
int to = 0;
int from = 0;
try
{
for (; from < elementsCount; from++)
{
if (predicate.apply(buffer[from]))
{
continue;
}
if (to != from)
{
buffer[to] = buffer[from];
}
to++;
}
}
finally
{
// Keep the list in a consistent state, even if the predicate throws an exception.
for (; from < elementsCount; from++)
{
if (to != from)
{
buffer[to] = buffer[from];
}
to++;
}
this.elementsCount = to;
}
return elementsCount - to;
}
/**
* {@inheritDoc}
*/
@Override
public T forEach(final T predicate)
{
return forEach(predicate, 0, size());
}
/**
* Applies predicate
to a slice of the list,
* fromIndex
, inclusive, to toIndex
,
* exclusive, or until predicate returns false
.
*/
public T forEach(final T predicate,
final int fromIndex, final int toIndex)
{
assert (fromIndex >= 0 && fromIndex <= size()) : "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size()) : "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: "
+ fromIndex + ", " + toIndex;
final char[] buffer = this.buffer;
for (int i = fromIndex; i < toIndex; i++)
{
if (!predicate.apply(buffer[i])) {
break;
}
}
return predicate;
}
/**
* Returns a new object of this class with no need to declare generic type (shortcut
* instead of using a constructor).
*/
public static/* */
CharArrayList newInstance()
{
return new CharArrayList();
}
/**
* Returns a new object of this class with no need to declare generic type (shortcut
* instead of using a constructor).
*/
public static/* */
CharArrayList newInstanceWithCapacity(final int initialCapacity)
{
return new CharArrayList(initialCapacity);
}
/**
* Create a list from a variable number of arguments or an array of char
.
* The elements are copied from the argument to the internal buffer.
*/
public static/* */
CharArrayList from(final char... elements)
{
final CharArrayList list = new CharArrayList(elements.length);
list.add(elements);
return list;
}
/**
* Create a list from elements of another container.
*/
public static/* */
CharArrayList from(final CharContainer container)
{
return new CharArrayList(container);
}
/**
* In-place sort the list 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)
*/
public void sort(final int beginIndex, final int endIndex)
{
assert endIndex <= this.elementsCount;
if (endIndex - beginIndex > 1)
{
CharSort.quicksort(this.buffer, beginIndex, endIndex);
}
}
/**
* In-place sort the whole list by natural ordering (smaller first)
*
* This routine uses Dual-pivot Quicksort, from [Yaroslavskiy 2009]
*
*/
public void sort()
{
sort(0, this.elementsCount);
}
////////////////////////////
/**
* In-place sort the list from [beginIndex, endIndex[
* using a CharComparator *
* This routine uses Dual-pivot Quicksort, from [Yaroslavskiy 2009] *
* @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,
CharComparator
comp)
{
assert endIndex <= this.elementsCount;
if (endIndex - beginIndex > 1)
{
CharSort.quicksort(this.buffer, beginIndex, endIndex, comp);
}
}
/**
* In-place sort the whole list
* using a CharComparator *
* This routine uses Dual-pivot Quicksort, from [Yaroslavskiy 2009] *
*/
public void sort(
CharComparator
comp)
{
sort(0, this.elementsCount, comp);
}
}