/*******************************************************************************
* Breakout Cave Survey Visualizer
*
* Copyright (C) 2014 James Edwards
*
* jedwards8 at fastmail dot fm
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*******************************************************************************/
package org.andork.collect;
import java.util.Arrays;
import java.util.Iterator;
/**
* An {@link Iterable} that concatenates the results from multiple
* {@code Iterable}s together.
*
* @author andy.edwards
*
* @param <T>
* the element type.
*/
public class IterableChain<T> implements Iterable<T> {
private static class ChainIterator<T> implements Iterator<T> {
private final Iterator<? extends T> first;
private final Iterator<? extends T> second;
private Iterator<? extends T> last;
private ChainIterator() {
this(null, null);
}
private ChainIterator(Iterator<? extends T> first) {
this(first, null);
}
private ChainIterator(Iterator<? extends T> first, Iterator<? extends T> second) {
super();
if (first == null && second != null) {
first = second;
second = null;
}
this.first = first;
this.second = second;
}
@Override
public boolean hasNext() {
return first != null && first.hasNext() || second != null && second.hasNext();
}
@Override
public T next() {
last = first.hasNext() || second == null ? first : second;
return last.next();
}
@Override
public void remove() {
last.remove();
}
}
public static <T> Iterable<T> join(Iterable<? extends Iterable<? extends T>> chain) {
Iterator<? extends Iterable<? extends T>> i = chain.iterator();
if (!i.hasNext()) {
return new IterableChain<T>();
}
Iterable<? extends T> first = i.next();
if (!i.hasNext()) {
return new IterableChain<T>(first);
}
Iterable<? extends T> second = i.next();
IterableChain<T> result = new IterableChain<T>(first, second);
while (i.hasNext()) {
result = result.add(i.next());
}
return result;
}
public static <T> Iterable<T> join(Iterable<? extends T>... chain) {
return join(Arrays.asList(chain));
}
private final Iterable<? extends T> first;
private final Iterable<? extends T> second;
public IterableChain() {
this(null, null);
}
public IterableChain(Iterable<? extends T> first) {
this(first, null);
}
public IterableChain(Iterable<? extends T> first, Iterable<? extends T> second) {
super();
if (first == null && second != null) {
first = second;
second = null;
}
this.first = first;
this.second = second;
}
public IterableChain<T> add(Iterable<? extends T> next) {
return new IterableChain<T>(this, next);
}
@Override
public Iterator<T> iterator() {
return new ChainIterator<T>(first == null ? null : first.iterator(), second == null ? null : second.iterator());
}
}