com.gs.collections.impl.list.mutable.CompositeFastList Maven / Gradle / Ivy
Show all versions of gs-collections Show documentation
/*
* 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.Serializable;
import java.lang.reflect.Array;
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.NoSuchElementException;
import java.util.concurrent.ExecutorService;
import com.gs.collections.api.block.function.Function;
import com.gs.collections.api.block.function.Function2;
import com.gs.collections.api.block.function.primitive.DoubleObjectToDoubleFunction;
import com.gs.collections.api.block.function.primitive.FloatObjectToFloatFunction;
import com.gs.collections.api.block.function.primitive.IntObjectToIntFunction;
import com.gs.collections.api.block.function.primitive.LongObjectToLongFunction;
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.list.MutableList;
import com.gs.collections.api.list.ParallelListIterable;
import com.gs.collections.impl.block.factory.Predicates;
import com.gs.collections.impl.lazy.parallel.list.NonParallelListIterable;
import com.gs.collections.impl.parallel.BatchIterable;
import com.gs.collections.impl.parallel.ParallelIterate;
import com.gs.collections.impl.utility.Iterate;
/**
* CompositeFastList behaves like a list, but is composed of at least one list.
* It is useful where you don't want the additional expense of appending several lists or allocating memory
* for a super list to add multiple sublists to.
* Note: mutation operations (e.g. add and remove, sorting) will change the underlying
* lists - so be sure to only use a composite list where it will be the only reference to the sublists
* (for example, a composite list which contains multiple query results is OK as long
* as it is the only thing that references the lists)
*/
public final class CompositeFastList
extends AbstractMutableList
implements BatchIterable, Serializable
{
private static final Predicate2, Object> REMOVE_PREDICATE = new Predicate2, Object>()
{
public boolean accept(FastList> list, Object toRemove)
{
return list.remove(toRemove);
}
};
private static final Procedure> REVERSE_LIST_PROCEDURE = new Procedure>()
{
public void value(FastList> each)
{
each.reverseThis();
}
};
private static final long serialVersionUID = 2L;
private final FastList> lists = FastList.newList();
private int size;
@Override
public MutableList clone()
{
throw new UnsupportedOperationException(this.getClass().getSimpleName() + ".clone() not implemented yet");
}
public int size()
{
return this.size;
}
public void resetSize()
{
int newSize = 0;
for (int i = this.lists.size() - 1; i >= 0; i--)
{
newSize += this.lists.get(i).size();
}
this.size = newSize;
}
public void batchForEach(Procedure super E> procedure, int sectionIndex, int sectionCount)
{
if (this.lists.size() == 1)
{
this.lists.get(0).batchForEach(procedure, sectionIndex, sectionCount);
}
else
{
this.lists.get(sectionIndex).batchForEach(procedure, 0, 1);
}
}
public int getBatchCount(int batchSize)
{
if (this.lists.size() == 1)
{
return this.lists.get(0).getBatchCount(batchSize);
}
return this.lists.size();
}
@Override
public CompositeFastList reverseThis()
{
ParallelIterate.forEach(this.lists, REVERSE_LIST_PROCEDURE);
this.lists.reverseThis();
return this;
}
@Override
public void each(final Procedure super E> procedure)
{
this.lists.forEach(new Procedure>()
{
public void value(FastList list)
{
list.forEach(procedure);
}
});
}
@Override
public IV injectInto(IV injectedValue, final Function2 super IV, ? super E, ? extends IV> function)
{
return this.lists.injectInto(injectedValue, new Function2, IV>()
{
public IV value(IV inject, FastList list)
{
return list.injectInto(inject, function);
}
});
}
@Override
public int injectInto(int injectedValue, final IntObjectToIntFunction super E> function)
{
return this.lists.injectInto(injectedValue, new IntObjectToIntFunction>()
{
public int intValueOf(int inject, FastList list)
{
return list.injectInto(inject, function);
}
});
}
@Override
public float injectInto(float injectedValue, final FloatObjectToFloatFunction super E> function)
{
return this.lists.injectInto(injectedValue, new FloatObjectToFloatFunction>()
{
public float floatValueOf(float inject, FastList list)
{
return list.injectInto(inject, function);
}
});
}
@Override
public long injectInto(long injectedValue, final LongObjectToLongFunction super E> function)
{
return this.lists.injectInto(injectedValue, new LongObjectToLongFunction>()
{
public long longValueOf(long inject, FastList list)
{
return list.injectInto(inject, function);
}
});
}
@Override
public double injectInto(double injectedValue, final DoubleObjectToDoubleFunction super E> function)
{
return this.lists.injectInto(injectedValue, new DoubleObjectToDoubleFunction>()
{
public double doubleValueOf(double inject, FastList list)
{
return list.injectInto(inject, function);
}
});
}
@Override
public void forEachWithIndex(ObjectIntProcedure super E> objectIntProcedure)
{
this.lists.forEach(new ProcedureToInnerListObjectIntProcedure(objectIntProcedure));
}
@Override
public void reverseForEach(final Procedure super E> procedure)
{
this.lists.reverseForEach(new Procedure>()
{
public void value(FastList each)
{
each.reverseForEach(procedure);
}
});
}
@Override
public void forEachWith(
final Procedure2 super E, ? super P> procedure2,
final P parameter)
{
this.lists.forEach(new Procedure>()
{
public void value(FastList list)
{
list.forEachWith(procedure2, parameter);
}
});
}
@Override
public boolean isEmpty()
{
return this.lists.allSatisfy(new Predicate>()
{
public boolean accept(FastList list)
{
return list.isEmpty();
}
});
}
@Override
public boolean contains(final Object object)
{
return this.lists.anySatisfy(new Predicate>()
{
public boolean accept(FastList list)
{
return list.contains(object);
}
});
}
@Override
public Iterator iterator()
{
if (this.lists.isEmpty())
{
return Collections.emptyList().iterator();
}
return new CompositeIterator(this.lists);
}
@Override
public Object[] toArray()
{
final Object[] result = new Object[this.size()];
this.forEachWithIndex(new ObjectIntProcedure()
{
public void value(E each, int index)
{
result[index] = each;
}
});
return result;
}
@Override
public boolean add(E object)
{
if (this.lists.isEmpty())
{
this.addComposited(FastList.newList());
}
Collection list = this.lists.getLast();
this.size++;
return list.add(object);
}
@Override
public boolean remove(Object object)
{
boolean removed = this.lists.anySatisfyWith(REMOVE_PREDICATE, object);
if (removed)
{
this.size--;
}
return removed;
}
@Override
public boolean addAll(Collection extends E> collection)
{
if (!collection.isEmpty())
{
Collection extends E> collectionToAdd = collection instanceof FastList ? collection : new FastList(collection);
this.addComposited(collectionToAdd);
}
return true;
}
@Override
public boolean containsAll(Collection> collection)
{
return Iterate.allSatisfy(collection, Predicates.in(this));
}
@Override
public Object[] toArray(Object[] array)
{
int size = this.size();
final Object[] result = array.length >= size
? array
: (Object[]) Array.newInstance(array.getClass().getComponentType(), size);
this.forEachWithIndex(new ObjectIntProcedure()
{
public void value(E each, int index)
{
result[index] = each;
}
});
if (result.length > size)
{
result[size] = null;
}
return result;
}
public void addComposited(Collection extends E> collection)
{
if (!(collection instanceof FastList))
{
throw new IllegalArgumentException("CompositeFastList can only add FastLists");
}
this.size += collection.size();
this.lists.add((FastList) collection);
}
public boolean addAll(int index, Collection extends E> collection)
{
throw new UnsupportedOperationException(this.getClass().getSimpleName() + ".addAll(index, collection) not implemented yet");
}
public void clear()
{
this.lists.forEach(new Procedure>()
{
public void value(FastList object)
{
object.clear();
}
});
this.size = 0;
}
@Override
public boolean retainAll(Collection> collection)
{
boolean changed = false;
for (int i = this.lists.size() - 1; i >= 0; i--)
{
changed = this.lists.get(i).retainAll(collection) || changed;
}
if (changed)
{
this.resetSize();
}
return changed;
}
@Override
public boolean removeAll(Collection> collection)
{
if (collection.isEmpty())
{
return false;
}
boolean changed = false;
for (int i = this.lists.size() - 1; i >= 0; i--)
{
changed = this.lists.get(i).removeAll(collection) || changed;
}
if (changed)
{
this.resetSize();
}
return changed;
}
public E get(int index)
{
this.rangeCheck(index);
int p = 0;
int currentSize = this.lists.getFirst().size();
while (index >= currentSize)
{
index -= currentSize;
currentSize = this.lists.get(++p).size();
}
return this.lists.get(p).items[index];
}
private void rangeCheck(int index)
{
if (index >= this.size())
{
throw new IndexOutOfBoundsException("No such element " + index + " size: " + this.size());
}
}
public E set(int index, E element)
{
this.rangeCheck(index);
int p = 0;
int currentSize = this.lists.getFirst().size();
while (index >= currentSize)
{
index -= currentSize;
currentSize = this.lists.get(++p).size();
}
return this.lists.get(p).set(index, element);
}
public void add(int index, E element)
{
int localSize = this.size();
if (index > localSize || index < 0)
{
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + localSize);
}
int max = 0;
for (int i = 0; i < this.lists.size(); i++)
{
List list = this.lists.get(i);
int previousMax = max;
max += list.size();
if (index <= max)
{
list.add(index - previousMax, element);
this.size++;
return;
}
}
}
public E remove(int index)
{
this.rangeCheck(index);
int p = 0;
int currentSize = this.lists.getFirst().size();
while (index >= currentSize)
{
index -= currentSize;
currentSize = this.lists.get(++p).size();
}
this.size--;
return this.lists.get(p).remove(index);
}
@Override
public int indexOf(Object o)
{
int offset = 0;
int listsSize = this.lists.size();
for (int i = 0; i < listsSize; i++)
{
MutableList list = this.lists.get(i);
int index = list.indexOf(o);
if (index > -1)
{
return index + offset;
}
offset += list.size();
}
return -1;
}
@Override
public int lastIndexOf(Object o)
{
int offset = this.size();
for (int i = this.lists.size() - 1; i >= 0; i--)
{
MutableList list = this.lists.get(i);
offset -= list.size();
int index = list.lastIndexOf(o);
if (index > -1)
{
return index + offset;
}
}
return -1;
}
/**
* a list iterator is a problem for a composite list as going back in the order of the list is an issue,
* as are the other methods like set() and add() (and especially, remove).
* Convert the internal lists to one list (if not already just one list)
* and return that list's list iterator.
*
* AFAIK list iterator is only commonly used in sorting.
*
* @return a ListIterator for this, with internal state convertedto one list if needed.
*/
@Override
public ListIterator listIterator()
{
return this.listIterator(0);
}
/**
* a list iterator is a problem for a composite list as going back in the order of the list is an issue,
* as are the other methods like set() and add() (and especially, remove).
* Convert the internal lists to one list (if not already just one list)
* and return that list's list iterator.
*
* AFAIK list iterator is only commonly used in sorting.
*
* @return a ListIterator for this, with internal state convertedto one list if needed.
*/
@Override
public ListIterator listIterator(int index)
{
if (this.lists.size() > 1 || this.lists.isEmpty())
{
this.flattenLists();
}
return super.listIterator(index);
}
@Override
public int count(Predicate super E> predicate)
{
int count = 0;
int localSize = this.lists.size();
for (int i = 0; i < localSize; i++)
{
count += this.lists.get(i).count(predicate);
}
return count;
}
@Override
public int countWith(Predicate2 super E, ? super P> predicate, P parameter)
{
int count = 0;
int localSize = this.lists.size();
for (int i = 0; i < localSize; i++)
{
count += this.lists.get(i).countWith(predicate, parameter);
}
return count;
}
@Override
public boolean anySatisfy(final Predicate super E> predicate)
{
return this.lists.anySatisfy(new Predicate>()
{
public boolean accept(FastList each)
{
return each.anySatisfy(predicate);
}
});
}
@Override
public > R select(Predicate super E> predicate, R target)
{
int localSize = this.lists.size();
for (int i = 0; i < localSize; i++)
{
this.lists.get(i).select(predicate, target);
}
return target;
}
@Override
public > R selectWith(Predicate2 super E, ? super P> predicate, P parameter, R target)
{
int localSize = this.lists.size();
for (int i = 0; i < localSize; i++)
{
this.lists.get(i).selectWith(predicate, parameter, target);
}
return target;
}
@Override
public > R reject(Predicate super E> predicate, R target)
{
int localSize = this.lists.size();
for (int i = 0; i < localSize; i++)
{
this.lists.get(i).reject(predicate, target);
}
return target;
}
@Override
public > R rejectWith(Predicate2 super E, ? super P> predicate, P parameter, R target)
{
int localSize = this.lists.size();
for (int i = 0; i < localSize; i++)
{
this.lists.get(i).rejectWith(predicate, parameter, target);
}
return target;
}
@Override
public > R collect(Function super E, ? extends V> function, R target)
{
int localSize = this.lists.size();
for (int i = 0; i < localSize; i++)
{
this.lists.get(i).collect(function, target);
}
return target;
}
@Override
public > R collectWith(Function2 super E, ? super P, ? extends A> function, P parameter, R target)
{
int localSize = this.lists.size();
for (int i = 0; i < localSize; i++)
{
this.lists.get(i).collectWith(function, parameter, target);
}
return target;
}
@Override
public
boolean anySatisfyWith(final Predicate2 super E, ? super P> predicate, P parameter)
{
return this.lists.anySatisfyWith(new Predicate2, P>()
{
public boolean accept(FastList each, P parm)
{
return each.anySatisfyWith(predicate, parm);
}
}, parameter);
}
@Override
public boolean allSatisfy(final Predicate super E> predicate)
{
return this.lists.allSatisfy(new Predicate>()
{
public boolean accept(FastList each)
{
return each.allSatisfy(predicate);
}
});
}
@Override
public boolean allSatisfyWith(final Predicate2 super E, ? super P> predicate, P parameter)
{
return this.lists.allSatisfyWith(new Predicate2, P>()
{
public boolean accept(FastList each, P param)
{
return each.allSatisfyWith(predicate, param);
}
}, parameter);
}
@Override
public boolean noneSatisfy(final Predicate super E> predicate)
{
return this.lists.allSatisfy(new Predicate>()
{
public boolean accept(FastList each)
{
return each.noneSatisfy(predicate);
}
});
}
@Override
public boolean noneSatisfyWith(final Predicate2 super E, ? super P> predicate, P parameter)
{
return this.lists.allSatisfyWith(new Predicate2, P>()
{
public boolean accept(FastList each, P param)
{
return each.noneSatisfyWith(predicate, param);
}
}, parameter);
}
/**
* convert multiple contained lists into one list and replace the contained lists with that list.
* Synchronize to prevent changes to this list whilst this process is happening
*/
private void flattenLists()
{
FastList list = (FastList) this.toList();
this.lists.clear();
this.lists.add(list);
}
/**
* Override in subclasses where it can be optimized.
*/
@Override
protected void defaultSort(Comparator super E> comparator)
{
FastList list = comparator == null
? (FastList) this.toSortedList()
: (FastList) this.toSortedList(comparator);
this.lists.clear();
this.lists.add(list);
}
private final class CompositeIterator
implements Iterator
{
private final Iterator[] iterators;
private Iterator currentIterator;
private int currentIndex;
private CompositeIterator(FastList> newLists)
{
this.iterators = new Iterator[newLists.size()];
for (int i = 0; i < newLists.size(); ++i)
{
this.iterators[i] = newLists.get(i).iterator();
}
this.currentIterator = this.iterators[0];
this.currentIndex = 0;
}
public boolean hasNext()
{
if (this.currentIterator.hasNext())
{
return true;
}
if (this.currentIndex < this.iterators.length - 1)
{
this.currentIterator = this.iterators[++this.currentIndex];
return this.hasNext();
}
return false;
}
public E next()
{
if (this.currentIterator.hasNext())
{
return this.currentIterator.next();
}
if (this.currentIndex < this.iterators.length - 1)
{
this.currentIterator = this.iterators[++this.currentIndex];
return this.next();
}
throw new NoSuchElementException();
}
public void remove()
{
CompositeFastList.this.size--;
this.currentIterator.remove();
}
}
private static final class ProcedureToInnerListObjectIntProcedure implements Procedure>
{
private static final long serialVersionUID = 1L;
private int index;
private final ObjectIntProcedure super E> objectIntProcedure;
private ProcedureToInnerListObjectIntProcedure(ObjectIntProcedure super E> objectIntProcedure)
{
this.objectIntProcedure = objectIntProcedure;
}
public void value(FastList list)
{
list.forEach(new Procedure()
{
public void value(E object)
{
ProcedureToInnerListObjectIntProcedure.this.objectIntProcedure.value(
object,
ProcedureToInnerListObjectIntProcedure.this.index);
ProcedureToInnerListObjectIntProcedure.this.index++;
}
});
}
}
@Override
public ParallelListIterable asParallel(ExecutorService executorService, int batchSize)
{
return new NonParallelListIterable(this);
}
}