/*******************************************************************************
* Copyright (c) 2014 Bruno Medeiros and other Contributors.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bruno Medeiros - initial API and implementation
*******************************************************************************/
package melnorme.utilbox.collections;
import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue;
import java.util.Collection;
import java.util.Collections;
import java.util.function.Function;
import java.util.function.Predicate;
import melnorme.utilbox.core.fntypes.FunctionX;
import melnorme.utilbox.misc.ArrayUtil;
import melnorme.utilbox.misc.CollectionUtil;
/**
* An {@link Iterable} with size information.
*
* This is essentially the same as {@link Collection}, but without the methods that modify the underlying collection.
* Indeed, its main purpose is as a replacement for {@link Collection},
* providing <b>statically</b> checked read-only access.
* This is preferable to {@link Collections#unmodifiableCollection(Collection)} because that one only checks at runtime.
*/
public interface Collection2<E> extends Iterable<E> {
/** @return the number of elements in this collection */
int size();
/** @return <tt>true</tt> if this collection contains no elements */
boolean isEmpty();
/** @return the receiver (this), with the type parameter recast.
* WARNING: This operation is only safe if:
* - The bound T is a supertype of E, and the returned collection is used only for reading. */
<T> Collection2<T> upcastTypeParameter();
/* ----------------- utility methods ----------------- */
default <R> ArrayList2<R> map(Function<? super E, ? extends R> evalFunction) {
return CollectionUtil.map(this, evalFunction);
}
default <R, EXC extends Exception> ArrayList2<R> mapx(FunctionX<? super E, ? extends R, EXC> evalFunction)
throws EXC {
return CollectionUtil.mapx(this, evalFunction);
}
default <EXC extends Exception> ArrayList2<E> filterx(
ArrayList2<E> into, FunctionX<E, Boolean, EXC> predicate
) throws EXC {
return CollectionUtil.filter2x(into, this, predicate);
}
/**
* @return the index in the iteration order of the first element that matches given predicate, or -1 otherwise.
* Note that if the iteration order of this collection is not stable, then the index isn't either.
*/
default int indexUntil(Predicate<? super E> predicate) {
return CollectionUtil.indexUntil(iterator(), predicate);
}
/** {@link CollectionUtil#findElement(java.util.Iterator, Predicate)} */
default E findElement(Predicate<? super E> predicate) {
return CollectionUtil.findElement(iterator(), predicate);
}
/* ----------------- Some array utility methods ----------------- */
default ArrayList2<E> toArrayList() {
return new ArrayList2<>(this);
}
default Object[] toArray() {
return this.<Object>upcastTypeParameter().toArray(Object.class);
}
@SuppressWarnings("unchecked")
default <T> T[] toArray(T[] a) {
Class<T> componentType = (Class<T>) a.getClass().getComponentType();
return this.<T>upcastTypeParameter().toArray(componentType);
}
default E[] toArray(Class<E> componentType) {
E[] newArray = ArrayUtil.create(size(), componentType);
copyToArray(newArray);
return newArray;
}
// Subclasses can reimplement with more optimized versions (ie, array lists for example)
default Object[] copyToArray(Object[] destArray) {
assertTrue(destArray.length == size());
int i = 0;
for(E element : this) {
destArray[i++] = element;
}
return destArray;
}
}