org.jhotdraw8.collection.primitive.IntArrayList Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.jhotdraw8.collection Show documentation
Show all versions of org.jhotdraw8.collection Show documentation
JHotDraw8 Utility classes for Collections
The newest version!
/*
* @(#)IntArrayList.java
* Copyright © 2023 The authors and contributors of JHotDraw. MIT License.
*/
package org.jhotdraw8.collection.primitive;
import org.jhotdraw8.collection.util.ListHelper;
import org.jhotdraw8.icollection.facade.ListFacade;
import org.jspecify.annotations.Nullable;
import java.util.AbstractList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.PrimitiveIterator;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.IntPredicate;
import java.util.stream.IntStream;
/**
* A {@code int}-valued list backed by a primitive array.
*
* @author Werner Randelshofer
*/
public class IntArrayList extends AbstractList implements IntList {
private static final int[] EMPTY = new int[0];
private int[] items;
/**
* Holds the size of the list. Invariant: size >= 0.
*/
private int size;
/**
* Creates a new empty instance with 0 initial capacity.
*/
public IntArrayList() {
items = EMPTY;
}
/**
* Creates a new empty instance with the specified initial capacity.
*
* @param initialCapacity the initial capacity
*/
public IntArrayList(int initialCapacity) {
items = new int[initialCapacity];
}
/**
* Creates a new instance from the specified collection
*
* @param collection a collection of integers
*/
public IntArrayList(Collection collection) {
this.size = collection.size();
this.items = new int[size];
int count = 0;
//noinspection ForLoopReplaceableByForEach
for (Iterator iter = collection.iterator(); iter.hasNext(); ) {
Integer value = iter.next();
items[count++] = value;
}
}
private IntArrayList(int[] items) {
this.items = items;
this.size = items.length;
}
/**
* Creates a new instance with the specified items.
*
* @param items the items (the newly created instance references the
* provided array)
* @return the new instance
*/
public static IntArrayList of(int... items) {
return new IntArrayList(items);
}
@Override
public boolean add(Integer integer) {
addAsInt(integer);
return true;
}
/**
* Adds all items of the specified list to this list.
*
* @param that another list
*/
public void addAllAsInt(IntArrayList that) {
if (that.isEmpty()) {
return;
}
grow(size + that.size);
System.arraycopy(that.items, 0, this.items, this.size, that.size);
this.size += that.size;
}
/**
* Adds all items of this collection to the specified collection.
*
* @param the type of the collection
* @param out the output collection
* @return out
*/
public > T addAllInto(T out) {
for (int i = 0, n = size; i < n; i++) {
out.add(items[i]);
}
return out;
}
/**
* Adds a new item to the end of the list.
*
* @param newItem the new item
*/
@Override
public void addAsInt(int newItem) {
grow(size + 1);
items[size++] = newItem;
}
/**
* Inserts a new item at the specified index into this list.
*
* @param index the index
* @param newItem the new item
*/
@Override
public void addAsInt(int index, int newItem) {
Objects.checkIndex(index, size + 1);
grow(size + 1);
items[index] = newItem;
++size;
}
/**
* Clears the list in O(1).
*/
@Override
public void clear() {
// Performance: do not fill array with 0 values
size = 0;
}
@Override
public boolean contains(Object o) {
if (o instanceof Integer e) {
return indexOfAsInt(e) != -1;
}
return false;
}
/**
* Copies the contents of this list into the provided array.
*
* @param a an array
* @param offset the offset into the array
*/
public void copyInto(int[] a, int offset) {
System.arraycopy(items, 0, a, offset, size);
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
// FIXME this is not correct since we implement List
if (getClass() != obj.getClass()) {
return false;
}
final IntArrayList other = (IntArrayList) obj;
if (other.size != this.size) {
return false;
}
for (int i = 0; i < size; i++) {
if (other.items[i] != this.items[i]) {
return false;
}
}
return true;
}
/*
* Gets the item at the specified index.
*
* @param index an index
* @return the item at the index
*/
@Override
public Integer get(int index) {
Objects.checkIndex(index, size);
return items[index];
}
/**
* Gets the array that is used internally by this list.
*
* @return the internal array
*/
public int[] getArray() {
return items;
}
/**
* Gets the item at the specified index.
*
* @param index an index
* @return the item at the index
*/
@Override
public int getAsInt(int index) {
Objects.checkIndex(index, size);
return items[index];
}
@Override
public int getFirstAsInt() {
return getAsInt(0);
}
@Override
public int getLastAsInt() {
return getAsInt(size - 1);
}
private void grow(int capacity) {
if (items.length < capacity) {
items = ListHelper.grow(Math.max(1, items.length * 2), 1, items);
}
}
@Override
public int hashCode() {
int result = 1;
for (int i = 0; i < size; i++) {
result = 31 * result + items[i];
}
return result;
}
@Override
public int indexOfAsInt(int item) {
return indexOfAsInt(item, 0);
}
public int indexOfAsInt(int item, int start) {
for (int i = start; i < size; i++) {
if (items[i] == item) {
return i;
}
}
return -1;
}
/**
* Returns a stream for processing the items of this list.
*
* @return a stream
*/
public IntStream intStream() {
return (size == 0) ? IntStream.empty() : Arrays.stream(items, 0, size);
}
/**
* Returns true if size==0.
*
* @return true if empty
*/
@Override
public boolean isEmpty() {
return size == 0;
}
/**
* Returns an iterator for this list.
*
* @return an iterator over the elements of this list
*/
@Override
public PrimitiveIterator.OfInt iterator() {
return new PrimitiveIterator.OfInt() {
private final int[] items = IntArrayList.this.items;
private final int size = IntArrayList.this.size;
private int index = 0;
@Override
public boolean hasNext() {
return index < size;
}
@Override
public int nextInt() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return items[index++];
}
};
}
@Override
public int lastIndexOfAsInt(int item) {
return lastIndexOfAsInt(item, size - 1);
}
public int lastIndexOfAsInt(int item, int start) {
for (int i = start; i >= 0; i--) {
if (items[i] == item) {
return i;
}
}
return -1;
}
@Override
public boolean remove(Object o) {
if (o instanceof Integer) {
int index = indexOfAsInt((int) o);
if (index != -1) {
removeAtAsInt(index);
return true;
}
}
return false;
}
/**
* Removes the item at the specified index from this list.
*
* @param index an index
* @return the removed item
*/
@Override
public int removeAtAsInt(int index) {
Objects.checkIndex(index, size);
int removedItem = items[index];
int numMoved = size - index - 1;
if (numMoved > 0) {
System.arraycopy(items, index + 1, items, index, numMoved);
}
--size;
return removedItem;
}
/**
* Removes all the elements of this collection that satisfy the given
* predicate.
*
* @param filter a predicate which returns {@code true} for elements to be
* removed
* @return {@code true} if any elements were removed
*/
public boolean removeIfAsInt(IntPredicate filter) {
boolean hasRemoved = false;
Objects.requireNonNull(filter, "filter");
for (int i = size - 1; i >= 0; i--) {
if (filter.test(getAsInt(i))) {
removeAtAsInt(i);
hasRemoved = true;
}
}
return hasRemoved;
}
/**
* Removes the last item
*
* @return the removed item
* @throws NoSuchElementException if the list is empty
*/
@Override
public int removeLastAsInt() {
if (isEmpty()) {
throw new NoSuchElementException("List is empty.");
}
return removeAtAsInt(size - 1);
}
@Override
public List reversed() {
return new ListFacade<>(
this::size,
i -> get(size() - i)
);
}
/**
* Replaces the item at the specified index.
*
* @param index an index
* @param newItem the new item
* @return the old item
*/
@Override
public Integer set(int index, Integer newItem) {
Objects.checkIndex(index, size);
int removedItem = items[index];
items[index] = newItem;
return removedItem;
}
/**
* Replaces the item at the specified index.
*
* @param index an index
* @param newItem the new item
* @return the old item
*/
public int setAsInt(int index, int newItem) {
Objects.checkIndex(index, size);
int removedItem = items[index];
items[index] = newItem;
return removedItem;
}
/**
* Sets the size of this list. If the new size is greater than the current
* size, new {@code 0} items are added to the end of the list. If the new
* size is less than the current size, all items at indices greater or
* equal {@code newSize} are discarded.
*
* @param newSize the new size
*/
public void setSize(int newSize) {
grow(newSize);
if (newSize > size) {
Arrays.fill(items, size, newSize, 0);
}
size = newSize;
}
/**
* Returns the size of the list.
*
* @return the size
*/
@Override
public int size() {
return size;
}
/**
* Sorts the items in ascending order.
*/
public void sort() {
Arrays.sort(items, 0, size);
}
/**
* Sorts this list according to the order induced by the specified
* {@link Comparator}. The sort is stable: it does not
* reorder equal elements.
*
* @param c the {@code Comparator} used to compare list elements.
* A {@code null} value indicates that the elements'
* {@linkplain Comparable natural ordering} should be used.
*/
@Override
public void sort(@Nullable Comparator super Integer> c) {
if (size > 1) {
if (c == null) {
Arrays.sort(items, 0, size);
} else {
// XXX this is inefficient, we need a sort method for an int-array that takes a comparator.
final Integer[] objects = new Integer[size];
for (int i = 0; i < size; i++) {
objects[i] = items[i];
}
Arrays.sort(objects, 0, size, c);
for (int i = 0; i < size; i++) {
items[i] = objects[i];
}
}
}
}
/**
* Returns a spliterator for this list.
*
* @return a spliterator over the elements of this list
*/
@Override
public Spliterator.OfInt spliterator() {
return Spliterators.spliterator(items, 0, size, Spliterator.ORDERED | Spliterator.IMMUTABLE);
}
/**
* Returns a new array containing all the elements in this collection.
*
* @return array
*/
public int[] toIntArray() {
int[] result = new int[size];
System.arraycopy(items, 0, result, 0, size);
return result;
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; i < size; i++) {
if (i > 0) {
b.append(", ");
}
b.append(items[i]);
}
return b.append(']').toString();
}
/**
* Trims the capacity of the list its current size.
*/
public void trimToSize() {
items = ListHelper.trimToSize(size, 1, items);
}
}