content: package edu.berkeley.nlp.lm.collections;
  
  import java.util.Iterator;
  
  import edu.berkeley.nlp.lm.util.Pair;
  
  /**
   * Utilities for dealing with Iterators
   * 
   * @author adampauls
   * 
   */
  public class Iterators
  {
  
  	/**
  	 * Wraps an Iterator as an Iterable
  	 * 
  	 * @param <T>
  	 * @param it
  	 * @return
  	 */
  	public static <T> Iterable<T> able(final Iterator<T> it) {
  		return new Iterable<T>()
  		{
  			boolean used = false;
  
  			@Override
  			public Iterator<T> iterator() {
  				if (used) throw new RuntimeException("One use iterable");
  				used = true;
  				return it;
  			}
  		};
  	}
  
  	public static <T> Iterable<T> flatten(final Iterator<Iterator<T>> iters) {
  		return Iterators.able(new IteratorIterator<T>(iters));
  	}
  
  	/**
  	 * Wraps a two-level iteration scenario in an iterator. Each key of the keys
  	 * iterator returns an iterator (via the factory) over T's.
  	 * <p>
  	 * The IteratorIterator loops through the iterator associated with each key
  	 * until all the keys are used up.
  	 */
  	public static class IteratorIterator<T> implements Iterator<T>
  	{
  		Iterator<T> current = null;
  
  		private final Iterator<Iterator<T>> iters;
  
  		public IteratorIterator(final Iterator<Iterator<T>> iters) {
  			this.iters = iters;
  			current = getNextIterator();
  		}
  
  		private Iterator<T> getNextIterator() {
  			Iterator<T> next = null;
  			while (next == null) {
  				if (!iters.hasNext()) break;
  				next = iters.next();
  				if (!next.hasNext()) next = null;
  			}
  			return next;
  		}
  
  		@Override
  		public boolean hasNext() {
  			return current != null;
  		}
  
  		@Override
  		public T next() {
  			final T next = current.next();
  			if (!current.hasNext()) current = getNextIterator();
  			return next;
  		}
  
  		@Override
  		public void remove() {
  			throw new UnsupportedOperationException();
  		}
  
  	}
  
  	/**
  	 * Wraps a base iterator with a transformation function.
  	 */
  	public static abstract class Transform<S, T> implements Iterator<T>
  	{
  
  		private final Iterator<S> base;
  
  		public Transform(final Iterator<S> base) {
  			this.base = base;
  		}
  
  		@Override
  		public boolean hasNext() {
  			return base.hasNext();
  		}
  
  		@Override
  		public T next() {
  			return transform(base.next());
  		}
  
  		protected abstract T transform(S next);
  
  		@Override
  		public void remove() {
  			base.remove();
  		}
  
  	}
  
  	public static <S, T> Iterator<Pair<S, T>> zip(final Iterator<S> s, final Iterator<T> t) {
  		return new Iterator<Pair<S, T>>()
  		{
  			@Override
  			public boolean hasNext() {
  				return s.hasNext() && t.hasNext();
  			}
  
  			@Override
  			public Pair<S, T> next() {
  				return Pair.newPair(s.next(), t.next());
  			}
  
  			@Override
  			public void remove() {
  				throw new UnsupportedOperationException();
  			}
  		};
  	}
  
  }
  