blob: ec5ae43a4200a406d70ea4e8c63980627c5d7ab0 [file] [log] [blame]
/*
* Copyright (c) 2010, Rickard Öberg. All Rights Reserved.
*
* 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 org.qi4j.functional;
import java.lang.reflect.Array;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* Utility methods for working with Iterables. See test for examples of how to use.
*/
public final class Iterables
{
@SuppressWarnings( "raw" )
private static final Iterable EMPTY = new Iterable()
{
Iterator iterator = new Iterator()
{
@Override
public boolean hasNext()
{
return false;
}
@Override
public Object next()
{
throw new NoSuchElementException();
}
@Override
public void remove()
{
}
};
@Override
public Iterator iterator()
{
return iterator;
}
};
@SuppressWarnings( "unchecked" )
public static <T> Iterable<T> empty()
{
return EMPTY;
}
public static <T> Iterable<T> constant( final T item )
{
return new Iterable<T>()
{
@Override
public Iterator<T> iterator()
{
return new Iterator<T>()
{
@Override
public boolean hasNext()
{
return true;
}
@Override
public T next()
{
return item;
}
@Override
public void remove()
{
}
};
}
};
}
public static <T> Iterable<T> limit( final int limitItems, final Iterable<T> iterable )
{
return new Iterable<T>()
{
@Override
public Iterator<T> iterator()
{
final Iterator<T> iterator = iterable.iterator();
return new Iterator<T>()
{
int count;
@Override
public boolean hasNext()
{
return count < limitItems && iterator.hasNext();
}
@Override
public T next()
{
count++;
return iterator.next();
}
@Override
public void remove()
{
iterator.remove();
}
};
}
};
}
public static <T> Iterable<T> unique( final Iterable<T> iterable )
{
return new Iterable<T>()
{
@Override
public Iterator<T> iterator()
{
final Iterator<T> iterator = iterable.iterator();
return new Iterator<T>()
{
private final Set<T> items = new HashSet<>();
private T nextItem;
@Override
public boolean hasNext()
{
while( iterator.hasNext() )
{
nextItem = iterator.next();
if( items.add( nextItem ) )
{
return true;
}
}
return false;
}
@Override
public T next()
{
if( nextItem == null && !hasNext() )
{
throw new NoSuchElementException();
}
return nextItem;
}
@Override
public void remove()
{
}
};
}
};
}
public static <T, C extends Collection<T>> C addAll( C collection, Iterable<? extends T> iterable )
{
for( T item : iterable )
{
collection.add( item );
}
return collection;
}
public static long count( Iterable<?> iterable )
{
long c = 0;
for( Object anIterable : iterable )
{
c++;
}
return c;
}
@SuppressWarnings( "unchecked" )
public static <X> Iterable<X> filter( Specification<? /* super X*/> specification, Iterable<X> i )
{
return new FilterIterable<>( i, (Specification<? super X>) specification );
}
public static <X> X first( Iterable<X> i )
{
Iterator<X> iter = i.iterator();
if( iter.hasNext() )
{
return iter.next();
}
else
{
return null;
}
}
public static <X> X single( Iterable<X> i )
{
Iterator<X> iter = i.iterator();
if( iter.hasNext() )
{
X result = iter.next();
if( iter.hasNext() )
{
throw new IllegalArgumentException( "More than one element in iterable" );
}
return result;
}
else
{
throw new IllegalArgumentException( "No elements in iterable" );
}
}
public static <X> Iterable<X> skip( final int skip, final Iterable<X> iterable )
{
return new Iterable<X>()
{
@Override
public Iterator<X> iterator()
{
Iterator<X> iterator = iterable.iterator();
for( int i = 0; i < skip; i++ )
{
if( iterator.hasNext() )
{
iterator.next();
}
else
{
return Iterables.<X>empty().iterator();
}
}
return iterator;
}
};
}
public static <X> X last( Iterable<X> i )
{
Iterator<X> iter = i.iterator();
X item = null;
while( iter.hasNext() )
{
item = iter.next();
}
return item;
}
public static <X> Iterable<X> reverse( Iterable<X> iterable )
{
List<X> list = toList( iterable );
Collections.reverse( list );
return list;
}
public static <T> boolean matchesAny( Specification<? super T> specification, Iterable<T> iterable )
{
boolean result = false;
for( T item : iterable )
{
if( ( (Specification<? super T>) specification ).satisfiedBy( item ) )
{
result = true;
break;
}
}
return result;
}
public static <T> boolean matchesAll( Specification<? super T> specification, Iterable<T> iterable )
{
boolean result = true;
for( T item : iterable )
{
if( !specification.satisfiedBy( item ) )
{
result = false;
}
}
return result;
}
public static <X> Iterable<X> flatten( Iterable<?>... multiIterator )
{
return new FlattenIterable<>( Iterables.<Iterable<X>>cast( Arrays.asList( multiIterator ) ) );
}
public static <X, I extends Iterable<? extends X>> Iterable<X> flattenIterables( Iterable<I> multiIterator )
// public static <X> Iterable<X> flattenIterables( Iterable<Iterable<?>> multiIterator )
{
return new FlattenIterable<>( Iterables.<Iterable<X>>cast( multiIterator ) );
}
@SafeVarargs
public static <T> Iterable<T> mix( final Iterable<T>... iterables )
{
return new Iterable<T>()
{
@Override
public Iterator<T> iterator()
{
final Iterable<Iterator<T>> iterators = toList( map( new Function<Iterable<T>, Iterator<T>>()
{
@Override
public Iterator<T> map( Iterable<T> iterable )
{
return iterable.iterator();
}
}, Iterables.iterable( iterables ) ) );
return new Iterator<T>()
{
Iterator<Iterator<T>> iterator;
Iterator<T> iter;
@Override
public boolean hasNext()
{
for( Iterator<T> iterator : iterators )
{
if( iterator.hasNext() )
{
return true;
}
}
return false;
}
@Override
public T next()
{
if( iterator == null )
{
iterator = iterators.iterator();
}
while( iterator.hasNext() )
{
iter = iterator.next();
if( iter.hasNext() )
{
return iter.next();
}
}
iterator = null;
return next();
}
@Override
public void remove()
{
if( iter != null )
{
iter.remove();
}
}
};
}
};
}
@SuppressWarnings( "unchecked" )
public static <FROM, TO> Iterable<TO> map( Function<? /* super FROM */, TO> function, Iterable<FROM> from )
{
return new MapIterable<>( from, (Function<FROM, TO>) function );
}
public static <T> Iterable<T> iterable( Enumeration<T> enumeration )
{
List<T> list = new ArrayList<>();
while( enumeration.hasMoreElements() )
{
T item = enumeration.nextElement();
list.add( item );
}
return list;
}
@SafeVarargs
public static <T> Iterable<T> iterable( T... items )
{
return Arrays.asList( items );
}
@SuppressWarnings( {"raw", "unchecked"} )
public static <T> Iterable<T> cast( Iterable<?> iterable )
{
Iterable iter = iterable;
return iter;
}
public static <FROM, TO> Function<FROM, TO> cast()
{
return new Function<FROM, TO>()
{
@Override
@SuppressWarnings( "unchecked" )
public TO map( FROM from )
{
return (TO) from;
}
};
}
public static <FROM, TO> TO fold( Function<? super FROM, TO> function, Iterable<? extends FROM> i )
{
return last( map( function, i ) );
}
public static <T> Iterable<T> prepend( final T item, final Iterable<T> iterable )
{
return new Iterable<T>()
{
@Override
public Iterator<T> iterator()
{
return new Iterator<T>()
{
T first = item;
Iterator<T> iterator;
@Override
public boolean hasNext()
{
if( first != null )
{
return true;
}
else
{
if( iterator == null )
{
iterator = iterable.iterator();
}
}
return iterator.hasNext();
}
@Override
public T next()
{
if( first != null )
{
try
{
return first;
}
finally
{
first = null;
}
}
else
{
return iterator.next();
}
}
@Override
public void remove()
{
}
};
}
};
}
public static <T> Iterable<T> append( final T item, final Iterable<T> iterable )
{
return new Iterable<T>()
{
@Override
public Iterator<T> iterator()
{
final Iterator<T> iterator = iterable.iterator();
return new Iterator<T>()
{
T last = item;
@Override
public boolean hasNext()
{
if( iterator.hasNext() )
{
return true;
}
else
{
return last != null;
}
}
@Override
public T next()
{
if( iterator.hasNext() )
{
return iterator.next();
}
else
{
try
{
return last;
}
finally
{
last = null;
}
}
}
@Override
public void remove()
{
}
};
}
};
}
@SafeVarargs
public static <T> Iterable<T> debug( String format,
final Iterable<T> iterable,
final Function<T, String>... functions
)
{
final MessageFormat msgFormat = new MessageFormat( format );
return map( new Function<T, T>()
{
@Override
public T map( T t )
{
if( functions.length != 0 )
{
String[] mapped = new String[ functions.length ];
for( int i = 0; i < functions.length; i++ )
{
Function<T, String> function = functions[i];
mapped[i] = function.map( t );
}
}
return t;
}
}, iterable );
}
public static <T> Iterable<T> cache( Iterable<T> iterable )
{
return new CacheIterable<>( iterable );
}
public static <T> String toString( Iterable<T> iterable )
{
return toString( iterable, new Function<T, String>()
{
@Override
public String map( T t )
{
return t == null ? "[null]" : t.toString();
}
}, "," );
}
public static <T> String toString( Iterable<T> iterable, Function<T, String> toStringFunction, String separator )
{
StringBuilder builder = new StringBuilder();
boolean first = true;
for( T item : iterable )
{
if( !first )
{
builder.append( separator );
}
builder.append( toStringFunction.map( item ) );
first = false;
}
return builder.toString();
}
public static <T> List<T> toList( Iterable<T> iterable )
{
return addAll( new ArrayList<T>(), iterable );
}
public static Object[] toArray( Iterable<Object> iterable )
{
return toArray( Object.class, iterable );
}
@SuppressWarnings( "unchecked" )
public static <T> T[] toArray( Class<T> componentType, Iterable<T> iterable )
{
if( iterable == null )
{
return null;
}
List<T> list = toList( iterable );
return list.toArray( (T[]) Array.newInstance( componentType, list.size() ) );
}
@SuppressWarnings( {"raw", "unchecked"} )
public static <X extends Comparable> Iterable<X> sort( Iterable<X> iterable )
{
List<X> list = toList( iterable );
Collections.sort( list );
return list;
}
public static <X> Iterable<X> sort( Comparator<? super X> comparator, Iterable<X> iterable )
{
List<X> list = toList( iterable );
Collections.sort( list, comparator );
return list;
}
private static class MapIterable<FROM, TO>
implements Iterable<TO>
{
private final Iterable<FROM> from;
private final Function<? super FROM, TO> function;
private MapIterable( Iterable<FROM> from, Function<? super FROM, TO> function )
{
this.from = from;
this.function = function;
}
@Override
public Iterator<TO> iterator()
{
return new MapIterator<>( from.iterator(), function );
}
static class MapIterator<FROM, TO>
implements Iterator<TO>
{
private final Iterator<FROM> fromIterator;
private final Function<? super FROM, TO> function;
private MapIterator( Iterator<FROM> fromIterator, Function<? super FROM, TO> function )
{
this.fromIterator = fromIterator;
this.function = function;
}
@Override
public boolean hasNext()
{
return fromIterator.hasNext();
}
@Override
public TO next()
{
FROM from = fromIterator.next();
return function.map( from );
}
@Override
public void remove()
{
fromIterator.remove();
}
}
}
private static class FilterIterable<T>
implements Iterable<T>
{
private final Iterable<T> iterable;
private final Specification<? super T> specification;
private FilterIterable( Iterable<T> iterable, Specification<? super T> specification )
{
this.iterable = iterable;
this.specification = specification;
}
@Override
public Iterator<T> iterator()
{
return new FilterIterator<>( iterable.iterator(), specification );
}
private static class FilterIterator<T>
implements Iterator<T>
{
private final Iterator<T> iterator;
private final Specification<? super T> specification;
private T currentValue;
boolean finished = false;
boolean nextConsumed = true;
private FilterIterator( Iterator<T> iterator, Specification<? super T> specification )
{
this.specification = specification;
this.iterator = iterator;
}
public boolean moveToNextValid()
{
boolean found = false;
while( !found && iterator.hasNext() )
{
T currentValue = iterator.next();
boolean satisfies = specification.satisfiedBy( currentValue );
if( satisfies )
{
found = true;
this.currentValue = currentValue;
nextConsumed = false;
}
}
if( !found )
{
finished = true;
}
return found;
}
@Override
public T next()
{
if( !nextConsumed )
{
nextConsumed = true;
return currentValue;
}
else
{
if( !finished )
{
if( moveToNextValid() )
{
nextConsumed = true;
return currentValue;
}
}
}
return null;
}
@Override
public boolean hasNext()
{
return !finished
&& ( !nextConsumed || moveToNextValid() );
}
@Override
public void remove()
{
}
}
}
private static class FlattenIterable<T, I extends Iterable<? extends T>>
implements Iterable<T>
{
private final Iterable<I> iterable;
private FlattenIterable( Iterable<I> iterable )
{
this.iterable = iterable;
}
@Override
public Iterator<T> iterator()
{
return new FlattenIterator<>( iterable.iterator() );
}
static class FlattenIterator<T, I extends Iterable<? extends T>>
implements Iterator<T>
{
private final Iterator<I> iterator;
private Iterator<? extends T> currentIterator;
private FlattenIterator( Iterator<I> iterator )
{
this.iterator = iterator;
currentIterator = null;
}
@Override
public boolean hasNext()
{
if( currentIterator == null )
{
if( iterator.hasNext() )
{
I next = iterator.next();
currentIterator = next.iterator();
}
else
{
return false;
}
}
while( !currentIterator.hasNext()
&& iterator.hasNext() )
{
currentIterator = iterator.next().iterator();
}
return currentIterator.hasNext();
}
@Override
public T next()
{
return currentIterator.next();
}
@Override
public void remove()
{
if( currentIterator == null )
{
throw new IllegalStateException();
}
currentIterator.remove();
}
}
}
private static class CacheIterable<T>
implements Iterable<T>
{
private final Iterable<T> iterable;
private Iterable<T> cache;
private CacheIterable( Iterable<T> iterable )
{
this.iterable = iterable;
}
@Override
public Iterator<T> iterator()
{
if( cache != null )
{
return cache.iterator();
}
final Iterator<T> source = iterable.iterator();
return new Iterator<T>()
{
List<T> iteratorCache = new ArrayList<>();
@Override
public boolean hasNext()
{
boolean hasNext = source.hasNext();
if( !hasNext )
{
cache = iteratorCache;
}
return hasNext;
}
@Override
public T next()
{
T next = source.next();
iteratorCache.add( next );
return next;
}
@Override
public void remove()
{
}
};
}
}
private Iterables()
{
}
}