de.unkrig.commons.util.collections.IterableUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of de-unkrig-commons Show documentation
Show all versions of de-unkrig-commons Show documentation
A versatile Java(TM) library that implements many useful container and utility classes.
/*
* de.unkrig.commons - A general-purpose Java class library
*
* Copyright (c) 2012, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package de.unkrig.commons.util.collections;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicInteger;
import de.unkrig.commons.lang.protocol.Predicate;
import de.unkrig.commons.lang.protocol.Transformer;
import de.unkrig.commons.nullanalysis.NotNull;
import de.unkrig.commons.nullanalysis.Nullable;
/**
* Various {@link Iterable}-related utility methods.
*/
public final
class IterableUtil {
private
IterableUtil() {}
/**
* @return An {@link Iterable} which can't be modified through the {@link Iterator#remove()} method
*/
public static Iterable
unmodifiableIterable(final Iterable i) {
return new Iterable() {
@Override public Iterator
iterator() {
final Iterator it = i.iterator();
return new Iterator() {
@Override public boolean
hasNext() { return it.hasNext(); }
@Override public T
next() { return it.next(); }
@Override public void
remove() { throw new UnsupportedOperationException("remove"); }
};
}
};
}
/**
* @return An {@link Iterable} producing the given {@code subject} {@code n} times
*/
public static Iterable
repeat(final T subject, final int n) {
if (n < 0) throw new IllegalArgumentException(Integer.toString(n));
return new Iterable() {
@Override public Iterator
iterator() {
return new Iterator() {
final AtomicInteger index = new AtomicInteger();
@Override public boolean
hasNext() {
return this.index.intValue() < n;
}
@Override public T
next() {
if (this.index.getAndIncrement() >= n) throw new NoSuchElementException();
return subject;
}
@Override public void
remove() {
throw new UnsupportedOperationException("remove");
}
};
}
};
}
/**
* @return An {@link Iterable} that traverses the elements of the given {@link List} in reverse order.
*/
public static Iterable
reverseList(final List list) {
return new Iterable() {
@Override public Iterator
iterator() {
final ListIterator li = list.listIterator(list.size());
return new Iterator() {
@Override public boolean
hasNext() { return li.hasPrevious(); }
@Override public E
next() { return li.previous(); }
@Override public void
remove() { li.remove(); }
};
}
};
}
/**
* @return An iterator for the elements of {@code element1} and {@code element2}
*/
public static Iterable
concat(Iterable element1, Iterable element2) {
List> l = new ArrayList>(2);
l.add(element1);
l.add(element2);
return IterableUtil.concat(l);
}
/**
* @return An iterator for the elements of {@code element1}, {@code element2} and {@code element3}
*/
public static Iterable
concat(Iterable element1, Iterable element2, Iterable element3) {
List> l = new ArrayList>(3);
l.add(element1);
l.add(element2);
l.add(element3);
return IterableUtil.concat(l);
}
/**
* @return An iterator for the elements of {@code element1}, {@code element2}, {@code element3} and {@code element4}
*/
public static Iterable
concat(Iterable element1, Iterable element2, Iterable element3, Iterable element4) {
List> l = new ArrayList>(4);
l.add(element1);
l.add(element2);
l.add(element3);
l.add(element4);
return IterableUtil.concat(l);
}
/**
* @return An iterator for the elements of the given {@code elements}
*/
public static Iterable
concat(final Iterable> elements) {
return new Iterable() {
@Override public Iterator
iterator() {
return new Iterator() {
Iterator> outer = elements.iterator();
Iterator inner = IteratorUtil.atEnd();
@Override public boolean
hasNext() {
while (!this.inner.hasNext()) {
if (!this.outer.hasNext()) return false;
this.inner = this.outer.next().iterator();
}
return true;
}
@Override public T
next() throws NoSuchElementException {
if (!this.hasNext()) throw new NoSuchElementException();
return this.inner.next();
}
@Override public void
remove() {
this.inner.remove();
}
};
}
};
}
/**
* Returns an {@link Iterable} which hides the elements of the delegate which do not qualifiy.
*/
public static Iterable
filter(final Iterable delegate, final Predicate super T> qualifies) {
return new Iterable() {
@Override public Iterator iterator() { return IteratorUtil.filter(delegate.iterator(), qualifies); }
};
}
/**
* Returns an iterable which contains the transformed elements of the delegate
*/
public static Iterable
transform(final Iterable extends I> delegate, final Transformer transform) {
return new Iterable() {
@Override public Iterator
iterator() { return IteratorUtil.transform(delegate.iterator(), transform); }
};
}
/**
* Wraps the given {@link Iterable} in a collection, which, as enforced by the nature of the {@link Iterable},
* supports only element removal.
*/
public static Collection
asCollection(final Iterable delegate) {
return new AbstractCollection() {
@Override public Iterator
iterator() { return delegate.iterator(); }
@Override public int
size() {
int result = 0;
for (Iterator it = this.iterator(); it.hasNext(); it.next()) result++;
return result;
}
@Override public boolean
isEmpty() { return !this.iterator().hasNext(); }
@Override public boolean
addAll(@Nullable Collection extends T> c) { throw new UnsupportedOperationException(); }
};
}
/**
* A helper interface which extends the "iterator" pattern with the possibility to access not only the "current"
* element, but also the previous and next element.
* @param
*/
public
interface ElementWithContext {
/**
* @return The element before the current element, or {@code null} iffthe current element is the first element
*/
@Nullable T previous();
/**
* @return The current element (always non-{@code null}
*/
T current();
/**
* @return The element after the current element, or {@code null} iff the current element is the last element
*/
@Nullable T next();
}
/**
* @return An iterable which wraps the given delegate
*/
public static Iterable>
iterableWithContext(final Iterable delegate) {
return new Iterable>() {
@Override public Iterator>
iterator() { return IterableUtil.iteratorWithContext(delegate); }
};
}
/**
* @param iterable Must produce non-{@code null} values
* @return An iterator that produces {@link ElementWithContext}s for the elements of the given
* iterable
*/
public static Iterator>
iteratorWithContext(final Iterable iterable) {
class ElementWithContextIterator implements Iterator> {
@Nullable private T current, next;
private final Iterator it = iterable.iterator();
@Override public boolean
hasNext() {
return this.next != null || this.it.hasNext();
}
@Override public ElementWithContext
next() {
final T previous = this.current;
if (this.next == null) {
T e = this.it.next();
assert e != null : "Delegate must produce non-null values";
this.current = e;
} else {
this.current = this.next;
this.next = null;
}
return new ElementWithContext() {
@Override @Nullable public T
previous() { return previous; }
@Override @NotNull public T
current() {
T result = ElementWithContextIterator.this.current;
assert result != null;
return result;
}
@Override @Nullable public T
next() {
if (ElementWithContextIterator.this.next != null) return ElementWithContextIterator.this.next;
if (!ElementWithContextIterator.this.it.hasNext()) return null;
T e = ElementWithContextIterator.this.it.next();
assert e != null : "Delegate must produce non-null values";
ElementWithContextIterator.this.next = e;
return ElementWithContextIterator.this.next;
}
};
}
@Override public void
remove() { throw new UnsupportedOperationException("remove"); }
}
return new ElementWithContextIterator();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy