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

com.landawn.abacus.util.TriIterator 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) 2018, 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;

import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.function.BiConsumer;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;

import com.landawn.abacus.util.Fn.Suppliers;
import com.landawn.abacus.util.u.Optional;
import com.landawn.abacus.util.function.IndexedConsumer;
import com.landawn.abacus.util.function.TriFunction;
import com.landawn.abacus.util.function.TriPredicate;
import com.landawn.abacus.util.stream.Stream;

/**
 *
 * @author Haiyang Li
 * @param 
 * @param 
 * @param 
 * @since 1.2.10
 */
public abstract class TriIterator extends ImmutableIterator> {

    @SuppressWarnings("rawtypes")
    private static final TriIterator EMPTY = new TriIterator() {
        @Override
        public boolean hasNext() {
            return false;
        }

        @Override
        public Object next() {
            throw new NoSuchElementException();
        }

        @Override
        protected void next(Throwables.TriConsumer action) throws NoSuchElementException {
            throw new NoSuchElementException();
        }

        @Override
        public void forEachRemaining(Throwables.TriConsumer action) throws Exception {
            N.checkArgNotNull(action);
        }

        @Override
        public ObjIterator map(TriFunction mapper) {
            N.checkArgNotNull(mapper);

            return ObjIterator.empty();
        }
    };

    /**
     *
     * @param 
     * @param 
     * @param 
     * @return
     */
    public static  TriIterator empty() {
        return EMPTY;
    }

    /**
     * Returns an infinite {@code BiIterator}.
     *
     * @param 
     * @param 
     * @param 
     * @param output transfer the next values.
     * @return
     */
    public static  TriIterator generate(final Consumer> output) {
        return generate(com.landawn.abacus.util.function.BooleanSupplier.TRUE, output);
    }

    /**
     *
     * @param 
     * @param 
     * @param 
     * @param hasNext
     * @param output
     * @return
     */
    public static  TriIterator generate(final BooleanSupplier hasNext, final Consumer> output) {
        N.checkArgNotNull(hasNext);
        N.checkArgNotNull(output);

        return new TriIterator<>() {
            private final Triple tmp = new Triple<>();

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

            @Override
            public Triple next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                output.accept(tmp);

                return Triple.of(tmp.left, tmp.middle, tmp.right);
            }

            @Override
            protected  void next(final Throwables.TriConsumer action)
                    throws NoSuchElementException, E {
                // N.checkArgNotNull(action);

                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                output.accept(tmp);

                action.accept(tmp.left, tmp.middle, tmp.right);
            }

            @Override
            public  void forEachRemaining(final Throwables.TriConsumer action) throws E {
                N.checkArgNotNull(action);

                while (hasNext.getAsBoolean()) {
                    output.accept(tmp);

                    action.accept(tmp.left, tmp.middle, tmp.right);
                }
            }

            @Override
            public  ObjIterator map(final TriFunction mapper) {
                N.checkArgNotNull(mapper);

                return new ObjIterator<>() {
                    @Override
                    public boolean hasNext() {
                        return hasNext.getAsBoolean();
                    }

                    @Override
                    public R next() {
                        if (!hasNext()) {
                            throw new NoSuchElementException();
                        }

                        output.accept(tmp);

                        return mapper.apply(tmp.left, tmp.middle, tmp.right);
                    }
                };
            }
        };
    }

    /**
     *
     * @param 
     * @param 
     * @param 
     * @param fromIndex
     * @param toIndex
     * @param output
     * @return
     */
    public static  TriIterator generate(final int fromIndex, final int toIndex, final IndexedConsumer> output) {
        N.checkFromToIndex(fromIndex, toIndex, Integer.MAX_VALUE);
        N.checkArgNotNull(output);

        return new TriIterator<>() {
            private final MutableInt cursor = MutableInt.of(fromIndex);
            private final Triple tmp = new Triple<>();

            @Override
            public boolean hasNext() {
                return cursor.value() < toIndex;
            }

            @Override
            public Triple next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                output.accept(cursor.getAndIncrement(), tmp);

                return Triple.of(tmp.left, tmp.middle, tmp.right);
            }

            @Override
            protected  void next(final Throwables.TriConsumer action)
                    throws NoSuchElementException, E {
                // N.checkArgNotNull(action);

                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                output.accept(cursor.getAndIncrement(), tmp);

                action.accept(tmp.left, tmp.middle, tmp.right);
            }

            @Override
            public  void forEachRemaining(final Throwables.TriConsumer action) throws E {
                N.checkArgNotNull(action);

                while (cursor.value() < toIndex) {
                    output.accept(cursor.getAndIncrement(), tmp);

                    action.accept(tmp.left, tmp.middle, tmp.right);
                }
            }

            @Override
            public  ObjIterator map(final TriFunction mapper) {
                N.checkArgNotNull(mapper);

                return new ObjIterator<>() {
                    @Override
                    public boolean hasNext() {
                        return cursor.value() < toIndex;
                    }

                    @Override
                    public R next() {
                        if (!hasNext()) {
                            throw new NoSuchElementException();
                        }

                        output.accept(cursor.getAndIncrement(), tmp);

                        return mapper.apply(tmp.left, tmp.middle, tmp.right);
                    }
                };
            }
        };
    }

    /**
     *
     * @param 
     * @param 
     * @param 
     * @param a
     * @param b
     * @param c
     * @return
     */
    public static  TriIterator zip(final A[] a, final B[] b, final C[] c) {
        return zip(Array.asList(a), Array.asList(b), Array.asList(c));
    }

    /**
     *
     * @param 
     * @param 
     * @param 
     * @param a
     * @param b
     * @param c
     * @param valueForNoneA
     * @param valueForNoneB
     * @param valueForNoneC
     * @return
     */
    public static  TriIterator zip(final A[] a, final B[] b, final C[] c, final A valueForNoneA, final B valueForNoneB,
            final C valueForNoneC) {
        return zip(Array.asList(a), Array.asList(b), Array.asList(c), valueForNoneA, valueForNoneB, valueForNoneC);
    }

    /**
     *
     * @param 
     * @param 
     * @param 
     * @param a
     * @param b
     * @param c
     * @return
     */
    public static  TriIterator zip(final Iterable a, final Iterable b, final Iterable c) {
        return zip(a == null ? null : a.iterator(), b == null ? null : b.iterator(), c == null ? null : c.iterator());
    }

    /**
     *
     * @param 
     * @param 
     * @param 
     * @param a
     * @param b
     * @param c
     * @param valueForNoneA
     * @param valueForNoneB
     * @param valueForNoneC
     * @return
     */
    public static  TriIterator zip(final Iterable a, final Iterable b, final Iterable c, final A valueForNoneA,
            final B valueForNoneB, final C valueForNoneC) {
        return zip(a == null ? null : a.iterator(), b == null ? null : b.iterator(), c == null ? null : c.iterator(), valueForNoneA, valueForNoneB,
                valueForNoneC);
    }

    /**
     *
     * @param 
     * @param 
     * @param 
     * @param iterA
     * @param iterB
     * @param iterC
     * @return
     */
    public static  TriIterator zip(final Iterator iterA, final Iterator iterB, final Iterator iterC) {
        if (iterA == null || iterB == null || iterC == null) {
            return empty();
        }

        return new TriIterator<>() {
            @Override
            public boolean hasNext() {
                return iterA.hasNext() && iterB.hasNext() && iterC.hasNext();
            }

            @Override
            public Triple next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                return Triple.of(iterA.next(), iterB.next(), iterC.next());
            }

            @Override
            protected  void next(final Throwables.TriConsumer action)
                    throws NoSuchElementException, E {
                // N.checkArgNotNull(action);

                action.accept(iterA.next(), iterB.next(), iterC.next());
            }

            @Override
            public  void forEachRemaining(final Throwables.TriConsumer action) throws E {
                N.checkArgNotNull(action);

                while (iterA.hasNext() && iterB.hasNext() && iterC.hasNext()) {
                    action.accept(iterA.next(), iterB.next(), iterC.next());
                }
            }

            @Override
            public  ObjIterator map(final TriFunction mapper) {
                N.checkArgNotNull(mapper);

                return new ObjIterator<>() {
                    @Override
                    public boolean hasNext() {
                        return iterA.hasNext() && iterB.hasNext() && iterC.hasNext();
                    }

                    @Override
                    public R next() {
                        if (!hasNext()) {
                            throw new NoSuchElementException();
                        }

                        return mapper.apply(iterA.next(), iterB.next(), iterC.next());
                    }
                };
            }
        };
    }

    /**
     *
     * @param 
     * @param 
     * @param 
     * @param iterA
     * @param iterB
     * @param iterC
     * @param valueForNoneA
     * @param valueForNoneB
     * @param valueForNoneC
     * @return
     */
    public static  TriIterator zip(final Iterator iterA, final Iterator iterB, final Iterator iterC, final A valueForNoneA,
            final B valueForNoneB, final C valueForNoneC) {
        final Iterator iter1 = iterA == null ? ObjIterator. empty() : iterA;
        final Iterator iter2 = iterB == null ? ObjIterator. empty() : iterB;
        final Iterator iter3 = iterC == null ? ObjIterator. empty() : iterC;

        return new TriIterator<>() {
            @Override
            public boolean hasNext() {
                return iter1.hasNext() || iter2.hasNext() || iter3.hasNext();
            }

            @Override
            public Triple next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                return Triple.of(iter1.hasNext() ? iter1.next() : valueForNoneA, iter2.hasNext() ? iter2.next() : valueForNoneB,
                        iter3.hasNext() ? iter3.next() : valueForNoneC);
            }

            @Override
            protected  void next(final Throwables.TriConsumer action)
                    throws NoSuchElementException, E {
                // N.checkArgNotNull(action);

                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                action.accept(iter1.hasNext() ? iter1.next() : valueForNoneA, iter2.hasNext() ? iter2.next() : valueForNoneB,
                        iter3.hasNext() ? iter3.next() : valueForNoneC);
            }

            @Override
            public  void forEachRemaining(final Throwables.TriConsumer action) throws E {
                N.checkArgNotNull(action);

                while (iter1.hasNext() || iter2.hasNext() || iter3.hasNext()) {
                    action.accept(iter1.hasNext() ? iter1.next() : valueForNoneA, iter2.hasNext() ? iter2.next() : valueForNoneB,
                            iter3.hasNext() ? iter3.next() : valueForNoneC);
                }
            }

            @Override
            public  ObjIterator map(final TriFunction mapper) {
                N.checkArgNotNull(mapper);

                return new ObjIterator<>() {
                    @Override
                    public boolean hasNext() {
                        return iter1.hasNext() || iter2.hasNext() || iter3.hasNext();
                    }

                    @Override
                    public R next() {
                        if (!hasNext()) {
                            throw new NoSuchElementException();
                        }

                        return mapper.apply(iter1.hasNext() ? iter1.next() : valueForNoneA, iter2.hasNext() ? iter2.next() : valueForNoneB,
                                iter3.hasNext() ? iter3.next() : valueForNoneC);
                    }
                };
            }
        };
    }

    /**
     *
     * @param 
     * @param 
     * @param 
     * @param 
     * @param iter
     * @param unzipFunc output parameter.
     * @return
     */
    public static  TriIterator unzip(final Iterable iter, final BiConsumer> unzipFunc) {
        if (iter == null) {
            return TriIterator.empty();
        }

        return unzip(iter.iterator(), unzipFunc);
    }

    /**
     *
     * @param 
     * @param 
     * @param 
     * @param 
     * @param iter
     * @param unzipFunc output parameter.
     * @return
     */
    public static  TriIterator unzip(final Iterator iter, final BiConsumer> unzipFunc) {
        if (iter == null) {
            return TriIterator.empty();
        }

        final BooleanSupplier hasNext = iter::hasNext;

        final Consumer> output = out -> unzipFunc.accept(iter.next(), out);

        return TriIterator.generate(hasNext, output);
    }

    /**
     *
     * @param 
     * @param action
     * @throws NoSuchElementException
     * @throws E
     */
    protected abstract  void next(final Throwables.TriConsumer action)
            throws NoSuchElementException, E;

    /**
     * For each remaining.
     *
     * @param 
     * @param action
     * @throws E the e
     */
    public abstract  void forEachRemaining(final Throwables.TriConsumer action) throws E;

    /**
     * It's preferred to call forEachRemaining(Try.TriConsumer) to avoid the create the unnecessary Triple Objects.
     *
     * @param action
     * @deprecated
     */
    @Override
    @Deprecated
    public void forEachRemaining(java.util.function.Consumer> action) {
        super.forEachRemaining(action);
    }

    @SuppressWarnings("rawtypes")
    private static final Throwables.TriConsumer DO_NOTHING = (a, b, c) -> {
        // do nothing;
    };

    /**
     *
     *
     * @param n
     * @return
     */
    public TriIterator skip(final long n) {
        N.checkArgNotNegative(n, "n");

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

        final TriIterator iter = this;

        return new TriIterator<>() {
            private boolean skipped = false;

            @Override
            public boolean hasNext() {
                if (!skipped) {
                    skip();
                }

                return iter.hasNext();
            }

            @Override
            public Triple next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                return iter.next();
            }

            @Override
            protected  void next(final Throwables.TriConsumer action)
                    throws NoSuchElementException, E {
                if (!skipped) {
                    skip();
                }

                iter.next(action);
            }

            @Override
            public  void forEachRemaining(final Throwables.TriConsumer action) throws E {
                if (!skipped) {
                    skip();
                }

                iter.forEachRemaining(action);
            }

            @Override
            public  ObjIterator map(final TriFunction mapper) {
                if (!skipped) {
                    skip();
                }

                return iter.map(mapper);
            }

            private void skip() {
                long idx = 0;

                final Throwables.TriConsumer action = DO_NOTHING;

                while (idx++ < n && iter.hasNext()) {
                    iter.next(action);
                }

                skipped = true;
            }
        };
    }

    /**
     *
     *
     * @param count
     * @return
     */
    public TriIterator limit(final long count) {
        N.checkArgNotNegative(count, "count");

        if (count == 0) {
            return TriIterator. empty();
        }

        final TriIterator iter = this;

        return new TriIterator<>() {
            private long cnt = count;

            @Override
            public boolean hasNext() {
                return cnt > 0 && iter.hasNext();
            }

            @Override
            public Triple next() {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                cnt--;
                return iter.next();
            }

            @Override
            protected  void next(final Throwables.TriConsumer action)
                    throws NoSuchElementException, E {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }

                cnt--;
                iter.next(action);
            }

            @Override
            public  void forEachRemaining(final Throwables.TriConsumer action) throws E {
                while (hasNext()) {
                    cnt--;
                    iter.next(action);
                }
            }

            @Override
            public  ObjIterator map(final TriFunction mapper) {
                if (cnt > 0) {
                    return iter. map(mapper).limit(cnt);
                } else {
                    return ObjIterator. empty();
                }
            }
        };
    }

    /**
     *
     *
     * @param predicate
     * @return
     */
    public TriIterator filter(final TriPredicate predicate) {
        N.checkArgNotNull(predicate, "predicate");

        final TriIterator iter = this;

        return new TriIterator<>() {
            private final Triple next = new Triple<>();
            private final Throwables.TriConsumer setNext = (a, b, c) -> next.set(a, b, c);

            private boolean hasNext = false;

            @Override
            public boolean hasNext() {
                if (!hasNext) {
                    while (iter.hasNext()) {
                        iter.next(setNext);

                        if (predicate.test(next.left, next.middle, next.right)) {
                            hasNext = true;
                            break;
                        }
                    }
                }

                return hasNext;
            }

            @Override
            public Triple next() {
                if (!hasNext && !hasNext()) {
                    throw new NoSuchElementException();
                }

                hasNext = false;

                return next.copy();
            }

            @Override
            protected  void next(final Throwables.TriConsumer action)
                    throws NoSuchElementException, E {
                if (!hasNext && !hasNext()) {
                    throw new NoSuchElementException();
                }

                hasNext = false;

                action.accept(next.left, next.middle, next.right);
            }

            @Override
            public  void forEachRemaining(final Throwables.TriConsumer action) throws E {
                while (hasNext()) {
                    hasNext = false;

                    action.accept(next.left, next.middle, next.right);
                }
            }

            @Override
            public  ObjIterator map(final TriFunction mapper) {
                return new ObjIterator<>() {
                    @Override
                    public boolean hasNext() {
                        if (!hasNext) {
                            while (iter.hasNext()) {
                                iter.next(setNext);

                                if (predicate.test(next.left, next.middle, next.right)) {
                                    hasNext = true;
                                    break;
                                }
                            }
                        }

                        return hasNext;
                    }

                    @Override
                    public R next() {
                        if (!hasNext && !hasNext()) {
                            throw new NoSuchElementException();
                        }

                        hasNext = false;

                        return mapper.apply(next.left, next.middle, next.right);
                    }
                };
            }
        };
    }

    /**
     *
     * @param 
     * @param mapper
     * @return
     */
    public abstract  ObjIterator map(final TriFunction mapper);

    /**
     *
     *
     * @return
     */
    public Optional> first() {
        if (hasNext()) {
            return Optional.of(next());
        } else {
            return Optional.> empty();
        }
    }

    /**
     *
     *
     * @return
     */
    public Optional> last() {
        if (hasNext()) {
            final Triple next = new Triple<>();
            final Throwables.TriConsumer setNext = (a, b, c) -> next.set(a, b, c);

            forEachRemaining(setNext);

            return Optional.of(next);
        } else {
            return Optional.> empty();
        }
    }

    /**
     *
     * @param 
     * @param mapper
     * @return
     */
    public  Stream stream(final TriFunction mapper) {
        N.checkArgNotNull(mapper);

        return Stream.of(map(mapper));
    }

    /**
     *
     *
     * @return
     */
    public Triple[] toArray() {
        return toArray(new Triple[0]);
    }

    /**
     *
     * @param 
     * @param a
     * @return
     * @deprecated
     */
    @Deprecated
    public  T[] toArray(final T[] a) {
        return toList().toArray(a);
    }

    /**
     *
     *
     * @return
     */
    public List> toList() {
        return toCollection(Suppliers.ofList());
    }
}