All Downloads are FREE. Search and download functionalities are using the official Maven repository.

at.molindo.utils.collections.IteratorUtils Maven / Gradle / Ivy

There is a newer version: 3.0.0
Show newest version
/**
 * Copyright 2010 Molindo GmbH
 *
 * 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 at.molindo.utils.collections;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;

import javax.annotation.Nonnull;

import at.molindo.utils.data.Function;
import at.molindo.utils.data.ObjectUtils;

public class IteratorUtils {

	public static final Iterator EMPTY_ITERATOR = new Iterator() {

		@Override
		public boolean hasNext() {
			return false;
		}

		@Override
		public Object next() {
			throw new NoSuchElementException();
		}

		@Override
		public void remove() {
			throw new IllegalStateException();
		}

	};

	public static final Iterable EMPTY_ITERABLE = new Iterable() {

		@Override
		public Iterator iterator() {
			return empty();
		}
	};

	private IteratorUtils() {

	}

	/**
	 * 
	 * @param 
	 * @param iter
	 * @return an {@link Iterable} that alway returns the passed
	 *         {@link Iterator} instance
	 */
	public static  Iterable iterable(final Iterator iter) {
		return new Iterable() {
			@Override
			public Iterator iterator() {
				return iter;
			}
		};
	}

	/**
	 * @param 
	 * @param iterable
	 * @return {@link Iterable#iterator()} or {@link #EMPTY_ITERATOR} if null
	 */
	@SuppressWarnings("unchecked")
	public static  Iterator iterator(Iterable iterable) {
		return iterable == null ? (Iterator) EMPTY_ITERATOR : iterable.iterator();
	}

	/**
	 * transforms an {@link Iterator} of {@link Iterable}s to an
	 * {@link Iterator} of {@link Iterator}s
	 */
	public static  Iterator> iterators(Iterator> iterables) {
		return transform(iterables, new Function, Iterator>() {

			@Override
			public Iterator apply(Iterable input) {
				return iterator(input);
			}
		});
	}

	/**
	 * transforms an {@link Iterable} of {@link Iterable}s to an
	 * {@link Iterable} of {@link Iterator}s
	 */
	public static  Iterable> iterators(Iterable> iterables) {
		return transform(iterables, new Function, Iterator>() {

			@Override
			public Iterator apply(Iterable input) {
				return iterator(input);
			}
		});
	}

	/**
	 * 
	 * @param 
	 * @param iter
	 * @return the next element if available, null otherwise
	 */
	public static  T next(final Iterator iter) {
		return iter == null || !iter.hasNext() ? null : iter.next();
	}

	/**
	 * 
	 * @param 
	 * @param iter
	 * @return the first element if available, null otherwise
	 */
	public static  T first(final Iterable iter) {
		return iter == null ? null : next(iter.iterator());
	}

	/**
	 * 
	 * @param 
	 * @param iter
	 * @return an {@link ArrayList} containing all elements
	 */
	public static  ArrayList list(final Iterable iter) {
		if (iter instanceof Collection) {
			// use collection size for initial capacity
			return list(iterator(iter), ((Collection) iter).size());
		} else {
			return list(iterator(iter));
		}
	}

	/**
	 * 
	 * @param 
	 * @param iter
	 * @return an {@link ArrayList} containing all elements
	 */
	public static  ArrayList list(final Iterable iter, final int initialCapacity) {
		return list(iterator(iter), initialCapacity);
	}

	/**
	 * 
	 * @param 
	 * @param iter
	 * @return an {@link ArrayList} containing all elements
	 */
	public static  ArrayList list(final Iterator iter) {
		return addAll(new ArrayList(), iter);
	}

	/**
	 * 
	 * @param 
	 * @param iter
	 * @return an {@link ArrayList} containing all elements
	 */
	public static  ArrayList list(final Iterator iter, final int initialCapacity) {
		return addAll(new ArrayList(initialCapacity), iter);
	}

	/**
	 * adds all elements from iter to collection
	 * 
	 * @param 
	 * @param 
	 * @param collection
	 * @param iter
	 * @return
	 */
	public static > C addAll(final C collection, final Iterator iter) {
		while (iter.hasNext()) {
			collection.add(iter.next());
		}
		return collection;
	}

	/**
	 * adds all elements from iter to map, generating values using function
	 * 
	 * @param 
	 * @param 
	 * @param 
	 * @param map
	 * @param iter
	 * @param func
	 * @return
	 */
	public static > M putKeys(final M map, final Iterator iter, Function func) {
		while (iter.hasNext()) {
			K key = iter.next();
			map.put(key, func.apply(key));
		}
		return map;
	}

	/**
	 * adds all elements from iter to map, generating keys using function
	 * 
	 * @param 
	 * @param 
	 * @param 
	 * @param map
	 * @param iter
	 * @param func
	 * @return
	 */
	public static > M putValues(final M map, final Iterator iter, Function func) {
		while (iter.hasNext()) {
			V value = iter.next();
			map.put(func.apply(value), value);
		}
		return map;
	}

	/**
	 * type save access to {@link #EMPTY_ITERATOR}
	 * 
	 * @param 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static  Iterator empty() {
		return (Iterator) EMPTY_ITERATOR;
	}

	public static  Iterator empty(Class cls) {
		return empty();
	}

	/**
	 * type save access to {@link #EMPTY_ITERABLE}
	 * 
	 * @param 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static  Iterable emptyIterable() {
		return (Iterable) EMPTY_ITERABLE;
	}

	public static  Iterable emptyIterable(Class cls) {
		return emptyIterable();
	}

	public static  Iterator notNull(Iterator iter) {
		if (iter == null) {
			return empty();
		} else {
			return iter;
		}
	}

	public static  Iterable notNull(Iterable iter) {
		if (iter == null) {
			return emptyIterable();
		} else {
			return iter;
		}
	}

	/**
	 * type safe cast from any array to an {@link Iterable}
	 * 
	 * @param 
	 * @param cls
	 * @param list
	 * @return
	 */
	public static  Iterable cast(final Class cls, final Object[] list) {
		return cast(cls, Arrays.asList(list));
	}

	/**
	 * a type safe cast for {@link Iterable}
	 * 
	 * @param 
	 * @param cls
	 * @param iterable
	 * @return
	 */
	public static  Iterable cast(final Class cls, final Iterable iterable) {
		if (cls == null) {
			throw new NullPointerException("cls");
		}
		if (iterable == null) {
			throw new NullPointerException("iterable");
		}

		return new Iterable() {

			@Override
			public Iterator iterator() {
				return new Iterator() {

					private final Iterator _iter = iterable.iterator();

					@Override
					public boolean hasNext() {
						return _iter.hasNext();
					}

					@Override
					public T next() {
						return cls.cast(_iter.next());
					}

					@Override
					public void remove() {
						_iter.remove();
					}
				};
			}
		};
	}

	/**
	 * skips a given number of elements in iterator while there are available
	 * 
	 * @param 
	 * @param iter
	 * @param skip
	 * @return
	 */
	public static  Iterator skip(final Iterator iter, int skip) {
		while (skip-- > 0 && iter.hasNext()) {
			iter.next();
		}
		return iter;
	}

	/**
	 * don't return more elements than given by max
	 * 
	 * @param 
	 * @param iter
	 * @param max
	 * @return
	 */
	public static  Iterator max(final Iterator iter, final int max) {
		return new Iterator() {

			int _remaining = max;

			@Override
			public boolean hasNext() {
				return _remaining > 0 && iter.hasNext();
			}

			@Override
			public T next() {
				if (_remaining <= 0) {
					throw new NoSuchElementException();
				}
				_remaining--;
				return iter.next();
			}

			@Override
			public void remove() {
				iter.remove();
			}

		};
	}

	public static  Iterator object(final T o) {
		return new Iterator() {

			private boolean _hasNext = o != null;

			@Override
			public boolean hasNext() {
				return _hasNext;
			}

			@Override
			public T next() {
				if (!_hasNext) {
					throw new NoSuchElementException();
				}
				_hasNext = false;
				return o;
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException();
			}

		};
	}

	public static  Iterable filter(final Iterable iterable, final Function filter) {
		return new Iterable() {

			@Override
			public Iterator iterator() {
				return filter(iterable.iterator(), filter);
			}

		};
	}

	/**
	 * 
	 * @param 
	 * @param iter
	 * @param filter
	 *            function that returns true if object is allowed
	 * @return
	 */
	public static  Iterator filter(final Iterator iter, final Function filter) {
		return new Iterator() {

			private T _next = findNext();
			private boolean _hasNext;

			private T findNext() {
				while (iter.hasNext()) {
					T next = iter.next();
					if (Boolean.TRUE.equals(filter.apply(next))) {
						_hasNext = true;
						return next;
					}
				}
				_hasNext = false;
				return null;
			}

			@Override
			public boolean hasNext() {
				return _hasNext;
			}

			@Override
			public T next() {
				T next = _next;
				_next = findNext();
				return next;
			}

			@Override
			public void remove() {
				iter.remove();
			}

		};
	}

	public static  Iterator transform(final Iterator iter, final Function f) {
		return new Iterator() {

			@Override
			public boolean hasNext() {
				return iter.hasNext();
			}

			@Override
			public T next() {
				return f.apply(iter.next());
			}

			@Override
			public void remove() {
				iter.remove();
			}
		};
	}

	public static  Iterable transform(final Iterable iterable, final Function f) {
		return new Iterable() {

			@Override
			public Iterator iterator() {
				return transform(iterable.iterator(), f);
			}
		};
	}

	public static boolean equals(Iterable iterable1, Iterable iterable2) {
		return equals(iterable1.iterator(), iterable2.iterator());
	}

	public static boolean equals(Iterator iter1, Iterator iter2) {
		while (iter1.hasNext() && iter2.hasNext()) {
			if (!ObjectUtils.equals(iter1.next(), iter2.next())) {
				return false;
			}
		}
		return iter1.hasNext() == iter2.hasNext();
	}

	public static  Iterable readOnly(@Nonnull final Iterable iter) {
		return new Iterable() {

			@Override
			public Iterator iterator() {
				return readOnly(iter.iterator());
			}
		};
	}

	public static  Iterator readOnly(@Nonnull final Iterator iter) {
		return new Iterator() {

			@Override
			public boolean hasNext() {
				return iter.hasNext();
			}

			@Override
			public T next() {
				return iter.next();
			}

			@Override
			public void remove() {
				throw new UnsupportedOperationException("read-only");
			}
		};
	}

	public static  Iterator chain(final Iterator... iterators) {
		return chain(Arrays.asList(iterators));
	}

	public static  Iterator chain(final Iterable> iterable) {
		return chain(iterator(iterable));
	}

	public static  Iterator chain(final Iterator> iter) {
		return new Iterator() {

			private final Iterator> _iter;
			private Iterator _current;
			private Iterator _previous;

			{
				_iter = iter;
				if (_iter.hasNext()) {
					_current = _iter.next();
					_previous = empty();
					findNext();
				} else {
					_current = empty();
				}
			}

			private void findNext() {
				while (!_current.hasNext() && _iter.hasNext()) {
					_current = _iter.next();
				}
			}

			@Override
			public boolean hasNext() {
				return _current.hasNext();
			}

			@Override
			public T next() {
				T next = _current.next();
				_previous = _current;
				findNext();
				return next;
			}

			@Override
			public void remove() {
				_previous.remove();
			}

		};

	}
}