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

com.landawn.abacus.util.BiIterator Maven / Gradle / Ivy

/*
 * 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.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;

import com.landawn.abacus.util.function.BiConsumer;
import com.landawn.abacus.util.function.BiFunction;
import com.landawn.abacus.util.function.BooleanSupplier;
import com.landawn.abacus.util.function.Consumer;
import com.landawn.abacus.util.function.IndexedConsumer;
import com.landawn.abacus.util.stream.Stream;

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

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

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

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

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

            return ObjIterator.empty();
        }
    };

    public static  BiIterator empty() {
        return EMPTY;
    }

    public static  BiIterator of(final Map map) {
        if (N.isNullOrEmpty(map)) {
            return empty();
        }

        return of(map.entrySet().iterator());
    }

    public static  BiIterator of(final Iterator> iter) {
        if (iter == null) {
            return empty();
        }

        return new BiIterator() {

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

            @Override
            public Pair next() {
                return Pair.from(iter.next());
            }

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

                Map.Entry entry = null;

                while (iter.hasNext()) {
                    entry = iter.next();
                    action.accept(entry.getKey(), entry.getValue());
                }
            }

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

                return new ObjIterator() {
                    private Map.Entry entry = null;

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

                    @Override
                    public R next() {
                        entry = iter.next();

                        return mapper.apply(entry.getKey(), entry.getValue());
                    }
                };
            }
        };
    }

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

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

        return new BiIterator() {
            private final Pair tmp = new Pair();

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

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

                output.accept(tmp);

                return Pair.of(tmp.left, tmp.right);
            }

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

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

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

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

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

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

                        output.accept(tmp);

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

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

        return new BiIterator() {
            private final MutableInt cursor = MutableInt.of(fromIndex);
            private final Pair tmp = new Pair();

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

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

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

                return Pair.of(tmp.left, tmp.right);
            }

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

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

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

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

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

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

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

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

    public static  BiIterator zip(final A[] a, final B[] b) {
        return zip(Array.asList(a), Array.asList(b));
    }

    public static  BiIterator zip(final A[] a, final B[] b, final A valueForNoneA, final B valueForNoneB) {
        return zip(Array.asList(a), Array.asList(b), valueForNoneA, valueForNoneB);
    }

    public static  BiIterator zip(final Collection a, final Collection b) {
        return zip(a == null ? null : a.iterator(), b == null ? null : b.iterator());
    }

    public static  BiIterator zip(final Collection a, final Collection b, final A valueForNoneA, final B valueForNoneB) {
        return zip(a == null ? null : a.iterator(), b == null ? null : b.iterator(), valueForNoneA, valueForNoneB);
    }

    public static  BiIterator zip(final Iterator iterA, final Iterator iterB) {
        if (iterA == null || iterB == null) {
            return empty();
        }

        return new BiIterator() {
            @Override
            public boolean hasNext() {
                return iterA.hasNext() && iterB.hasNext();
            }

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

                return Pair.of(iterA.next(), iterB.next());
            }

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

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

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

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

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

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

    public static  BiIterator zip(final Iterator iterA, final Iterator iterB, final A valueForNoneA, final B valueForNoneB) {
        final Iterator iter1 = iterA == null ? ObjIterator. empty() : iterA;
        final Iterator iter2 = iterB == null ? ObjIterator. empty() : iterB;

        return new BiIterator() {
            @Override
            public boolean hasNext() {
                return iter1.hasNext() || iter2.hasNext();
            }

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

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

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

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

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

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

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

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

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

        final BooleanSupplier hasNext = new BooleanSupplier() {
            @Override
            public boolean getAsBoolean() {
                return iter.hasNext();
            }
        };

        final Consumer> output = new Consumer>() {
            @Override
            public void accept(Pair out) {
                unzip.accept(iter.next(), out);
            }
        };

        return BiIterator.generate(hasNext, output);
    }

    public abstract  void forEachRemaining(final Try.BiConsumer action) throws E;

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

    public abstract  ObjIterator map(final BiFunction mapper);

    public  Stream stream(final BiFunction mapper) {
        N.checkArgNotNull(mapper);

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