com.landawn.abacus.util.stream.ByteStream Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of abacus-common Show documentation
Show all versions of abacus-common Show documentation
A general programming library in Java/Android. It's easy to learn and simple to use with concise and powerful APIs.
/*
* Copyright (C) 2016, 2017, 2018, 2019 HaiYang Li
*
* 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 com.landawn.abacus.util.stream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.Random;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.BinaryOperator;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.annotation.IntermediateOp;
import com.landawn.abacus.annotation.LazyEvaluation;
import com.landawn.abacus.annotation.ParallelSupported;
import com.landawn.abacus.annotation.SequentialOnly;
import com.landawn.abacus.annotation.TerminalOp;
import com.landawn.abacus.exception.UncheckedIOException;
import com.landawn.abacus.util.Array;
import com.landawn.abacus.util.AsyncExecutor;
import com.landawn.abacus.util.ByteIterator;
import com.landawn.abacus.util.ByteList;
import com.landawn.abacus.util.ByteSummaryStatistics;
import com.landawn.abacus.util.ClassUtil;
import com.landawn.abacus.util.ContinuableFuture;
import com.landawn.abacus.util.Fn;
import com.landawn.abacus.util.Fn.FnB;
import com.landawn.abacus.util.Holder;
import com.landawn.abacus.util.IOUtil;
import com.landawn.abacus.util.IndexedByte;
import com.landawn.abacus.util.MergeResult;
import com.landawn.abacus.util.MutableInt;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.Pair;
import com.landawn.abacus.util.Percentage;
import com.landawn.abacus.util.RateLimiter;
import com.landawn.abacus.util.Throwables;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.u.OptionalByte;
import com.landawn.abacus.util.u.OptionalDouble;
import com.landawn.abacus.util.function.ByteBiFunction;
import com.landawn.abacus.util.function.ByteBiPredicate;
import com.landawn.abacus.util.function.ByteBinaryOperator;
import com.landawn.abacus.util.function.ByteConsumer;
import com.landawn.abacus.util.function.ByteFunction;
import com.landawn.abacus.util.function.ByteNFunction;
import com.landawn.abacus.util.function.BytePredicate;
import com.landawn.abacus.util.function.ByteSupplier;
import com.landawn.abacus.util.function.ByteTernaryOperator;
import com.landawn.abacus.util.function.ByteToIntFunction;
import com.landawn.abacus.util.function.ByteTriPredicate;
import com.landawn.abacus.util.function.ByteUnaryOperator;
import com.landawn.abacus.util.function.ObjByteConsumer;
import com.landawn.abacus.util.function.ToByteFunction;
/**
* The Stream will be automatically closed after execution(A terminal method is executed/triggered).
*
* @see BaseStream
* @see Stream
*/
@com.landawn.abacus.annotation.Immutable
@LazyEvaluation
public abstract class ByteStream extends StreamBase {
static final Random RAND = new SecureRandom();
ByteStream(final boolean sorted, final Collection closeHandlers) {
super(sorted, null, closeHandlers);
}
@Override
public ByteStream rateLimited(final RateLimiter rateLimiter) {
checkArgNotNull(rateLimiter, "rateLimiter");
final ByteConsumer action = it -> rateLimiter.acquire();
if (isParallel()) {
return sequential().onEach(action).parallel(maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(), cancelUncompletedThreads());
} else {
return onEach(action);
}
}
@Override
public ByteStream skipUntil(final BytePredicate predicate) {
assertNotClosed();
return dropWhile(t -> !predicate.test(t));
}
@ParallelSupported
@IntermediateOp
public abstract ByteStream map(ByteUnaryOperator mapper);
@ParallelSupported
@IntermediateOp
public abstract IntStream mapToInt(ByteToIntFunction mapper);
@ParallelSupported
@IntermediateOp
public abstract Stream mapToObj(ByteFunction extends U> mapper);
@ParallelSupported
@IntermediateOp
public abstract ByteStream flatMap(ByteFunction extends ByteStream> mapper);
// @ParallelSupported
// @IntermediateOp
// public abstract ByteStream flatmap(ByteFunction mapper);
@ParallelSupported
@IntermediateOp
public abstract ByteStream flatmap(ByteFunction mapper);
@ParallelSupported
@IntermediateOp
public abstract IntStream flatMapToInt(ByteFunction extends IntStream> mapper);
@ParallelSupported
@IntermediateOp
public abstract Stream flatMapToObj(ByteFunction extends Stream> mapper);
@ParallelSupported
@IntermediateOp
public abstract Stream flatmapToObj(ByteFunction extends Collection> mapper);
@ParallelSupported
@IntermediateOp
public abstract Stream flattMapToObj(ByteFunction mapper);
/**
* Note: copied from StreamEx: https://github.com/amaembo/streamex
*
* @param
* @param mapper
* @return
*/
@Beta
@ParallelSupported
@IntermediateOp
public abstract ByteStream mapPartial(ByteFunction mapper);
/**
* Note: copied from StreamEx: https://github.com/amaembo/streamex
*
*
*
* Returns a stream consisting of results of applying the given function to
* the ranges created from the source elements.
* This is a quasi-intermediate
* partial reduction operation.
*
* @param sameRange a non-interfering, stateless predicate to apply to
* the leftmost and next elements which returns true for elements
* which belong to the same range.
* @param mapper a non-interfering, stateless function to apply to the
* range borders and produce the resulting element. If value was
* not merged to the interval, then mapper will receive the same
* value twice, otherwise it will receive the leftmost and the
* rightmost values which were merged to the range.
* @return
* @see #collapse(ByteBiPredicate, ByteBinaryOperator)
* @see Stream#rangeMap(BiPredicate, BiFunction)
*/
@SequentialOnly
@IntermediateOp
public abstract ByteStream rangeMap(final ByteBiPredicate sameRange, final ByteBinaryOperator mapper);
/**
* Note: copied from StreamEx: https://github.com/amaembo/streamex
*
*
*
* Returns a stream consisting of results of applying the given function to
* the ranges created from the source elements.
* This is a quasi-intermediate
* partial reduction operation.
*
* @param sameRange a non-interfering, stateless predicate to apply to
* the leftmost and next elements which returns true for elements
* which belong to the same range.
* @param mapper a non-interfering, stateless function to apply to the
* range borders and produce the resulting element. If value was
* not merged to the interval, then mapper will receive the same
* value twice, otherwise it will receive the leftmost and the
* rightmost values which were merged to the range.
* @return
* @see Stream#rangeMap(BiPredicate, BiFunction)
*/
@SequentialOnly
@IntermediateOp
public abstract Stream rangeMapToObj(final ByteBiPredicate sameRange, final ByteBiFunction mapper);
/**
* Merge series of adjacent elements which satisfy the given predicate using
* the merger function and return a new stream.
*
*
* This method only runs sequentially, even in parallel stream.
*
* @param collapsible
* @return
*/
@SequentialOnly
@IntermediateOp
public abstract Stream collapse(final ByteBiPredicate collapsible);
/**
* Merge series of adjacent elements which satisfy the given predicate using
* the merger function and return a new stream.
*
*
* This method only runs sequentially, even in parallel stream.
*
* @param collapsible
* @param mergeFunction
* @return
*/
@SequentialOnly
@IntermediateOp
public abstract ByteStream collapse(final ByteBiPredicate collapsible, final ByteBinaryOperator mergeFunction);
/**
*
* @param collapsible test the current element with the first element and previous element in the series. The first parameter is the first element of this series, the second parameter is the previous element and the third parameter is the current element.
* @param mergeFunction
* @return
*/
@SequentialOnly
@IntermediateOp
public abstract ByteStream collapse(final ByteTriPredicate collapsible, final ByteBinaryOperator mergeFunction);
/**
* Returns a {@code Stream} produced by iterative application of a accumulation function
* to an initial element {@code init} and next element of the current stream.
* Produces a {@code Stream} consisting of {@code init}, {@code acc(init, value1)},
* {@code acc(acc(init, value1), value2)}, etc.
*
* This is an intermediate operation.
*
*
Example:
*
* accumulator: (a, b) -> a + b
* stream: [1, 2, 3, 4, 5]
* result: [1, 3, 6, 10, 15]
*
*
*
* This method only runs sequentially, even in parallel stream.
*
* @param accumulator the accumulation function
* @return
*/
@SequentialOnly
@IntermediateOp
public abstract ByteStream scan(final ByteBinaryOperator accumulator);
/**
* Returns a {@code Stream} produced by iterative application of a accumulation function
* to an initial element {@code init} and next element of the current stream.
* Produces a {@code Stream} consisting of {@code init}, {@code acc(init, value1)},
* {@code acc(acc(init, value1), value2)}, etc.
*
* This is an intermediate operation.
*
*
Example:
*
* init:10
* accumulator: (a, b) -> a + b
* stream: [1, 2, 3, 4, 5]
* result: [11, 13, 16, 20, 25]
*
*
*
* This method only runs sequentially, even in parallel stream.
*
* @param init the initial value. it's only used once by accumulator
to calculate the fist element in the returned stream.
* It will be ignored if this stream is empty and won't be the first element of the returned stream.
*
* @param accumulator the accumulation function
* @return
*/
@SequentialOnly
@IntermediateOp
public abstract ByteStream scan(final byte init, final ByteBinaryOperator accumulator);
/**
*
* @param init
* @param accumulator
* @param initIncluded
* @return
*/
@SequentialOnly
@IntermediateOp
public abstract ByteStream scan(final byte init, final ByteBinaryOperator accumulator, final boolean initIncluded);
@SequentialOnly
@IntermediateOp
public abstract ByteStream prepend(final byte... a);
@SequentialOnly
@IntermediateOp
public abstract ByteStream append(final byte... a);
@SequentialOnly
@IntermediateOp
public abstract ByteStream appendIfEmpty(final byte... a);
@SequentialOnly
@TerminalOp
public abstract ByteList toByteList();
/**
*
* @param keyMapper
* @param valueMapper
* @return
* @see Collectors#toMap(Throwables.Function, Throwables.Function)
*/
@ParallelSupported
@TerminalOp
public abstract Map toMap(Throwables.ByteFunction extends K, E> keyMapper,
Throwables.ByteFunction extends V, E2> valueMapper) throws E, E2;
/**
*
* @param keyMapper
* @param valueMapper
* @param mapFactory
* @return
* @see Collectors#toMap(Throwables.Function, Throwables.Function, Supplier)
*/
@ParallelSupported
@TerminalOp
public abstract , E extends Exception, E2 extends Exception> M toMap(Throwables.ByteFunction extends K, E> keyMapper,
Throwables.ByteFunction extends V, E2> valueMapper, Supplier extends M> mapFactory) throws E, E2;
/**
*
* @param keyMapper
* @param valueMapper
* @param mergeFunction
* @return
* @see Collectors#toMap(Throwables.Function, Throwables.Function, BinaryOperator)
*/
@ParallelSupported
@TerminalOp
public abstract Map toMap(Throwables.ByteFunction extends K, E> keyMapper,
Throwables.ByteFunction extends V, E2> valueMapper, BinaryOperator mergeFunction) throws E, E2;
/**
*
* @param keyMapper
* @param valueMapper
* @param mergeFunction
* @param mapFactory
* @return
* @see Collectors#toMap(Throwables.Function, Throwables.Function, BinaryOperator, Supplier)
*/
@ParallelSupported
@TerminalOp
public abstract , E extends Exception, E2 extends Exception> M toMap(Throwables.ByteFunction extends K, E> keyMapper,
Throwables.ByteFunction extends V, E2> valueMapper, BinaryOperator mergeFunction, Supplier extends M> mapFactory) throws E, E2;
/**
*
* @param keyMapper
* @param downstream
* @return
* @see Collectors#groupingBy(Throwables.Function, Collector)
*/
@ParallelSupported
@TerminalOp
public abstract Map groupTo(Throwables.ByteFunction extends K, E> keyMapper, final Collector downstream)
throws E;
/**
*
* @param keyMapper
* @param downstream
* @param mapFactory
* @return
* @see Collectors#groupingBy(Throwables.Function, Collector, Supplier)
*/
@ParallelSupported
@TerminalOp
public abstract , E extends Exception> M groupTo(Throwables.ByteFunction extends K, E> keyMapper,
final Collector downstream, final Supplier extends M> mapFactory) throws E;
/**
*
* @param identity
* @param op
* @return
*/
@ParallelSupported
@TerminalOp
public abstract byte reduce(byte identity, ByteBinaryOperator op);
/**
*
* @param op
* @return
*/
@ParallelSupported
@TerminalOp
public abstract OptionalByte reduce(ByteBinaryOperator op);
/**
*
* @param supplier
* @param accumulator
* @param combiner
* @return
* @see Stream#collect(Supplier, BiConsumer, BiConsumer)
*/
@ParallelSupported
@TerminalOp
public abstract R collect(Supplier supplier, ObjByteConsumer super R> accumulator, BiConsumer combiner);
/**
* Only call this method when the returned type {@code R} is one types: {@code Collection/Map/StringBuilder/Multiset/LongMultiset/Multimap/BooleanList/IntList/.../DoubleList}.
* Otherwise, please call {@link #collect(Supplier, ObjByteConsumer, BiConsumer)}.
*
* @param supplier
* @param accumulator
* @return
* @see #collect(Supplier, ObjByteConsumer, BiConsumer)
* @see Stream#collect(Supplier, BiConsumer)
* @see Stream#collect(Supplier, BiConsumer, BiConsumer)
*/
@ParallelSupported
@TerminalOp
public abstract R collect(Supplier supplier, ObjByteConsumer super R> accumulator);
@ParallelSupported
@TerminalOp
public abstract void forEach(Throwables.ByteConsumer action) throws E;
@ParallelSupported
@TerminalOp
public abstract void forEachIndexed(Throwables.IndexedByteConsumer action) throws E;
@ParallelSupported
@TerminalOp
public abstract boolean anyMatch(final Throwables.BytePredicate predicate) throws E;
@ParallelSupported
@TerminalOp
public abstract boolean allMatch(final Throwables.BytePredicate predicate) throws E;
@ParallelSupported
@TerminalOp
public abstract boolean noneMatch(final Throwables.BytePredicate predicate) throws E;
@ParallelSupported
@TerminalOp
public abstract OptionalByte findFirst(final Throwables.BytePredicate predicate) throws E;
/**
* Returns the first element matched by {@code predicateForFirst} if found or the first element if this stream is not empty
* Otherwise an empty {@code OptionalByte} will be returned.
*
* @param
* @param predicateForFirst
* @return
* @throws E
*/
@ParallelSupported
@TerminalOp
public abstract OptionalByte findFirstOrAny(Throwables.BytePredicate predicateForFirst) throws E;
/**
* Returns the first element matched by {@code predicateForFirst} if found or the last element if this stream is not empty
* Otherwise an empty {@code OptionalByte} will be returned.
*
* @param
* @param predicateForFirst
* @return
* @throws E
*/
@ParallelSupported
@TerminalOp
public abstract OptionalByte findFirstOrLast(Throwables.BytePredicate predicateForFirst) throws E;
/**
* Consider using: {@code stream.reversed().findFirst(predicate)} for better performance if possible.
*
* @param
* @param predicate
* @return
* @throws E
*/
@ParallelSupported
@TerminalOp
public abstract OptionalByte findLast(final Throwables.BytePredicate predicate) throws E;
@ParallelSupported
@TerminalOp
public abstract OptionalByte findAny(final Throwables.BytePredicate predicate) throws E;
@SequentialOnly
@TerminalOp
public abstract OptionalByte min();
@SequentialOnly
@TerminalOp
public abstract OptionalByte max();
/**
*
* @param k
* @return OptionalByte.empty() if there is no element or count less than k, otherwise the kth largest element.
*/
@SequentialOnly
@TerminalOp
public abstract OptionalByte kthLargest(int k);
/**
*
* @return int
*/
@SequentialOnly
@TerminalOp
public abstract long sum();
@SequentialOnly
@TerminalOp
public abstract OptionalDouble average();
@SequentialOnly
@TerminalOp
public abstract ByteSummaryStatistics summarize();
@SequentialOnly
@TerminalOp
public abstract Pair>> summarizeAndPercentiles();
/**
*
* @param b
* @param nextSelector first parameter is selected if Nth.FIRST
is returned, otherwise the second parameter is selected.
* @return
* @deprecated replaced by {@code mergeWith(ByteStream, ByteBiFunction)}
* @see #mergeWith(ByteStream, ByteBiFunction)
*/
@SequentialOnly
@IntermediateOp
@Deprecated
public ByteStream merge(final ByteStream b, final ByteBiFunction nextSelector) {
return mergeWith(b, nextSelector);
}
/**
*
* @param b
* @param nextSelector first parameter is selected if Nth.FIRST
is returned, otherwise the second parameter is selected.
* @return
*/
@SequentialOnly
@IntermediateOp
public abstract ByteStream mergeWith(final ByteStream b, final ByteBiFunction nextSelector);
@ParallelSupported
@IntermediateOp
public abstract ByteStream zipWith(ByteStream b, ByteBinaryOperator zipFunction);
@ParallelSupported
@IntermediateOp
public abstract ByteStream zipWith(ByteStream b, ByteStream c, ByteTernaryOperator zipFunction);
@ParallelSupported
@IntermediateOp
public abstract ByteStream zipWith(ByteStream b, byte valueForNoneA, byte valueForNoneB, ByteBinaryOperator zipFunction);
@ParallelSupported
@IntermediateOp
public abstract ByteStream zipWith(ByteStream b, ByteStream c, byte valueForNoneA, byte valueForNoneB, byte valueForNoneC, ByteTernaryOperator zipFunction);
@SequentialOnly
@IntermediateOp
public abstract IntStream asIntStream();
@SequentialOnly
@IntermediateOp
public abstract Stream boxed();
/**
* Remember to close this Stream after the iteration is done, if needed.
*
* @return
*/
@Override
public ByteIterator iterator() {
assertNotClosed();
if (!isEmptyCloseHandlers(closeHandlers) && logger.isWarnEnabled()) {
logger.warn("### Remember to close " + ClassUtil.getSimpleClassName(getClass()));
}
return iteratorEx();
}
abstract ByteIteratorEx iteratorEx();
public static ByteStream empty() {
return new ArrayByteStream(N.EMPTY_BYTE_ARRAY, true, null);
}
public static ByteStream ofNullable(final Byte e) {
return e == null ? empty() : of(e);
}
@SafeVarargs
public static ByteStream of(final byte... a) {
return N.isNullOrEmpty(a) ? empty() : new ArrayByteStream(a);
}
public static ByteStream of(final byte[] a, final int startIndex, final int endIndex) {
return N.isNullOrEmpty(a) && (startIndex == 0 && endIndex == 0) ? empty() : new ArrayByteStream(a, startIndex, endIndex);
}
public static ByteStream of(final Byte[] a) {
return Stream.of(a).mapToByte(FnB.unbox());
}
public static ByteStream of(final Byte[] a, final int startIndex, final int endIndex) {
return Stream.of(a, startIndex, endIndex).mapToByte(FnB.unbox());
}
public static ByteStream of(final Collection c) {
return Stream.of(c).mapToByte(FnB.unbox());
}
public static ByteStream of(final ByteIterator iterator) {
return iterator == null ? empty() : new IteratorByteStream(iterator);
}
public static ByteStream of(final ByteBuffer buf) {
if (buf == null) {
return empty();
}
return IntStream.range(buf.position(), buf.limit()).mapToByte(buf::get);
}
public static ByteStream of(final File file) {
return of(IOUtil.newFileInputStream(file), true);
}
public static ByteStream of(final InputStream is) {
return of(is, false);
}
public static ByteStream of(final InputStream is, final boolean closeReaderAferExecution) {
if (is == null) {
return empty();
}
final ByteIterator iter = new ByteIterator() {
private final byte[] buf = new byte[8192];
private boolean isEnd = false;
private int count = 0;
private int idx = 0;
@Override
public boolean hasNext() {
if (idx >= count && !isEnd) {
try {
count = is.read(buf);
idx = 0;
isEnd = count <= 0;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
return count > idx;
}
@Override
public byte nextByte() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return buf[idx++];
}
};
if (closeReaderAferExecution) {
return of(iter).onClose(Fn.close(is));
} else {
return of(iter);
}
}
/**
* Lazy evaluation.
*
*
* This is equal to: {@code Stream.just(supplier).flatMapToByte(it -> it.get())}.
*
* @param
* @param supplier
* @return
*/
public static ByteStream defer(final Supplier supplier) {
N.checkArgNotNull(supplier, "supplier");
return Stream.just(supplier).flatMapToByte(Supplier::get);
}
/**
* Lazy evaluation.
*
*
* This is equal to: {@code Stream.just(supplier).flatMapToByte(it -> it.get().stream())}.
*
* @param supplier
* @return
*/
@Beta
public static ByteStream from(final Supplier supplier) {
N.checkArgNotNull(supplier, "supplier");
return Stream.just(supplier).flatMapToByte(it -> it.get().stream());
}
private static final Function flatMapper = ByteStream::of;
private static final Function flattMapper = ByteStream::flatten;
public static ByteStream flatten(final byte[][] a) {
return N.isNullOrEmpty(a) ? empty() : Stream.of(a).flatMapToByte(flatMapper);
}
public static ByteStream flatten(final byte[][] a, final boolean vertically) {
if (N.isNullOrEmpty(a)) {
return empty();
} else if (a.length == 1) {
return of(a[0]);
} else if (!vertically) {
return Stream.of(a).flatMapToByte(flatMapper);
}
long n = 0;
for (byte[] e : a) {
n += N.len(e);
}
if (n == 0) {
return empty();
}
final int rows = N.len(a);
final long count = n;
final ByteIterator iter = new ByteIteratorEx() {
private int rowNum = 0;
private int colNum = 0;
private long cnt = 0;
@Override
public boolean hasNext() {
return cnt < count;
}
@Override
public byte nextByte() {
if (cnt++ >= count) {
throw new NoSuchElementException();
}
if (rowNum == rows) {
rowNum = 0;
colNum++;
}
while (a[rowNum] == null || colNum >= a[rowNum].length) {
if (rowNum < rows - 1) {
rowNum++;
} else {
rowNum = 0;
colNum++;
}
}
return a[rowNum++][colNum];
}
};
return of(iter);
}
public static ByteStream flatten(final byte[][] a, final byte valueForNone, final boolean vertically) {
if (N.isNullOrEmpty(a)) {
return empty();
} else if (a.length == 1) {
return of(a[0]);
}
long n = 0;
int maxLen = 0;
for (byte[] e : a) {
n += N.len(e);
maxLen = N.max(maxLen, N.len(e));
}
if (n == 0) {
return empty();
}
final int rows = N.len(a);
final int cols = maxLen;
final long count = (long) rows * cols;
ByteIterator iter = null;
if (vertically) {
iter = new ByteIteratorEx() {
private int rowNum = 0;
private int colNum = 0;
private long cnt = 0;
@Override
public boolean hasNext() {
return cnt < count;
}
@Override
public byte nextByte() {
if (cnt++ >= count) {
throw new NoSuchElementException();
}
if (rowNum == rows) {
rowNum = 0;
colNum++;
}
if (a[rowNum] == null || colNum >= a[rowNum].length) {
rowNum++;
return valueForNone;
} else {
return a[rowNum++][colNum];
}
}
};
} else {
iter = new ByteIteratorEx() {
private int rowNum = 0;
private int colNum = 0;
private long cnt = 0;
@Override
public boolean hasNext() {
return cnt < count;
}
@Override
public byte nextByte() {
if (cnt++ >= count) {
throw new NoSuchElementException();
}
if (colNum >= cols) {
colNum = 0;
rowNum++;
}
if (a[rowNum] == null || colNum >= a[rowNum].length) {
colNum++;
return valueForNone;
} else {
return a[rowNum][colNum++];
}
}
};
}
return of(iter);
}
public static ByteStream flatten(final byte[][][] a) {
return N.isNullOrEmpty(a) ? empty() : Stream.of(a).flatMapToByte(flattMapper);
}
public static ByteStream range(final byte startInclusive, final byte endExclusive) {
if (startInclusive >= endExclusive) {
return empty();
}
return new IteratorByteStream(new ByteIteratorEx() {
private byte next = startInclusive;
private int cnt = endExclusive * 1 - startInclusive;
@Override
public boolean hasNext() {
return cnt > 0;
}
@Override
public byte nextByte() {
if (cnt-- <= 0) {
throw new NoSuchElementException();
}
return next++;
}
@Override
public void advance(long n) {
cnt = n >= cnt ? 0 : cnt - (int) n;
next += n;
}
@Override
public long count() {
return cnt;
}
@Override
public byte[] toArray() {
final byte[] result = new byte[cnt];
for (int i = 0; i < cnt; i++) {
result[i] = next++;
}
cnt = 0;
return result;
}
});
}
public static ByteStream range(final byte startInclusive, final byte endExclusive, final byte by) {
if (by == 0) {
throw new IllegalArgumentException("'by' can't be zero");
}
if (endExclusive == startInclusive || endExclusive > startInclusive != by > 0) {
return empty();
}
return new IteratorByteStream(new ByteIteratorEx() {
private byte next = startInclusive;
private int cnt = (endExclusive * 1 - startInclusive) / by + ((endExclusive * 1 - startInclusive) % by == 0 ? 0 : 1);
@Override
public boolean hasNext() {
return cnt > 0;
}
@Override
public byte nextByte() {
if (cnt-- <= 0) {
throw new NoSuchElementException();
}
byte result = next;
next += by;
return result;
}
@Override
public void advance(long n) {
cnt = n >= cnt ? 0 : cnt - (int) n;
next += n * by;
}
@Override
public long count() {
return cnt;
}
@Override
public byte[] toArray() {
final byte[] result = new byte[cnt];
for (int i = 0; i < cnt; i++, next += by) {
result[i] = next;
}
cnt = 0;
return result;
}
});
}
public static ByteStream rangeClosed(final byte startInclusive, final byte endInclusive) {
if (startInclusive > endInclusive) {
empty();
} else if (startInclusive == endInclusive) {
return of(startInclusive);
}
return new IteratorByteStream(new ByteIteratorEx() {
private byte next = startInclusive;
private int cnt = endInclusive * 1 - startInclusive + 1;
@Override
public boolean hasNext() {
return cnt > 0;
}
@Override
public byte nextByte() {
if (cnt-- <= 0) {
throw new NoSuchElementException();
}
return next++;
}
@Override
public void advance(long n) {
cnt = n >= cnt ? 0 : cnt - (int) n;
next += n;
}
@Override
public long count() {
return cnt;
}
@Override
public byte[] toArray() {
final byte[] result = new byte[cnt];
for (int i = 0; i < cnt; i++) {
result[i] = next++;
}
cnt = 0;
return result;
}
});
}
public static ByteStream rangeClosed(final byte startInclusive, final byte endInclusive, final byte by) {
if (by == 0) {
throw new IllegalArgumentException("'by' can't be zero");
}
if (endInclusive == startInclusive) {
return of(startInclusive);
} else if (endInclusive > startInclusive != by > 0) {
return empty();
}
return new IteratorByteStream(new ByteIteratorEx() {
private byte next = startInclusive;
private int cnt = (endInclusive * 1 - startInclusive) / by + 1;
@Override
public boolean hasNext() {
return cnt > 0;
}
@Override
public byte nextByte() {
if (cnt-- <= 0) {
throw new NoSuchElementException();
}
byte result = next;
next += by;
return result;
}
@Override
public void advance(long n) {
cnt = n >= cnt ? 0 : cnt - (int) n;
next += n * by;
}
@Override
public long count() {
return cnt;
}
@Override
public byte[] toArray() {
final byte[] result = new byte[cnt];
for (int i = 0; i < cnt; i++, next += by) {
result[i] = next;
}
cnt = 0;
return result;
}
});
}
public static ByteStream repeat(final byte element, final long n) {
N.checkArgNotNegative(n, "n");
if (n == 0) {
return empty();
} else if (n < 10) {
return of(Array.repeat(element, (int) n));
}
return new IteratorByteStream(new ByteIteratorEx() {
private long cnt = n;
@Override
public boolean hasNext() {
return cnt > 0;
}
@Override
public byte nextByte() {
if (cnt-- <= 0) {
throw new NoSuchElementException();
}
return element;
}
@Override
public void advance(long n) {
cnt = n >= cnt ? 0 : cnt - (int) n;
}
@Override
public long count() {
return cnt;
}
@Override
public byte[] toArray() {
final byte[] result = new byte[(int) cnt];
for (int i = 0; i < cnt; i++) {
result[i] = element;
}
cnt = 0;
return result;
}
});
}
public static ByteStream random() {
final int bound = Byte.MAX_VALUE - Byte.MIN_VALUE + 1;
return generate(() -> (byte) (RAND.nextInt(bound) + Byte.MIN_VALUE));
}
public static ByteStream iterate(final BooleanSupplier hasNext, final ByteSupplier next) {
N.checkArgNotNull(hasNext);
N.checkArgNotNull(next);
return new IteratorByteStream(new ByteIteratorEx() {
private boolean hasNextVal = false;
@Override
public boolean hasNext() {
if (!hasNextVal) {
hasNextVal = hasNext.getAsBoolean();
}
return hasNextVal;
}
@Override
public byte nextByte() {
if (!hasNextVal && !hasNext()) {
throw new NoSuchElementException();
}
hasNextVal = false;
return next.getAsByte();
}
});
}
public static ByteStream iterate(final byte init, final BooleanSupplier hasNext, final ByteUnaryOperator f) {
N.checkArgNotNull(hasNext);
N.checkArgNotNull(f);
return new IteratorByteStream(new ByteIteratorEx() {
private byte t = 0;
private boolean isFirst = true;
private boolean hasNextVal = false;
@Override
public boolean hasNext() {
if (!hasNextVal) {
hasNextVal = hasNext.getAsBoolean();
}
return hasNextVal;
}
@Override
public byte nextByte() {
if (!hasNextVal && !hasNext()) {
throw new NoSuchElementException();
}
hasNextVal = false;
if (isFirst) {
isFirst = false;
t = init;
} else {
t = f.applyAsByte(t);
}
return t;
}
});
}
/**
*
* @param init
* @param hasNext test if has next by hasNext.test(init) for first time and hasNext.test(f.apply(previous)) for remaining.
* @param f
* @return
*/
public static ByteStream iterate(final byte init, final BytePredicate hasNext, final ByteUnaryOperator f) {
N.checkArgNotNull(hasNext);
N.checkArgNotNull(f);
return new IteratorByteStream(new ByteIteratorEx() {
private byte t = 0;
private byte cur = 0;
private boolean isFirst = true;
private boolean hasMore = true;
private boolean hasNextVal = false;
@Override
public boolean hasNext() {
if (!hasNextVal && hasMore) {
if (isFirst) {
isFirst = false;
hasNextVal = hasNext.test(cur = init);
} else {
hasNextVal = hasNext.test(cur = f.applyAsByte(t));
}
if (!hasNextVal) {
hasMore = false;
}
}
return hasNextVal;
}
@Override
public byte nextByte() {
if (!hasNextVal && !hasNext()) {
throw new NoSuchElementException();
}
t = cur;
hasNextVal = false;
return t;
}
});
}
public static ByteStream iterate(final byte init, final ByteUnaryOperator f) {
N.checkArgNotNull(f);
return new IteratorByteStream(new ByteIteratorEx() {
private byte t = 0;
private boolean isFirst = true;
@Override
public boolean hasNext() {
return true;
}
@Override
public byte nextByte() {
if (isFirst) {
isFirst = false;
t = init;
} else {
t = f.applyAsByte(t);
}
return t;
}
});
}
public static ByteStream generate(final ByteSupplier s) {
N.checkArgNotNull(s);
return new IteratorByteStream(new ByteIteratorEx() {
@Override
public boolean hasNext() {
return true;
}
@Override
public byte nextByte() {
return s.getAsByte();
}
});
}
@SafeVarargs
public static ByteStream concat(final byte[]... a) {
if (N.isNullOrEmpty(a)) {
return empty();
}
return concat(Arrays.asList(a));
}
@SafeVarargs
public static ByteStream concat(final ByteIterator... a) {
if (N.isNullOrEmpty(a)) {
return empty();
}
return concatIterators(Array.asList(a));
}
@SafeVarargs
public static ByteStream concat(final ByteStream... a) {
if (N.isNullOrEmpty(a)) {
return empty();
}
return concat(Array.asList(a));
}
@Beta
public static ByteStream concat(final List c) {
if (N.isNullOrEmpty(c)) {
return empty();
}
return of(new ByteIteratorEx() {
private final Iterator iter = c.iterator();
private byte[] cur;
private int cursor = 0;
@Override
public boolean hasNext() {
while ((N.isNullOrEmpty(cur) || cursor >= cur.length) && iter.hasNext()) {
cur = iter.next();
cursor = 0;
}
return cur != null && cursor < cur.length;
}
@Override
public byte nextByte() {
if ((cur == null || cursor >= cur.length) && !hasNext()) {
throw new NoSuchElementException();
}
return cur[cursor++];
}
});
}
public static ByteStream concat(final Collection extends ByteStream> c) {
return N.isNullOrEmpty(c) ? empty() : new IteratorByteStream(new ByteIteratorEx() {
private final Iterator extends ByteStream> iterators = c.iterator();
private ByteStream cur;
private ByteIterator iter;
@Override
public boolean hasNext() {
while ((iter == null || !iter.hasNext()) && iterators.hasNext()) {
if (cur != null) {
cur.close();
}
cur = iterators.next();
iter = cur == null ? null : cur.iteratorEx();
}
return iter != null && iter.hasNext();
}
@Override
public byte nextByte() {
if ((iter == null || !iter.hasNext()) && !hasNext()) {
throw new NoSuchElementException();
}
return iter.nextByte();
}
}).onClose(newCloseHandler(c));
}
@Beta
public static ByteStream concatIterators(final Collection extends ByteIterator> c) {
if (N.isNullOrEmpty(c)) {
return empty();
}
return new IteratorByteStream(new ByteIteratorEx() {
private final Iterator extends ByteIterator> iter = c.iterator();
private ByteIterator cur;
@Override
public boolean hasNext() {
while ((cur == null || !cur.hasNext()) && iter.hasNext()) {
cur = iter.next();
}
return cur != null && cur.hasNext();
}
@Override
public byte nextByte() {
if ((cur == null || !cur.hasNext()) && !hasNext()) {
throw new NoSuchElementException();
}
return cur.nextByte();
}
});
}
/**
* Zip together the "a" and "b" arrays until one of them runs out of values.
* Each pair of values is combined into a single value using the supplied zipFunction function.
*
* @param a
* @param b
* @return
*/
public static ByteStream zip(final byte[] a, final byte[] b, final ByteBinaryOperator zipFunction) {
if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b)) {
return empty();
}
return new IteratorByteStream(new ByteIteratorEx() {
private final int len = N.min(N.len(a), N.len(b));
private int cursor = 0;
@Override
public boolean hasNext() {
return cursor < len;
}
@Override
public byte nextByte() {
if (cursor >= len) {
throw new NoSuchElementException();
}
return zipFunction.applyAsByte(a[cursor], b[cursor++]);
}
});
}
/**
* Zip together the "a", "b" and "c" arrays until one of them runs out of values.
* Each triple of values is combined into a single value using the supplied zipFunction function.
*
* @param a
* @param b
* @param c
* @return
*/
public static ByteStream zip(final byte[] a, final byte[] b, final byte[] c, final ByteTernaryOperator zipFunction) {
if (N.isNullOrEmpty(a) || N.isNullOrEmpty(b) || N.isNullOrEmpty(c)) {
return empty();
}
return new IteratorByteStream(new ByteIteratorEx() {
private final int len = N.min(N.len(a), N.len(b), N.len(c));
private int cursor = 0;
@Override
public boolean hasNext() {
return cursor < len;
}
@Override
public byte nextByte() {
if (cursor >= len) {
throw new NoSuchElementException();
}
return zipFunction.applyAsByte(a[cursor], b[cursor], c[cursor++]);
}
});
}
/**
* Zip together the "a" and "b" iterators until one of them runs out of values.
* Each pair of values is combined into a single value using the supplied zipFunction function.
*
* @param a
* @param b
* @return
*/
public static ByteStream zip(final ByteIterator a, final ByteIterator b, final ByteBinaryOperator zipFunction) {
return new IteratorByteStream(new ByteIteratorEx() {
private final ByteIterator iterA = a == null ? ByteIterator.empty() : a;
private final ByteIterator iterB = b == null ? ByteIterator.empty() : b;
@Override
public boolean hasNext() {
return iterA.hasNext() && iterB.hasNext();
}
@Override
public byte nextByte() {
return zipFunction.applyAsByte(iterA.nextByte(), iterB.nextByte());
}
});
}
/**
* Zip together the "a", "b" and "c" iterators until one of them runs out of values.
* Each triple of values is combined into a single value using the supplied zipFunction function.
*
* @param a
* @param b
* @return
*/
public static ByteStream zip(final ByteIterator a, final ByteIterator b, final ByteIterator c, final ByteTernaryOperator zipFunction) {
return new IteratorByteStream(new ByteIteratorEx() {
private final ByteIterator iterA = a == null ? ByteIterator.empty() : a;
private final ByteIterator iterB = b == null ? ByteIterator.empty() : b;
private final ByteIterator iterC = c == null ? ByteIterator.empty() : c;
@Override
public boolean hasNext() {
return iterA.hasNext() && iterB.hasNext() && iterC.hasNext();
}
@Override
public byte nextByte() {
return zipFunction.applyAsByte(iterA.nextByte(), iterB.nextByte(), iterC.nextByte());
}
});
}
/**
* Zip together the "a" and "b" streams until one of them runs out of values.
* Each pair of values is combined into a single value using the supplied zipFunction function.
*
* @param a
* @param b
* @return
*/
public static ByteStream zip(final ByteStream a, final ByteStream b, final ByteBinaryOperator zipFunction) {
return zip(iterate(a), iterate(b), zipFunction).onClose(newCloseHandler(a, b));
}
/**
* Zip together the "a", "b" and "c" streams until one of them runs out of values.
* Each triple of values is combined into a single value using the supplied zipFunction function.
*
* @param a
* @param b
* @return
*/
public static ByteStream zip(final ByteStream a, final ByteStream b, final ByteStream c, final ByteTernaryOperator zipFunction) {
return zip(iterate(a), iterate(b), iterate(c), zipFunction).onClose(newCloseHandler(Array.asList(a, b, c)));
}
/**
* Zip together the iterators until one of them runs out of values.
* Each array of values is combined into a single value using the supplied zipFunction function.
*
* @param c
* @param zipFunction
* @return
*/
public static ByteStream zip(final Collection extends ByteStream> c, final ByteNFunction zipFunction) {
return Stream.zip(c, zipFunction).mapToByte(ToByteFunction.UNBOX);
}
/**
* Zip together the "a" and "b" iterators until all of them runs out of values.
* Each pair of values is combined into a single value using the supplied zipFunction function.
*
* @param a
* @param b
* @param valueForNoneA value to fill if "a" runs out of values first.
* @param valueForNoneB value to fill if "b" runs out of values first.
* @param zipFunction
* @return
*/
public static ByteStream zip(final byte[] a, final byte[] b, final byte valueForNoneA, final byte valueForNoneB, final ByteBinaryOperator zipFunction) {
if (N.isNullOrEmpty(a) && N.isNullOrEmpty(b)) {
return empty();
}
return new IteratorByteStream(new ByteIteratorEx() {
private final int aLen = N.len(a), bLen = N.len(b), len = N.max(aLen, bLen);
private int cursor = 0;
private byte ret = 0;
@Override
public boolean hasNext() {
return cursor < len;
}
@Override
public byte nextByte() {
if (cursor >= len) {
throw new NoSuchElementException();
}
ret = zipFunction.applyAsByte(cursor < aLen ? a[cursor] : valueForNoneA, cursor < bLen ? b[cursor] : valueForNoneB);
cursor++;
return ret;
}
});
}
/**
* Zip together the "a", "b" and "c" iterators until all of them runs out of values.
* Each triple of values is combined into a single value using the supplied zipFunction function.
*
* @param a
* @param b
* @param c
* @param valueForNoneA value to fill if "a" runs out of values.
* @param valueForNoneB value to fill if "b" runs out of values.
* @param valueForNoneC value to fill if "c" runs out of values.
* @param zipFunction
* @return
*/
public static ByteStream zip(final byte[] a, final byte[] b, final byte[] c, final byte valueForNoneA, final byte valueForNoneB, final byte valueForNoneC,
final ByteTernaryOperator zipFunction) {
if (N.isNullOrEmpty(a) && N.isNullOrEmpty(b) && N.isNullOrEmpty(c)) {
return empty();
}
return new IteratorByteStream(new ByteIteratorEx() {
private final int aLen = N.len(a), bLen = N.len(b), cLen = N.len(c), len = N.max(aLen, bLen, cLen);
private int cursor = 0;
private byte ret = 0;
@Override
public boolean hasNext() {
return cursor < len;
}
@Override
public byte nextByte() {
if (cursor >= len) {
throw new NoSuchElementException();
}
ret = zipFunction.applyAsByte(cursor < aLen ? a[cursor] : valueForNoneA, cursor < bLen ? b[cursor] : valueForNoneB,
cursor < cLen ? c[cursor] : valueForNoneC);
cursor++;
return ret;
}
});
}
/**
* Zip together the "a" and "b" iterators until all of them runs out of values.
* Each pair of values is combined into a single value using the supplied zipFunction function.
*
* @param a
* @param b
* @param valueForNoneA value to fill if "a" runs out of values first.
* @param valueForNoneB value to fill if "b" runs out of values first.
* @param zipFunction
* @return
*/
public static ByteStream zip(final ByteIterator a, final ByteIterator b, final byte valueForNoneA, final byte valueForNoneB,
final ByteBinaryOperator zipFunction) {
return new IteratorByteStream(new ByteIteratorEx() {
private final ByteIterator iterA = a == null ? ByteIterator.empty() : a;
private final ByteIterator iterB = b == null ? ByteIterator.empty() : b;
@Override
public boolean hasNext() {
return iterA.hasNext() || iterB.hasNext();
}
@Override
public byte nextByte() {
if (iterA.hasNext()) {
return zipFunction.applyAsByte(iterA.nextByte(), iterB.hasNext() ? iterB.nextByte() : valueForNoneB);
} else {
return zipFunction.applyAsByte(valueForNoneA, iterB.nextByte());
}
}
});
}
/**
* Zip together the "a", "b" and "c" iterators until all of them runs out of values.
* Each triple of values is combined into a single value using the supplied zipFunction function.
*
* @param a
* @param b
* @param c
* @param valueForNoneA value to fill if "a" runs out of values.
* @param valueForNoneB value to fill if "b" runs out of values.
* @param valueForNoneC value to fill if "c" runs out of values.
* @param zipFunction
* @return
*/
public static ByteStream zip(final ByteIterator a, final ByteIterator b, final ByteIterator c, final byte valueForNoneA, final byte valueForNoneB,
final byte valueForNoneC, final ByteTernaryOperator zipFunction) {
return new IteratorByteStream(new ByteIteratorEx() {
private final ByteIterator iterA = a == null ? ByteIterator.empty() : a;
private final ByteIterator iterB = b == null ? ByteIterator.empty() : b;
private final ByteIterator iterC = c == null ? ByteIterator.empty() : c;
@Override
public boolean hasNext() {
return iterA.hasNext() || iterB.hasNext() || iterC.hasNext();
}
@Override
public byte nextByte() {
if (iterA.hasNext()) {
return zipFunction.applyAsByte(iterA.nextByte(), iterB.hasNext() ? iterB.nextByte() : valueForNoneB,
iterC.hasNext() ? iterC.nextByte() : valueForNoneC);
} else if (iterB.hasNext()) {
return zipFunction.applyAsByte(valueForNoneA, iterB.nextByte(), iterC.hasNext() ? iterC.nextByte() : valueForNoneC);
} else {
return zipFunction.applyAsByte(valueForNoneA, valueForNoneB, iterC.nextByte());
}
}
});
}
/**
* Zip together the "a" and "b" iterators until all of them runs out of values.
* Each pair of values is combined into a single value using the supplied zipFunction function.
*
* @param a
* @param b
* @param valueForNoneA value to fill if "a" runs out of values first.
* @param valueForNoneB value to fill if "b" runs out of values first.
* @param zipFunction
* @return
*/
public static ByteStream zip(final ByteStream a, final ByteStream b, final byte valueForNoneA, final byte valueForNoneB,
final ByteBinaryOperator zipFunction) {
return zip(iterate(a), iterate(b), valueForNoneA, valueForNoneB, zipFunction).onClose(newCloseHandler(a, b));
}
/**
* Zip together the "a", "b" and "c" iterators until all of them runs out of values.
* Each triple of values is combined into a single value using the supplied zipFunction function.
*
* @param a
* @param b
* @param c
* @param valueForNoneA value to fill if "a" runs out of values.
* @param valueForNoneB value to fill if "b" runs out of values.
* @param valueForNoneC value to fill if "c" runs out of values.
* @param zipFunction
* @return
*/
public static ByteStream zip(final ByteStream a, final ByteStream b, final ByteStream c, final byte valueForNoneA, final byte valueForNoneB,
final byte valueForNoneC, final ByteTernaryOperator zipFunction) {
return zip(iterate(a), iterate(b), iterate(c), valueForNoneA, valueForNoneB, valueForNoneC, zipFunction)
.onClose(newCloseHandler(Array.asList(a, b, c)));
}
/**
* Zip together the iterators until all of them runs out of values.
* Each array of values is combined into a single value using the supplied zipFunction function.
*
* @param c
* @param valuesForNone value to fill for any iterator runs out of values.
* @param zipFunction
* @return
*/
public static ByteStream zip(final Collection extends ByteStream> c, final byte[] valuesForNone, final ByteNFunction zipFunction) {
return Stream.zip(c, valuesForNone, zipFunction).mapToByte(ToByteFunction.UNBOX);
}
/**
*
* @param a
* @param b
* @param nextSelector first parameter is selected if Nth.FIRST
is returned, otherwise the second parameter is selected.
* @return
*/
public static ByteStream merge(final byte[] a, final byte[] b, final ByteBiFunction nextSelector) {
if (N.isNullOrEmpty(a)) {
return of(b);
} else if (N.isNullOrEmpty(b)) {
return of(a);
}
return new IteratorByteStream(new ByteIteratorEx() {
private final int lenA = a.length;
private final int lenB = b.length;
private int cursorA = 0;
private int cursorB = 0;
@Override
public boolean hasNext() {
return cursorA < lenA || cursorB < lenB;
}
@Override
public byte nextByte() {
if (cursorA < lenA) {
if (cursorB < lenB) {
if (nextSelector.apply(a[cursorA], b[cursorB]) == MergeResult.TAKE_FIRST) {
return a[cursorA++];
} else {
return b[cursorB++];
}
} else {
return a[cursorA++];
}
} else if (cursorB < lenB) {
return b[cursorB++];
} else {
throw new NoSuchElementException();
}
}
});
}
/**
*
* @param a
* @param b
* @param c
* @param nextSelector first parameter is selected if Nth.FIRST
is returned, otherwise the second parameter is selected.
* @return
*/
public static ByteStream merge(final byte[] a, final byte[] b, final byte[] c, final ByteBiFunction nextSelector) {
return merge(merge(a, b, nextSelector).iteratorEx(), ByteStream.of(c).iteratorEx(), nextSelector);
}
/**
*
* @param a
* @param b
* @param nextSelector first parameter is selected if Nth.FIRST
is returned, otherwise the second parameter is selected.
* @return
*/
public static ByteStream merge(final ByteIterator a, final ByteIterator b, final ByteBiFunction nextSelector) {
return new IteratorByteStream(new ByteIteratorEx() {
private final ByteIterator iterA = a == null ? ByteIterator.empty() : a;
private final ByteIterator iterB = b == null ? ByteIterator.empty() : b;
private byte nextA = 0;
private byte nextB = 0;
private boolean hasNextA = false;
private boolean hasNextB = false;
@Override
public boolean hasNext() {
return iterA.hasNext() || iterB.hasNext() || hasNextA || hasNextB;
}
@Override
public byte nextByte() {
if (hasNextA) {
if (iterB.hasNext()) {
if (nextSelector.apply(nextA, (nextB = iterB.nextByte())) == MergeResult.TAKE_FIRST) {
hasNextA = false;
hasNextB = true;
return nextA;
} else {
return nextB;
}
} else {
hasNextA = false;
return nextA;
}
} else if (hasNextB) {
if (iterA.hasNext()) {
if (nextSelector.apply((nextA = iterA.nextByte()), nextB) == MergeResult.TAKE_FIRST) {
return nextA;
} else {
hasNextA = true;
hasNextB = false;
return nextB;
}
} else {
hasNextB = false;
return nextB;
}
} else if (iterA.hasNext()) {
if (iterB.hasNext()) {
if (nextSelector.apply((nextA = iterA.nextByte()), (nextB = iterB.nextByte())) == MergeResult.TAKE_FIRST) {
hasNextB = true;
return nextA;
} else {
hasNextA = true;
return nextB;
}
} else {
return iterA.nextByte();
}
} else if (iterB.hasNext()) {
return iterB.nextByte();
} else {
throw new NoSuchElementException();
}
}
});
}
/**
*
* @param a
* @param b
* @param c
* @param nextSelector first parameter is selected if Nth.FIRST
is returned, otherwise the second parameter is selected.
* @return
*/
public static ByteStream merge(final ByteIterator a, final ByteIterator b, final ByteIterator c, final ByteBiFunction nextSelector) {
return merge(merge(a, b, nextSelector).iteratorEx(), c, nextSelector);
}
/**
*
* @param a
* @param b
* @param nextSelector first parameter is selected if Nth.FIRST
is returned, otherwise the second parameter is selected.
* @return
*/
public static ByteStream merge(final ByteStream a, final ByteStream b, final ByteBiFunction nextSelector) {
return merge(iterate(a), iterate(b), nextSelector).onClose(newCloseHandler(a, b));
}
/**
*
* @param a
* @param b
* @param c
* @param nextSelector first parameter is selected if Nth.FIRST
is returned, otherwise the second parameter is selected.
* @return
*/
public static ByteStream merge(final ByteStream a, final ByteStream b, final ByteStream c, final ByteBiFunction nextSelector) {
return merge(merge(a, b, nextSelector), c, nextSelector);
}
/**
*
* @param c
* @param nextSelector first parameter is selected if Nth.FIRST
is returned, otherwise the second parameter is selected.
* @return
*/
public static ByteStream merge(final Collection extends ByteStream> c, final ByteBiFunction nextSelector) {
if (N.isNullOrEmpty(c)) {
return empty();
} else if (c.size() == 1) {
return c.iterator().next();
} else if (c.size() == 2) {
final Iterator extends ByteStream> iter = c.iterator();
return merge(iter.next(), iter.next(), nextSelector);
}
final Iterator extends ByteStream> iter = c.iterator();
ByteStream result = merge(iter.next(), iter.next(), nextSelector);
while (iter.hasNext()) {
result = merge(result, iter.next(), nextSelector);
}
return result;
}
/**
* All the elements from each input {@code Collection/Iterator/Stream} will be merged into two queues by multiple threads.
* Then these two new queues will be merged into one {@code Iterator/Stream} by one thread.
* So it's not totally lazy evaluation and may cause out of memory error if there are too many elements merged into the new queues.
* Consider using {@code merge}, which is totally lazy evaluation.
*
*
* @param c
* @param nextSelector first parameter is selected if Nth.FIRST
is returned, otherwise the second parameter is selected.
* @return
*/
public static ByteStream parallelMerge(final Collection extends ByteStream> c, final ByteBiFunction nextSelector) {
return parallelMerge(c, nextSelector, DEFAULT_MAX_THREAD_NUM);
}
/**
* All the elements from each input {@code Collection/Iterator/Stream} will be merged into two queues by multiple threads.
* Then these two new queues will be merged into one {@code Iterator/Stream} by one thread.
* So it's not totally lazy evaluation and may cause out of memory error if there are too many elements merged into the new queues.
* Consider using {@code merge}, which is totally lazy evaluation.
*
*
* @param c
* @param nextSelector first parameter is selected if Nth.FIRST
is returned, otherwise the second parameter is selected.
* @param maxThreadNum
* @return
*/
public static ByteStream parallelMerge(final Collection extends ByteStream> c, final ByteBiFunction nextSelector, final int maxThreadNum) {
N.checkArgument(maxThreadNum > 0, "'maxThreadNum' must not less than 1");
if (maxThreadNum <= 1) {
return merge(c, nextSelector);
} else if (N.isNullOrEmpty(c)) {
return empty();
} else if (c.size() == 1) {
return c.iterator().next();
} else if (c.size() == 2) {
final Iterator extends ByteStream> iter = c.iterator();
return merge(iter.next(), iter.next(), nextSelector);
} else if (c.size() == 3) {
final Iterator extends ByteStream> iter = c.iterator();
return merge(iter.next(), iter.next(), iter.next(), nextSelector);
}
final Supplier supplier = () -> {
final Queue queue = N.newLinkedList();
queue.addAll(c);
final Holder eHolder = new Holder<>();
final MutableInt cnt = MutableInt.of(c.size());
final List> futureList = new ArrayList<>(c.size() - 1);
final int threadNum = N.min(maxThreadNum, c.size() / 2 + 1);
AsyncExecutor asyncExecutorToUse = checkAsyncExecutor(DEFAULT_ASYNC_EXECUTOR, threadNum, 0);
for (int i = 0; i < threadNum; i++) {
asyncExecutorToUse = execute(asyncExecutorToUse, threadNum, 0, i, futureList, () -> {
ByteStream a = null;
ByteStream b = null;
ByteStream c1 = null;
try {
while (eHolder.value() == null) {
synchronized (queue) {
if (cnt.intValue() > 2 && queue.size() > 1) {
a = queue.poll();
b = queue.poll();
cnt.decrement();
} else {
break;
}
}
c1 = ByteStream.of(merge(a, b, nextSelector).toArray());
synchronized (queue) {
queue.offer(c1);
}
}
} catch (Throwable e) {
setError(eHolder, e);
}
});
}
completeAndShutdownTempExecutor(futureList, eHolder, c, asyncExecutorToUse);
return merge(queue.poll(), queue.poll(), nextSelector);
};
return Stream.just(supplier).flatMapToByte(Supplier::get);
}
public static abstract class ByteStreamEx extends ByteStream {
private ByteStreamEx(boolean sorted, Collection closeHandlers) {
super(sorted, closeHandlers);
}
}
}