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

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

There is a newer version: 1.10.1
Show newest version
/*
 * Copyright (C) 2016 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.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;

import com.landawn.abacus.util.Fn;
import com.landawn.abacus.util.IndexedShort;
import com.landawn.abacus.util.Joiner;
import com.landawn.abacus.util.Multiset;
import com.landawn.abacus.util.MutableLong;
import com.landawn.abacus.util.MutableShort;
import com.landawn.abacus.util.N;
import com.landawn.abacus.util.Nth;
import com.landawn.abacus.util.Optional;
import com.landawn.abacus.util.OptionalShort;
import com.landawn.abacus.util.Pair;
import com.landawn.abacus.util.Percentage;
import com.landawn.abacus.util.ShortIterator;
import com.landawn.abacus.util.ShortList;
import com.landawn.abacus.util.ShortMatrix;
import com.landawn.abacus.util.ShortSummaryStatistics;
import com.landawn.abacus.util.Try;
import com.landawn.abacus.util.function.BiConsumer;
import com.landawn.abacus.util.function.BiPredicate;
import com.landawn.abacus.util.function.BinaryOperator;
import com.landawn.abacus.util.function.Consumer;
import com.landawn.abacus.util.function.Function;
import com.landawn.abacus.util.function.ObjShortConsumer;
import com.landawn.abacus.util.function.Predicate;
import com.landawn.abacus.util.function.ShortBiFunction;
import com.landawn.abacus.util.function.ShortBiPredicate;
import com.landawn.abacus.util.function.ShortConsumer;
import com.landawn.abacus.util.function.ShortFunction;
import com.landawn.abacus.util.function.ShortPredicate;
import com.landawn.abacus.util.function.ShortTriFunction;
import com.landawn.abacus.util.function.Supplier;
import com.landawn.abacus.util.function.ToShortFunction;

/**
 * This class is a sequential, stateful and immutable stream implementation.
 *
 * @since 0.8
 * 
 * @author Haiyang Li
 */
abstract class AbstractShortStream extends ShortStream {

    AbstractShortStream(final boolean sorted, final Collection closeHandlers) {
        super(sorted, closeHandlers);
    }

    @Override
    public ShortStream flattMap(final ShortFunction mapper) {
        return flatMap(new ShortFunction() {
            @Override
            public ShortStream apply(short t) {
                return ShortStream.of(mapper.apply(t));
            }
        });
    }

    @Override
    public  Stream flattMapToObj(final ShortFunction> mapper) {
        return flatMapToObj(new ShortFunction>() {
            @Override
            public Stream apply(short t) {
                return Stream.of(mapper.apply(t));
            }
        });
    }

    @Override
    public ShortStream skip(final long n, final ShortConsumer action) {
        N.checkArgNotNegative(n, "n");

        if (n == 0) {
            return this;
        }

        final ShortPredicate filter = isParallel() ? new ShortPredicate() {
            final AtomicLong cnt = new AtomicLong(n);

            @Override
            public boolean test(short value) {
                return cnt.getAndDecrement() > 0;
            }
        } : new ShortPredicate() {
            final MutableLong cnt = MutableLong.of(n);

            @Override
            public boolean test(short value) {
                return cnt.getAndDecrement() > 0;
            }
        };

        return dropWhile(filter, action);
    }

    @Override
    public ShortStream removeIf(final ShortPredicate predicate) {
        N.checkArgNotNull(predicate);

        return filter(new ShortPredicate() {
            @Override
            public boolean test(short value) {
                return predicate.test(value) == false;
            }
        });
    }

    @Override
    public ShortStream removeIf(final ShortPredicate predicate, final ShortConsumer action) {
        N.checkArgNotNull(predicate);
        N.checkArgNotNull(predicate);

        return filter(new ShortPredicate() {
            @Override
            public boolean test(short value) {
                if (predicate.test(value)) {
                    action.accept(value);
                    return false;
                }

                return true;
            }
        });
    }

    @Override
    public ShortStream dropWhile(final ShortPredicate predicate, final ShortConsumer action) {
        N.checkArgNotNull(predicate);
        N.checkArgNotNull(action);

        return dropWhile(new ShortPredicate() {
            @Override
            public boolean test(short value) {
                if (predicate.test(value)) {
                    action.accept(value);
                    return true;
                }

                return false;
            }
        });
    }

    @Override
    public ShortStream step(final long step) {
        N.checkArgPositive(step, "step");

        if (step == 1) {
            return this;
        }

        final long skip = step - 1;
        final ShortIteratorEx iter = this.iteratorEx();

        final ShortIterator shortIterator = new ShortIteratorEx() {
            @Override
            public boolean hasNext() {
                return iter.hasNext();
            }

            @Override
            public short nextShort() {
                final short next = iter.nextShort();
                iter.skip(skip);
                return next;
            }
        };

        return newStream(shortIterator, sorted);
    }

    @Override
    public Stream split(final int size) {
        return splitToList(size).map(new Function() {
            @Override
            public ShortStream apply(ShortList t) {
                return new ArrayShortStream(t.array(), 0, t.size(), sorted, null);
            }
        });
    }

    @Override
    public Stream split(final ShortPredicate predicate) {
        return splitToList(predicate).map(new Function() {
            @Override
            public ShortStream apply(ShortList t) {
                return new ArrayShortStream(t.array(), 0, t.size(), sorted, null);
            }
        });
    }

    @Override
    public Stream splitToList(final ShortPredicate predicate) {
        final BiPredicate predicate2 = new BiPredicate() {

            @Override
            public boolean test(Short t, Object u) {
                return predicate.test(t);
            }
        };

        return splitToList(null, predicate2, null);
    }

    @Override
    public  Stream split(final U seed, final BiPredicate predicate, final Consumer seedUpdate) {
        return splitToList(seed, predicate, seedUpdate).map(new Function() {
            @Override
            public ShortStream apply(ShortList t) {
                return new ArrayShortStream(t.array(), 0, t.size(), sorted, null);
            }
        });
    }

    @Override
    public Stream sliding(final int windowSize, final int increment) {
        return slidingToList(windowSize, increment).map(new Function() {
            @Override
            public ShortStream apply(ShortList t) {
                return new ArrayShortStream(t.array(), 0, t.size(), sorted, null);
            }
        });
    }

    @Override
    public ShortStream collapse(final ShortBiPredicate collapsible, final ShortBiFunction mergeFunction) {
        final ShortIteratorEx iter = iteratorEx();

        return newStream(new ShortIteratorEx() {
            private boolean hasNext = false;
            private short next = 0;

            @Override
            public boolean hasNext() {
                return hasNext || iter.hasNext();
            }

            @Override
            public short nextShort() {
                short res = hasNext ? next : (next = iter.nextShort());

                while ((hasNext = iter.hasNext())) {
                    if (collapsible.test(next, (next = iter.nextShort()))) {
                        res = mergeFunction.apply(res, next);
                    } else {
                        break;
                    }
                }

                return res;
            }
        }, false);
    }

    @Override
    public ShortStream scan(final ShortBiFunction accumulator) {
        final ShortIteratorEx iter = iteratorEx();

        return newStream(new ShortIteratorEx() {
            private short res = 0;
            private boolean isFirst = true;

            @Override
            public boolean hasNext() {
                return iter.hasNext();
            }

            @Override
            public short nextShort() {
                if (isFirst) {
                    isFirst = false;
                    return (res = iter.nextShort());
                } else {
                    return (res = accumulator.apply(res, iter.nextShort()));
                }
            }
        }, false);
    }

    @Override
    public ShortStream scan(final short seed, final ShortBiFunction accumulator) {
        final ShortIteratorEx iter = iteratorEx();

        return newStream(new ShortIteratorEx() {
            private short res = seed;

            @Override
            public boolean hasNext() {
                return iter.hasNext();
            }

            @Override
            public short nextShort() {
                return (res = accumulator.apply(res, iter.nextShort()));
            }
        }, false);
    }

    @Override
    public  Map toMap(ShortFunction keyExtractor, ShortFunction valueMapper) {
        final Supplier> mapFactory = Fn.Suppliers.ofMap();

        return toMap(keyExtractor, valueMapper, mapFactory);
    }

    @Override
    public > M toMap(ShortFunction keyExtractor, ShortFunction valueMapper, Supplier mapFactory) {
        final BinaryOperator mergeFunction = Fn.throwingMerger();

        return toMap(keyExtractor, valueMapper, mergeFunction, mapFactory);
    }

    @Override
    public  Map toMap(ShortFunction keyExtractor, ShortFunction valueMapper, BinaryOperator mergeFunction) {
        final Supplier> mapFactory = Fn.Suppliers.ofMap();

        return toMap(keyExtractor, valueMapper, mergeFunction, mapFactory);
    }

    @Override
    public  Map toMap(ShortFunction classifier, Collector downstream) {
        final Supplier> mapFactory = Fn.Suppliers.ofMap();

        return toMap(classifier, downstream, mapFactory);
    }

    @Override
    public ShortMatrix toMatrix() {
        return ShortMatrix.of(toArray());
    }

    @Override
    public ShortStream distinct() {
        final Set set = new HashSet<>();

        return newStream(this.sequential().filter(new ShortPredicate() {
            @Override
            public boolean test(short value) {
                return set.add(value);
            }
        }).iteratorEx(), sorted);
    }

    @Override
    public ShortStream top(int n) {
        return top(n, SHORT_COMPARATOR);
    }

    @Override
    public OptionalShort first() {
        final ShortIterator iter = this.iteratorEx();

        return iter.hasNext() ? OptionalShort.of(iter.nextShort()) : OptionalShort.empty();
    }

    @Override
    public OptionalShort last() {
        final ShortIterator iter = this.iteratorEx();

        if (iter.hasNext() == false) {
            return OptionalShort.empty();
        }

        short next = iter.nextShort();

        while (iter.hasNext()) {
            next = iter.nextShort();
        }

        return OptionalShort.of(next);
    }

    @Override
    public  OptionalShort findAny(final Try.ShortPredicate predicate) throws E {
        return findFirst(predicate);
    }

    @Override
    public  OptionalShort findFirstOrLast(Try.ShortPredicate predicateForFirst,
            Try.ShortPredicate predicateForLast) throws E, E2 {
        final ShortIteratorEx iter = iteratorEx();
        MutableShort last = null;
        short next = 0;

        while (iter.hasNext()) {
            next = iter.nextShort();

            if (predicateForFirst.test(next)) {
                return OptionalShort.of(next);
            } else if (predicateForLast.test(next)) {
                if (last == null) {
                    last = MutableShort.of(next);
                } else {
                    last.setValue(next);
                }
            }
        }

        return last == null ? OptionalShort.empty() : OptionalShort.of(last.value());
    }

    @Override
    public ShortStream intersection(final Collection c) {
        final Multiset multiset = Multiset.from(c);

        return newStream(this.sequential().filter(new ShortPredicate() {
            @Override
            public boolean test(short value) {
                return multiset.getAndRemove(value) > 0;
            }
        }).iteratorEx(), sorted);
    }

    @Override
    public ShortStream difference(final Collection c) {
        final Multiset multiset = Multiset.from(c);

        return newStream(this.sequential().filter(new ShortPredicate() {
            @Override
            public boolean test(short value) {
                return multiset.getAndRemove(value) < 1;
            }
        }).iteratorEx(), sorted);
    }

    @Override
    public ShortStream symmetricDifference(final Collection c) {
        final Multiset multiset = Multiset.from(c);

        return newStream(this.sequential().filter(new ShortPredicate() {
            @Override
            public boolean test(short value) {
                return multiset.getAndRemove(value) < 1;
            }
        }).append(Stream.of(c).filter(new Predicate() {
            @Override
            public boolean test(Short value) {
                return multiset.getAndRemove(value) > 0;
            }
        }).mapToShort(ToShortFunction.UNBOX)).iteratorEx(), false);
    }

    @Override
    public Stream splitAt(final int n) {
        N.checkArgNotNegative(n, "n");

        return newStream(new ObjIteratorEx() {
            private ShortStream[] a = null;
            private int cursor = 0;

            @Override
            public boolean hasNext() {
                init();

                return cursor < 2;
            }

            @Override
            public ShortStream next() {
                if (hasNext() == false) {
                    throw new NoSuchElementException();
                }

                return a[cursor++];
            }

            private void init() {
                if (a == null) {
                    final ShortIterator iter = AbstractShortStream.this.iteratorEx();
                    final ShortList list = new ShortList();

                    while (list.size() < n && iter.hasNext()) {
                        list.add(iter.nextShort());
                    }

                    a = new ShortStream[] { new ArrayShortStream(list.array(), 0, list.size(), sorted, null), new IteratorShortStream(iter, sorted, null) };
                }
            }

        }, false, null);
    }

    @Override
    public Stream splitBy(final ShortPredicate where) {
        N.checkArgNotNull(where);

        return newStream(new ObjIteratorEx() {
            private ShortStream[] a = null;
            private int cursor = 0;

            @Override
            public boolean hasNext() {
                init();

                return cursor < 2;
            }

            @Override
            public ShortStream next() {
                if (hasNext() == false) {
                    throw new NoSuchElementException();
                }

                return a[cursor++];
            }

            private void init() {
                if (a == null) {
                    final ShortIterator iter = AbstractShortStream.this.iteratorEx();
                    final ShortList list = new ShortList();
                    short next = 0;
                    ShortStream s = null;

                    while (iter.hasNext()) {
                        next = iter.nextShort();

                        if (where.test(next)) {
                            list.add(next);
                        } else {
                            s = ShortStream.of(next);

                            break;
                        }
                    }

                    a = new ShortStream[] { new ArrayShortStream(list.array(), 0, list.size(), sorted, null), new IteratorShortStream(iter, sorted, null) };

                    if (s != null) {
                        if (sorted) {
                            a[1] = new IteratorShortStream(a[1].prepend(s).iteratorEx(), sorted, null);
                        } else {
                            a[1] = a[1].prepend(s);
                        }
                    }
                }
            }

        }, false, null);
    }

    @Override
    public ShortStream reversed() {
        return newStream(new ShortIteratorEx() {
            private boolean initialized = false;
            private short[] aar;
            private int cursor;

            @Override
            public boolean hasNext() {
                if (initialized == false) {
                    init();
                }

                return cursor > 0;
            }

            @Override
            public short nextShort() {
                if (initialized == false) {
                    init();
                }

                if (cursor <= 0) {
                    throw new NoSuchElementException();
                }

                return aar[--cursor];
            }

            @Override
            public long count() {
                if (initialized == false) {
                    init();
                }

                return cursor;
            }

            @Override
            public void skip(long n) {
                if (initialized == false) {
                    init();
                }

                cursor = n < cursor ? cursor - (int) n : 0;
            }

            @Override
            public short[] toArray() {
                if (initialized == false) {
                    init();
                }

                final short[] a = new short[cursor];

                for (int i = 0; i < cursor; i++) {
                    a[i] = aar[cursor - i - 1];
                }

                return a;
            }

            private void init() {
                if (initialized == false) {
                    initialized = true;
                    aar = AbstractShortStream.this.toArray();
                    cursor = aar.length;
                }
            }
        }, false);
    }

    @Override
    public ShortStream shuffled(final Random rnd) {
        return lazyLoad(new Function() {
            @Override
            public short[] apply(final short[] a) {
                N.shuffle(a, rnd);
                return a;
            }
        }, false);
    }

    @Override
    public ShortStream rotated(final int distance) {
        return newStream(new ShortIteratorEx() {
            private boolean initialized = false;
            private short[] aar;
            private int len;
            private int start;
            private int cnt = 0;

            @Override
            public boolean hasNext() {
                if (initialized == false) {
                    init();
                }

                return cnt < len;
            }

            @Override
            public short nextShort() {
                if (hasNext() == false) {
                    throw new NoSuchElementException();
                }

                return aar[(start + cnt++) % len];
            }

            @Override
            public long count() {
                if (initialized == false) {
                    init();
                }

                return len - cnt;
            }

            @Override
            public void skip(long n) {
                if (initialized == false) {
                    init();
                }

                cnt = n < len - cnt ? cnt + (int) n : len;
            }

            @Override
            public short[] toArray() {
                if (initialized == false) {
                    init();
                }

                final short[] a = new short[len - cnt];

                for (int i = cnt; i < len; i++) {
                    a[i - cnt] = aar[(start + i) % len];
                }

                return a;
            }

            private void init() {
                if (initialized == false) {
                    initialized = true;
                    aar = AbstractShortStream.this.toArray();
                    len = aar.length;

                    if (len > 0) {
                        start = distance % len;

                        if (start < 0) {
                            start += len;
                        }

                        start = len - start;
                    }
                }
            }
        }, distance == 0 && sorted);
    }

    @Override
    public ShortStream sorted() {
        if (sorted) {
            return this;
        }

        return lazyLoad(new Function() {
            @Override
            public short[] apply(final short[] a) {
                if (isParallel()) {
                    N.parallelSort(a);
                } else {
                    N.sort(a);
                }

                return a;
            }
        }, true);
    }

    @Override
    public ShortStream reverseSorted() {
        return newStream(new ShortIteratorEx() {
            private boolean initialized = false;
            private short[] aar;
            private int cursor;

            @Override
            public boolean hasNext() {
                if (initialized == false) {
                    init();
                }

                return cursor > 0;
            }

            @Override
            public short nextShort() {
                if (initialized == false) {
                    init();
                }

                if (cursor <= 0) {
                    throw new NoSuchElementException();
                }

                return aar[--cursor];
            }

            @Override
            public long count() {
                if (initialized == false) {
                    init();
                }

                return cursor;
            }

            @Override
            public void skip(long n) {
                if (initialized == false) {
                    init();
                }

                cursor = n < cursor ? cursor - (int) n : 0;
            }

            @Override
            public short[] toArray() {
                if (initialized == false) {
                    init();
                }

                final short[] a = new short[cursor];

                for (int i = 0; i < cursor; i++) {
                    a[i] = aar[cursor - i - 1];
                }

                return a;
            }

            private void init() {
                if (initialized == false) {
                    initialized = true;
                    aar = AbstractShortStream.this.toArray();

                    if (isParallel()) {
                        N.parallelSort(aar);
                    } else {
                        N.sort(aar);
                    }

                    cursor = aar.length;
                }
            }
        }, false);
    }

    private ShortStream lazyLoad(final Function op, final boolean sorted) {
        return newStream(new ShortIteratorEx() {
            private boolean initialized = false;
            private short[] aar;
            private int cursor = 0;
            private int len;

            @Override
            public boolean hasNext() {
                if (initialized == false) {
                    init();
                }

                return cursor < len;
            }

            @Override
            public short nextShort() {
                if (initialized == false) {
                    init();
                }

                if (cursor >= len) {
                    throw new NoSuchElementException();
                }

                return aar[cursor++];
            }

            @Override
            public long count() {
                if (initialized == false) {
                    init();
                }

                return len - cursor;
            }

            @Override
            public void skip(long n) {
                if (initialized == false) {
                    init();
                }

                cursor = n > len - cursor ? len : cursor + (int) n;
            }

            @Override
            public short[] toArray() {
                if (initialized == false) {
                    init();
                }

                final short[] a = new short[len - cursor];

                for (int i = cursor; i < len; i++) {
                    a[i - cursor] = aar[i];
                }

                return a;
            }

            private void init() {
                if (initialized == false) {
                    initialized = true;
                    aar = op.apply(AbstractShortStream.this.toArray());
                    len = aar.length;
                }
            }
        }, sorted);
    }

    @Override
    public Optional> percentiles() {
        final short[] a = sorted().toArray();

        if (a.length == 0) {
            return Optional.empty();
        }

        return Optional.of(N.percentiles(a));
    }

    @Override
    public Pair>> summarizze() {
        final short[] a = sorted().toArray();

        if (N.isNullOrEmpty(a)) {
            return Pair.of(new ShortSummaryStatistics(), Optional.> empty());
        } else {
            return Pair.of(new ShortSummaryStatistics(a.length, sum(a), a[0], a[a.length - 1]), Optional.of(N.percentiles(a)));
        }
    }

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

    @Override
    public String join(final CharSequence delimiter, final CharSequence prefix, final CharSequence suffix) {
        final Joiner joiner = Joiner.with(delimiter, prefix, suffix).reuseStringBuilder(true);
        final ShortIteratorEx iter = this.iteratorEx();

        while (iter.hasNext()) {
            joiner.append(iter.nextShort());
        }

        return joiner.toString();
    }

    @Override
    public  R collect(Supplier supplier, ObjShortConsumer accumulator) {
        final BiConsumer combiner = collectingCombiner;

        return collect(supplier, accumulator, combiner);
    }

    @Override
    public Pair headAndTail() {
        return Pair.of(head(), tail());
    }

    //    @SuppressWarnings("deprecation")
    //    @Override
    //    public Pair headAndTaill() {
    //        return Pair.of(headd(), taill());
    //    }

    @Override
    public Stream indexed() {
        return newStream(this.sequential().mapToObj(new ShortFunction() {
            final MutableLong idx = MutableLong.of(0);

            @Override
            public IndexedShort apply(short t) {
                return IndexedShort.of(t, idx.getAndIncrement());
            }
        }).iterator(), true, INDEXED_SHORT_COMPARATOR);
    }

    @Override
    public ShortStream append(ShortStream stream) {
        return ShortStream.concat(this, stream);
    }

    @Override
    public ShortStream prepend(ShortStream stream) {
        return ShortStream.concat(stream, this);
    }

    @Override
    public ShortStream merge(ShortStream b, ShortBiFunction nextSelector) {
        return ShortStream.merge(this, b, nextSelector);
    }

    @Override
    public ShortStream zipWith(ShortStream b, ShortBiFunction zipFunction) {
        return ShortStream.zip(this, b, zipFunction);
    }

    @Override
    public ShortStream zipWith(ShortStream b, ShortStream c, ShortTriFunction zipFunction) {
        return ShortStream.zip(this, b, c, zipFunction);
    }

    @Override
    public ShortStream zipWith(ShortStream b, short valueForNoneA, short valueForNoneB, ShortBiFunction zipFunction) {
        return ShortStream.zip(this, b, valueForNoneA, valueForNoneB, zipFunction);
    }

    @Override
    public ShortStream zipWith(ShortStream b, ShortStream c, short valueForNoneA, short valueForNoneB, short valueForNoneC,
            ShortTriFunction zipFunction) {
        return ShortStream.zip(this, b, c, valueForNoneA, valueForNoneB, valueForNoneC, zipFunction);
    }

    @Override
    public ShortStream cached() {
        return newStream(toArray(), sorted);
    }
}