/* * Copyright 2015 Goldman Sachs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gs.collections.impl.list.mutable; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.List; import java.util.RandomAccess; import com.gs.collections.api.block.HashingStrategy; import com.gs.collections.api.block.function.Function; import com.gs.collections.api.block.function.Function0; import com.gs.collections.api.block.function.Function2; import com.gs.collections.api.block.function.Function3; import com.gs.collections.api.block.function.primitive.BooleanFunction; import com.gs.collections.api.block.function.primitive.ByteFunction; import com.gs.collections.api.block.function.primitive.CharFunction; import com.gs.collections.api.block.function.primitive.DoubleFunction; import com.gs.collections.api.block.function.primitive.DoubleObjectToDoubleFunction; import com.gs.collections.api.block.function.primitive.FloatFunction; import com.gs.collections.api.block.function.primitive.FloatObjectToFloatFunction; import com.gs.collections.api.block.function.primitive.IntFunction; import com.gs.collections.api.block.function.primitive.IntObjectToIntFunction; import com.gs.collections.api.block.function.primitive.LongFunction; import com.gs.collections.api.block.function.primitive.LongObjectToLongFunction; import com.gs.collections.api.block.function.primitive.ShortFunction; import com.gs.collections.api.block.predicate.Predicate; import com.gs.collections.api.block.predicate.Predicate2; import com.gs.collections.api.block.procedure.Procedure; import com.gs.collections.api.block.procedure.Procedure2; import com.gs.collections.api.block.procedure.primitive.ObjectIntProcedure; import com.gs.collections.api.collection.primitive.MutableBooleanCollection; import com.gs.collections.api.collection.primitive.MutableByteCollection; import com.gs.collections.api.collection.primitive.MutableCharCollection; import com.gs.collections.api.collection.primitive.MutableDoubleCollection; import com.gs.collections.api.collection.primitive.MutableFloatCollection; import com.gs.collections.api.collection.primitive.MutableIntCollection; import com.gs.collections.api.collection.primitive.MutableLongCollection; import com.gs.collections.api.collection.primitive.MutableShortCollection; import com.gs.collections.api.list.MutableList; import com.gs.collections.api.list.primitive.MutableBooleanList; import com.gs.collections.api.list.primitive.MutableByteList; import com.gs.collections.api.list.primitive.MutableCharList; import com.gs.collections.api.list.primitive.MutableDoubleList; import com.gs.collections.api.list.primitive.MutableFloatList; import com.gs.collections.api.list.primitive.MutableIntList; import com.gs.collections.api.list.primitive.MutableLongList; import com.gs.collections.api.list.primitive.MutableShortList; import com.gs.collections.api.map.MutableMap; import com.gs.collections.api.map.primitive.ObjectDoubleMap; import com.gs.collections.api.map.primitive.ObjectLongMap; import com.gs.collections.api.multimap.MutableMultimap; import com.gs.collections.api.ordered.OrderedIterable; import com.gs.collections.api.partition.list.PartitionMutableList; import com.gs.collections.api.tuple.Twin; import com.gs.collections.impl.block.factory.Comparators; import com.gs.collections.impl.block.factory.Predicates2; import com.gs.collections.impl.block.factory.Procedures2; import com.gs.collections.impl.list.mutable.primitive.BooleanArrayList; import com.gs.collections.impl.list.mutable.primitive.ByteArrayList; import com.gs.collections.impl.list.mutable.primitive.CharArrayList; import com.gs.collections.impl.list.mutable.primitive.DoubleArrayList; import com.gs.collections.impl.list.mutable.primitive.FloatArrayList; import com.gs.collections.impl.list.mutable.primitive.IntArrayList; import com.gs.collections.impl.list.mutable.primitive.LongArrayList; import com.gs.collections.impl.list.mutable.primitive.ShortArrayList; import com.gs.collections.impl.map.mutable.UnifiedMap; import com.gs.collections.impl.multimap.list.FastListMultimap; import com.gs.collections.impl.parallel.BatchIterable; import com.gs.collections.impl.partition.list.PartitionFastList; import com.gs.collections.impl.utility.ArrayIterate; import com.gs.collections.impl.utility.ArrayListIterate; import com.gs.collections.impl.utility.Iterate; import com.gs.collections.impl.utility.ListIterate; import com.gs.collections.impl.utility.internal.InternalArrayIterate; import com.gs.collections.impl.utility.internal.RandomAccessListIterate; import net.jcip.annotations.NotThreadSafe; /** * FastList is an attempt to provide the same functionality as ArrayList without the support for concurrent * modification exceptions. It also attempts to correct the problem with subclassing ArrayList * in that the data elements are protected, not private. It is this issue that caused this class * to be created in the first place. The intent was to provide optimized internal iterators which use direct access * against the array of items, which is currently not possible by subclassing ArrayList. * <p> * An empty FastList created by calling the default constructor starts with a shared reference to a static * empty array (DEFAULT_SIZED_EMPTY_ARRAY). This makes empty FastLists very memory efficient. The * first call to add will lazily create an array of size 10. * <p> * An empty FastList created by calling the pre-size constructor with a value of 0 (new FastList(0)) starts * with a shared reference to a static empty array (ZERO_SIZED_ARRAY). This makes FastLists presized to 0 very * memory efficient as well. The first call to add will lazily create an array of size 1. */ @NotThreadSafe public class FastList<T> extends AbstractMutableList<T> implements Externalizable, RandomAccess, BatchIterable<T> { private static final long serialVersionUID = 1L; private static final Object[] DEFAULT_SIZED_EMPTY_ARRAY = {}; private static final Object[] ZERO_SIZED_ARRAY = {}; private static final int MAXIMUM_ARRAY_SIZE = Integer.MAX_VALUE - 8; protected int size; protected transient T[] items = (T[]) DEFAULT_SIZED_EMPTY_ARRAY; public FastList() { } public FastList(int initialCapacity) { this.items = initialCapacity == 0 ? (T[]) ZERO_SIZED_ARRAY : (T[]) new Object[initialCapacity]; } protected FastList(T[] array) { this(array.length, array); } protected FastList(int size, T[] array) { this.size = size; this.items = array; } public FastList(Collection<? extends T> source) { this.items = (T[]) source.toArray(); this.size = this.items.length; } public static <E> FastList<E> newList() { return new FastList<E>(); } public static <E> FastList<E> wrapCopy(E... array) { E[] newArray = (E[]) new Object[array.length]; System.arraycopy(array, 0, newArray, 0, array.length); return new FastList<E>(newArray); } public static <E> FastList<E> newList(int initialCapacity) { return new FastList<E>(initialCapacity); } public static <E> FastList<E> newList(Iterable<? extends E> source) { return FastList.newListWith((E[]) Iterate.toArray(source)); } /** * Creates a new list using the passed {@code elements} argument as the backing store. * <p> * !!! WARNING: This method uses the passed in array, so can be very unsafe if the original * array is held onto anywhere else. !!! */ public static <E> FastList<E> newListWith(E... elements) { return new FastList<E>(elements); } /** * Creates a new FastList pre-sized to the specified size filled with default values generated by the specified function. * * @since 3.0 */ public static <E> FastList<E> newWithNValues(int size, Function0<E> factory) { FastList<E> newFastList = FastList.newList(size); for (int i = 0; i < size; i++) { newFastList.add(factory.value()); } return newFastList; } @Override public FastList<T> clone() { FastList<T> result = (FastList<T>) super.clone(); if (this.items.length > 0) { result.items = this.items.clone(); } return result; } public void clear() { Arrays.fill(this.items, null); this.size = 0; } @Override public void forEach(int from, int to, Procedure<? super T> procedure) { ListIterate.rangeCheck(from, to, this.size); InternalArrayIterate.forEachWithoutChecks(this.items, from, to, procedure); } @Override public void forEachWithIndex(int from, int to, ObjectIntProcedure<? super T> objectIntProcedure) { ListIterate.rangeCheck(from, to, this.size); InternalArrayIterate.forEachWithIndexWithoutChecks(this.items, from, to, objectIntProcedure); } public void batchForEach(Procedure<? super T> procedure, int sectionIndex, int sectionCount) { InternalArrayIterate.batchForEach(procedure, this.items, this.size, sectionIndex, sectionCount); } public int getBatchCount(int batchSize) { return Math.max(1, this.size() / batchSize); } public <E> E[] toArray(E[] array, int sourceFromIndex, int sourceToIndex, int destinationIndex) { System.arraycopy(this.items, sourceFromIndex, array, destinationIndex, sourceToIndex - sourceFromIndex + 1); return array; } public <E> E[] toArray(int sourceFromIndex, int sourceToIndex) { return this.toArray((E[]) new Object[sourceToIndex - sourceFromIndex + 1], sourceFromIndex, sourceToIndex, 0); } @Override public FastList<T> sortThis(Comparator<? super T> comparator) { Arrays.sort(this.items, 0, this.size, comparator); return this; } @Override public FastList<T> sortThis() { Arrays.sort(this.items, 0, this.size); return this; } @Override public FastList<T> reverseThis() { ArrayIterate.reverse(this.items, this.size); return this; } @Override public boolean addAll(Collection<? extends T> source) { if (source.isEmpty()) { return false; } if (source.getClass() == FastList.class) { this.addAllFastList((FastList<T>) source); } else if (source.getClass() == ArrayList.class) { this.addAllArrayList((ArrayList<T>) source); } else if (source instanceof List && source instanceof RandomAccess) { this.addAllRandomAccessList((List<T>) source); } else { this.addAllCollection(source); } return true; } private void addAllFastList(FastList<T> source) { int sourceSize = source.size(); int newSize = this.size + sourceSize; this.ensureCapacity(newSize); System.arraycopy(source.items, 0, this.items, this.size, sourceSize); this.size = newSize; } private void addAllArrayList(ArrayList<T> source) { int sourceSize = source.size(); int newSize = this.size + sourceSize; this.ensureCapacity(newSize); ArrayListIterate.toArray(source, this.items, this.size, sourceSize); this.size = newSize; } private void addAllRandomAccessList(List<T> source) { int sourceSize = source.size(); int newSize = this.size + sourceSize; this.ensureCapacity(newSize); RandomAccessListIterate.toArray(source, this.items, this.size, sourceSize); this.size = newSize; } private void addAllCollection(Collection<? extends T> source) { this.ensureCapacity(this.size + source.size()); Iterate.forEachWith(source, Procedures2.<T>addToCollection(), this); } @Override public boolean containsAll(Collection<?> source) { return Iterate.allSatisfyWith(source, Predicates2.in(), this); } @Override public boolean containsAllArguments(Object... source) { return ArrayIterate.allSatisfyWith(source, Predicates2.in(), this); } @Override public <E> E[] toArray(E[] array) { if (array.length < this.size) { array = (E[]) Array.newInstance(array.getClass().getComponentType(), this.size); } System.arraycopy(this.items, 0, array, 0, this.size); if (array.length > this.size) { array[this.size] = null; } return array; } @Override public Object[] toArray() { return this.copyItemsWithNewCapacity(this.size); } public T[] toTypedArray(Class<T> clazz) { T[] array = (T[]) Array.newInstance(clazz, this.size); System.arraycopy(this.items, 0, array, 0, this.size); return array; } private void throwOutOfBounds(int index) { throw this.newIndexOutOfBoundsException(index); } public T set(int index, T element) { T previous = this.get(index); this.items[index] = element; return previous; } @Override public int indexOf(Object object) { return InternalArrayIterate.indexOf(this.items, this.size, object); } @Override public int lastIndexOf(Object object) { return InternalArrayIterate.lastIndexOf(this.items, this.size, object); } public void trimToSize() { if (this.size < this.items.length) { this.transferItemsToNewArrayWithCapacity(this.size); } } /** * Express load factor as 0.25 to trim a collection with more than 25% excess capacity */ public boolean trimToSizeIfGreaterThanPercent(double loadFactor) { double excessCapacity = 1.0 - (double) this.size / (double) this.items.length; if (excessCapacity > loadFactor) { this.trimToSize(); return true; } return false; } public void ensureCapacity(int minCapacity) { int oldCapacity = this.items.length; if (minCapacity > oldCapacity) { int newCapacity = Math.max(this.sizePlusFiftyPercent(oldCapacity), minCapacity); this.transferItemsToNewArrayWithCapacity(newCapacity); } } private void transferItemsToNewArrayWithCapacity(int newCapacity) { this.items = (T[]) this.copyItemsWithNewCapacity(newCapacity); } private Object[] copyItemsWithNewCapacity(int newCapacity) { Object[] newItems = new Object[newCapacity]; System.arraycopy(this.items, 0, newItems, 0, Math.min(this.size, newCapacity)); return newItems; } public FastList<T> with(T element1, T element2) { this.add(element1); this.add(element2); return this; } public FastList<T> with(T element1, T element2, T element3) { this.add(element1); this.add(element2); this.add(element3); return this; } public FastList<T> with(T... elements) { return this.withArrayCopy(elements, 0, elements.length); } public FastList<T> withArrayCopy(T[] elements, int begin, int length) { this.ensureCapacity(this.size + length); System.arraycopy(elements, begin, this.items, this.size, length); this.size += length; return this; } @Override public T getFirst() { return this.isEmpty() ? null : this.items[0]; } @Override public T getLast() { return this.isEmpty() ? null : this.items[this.size() - 1]; } @Override public <V> FastListMultimap<V, T> groupBy(Function<? super T, ? extends V> function) { return this.groupBy(function, FastListMultimap.<V, T>newMultimap()); } @Override public <V, R extends MutableMultimap<V, T>> R groupBy(Function<? super T, ? extends V> function, R target) { return InternalArrayIterate.groupBy(this.items, this.size, function, target); } @Override public <V> FastListMultimap<V, T> groupByEach(Function<? super T, ? extends Iterable<V>> function) { return this.groupByEach(function, FastListMultimap.<V, T>newMultimap()); } @Override public <V, R extends MutableMultimap<V, T>> R groupByEach( Function<? super T, ? extends Iterable<V>> function, R target) { return InternalArrayIterate.groupByEach(this.items, this.size, function, target); } @Override public <K> MutableMap<K, T> groupByUniqueKey(Function<? super T, ? extends K> function) { return this.groupByUniqueKey(function, UnifiedMap.<K, T>newMap()); } @Override public <K, R extends MutableMap<K, T>> R groupByUniqueKey(Function<? super T, ? extends K> function, R target) { return InternalArrayIterate.groupByUniqueKey(this.items, this.size, function, target); } @Override public void appendString(Appendable appendable, String start, String separator, String end) { InternalArrayIterate.appendString(this, this.items, this.size, appendable, start, separator, end); } @Override public MutableList<T> take(int count) { return RandomAccessListIterate.take(this, count); } @Override public MutableList<T> drop(int count) { return RandomAccessListIterate.drop(this, count); } @Override public PartitionFastList<T> partition(Predicate<? super T> predicate) { return InternalArrayIterate.partition(this.items, this.size, predicate); } @Override public <P> PartitionFastList<T> partitionWith(Predicate2<? super T, ? super P> predicate, P parameter) { return InternalArrayIterate.partitionWith(this.items, this.size, predicate, parameter); } @Override public void each(Procedure<? super T> procedure) { for (int i = 0; i < this.size; i++) { procedure.value(this.items[i]); } } public void forEachIf(Predicate<? super T> predicate, Procedure<? super T> procedure) { for (int i = 0; i < this.size; i++) { T item = this.items[i]; if (predicate.accept(item)) { procedure.value(item); } } } @Override public void forEachWithIndex(ObjectIntProcedure<? super T> objectIntProcedure) { InternalArrayIterate.forEachWithIndex(this.items, this.size, objectIntProcedure); } @Override public <P> void forEachWith(Procedure2<? super T, ? super P> procedure, P parameter) { for (int i = 0; i < this.size; i++) { procedure.value(this.items[i], parameter); } } @Override public FastList<T> select(Predicate<? super T> predicate) { return this.select(predicate, FastList.<T>newList()); } @Override public <R extends Collection<T>> R select(Predicate<? super T> predicate, R target) { return InternalArrayIterate.select(this.items, this.size, predicate, target); } @Override public <P> FastList<T> selectWith(Predicate2<? super T, ? super P> predicate, P parameter) { return this.selectWith(predicate, parameter, FastList.<T>newList()); } @Override public <P, R extends Collection<T>> R selectWith( Predicate2<? super T, ? super P> predicate, P parameter, R target) { return InternalArrayIterate.selectWith(this.items, this.size, predicate, parameter, target); } @Override public FastList<T> reject(Predicate<? super T> predicate) { return this.reject(predicate, FastList.<T>newList()); } @Override public <R extends Collection<T>> R reject(Predicate<? super T> predicate, R target) { return InternalArrayIterate.reject(this.items, this.size, predicate, target); } @Override public <P> FastList<T> rejectWith(Predicate2<? super T, ? super P> predicate, P parameter) { return this.rejectWith(predicate, parameter, FastList.<T>newList()); } @Override public <P, R extends Collection<T>> R rejectWith( Predicate2<? super T, ? super P> predicate, P parameter, R target) { return InternalArrayIterate.rejectWith(this.items, this.size, predicate, parameter, target); } @Override public <P> Twin<MutableList<T>> selectAndRejectWith( Predicate2<? super T, ? super P> predicate, P parameter) { return InternalArrayIterate.selectAndRejectWith(this.items, this.size, predicate, parameter); } @Override public <S> FastList<S> selectInstancesOf(Class<S> clazz) { return InternalArrayIterate.selectInstancesOf(this.items, this.size, clazz); } @Override public boolean removeIf(Predicate<? super T> predicate) { int currentFilledIndex = 0; for (int i = 0; i < this.size; i++) { T item = this.items[i]; if (!predicate.accept(item)) { // keep it if (currentFilledIndex != i) { this.items[currentFilledIndex] = item; } currentFilledIndex++; } } boolean changed = currentFilledIndex < this.size; this.wipeAndResetTheEnd(currentFilledIndex); return changed; } private void wipeAndResetTheEnd(int newCurrentFilledIndex) { for (int i = newCurrentFilledIndex; i < this.size; i++) { this.items[i] = null; } this.size = newCurrentFilledIndex; } @Override public <P> boolean removeIfWith(Predicate2<? super T, ? super P> predicate, P parameter) { int currentFilledIndex = 0; for (int i = 0; i < this.size; i++) { T item = this.items[i]; if (!predicate.accept(item, parameter)) { // keep it if (currentFilledIndex != i) { this.items[currentFilledIndex] = item; } currentFilledIndex++; } } boolean changed = currentFilledIndex < this.size; this.wipeAndResetTheEnd(currentFilledIndex); return changed; } @Override public <V> FastList<V> collect(Function<? super T, ? extends V> function) { return this.collect(function, FastList.<V>newList(this.size())); } @Override public MutableBooleanList collectBoolean(BooleanFunction<? super T> booleanFunction) { return this.collectBoolean(booleanFunction, new BooleanArrayList(this.size)); } @Override public <R extends MutableBooleanCollection> R collectBoolean(BooleanFunction<? super T> booleanFunction, R target) { for (int i = 0; i < this.size; i++) { target.add(booleanFunction.booleanValueOf(this.items[i])); } return target; } @Override public MutableByteList collectByte(ByteFunction<? super T> byteFunction) { return this.collectByte(byteFunction, new ByteArrayList(this.size)); } @Override public <R extends MutableByteCollection> R collectByte(ByteFunction<? super T> byteFunction, R target) { for (int i = 0; i < this.size; i++) { target.add(byteFunction.byteValueOf(this.items[i])); } return target; } @Override public MutableCharList collectChar(CharFunction<? super T> charFunction) { return this.collectChar(charFunction, new CharArrayList(this.size)); } @Override public <R extends MutableCharCollection> R collectChar(CharFunction<? super T> charFunction, R target) { for (int i = 0; i < this.size; i++) { target.add(charFunction.charValueOf(this.items[i])); } return target; } @Override public MutableDoubleList collectDouble(DoubleFunction<? super T> doubleFunction) { return this.collectDouble(doubleFunction, new DoubleArrayList(this.size)); } @Override public <R extends MutableDoubleCollection> R collectDouble(DoubleFunction<? super T> doubleFunction, R target) { for (int i = 0; i < this.size; i++) { target.add(doubleFunction.doubleValueOf(this.items[i])); } return target; } @Override public MutableFloatList collectFloat(FloatFunction<? super T> floatFunction) { return this.collectFloat(floatFunction, new FloatArrayList(this.size)); } @Override public <R extends MutableFloatCollection> R collectFloat(FloatFunction<? super T> floatFunction, R target) { for (int i = 0; i < this.size; i++) { target.add(floatFunction.floatValueOf(this.items[i])); } return target; } @Override public MutableIntList collectInt(IntFunction<? super T> intFunction) { return this.collectInt(intFunction, new IntArrayList(this.size)); } @Override public <R extends MutableIntCollection> R collectInt(IntFunction<? super T> intFunction, R target) { for (int i = 0; i < this.size; i++) { target.add(intFunction.intValueOf(this.items[i])); } return target; } @Override public MutableLongList collectLong(LongFunction<? super T> longFunction) { return this.collectLong(longFunction, new LongArrayList(this.size)); } @Override public <R extends MutableLongCollection> R collectLong(LongFunction<? super T> longFunction, R target) { for (int i = 0; i < this.size; i++) { target.add(longFunction.longValueOf(this.items[i])); } return target; } @Override public MutableShortList collectShort(ShortFunction<? super T> shortFunction) { return this.collectShort(shortFunction, new ShortArrayList(this.size)); } @Override public <R extends MutableShortCollection> R collectShort(ShortFunction<? super T> shortFunction, R target) { for (int i = 0; i < this.size; i++) { target.add(shortFunction.shortValueOf(this.items[i])); } return target; } @Override public <V, R extends Collection<V>> R collect(Function<? super T, ? extends V> function, R target) { return InternalArrayIterate.collect(this.items, this.size, function, target); } @Override public <V> FastList<V> flatCollect(Function<? super T, ? extends Iterable<V>> function) { return this.flatCollect(function, FastList.<V>newList(this.size())); } @Override public <V, R extends Collection<V>> R flatCollect( Function<? super T, ? extends Iterable<V>> function, R target) { return InternalArrayIterate.flatCollect(this.items, this.size, function, target); } @Override public <P, V> FastList<V> collectWith(Function2<? super T, ? super P, ? extends V> function, P parameter) { return this.collectWith(function, parameter, FastList.<V>newList(this.size())); } @Override public <P, V, R extends Collection<V>> R collectWith( Function2<? super T, ? super P, ? extends V> function, P parameter, R target) { return InternalArrayIterate.collectWith(this.items, this.size, function, parameter, target); } @Override public <V> FastList<V> collectIf( Predicate<? super T> predicate, Function<? super T, ? extends V> function) { return this.collectIf(predicate, function, FastList.<V>newList()); } @Override public <V, R extends Collection<V>> R collectIf( Predicate<? super T> predicate, Function<? super T, ? extends V> function, R target) { return InternalArrayIterate.collectIf(this.items, this.size, predicate, function, target); } @Override public T detect(Predicate<? super T> predicate) { return InternalArrayIterate.detect(this.items, this.size, predicate); } @Override public T detectIfNone(Predicate<? super T> predicate, Function0<? extends T> defaultValueBlock) { T result = this.detect(predicate); return result == null ? defaultValueBlock.value() : result; } @Override public int detectIndex(Predicate<? super T> predicate) { return InternalArrayIterate.detectIndex(this.items, this.size, predicate); } @Override public int detectLastIndex(Predicate<? super T> predicate) { return InternalArrayIterate.detectLastIndex(this.items, this.size, predicate); } @Override public T min(Comparator<? super T> comparator) { return InternalArrayIterate.min(this.items, this.size, comparator); } @Override public T max(Comparator<? super T> comparator) { return InternalArrayIterate.max(this.items, this.size, comparator); } @Override public T min() { return InternalArrayIterate.min(this.items, this.size); } @Override public T max() { return InternalArrayIterate.max(this.items, this.size); } @Override public <V extends Comparable<? super V>> T minBy(Function<? super T, ? extends V> function) { return InternalArrayIterate.minBy(this.items, this.size, function); } @Override public <V extends Comparable<? super V>> T maxBy(Function<? super T, ? extends V> function) { return InternalArrayIterate.maxBy(this.items, this.size, function); } @Override public <P> T detectWith(Predicate2<? super T, ? super P> predicate, P parameter) { return InternalArrayIterate.detectWith(this.items, this.size, predicate, parameter); } @Override public <P> T detectWithIfNone( Predicate2<? super T, ? super P> predicate, P parameter, Function0<? extends T> defaultValueBlock) { T result = this.detectWith(predicate, parameter); return result == null ? defaultValueBlock.value() : result; } public T get(int index) { if (index < this.size) { return this.items[index]; } throw this.newIndexOutOfBoundsException(index); } private IndexOutOfBoundsException newIndexOutOfBoundsException(int index) { return new IndexOutOfBoundsException("Index: " + index + " Size: " + this.size); } @Override public boolean add(T newItem) { if (this.items.length == this.size) { this.ensureCapacityForAdd(); } this.items[this.size++] = newItem; return true; } private void ensureCapacityForAdd() { if (this.items == DEFAULT_SIZED_EMPTY_ARRAY) { this.items = (T[]) new Object[10]; } else { this.transferItemsToNewArrayWithCapacity(this.sizePlusFiftyPercent(this.size)); } } public void add(int index, T element) { if (index > -1 && index < this.size) { this.addAtIndex(index, element); } else if (index == this.size) { this.add(element); } else { this.throwOutOfBounds(index); } } private void addAtIndex(int index, T element) { int oldSize = this.size++; if (this.items.length == oldSize) { T[] newItems = (T[]) new Object[this.sizePlusFiftyPercent(oldSize)]; if (index > 0) { System.arraycopy(this.items, 0, newItems, 0, index); } System.arraycopy(this.items, index, newItems, index + 1, oldSize - index); this.items = newItems; } else { System.arraycopy(this.items, index, this.items, index + 1, oldSize - index); } this.items[index] = element; } private int sizePlusFiftyPercent(int oldSize) { int result = oldSize + (oldSize >> 1) + 1; return result < oldSize ? MAXIMUM_ARRAY_SIZE : result; } public T remove(int index) { T previous = this.get(index); int totalOffset = this.size - index - 1; if (totalOffset > 0) { System.arraycopy(this.items, index + 1, this.items, index, totalOffset); } this.items[--this.size] = null; return previous; } @Override public boolean remove(Object object) { int index = this.indexOf(object); if (index >= 0) { this.remove(index); return true; } return false; } public boolean addAll(int index, Collection<? extends T> source) { if (index > this.size || index < 0) { this.throwOutOfBounds(index); } if (source.isEmpty()) { return false; } if (source.getClass() == FastList.class) { this.addAllFastListAtIndex((FastList<T>) source, index); } else if (source.getClass() == ArrayList.class) { this.addAllArrayListAtIndex((ArrayList<T>) source, index); } else if (source instanceof List && source instanceof RandomAccess) { this.addAllRandomAccessListAtIndex((List<T>) source, index); } else { this.addAllCollectionAtIndex(source, index); } return true; } private void addAllFastListAtIndex(FastList<T> source, int index) { int sourceSize = source.size(); int newSize = this.size + sourceSize; this.ensureCapacity(newSize); this.shiftElementsAtIndex(index, sourceSize); System.arraycopy(source.items, 0, this.items, index, sourceSize); this.size = newSize; } private void addAllArrayListAtIndex(ArrayList<T> source, int index) { int sourceSize = source.size(); int newSize = this.size + sourceSize; this.ensureCapacity(newSize); this.shiftElementsAtIndex(index, sourceSize); ArrayListIterate.toArray(source, this.items, index, sourceSize); this.size = newSize; } private void addAllRandomAccessListAtIndex(List<T> source, int index) { int sourceSize = source.size(); int newSize = this.size + sourceSize; this.ensureCapacity(newSize); this.shiftElementsAtIndex(index, sourceSize); RandomAccessListIterate.toArray(source, this.items, index, sourceSize); this.size = newSize; } private void addAllCollectionAtIndex(Collection<? extends T> source, int index) { Object[] newItems = source.toArray(); int sourceSize = newItems.length; int newSize = this.size + sourceSize; this.ensureCapacity(newSize); this.shiftElementsAtIndex(index, sourceSize); this.size = newSize; System.arraycopy(newItems, 0, this.items, index, sourceSize); } private void shiftElementsAtIndex(int index, int sourceSize) { int numberToMove = this.size - index; if (numberToMove > 0) { System.arraycopy(this.items, index, this.items, index + sourceSize, numberToMove); } } public int size() { return this.size; } @Override public int count(Predicate<? super T> predicate) { return InternalArrayIterate.count(this.items, this.size, predicate); } @Override public <P> int countWith(Predicate2<? super T, ? super P> predicate, P parameter) { return InternalArrayIterate.countWith(this.items, this.size, predicate, parameter); } @Override public <S> boolean corresponds(OrderedIterable<S> other, Predicate2<? super T, ? super S> predicate) { return InternalArrayIterate.corresponds(this.items, this.size, other, predicate); } @Override public boolean anySatisfy(Predicate<? super T> predicate) { return InternalArrayIterate.anySatisfy(this.items, this.size, predicate); } @Override public <P> boolean anySatisfyWith(Predicate2<? super T, ? super P> predicate, P parameter) { return InternalArrayIterate.anySatisfyWith(this.items, this.size, predicate, parameter); } @Override public boolean allSatisfy(Predicate<? super T> predicate) { return InternalArrayIterate.allSatisfy(this.items, this.size, predicate); } @Override public <P> boolean allSatisfyWith(Predicate2<? super T, ? super P> predicate, P parameter) { return InternalArrayIterate.allSatisfyWith(this.items, this.size, predicate, parameter); } @Override public boolean noneSatisfy(Predicate<? super T> predicate) { return InternalArrayIterate.noneSatisfy(this.items, this.size, predicate); } @Override public <P> boolean noneSatisfyWith(Predicate2<? super T, ? super P> predicate, P parameter) { return InternalArrayIterate.noneSatisfyWith(this.items, this.size, predicate, parameter); } @Override public <IV> IV injectInto(IV injectedValue, Function2<? super IV, ? super T, ? extends IV> function) { IV result = injectedValue; for (int i = 0; i < this.size; i++) { result = function.value(result, this.items[i]); } return result; } @Override public int injectInto(int injectedValue, IntObjectToIntFunction<? super T> function) { int result = injectedValue; for (int i = 0; i < this.size; i++) { result = function.intValueOf(result, this.items[i]); } return result; } @Override public long injectInto(long injectedValue, LongObjectToLongFunction<? super T> function) { long result = injectedValue; for (int i = 0; i < this.size; i++) { result = function.longValueOf(result, this.items[i]); } return result; } @Override public double injectInto(double injectedValue, DoubleObjectToDoubleFunction<? super T> function) { double result = injectedValue; for (int i = 0; i < this.size; i++) { result = function.doubleValueOf(result, this.items[i]); } return result; } @Override public float injectInto(float injectedValue, FloatObjectToFloatFunction<? super T> function) { float result = injectedValue; for (int i = 0; i < this.size; i++) { result = function.floatValueOf(result, this.items[i]); } return result; } @Override public MutableList<T> distinct() { return InternalArrayIterate.distinct(this.items, this.size); } @Override public MutableList<T> distinct(HashingStrategy<? super T> hashingStrategy) { return InternalArrayIterate.distinct(this.items, this.size, hashingStrategy); } @Override public long sumOfInt(IntFunction<? super T> function) { return InternalArrayIterate.sumOfInt(this.items, this.size, function); } @Override public long sumOfLong(LongFunction<? super T> function) { return InternalArrayIterate.sumOfLong(this.items, this.size, function); } @Override public double sumOfFloat(FloatFunction<? super T> function) { return InternalArrayIterate.sumOfFloat(this.items, this.size, function); } @Override public double sumOfDouble(DoubleFunction<? super T> function) { return InternalArrayIterate.sumOfDouble(this.items, this.size, function); } @Override public <V> ObjectLongMap<V> sumByInt(Function<T, V> groupBy, IntFunction<? super T> function) { return InternalArrayIterate.sumByInt(this.items, this.size, groupBy, function); } @Override public <V> ObjectLongMap<V> sumByLong(Function<T, V> groupBy, LongFunction<? super T> function) { return InternalArrayIterate.sumByLong(this.items, this.size, groupBy, function); } @Override public <V> ObjectDoubleMap<V> sumByFloat(Function<T, V> groupBy, FloatFunction<? super T> function) { return InternalArrayIterate.sumByFloat(this.items, this.size, groupBy, function); } @Override public <V> ObjectDoubleMap<V> sumByDouble(Function<T, V> groupBy, DoubleFunction<? super T> function) { return InternalArrayIterate.sumByDouble(this.items, this.size, groupBy, function); } @Override public <IV, P> IV injectIntoWith( IV injectValue, Function3<? super IV, ? super T, ? super P, ? extends IV> function, P parameter) { IV result = injectValue; for (int i = 0; i < this.size; i++) { result = function.value(result, this.items[i], parameter); } return result; } @Override public FastList<T> toList() { return FastList.newList(this); } @Override public FastList<T> toSortedList() { return this.toSortedList(Comparators.naturalOrder()); } @Override public FastList<T> toSortedList(Comparator<? super T> comparator) { return FastList.newList(this).sortThis(comparator); } @Override public MutableList<T> takeWhile(Predicate<? super T> predicate) { int endIndex = this.detectNotIndex(predicate); T[] result = (T[]) new Object[endIndex]; System.arraycopy(this.items, 0, result, 0, endIndex); return FastList.newListWith(result); } @Override public MutableList<T> dropWhile(Predicate<? super T> predicate) { int startIndex = this.detectNotIndex(predicate); int resultSize = this.size() - startIndex; T[] result = (T[]) new Object[resultSize]; System.arraycopy(this.items, startIndex, result, 0, resultSize); return FastList.newListWith(result); } @Override public PartitionMutableList<T> partitionWhile(Predicate<? super T> predicate) { PartitionMutableList<T> result = new PartitionFastList<T>(); FastList<T> selected = (FastList<T>) result.getSelected(); FastList<T> rejected = (FastList<T>) result.getRejected(); int partitionIndex = this.detectNotIndex(predicate); int rejectedSize = this.size() - partitionIndex; selected.withArrayCopy(this.items, 0, partitionIndex); rejected.withArrayCopy(this.items, partitionIndex, rejectedSize); return result; } private int detectNotIndex(Predicate<? super T> predicate) { for (int index = 0; index < this.size; index++) { if (!predicate.accept(this.items[index])) { return index; } } return this.size; } @Override public boolean equals(Object that) { if (that == this) { return true; } if (!(that instanceof List)) { return false; } if (that instanceof FastList) { return this.fastListEquals((FastList<?>) that); } return InternalArrayIterate.arrayEqualsList(this.items, this.size, (List<?>) that); } public boolean fastListEquals(FastList<?> that) { if (this.size != that.size) { return false; } for (int i = 0; i < this.size; i++) { if (!Comparators.nullSafeEquals(this.items[i], that.items[i])) { return false; } } return true; } @Override public int hashCode() { int hashCode = 1; for (int i = 0; i < this.size; i++) { T item = this.items[i]; hashCode = 31 * hashCode + (item == null ? 0 : item.hashCode()); } return hashCode; } public void writeExternal(ObjectOutput out) throws IOException { out.writeInt(this.size()); for (int i = 0; i < this.size; i++) { out.writeObject(this.items[i]); } } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.size = in.readInt(); this.items = (T[]) new Object[this.size]; for (int i = 0; i < this.size; i++) { this.items[i] = (T) in.readObject(); } } }