com.landawn.abacus.util.stream.StreamBase Maven / Gradle / Ivy
/*
* 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.Serial;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.security.SecureRandom;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Deque;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Spliterator;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
import com.landawn.abacus.annotation.Internal;
import com.landawn.abacus.annotation.LazyEvaluation;
import com.landawn.abacus.annotation.SuppressFBWarnings;
import com.landawn.abacus.logging.Logger;
import com.landawn.abacus.logging.LoggerFactory;
import com.landawn.abacus.util.AsyncExecutor;
import com.landawn.abacus.util.BiMap;
import com.landawn.abacus.util.BooleanList;
import com.landawn.abacus.util.ByteIterator;
import com.landawn.abacus.util.ByteList;
import com.landawn.abacus.util.CharIterator;
import com.landawn.abacus.util.CharList;
import com.landawn.abacus.util.ClassUtil;
import com.landawn.abacus.util.Comparators;
import com.landawn.abacus.util.ContinuableFuture;
import com.landawn.abacus.util.DoubleIterator;
import com.landawn.abacus.util.DoubleList;
import com.landawn.abacus.util.ExceptionUtil;
import com.landawn.abacus.util.FloatIterator;
import com.landawn.abacus.util.FloatList;
import com.landawn.abacus.util.Fn;
import com.landawn.abacus.util.Fn.Suppliers;
import com.landawn.abacus.util.Holder;
import com.landawn.abacus.util.IOUtil;
import com.landawn.abacus.util.ImmutableList;
import com.landawn.abacus.util.ImmutableSet;
import com.landawn.abacus.util.Indexed;
import com.landawn.abacus.util.IndexedByte;
import com.landawn.abacus.util.IndexedChar;
import com.landawn.abacus.util.IndexedDouble;
import com.landawn.abacus.util.IndexedFloat;
import com.landawn.abacus.util.IndexedInt;
import com.landawn.abacus.util.IndexedLong;
import com.landawn.abacus.util.IndexedShort;
import com.landawn.abacus.util.IntIterator;
import com.landawn.abacus.util.IntList;
import com.landawn.abacus.util.InternalUtil;
import com.landawn.abacus.util.LongIterator;
import com.landawn.abacus.util.LongList;
import com.landawn.abacus.util.Multimap;
import com.landawn.abacus.util.Multiset;
import com.landawn.abacus.util.MutableBoolean;
import com.landawn.abacus.util.MutableInt;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.Numbers;
import com.landawn.abacus.util.ShortIterator;
import com.landawn.abacus.util.ShortList;
import com.landawn.abacus.util.Strings;
import com.landawn.abacus.util.Throwables;
import com.landawn.abacus.util.Tuple;
import com.landawn.abacus.util.Tuple.Tuple3;
import com.landawn.abacus.util.Wrapper;
import com.landawn.abacus.util.cs;
@SuppressWarnings({ "java:S6539" })
@LazyEvaluation
abstract class StreamBase, S extends BaseStream>
implements BaseStream {
static final Logger logger = LoggerFactory.getLogger(StreamBase.class);
static final Object NONE = ClassUtil.createNullMask();
static final Random RAND = new SecureRandom();
static final int DEFAULT_CHARACTERISTICS_OBJ_JDK_STREAM = Spliterator.ORDERED | Spliterator.IMMUTABLE;
static final int DEFAULT_CHARACTERISTICS_PRIMITIVE_JDK_STREAM = Spliterator.ORDERED | Spliterator.IMMUTABLE | Spliterator.NONNULL;
static final String ERROR_MSG_FOR_NO_SUCH_EX = InternalUtil.ERROR_MSG_FOR_NO_SUCH_EX;
/**
*
* Char array with value {@code "['n', 'u', 'l', 'l']"}.
*/
static final char[] NULL_CHAR_ARRAY = Strings.NULL_STRING.toCharArray();
static final char[] ELEMENT_SEPARATOR_CHAR_ARRAY = Strings.ELEMENT_SEPARATOR.toCharArray();
static final int MAX_WAIT_TIME_FOR_QUEUE_OFFER = 9; // unit is milliseconds
static final int MAX_WAIT_TIME_FOR_QUEUE_POLL = 7; // unit is milliseconds
static final int MAX_WAIT_TIME_FOR_QUEUE_OFFER_FOR_ADD_SUBSCRIBER = 30_000; // unit is milliseconds
static final int MAX_BUFFERED_SIZE = 10240;
static final int DEFAULT_BUFFERED_SIZE_PER_ITERATOR = 64;
@SuppressWarnings("rawtypes")
static final Comparator NULL_MIN_COMPARATOR = Comparators.nullsFirst();
@SuppressWarnings("rawtypes")
static final Comparator NULL_MAX_COMPARATOR = Comparators.nullsLast();
@SuppressWarnings("rawtypes")
static final Comparator NATURAL_COMPARATOR = Comparators.naturalOrder();
@SuppressWarnings("rawtypes")
static final Comparator REVERSED_COMPARATOR = Comparators.reverseOrder();
static final Comparator CHAR_COMPARATOR = Character::compare;
static final Comparator BYTE_COMPARATOR = Byte::compare;
static final Comparator SHORT_COMPARATOR = Short::compare;
static final Comparator INT_COMPARATOR = Integer::compare;
static final Comparator LONG_COMPARATOR = Long::compare;
static final Comparator FLOAT_COMPARATOR = Float::compare;
static final Comparator DOUBLE_COMPARATOR = Double::compare;
static final Comparator INDEXED_BYTE_COMPARATOR = (a, b) -> N.compare(a.longIndex(), b.longIndex());
static final Comparator INDEXED_CHAR_COMPARATOR = (a, b) -> N.compare(a.longIndex(), b.longIndex());
static final Comparator INDEXED_SHORT_COMPARATOR = (a, b) -> N.compare(a.longIndex(), b.longIndex());
static final Comparator INDEXED_INT_COMPARATOR = (a, b) -> N.compare(a.longIndex(), b.longIndex());
static final Comparator INDEXED_LONG_COMPARATOR = (a, b) -> N.compare(a.longIndex(), b.longIndex());
static final Comparator INDEXED_FLOAT_COMPARATOR = (a, b) -> N.compare(a.longIndex(), b.longIndex());
static final Comparator INDEXED_DOUBLE_COMPARATOR = (a, b) -> N.compare(a.longIndex(), b.longIndex());
static final Comparator> INDEXED_COMPARATOR = (a, b) -> N.compare(a.longIndex(), b.longIndex());
static final BiMap, Comparator>> DEFAULT_COMPARATOR_MAP = new BiMap<>();
static {
DEFAULT_COMPARATOR_MAP.put(char.class, CHAR_COMPARATOR);
DEFAULT_COMPARATOR_MAP.put(byte.class, BYTE_COMPARATOR);
DEFAULT_COMPARATOR_MAP.put(short.class, SHORT_COMPARATOR);
DEFAULT_COMPARATOR_MAP.put(int.class, INT_COMPARATOR);
DEFAULT_COMPARATOR_MAP.put(long.class, LONG_COMPARATOR);
DEFAULT_COMPARATOR_MAP.put(float.class, FLOAT_COMPARATOR);
DEFAULT_COMPARATOR_MAP.put(double.class, DOUBLE_COMPARATOR);
DEFAULT_COMPARATOR_MAP.put(Object.class, NATURAL_COMPARATOR);
}
static final Map, Integer> CLS_SEQ_MAP = new BiMap<>();
static {
int idx = 0;
CLS_SEQ_MAP.put(boolean[].class, idx++); // 0
CLS_SEQ_MAP.put(char[].class, idx++);
CLS_SEQ_MAP.put(byte[].class, idx++);
CLS_SEQ_MAP.put(short[].class, idx++);
CLS_SEQ_MAP.put(int[].class, idx++);
CLS_SEQ_MAP.put(long[].class, idx++);
CLS_SEQ_MAP.put(float[].class, idx++);
CLS_SEQ_MAP.put(double[].class, idx++); // 7
CLS_SEQ_MAP.put(BooleanList.class, idx++); // 8
CLS_SEQ_MAP.put(CharList.class, idx++);
CLS_SEQ_MAP.put(ByteList.class, idx++);
CLS_SEQ_MAP.put(ShortList.class, idx++);
CLS_SEQ_MAP.put(IntList.class, idx++);
CLS_SEQ_MAP.put(LongList.class, idx++);
CLS_SEQ_MAP.put(FloatList.class, idx++);
CLS_SEQ_MAP.put(DoubleList.class, idx++); // 15
}
static final LocalRunnable EMPTY_CLOSE_HANDLER = () -> {
// do nothing.
};
static final int CORE_THREAD_POOL_SIZE = IOUtil.IS_PLATFORM_ANDROID //
? Math.max(64, IOUtil.CPU_CORES * 8) //
: Math.max(256, IOUtil.CPU_CORES * 16);
static final int MAX_THREAD_NUM_PER_OPERATION = IOUtil.IS_PLATFORM_ANDROID //
? Math.min(16, IOUtil.CPU_CORES) //
: Math.min(64, IOUtil.CPU_CORES * 8);
static final int DEFAULT_MAX_THREAD_NUM = Math.min(MAX_THREAD_NUM_PER_OPERATION, IOUtil.CPU_CORES);
static final int DEFAULT_READING_THREAD_NUM = Math.min(MAX_THREAD_NUM_PER_OPERATION, IOUtil.CPU_CORES);
static final int RESERVED_POOL_SIZE = CORE_THREAD_POOL_SIZE / 16; // To reduce chance of deadlock.
// static final long MAX_WAIT_TO_BREAK_FOR_DEAD_LOCK = 6 * 60 * 1000; // 6 minutes
static final Splitor DEFAULT_SPLITOR = Splitor.ITERATOR;
static final int MAX_POOLED_EXECUTOR_SIZE_FOR_VIRTUAL_THREAD = IOUtil.CPU_CORES;
static final IdentityHashMap EXECUTOR_MAP_FOR_VIRTUAL_THREAD = new IdentityHashMap<>(
MAX_POOLED_EXECUTOR_SIZE_FOR_VIRTUAL_THREAD * 2 + 1); // TODO try to avoid resize. Will it work?
static final ArrayBlockingQueue EXECUTOR_QUEUE_FOR_VIRTUAL_THREAD = new ArrayBlockingQueue<>(MAX_POOLED_EXECUTOR_SIZE_FOR_VIRTUAL_THREAD);
static final boolean isVirtualThreadSupported;
static {
boolean tmp = false;
try {
@SuppressWarnings("resource")
final ExecutorService executor = newVirtualThreadPerTaskExecutor();
executor.shutdown();
// for (int i = 0; i < MAX_POOLED_EXECUTOR_SIZE_FOR_VIRTUAL_THREAD; i++) {
// ExecutorService virtualThreadPerTaskExecutor = newVirtualThreadPerTaskExecutor();
// EXECUTOR_MAP_FOR_VIRTUAL_THREAD.put(virtualThreadPerTaskExecutor, true);
// }
//
// EXECUTOR_QUEUE_FOR_VIRTUAL_THREAD.addAll(EXECUTOR_MAP_FOR_VIRTUAL_THREAD.keySet());
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
logger.warn("Starting to shutdown task executors for virtual threads for Stream");
for (final ExecutorService virtualThreadPerTaskExecutor : EXECUTOR_MAP_FOR_VIRTUAL_THREAD.keySet()) {
try {
virtualThreadPerTaskExecutor.shutdown();
//noinspection ResultOfMethodCallIgnored
virtualThreadPerTaskExecutor.awaitTermination(120, TimeUnit.SECONDS);
} catch (final InterruptedException e) {
logger.warn("Not all the executors for virtual threads for Stream are completed successfully before shutdown.");
} finally {
logger.warn("Completed to shutdown task executors for virtual threads for Stream");
}
}
}));
tmp = true;
} catch (final Throwable e) { // NOSONAR
// ignore
}
//noinspection ConstantValue
isVirtualThreadSupported = tmp;
}
private static final AtomicInteger ACTIVE_THREAD_NUM = new AtomicInteger();
static final AsyncExecutor DEFAULT_ASYNC_EXECUTOR;
static {
// TODO dead lock if the total thread number started by this stream and its upstream is bigger than CORE_THREAD_POOL_SIZE(or CORE_THREAD_POOL_SIZE_FOR_ANDROID for Android).
// If the total thread number started by this stream and its down stream is big, please specified its owner {@code Executor} by {@code parallel(..., Executor)}.
// UPDATE: this deadlock problem has been resolved by using BaseStream.execute(...)
// core pool size and maximum pool size must be same, otherwise hung.
// final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(//
// N.max(64, IOUtil.CPU_CORES * 8), // coreThreadPoolSize
// MAX_THREAD_POOL_SIZE, // maxThreadPoolSize
// 180L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
// final ThreadPoolExecutor threadPoolExecutor = Executors.newFixedThreadPool(CORE_THREAD_POOL_SIZE);
final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(//
CORE_THREAD_POOL_SIZE, // coreThreadPoolSize
CORE_THREAD_POOL_SIZE, // maxThreadPoolSize
180L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
threadPoolExecutor.setRejectedExecutionHandler((r, executor) -> {
// // This should not be called.
// if (activeThreadNum.get() > 0) {
// activeThreadNum.decrementAndGet();
// }
// Since it should not happen. throw exception.
throw new RuntimeException("No task should be rejected by thread pool. This is an unexpected behavior");
});
threadPoolExecutor.allowCoreThreadTimeOut(true);
DEFAULT_ASYNC_EXECUTOR = new AsyncExecutor(threadPoolExecutor) {
@Override
public ContinuableFuture execute(final Throwables.Runnable extends Exception> command) {
// if (threadPoolExecutor.getActiveCount() >= MAX_THREAD_POOL_SIZE) {
// throw new RejectedExecutionException("Task is rejected due to exceed max thread pool size: " + MAX_THREAD_POOL_SIZE);
// }
// if (logger.isDebugEnabled()) {
// logger.debug("######: ActiveTaskCount-Executor: {}", activeThreadNum.get());
// }
ACTIVE_THREAD_NUM.incrementAndGet();
return super.execute(new FutureTask<>(() -> {
try {
command.run();
return null;
} finally {
ACTIVE_THREAD_NUM.decrementAndGet();
// if (logger.isDebugEnabled()) {
// logger.debug("======: ActiveTaskCount-Pool: {}", threadPoolExecutor.getActiveCount());
// }
}
}) {
@Override
public boolean cancel(final boolean mayInterruptIfRunning) {
// // This should not be called.
// if (isCancelled()) {
// return true;
// }
//
// final boolean ret = super.cancel(mayInterruptIfRunning);
//
// if (ret && activeThreadNum.get() > 0) {
// activeThreadNum.decrementAndGet();
// }
//
// return ret;
// Since it should not happen. throw exception.
throw new RuntimeException("No task should be cancelled if there is no call Future.cancel. This is an unexpected behavior");
}
});
}
@Override
public ContinuableFuture execute(final Callable command) {
// if (threadPoolExecutor.getActiveCount() >= MAX_THREAD_POOL_SIZE) {
// throw new RejectedExecutionException("Task is rejected due to exceed max thread pool size: " + MAX_THREAD_POOL_SIZE);
// }
// if (logger.isDebugEnabled()) {
// logger.debug("######: ActiveTaskCount-Executor: {}", activeThreadNum.get());
// }
ACTIVE_THREAD_NUM.incrementAndGet();
return super.execute(new FutureTask<>(() -> {
try {
return command.call();
} finally {
ACTIVE_THREAD_NUM.decrementAndGet();
// if (logger.isDebugEnabled()) {
// logger.debug("======: ActiveTaskCount-Pool: {}", threadPoolExecutor.getActiveCount());
// }
}
}) {
@Override
public boolean cancel(final boolean mayInterruptIfRunning) {
// // This should not be called.
// if (isCancelled()) {
// return true;
// }
//
// final boolean ret = super.cancel(mayInterruptIfRunning);
//
// if (ret && activeThreadNum.get() > 0) {
// activeThreadNum.decrementAndGet();
// }
//
// return ret;
// Since it should not happen. throw exception.
throw new RuntimeException("No task should be cancelled if there is no call Future.cancel. This is an unexpected behavior");
}
});
}
};
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
logger.warn("Starting to shutdown tasks for Stream");
try {
threadPoolExecutor.shutdown();
//noinspection ResultOfMethodCallIgnored
threadPoolExecutor.awaitTermination(120, TimeUnit.SECONDS);
} catch (final InterruptedException e) {
logger.warn("Not all the requests/tasks for Stream are completed successfully before shutdown.");
} finally {
logger.warn("Completed to shutdown tasks for Stream");
}
}));
}
@SuppressWarnings("rawtypes")
static final BiConsumer collectingCombiner = (t, u) -> {
if (t instanceof Collection) {
((Collection) t).addAll((Collection) u);
} else if (t instanceof Map) {
((Map) t).putAll((Map) u);
} else if (t instanceof StringBuilder) {
((StringBuilder) t).append((StringBuilder) u);
} else //noinspection ConstantValue
if (t instanceof Multiset) {
((Multiset) t).addAll((Multiset) u);
} else if (t instanceof Multimap) {
((Multimap) t).putMany((Multimap) u);
} else {
final Class> cls = t.getClass();
final Integer num = CLS_SEQ_MAP.get(cls);
if (num == null) {
throw new RuntimeException(cls.getCanonicalName()
+ " can't be combined by default. Only Collection/Map/StringBuilder/Multiset/LongMultiset/Multimap/BooleanList/IntList/.../DoubleList are supported");
}
switch (num) {
case 8:
((BooleanList) t).addAll((BooleanList) u);
break;
case 9:
((CharList) t).addAll((CharList) u);
break;
case 10:
((ByteList) t).addAll((ByteList) u);
break;
case 11:
((ShortList) t).addAll((ShortList) u);
break;
case 12:
((IntList) t).addAll((IntList) u);
break;
case 13:
((LongList) t).addAll((LongList) u);
break;
case 14:
((FloatList) t).addAll((FloatList) u);
break;
case 15:
((DoubleList) t).addAll((DoubleList) u);
break;
default:
throw new IllegalArgumentException(cls.getCanonicalName()
+ " can't be combined by default. Only Collection/Map/StringBuilder/Multiset/LongMultiset/Multimap/BooleanList/IntList/.../DoubleList are supported");
}
}
};
static volatile boolean isListElementDataFieldGettable = true;
static final Field listElementDataField;
static {
Field tmp = null;
try {
tmp = ArrayList.class.getDeclaredField("elementData");
} catch (final Throwable e) { // NOSONAR
// ignore.
}
listElementDataField = tmp != null && tmp.getType().equals(Object[].class) ? tmp : null;
if (listElementDataField != null) {
ClassUtil.setAccessibleQuietly(listElementDataField, true);
}
tmp = null;
try {
tmp = ArrayList.class.getDeclaredField("size");
} catch (final Throwable e) { // NOSONAR
// ignore.
}
}
final boolean sorted;
final Comparator super T> cmp;
final Deque closeHandlers;
boolean isClosed = false;
StreamBase(final boolean sorted, final Comparator super T> cmp, final Collection closeHandlers) {
this.closeHandlers = isEmptyCloseHandlers(closeHandlers) ? null
: (closeHandlers instanceof LocalArrayDeque ? (LocalArrayDeque) closeHandlers : new LocalArrayDeque<>(closeHandlers));
this.sorted = sorted;
this.cmp = cmp;
}
@Override
public S shuffled() {
return shuffled(RAND);
}
@Override
public OT elementAt(final long position) throws IllegalStateException, IllegalArgumentException {
assertNotClosed();
checkArgNotNegative(position, cs.position);
if (position == 0) {
return first();
} else {
//noinspection resource
return skip(position).first();
}
}
@Override
public ImmutableList toImmutableList() {
return ImmutableList.wrap(toList());
}
@Override
public ImmutableSet toImmutableSet() {
return ImmutableSet.wrap(toSet());
}
@Override
public A toArray() {
return toArray(true);
}
protected abstract A toArray(boolean closeStream);
protected A toArrayForIntermediateOp() {
// return toArray(false);
return toArray(true);
}
// Try to avoid unnecessary copy of array if possible
protected Tuple3 arrayForIntermediateOp() {
// final A a = toArray(false);
final A a = toArray(true);
return Tuple.of(a, 0, Array.getLength(a));
}
@Override
public S throwIfEmpty() {
return throwIfEmpty(Suppliers.newNoSuchElementException());
}
@Override
public S throwIfEmpty(final Supplier extends RuntimeException> exceptionSupplier) throws IllegalArgumentException {
checkArgNotNull(exceptionSupplier, cs.exceptionSupplier);
return ifEmpty(() -> {
throw exceptionSupplier.get();
});
}
@Override
public void println() {
//noinspection resource
N.println(sequential().join(", ", "[", "]"));
}
@Override
public boolean isParallel() {
return false;
}
@Override
public S sequential() {
return (S) this;
}
@Override
public S parallel() {
return parallel(DEFAULT_MAX_THREAD_NUM);
}
@Override
public S parallel(final int maxThreadNum) {
return parallel(maxThreadNum, null);
}
@Override
public S parallel(final Executor executor) {
return parallel(DEFAULT_MAX_THREAD_NUM, executor);
}
@Override
public S parallel(final int maxThreadNum, final Executor executor) {
checkArgNotNegative(maxThreadNum, cs.maxThreadNum);
final AsyncExecutor asyncExecutor = executor == null ? DEFAULT_ASYNC_EXECUTOR : createAsyncExecutor(executor);
return parallel(checkMaxThreadNum(maxThreadNum, 0, asyncExecutor), 0, DEFAULT_SPLITOR, asyncExecutor, false);
}
// @Override
// public S parallel(final Splitor splitor) {
// return parallel(DEFAULT_MAX_THREAD_NUM, splitor);
// }
//
// @Override
// public S parallel(final int maxThreadNum, final Splitor splitor) throws IllegalArgumentException {
// checkArgNotNegative(maxThreadNum, "maxThreadNum"); //NOSONAR
//
// // if (maxThreadNum > MAX_THREAD_NUM_PER_OPERATION) {
// // throw new IllegalArgumentException("'maxThreadNum' must be >= 0 and <= " + MAX_THREAD_NUM_PER_OPERATION
// // + " for default Executor. To parallelize Stream with bigger thread number, Please specify Executor.");
// // }
//
// return parallel(checkMaxThreadNum(maxThreadNum, 0, DEFAULT_ASYNC_EXECUTOR), 0, splitor == null ? DEFAULT_SPLITOR : splitor, DEFAULT_ASYNC_EXECUTOR,
// false);
// }
//
// @Override
// public S parallel(final int maxThreadNum, final Splitor splitor, final Executor executor) throws IllegalArgumentException {
// checkArgNotNegative(maxThreadNum, cs.maxThreadNum);
//
// final AsyncExecutor asyncExecutor = executor == null ? DEFAULT_ASYNC_EXECUTOR : createAsyncExecutor(executor);
//
// return parallel(checkMaxThreadNum(maxThreadNum, 0, asyncExecutor), 0, splitor == null ? DEFAULT_SPLITOR : splitor, asyncExecutor, false);
// }
// @Override
// public S parallel(int maxThreadNum, boolean withVirtualThread) {
// return parallel(maxThreadNum, withVirtualThread ? 1 : 0);
// }
//
// @Override
// public S parallel(int maxThreadNum, int executorNumForVirtualThread) {
// checkArgNotNegative(maxThreadNum, "maxThreadNum");
// checkArgNotNegative(executorNumForVirtualThread, "executorNumForVirtualThread");
//
// final int checkedMaxThreadNum = checkMaxThreadNum(maxThreadNum, executorNumForVirtualThread, DEFAULT_ASYNC_EXECUTOR);
// final int checkedVirtualTaskNum = checkExecutorNumForVirtualThread(checkedMaxThreadNum, executorNumForVirtualThread);
//
// return parallel(checkedMaxThreadNum, checkedVirtualTaskNum, DEFAULT_SPLITOR, DEFAULT_ASYNC_EXECUTOR, false);
// }
@SuppressWarnings("deprecation")
@Override
public S parallel(final ParallelSettings ps) throws IllegalArgumentException {
checkArgNotNull(ps, cs.ps);
checkArgNotNegative(ps.maxThreadNum(), "ps.maxThreadNum()");
checkArgNotNegative(ps.executorNumForVirtualThread(), "ps.executorNumForVirtualThread()");
final int maxThreadNum = ps.maxThreadNum() == 0 ? DEFAULT_MAX_THREAD_NUM : ps.maxThreadNum();
final Splitor splitor = ps.splitor() == null ? DEFAULT_SPLITOR : ps.splitor();
final AsyncExecutor asyncExecutor = ps.executor() == null ? DEFAULT_ASYNC_EXECUTOR : createAsyncExecutor(ps.executor());
final int checkedMaxThreadNum = checkMaxThreadNum(maxThreadNum, ps.executorNumForVirtualThread(), asyncExecutor);
final int checkedVirtualTaskNum = checkExecutorNumForVirtualThread(checkedMaxThreadNum, ps.executorNumForVirtualThread());
return parallel(checkedMaxThreadNum, checkedVirtualTaskNum, splitor, asyncExecutor, false);
}
protected abstract S parallel(final int maxThreadNum, int executorNumForVirtualThread, final Splitor splitor, final AsyncExecutor asyncExecutor,
final boolean cancelUncompletedThreads);
// protected abstract S parallel(final int maxThreadNum, final Splitor splitor, final AsyncExecutor asyncExecutor, final boolean cancelUncompletedThreads);
// protected abstract S parallel(final int maxThreadNum, final Splitor splitor, final AsyncExecutor asyncExecutor, final boolean cancelUncompletedThreads);
static int checkMaxThreadNum(final int maxThreadNum, final int executorNumForVirtualThread, final AsyncExecutor asyncExecutor) {
if (maxThreadNum == 0) {
return DEFAULT_MAX_THREAD_NUM;
} else if ((executorNumForVirtualThread == 0 || !isVirtualThreadSupported) && (asyncExecutor == null || asyncExecutor == DEFAULT_ASYNC_EXECUTOR)
&& maxThreadNum > MAX_THREAD_NUM_PER_OPERATION) {
// throw new IllegalArgumentException("'maxThreadNum' must be >= 0 and <= " + MAX_THREAD_NUM_PER_OPERATION
// + " for default Executor. To parallelize Stream with bigger thread number, Please specify Executor.");
// return MAX_THREAD_NUM_PER_OPERATION; // should and why if yes?
}
return maxThreadNum;
}
static int checkExecutorNumForVirtualThread(final int maxThreadNum, final int executorNumForVirtualThread) {
if (!isVirtualThreadSupported) {
return 0; // follow down 0 for java version < 19
}
return N.min(maxThreadNum / 2, executorNumForVirtualThread); // only meaningful when executorNumForVirtualThread <= maxThreadNum / 2
}
@Override
@SuppressWarnings("rawtypes")
public SS sps(final Function super S, ? extends SS> ops) throws IllegalStateException {
assertNotClosed();
if (isParallel()) {
return (SS) ops.apply((S) this).sequential();
} else {
return (SS) ops.apply(this.parallel()).sequential();
}
}
@Override
@SuppressWarnings({ "rawtypes" })
public SS sps(final int maxThreadNum, final Function super S, ? extends SS> ops) throws IllegalStateException {
assertNotClosed();
final int executorNumForVirtualThread = 0;
if (isParallel() && maxThreadNum == maxThreadNum() && executorNumForVirtualThread == executorNumForVirtualThread()) {
return (SS) ops.apply((S) this).sequential();
} else {
final int checkedMaxThreadNum = checkMaxThreadNum(maxThreadNum, executorNumForVirtualThread, asyncExecutor());
final int checkedVirtualTaskNum = checkExecutorNumForVirtualThread(checkedMaxThreadNum, executorNumForVirtualThread);
return (SS) ops.apply(parallel(checkedMaxThreadNum, checkedVirtualTaskNum, splitor(), asyncExecutor(), cancelUncompletedThreads())).sequential();
}
}
@Override
@SuppressWarnings("rawtypes")
public SS sps(final int maxThreadNum, final Executor executor, final Function super S, ? extends SS> ops)
throws IllegalStateException {
assertNotClosed();
final AsyncExecutor asyncExecutor = executor == null ? DEFAULT_ASYNC_EXECUTOR : createAsyncExecutor(executor);
return (SS) ops.apply(parallel(checkMaxThreadNum(maxThreadNum, 0, asyncExecutor), 0, splitor(), asyncExecutor, cancelUncompletedThreads()))
.sequential();
}
// @Override
// @SuppressWarnings("rawtypes")
// public SS sps(int maxThreadNum, boolean withVirtualThread, final Function super S, ? extends SS> ops) {
// return sps(maxThreadNum, withVirtualThread ? 1 : 0, ops);
// }
//
// @Override
// @SuppressWarnings("rawtypes")
// public SS sps(int maxThreadNum, int executorNumForVirtualThread, final Function super S, ? extends SS> ops) {
// assertNotClosed();
//
// if (isParallel() && maxThreadNum == maxThreadNum() && executorNumForVirtualThread == executorNumForVirtualThread()) {
// return (SS) ((StreamBase) ops.apply((S) this)).sequential();
// } else {
// final int checkedMaxThreadNum = checkMaxThreadNum(maxThreadNum, executorNumForVirtualThread, asyncExecutor());
// final int checkedVirtualTaskNum = checkExecutorNumForVirtualThread(checkedMaxThreadNum, executorNumForVirtualThread);
//
// return (SS) ((StreamBase) ops.apply(parallel(checkedMaxThreadNum, checkedVirtualTaskNum, splitor(), asyncExecutor(), cancelUncompletedThreads())))
// .sequential();
// }
// }
// @Override
// @SuppressWarnings("rawtypes")
// public SS sps(final ParallelSettings ps, final Function super S, ? extends SS> ops) {
// assertNotClosed();
//
// return (SS) ((StreamBase) ops.apply(parallel(ps))).sequential();
// }
@Override
@SuppressWarnings("rawtypes")
public SS psp(final Function super S, ? extends SS> ops) throws IllegalStateException {
assertNotClosed();
if (isParallel()) {
return (SS) ((StreamBase) ops.apply(this.sequential())).parallel(maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads());
} else {
return (SS) ops.apply((S) this).parallel();
}
}
protected int maxThreadNum() {
// throw new UnsupportedOperationException();
// ignore, do nothing if it's sequential stream.
return 1; //NOSONAR
}
@SuppressWarnings("SameReturnValue")
protected int executorNumForVirtualThread() {
// throw new UnsupportedOperationException();
// ignore, do nothing if it's sequential stream.
return 0; //NOSONAR
}
protected Splitor splitor() {
// throw new UnsupportedOperationException();
// ignore, do nothing if it's sequential stream.
return DEFAULT_SPLITOR;
}
protected AsyncExecutor asyncExecutor() {
// throw new UnsupportedOperationException();
// ignore, do nothing if it's sequential stream.
return DEFAULT_ASYNC_EXECUTOR;
}
protected static Executor executor() {
return DEFAULT_ASYNC_EXECUTOR.getExecutor();
}
protected boolean cancelUncompletedThreads() {
// throw new UnsupportedOperationException();
// ignore, do nothing if it's sequential stream.
return false;
}
final AsyncExecutor createAsyncExecutor(final Executor executor) {
checkArgNotNull(executor, cs.executor);
return new AsyncExecutor(executor);
}
@Override
@SuppressWarnings("rawtypes")
public RS transform(final Function super S, ? extends RS> transfer) throws IllegalStateException, IllegalArgumentException {
assertNotClosed();
checkArgNotNull(transfer, cs.transfer);
// final Supplier delayInitializer = () -> transfer.apply((S) this);
//
// Stream.defer(delayInitializer)... to RS
return transfer.apply((S) this); // TODO not lazy evaluation?
}
@Override
public synchronized void close() {
if (isClosed) {
return;
}
if (isEmptyCloseHandlers(closeHandlers)) {
if (N.notEmpty(closeHandlers)) {
closeHandlers.clear();
}
isClosed = true;
return;
}
// // Only mark the stream closed if closeHandlers are not empty.
// if (isClosed || isEmptyCloseHandlers(closeHandlers)) {
// return;
// }
isClosed = true;
if (logger.isDebugEnabled()) {
logger.debug("### Closing " + ClassUtil.getSimpleClassName(getClass()));
}
close(closeHandlers);
if (N.notEmpty(closeHandlers)) {
closeHandlers.clear();
}
}
static void close(final Collection extends Runnable> closeHandlers) {
Exception ex = null;
for (final Runnable closeHandler : closeHandlers) {
try {
closeHandler.run();
} catch (final Exception e) {
if (ex == null) {
ex = e;
} else {
ex.addSuppressed(e);
}
}
}
if (ex != null) {
throw toRuntimeException(ex);
}
}
static void closeIterators(final Collection extends IteratorEx>> iters) {
Exception ex = null;
for (final IteratorEx> iter : iters) {
try {
iter.close();
} catch (final Exception e) {
if (ex == null) {
ex = e;
} else {
ex.addSuppressed(e);
}
}
}
if (ex != null) {
throw toRuntimeException(ex);
}
}
@SuppressWarnings("rawtypes")
static void close(final Holder extends BaseStream> holder) {
if (holder.value() != null) {
holder.value().close();
}
}
final void assertNotClosed() {
if (isClosed) {
throw new IllegalStateException("This stream is already terminated.");
}
}
final void checkIndex(final int index, final int length) {
if (index < 0 || index >= length) {
try {
N.checkElementIndex(index, length);
} finally {
close();
}
}
}
final void checkFromToIndex(final int fromIndex, final int toIndex, final int length) {
if (fromIndex < 0 || fromIndex > toIndex || toIndex > length) {
try {
N.checkFromToIndex(fromIndex, toIndex, length);
} finally {
close();
}
}
}
final void checkFromIndexSize(final int fromIndex, final int size, final int length) {
if ((length | fromIndex | size) < 0 || size > length - fromIndex) {
try {
N.checkFromIndexSize(fromIndex, size, length);
} finally {
close();
}
}
}
final void checkArgPositive(final int arg, final String argNameOrErrorMsg) {
if (arg <= 0) {
try {
N.checkArgPositive(arg, argNameOrErrorMsg);
} finally {
close();
}
}
}
final void checkArgPositive(final long arg, final String argNameOrErrorMsg) {
if (arg <= 0) {
try {
N.checkArgPositive(arg, argNameOrErrorMsg);
} finally {
close();
}
}
}
final void checkArgNotNegative(final int arg, final String argNameOrErrorMsg) {
if (arg < 0) {
try {
N.checkArgNotNegative(arg, argNameOrErrorMsg);
} finally {
close();
}
}
}
final void checkArgNotNegative(final long arg, final String argNameOrErrorMsg) {
if (arg < 0) {
try {
N.checkArgNotNegative(arg, argNameOrErrorMsg);
} finally {
close();
}
}
}
@SuppressFBWarnings("NP_LOAD_OF_KNOWN_NULL_VALUE")
final ARG checkArgNotNull(final ARG obj) {
if (obj == null) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkArgNotNull(obj);
} finally {
close();
}
}
return obj;
}
@SuppressFBWarnings("NP_LOAD_OF_KNOWN_NULL_VALUE")
final ARG checkArgNotNull(final ARG obj, final String errorMessage) {
if (obj == null) {
try {
//noinspection ConstantValue
N.checkArgNotNull(obj, errorMessage);
} finally {
close();
}
}
return obj;
}
final void checkArgNotEmpty(final Collection> c, final String errorMessage) {
if (c == null || c.size() == 0) {
try {
N.checkArgNotEmpty(c, errorMessage);
} finally {
close();
}
}
}
final void checkArgument(final boolean b, final String errorMessage) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkArgument(b, errorMessage);
} finally {
close();
}
}
}
final void checkArgument(final boolean b, final String errorMessageTemplate, final int p1) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkArgument(b, errorMessageTemplate, p1);
} finally {
close();
}
}
}
final void checkArgument(final boolean b, final String errorMessageTemplate, final long p1) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkArgument(b, errorMessageTemplate, p1);
} finally {
close();
}
}
}
final void checkArgument(final boolean b, final String errorMessageTemplate, final Object p1) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkArgument(b, errorMessageTemplate, p1);
} finally {
close();
}
}
}
final void checkArgument(final boolean b, final String errorMessageTemplate, final int p1, final int p2) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkArgument(b, errorMessageTemplate, p1, p2);
} finally {
close();
}
}
}
final void checkArgument(final boolean b, final String errorMessageTemplate, final long p1, final long p2) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkArgument(b, errorMessageTemplate, p1, p2);
} finally {
close();
}
}
}
final void checkArgument(final boolean b, final String errorMessageTemplate, final Object p1, final Object p2) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkArgument(b, errorMessageTemplate, p1, p2);
} finally {
close();
}
}
}
final void checkArgument(final boolean b, final String errorMessageTemplate, final Object p1, final Object p2, final Object p3) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkArgument(b, errorMessageTemplate, p1, p2, p3);
} finally {
close();
}
}
}
final void checkState(final boolean b) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkState(b);
} finally {
close();
}
}
}
final void checkState(final boolean b, final String errorMessage) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkState(b, errorMessage);
} finally {
close();
}
}
}
final void checkState(final boolean b, final String errorMessageTemplate, final int p1) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkState(b, errorMessageTemplate, p1);
} finally {
close();
}
}
}
final void checkState(final boolean b, final String errorMessageTemplate, final long p1) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkState(b, errorMessageTemplate, p1);
} finally {
close();
}
}
}
final void checkState(final boolean b, final String errorMessageTemplate, final Object p1) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkState(b, errorMessageTemplate, p1);
} finally {
close();
}
}
}
final void checkState(final boolean b, final String errorMessageTemplate, final int p1, final int p2) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkState(b, errorMessageTemplate, p1, p2);
} finally {
close();
}
}
}
final void checkState(final boolean b, final String errorMessageTemplate, final long p1, final long p2) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkState(b, errorMessageTemplate, p1, p2);
} finally {
close();
}
}
}
final void checkState(final boolean b, final String errorMessageTemplate, final Object p1, final Object p2) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkState(b, errorMessageTemplate, p1, p2);
} finally {
close();
}
}
}
final void checkState(final boolean b, final String errorMessageTemplate, final Object p1, final Object p2, final Object p3) {
if (!b) {
try {
//noinspection ConstantValue,DataFlowIssue
N.checkState(b, errorMessageTemplate, p1, p2, p3);
} finally {
close();
}
}
}
Deque mergeCloseHandler(final Runnable closeHandler) {
return mergeCloseHandlers(closeHandler, closeHandlers);
}
Deque mergeCloseHandler(final Collection extends IteratorEx>> iters) {
return mergeCloseHandler(() -> closeIterators(iters));
}
static boolean isEmptyCloseHandler(final Runnable closeHandler) {
return closeHandler == null || closeHandler == EMPTY_CLOSE_HANDLER;
}
static boolean isEmptyCloseHandlers(final Collection extends Runnable> closeHandlers) {
return N.isEmpty(closeHandlers) || (closeHandlers.size() == 1 && isEmptyCloseHandler(N.firstOrNullIfEmpty(closeHandlers)));
}
static LocalRunnable newCloseHandler(final Runnable closeHandler) {
return LocalRunnable.wrap(closeHandler);
}
static LocalRunnable newCloseHandler(final AutoCloseable closeable) {
return LocalRunnable.wrap(closeable);
}
@SuppressWarnings("rawtypes")
static LocalRunnable newCloseHandler(final StreamBase s) {
if (s == null || isEmptyCloseHandlers(s.closeHandlers)) {
return EMPTY_CLOSE_HANDLER;
}
return s::close;
}
@SuppressWarnings("rawtypes")
static LocalRunnable newCloseHandler(final StreamBase a, final StreamBase b) {
if ((a == null || isEmptyCloseHandlers(a.closeHandlers)) && (b == null || isEmptyCloseHandlers(b.closeHandlers))) {
return EMPTY_CLOSE_HANDLER;
} else if (a == null || isEmptyCloseHandlers(a.closeHandlers)) {
return b::close;
} else if (b == null || isEmptyCloseHandlers(b.closeHandlers)) {
return a::close;
} else {
return () -> {
RuntimeException runtimeException = null;
try {
a.close();
} catch (final Exception throwable1) {
runtimeException = toRuntimeException(throwable1);
}
try {
b.close();
} catch (final Exception throwable2) {
if (runtimeException == null) {
runtimeException = toRuntimeException(throwable2);
} else {
runtimeException.addSuppressed(throwable2);
}
}
if (runtimeException != null) {
throw runtimeException;
}
};
}
}
@SuppressWarnings("rawtypes")
static LocalRunnable newCloseHandler(final Collection extends StreamBase> c) {
if (N.isEmpty(c)) {
return EMPTY_CLOSE_HANDLER;
}
boolean allEmptyHandlers = true;
for (final StreamBase s : c) {
if (!(s == null || s.isClosed || isEmptyCloseHandlers(s.closeHandlers))) {
allEmptyHandlers = false;
break;
}
}
if (allEmptyHandlers) {
return EMPTY_CLOSE_HANDLER;
}
return () -> {
RuntimeException runtimeException = null;
for (final StreamBase s : c) {
if (s == null || s.isClosed || isEmptyCloseHandlers(s.closeHandlers)) {
continue;
}
try {
s.close();
} catch (final Exception throwable) {
if (runtimeException == null) {
runtimeException = toRuntimeException(throwable);
} else {
runtimeException.addSuppressed(throwable);
}
}
}
if (runtimeException != null) {
throw runtimeException;
}
};
}
static Deque mergeCloseHandlers(final Runnable newCloseHandlerToAdd, final Deque closeHandlers) {
return mergeCloseHandlers(newCloseHandlerToAdd, closeHandlers, false);
}
static Deque mergeCloseHandlers(final Runnable newCloseHandlerToAdd, final Deque closeHandlers,
final boolean closeNewHandlerFirst) {
if (isEmptyCloseHandler(newCloseHandlerToAdd)) {
return closeHandlers;
}
final Deque newCloseHandlers = new LocalArrayDeque<>(isEmptyCloseHandlers(closeHandlers) ? 1 : closeHandlers.size() + 1);
if (closeNewHandlerFirst) {
newCloseHandlers.add(newCloseHandler(newCloseHandlerToAdd));
}
if (!isEmptyCloseHandlers(closeHandlers)) {
newCloseHandlers.addAll(closeHandlers);
}
if (!closeNewHandlerFirst) {
newCloseHandlers.add(newCloseHandler(newCloseHandlerToAdd));
}
return newCloseHandlers;
}
static Deque mergeCloseHandlers(final Deque closeHandlersA, final Deque closeHandlersB) {
if (isEmptyCloseHandlers(closeHandlersA) && closeHandlersB instanceof LocalArrayDeque) {
return closeHandlersB;
} else if (closeHandlersA instanceof LocalArrayDeque && isEmptyCloseHandlers(closeHandlersB)) {
return closeHandlersA;
} else if (isEmptyCloseHandlers(closeHandlersA) && isEmptyCloseHandlers(closeHandlersB)) {
return null; // NOSONAR
}
final Deque newCloseHandlers = new LocalArrayDeque<>();
if (!isEmptyCloseHandlers(closeHandlersA)) {
newCloseHandlers.addAll(closeHandlersA);
}
if (!isEmptyCloseHandlers(closeHandlersB)) {
for (final LocalRunnable h : closeHandlersB) {
if (!newCloseHandlers.contains(h)) {
newCloseHandlers.add(h);
}
}
}
return newCloseHandlers;
}
@SuppressWarnings("rawtypes")
static Deque mergeCloseHandlers(final Deque newCloseHandlers, final StreamBase s) {
return mergeCloseHandlers(s == null ? null : s.closeHandlers, newCloseHandlers);
}
static void setError(final Holder errorHolder, final Throwable e) {
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (errorHolder) { //NOSONAR
if (errorHolder.value() == null) {
errorHolder.setValue(e);
} else {
errorHolder.value().addSuppressed(e);
}
}
}
CharStream newStream(final char[] a) {
return newStream(a, false);
}
CharStream newStream(final char[] a, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayCharStream(a, 0, a.length, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayCharStream(a, sorted, closeHandlers);
}
}
CharStream newStream(final char[] a, final int fromIndex, final int toIndex) {
return newStream(a, fromIndex, toIndex, false);
}
CharStream newStream(final char[] a, final int fromIndex, final int toIndex, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayCharStream(a, fromIndex, toIndex, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayCharStream(a, fromIndex, toIndex, sorted, closeHandlers);
}
}
CharStream newStream(final CharIterator iter) {
return newStream(iter, false);
}
CharStream newStream(final CharIterator iter, final boolean sorted) {
return newStream(iter, sorted, closeHandlers);
}
CharStream newStream(final CharIterator iter, final boolean sorted, final Deque closeHandlers) {
if (isParallel()) {
return new ParallelIteratorCharStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new IteratorCharStream(iter, sorted, closeHandlers);
}
}
ByteStream newStream(final byte[] a) {
return newStream(a, false);
}
ByteStream newStream(final byte[] a, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayByteStream(a, 0, a.length, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayByteStream(a, sorted, closeHandlers);
}
}
ByteStream newStream(final byte[] a, final int fromIndex, final int toIndex) {
return newStream(a, fromIndex, toIndex, false);
}
ByteStream newStream(final byte[] a, final int fromIndex, final int toIndex, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayByteStream(a, fromIndex, toIndex, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayByteStream(a, fromIndex, toIndex, sorted, closeHandlers);
}
}
ByteStream newStream(final ByteIterator iter) {
return newStream(iter, false);
}
ByteStream newStream(final ByteIterator iter, final boolean sorted) {
return newStream(iter, sorted, closeHandlers);
}
ByteStream newStream(final ByteIterator iter, final boolean sorted, final Deque closeHandlers) {
if (isParallel()) {
return new ParallelIteratorByteStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new IteratorByteStream(iter, sorted, closeHandlers);
}
}
ShortStream newStream(final short[] a) {
return newStream(a, false);
}
ShortStream newStream(final short[] a, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayShortStream(a, 0, a.length, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayShortStream(a, sorted, closeHandlers);
}
}
ShortStream newStream(final short[] a, final int fromIndex, final int toIndex) {
return newStream(a, fromIndex, toIndex, false);
}
ShortStream newStream(final short[] a, final int fromIndex, final int toIndex, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayShortStream(a, fromIndex, toIndex, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayShortStream(a, fromIndex, toIndex, sorted, closeHandlers);
}
}
ShortStream newStream(final ShortIterator iter) {
return newStream(iter, false);
}
ShortStream newStream(final ShortIterator iter, final boolean sorted) {
return newStream(iter, sorted, closeHandlers);
}
ShortStream newStream(final ShortIterator iter, final boolean sorted, final Deque closeHandlers) {
if (isParallel()) {
return new ParallelIteratorShortStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new IteratorShortStream(iter, sorted, closeHandlers);
}
}
IntStream newStream(final int[] a) {
return newStream(a, false);
}
IntStream newStream(final int[] a, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayIntStream(a, 0, a.length, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayIntStream(a, sorted, closeHandlers);
}
}
IntStream newStream(final int[] a, final int fromIndex, final int toIndex) {
return newStream(a, fromIndex, toIndex, false);
}
IntStream newStream(final int[] a, final int fromIndex, final int toIndex, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayIntStream(a, fromIndex, toIndex, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayIntStream(a, fromIndex, toIndex, sorted, closeHandlers);
}
}
IntStream newStream(final IntIterator iter) {
return newStream(iter, false);
}
IntStream newStream(final IntIterator iter, final boolean sorted) {
return newStream(iter, sorted, closeHandlers);
}
IntStream newStream(final IntIterator iter, final boolean sorted, final Deque closeHandlers) {
if (isParallel()) {
return new ParallelIteratorIntStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new IteratorIntStream(iter, sorted, closeHandlers);
}
}
LongStream newStream(final long[] a) {
return newStream(a, false);
}
LongStream newStream(final long[] a, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayLongStream(a, 0, a.length, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayLongStream(a, sorted, closeHandlers);
}
}
LongStream newStream(final long[] a, final int fromIndex, final int toIndex) {
return newStream(a, fromIndex, toIndex, false);
}
LongStream newStream(final long[] a, final int fromIndex, final int toIndex, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayLongStream(a, fromIndex, toIndex, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayLongStream(a, fromIndex, toIndex, sorted, closeHandlers);
}
}
LongStream newStream(final LongIterator iter) {
return newStream(iter, false);
}
LongStream newStream(final LongIterator iter, final boolean sorted) {
return newStream(iter, sorted, closeHandlers);
}
LongStream newStream(final LongIterator iter, final boolean sorted, final Deque closeHandlers) {
if (isParallel()) {
return new ParallelIteratorLongStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new IteratorLongStream(iter, sorted, closeHandlers);
}
}
FloatStream newStream(final float[] a) {
return newStream(a, false);
}
FloatStream newStream(final float[] a, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayFloatStream(a, 0, a.length, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayFloatStream(a, sorted, closeHandlers);
}
}
FloatStream newStream(final float[] a, final int fromIndex, final int toIndex) {
return newStream(a, fromIndex, toIndex, false);
}
FloatStream newStream(final float[] a, final int fromIndex, final int toIndex, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayFloatStream(a, fromIndex, toIndex, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayFloatStream(a, fromIndex, toIndex, sorted, closeHandlers);
}
}
FloatStream newStream(final FloatIterator iter) {
return newStream(iter, false);
}
FloatStream newStream(final FloatIterator iter, final boolean sorted) {
return newStream(iter, sorted, closeHandlers);
}
FloatStream newStream(final FloatIterator iter, final boolean sorted, final Deque closeHandlers) {
if (isParallel()) {
return new ParallelIteratorFloatStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new IteratorFloatStream(iter, sorted, closeHandlers);
}
}
DoubleStream newStream(final double[] a) {
return newStream(a, false);
}
DoubleStream newStream(final double[] a, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayDoubleStream(a, 0, a.length, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayDoubleStream(a, sorted, closeHandlers);
}
}
DoubleStream newStream(final double[] a, final int fromIndex, final int toIndex) {
return newStream(a, fromIndex, toIndex, false);
}
DoubleStream newStream(final double[] a, final int fromIndex, final int toIndex, final boolean sorted) {
if (isParallel()) {
return new ParallelArrayDoubleStream(a, fromIndex, toIndex, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayDoubleStream(a, fromIndex, toIndex, sorted, closeHandlers);
}
}
DoubleStream newStream(final DoubleIterator iter) {
return newStream(iter, false);
}
DoubleStream newStream(final DoubleIterator iter, final boolean sorted) {
return newStream(iter, sorted, closeHandlers);
}
DoubleStream newStream(final DoubleIterator iter, final boolean sorted, final Deque closeHandlers) {
if (isParallel()) {
return new ParallelIteratorDoubleStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new IteratorDoubleStream(iter, sorted, closeHandlers);
}
}
Stream newStream(final E[] a) {
return newStream(a, false, null);
}
Stream newStream(final E[] a, final boolean sorted, final Comparator super E> comparator) {
return newStream(a, 0, a.length, sorted, comparator);
}
Stream newStream(final E[] a, final int fromIndex, final int toIndex) {
return newStream(a, fromIndex, toIndex, false, null);
}
Stream newStream(final E[] a, final int fromIndex, final int toIndex, final boolean sorted, final Comparator super E> comparator) {
if (isParallel()) {
return new ParallelArrayStream<>(a, fromIndex, toIndex, sorted, comparator, maxThreadNum(), executorNumForVirtualThread(), splitor(),
asyncExecutor(), cancelUncompletedThreads(), closeHandlers);
} else {
return new ArrayStream<>(a, fromIndex, toIndex, sorted, comparator, closeHandlers);
}
}
Stream newStream(final Iterator iter) {
return newStream(iter, false, null);
}
Stream newStream(final Iterator iter, final boolean sorted, final Comparator super E> comparator) {
return newStream(iter, sorted, comparator, closeHandlers);
}
Stream newStream(final Iterator iter, final boolean sorted, final Comparator super E> comparator, final Deque closeHandlers) {
if (isParallel()) {
return new ParallelIteratorStream<>(iter, sorted, comparator, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new IteratorStream<>(iter, sorted, comparator, closeHandlers);
}
}
Stream newStream(final Stream s) {
return newStream(s, false, null);
}
Stream newStream(final Stream s, final boolean sorted, final Comparator super E> comparator) {
return newStream(s, sorted, comparator, closeHandlers);
}
Stream newStream(final Stream s, final boolean sorted, final Comparator super E> comparator, final Deque closeHandlers) {
if (isParallel()) {
return new ParallelIteratorStream<>(s, sorted, comparator, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
cancelUncompletedThreads(), closeHandlers);
} else {
return new IteratorStream<>(s, sorted, comparator, closeHandlers);
}
}
static CharIteratorEx iterate(final CharStream s) {
return s == null ? CharIteratorEx.empty() : s.iteratorEx();
}
static ByteIteratorEx iterate(final ByteStream s) {
return s == null ? ByteIteratorEx.empty() : s.iteratorEx();
}
static ShortIteratorEx iterate(final ShortStream s) {
return s == null ? ShortIteratorEx.empty() : s.iteratorEx();
}
static IntIteratorEx iterate(final IntStream s) {
return s == null ? IntIteratorEx.empty() : s.iteratorEx();
}
static LongIteratorEx iterate(final LongStream s) {
return s == null ? LongIteratorEx.empty() : s.iteratorEx();
}
static FloatIteratorEx iterate(final FloatStream s) {
return s == null ? FloatIteratorEx.empty() : s.iteratorEx();
}
static DoubleIteratorEx iterate(final DoubleStream s) {
return s == null ? DoubleIteratorEx.empty() : s.iteratorEx();
}
static ObjIteratorEx iterate(final Stream extends T> s) {
return s == null ? ObjIteratorEx.empty() : (ObjIteratorEx) s.iteratorEx();
}
static List> iterateAll(final Collection extends Stream extends T>> streams) {
if (N.isEmpty(streams)) {
return new ArrayList<>(0);
}
final List> result = new ArrayList<>(streams.size());
for (final Stream extends T> s : streams) {
result.add(s == null ? ObjIteratorEx.empty() : (ObjIteratorEx) s.iteratorEx());
}
return result;
}
static CharIteratorEx charIterator(final ObjIteratorEx iter) {
return CharIteratorEx.from(iter);
}
static ByteIteratorEx byteIterator(final ObjIteratorEx iter) {
return ByteIteratorEx.from(iter);
}
static ShortIteratorEx shortIterator(final ObjIteratorEx iter) {
return ShortIteratorEx.from(iter);
}
static IntIteratorEx intIterator(final ObjIteratorEx iter) {
return IntIteratorEx.from(iter);
}
static LongIteratorEx longIterator(final ObjIteratorEx iter) {
return LongIteratorEx.from(iter);
}
static FloatIteratorEx floatIterator(final ObjIteratorEx iter) {
return FloatIteratorEx.from(iter);
}
static DoubleIteratorEx doubleIterator(final ObjIteratorEx iter) {
return DoubleIteratorEx.from(iter);
}
static int sum(final char[] a) {
if (a == null || a.length == 0) {
return 0;
}
return sum(a, 0, a.length);
}
static int sum(final char[] a, final int fromIndex, final int toIndex) {
long sum = 0;
for (int i = fromIndex; i < toIndex; i++) {
sum += a[i];
}
return Numbers.toIntExact(sum);
}
static int sum(final byte[] a) {
if (a == null || a.length == 0) {
return 0;
}
return sum(a, 0, a.length);
}
static int sum(final byte[] a, final int fromIndex, final int toIndex) {
long sum = 0;
for (int i = fromIndex; i < toIndex; i++) {
sum += a[i];
}
return Numbers.toIntExact(sum);
}
static int sum(final short[] a) {
if (a == null || a.length == 0) {
return 0;
}
return sum(a, 0, a.length);
}
static int sum(final short[] a, final int fromIndex, final int toIndex) {
long sum = 0;
for (int i = fromIndex; i < toIndex; i++) {
sum += a[i];
}
return Numbers.toIntExact(sum);
}
static int sum(final int[] a) {
if (a == null || a.length == 0) {
return 0;
}
return sum(a, 0, a.length);
}
static int sum(final int[] a, final int fromIndex, final int toIndex) {
long sum = 0;
for (int i = fromIndex; i < toIndex; i++) {
sum += a[i];
}
return Numbers.toIntExact(sum);
}
static long sum(final long[] a) {
if (a == null || a.length == 0) {
return 0L;
}
return sum(a, 0, a.length);
}
static long sum(final long[] a, final int fromIndex, final int toIndex) {
long sum = 0;
for (int i = fromIndex; i < toIndex; i++) {
sum += a[i];
}
return sum;
}
static double sum(final float[] a) {
if (a == null || a.length == 0) {
return 0d;
}
return sum(a, 0, a.length);
}
static double sum(final float[] a, final int fromIndex, final int toIndex) {
//noinspection resource
return FloatStream.of(a, fromIndex, toIndex).sum();
}
static double sum(final double[] a) {
if (a == null || a.length == 0) {
return 0d;
}
return sum(a, 0, a.length);
}
static double sum(final double[] a, final int fromIndex, final int toIndex) {
//noinspection resource
return DoubleStream.of(a, fromIndex, toIndex).sum();
}
static void complete(final List> futureList, final Holder eHolder) {
if (eHolder.value() != null) {
throwRuntimeException(eHolder);
}
try {
for (final ContinuableFuture future : futureList) {
future.get();
if (eHolder.value() != null) {
break;
}
}
} catch (InterruptedException | ExecutionException e) {
if (eHolder.value() != null) {
throwRuntimeException(eHolder);
}
throw toRuntimeException(e);
}
if (eHolder.value() != null) {
throwRuntimeException(eHolder);
}
}
static void complette(final List> futureList, final Holder eHolder, final E throwableTypeToNotUse)
throws E {
if (eHolder.value() != null) {
throwException(eHolder, throwableTypeToNotUse);
}
try {
for (final ContinuableFuture future : futureList) {
future.get();
if (eHolder.value() != null) {
break;
}
}
} catch (InterruptedException | ExecutionException e) {
if (eHolder.value() != null) {
throwException(eHolder, throwableTypeToNotUse);
}
throw toRuntimeException(e);
}
if (eHolder.value() != null) {
throwException(eHolder, throwableTypeToNotUse);
}
}
static Deque completeToClose(final MutableBoolean onGoing, final Holder holderForAsyncExecutorUsed) {
final Deque closeHandlers = new LocalArrayDeque<>(1);
closeHandlers.add(() -> {
onGoing.setFalse();
if (holderForAsyncExecutorUsed.isNotNull()) {
shutdownTempExecutor(holderForAsyncExecutorUsed.value());
}
});
return closeHandlers;
}
static void completeAndShutdownTempExecutor(final List> futureList, final Holder eHolder,
@SuppressWarnings("rawtypes") final Collection extends BaseStream> streams, final AsyncExecutor asyncExecutorToUse) {
try {
complete(futureList, eHolder);
} finally {
try {
if (eHolder.value() != null) {
IOUtil.closeAllQuietly(streams);
}
} finally {
shutdownTempExecutor(asyncExecutorToUse);
}
}
}
static void completeAndShutdownTempExecutor(final List> futureList, final Holder eHolder,
@SuppressWarnings("rawtypes") final BaseStream stream, final AsyncExecutor specifiedAsyncExecutor, final AsyncExecutor asyncExecutorToUse)
throws E {
try {
complette(futureList, eHolder, (E) null);
} finally {
try (stream) {
shutdownTempExecutor(asyncExecutorToUse, specifiedAsyncExecutor);
}
}
}
static R completeAndCollectResult(final List> futureList, final Holder eHolder, final Supplier supplier,
final BiConsumer combiner, @SuppressWarnings("rawtypes") final BaseStream stream, final AsyncExecutor specifiedAsyncExecutor,
final AsyncExecutor asyncExecutorToUse) {
if (eHolder.value() != null) {
stream.close();
throwException(eHolder, null);
}
R container = (R) NONE;
try {
for (final ContinuableFuture future : futureList) {
if (container == NONE) {
container = future.get();
} else {
combiner.accept(container, future.get());
}
if (eHolder.value() != null) {
break;
}
}
} catch (InterruptedException | ExecutionException e) {
if (eHolder.value() != null) {
throwRuntimeException(eHolder);
}
throw toRuntimeException(e);
} finally {
try (stream) {
shutdownTempExecutor(asyncExecutorToUse, specifiedAsyncExecutor);
}
}
if (eHolder.value() != null) {
throwRuntimeException(eHolder);
}
return container == NONE ? supplier.get() : container;
}
static int calculateBufferedSize(final int len, final int readThreadNum) {
return N.max(N.min(MAX_BUFFERED_SIZE, len * DEFAULT_BUFFERED_SIZE_PER_ITERATOR), readThreadNum * 16);
}
static int toInt(final long max) {
return max > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) max;
}
static void setError(final Holder errorHolder, final Throwable e, final MutableBoolean onGoing) {
// Set error handle first, then set onGoing sign.
// If onGoing sign is set first but error has not been set, threads may stop without throwing exception because errorHolder is empty.
setError(errorHolder, e);
onGoing.setFalse();
}
static void setStopFlagAndThrowException(final Holder errorHolder, final MutableBoolean onGoing) {
onGoing.setFalse();
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (errorHolder) { //NOSONAR
if (errorHolder.value() != null) {
throw toRuntimeException(errorHolder.getAndSet(null), false);
}
}
}
static void throwRuntimeException(final Holder eHolder) {
if (eHolder.value() instanceof RuntimeException) {
throw (RuntimeException) eHolder.value();
} else if (eHolder.value() instanceof Error) {
throw (Error) eHolder.value();
} else {
throw toRuntimeException(eHolder.value());
}
}
static void throwException(final Holder eHolder, @SuppressWarnings("unused") final E throwableTypeToNotUse) throws E { //NOSONAR
final Throwable value = eHolder.value();
if (value instanceof Exception) {
throw (E) value;
} else if (value instanceof final Error error) {
throw error;
} else {
throw toRuntimeException(value);
}
}
static RuntimeException toRuntimeException(final Exception e) {
return ExceptionUtil.toRuntimeException(e, true);
}
static RuntimeException toRuntimeException(final Throwable e) {
return ExceptionUtil.toRuntimeException(e, true);
}
static RuntimeException toRuntimeException(final Throwable e, final boolean throwIfItIsError) {
return ExceptionUtil.toRuntimeException(e, true, throwIfItIsError);
}
static boolean isSameComparator(final Comparator> a, final Comparator> b) {
if (a == b) { // NOSONAR
return true;
} else if (a == null) {
return DEFAULT_COMPARATOR_MAP.containsValue(b);
} else if (b == null) {
return DEFAULT_COMPARATOR_MAP.containsValue(a);
} else {
return (a == NATURAL_COMPARATOR && DEFAULT_COMPARATOR_MAP.containsValue(b)) || (b == NATURAL_COMPARATOR && DEFAULT_COMPARATOR_MAP.containsValue(a)); // NOSONAR
}
}
static Object hashKey(final Object obj) {
return obj == null ? NONE : (obj.getClass().isArray() ? Wrapper.of(obj) : obj);
}
static T[] toArray(final Collection c) {
if (isListElementDataFieldGettable && listElementDataField != null && c.getClass().equals(ArrayList.class)) {
try {
return (T[]) listElementDataField.get(c);
} catch (final Throwable e) { // NOSONAR
// ignore;
isListElementDataFieldGettable = false;
}
}
return (T[]) c.toArray();
}
static List subList(final List list, final int fromIndex, final int toIndex) {
return list.subList(fromIndex, N.min(list.size(), toIndex));
}
static List slice(final T[] a, final int fromIndex, final int toIndex) {
if (N.isEmpty(a)) {
return N.emptyList();
}
// return N.asList(N.copyOfRange(a, fromIndex, toIndex));
return N.slice(a, fromIndex, toIndex);
}
@SuppressFBWarnings("NP_LOAD_OF_KNOWN_NULL_VALUE")
protected static AsyncExecutor checkAsyncExecutor(AsyncExecutor asyncExecutor, final int threadNum, final int executorNumForVirtualThread) {
if (asyncExecutor == null || asyncExecutor == DEFAULT_ASYNC_EXECUTOR) {
if (executorNumForVirtualThread == 0 || !isVirtualThreadSupported) {
int activeCount = 0;
synchronized (DEFAULT_ASYNC_EXECUTOR) {
activeCount = ACTIVE_THREAD_NUM.get();
final boolean canUseDefaultAsyncExecutor = CORE_THREAD_POOL_SIZE - activeCount - threadNum > RESERVED_POOL_SIZE;
if (canUseDefaultAsyncExecutor) {
return DEFAULT_ASYNC_EXECUTOR;
}
}
logActiveThreads(activeCount);
asyncExecutor = new AsyncExecutor(Executors.newFixedThreadPool(threadNum + 1)); // + 1, just in case.
} else {
if (executorNumForVirtualThread == 1) {
ExecutorService virtualThreadPerTaskExecutor = EXECUTOR_QUEUE_FOR_VIRTUAL_THREAD.poll();
if (virtualThreadPerTaskExecutor == null) {
synchronized (EXECUTOR_MAP_FOR_VIRTUAL_THREAD) {
if (EXECUTOR_MAP_FOR_VIRTUAL_THREAD.size() < MAX_POOLED_EXECUTOR_SIZE_FOR_VIRTUAL_THREAD) {
virtualThreadPerTaskExecutor = newVirtualThreadPerTaskExecutor();
EXECUTOR_MAP_FOR_VIRTUAL_THREAD.put(virtualThreadPerTaskExecutor, true);
}
}
//noinspection ConstantValue
if (virtualThreadPerTaskExecutor == null) { //NOSONAR
virtualThreadPerTaskExecutor = newVirtualThreadPerTaskExecutor();
}
}
asyncExecutor = new AsyncExecutor(virtualThreadPerTaskExecutor);
} else {
final int virtualThreadNumPerTaskExecutor = threadNum % executorNumForVirtualThread == 0 ? threadNum / executorNumForVirtualThread
: threadNum / executorNumForVirtualThread + 1;
final LocalMultiVirtualThreadExecutor localMultiVirtualThreadExecutor = new LocalMultiVirtualThreadExecutor(
virtualThreadNumPerTaskExecutor);
asyncExecutor = new AsyncExecutor(localMultiVirtualThreadExecutor);
}
}
}
return asyncExecutor;
}
protected static AsyncExecutor execute(final AsyncExecutor asyncExecutorToUse, final int maxThreadNum, final int executorNumForVirtualThread,
final int taskIndex, final Runnable cmd) {
return execute(asyncExecutorToUse, maxThreadNum, executorNumForVirtualThread, taskIndex, Fn.r2c(cmd));
}
protected static AsyncExecutor execute(final AsyncExecutor asyncExecutorToUse, final int maxThreadNum, final int executorNumForVirtualThread,
final int taskIndex, final Callable> cmd) {
return execute(asyncExecutorToUse, maxThreadNum, executorNumForVirtualThread, taskIndex, null, cmd);
}
protected static AsyncExecutor execute(final AsyncExecutor asyncExecutorToUse, final int maxThreadNum, final int executorNumForVirtualThread,
final int taskIndex, final List> futureList, final Runnable cmd) {
return execute(asyncExecutorToUse, maxThreadNum, executorNumForVirtualThread, taskIndex, futureList, Fn.r2c(cmd));
}
protected static AsyncExecutor execute(AsyncExecutor asyncExecutorToUse, final int maxThreadNum,
@SuppressWarnings("unused") final int executorNumForVirtualThread, final int taskIndex, final List> futureList,
final Callable cmd) {
// if (executorNumForVirtualThread == 0 || isVirtualThreadSupported == false) {
if (asyncExecutorToUse == null) {
asyncExecutorToUse = DEFAULT_ASYNC_EXECUTOR;
}
if (asyncExecutorToUse == DEFAULT_ASYNC_EXECUTOR) {
int activeCount = 0;
synchronized (DEFAULT_ASYNC_EXECUTOR) {
activeCount = ACTIVE_THREAD_NUM.get();
if (CORE_THREAD_POOL_SIZE - activeCount > RESERVED_POOL_SIZE) {
if (futureList == null) {
asyncExecutorToUse.execute(cmd);
} else {
futureList.add(asyncExecutorToUse.execute(cmd));
}
return asyncExecutorToUse;
}
}
logActiveThreads(activeCount);
asyncExecutorToUse = new AsyncExecutor(Executors.newFixedThreadPool(maxThreadNum - taskIndex + 1)); // + 1, just in case.
}
// } else if (asyncExecutorToUse == null || asyncExecutorToUse == DEFAULT_ASYNC_EXECUTOR) {
// if (executorNumForVirtualThread == 1) {
// ExecutorService virtualThreadPerTaskExecutor = EXECUTOR_QUEUE_FOR_VIRTUAL_THREAD.poll();
//
// if (virtualThreadPerTaskExecutor == null) {
// synchronized (EXECUTOR_MAP_FOR_VIRTUAL_THREAD) {
// if (EXECUTOR_MAP_FOR_VIRTUAL_THREAD.size() < MAX_POOLED_EXECUTOR_SIZE_FOR_VIRTUAL_THREAD) {
//
// virtualThreadPerTaskExecutor = newVirtualThreadPerTaskExecutor();
// EXECUTOR_MAP_FOR_VIRTUAL_THREAD.put(virtualThreadPerTaskExecutor, true);
// }
// }
//
// if (virtualThreadPerTaskExecutor == null) { //NOSONAR
// virtualThreadPerTaskExecutor = newVirtualThreadPerTaskExecutor();
// }
// }
//
// asyncExecutorToUse = new AsyncExecutor(virtualThreadPerTaskExecutor);
// } else {
// final int virtualThreadNumPerTaskExecutor = maxThreadNum % executorNumForVirtualThread == 0
// ? maxThreadNum / executorNumForVirtualThread
// : maxThreadNum / executorNumForVirtualThread + 1;
// final LocalMultiVirtualThreadExecutor localMultiVirtualThreadExecutor = new LocalMultiVirtualThreadExecutor(virtualThreadNumPerTaskExecutor);
// asyncExecutorToUse = new AsyncExecutor(localMultiVirtualThreadExecutor);
// }
// }
if (futureList == null) {
asyncExecutorToUse.execute(cmd);
} else {
futureList.add(asyncExecutorToUse.execute(cmd));
}
return asyncExecutorToUse;
}
// // TODO a bug? dead lock
// ExecutorService newVirtualThreadPerTaskExecutor = Executors.newVirtualThreadPerTaskExecutor();
// ExecutorService newVirtualThreadPerTaskExecutor2 = Executors.newVirtualThreadPerTaskExecutor();
// Stream.range(1, 1000)
// .parallel(128, newVirtualThreadPerTaskExecutor)
// .onEach(Fn.sleep(10))
// .parallel(128, newVirtualThreadPerTaskExecutor2)
// .onEach(Fn.sleep(10))
// .count();
// @SuppressWarnings("preview")
private static ExecutorService newVirtualThreadPerTaskExecutor() {
// TODO disable it because it required Java 19.
// A preview version released: 3.3.19.preview
// return Executors.newVirtualThreadPerTaskExecutor();
throw new UnsupportedOperationException("It's disabled because Java 19 is required for source and target version by compiler");
}
static void shutdownTempExecutor(final AsyncExecutor asyncExecutorToUse) {
shutdownTempExecutor(asyncExecutorToUse, null);
}
static void shutdownTempExecutor(final AsyncExecutor asyncExecutorToUse, final AsyncExecutor specifiedAsyncExecutor) {
if (asyncExecutorToUse == null || asyncExecutorToUse == DEFAULT_ASYNC_EXECUTOR || asyncExecutorToUse == specifiedAsyncExecutor) {
// continue;
} else {
// if (isVirtualThreadSupported) {
// final Executor executor = asyncExecutorToUse.getExecutor();
// boolean isPooledVirtualThreadExecutor = false;
//
// if (EXECUTOR_MAP_FOR_VIRTUAL_THREAD.size() < MAX_POOLED_EXECUTOR_SIZE_FOR_VIRTUAL_THREAD) {
// // TODO really need?
// synchronized (EXECUTOR_MAP_FOR_VIRTUAL_THREAD) {
// isPooledVirtualThreadExecutor = EXECUTOR_MAP_FOR_VIRTUAL_THREAD.containsKey(executor);
// }
// } else {
// isPooledVirtualThreadExecutor = EXECUTOR_MAP_FOR_VIRTUAL_THREAD.containsKey(executor);
// }
//
// if (isPooledVirtualThreadExecutor) {
// EXECUTOR_QUEUE_FOR_VIRTUAL_THREAD.offer((ExecutorService) executor); //NOSONAR
// } else if (executor instanceof LocalMultiVirtualThreadExecutor) {
// ((LocalMultiVirtualThreadExecutor) executor).shutdown();
// } else {
// asyncExecutorToUse.shutdown();
// }
// } else {
// asyncExecutorToUse.shutdown();
// }
asyncExecutorToUse.shutdown();
}
}
static void logActiveThreads(final int activeCount) {
logger.info(
"Creating a new thread pool to void dead lock if there are too many active threads running in default thread pool. This new thread pool will be closed or shut down after execution. Core thread pool size: {}, Current active threads: {}",
CORE_THREAD_POOL_SIZE, activeCount);
}
static boolean canBeSequential(final int maxThreadNum) {
return maxThreadNum <= 1;
}
static boolean canBeSequential(final int maxThreadNum, final int fromIndex, final int toIndex) {
return maxThreadNum <= 1 || toIndex - fromIndex <= 1;
}
@Internal
interface LocalRunnable extends Runnable {
static LocalRunnable wrap(final Runnable closeHandler) {
if (closeHandler == null) {
return EMPTY_CLOSE_HANDLER;
} else if (closeHandler instanceof LocalRunnable) {
return (LocalRunnable) closeHandler;
}
return new LocalRunnable() {
private volatile boolean isClosed = false;
@Override
public void run() {
if (isClosed) {
return;
}
isClosed = true;
closeHandler.run();
}
};
}
static LocalRunnable wrap(final AutoCloseable closeable) {
return new LocalRunnable() {
private volatile boolean isClosed = false;
@Override
public void run() {
if (isClosed) {
return;
}
isClosed = true;
IOUtil.close(closeable);
}
};
}
}
@Internal
static final class LocalArrayDeque extends ArrayDeque {
@Serial
private static final long serialVersionUID = -97425473105100734L;
public LocalArrayDeque() {
}
public LocalArrayDeque(final int initialCapacity) {
super(initialCapacity);
}
public LocalArrayDeque(final Collection extends T> c) {
super(c);
}
}
/**
*
* Methods defined in this class will only be called sequentially
*
*/
@Internal
static final class LocalMultiVirtualThreadExecutor implements ExecutorService {
private final MutableInt virtualThreadCounter = MutableInt.of(0);
private final int virtualThreadNumPerTaskExecutor;
private ExecutorService currentVirtualThreadTaskExecutor;
private List executorServicesUsed = null;
private boolean isShutDown = false;
LocalMultiVirtualThreadExecutor(final int virtualThreadNumPerTaskExecutor) {
this.virtualThreadNumPerTaskExecutor = N.max(2, virtualThreadNumPerTaskExecutor);
}
@Override
public void execute(final Runnable command) {
final ExecutorService virtualThreadTaskExecutor = getVirtualThreadTaskExecutor();
virtualThreadTaskExecutor.execute(command);
}
@Override
public Future submit(final Callable task) {
final ExecutorService virtualThreadTaskExecutor = getVirtualThreadTaskExecutor();
return virtualThreadTaskExecutor.submit(task);
}
@Override
public Future> submit(final Runnable task) {
final ExecutorService virtualThreadTaskExecutor = getVirtualThreadTaskExecutor();
return virtualThreadTaskExecutor.submit(task);
}
@Override
public Future submit(final Runnable task, final T result) {
final ExecutorService virtualThreadTaskExecutor = getVirtualThreadTaskExecutor();
return virtualThreadTaskExecutor.submit(task, result);
}
private ExecutorService getVirtualThreadTaskExecutor() {
if (virtualThreadCounter.getAndIncrement() % virtualThreadNumPerTaskExecutor == 0 || currentVirtualThreadTaskExecutor == null) {
currentVirtualThreadTaskExecutor = EXECUTOR_QUEUE_FOR_VIRTUAL_THREAD.poll();
if (currentVirtualThreadTaskExecutor == null) {
synchronized (EXECUTOR_MAP_FOR_VIRTUAL_THREAD) {
if (EXECUTOR_MAP_FOR_VIRTUAL_THREAD.size() < MAX_POOLED_EXECUTOR_SIZE_FOR_VIRTUAL_THREAD) {
currentVirtualThreadTaskExecutor = newVirtualThreadPerTaskExecutor();
EXECUTOR_MAP_FOR_VIRTUAL_THREAD.put(currentVirtualThreadTaskExecutor, true);
}
}
if (currentVirtualThreadTaskExecutor == null) {
currentVirtualThreadTaskExecutor = newVirtualThreadPerTaskExecutor();
}
}
if (executorServicesUsed == null) {
executorServicesUsed = new ArrayList<>();
}
executorServicesUsed.add(currentVirtualThreadTaskExecutor);
}
return currentVirtualThreadTaskExecutor;
}
/**
* @throws UnsupportedOperationException
* @deprecated UnsupportedOperationException
*/
@Deprecated
@Override
public List> invokeAll(final Collection extends Callable> tasks) {
throw new UnsupportedOperationException();
}
/**
* @throws UnsupportedOperationException
* @deprecated UnsupportedOperationException
*/
@Deprecated
@Override
public List> invokeAll(final Collection extends Callable> tasks, final long timeout, final TimeUnit unit)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* @throws UnsupportedOperationException
* @deprecated UnsupportedOperationException
*/
@Deprecated
@Override
public T invokeAny(final Collection extends Callable> tasks) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* @throws UnsupportedOperationException
* @deprecated UnsupportedOperationException
*/
@Deprecated
@Override
public T invokeAny(final Collection extends Callable> tasks, final long timeout, final TimeUnit unit) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public boolean isShutdown() {
return isShutDown;
}
@Override
public void shutdown() {
if (isShutDown) {
return;
}
if (N.notEmpty(executorServicesUsed)) {
List executorServicesToShutdown = null;
if (EXECUTOR_MAP_FOR_VIRTUAL_THREAD.size() < MAX_POOLED_EXECUTOR_SIZE_FOR_VIRTUAL_THREAD) {
// TODO really need?
synchronized (EXECUTOR_MAP_FOR_VIRTUAL_THREAD) {
for (final ExecutorService executorService : executorServicesUsed) {
if (EXECUTOR_MAP_FOR_VIRTUAL_THREAD.containsKey(executorService)) {
EXECUTOR_QUEUE_FOR_VIRTUAL_THREAD.offer(executorService); //NOSONAR
} else {
if (executorServicesToShutdown == null) {
executorServicesToShutdown = new ArrayList<>(executorServicesUsed.size() / 2);
}
executorServicesToShutdown.add(executorService);
}
}
}
} else {
// No more resize.
for (final ExecutorService executorService : executorServicesUsed) {
if (EXECUTOR_MAP_FOR_VIRTUAL_THREAD.containsKey(executorService)) {
EXECUTOR_QUEUE_FOR_VIRTUAL_THREAD.offer(executorService); //NOSONAR
} else {
if (executorServicesToShutdown == null) {
executorServicesToShutdown = new ArrayList<>(executorServicesUsed.size() / 2);
}
executorServicesToShutdown.add(executorService);
}
}
}
if (N.notEmpty(executorServicesToShutdown)) {
RuntimeException ex = null;
for (final ExecutorService executorService : executorServicesToShutdown) {
try {
executorService.shutdown();
} catch (final RuntimeException e) {
if (ex == null) {
ex = e;
} else {
ex.addSuppressed(e);
}
}
}
if (ex != null) {
throw ex;
}
}
}
isShutDown = true; // just return true.
}
/**
*
* @deprecated UnsupportedOperationException
*/
@Deprecated
@Override
public List shutdownNow() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
*
* @deprecated UnsupportedOperationException
*/
@Deprecated
@Override
public boolean isTerminated() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
*
* @deprecated UnsupportedOperationException
*/
@Deprecated
@Override
public boolean awaitTermination(final long timeout, final TimeUnit unit) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy