/*
* 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.set.sorted.immutable;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.SortedSet;
import java.util.concurrent.ExecutorService;
import com.gs.collections.api.LazyIterable;
import com.gs.collections.api.block.function.Function;
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.primitive.ObjectIntProcedure;
import com.gs.collections.api.map.MapIterable;
import com.gs.collections.api.multimap.sortedset.ImmutableSortedSetMultimap;
import com.gs.collections.api.ordered.OrderedIterable;
import com.gs.collections.api.set.sorted.ImmutableSortedSet;
import com.gs.collections.api.set.sorted.MutableSortedSet;
import com.gs.collections.api.set.sorted.ParallelSortedSetIterable;
import com.gs.collections.api.set.sorted.SortedSetIterable;
import com.gs.collections.impl.factory.SortedSets;
import com.gs.collections.impl.lazy.AbstractLazyIterable;
import com.gs.collections.impl.lazy.parallel.AbstractBatch;
import com.gs.collections.impl.lazy.parallel.AbstractParallelIterable;
import com.gs.collections.impl.lazy.parallel.list.ListBatch;
import com.gs.collections.impl.lazy.parallel.set.sorted.AbstractParallelSortedSetIterable;
import com.gs.collections.impl.lazy.parallel.set.sorted.CollectSortedSetBatch;
import com.gs.collections.impl.lazy.parallel.set.sorted.FlatCollectSortedSetBatch;
import com.gs.collections.impl.lazy.parallel.set.sorted.RootSortedSetBatch;
import com.gs.collections.impl.lazy.parallel.set.sorted.SelectSortedSetBatch;
import com.gs.collections.impl.lazy.parallel.set.sorted.SortedSetBatch;
import com.gs.collections.impl.list.mutable.FastList;
import com.gs.collections.impl.map.mutable.ConcurrentHashMap;
import com.gs.collections.impl.set.sorted.mutable.TreeSortedSet;
import com.gs.collections.impl.utility.ArrayIterate;
import com.gs.collections.impl.utility.ListIterate;
import com.gs.collections.impl.utility.internal.InternalArrayIterate;
import net.jcip.annotations.Immutable;
@Immutable
final class ImmutableTreeSet<T>
extends AbstractImmutableSortedSet<T>
implements Serializable
{
private static final long serialVersionUID = 2L;
private final T[] delegate;
private final Comparator<? super T> comparator;
private ImmutableTreeSet(SortedSet<T> sortedSet)
{
this.delegate = (T[]) sortedSet.toArray();
this.comparator = sortedSet.comparator();
}
public static <T> ImmutableSortedSet<T> newSetWith(T... elements)
{
return new ImmutableTreeSet<T>(TreeSortedSet.newSetWith(elements));
}
public static <T> ImmutableSortedSet<T> newSetWith(Comparator<? super T> comparator, T... elements)
{
return new ImmutableTreeSet<T>(TreeSortedSet.newSetWith(comparator, elements));
}
public static <T> ImmutableSortedSet<T> newSet(SortedSet<T> set)
{
return new ImmutableTreeSet<T>(TreeSortedSet.newSet(set));
}
public int size()
{
return this.delegate.length;
}
private Object writeReplace()
{
return new ImmutableSortedSetSerializationProxy<T>(this);
}
@Override
public boolean equals(Object obj)
{
if (obj == this)
{
return true;
}
if (!(obj instanceof Set))
{
return false;
}
Set<?> otherSet = (Set<?>) obj;
if (otherSet.size() != this.size())
{
return false;
}
try
{
return this.containsAll(otherSet);
}
catch (ClassCastException ignored)
{
return false;
}
}
@Override
public int hashCode()
{
int result = 0;
for (T each : this.delegate)
{
result += each.hashCode();
}
return result;
}
@Override
public boolean contains(Object object)
{
return Arrays.binarySearch(this.delegate, (T) object, this.comparator) >= 0;
}
public Iterator<T> iterator()
{
return FastList.newListWith(this.delegate).asUnmodifiable().iterator();
}
public void each(Procedure<? super T> procedure)
{
for (T t : this.delegate)
{
procedure.value(t);
}
}
public T first()
{
return this.delegate[0];
}
public T last()
{
return this.delegate[this.delegate.length - 1];
}
public Comparator<? super T> comparator()
{
return this.comparator;
}
public int compareTo(SortedSetIterable<T> otherSet)
{
Iterator<T> iterator = otherSet.iterator();
for (T eachInThis : this.delegate)
{
if (!iterator.hasNext())
{
return 1;
}
T eachInOther = iterator.next();
int compare = this.compare(eachInThis, eachInOther);
if (compare != 0)
{
return compare;
}
}
return iterator.hasNext() ? -1 : 0;
}
private int compare(T o1, T o2)
{
return this.comparator == null
? ((Comparable<T>) o1).compareTo(o2)
: this.comparator.compare(o1, o2);
}
@Override
public ParallelSortedSetIterable<T> asParallel(ExecutorService executorService, int batchSize)
{
return new SortedSetIterableParallelIterable(executorService, batchSize);
}
private final class SortedSetIterableParallelIterable extends AbstractParallelSortedSetIterable<T, RootSortedSetBatch<T>>
{
private final ExecutorService executorService;
private final int batchSize;
private SortedSetIterableParallelIterable(ExecutorService executorService, int batchSize)
{
if (executorService == null)
{
throw new NullPointerException();
}
if (batchSize < 1)
{
throw new IllegalArgumentException();
}
this.executorService = executorService;
this.batchSize = batchSize;
}
public Comparator<? super T> comparator()
{
return ImmutableTreeSet.this.comparator;
}
@Override
public ExecutorService getExecutorService()
{
return this.executorService;
}
@Override
public LazyIterable<RootSortedSetBatch<T>> split()
{
return new SortedSetIterableParallelBatchLazyIterable();
}
public void forEach(Procedure<? super T> procedure)
{
AbstractParallelIterable.forEach(this, procedure);
}
public boolean anySatisfy(Predicate<? super T> predicate)
{
return AbstractParallelIterable.anySatisfy(this, predicate);
}
public boolean allSatisfy(Predicate<? super T> predicate)
{
return AbstractParallelIterable.allSatisfy(this, predicate);
}
public T detect(Predicate<? super T> predicate)
{
return AbstractParallelIterable.detect(this, predicate);
}
@Override
public Object[] toArray()
{
// TODO: Implement in parallel
return ImmutableTreeSet.this.toArray();
}
@Override
public <E> E[] toArray(E[] array)
{
// TODO: Implement in parallel
return ImmutableTreeSet.this.toArray(array);
}
@Override
public <V> ImmutableSortedSetMultimap<V, T> groupBy(Function<? super T, ? extends V> function)
{
// TODO: Implement in parallel
return ImmutableTreeSet.this.groupBy(function);
}
@Override
public <V> ImmutableSortedSetMultimap<V, T> groupByEach(Function<? super T, ? extends Iterable<V>> function)
{
// TODO: Implement in parallel
return ImmutableTreeSet.this.groupByEach(function);
}
@Override
public <V> MapIterable<V, T> groupByUniqueKey(Function<? super T, ? extends V> function)
{
// TODO: Implement in parallel
return ImmutableTreeSet.this.groupByUniqueKey(function);
}
@Override
public int getBatchSize()
{
return this.batchSize;
}
private class SortedSetIterableParallelBatchIterator implements Iterator<RootSortedSetBatch<T>>
{
protected int chunkIndex;
public boolean hasNext()
{
return this.chunkIndex * SortedSetIterableParallelIterable.this.getBatchSize() < ImmutableTreeSet.this.size();
}
public RootSortedSetBatch<T> next()
{
int chunkStartIndex = this.chunkIndex * SortedSetIterableParallelIterable.this.getBatchSize();
int chunkEndIndex = (this.chunkIndex + 1) * SortedSetIterableParallelIterable.this.getBatchSize();
int truncatedChunkEndIndex = Math.min(chunkEndIndex, ImmutableTreeSet.this.size());
this.chunkIndex++;
return new ImmutableTreeSetBatch(chunkStartIndex, truncatedChunkEndIndex);
}
public void remove()
{
throw new UnsupportedOperationException("Cannot call remove() on " + ImmutableTreeSet.this.getClass().getSimpleName());
}
}
private class SortedSetIterableParallelBatchLazyIterable
extends AbstractLazyIterable<RootSortedSetBatch<T>>
{
public void each(Procedure<? super RootSortedSetBatch<T>> procedure)
{
for (RootSortedSetBatch<T> chunk : this)
{
procedure.value(chunk);
}
}
public Iterator<RootSortedSetBatch<T>> iterator()
{
return new SortedSetIterableParallelBatchIterator();
}
}
}
private final class ImmutableTreeSetBatch extends AbstractBatch<T> implements RootSortedSetBatch<T>
{
private final int chunkStartIndex;
private final int chunkEndIndex;
private ImmutableTreeSetBatch(int chunkStartIndex, int chunkEndIndex)
{
this.chunkStartIndex = chunkStartIndex;
this.chunkEndIndex = chunkEndIndex;
}
public void forEach(Procedure<? super T> procedure)
{
for (int i = this.chunkStartIndex; i < this.chunkEndIndex; i++)
{
procedure.value(ImmutableTreeSet.this.delegate[i]);
}
}
@Override
public int count(Predicate<? super T> predicate)
{
int count = 0;
for (int i = this.chunkStartIndex; i < this.chunkEndIndex; i++)
{
if (predicate.accept(ImmutableTreeSet.this.delegate[i]))
{
count++;
}
}
return count;
}
public boolean anySatisfy(Predicate<? super T> predicate)
{
for (int i = this.chunkStartIndex; i < this.chunkEndIndex; i++)
{
if (predicate.accept(ImmutableTreeSet.this.delegate[i]))
{
return true;
}
}
return false;
}
public boolean allSatisfy(Predicate<? super T> predicate)
{
for (int i = this.chunkStartIndex; i < this.chunkEndIndex; i++)
{
if (!predicate.accept(ImmutableTreeSet.this.delegate[i]))
{
return false;
}
}
return true;
}
public T detect(Predicate<? super T> predicate)
{
for (int i = this.chunkStartIndex; i < this.chunkEndIndex; i++)
{
if (predicate.accept(ImmutableTreeSet.this.delegate[i]))
{
return ImmutableTreeSet.this.delegate[i];
}
}
return null;
}
public SortedSetBatch<T> select(Predicate<? super T> predicate)
{
return new SelectSortedSetBatch<T>(this, predicate);
}
public <V> ListBatch<V> collect(Function<? super T, ? extends V> function)
{
return new CollectSortedSetBatch<T, V>(this, function);
}
public <V> ListBatch<V> flatCollect(Function<? super T, ? extends Iterable<V>> function)
{
return new FlatCollectSortedSetBatch<T, V>(this, function);
}
public SortedSetBatch<T> distinct(ConcurrentHashMap<T, Boolean> distinct)
{
return this;
}
}
@Override
public int detectIndex(Predicate<? super T> predicate)
{
return ArrayIterate.detectIndex(this.delegate, predicate);
}
@Override
public <S> boolean corresponds(OrderedIterable<S> other, Predicate2<? super T, ? super S> predicate)
{
return InternalArrayIterate.corresponds(this.delegate, this.size(), other, predicate);
}
public void forEach(int fromIndex, int toIndex, Procedure<? super T> procedure)
{
ListIterate.rangeCheck(fromIndex, toIndex, this.size());
if (fromIndex > toIndex)
{
throw new IllegalArgumentException("fromIndex must not be greater than toIndex");
}
for (int i = fromIndex; i <= toIndex; i++)
{
procedure.value(this.delegate[i]);
}
}
public void forEachWithIndex(int fromIndex, int toIndex, ObjectIntProcedure<? super T> objectIntProcedure)
{
ListIterate.rangeCheck(fromIndex, toIndex, this.size());
if (fromIndex > toIndex)
{
throw new IllegalArgumentException("fromIndex must not be greater than toIndex");
}
for (int i = fromIndex; i <= toIndex; i++)
{
objectIntProcedure.value(this.delegate[i], i);
}
}
public int indexOf(Object object)
{
return ArrayIterate.indexOf(this.delegate, object);
}
public ImmutableSortedSet<T> take(int count)
{
if (count < 0)
{
throw new IllegalArgumentException("Count must be greater than zero, but was: " + count);
}
if (count >= this.size())
{
return this;
}
if (count == 0)
{
return SortedSets.immutable.empty(this.comparator());
}
MutableSortedSet<T> output = SortedSets.mutable.of(this.comparator());
for (int i = 0; i < count; i++)
{
output.add(this.delegate[i]);
}
return output.toImmutable();
}
public ImmutableSortedSet<T> drop(int count)
{
if (count < 0)
{
throw new IllegalArgumentException("Count must be greater than zero, but was: " + count);
}
if (count == 0)
{
return this;
}
if (count >= this.size())
{
return SortedSets.immutable.empty(this.comparator());
}
MutableSortedSet<T> output = SortedSets.mutable.of(this.comparator());
for (int i = 0; i < this.size(); i++)
{
if (i >= count)
{
output.add(this.delegate[i]);
}
}
return output.toImmutable();
}
}