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

org.javimmutable.collections.iterators.GenericIterator Maven / Gradle / Ivy

///###////////////////////////////////////////////////////////////////////////
//
// Burton Computer Corporation
// http://www.burton-computer.com
//
// Copyright (c) 2019, Burton Computer Corporation
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     Redistributions of source code must retain the above copyright
//     notice, this list of conditions and the following disclaimer.
//
//     Redistributions in binary form must reproduce the above copyright
//     notice, this list of conditions and the following disclaimer in
//     the documentation and/or other materials provided with the
//     distribution.
//
//     Neither the name of the Burton Computer Corporation nor the names
//     of its contributors may be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package org.javimmutable.collections.iterators;

import org.javimmutable.collections.Func1;
import org.javimmutable.collections.Indexed;
import org.javimmutable.collections.SplitIterator;
import org.javimmutable.collections.SplitableIterable;
import org.javimmutable.collections.SplitableIterator;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
import java.util.NoSuchElementException;

@ThreadSafe
public class GenericIterator
    extends AbstractSplitableIterator
{
    static final int MIN_SIZE_FOR_SPLIT = 32;

    private final Iterable root;
    private final int limit;
    private int offset;
    private boolean uninitialized;
    private State state;

    public GenericIterator(@Nonnull Iterable root,
                           int offset,
                           int limit)
    {
        assert offset <= limit;
        this.root = root;
        this.limit = limit;
        this.offset = offset;
        uninitialized = true;
    }

    public interface Iterable
        extends SplitableIterable
    {
        @Nullable
        State iterateOverRange(@Nullable State parent,
                                  int offset,
                                  int limit);

        int iterableSize();

        @Nonnull
        default SplitableIterator iterator()
        {
            return new GenericIterator<>(this, 0, iterableSize());
        }
    }

    public interface State
    {
        default boolean hasValue()
        {
            return false;
        }

        default T value()
        {
            throw new NoSuchElementException();
        }

        State advance();
    }

    @Override
    public synchronized boolean hasNext()
    {
        return prepare();
    }

    @Override
    public synchronized T next()
    {
        if (!prepare()) {
            throw new NoSuchElementException();
        }
        final T answer = state.value();
        offset += 1;
        if (offset < limit) {
            state = state.advance();
        } else {
            state = null;
        }
        assert offset <= limit;
        return answer;
    }

    @Override
    public synchronized boolean isSplitAllowed()
    {
        return (limit - offset) >= MIN_SIZE_FOR_SPLIT;
    }

    @Nonnull
    @Override
    public synchronized SplitIterator splitIterator()
    {
        final int splitIndex = offset + (limit - offset) / 2;
        return new SplitIterator<>(new GenericIterator<>(root, offset, splitIndex),
                                   new GenericIterator<>(root, splitIndex, limit));
    }

    private boolean prepare()
    {
        if (uninitialized) {
            state = root.iterateOverRange(null, offset, limit);
            uninitialized = false;
        }
        while (state != null) {
            if (state.hasValue()) {
                return true;
            }
            state = state.advance();
        }
        return false;
    }

    public static  State valueState(State parent,
                                          T value)
    {
        return new SingleValueState<>(parent, value);
    }

    public static  Iterable valueIterable(T value)
    {
        return new Iterable()
        {
            @Override
            public State iterateOverRange(@Nullable State parent,
                                             int offset,
                                             int limit)
            {
                assert offset >= 0 && offset <= limit && limit <= 1;
                if (offset == limit) {
                    return parent;
                } else {
                    return new SingleValueState(parent, value);
                }
            }

            @Override
            public int iterableSize()
            {
                return 1;
            }
        };
    }

    public static  State multiValueState(@Nullable State parent,
                                               @Nonnull Indexed values,
                                               int offset,
                                               int limit)
    {
        assert offset >= 0 && offset <= limit && limit <= values.size();
        return new MultiValueState<>(parent, values, offset, limit);
    }

    public static  State indexedState(State parent,
                                            Indexed> children,
                                            int offset,
                                            int limit)
    {
        assert 0 <= offset && offset <= limit;
        if (offset == limit) {
            return parent;
        } else {
            return new IndexedState<>(parent, children, offset, limit);
        }
    }

    public static  State transformState(State parent,
                                                 State source,
                                                 Func1 transforminator)
    {
        if (source == null) {
            return parent;
        } else {
            return new TransformState<>(parent, source, transforminator);
        }
    }

    private static class SingleValueState
        implements State
    {
        private final State parent;
        private final T value;
        private boolean available;

        private SingleValueState(State parent,
                                 T value)
        {
            this.parent = parent;
            this.value = value;
            available = true;
        }

        @Override
        public boolean hasValue()
        {
            return available;
        }

        @Override
        public T value()
        {
            assert available;
            available = false;
            return value;
        }

        @Override
        public State advance()
        {
            assert !available;
            return parent;
        }
    }

    private static class MultiValueState
        implements GenericIterator.State
    {
        private final GenericIterator.State parent;
        private final Indexed values;
        private final int limit;
        private int offset;

        private MultiValueState(@Nullable GenericIterator.State parent,
                                @Nonnull Indexed values,
                                int offset,
                                int limit)
        {
            this.parent = parent;
            this.values = values;
            this.offset = offset;
            this.limit = limit;
        }

        @Override
        public boolean hasValue()
        {
            return offset < limit;
        }

        @Override
        public T value()
        {
            return values.get(offset);
        }

        @Nullable
        @Override
        public GenericIterator.State advance()
        {
            offset += 1;
            if (offset < limit) {
                return this;
            } else {
                return parent;
            }
        }
    }

    private static class IndexedState
        implements State
    {
        private final State parent;
        private final Indexed> children;
        private int offset;
        private int limit;
        private int index;

        public IndexedState(State parent,
                            Indexed> children,
                            int offset,
                            int limit)
        {
            this.parent = parent;
            this.children = children;
            this.limit = limit;
            this.offset = offset;
            index = 0;
        }

        @Override
        public State advance()
        {
            final Iterable child = children.get(index);
            final int size = child.iterableSize();
            if (offset >= size) {
                index += 1;
                offset -= size;
                limit -= size;
                return this;
            } else if (limit <= size) {
                return child.iterateOverRange(parent, offset, limit);
            } else {
                final State answer = child.iterateOverRange(this, offset, size);
                index += 1;
                offset = 0;
                limit -= size;
                return answer;
            }
        }
    }

    private static class TransformState
        implements GenericIterator.State
    {
        private final Func1 transforminator;
        private final GenericIterator.State parent;
        private GenericIterator.State source;

        private TransformState(@Nullable GenericIterator.State parent,
                               @Nonnull GenericIterator.State source,
                               @Nonnull Func1 transforminator)
        {
            this.transforminator = transforminator;
            this.parent = parent;
            this.source = source;
        }

        @Override
        public boolean hasValue()
        {
            return source.hasValue();
        }

        @Override
        public B value()
        {
            return transforminator.apply(source.value());
        }

        @Nullable
        @Override
        public GenericIterator.State advance()
        {
            source = source.advance();
            if (source == null) {
                return parent;
            } else {
                return this;
            }
        }
    }
}