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

com.gs.collections.impl.list.immutable.AbstractImmutableList Maven / Gradle / Ivy

Go to download

GS Collections is a collections framework for Java. It has JDK-compatible List, Set and Map implementations with a rich API and set of utility classes that work with any JDK compatible Collections, Arrays, Maps or Strings. The iteration protocol was inspired by the Smalltalk collection framework.

There is a newer version: 7.0.3
Show newest version
/*
 * 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.immutable;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.RandomAccess;
import java.util.concurrent.ExecutorService;

import com.gs.collections.api.block.HashingStrategy;
import com.gs.collections.api.block.function.Function;
import com.gs.collections.api.block.function.Function2;
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.MutableCollection;
import com.gs.collections.api.list.ImmutableList;
import com.gs.collections.api.list.MutableList;
import com.gs.collections.api.list.ParallelListIterable;
import com.gs.collections.api.list.primitive.ImmutableBooleanList;
import com.gs.collections.api.list.primitive.ImmutableByteList;
import com.gs.collections.api.list.primitive.ImmutableCharList;
import com.gs.collections.api.list.primitive.ImmutableDoubleList;
import com.gs.collections.api.list.primitive.ImmutableFloatList;
import com.gs.collections.api.list.primitive.ImmutableIntList;
import com.gs.collections.api.list.primitive.ImmutableLongList;
import com.gs.collections.api.list.primitive.ImmutableShortList;
import com.gs.collections.api.multimap.MutableMultimap;
import com.gs.collections.api.multimap.list.ImmutableListMultimap;
import com.gs.collections.api.ordered.OrderedIterable;
import com.gs.collections.api.partition.list.PartitionImmutableList;
import com.gs.collections.api.stack.MutableStack;
import com.gs.collections.api.tuple.Pair;
import com.gs.collections.impl.block.factory.Comparators;
import com.gs.collections.impl.block.factory.Functions;
import com.gs.collections.impl.block.factory.HashingStrategies;
import com.gs.collections.impl.block.procedure.CollectIfProcedure;
import com.gs.collections.impl.block.procedure.CollectProcedure;
import com.gs.collections.impl.block.procedure.FlatCollectProcedure;
import com.gs.collections.impl.block.procedure.RejectProcedure;
import com.gs.collections.impl.block.procedure.SelectInstancesOfProcedure;
import com.gs.collections.impl.block.procedure.SelectProcedure;
import com.gs.collections.impl.block.procedure.primitive.CollectBooleanProcedure;
import com.gs.collections.impl.block.procedure.primitive.CollectByteProcedure;
import com.gs.collections.impl.block.procedure.primitive.CollectCharProcedure;
import com.gs.collections.impl.block.procedure.primitive.CollectDoubleProcedure;
import com.gs.collections.impl.block.procedure.primitive.CollectFloatProcedure;
import com.gs.collections.impl.block.procedure.primitive.CollectIntProcedure;
import com.gs.collections.impl.block.procedure.primitive.CollectLongProcedure;
import com.gs.collections.impl.block.procedure.primitive.CollectShortProcedure;
import com.gs.collections.impl.collection.immutable.AbstractImmutableCollection;
import com.gs.collections.impl.factory.Lists;
import com.gs.collections.impl.lazy.ReverseIterable;
import com.gs.collections.impl.lazy.parallel.list.ListIterableParallelIterable;
import com.gs.collections.impl.list.mutable.FastList;
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.multimap.list.FastListMultimap;
import com.gs.collections.impl.stack.mutable.ArrayStack;
import com.gs.collections.impl.utility.Iterate;
import com.gs.collections.impl.utility.ListIterate;
import com.gs.collections.impl.utility.OrderedIterate;
import net.jcip.annotations.Immutable;

/**
 * This class is the parent class for all ImmutableLists.  All implementations of ImmutableList must implement the List
 * interface so anArrayList.equals(anImmutableList) can return true when the contents and order are the same.
 */
@Immutable
abstract class AbstractImmutableList
        extends AbstractImmutableCollection
        implements ImmutableList, List
{
    public List castToList()
    {
        return this;
    }

    @Override
    public boolean equals(Object that)
    {
        if (that == this)
        {
            return true;
        }
        if (!(that instanceof List))
        {
            return false;
        }
        List list = (List) that;
        if (this.size() != list.size())
        {
            return false;
        }
        if (list instanceof RandomAccess)
        {
            return this.randomAccessListEquals(list);
        }
        return this.regularListEquals(list);
    }

    private boolean randomAccessListEquals(List list)
    {
        int localSize = this.size();
        for (int i = 0; i < localSize; i++)
        {
            if (!Comparators.nullSafeEquals(this.get(i), list.get(i)))
            {
                return false;
            }
        }
        return true;
    }

    protected boolean regularListEquals(List list)
    {
        Iterator iterator = list.iterator();
        int localSize = this.size();
        for (int i = 0; i < localSize; i++)
        {
            if (!iterator.hasNext())
            {
                return false;
            }
            if (!Comparators.nullSafeEquals(this.get(i), iterator.next()))
            {
                return false;
            }
        }
        return !iterator.hasNext();
    }

    @Override
    public int hashCode()
    {
        int hashCode = 1;
        int localSize = this.size();
        for (int i = 0; i < localSize; i++)
        {
            T item = this.get(i);
            hashCode = 31 * hashCode + (item == null ? 0 : item.hashCode());
        }
        return hashCode;
    }

    public ImmutableList newWithout(T element)
    {
        int indexToRemove = this.indexOf(element);
        if (indexToRemove < 0)
        {
            return this;
        }
        T[] results = (T[]) new Object[this.size() - 1];
        int currentIndex = 0;
        for (int i = 0; i < this.size(); i++)
        {
            T item = this.get(i);
            if (i != indexToRemove)
            {
                results[currentIndex++] = item;
            }
        }
        return Lists.immutable.with(results);
    }

    public ImmutableList newWithAll(Iterable elements)
    {
        final int oldSize = this.size();
        int newSize = Iterate.sizeOf(elements);
        final T[] array = (T[]) new Object[oldSize + newSize];
        this.toArray(array);
        Iterate.forEachWithIndex(elements, new ObjectIntProcedure()
        {
            public void value(T each, int index)
            {
                array[oldSize + index] = each;
            }
        });
        return Lists.immutable.with(array);
    }

    public ImmutableList newWithoutAll(Iterable elements)
    {
        FastList result = FastList.newListWith((T[]) this.toArray());
        this.removeAllFrom(elements, result);
        return result.toImmutable();
    }

    public T getFirst()
    {
        return this.isEmpty() ? null : this.get(0);
    }

    public T getLast()
    {
        return this.isEmpty() ? null : this.get(this.size() - 1);
    }

    public ImmutableList select(Predicate predicate)
    {
        MutableList result = Lists.mutable.empty();
        this.forEach(new SelectProcedure(predicate, result));
        return result.toImmutable();
    }

    public 

ImmutableList selectWith(Predicate2 predicate, P parameter) { return ListIterate.selectWith(this, predicate, parameter, FastList.newList()).toImmutable(); } @Override public > R selectWith( Predicate2 predicate, P parameter, R target) { return ListIterate.selectWith(this, predicate, parameter, target); } public ImmutableList reject(Predicate predicate) { MutableList result = Lists.mutable.empty(); this.forEach(new RejectProcedure(predicate, result)); return result.toImmutable(); } public

ImmutableList rejectWith(Predicate2 predicate, P parameter) { return ListIterate.rejectWith(this, predicate, parameter, FastList.newList()).toImmutable(); } @Override public > R rejectWith( Predicate2 predicate, P parameter, R target) { return ListIterate.rejectWith(this, predicate, parameter, target); } public PartitionImmutableList partition(Predicate predicate) { return ListIterate.partition(this, predicate).toImmutable(); } public

PartitionImmutableList partitionWith(Predicate2 predicate, P parameter) { return ListIterate.partitionWith(this, predicate, parameter).toImmutable(); } public ImmutableList selectInstancesOf(Class clazz) { FastList result = FastList.newList(this.size()); this.forEach(new SelectInstancesOfProcedure(clazz, result)); return result.toImmutable(); } public ImmutableList collect(Function function) { MutableList result = Lists.mutable.empty(); this.forEach(new CollectProcedure(function, result)); return result.toImmutable(); } public ImmutableBooleanList collectBoolean(BooleanFunction booleanFunction) { BooleanArrayList result = new BooleanArrayList(this.size()); this.forEach(new CollectBooleanProcedure(booleanFunction, result)); return result.toImmutable(); } public ImmutableByteList collectByte(ByteFunction byteFunction) { ByteArrayList result = new ByteArrayList(this.size()); this.forEach(new CollectByteProcedure(byteFunction, result)); return result.toImmutable(); } public ImmutableCharList collectChar(CharFunction charFunction) { CharArrayList result = new CharArrayList(this.size()); this.forEach(new CollectCharProcedure(charFunction, result)); return result.toImmutable(); } public ImmutableDoubleList collectDouble(DoubleFunction doubleFunction) { DoubleArrayList result = new DoubleArrayList(this.size()); this.forEach(new CollectDoubleProcedure(doubleFunction, result)); return result.toImmutable(); } public ImmutableFloatList collectFloat(FloatFunction floatFunction) { FloatArrayList result = new FloatArrayList(this.size()); this.forEach(new CollectFloatProcedure(floatFunction, result)); return result.toImmutable(); } public ImmutableIntList collectInt(IntFunction intFunction) { IntArrayList result = new IntArrayList(this.size()); this.forEach(new CollectIntProcedure(intFunction, result)); return result.toImmutable(); } public ImmutableLongList collectLong(LongFunction longFunction) { LongArrayList result = new LongArrayList(this.size()); this.forEach(new CollectLongProcedure(longFunction, result)); return result.toImmutable(); } public ImmutableShortList collectShort(ShortFunction shortFunction) { ShortArrayList result = new ShortArrayList(this.size()); this.forEach(new CollectShortProcedure(shortFunction, result)); return result.toImmutable(); } public ImmutableList collectWith(Function2 function, P parameter) { return this.collect(Functions.bind(function, parameter)); } public ImmutableList collectIf( Predicate predicate, Function function) { MutableList result = Lists.mutable.empty(); this.forEach(new CollectIfProcedure(result, function, predicate)); return result.toImmutable(); } @Override public > R collectWith( Function2 function, P parameter, R target) { return ListIterate.collectWith(this, function, parameter, target); } public ImmutableList flatCollect(Function> function) { MutableList result = Lists.mutable.empty(); this.forEach(new FlatCollectProcedure(function, result)); return result.toImmutable(); } @Override public > R flatCollect( Function> function, R target) { return ListIterate.flatCollect(this, function, target); } public int detectIndex(Predicate predicate) { return ListIterate.detectIndex(this, predicate); } public int detectLastIndex(Predicate predicate) { return ListIterate.detectLastIndex(this, predicate); } @Override public int count(Predicate predicate) { int count = 0; int size = this.size(); for (int i = 0; i < size; i++) { if (predicate.accept(this.get(i))) { count++; } } return count; } @Override public IV injectInto(IV injectedValue, Function2 function) { return ListIterate.injectInto(injectedValue, this, function); } @Override public int injectInto(int injectedValue, IntObjectToIntFunction function) { return ListIterate.injectInto(injectedValue, this, function); } @Override public long injectInto(long injectedValue, LongObjectToLongFunction function) { return ListIterate.injectInto(injectedValue, this, function); } @Override public double injectInto(double injectedValue, DoubleObjectToDoubleFunction function) { return ListIterate.injectInto(injectedValue, this, function); } @Override public float injectInto(float injectedValue, FloatObjectToFloatFunction function) { return ListIterate.injectInto(injectedValue, this, function); } @Override public long sumOfInt(IntFunction function) { return ListIterate.sumOfInt(this, function); } @Override public long sumOfLong(LongFunction function) { return ListIterate.sumOfLong(this, function); } @Override public double sumOfFloat(FloatFunction function) { return ListIterate.sumOfFloat(this, function); } @Override public double sumOfDouble(DoubleFunction function) { return ListIterate.sumOfDouble(this, function); } public ImmutableList tap(Procedure procedure) { this.forEach(procedure); return this; } public boolean corresponds(OrderedIterable other, Predicate2 predicate) { return OrderedIterate.corresponds(this, other, predicate); } @Override public void forEachWithIndex(ObjectIntProcedure objectIntProcedure) { int localSize = this.size(); for (int i = 0; i < localSize; i++) { T each = this.get(i); objectIntProcedure.value(each, i); } } @Override public

void forEachWith(Procedure2 procedure, P parameter) { int localSize = this.size(); for (int i = 0; i < localSize; i++) { T each = this.get(i); procedure.value(each, parameter); } } public void forEach( int from, int to, Procedure procedure) { ListIterate.rangeCheck(from, to, this.size()); if (from <= to) { for (int i = from; i <= to; i++) { procedure.value(this.get(i)); } } else { for (int i = from; i >= to; i--) { procedure.value(this.get(i)); } } } public void forEachWithIndex( int from, int to, ObjectIntProcedure objectIntProcedure) { ListIterate.rangeCheck(from, to, this.size()); if (from <= to) { for (int i = from; i <= to; i++) { objectIntProcedure.value(this.get(i), i); } } else { for (int i = from; i >= to; i--) { objectIntProcedure.value(this.get(i), i); } } } public void reverseForEach(Procedure procedure) { if (this.notEmpty()) { this.forEach(this.size() - 1, 0, procedure); } } public int indexOf(Object object) { int n = this.size(); if (object == null) { for (int i = 0; i < n; i++) { if (this.get(i) == null) { return i; } } } else { for (int i = 0; i < n; i++) { if (object.equals(this.get(i))) { return i; } } } return -1; } public int lastIndexOf(Object object) { int n = this.size() - 1; if (object == null) { for (int i = n; i >= 0; i--) { if (this.get(i) == null) { return i; } } } else { for (int i = n; i >= 0; i--) { if (object.equals(this.get(i))) { return i; } } } return -1; } public Iterator iterator() { return this.listIterator(0); } public boolean addAll(int index, Collection collection) { throw new UnsupportedOperationException("Cannot call addAll() on " + this.getClass().getSimpleName()); } public T set(int index, T element) { throw new UnsupportedOperationException("Cannot call set() on " + this.getClass().getSimpleName()); } public void add(int index, T element) { throw new UnsupportedOperationException("Cannot call add() on " + this.getClass().getSimpleName()); } public T remove(int index) { throw new UnsupportedOperationException("Cannot call remove() on " + this.getClass().getSimpleName()); } public ListIterator listIterator() { return new ImmutableListIterator(this, 0); } public ListIterator listIterator(int index) { if (index < 0 || index > this.size()) { throw new IndexOutOfBoundsException("Index: " + index); } return new ImmutableListIterator(this, index); } public ImmutableSubList subList(int fromIndex, int toIndex) { return new ImmutableSubList(this, fromIndex, toIndex); } public ImmutableList distinct() { return ListIterate.distinct(this.castToList()).toImmutable(); } public ImmutableList distinct(HashingStrategy hashingStrategy) { return ListIterate.distinct(this.castToList(), hashingStrategy).toImmutable(); } @Override public void appendString(Appendable appendable, String start, String separator, String end) { ListIterate.appendString(this, appendable, start, separator, end); } public ImmutableListMultimap groupBy(Function function) { return this.groupBy(function, FastListMultimap.newMultimap()).toImmutable(); } @Override public > R groupBy( Function function, R target) { return ListIterate.groupBy(this, function, target); } public ImmutableListMultimap groupByEach(Function> function) { return this.groupByEach(function, FastListMultimap.newMultimap()).toImmutable(); } @Override public > R groupByEach( Function> function, R target) { return ListIterate.groupByEach(this, function, target); } @Override public T min(Comparator comparator) { return ListIterate.min(this, comparator); } @Override public T max(Comparator comparator) { return ListIterate.max(this, comparator); } @Override public T min() { return ListIterate.min(this); } @Override public T max() { return ListIterate.max(this); } @Override public > T minBy(Function function) { return ListIterate.minBy(this, function); } @Override public > T maxBy(Function function) { return ListIterate.maxBy(this, function); } public ImmutableList> zip(Iterable that) { return this.zip(that, FastList.>newList()).toImmutable(); } public ImmutableList> zipWithIndex() { return this.zipWithIndex(FastList.>newList()).toImmutable(); } public ImmutableList take(int count) { if (count >= this.size()) { return this; } return ListIterate.take(this, count).toImmutable(); } public ImmutableList takeWhile(Predicate predicate) { return ListIterate.takeWhile(this, predicate).toImmutable(); } public ImmutableList drop(int count) { if (count == 0) { return this; } return ListIterate.drop(this, count).toImmutable(); } public ImmutableList dropWhile(Predicate predicate) { return ListIterate.dropWhile(this, predicate).toImmutable(); } public PartitionImmutableList partitionWhile(Predicate predicate) { return ListIterate.partitionWhile(this, predicate).toImmutable(); } @Override protected MutableCollection newMutable(int size) { return FastList.newList(size); } public MutableStack toStack() { return ArrayStack.newStack(this); } public ReverseIterable asReversed() { return ReverseIterable.adapt(this); } public ImmutableList toReversed() { return Lists.immutable.withAll(this.asReversed()); } public ParallelListIterable asParallel(ExecutorService executorService, int batchSize) { return new ListIterableParallelIterable(this, executorService, batchSize); } public int binarySearch(T key, Comparator comparator) { return Collections.binarySearch(this, key, comparator); } public int binarySearch(T key) { return Collections.binarySearch((List>) this, key); } public ImmutableList toImmutable() { return this; } protected static class ImmutableSubList extends AbstractImmutableList implements Serializable, RandomAccess { // Not important since it uses writeReplace() private static final long serialVersionUID = 1L; private final ImmutableList original; private final int offset; private final int size; protected ImmutableSubList(ImmutableList list, int fromIndex, int toIndex) { if (fromIndex < 0) { throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); } if (toIndex > list.size()) { throw new IndexOutOfBoundsException("toIndex = " + toIndex); } if (fromIndex > toIndex) { throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ')'); } this.original = list; this.offset = fromIndex; this.size = toIndex - fromIndex; } public T get(int index) { this.checkIfOutOfBounds(index); return this.original.get(index + this.offset); } public int size() { return this.size; } public ImmutableList newWith(T newItem) { int oldSize = this.size(); T[] array = (T[]) new Object[oldSize + 1]; this.toArray(array); array[oldSize] = newItem; return Lists.immutable.with(array); } protected Object writeReplace() { return Lists.immutable.withAll(this); } @Override public Iterator iterator() { return this.listIterator(0); } @Override public ImmutableSubList subList(int fromIndex, int toIndex) { if (fromIndex < 0) { throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); } if (toIndex > this.size()) { throw new IndexOutOfBoundsException("toIndex = " + toIndex); } if (fromIndex > toIndex) { throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ')'); } return new ImmutableSubList(this.original, this.offset + fromIndex, this.offset + toIndex); } private void checkIfOutOfBounds(int index) { if (index >= this.size || index < 0) { throw new IndexOutOfBoundsException("Index: " + index + " Size: " + this.size); } } @Override public T getFirst() { return this.isEmpty() ? null : this.original.get(this.offset); } @Override public T getLast() { return this.isEmpty() ? null : this.original.get(this.offset + this.size - 1); } @Override public MutableStack toStack() { return ArrayStack.newStack(this); } public void each(Procedure procedure) { ListIterate.forEach(this, procedure); } @Override public void forEachWithIndex(ObjectIntProcedure objectIntProcedure) { ListIterate.forEachWithIndex(this, objectIntProcedure); } @Override public

void forEachWith(Procedure2 procedure, P parameter) { ListIterate.forEachWith(this, procedure, parameter); } } }