All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.landawn.abacus.util.stream.StreamBase Maven / Gradle / Ivy

Go to download

A general programming library in Java/Android. It's easy to learn and simple to use with concise and powerful APIs.

There is a newer version: 5.2.4
Show newest version
/*
 * 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.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.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.TimeoutException;
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.IntermediateOp;
import com.landawn.abacus.annotation.Internal;
import com.landawn.abacus.annotation.LazyEvaluation;
import com.landawn.abacus.annotation.SequentialOnly;
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.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.LongIterator;
import com.landawn.abacus.util.LongList;
import com.landawn.abacus.util.LongMultiset;
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.RateLimiter;
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;

/**
 *
 */
@LazyEvaluation
abstract class StreamBase, S extends StreamBase>
        implements BaseStream {
    static final Logger logger = LoggerFactory.getLogger(StreamBase.class);

    static final Object NONE = new Object();

    /**
     *
     * 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 Runnable EMPTY_CLOSE_HANDLER = () -> {
        // do nothing.
    };

    static final int MAX_WAIT_TIME_FOR_QUEUE_OFFER = 10; // unit is milliseconds
    static final int MAX_WAIT_TIME_FOR_QUEUE_POLL = 3; // unit is milliseconds

    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 dead lock.

    // static final long MAX_WAIT_TO_BREAK_FOR_DEAD_LOCK = 6 * 60 * 1000; // 6 minutes

    static final int MAX_BUFFERED_SIZE = 10240;
    static final int DEFAULT_BUFFERED_SIZE_PER_ITERATOR = 64;

    static final Splitor DEFAULT_SPLITOR = Splitor.ITERATOR;

    static final Random RAND = new SecureRandom();

    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 {
            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() {
                @Override
                public void run() {
                    logger.warn("Starting to shutdown task executors for virtual threads for Stream");

                    for (ExecutorService virtualThreadPerTaskExecutor : EXECUTOR_MAP_FOR_VIRTUAL_THREAD.keySet()) {
                        try {
                            virtualThreadPerTaskExecutor.shutdown();

                            virtualThreadPerTaskExecutor.awaitTermination(120, TimeUnit.SECONDS);
                        } catch (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 (Throwable e) {
            // ignore
        }

        isVirtualThreadSupported = tmp;
    }

    private static final AtomicInteger activeThreadCounter = 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 dead lock 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 (activeThreadCounter.get() > 0) {
            //        activeThreadCounter.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 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: {}", activeThreadCounter.get());
                //    }

                activeThreadCounter.incrementAndGet();

                return super.execute(new FutureTask<>(() -> {
                    try {
                        command.run();
                        return null;
                    } finally {
                        activeThreadCounter.decrementAndGet();

                        //    if (logger.isDebugEnabled()) {
                        //        logger.debug("======: ActiveTaskCount-Pool: {}", threadPoolExecutor.getActiveCount());
                        //    }
                    }
                }) {
                    @Override
                    public boolean cancel(boolean mayInterruptIfRunning) {
                        //    // This should not be called.
                        //    if (isCancelled()) {
                        //        return true;
                        //    }
                        //
                        //    final boolean ret = super.cancel(mayInterruptIfRunning);
                        //
                        //    if (ret && activeThreadCounter.get() > 0) {
                        //        activeThreadCounter.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: {}", activeThreadCounter.get());
                //    }

                activeThreadCounter.incrementAndGet();

                return super.execute(new FutureTask<>(() -> {
                    try {
                        return command.call();
                    } finally {
                        activeThreadCounter.decrementAndGet();

                        //    if (logger.isDebugEnabled()) {
                        //        logger.debug("======: ActiveTaskCount-Pool: {}", threadPoolExecutor.getActiveCount());
                        //    }
                    }
                }) {
                    @Override
                    public boolean cancel(boolean mayInterruptIfRunning) {
                        //    // This should not be called.
                        //    if (isCancelled()) {
                        //        return true;
                        //    }
                        //
                        //    final boolean ret = super.cancel(mayInterruptIfRunning);
                        //
                        //    if (ret && activeThreadCounter.get() > 0) {
                        //        activeThreadCounter.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() {
            @Override
            public void run() {

                logger.warn("Starting to shutdown tasks for Stream");

                try {
                    threadPoolExecutor.shutdown();

                    threadPoolExecutor.awaitTermination(120, TimeUnit.SECONDS);
                } catch (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 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.reversedOrder();

    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> defaultComparator = new BiMap<>();

    static {
        defaultComparator.put(char.class, CHAR_COMPARATOR);
        defaultComparator.put(byte.class, BYTE_COMPARATOR);
        defaultComparator.put(short.class, SHORT_COMPARATOR);
        defaultComparator.put(int.class, INT_COMPARATOR);
        defaultComparator.put(long.class, LONG_COMPARATOR);
        defaultComparator.put(float.class, FLOAT_COMPARATOR);
        defaultComparator.put(double.class, DOUBLE_COMPARATOR);
        defaultComparator.put(Object.class, NATURAL_COMPARATOR);
    }

    static final Map, Integer> clsNum = new BiMap<>();

    static {
        int idx = 0;
        clsNum.put(boolean[].class, idx++); // 0
        clsNum.put(char[].class, idx++);
        clsNum.put(byte[].class, idx++);
        clsNum.put(short[].class, idx++);
        clsNum.put(int[].class, idx++);
        clsNum.put(long[].class, idx++);
        clsNum.put(float[].class, idx++);
        clsNum.put(double[].class, idx++); // 7
        clsNum.put(BooleanList.class, idx++); // 8
        clsNum.put(CharList.class, idx++);
        clsNum.put(ByteList.class, idx++);
        clsNum.put(ShortList.class, idx++);
        clsNum.put(IntList.class, idx++);
        clsNum.put(LongList.class, idx++);
        clsNum.put(FloatList.class, idx++);
        clsNum.put(DoubleList.class, idx++); // 15
    }

    //    @SuppressWarnings("rawtypes")
    //    static final BinaryOperator reducingCombiner = new BinaryOperator() {
    //        @Override
    //        public Object apply(Object t, Object u) {
    //            if (t instanceof Collection) {
    //                final Collection a = (Collection) t;
    //                final Collection b = (Collection) u;
    //
    //                if (a.size() >= b.size()) {
    //                    a.addAll(b);
    //                    return a;
    //                } else {
    //                    b.addAll(a);
    //                    return b;
    //                }
    //            } else if (t instanceof Map) {
    //                final Map a = (Map) t;
    //                final Map b = (Map) u;
    //
    //                if (a.size() >= b.size()) {
    //                    a.putAll(b);
    //                    return a;
    //                } else {
    //                    b.putAll(a);
    //                    return b;
    //                }
    //            } else if (t instanceof Object[]) {
    //                return N.concat((Object[]) t, (Object[]) u);
    //            } else if (t instanceof StringBuilder) {
    //                final StringBuilder a = (StringBuilder) t;
    //                final StringBuilder b = (StringBuilder) u;
    //
    //                if (a.length() >= b.length()) {
    //                    a.append(b);
    //                    return a;
    //                } else {
    //                    b.append(a);
    //                    return b;
    //                }
    //            } else if (t instanceof String) {
    //                return (String) t + (String) u;
    //            } else if (t instanceof Multiset) {
    //                final Multiset a = (Multiset) t;
    //                final Multiset b = (Multiset) u;
    //
    //                if (a.size() >= b.size()) {
    //                    a.addAll(b);
    //                    return a;
    //                } else {
    //                    b.addAll(a);
    //                    return b;
    //                }
    //            } else if (t instanceof LongMultiset) {
    //                final LongMultiset a = (LongMultiset) t;
    //                final LongMultiset b = (LongMultiset) u;
    //
    //                if (a.size() >= b.size()) {
    //                    a.addAll(b);
    //                    return a;
    //                } else {
    //                    b.addAll(a);
    //                    return b;
    //                }
    //            } else if (t instanceof Multimap) {
    //                final Multimap a = (Multimap) t;
    //                final Multimap b = (Multimap) u;
    //
    //                if (a.size() >= b.size()) {
    //                    a.putAll(b);
    //                    return a;
    //                } else {
    //                    b.putAll(a);
    //                    return b;
    //                }
    //            } else {
    //                final Class cls = t.getClass();
    //                final Integer num = clsNum.get(cls);
    //
    //                if (num == null) {
    //                    throw new RuntimeException(cls.getCanonicalName()
    //                            + " can't be combined by default. Only Collection/Map/StringBuilder/String/Multiset/LongMultiset/Multimap/BooleanList ... List/boolean[] ... Object[] are supported");
    //                }
    //
    //                switch (num.intValue()) {
    //                    case 0:
    //                        return N.concat((boolean[]) t, (boolean[]) u);
    //                    case 1:
    //                        return N.concat((char[]) t, (char[]) u);
    //                    case 2:
    //                        return N.concat((byte[]) t, (byte[]) u);
    //                    case 3:
    //                        return N.concat((short[]) t, (short[]) u);
    //                    case 4:
    //                        return N.concat((int[]) t, (int[]) u);
    //                    case 5:
    //                        return N.concat((long[]) t, (long[]) u);
    //                    case 6:
    //                        return N.concat((float[]) t, (float[]) u);
    //                    case 7:
    //                        return N.concat((double[]) t, (double[]) u);
    //                    case 8: {
    //                        final BooleanList a = (BooleanList) t;
    //                        final BooleanList b = (BooleanList) u;
    //
    //                        if (a.size() >= b.size()) {
    //                            a.addAll(b);
    //                            return a;
    //                        } else {
    //                            b.addAll(a);
    //                            return b;
    //                        }
    //                    }
    //                    case 9: {
    //                        final CharList a = (CharList) t;
    //                        final CharList b = (CharList) u;
    //
    //                        if (a.size() >= b.size()) {
    //                            a.addAll(b);
    //                            return a;
    //                        } else {
    //                            b.addAll(a);
    //                            return b;
    //                        }
    //                    }
    //                    case 10: {
    //                        final ByteList a = (ByteList) t;
    //                        final ByteList b = (ByteList) u;
    //
    //                        if (a.size() >= b.size()) {
    //                            a.addAll(b);
    //                            return a;
    //                        } else {
    //                            b.addAll(a);
    //                            return b;
    //                        }
    //                    }
    //                    case 11: {
    //                        final ShortList a = (ShortList) t;
    //                        final ShortList b = (ShortList) u;
    //
    //                        if (a.size() >= b.size()) {
    //                            a.addAll(b);
    //                            return a;
    //                        } else {
    //                            b.addAll(a);
    //                            return b;
    //                        }
    //                    }
    //                    case 12: {
    //                        final IntList a = (IntList) t;
    //                        final IntList b = (IntList) u;
    //
    //                        if (a.size() >= b.size()) {
    //                            a.addAll(b);
    //                            return a;
    //                        } else {
    //                            b.addAll(a);
    //                            return b;
    //                        }
    //                    }
    //                    case 13: {
    //                        final LongList a = (LongList) t;
    //                        final LongList b = (LongList) u;
    //
    //                        if (a.size() >= b.size()) {
    //                            a.addAll(b);
    //                            return a;
    //                        } else {
    //                            b.addAll(a);
    //                            return b;
    //                        }
    //                    }
    //                    case 14: {
    //                        final FloatList a = (FloatList) t;
    //                        final FloatList b = (FloatList) u;
    //
    //                        if (a.size() >= b.size()) {
    //                            a.addAll(b);
    //                            return a;
    //                        } else {
    //                            b.addAll(a);
    //                            return b;
    //                        }
    //                    }
    //                    case 15: {
    //                        final DoubleList a = (DoubleList) t;
    //                        final DoubleList b = (DoubleList) u;
    //
    //                        if (a.size() >= b.size()) {
    //                            a.addAll(b);
    //                            return a;
    //                        } else {
    //                            b.addAll(a);
    //                            return b;
    //                        }
    //                    }
    //
    //                    default:
    //                        throw new RuntimeException(cls.getCanonicalName()
    //                                + " can't be combined by default. Only Collection/Map/StringBuilder/String/Multiset/LongMultiset/Multimap/BooleanList ... List/boolean[] ... Object[] are supported");
    //                }
    //            }
    //        }
    //    };

    @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 if (t instanceof Multiset) {
            ((Multiset) t).addAll((Multiset) u);
        } else if (t instanceof LongMultiset) {
            ((LongMultiset) t).addAll((LongMultiset) u);
        } else if (t instanceof Multimap) {
            ((Multimap) t).putAll((Multimap) u);
        } else {
            final Class cls = t.getClass();
            Integer num = clsNum.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 RuntimeException(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 (Throwable e) {
            // 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 (Throwable e) {
            // ignore.
        }
    }

    final Deque closeHandlers;
    final boolean sorted;
    final Comparator cmp;
    boolean isClosed = false;

    StreamBase(final boolean sorted, final Comparator cmp, final Collection closeHandlers) {
        this.closeHandlers = isEmptyCloseHandlers(closeHandlers) ? null
                : (closeHandlers instanceof LocalArrayDeque ? (LocalArrayDeque) closeHandlers : new LocalArrayDeque<>(closeHandlers));

        this.sorted = sorted;
        this.cmp = cmp;
    }

    /**
     * 
     *
     * @param position 
     * @return 
     */
    @Override
    public OT elementAt(final long position) {
        assertNotClosed();

        checkArgNotNegative(position, "position");

        if (position == 0) {
            return first();
        } else {
            return skip(position).first();
        }
    }

    /**
     * 
     *
     * @param permitsPerSecond 
     * @return 
     */
    @Override
    public S rateLimited(double permitsPerSecond) {
        return rateLimited(RateLimiter.create(permitsPerSecond));
    }

    /**
     * 
     *
     * @param action 
     * @return 
     */
    @Override
    public S peek(C action) {
        return onEach(action);
    }

    //    @Override
    //    public OT findAny(P predicate) {
    //        return findFirst(predicate);
    //    }

    //    @Override
    //    public S slice(final long fromIndex, final long toIndex) {
    //        checkArgNotNegative(from, "fromIndex");
    //        checkArgNotNegative(toIndex, "toIndex");
    //        checkArgument(toIndex >= fromIndex, "'toIndex' can't be less than `fromIndex`");
    //
    //        return fromIndex == 0 ? limit(toIndex) : skip(from).limit(toIndex - fromIndex);
    //    }

    /**
     * 
     *
     * @param windowSize 
     * @return 
     */
    @Override
    public Stream sliding(int windowSize) {
        return sliding(windowSize, 1);
    }

    /**
     * 
     *
     * @param windowSize 
     * @return 
     */
    @Override
    public Stream slidingToList(int windowSize) {
        return slidingToList(windowSize, 1);
    }

    /**
     * 
     *
     * @return 
     */
    @Override
    public S shuffled() {
        return shuffled(RAND);
    }

    /**
     * 
     *
     * @param exceptionSupplier 
     * @return 
     */
    @SequentialOnly
    @IntermediateOp
    @Override
    public S throwIfEmpty(Supplier exceptionSupplier) {
        checkArgNotNull(exceptionSupplier, "exceptionSupplier");

        final Supplier tmp = () -> {
            throw exceptionSupplier.get();
        };

        return appendIfEmpty(tmp);
    }

    /**
     * 
     *
     * @return 
     */
    @SuppressWarnings("deprecation")
    @Override
    public ImmutableList toImmutableList() {
        return ImmutableList.wrap(toList());
    }

    /**
     * 
     *
     * @return 
     */
    @SuppressWarnings("deprecation")
    @Override
    public ImmutableSet toImmutableSet() {
        return ImmutableSet.wrap(toSet());
    }

    /**
     * 
     *
     * @param delimiter 
     * @return 
     */
    @Override
    public String join(final CharSequence delimiter) {
        return join(delimiter, "", "");
    }

    /**
     * 
     */
    @Override
    public void println() {
        N.println(sequential().join(", ", "[", "]"));
    }

    /**
     * 
     *
     * @param  
     * @param transfer 
     * @return 
     */
    @Override
    @SuppressWarnings("rawtypes")
    public  SS __(final Function transfer) {
        assertNotClosed();

        return transfer.apply((S) this);
    }

    /**
     * 
     *
     * @return 
     */
    @Override
    public boolean isParallel() {
        return false;
    }

    /**
     * 
     *
     * @return 
     */
    @Override
    public S sequential() {
        return (S) this;
    }

    /**
     * 
     *
     * @return 
     */
    @Override
    public S parallel() {
        return parallel(DEFAULT_MAX_THREAD_NUM, DEFAULT_SPLITOR);
    }

    /**
     * 
     *
     * @param maxThreadNum 
     * @return 
     * @see #maxThreadNumPerOperation()
     */
    @Override
    public S parallel(final int maxThreadNum) {
        return parallel(maxThreadNum, DEFAULT_SPLITOR);
    }

    /**
     * 
     *
     * @param splitor 
     * @return 
     */
    @Override
    public S parallel(final Splitor splitor) {
        return parallel(DEFAULT_MAX_THREAD_NUM, splitor);
    }

    /**
     * 
     *
     * @param maxThreadNum 
     * @param splitor 
     * @return 
     * @see #maxThreadNumPerOperation()
     */
    @Override
    public S parallel(final int maxThreadNum, final Splitor splitor) {
        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 specifiy Executor.");
        //    }

        return parallel(checkMaxThreadNum(maxThreadNum, 0, DEFAULT_ASYNC_EXECUTOR), 0, splitor == null ? DEFAULT_SPLITOR : splitor, DEFAULT_ASYNC_EXECUTOR,
                false);
    }

    /**
     * 
     *
     * @param maxThreadNum 
     * @param executor 
     * @return 
     */
    @Override
    public S parallel(final int maxThreadNum, final Executor executor) {
        return parallel(maxThreadNum, DEFAULT_SPLITOR, executor);
    }

    /**
     * 
     *
     * @param executor 
     * @return 
     */
    @Override
    public S parallel(final Executor executor) {
        return parallel(DEFAULT_MAX_THREAD_NUM, DEFAULT_SPLITOR, executor);
    }

    /**
     * 
     *
     * @param maxThreadNum 
     * @param splitor 
     * @param executor 
     * @return 
     */
    @Override
    public S parallel(final int maxThreadNum, final Splitor splitor, final Executor executor) {
        checkArgNotNegative(maxThreadNum, "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);
    //    }

    /**
     * 
     *
     * @param ps 
     * @return 
     */
    @Override
    public S parallel(final ParallelSettings ps) {
        checkArgNotNull(ps, "ps");
        checkArgNotNegative(ps.maxThreadNum(), "maxThreadNum");
        checkArgNotNegative(ps.executorNumForVirtualThread(), "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);
    }

    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 == false) && (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;
        }

        return maxThreadNum;
    }

    static int checkExecutorNumForVirtualThread(final int maxThreadNum, final int executorNumForVirtualThread) {
        if (isVirtualThreadSupported == false) {
            return 0; // follow down 0 for java version < 19
        }

        return N.min(maxThreadNum / 2, executorNumForVirtualThread); // only meaningful when executorNumForVirtualThread <= maxThreadNum / 2
    }

    // protected abstract S parallel(final int maxThreadNum, final Splitor splitor, final AsyncExecutor asyncExecutor, final boolean cancelUncompletedThreads);

    protected abstract S parallel(final int maxThreadNum, int executorNumForVirtualThread, final Splitor splitor, final AsyncExecutor asyncExecutor,
            final boolean cancelUncompletedThreads);

    /**
     * 
     *
     * @param  
     * @param ops 
     * @return 
     */
    @Override
    @SuppressWarnings("rawtypes")
    public  SS sps(final Function ops) {
        assertNotClosed();

        if (isParallel()) {
            return (SS) ((StreamBase) ops.apply((S) this)).sequential();
        } else {
            return (SS) ((StreamBase) ops.apply(parallel())).sequential();
        }
    }

    /**
     * 
     *
     * @param  
     * @param maxThreadNum 
     * @param ops 
     * @return 
     */
    @Override
    @SuppressWarnings("rawtypes")
    public  SS sps(int maxThreadNum, final Function ops) {
        assertNotClosed();

        final int executorNumForVirtualThread = 0;

        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(int maxThreadNum, boolean withVirtualThread, final Function ops) {
    //        return sps(maxThreadNum, withVirtualThread ? 1 : 0, ops);
    //    }
    //
    //    @Override
    //    @SuppressWarnings("rawtypes")
    //    public  SS sps(int maxThreadNum, int executorNumForVirtualThread, final Function 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 ops) {
    //        assertNotClosed();
    //
    //        return (SS) ((StreamBase) ops.apply(parallel(ps))).sequential();
    //    }

    /**
     * 
     *
     * @param  
     * @param ops 
     * @return 
     */
    @Override
    @SuppressWarnings("rawtypes")
    public  SS psp(final Function ops) {
        assertNotClosed();

        if (isParallel()) {
            return (SS) ((StreamBase) ops.apply(sequential())).parallel(maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
                    cancelUncompletedThreads());
        } else {
            return (SS) ((StreamBase) ops.apply((S) this)).parallel();
        }
    }

    protected int maxThreadNum() {
        // throw new UnsupportedOperationException();

        // ignore, do nothing if it's sequential stream.
        return 1; //NOSONAR
    }

    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 boolean cancelUncompletedThreads() {
        // throw new UnsupportedOperationException();

        // ignore, do nothing if it's sequential stream.
        return false;
    }

    protected static AsyncExecutor checkAsyncExecutor(AsyncExecutor asyncExecutor, final int threadNum, final int executorNumForVirtualThread) {
        if (executorNumForVirtualThread == 0 || isVirtualThreadSupported == false) {
            if (asyncExecutor == null || asyncExecutor == DEFAULT_ASYNC_EXECUTOR) {
                int activeCount = 0;

                synchronized (DEFAULT_ASYNC_EXECUTOR) {
                    activeCount = activeThreadCounter.get();
                    final boolean canUseDefaultAyncExecutor = CORE_THREAD_POOL_SIZE - activeCount - threadNum > RESERVED_POOL_SIZE;

                    if (canUseDefaultAyncExecutor) {
                        return DEFAULT_ASYNC_EXECUTOR;
                    }
                }

                logActiveThreads(activeCount);

                asyncExecutor = new AsyncExecutor(Executors.newFixedThreadPool(threadNum + 1)); // + 1, just in case.
            }
        } else if (asyncExecutor == null || asyncExecutor == 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();
                    }
                }

                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(AsyncExecutor asyncExecutorToUse, final int maxThreadNum, final int executorNumForVirtualThread, int taskIndex,
            final Runnable cmd) {
        return execute(asyncExecutorToUse, maxThreadNum, executorNumForVirtualThread, taskIndex, Fn.r2c(cmd));
    }

    protected static AsyncExecutor execute(AsyncExecutor asyncExecutorToUse, final int maxThreadNum, final int executorNumForVirtualThread, int taskIndex,
            final Callable cmd) {
        return execute(asyncExecutorToUse, maxThreadNum, executorNumForVirtualThread, taskIndex, null, cmd);
    }

    protected static AsyncExecutor execute(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, 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 = activeThreadCounter.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 isPooledVirtualTheadExecutor = false;

                if (EXECUTOR_MAP_FOR_VIRTUAL_THREAD.size() < MAX_POOLED_EXECUTOR_SIZE_FOR_VIRTUAL_THREAD) {
                    // TODO really need?
                    synchronized (EXECUTOR_MAP_FOR_VIRTUAL_THREAD) {
                        isPooledVirtualTheadExecutor = EXECUTOR_MAP_FOR_VIRTUAL_THREAD.containsKey(executor);
                    }
                } else {
                    isPooledVirtualTheadExecutor = EXECUTOR_MAP_FOR_VIRTUAL_THREAD.containsKey(executor);
                }

                if (isPooledVirtualTheadExecutor) {
                    EXECUTOR_QUEUE_FOR_VIRTUAL_THREAD.offer((ExecutorService) executor); //NOSONAR
                } else if (executor instanceof LocalMultiVirtualThreadExecutor) {
                    ((LocalMultiVirtualThreadExecutor) executor).shutdown();
                } else {
                    asyncExecutorToUse.shutdown();
                }
            } else {
                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;
    }

    //    @Override
    //    public Try tried() {
    //        return Try.of((S) this);
    //    }

    /**
     *
     * Methods defined in this class will only be called sequentially
     *
     */
    @Internal
    static final class LocalMultiVirtualThreadExecutor implements ExecutorService {
        private final MutableInt virtualTheadCouner = 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(Runnable command) {
            final ExecutorService virtualThreadTaskExecutor = getVirtualThreadTaskExecutor();

            virtualThreadTaskExecutor.execute(command);
        }

        @Override
        public  Future submit(Callable task) {
            final ExecutorService virtualThreadTaskExecutor = getVirtualThreadTaskExecutor();

            return virtualThreadTaskExecutor.submit(task);
        }

        @Override
        public Future submit(Runnable task) {
            final ExecutorService virtualThreadTaskExecutor = getVirtualThreadTaskExecutor();

            return virtualThreadTaskExecutor.submit(task);
        }

        @Override
        public  Future submit(Runnable task, T result) {
            final ExecutorService virtualThreadTaskExecutor = getVirtualThreadTaskExecutor();

            return virtualThreadTaskExecutor.submit(task, result);
        }

        private ExecutorService getVirtualThreadTaskExecutor() {
            if (virtualTheadCouner.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(Collection> tasks) throws InterruptedException, UnsupportedOperationException {
            throw new UnsupportedOperationException();
        }

        /**
         * @throws UnsupportedOperationException
         * @deprecated UnsupportedOperationException
         */
        @Deprecated
        @Override
        public  List> invokeAll(Collection> tasks, long timeout, TimeUnit unit)
                throws InterruptedException, UnsupportedOperationException {
            throw new UnsupportedOperationException();
        }

        /**
         * @throws UnsupportedOperationException
         * @deprecated UnsupportedOperationException
         */
        @Deprecated
        @Override
        public  T invokeAny(Collection> tasks) throws InterruptedException, ExecutionException, UnsupportedOperationException {
            throw new UnsupportedOperationException();
        }

        /**
         * @throws UnsupportedOperationException
         * @deprecated UnsupportedOperationException
         */
        @Deprecated
        @Override
        public  T invokeAny(Collection> tasks, long timeout, TimeUnit unit)
                throws InterruptedException, ExecutionException, TimeoutException, UnsupportedOperationException {
            throw new UnsupportedOperationException();
        }

        @Override
        public boolean isShutdown() {
            return isShutDown;
        }

        @Override
        public void shutdown() {
            if (isShutDown) {
                return;
            }

            if (N.notNullOrEmpty(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 (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 (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.notNullOrEmpty(executorServicesToShutdown)) {
                    RuntimeException ex = null;

                    for (ExecutorService executorService : executorServicesToShutdown) {
                        try {
                            executorService.shutdown();
                        } catch (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(long timeout, TimeUnit unit) throws UnsupportedOperationException {
            throw new UnsupportedOperationException();
        }
    }

    /**
     * 
     *
     * @return 
     */
    @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 synchronized void close() {
        if (isClosed) {
            return;
        }

        if (isEmptyCloseHandlers(closeHandlers)) {
            if (N.notNullOrEmpty(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.notNullOrEmpty(closeHandlers)) {
            closeHandlers.clear();
        }
    }

    static void close(final Deque closeHandlers) {
        Exception ex = null;

        for (Runnable closeHandler : closeHandlers) {
            try {
                closeHandler.run();
            } catch (Exception e) {
                if (ex == null) {
                    ex = e;
                } else {
                    ex.addSuppressed(e);
                }
            }
        }

        if (ex != null) {
            throw toRuntimeException(ex);
        }
    }

    static void close(final Collection> iters) {
        Exception ex = null;

        for (IteratorEx iter : iters) {
            try {
                iter.close();
            } catch (Exception e) {
                if (ex == null) {
                    ex = e;
                } else {
                    ex.addSuppressed(e);
                }
            }
        }

        if (ex != null) {
            throw toRuntimeException(ex);
        }
    }

    @SuppressWarnings("rawtypes")
    static void close(Holder holder) {
        if (holder.value() != null) {
            holder.value().close();
        }
    }

    void assertNotClosed() {
        if (isClosed) {
            throw new IllegalStateException("This stream is already terminated.");
        }
    }

    void checkIndex(final int index, final int length) {
        if (index < 0 || index >= length) {
            try {
                N.checkIndex(index, length);
            } finally {
                close();
            }
        }
    }

    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();
            }
        }
    }

    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();
            }
        }
    }

    int checkArgPositive(final int arg, final String argNameOrErrorMsg) {
        if (arg <= 0) {
            try {
                N.checkArgPositive(arg, argNameOrErrorMsg);
            } finally {
                close();
            }
        }

        return arg;
    }

    long checkArgPositive(final long arg, final String argNameOrErrorMsg) {
        if (arg <= 0) {
            try {
                N.checkArgPositive(arg, argNameOrErrorMsg);
            } finally {
                close();
            }
        }

        return arg;
    }

    int checkArgNotNegative(final int arg, final String argNameOrErrorMsg) {
        if (arg < 0) {
            try {
                N.checkArgNotNegative(arg, argNameOrErrorMsg);
            } finally {
                close();
            }
        }

        return arg;
    }

    long checkArgNotNegative(final long arg, final String argNameOrErrorMsg) {
        if (arg < 0) {
            try {
                N.checkArgNotNegative(arg, argNameOrErrorMsg);
            } finally {
                close();
            }
        }

        return arg;
    }

     ARG checkArgNotNull(final ARG obj) {
        if (obj == null) {
            try {
                N.checkArgNotNull(obj);
            } finally {
                close();
            }
        }

        return obj;
    }

     ARG checkArgNotNull(final ARG obj, final String errorMessage) {
        if (obj == null) {
            try {
                N.checkArgNotNull(obj, errorMessage);
            } finally {
                close();
            }
        }

        return obj;
    }

    @SuppressWarnings("rawtypes")
     ARG checkArgNotNullOrEmpty(final ARG obj, final String errorMessage) {
        if (obj == null || obj.size() == 0) {
            try {
                N.checkArgNotNullOrEmpty(obj, errorMessage);
            } finally {
                close();
            }
        }

        return obj;
    }

    void checkArgument(boolean b, String errorMessage) {
        if (!b) {
            try {
                N.checkArgument(b, errorMessage);
            } finally {
                close();
            }
        }
    }

    void checkArgument(boolean b, String errorMessageTemplate, int p1) {
        if (!b) {
            try {
                N.checkArgument(b, errorMessageTemplate, p1);
            } finally {
                close();
            }
        }
    }

    void checkArgument(boolean b, String errorMessageTemplate, long p1) {
        if (!b) {
            try {
                N.checkArgument(b, errorMessageTemplate, p1);
            } finally {
                close();
            }
        }
    }

    void checkArgument(boolean b, String errorMessageTemplate, Object p1) {
        if (!b) {
            try {
                N.checkArgument(b, errorMessageTemplate, p1);
            } finally {
                close();
            }
        }
    }

    void checkArgument(boolean b, String errorMessageTemplate, int p1, int p2) {
        if (!b) {
            try {
                N.checkArgument(b, errorMessageTemplate, p1, p2);
            } finally {
                close();
            }
        }
    }

    void checkArgument(boolean b, String errorMessageTemplate, long p1, long p2) {
        if (!b) {
            try {
                N.checkArgument(b, errorMessageTemplate, p1, p2);
            } finally {
                close();
            }
        }
    }

    void checkArgument(boolean b, String errorMessageTemplate, Object p1, Object p2) {
        if (!b) {
            try {
                N.checkArgument(b, errorMessageTemplate, p1, p2);
            } finally {
                close();
            }
        }
    }

    void checkArgument(boolean b, String errorMessageTemplate, Object p1, Object p2, Object p3) {
        if (!b) {
            try {
                N.checkArgument(b, errorMessageTemplate, p1, p2, p3);
            } finally {
                close();
            }
        }
    }

    void checkState(boolean b) {
        if (!b) {
            try {
                N.checkState(b);
            } finally {
                close();
            }
        }
    }

    void checkState(boolean b, String errorMessage) {
        if (!b) {
            try {
                N.checkState(b, errorMessage);
            } finally {
                close();
            }
        }
    }

    void checkState(boolean b, String errorMessageTemplate, int p1) {
        if (!b) {
            try {
                N.checkState(b, errorMessageTemplate, p1);
            } finally {
                close();
            }
        }
    }

    void checkState(boolean b, String errorMessageTemplate, long p1) {
        if (!b) {
            try {
                N.checkState(b, errorMessageTemplate, p1);
            } finally {
                close();
            }
        }
    }

    void checkState(boolean b, String errorMessageTemplate, Object p1) {
        if (!b) {
            try {
                N.checkState(b, errorMessageTemplate, p1);
            } finally {
                close();
            }
        }
    }

    void checkState(boolean b, String errorMessageTemplate, int p1, int p2) {
        if (!b) {
            try {
                N.checkState(b, errorMessageTemplate, p1, p2);
            } finally {
                close();
            }
        }
    }

    void checkState(boolean b, String errorMessageTemplate, long p1, long p2) {
        if (!b) {
            try {
                N.checkState(b, errorMessageTemplate, p1, p2);
            } finally {
                close();
            }
        }
    }

    void checkState(boolean b, String errorMessageTemplate, Object p1, Object p2) {
        if (!b) {
            try {
                N.checkState(b, errorMessageTemplate, p1, p2);
            } finally {
                close();
            }
        }
    }

    void checkState(boolean b, String errorMessageTemplate, Object p1, Object p2, Object p3) {
        if (!b) {
            try {
                N.checkState(b, errorMessageTemplate, p1, p2, p3);
            } finally {
                close();
            }
        }
    }

    //    void checkRuntimeException(final Holder eHolder, AsyncExecutor specifiedAsyncExecutor, final AsyncExecutor asyncExecutorToUse) {
    //        if (eHolder.value() != null) {
    //            try {
    //                shutdownTempExecutor(specifiedAsyncExecutor, asyncExecutorToUse);
    //            } finally {
    //                close();
    //            }
    //
    //            throwRuntimeException(eHolder);
    //        }
    //    }
    //
    //     void checkException(final Holder eHolder, final E throwableTypeToNotUse, final AsyncExecutor specifiedAsyncExecutor,
    //            final AsyncExecutor asyncExecutorToUse) throws E {
    //        if (eHolder.value() != null) {
    //            try {
    //                shutdownTempExecutor(specifiedAsyncExecutor, asyncExecutorToUse);
    //            } finally {
    //                close();
    //            }
    //
    //            throwException(eHolder, throwableTypeToNotUse);
    //        }
    //    }

    AsyncExecutor createAsyncExecutor(final Executor executor) {
        checkArgNotNull(executor, "executor");

        return new AsyncExecutor(executor);
    }

    protected 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);
        }
    }

    protected 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);
        }
    }

    protected CharStream newStream(final CharIterator iter, final boolean sorted) {
        if (isParallel()) {
            return new ParallelIteratorCharStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
                    cancelUncompletedThreads(), closeHandlers);
        } else {
            return new IteratorCharStream(iter, sorted, closeHandlers);
        }
    }

    protected 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);
        }
    }

    protected 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);
        }
    }

    protected ByteStream newStream(final ByteIterator iter, final boolean sorted) {
        if (isParallel()) {
            return new ParallelIteratorByteStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
                    cancelUncompletedThreads(), closeHandlers);
        } else {
            return new IteratorByteStream(iter, sorted, closeHandlers);
        }
    }

    protected 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);
        }
    }

    protected 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);
        }
    }

    protected ShortStream newStream(final ShortIterator iter, final boolean sorted) {
        if (isParallel()) {
            return new ParallelIteratorShortStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
                    cancelUncompletedThreads(), closeHandlers);
        } else {
            return new IteratorShortStream(iter, sorted, closeHandlers);
        }
    }

    protected 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);
        }
    }

    protected 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);
        }
    }

    protected IntStream newStream(final IntIterator iter, final boolean sorted) {
        if (isParallel()) {
            return new ParallelIteratorIntStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
                    cancelUncompletedThreads(), closeHandlers);
        } else {
            return new IteratorIntStream(iter, sorted, closeHandlers);
        }
    }

    protected 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);
        }
    }

    protected 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);
        }
    }

    protected LongStream newStream(final LongIterator iter, final boolean sorted) {
        if (isParallel()) {
            return new ParallelIteratorLongStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
                    cancelUncompletedThreads(), closeHandlers);
        } else {
            return new IteratorLongStream(iter, sorted, closeHandlers);
        }
    }

    protected 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);
        }
    }

    protected 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);
        }
    }

    protected FloatStream newStream(final FloatIterator iter, final boolean sorted) {
        if (isParallel()) {
            return new ParallelIteratorFloatStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
                    cancelUncompletedThreads(), closeHandlers);
        } else {
            return new IteratorFloatStream(iter, sorted, closeHandlers);
        }
    }

    protected 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);
        }
    }

    protected 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);
        }
    }

    protected DoubleStream newStream(final DoubleIterator iter, final boolean sorted) {
        if (isParallel()) {
            return new ParallelIteratorDoubleStream(iter, sorted, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
                    cancelUncompletedThreads(), closeHandlers);
        } else {
            return new IteratorDoubleStream(iter, sorted, closeHandlers);
        }
    }

    protected  Stream newStream(final E[] a, final boolean sorted, final Comparator comparator) {
        return newStream(a, 0, a.length, sorted, comparator);
    }

    protected  Stream newStream(final E[] a, final int fromIndex, final int toIndex, final boolean sorted, final Comparator 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);
        }
    }

    protected  Stream newStream(final Iterator iter, final boolean sorted, final Comparator comparator) {
        if (isParallel()) {
            return new ParallelIteratorStream<>(iter, sorted, comparator, maxThreadNum(), executorNumForVirtualThread(), splitor(), asyncExecutor(),
                    cancelUncompletedThreads(), closeHandlers);
        } else {
            return new IteratorStream<>(iter, sorted, comparator, closeHandlers);
        }
    }

    protected  Stream newStream(final Stream s, final boolean sorted, final Comparator comparator) {
        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 s) {
        return s == null ? ObjIteratorEx. empty() : (ObjIteratorEx) s.iteratorEx();
    }

    static void setError(final Holder errorHolder, Throwable e) {
        synchronized (errorHolder) { //NOSONAR
            if (errorHolder.value() == null) {
                errorHolder.setValue(e);
            } else {
                errorHolder.value().addSuppressed(e);
            }
        }
    }

    static void setError(final Holder errorHolder, 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();

        synchronized (errorHolder) { //NOSONAR
            if (errorHolder.value() != null) {
                throw toRuntimeException(errorHolder.getAndSet(null), true);
            }
        }
    }

    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
        if (eHolder.value() instanceof Exception) {
            throw (E) eHolder.value();
        } else if (eHolder.value() instanceof Error) {
            throw (Error) eHolder.value();
        } else {
            throw toRuntimeException(eHolder.value());
        }
    }

    static void complete(final List> futureList, final Holder eHolder) {
        if (eHolder.value() != null) {
            throwRuntimeException(eHolder);
        }

        try {
            for (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, E throwableTypeToNotUse)
            throws E {
        if (eHolder.value() != null) {
            throwException(eHolder, throwableTypeToNotUse);
        }

        try {
            for (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 void completeAndShutdownTempExecutor(final List> futureList, final Holder eHolder,
            @SuppressWarnings("rawtypes") final Collection 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 {
                shutdownTempExecutor(asyncExecutorToUse, specifiedAsyncExecutor);
            } finally {
                stream.close();
            }
        }
    }

    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, (RuntimeException) null);
        }

        R container = (R) NONE;

        try {
            for (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 {
                shutdownTempExecutor(asyncExecutorToUse, specifiedAsyncExecutor);
            } finally {
                stream.close();
            }
        }

        if (eHolder.value() != null) {
            throwRuntimeException(eHolder);
        }

        return container == NONE ? supplier.get() : container;
    }

    //    static void decreaseActiveThreadCounterForCancelledFuture(final Collection> futureList) {
    //        if (N.isNullOrEmpty(futureList)) {
    //            return;
    //        }
    //
    //        for (ContinuableFuture future : futureList) {
    //            if (future.isCancelled()) {
    //                activeThreadCounter.decrementAndGet();
    //            }
    //        }
    //    }

    // If this method is uncommented or be called, "execute(final Callable command)" and "execute(final Throwables.Runnable command)" should be modified to handle "cancel"
    //    // TODO really works or speed up???
    //    // TODO the activeThreadCounter/activeThreadDecrement won't be updated if it's cancelled? It has been fixed now - 20220815
    //    static void cancelAll(final List> futureList) {
    //        if (N.isNullOrEmpty(futureList)) {
    //            return;
    //        }
    //
    //        for (ContinuableFuture future : futureList) {
    //            if (!(future.isDone() || future.isAllCancelled())) {
    //                try {
    //                    future.cancelAll(true);
    //                } catch (Throwable e) {
    //                    // ignore
    //                    // e.printStackTrace();
    //                    logger.warn("Error happened during cancel unfinished threads/tasks: " + ExceptionUtil.getErrorMessage(e));
    //                }
    //            }
    //        }
    //    }

    static int calculateBufferedSize(final int len, final int readThreadNum) {
        return N.max(N.min(MAX_BUFFERED_SIZE, len * DEFAULT_BUFFERED_SIZE_PER_ITERATOR), readThreadNum * 2);
    }

    static boolean isSameComparator(Comparator a, Comparator b) {
        if (a == b) {
            return true;
        } else if (a == null) {
            return defaultComparator.containsValue(b);
        } else if (b == null) {
            return defaultComparator.containsValue(a);
        } else {
            return (a == NATURAL_COMPARATOR && defaultComparator.containsValue(b)) || (b == NATURAL_COMPARATOR && defaultComparator.containsValue(a));
        }
    }

    static int toInt(long max) {
        return max > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) max;
    }

    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 Runnable wrapCloseHandlers(final Runnable closeHandler) {
        if (closeHandler == null || closeHandler == EMPTY_CLOSE_HANDLER) {
            return EMPTY_CLOSE_HANDLER;
        }

        return new Runnable() {
            private volatile boolean isClosed = false;

            @Override
            public void run() {
                if (isClosed) {
                    return;
                }

                isClosed = true;
                closeHandler.run();
            }
        };
    }

    static Runnable newCloseHandler(final AutoCloseable closeable) {
        return Fn.closeQuietly(closeable);
    }

    static Runnable newCloseHandler(final StreamBase s) {
        if (s == null || isEmptyCloseHandlers(s.closeHandlers)) {
            return EMPTY_CLOSE_HANDLER;
        }

        return s::close;
    }

    static Runnable 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 (Exception throwable1) {
                    runtimeException = toRuntimeException(throwable1);
                }

                try {
                    b.close();
                } catch (Exception throwable2) {
                    if (runtimeException == null) {
                        runtimeException = toRuntimeException(throwable2);
                    } else {
                        runtimeException.addSuppressed(throwable2);
                    }
                }

                if (runtimeException != null) {
                    throw runtimeException;
                }
            };
        }
    }

    static Runnable newCloseHandler(final Collection> c) {
        if (N.isNullOrEmpty(c)) {
            return EMPTY_CLOSE_HANDLER;
        }

        boolean allEmptyHandlers = true;

        for (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 (StreamBase s : c) {
                if (s == null || s.isClosed || isEmptyCloseHandlers(s.closeHandlers)) {
                    continue;
                }

                try {
                    s.close();
                } catch (Exception throwable) {
                    if (runtimeException == null) {
                        runtimeException = toRuntimeException(throwable);
                    } else {
                        runtimeException.addSuppressed(throwable);
                    }
                }
            }

            if (runtimeException != null) {
                throw runtimeException;
            }
        };
    }

    static Deque mergeCloseHandlers(final StreamBase s, final Deque closeHandlers) {
        return mergeCloseHandlers(s == null ? null : s.closeHandlers, closeHandlers);
    }

    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;
        }

        final Deque newCloseHandlers = new LocalArrayDeque<>();

        if (!isEmptyCloseHandlers(closeHandlersA)) {
            newCloseHandlers.addAll(closeHandlersA);
        }

        if (!isEmptyCloseHandlers(closeHandlersB)) {
            for (Runnable h : closeHandlersB) {
                if (!newCloseHandlers.contains(h)) {
                    newCloseHandlers.add(h);
                }
            }
        }

        return newCloseHandlers;
    }

    static boolean isEmptyCloseHandlers(final Collection closeHandlers) {
        return N.isNullOrEmpty(closeHandlers) || (closeHandlers.size() == 1 && N.firstOrNullIfEmpty(closeHandlers) == EMPTY_CLOSE_HANDLER);
    }

    static Object hashKey(Object obj) {
        return obj == null ? NONE : (obj.getClass().isArray() ? Wrapper.of(obj) : obj);
    }

    static  T[] toArray(Collection c) {
        if (isListElementDataFieldGettable && listElementDataField != null && c.getClass().equals(ArrayList.class)) {
            try {
                return (T[]) listElementDataField.get(c);
            } catch (Throwable e) {
                // ignore;
                isListElementDataFieldGettable = false;
            }
        }

        return (T[]) c.toArray();
    }

    @SafeVarargs
    static  List createList(final T... a) {
        if (N.isNullOrEmpty(a)) {
            return new ArrayList<>();
        }

        return N.asList(a);
    }

    static long sum(final char[] a) {
        if (a == null || a.length == 0) {
            return 0;
        }

        return sum(a, 0, a.length);
    }

    static long sum(final char[] a, final int fromIndex, final int toIndex) {
        long sum = 0;

        for (int i = fromIndex; i < toIndex; i++) {
            sum += a[i];
        }

        return sum;
    }

    static long sum(final byte[] a) {
        if (a == null || a.length == 0) {
            return 0;
        }

        return sum(a, 0, a.length);
    }

    static long sum(final byte[] a, final int fromIndex, final int toIndex) {
        long sum = 0;

        for (int i = fromIndex; i < toIndex; i++) {
            sum += a[i];
        }

        return sum;
    }

    static long sum(final short[] a) {
        if (a == null || a.length == 0) {
            return 0;
        }

        return sum(a, 0, a.length);
    }

    static long sum(final short[] a, final int fromIndex, final int toIndex) {
        long sum = 0;

        for (int i = fromIndex; i < toIndex; i++) {
            sum += a[i];
        }

        return sum;
    }

    static long sum(final int[] a) {
        if (a == null || a.length == 0) {
            return 0;
        }

        return sum(a, 0, a.length);
    }

    static long sum(final int[] a, final int fromIndex, final int toIndex) {
        long sum = 0;

        for (int i = fromIndex; i < toIndex; i++) {
            sum += a[i];
        }

        return 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) {
        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) {
        return DoubleStream.of(a, fromIndex, toIndex).sum();
    }

    static RuntimeException toRuntimeException(final Exception e) {
        return ExceptionUtil.toRuntimeException(e);
    }

    static RuntimeException toRuntimeException(final Throwable e) {
        return ExceptionUtil.toRuntimeException(e);
    }

    static RuntimeException toRuntimeException(final Throwable e, final boolean throwIfItIsError) {
        return ExceptionUtil.toRuntimeException(e, throwIfItIsError);
    }

    @Internal
    static final class LocalArrayDeque extends ArrayDeque {
        private static final long serialVersionUID = -97425473105100734L;

        public LocalArrayDeque() {
        }

        public LocalArrayDeque(int initialCapacity) {
            super(initialCapacity);
        }

        public LocalArrayDeque(Collection c) {
            super(c);
        }
    }

    //    /**
    //     * Returns {@code min(cpu_cores * 16, 256)}
    //     *
    //     * @return
    //     */
    //    @Beta
    //    public static int maxThreadNumPerOperation() {
    //        return MAX_THREAD_NUM_PER_OPERATION;
    //    }
}