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

ru.yandex.bolts.collection.impl.AbstractIteratorF Maven / Gradle / Ivy

The newest version!
package ru.yandex.bolts.collection.impl;

import java.util.Iterator;
import java.util.NoSuchElementException;

import ru.yandex.bolts.collection.Cf;
import ru.yandex.bolts.collection.IteratorF;
import ru.yandex.bolts.collection.ListF;
import ru.yandex.bolts.collection.Option;
import ru.yandex.bolts.collection.SetF;
import ru.yandex.bolts.collection.Tuple2;
import ru.yandex.bolts.function.Function;
import ru.yandex.bolts.function.Function1B;
import ru.yandex.bolts.function.forhuman.Comparator;


public abstract class AbstractIteratorF extends AbstractTraversableF implements IteratorF {

    @Override
    protected IteratorF iterator() {
        return this;
    }

    private IteratorF self() { return this; }

    @Override
    public ListF toList() {
        return toListImpl(-1);
    }

    @Override
    public ListF toList(int initialCapacity) {
        return toListImpl(initialCapacity);
    }

    private ListF toListImpl(int initialCapacity) {
        if (!hasNext()) return Cf.list();

        ArrayListF result;
        if (initialCapacity < 0) {
            result = new ArrayListF<>();
        } else {
            result = new ArrayListF<>(initialCapacity);
        }
        forEach(result.addF());
        return result.convertToReadOnly();
    }

    public SetF toSet() {
        if (!hasNext()) return Cf.set();

        SetF result = Cf.hashSet();
        forEach(result.addF());
        return result.unmodifiable();
    }

    @Override
    public  IteratorF map(final Function f) {
        class MappedIterator extends AbstractIteratorF {
            public boolean hasNext() {
                return self().hasNext();
            }

            public B next() {
                return f.apply(self().next());
            }

            public void remove() {
                self().remove();
            }
        }
        return new MappedIterator();
    }


    @Override
    public  IteratorF flatMap(final Function> f) {
        class FlatMappedIterator extends AbstractIteratorF {
            private IteratorF cur = Cf.emptyIterator();

            @Override
            public boolean hasNext() {
                while (!cur.hasNext() && self().hasNext()) {
                    cur = Cf.x(f.apply(self().next()));
                }
                return cur.hasNext();
            }

            @Override
            public B next() {
                if (hasNext()) return cur.next();
                throw new NoSuchElementException("next on empty iterator");
            }

        }
        return new FlatMappedIterator();
    }

    @SuppressWarnings("unchecked")
    @Override
    public  IteratorF flatMapL(Function> f0) {
        Function> f = (Function>) f0;
        Function> g = f.andThen((Function, Iterator>) Iterable::iterator);
        return flatMap(g);
    }

    @Override
    public  IteratorF flatMapO(Function> f) {
        return flatMapL(f);
    }

    private static abstract class AbstractPrefetchingIterator extends AbstractIteratorF {
        private Option next = Option.none();
        private boolean eof = false;

        private void fill() {
            while (!eof && next.isEmpty()) {
                next = fetchNext();
                eof = next.isEmpty();
            }
        }

        @Override
        public boolean hasNext() {
            fill();
            return !eof && next.isDefined();
        }

        @Override
        public E next() {
            if (!hasNext())
                throw new NoSuchElementException("next on empty iterator");
            E r = next.get();
            next = Option.none();
            return r;
        }

        protected abstract Option fetchNext();
    }

    @Override
    public IteratorF filter(final Function1B f) {
        class FilterIterator extends AbstractPrefetchingIterator {

            @Override
            protected Option fetchNext() {
                while (self().hasNext()) {
                    E e = self().next();
                    if (f.apply(e))
                        return Option.some(e);
                }
                return Option.none();
            }
        };

        return new FilterIterator();
    }

    @Override
    public IteratorF filterNot(Function1B f) {
        return filter(f.notF());
    }

    @Override
    public IteratorF filterNotNull() {
        return filter(Function1B.notNullF());
    }

    public IteratorF> zipWithIndex() {
        class ZippedIterator extends AbstractIteratorF> {
            private int i = 0;

            public boolean hasNext() {
                return self().hasNext();
            }

            public Tuple2 next() {
                return Tuple2.tuple(self().next(), i++);
            }

            public void remove() {
                self().remove();
            }
        }

        return new ZippedIterator();
    }

    public IteratorF plus(final Iterator b) {
        return new AbstractIteratorF() {
            final IteratorF a = self();

            public boolean hasNext() {
                return a.hasNext() || b.hasNext();
            }

            public E next() {
                if (a.hasNext()) return a.next();
                else return b.next();
            }
        };
    }

    public IteratorF unmodifiable() {
        return UnmodifiableDefaultIteratorF.wrap(this);
    }

    public Option nextO() {
        if (hasNext()) return Option.some(next());
        else return Option.none();
    }

    @Override
    public int count() {
        return count(Function1B.trueF());
    }

    public IteratorF drop(int count) {
        int left = count;
        while (left > 0 && hasNext()) {
            next();
            --left;
        }
        return this;
    }

    public IteratorF take(final int count) {
        if (count <= 0) return Cf.emptyIterator();

        class TakeIterator extends AbstractIteratorF {
            int left = count;

            public boolean hasNext() {
                return left > 0 && self().hasNext();
            }

            public E next() {
                if (left == 0) throw new NoSuchElementException();
                E next = self().next();
                --left;
                return next;
            }

        };

        return new TakeIterator();
    }

    @Override
    public ListF takeSorted(int count) {
        return takeSorted(Comparator.naturalComparator().uncheckedCastC(), count);
    }

    @Override
    public ListF takeSortedDesc(int count) {
        return takeSorted(Comparator.naturalComparator().invert().uncheckedCastC(), count);
    }


    @Override
    public ListF takeSorted(java.util.Comparator comparator, int count) {
        if (count == 0) {
            return Cf.list();
        }
        if (count < 0) {
            throw new IllegalArgumentException("K must be greater than 0");
        }
        FixedSizeTop top = FixedSizeTop.cons(count, (java.util.Comparator) comparator);
        while (hasNext()) {
            top.add(next());
        }
        return top.getTopElements();
    }

    @Override
    public ListF takeSortedBy(Function f, int count) {
        return takeSorted(f.andThenNaturalComparator().nullLowC(), count);
    }

    @Override
    public ListF takeSortedByDesc(Function f, int count) {
        return takeSorted(f.andThenNaturalComparator().nullLowC().invert(), count);
    }

    public IteratorF dropWhile(Function1B p) {
        // XXX: should be lazy
        while (hasNext()) {
            E e = next();
            if (!p.apply(e))
                return Cf.list(e).iterator().plus(this);
        }
        return Cf.emptyIterator();
    }

    public IteratorF takeWhile(final Function1B f) {
        class TakeWhileIterator extends AbstractPrefetchingIterator {
            boolean end = false;

            @Override
            protected Option fetchNext() {
                if (!end && self().hasNext()) {
                    E e = self().next();
                    if (f.apply(e))
                        return Option.some(e);
                    else {
                        end = true;
                        return Option.none();
                    }
                }
                return Option.none();
            }

        }

        return new TakeWhileIterator();
    }

    @Override
    public IteratorF> paginate(int pageSize) {
        if (pageSize <= 0) throw new IllegalArgumentException();
        return new AbstractIteratorF>() {
            @Override
            public boolean hasNext() {
                return AbstractIteratorF.this.hasNext();
            }

            @Override
            public ListF next() {
                if (!hasNext()) throw new NoSuchElementException();
                ArrayListF items = new ArrayListF<>(pageSize);
                for (int i = 0; i < pageSize && AbstractIteratorF.this.hasNext(); ++i) {
                    items.add(AbstractIteratorF.this.next());
                }
                return items.convertToReadOnly();
            }
        };
    }
} //~