validators/src/main/java/de/redsix/dmncheck/util/Util.java
package de.redsix.dmncheck.util;
import java.util.Iterator;
import java.util.Objects;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.BiFunction;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
public final class Util {
private Util() {}
public static <A, B, C> Stream<C> zip(
final Stream<? extends A> a,
final Stream<? extends B> b,
final BiFunction<? super A, ? super B, ? extends C> zipper) {
Objects.requireNonNull(zipper);
final Spliterator<? extends A> aSpliterator = Objects.requireNonNull(a).spliterator();
final Spliterator<? extends B> bSpliterator = Objects.requireNonNull(b).spliterator();
// Zipping looses DISTINCT and SORTED characteristics
final int characteristics = aSpliterator.characteristics()
& bSpliterator.characteristics()
& ~(Spliterator.DISTINCT | Spliterator.SORTED);
final long zipSize = ((characteristics & Spliterator.SIZED) != 0)
? Math.min(aSpliterator.getExactSizeIfKnown(), bSpliterator.getExactSizeIfKnown())
: -1;
final Iterator<A> aIterator = Spliterators.iterator(aSpliterator);
final Iterator<B> bIterator = Spliterators.iterator(bSpliterator);
final Iterator<C> cIterator = new Iterator<>() {
@Override
public boolean hasNext() {
return aIterator.hasNext() && bIterator.hasNext();
}
@Override
public C next() {
return zipper.apply(aIterator.next(), bIterator.next());
}
};
final Spliterator<C> split = Spliterators.spliterator(cIterator, zipSize, characteristics);
return (a.isParallel() || b.isParallel())
? StreamSupport.stream(split, true)
: StreamSupport.stream(split, false);
}
public static <A, B, C, D> Stream<D> zip(
final Stream<? extends A> a,
final Stream<? extends B> b,
final Stream<? extends C> c,
final TriFunction<? super A, ? super B, ? super C, ? extends D> zipper) {
Objects.requireNonNull(zipper);
final Spliterator<? extends A> aSpliterator = Objects.requireNonNull(a).spliterator();
final Spliterator<? extends B> bSpliterator = Objects.requireNonNull(b).spliterator();
final Spliterator<? extends C> cSpliterator = Objects.requireNonNull(c).spliterator();
// Zipping looses DISTINCT and SORTED characteristics
final int characteristics = aSpliterator.characteristics()
& bSpliterator.characteristics()
& cSpliterator.characteristics()
& ~(Spliterator.DISTINCT | Spliterator.SORTED);
final long zipSize = ((characteristics & Spliterator.SIZED) != 0)
? Math.min(
aSpliterator.getExactSizeIfKnown(),
Math.min(bSpliterator.getExactSizeIfKnown(), cSpliterator.getExactSizeIfKnown()))
: -1;
final Iterator<A> aIterator = Spliterators.iterator(aSpliterator);
final Iterator<B> bIterator = Spliterators.iterator(bSpliterator);
final Iterator<C> cIterator = Spliterators.iterator(cSpliterator);
final Iterator<D> dIterator = new Iterator<>() {
@Override
public boolean hasNext() {
return aIterator.hasNext() && bIterator.hasNext() && cIterator.hasNext();
}
@Override
public D next() {
return zipper.apply(aIterator.next(), bIterator.next(), cIterator.next());
}
};
final Spliterator<D> split = Spliterators.spliterator(dIterator, zipSize, characteristics);
return (a.isParallel() || b.isParallel() || c.isParallel())
? StreamSupport.stream(split, true)
: StreamSupport.stream(split, false);
}
}