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

graphql.util.TraverserState Maven / Gradle / Ivy

There is a newer version: 230521-nf-execution
Show newest version
package graphql.util;

import graphql.Internal;

import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Deque;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

import static graphql.Assert.assertNotNull;

@Internal
public abstract class TraverserState {

    private Object initialData;


    private final Deque state;
    private final Set visited = new LinkedHashSet<>();


    private static class StackTraverserState extends TraverserState {

        private StackTraverserState(Object initialData) {
            super(initialData);
        }

        @Override
        public void pushAll(TraverserContext o, Function> getChildren) {
            super.state.push(o);
            super.state.push(Marker.END_LIST);
            new ReverseIterator<>(getChildren.apply(o.thisNode())).forEachRemaining((e) -> super.state.push(newContext(e, o)));
        }
    }

    private static class QueueTraverserState extends TraverserState {

        private QueueTraverserState(Object initialData) {
            super(initialData);
        }

        @Override
        public void pushAll(TraverserContext o, Function> getChildren) {
            getChildren.apply(o.thisNode()).iterator().forEachRemaining((e) -> super.state.add(newContext(e, o)));
            super.state.add(Marker.END_LIST);
            super.state.add(o);
        }
    }

    public enum Marker {
        END_LIST
    }

    private TraverserState(Object initialData) {
        this.initialData = initialData;
        this.state = new ArrayDeque<>(32);
    }

    public static  TraverserState newQueueState(Object initialData) {
        return new QueueTraverserState<>(initialData);
    }

    public static  TraverserState newStackState(Object initialData) {
        return new StackTraverserState<>(initialData);
    }

    public abstract void pushAll(TraverserContext o, Function> getChildren);

    public Object pop() {
        return this.state.pop();
    }


    public void addNewContexts(Collection children, TraverserContext root) {
        assertNotNull(children).stream().map((x) -> newContext(x, root)).forEach(this.state::add);
    }

    public boolean isEmpty() {
        return state.isEmpty();
    }


    public void addVisited(T visited) {
        this.visited.add(visited);
    }

    public TraverserContext newContext(T o, TraverserContext parent) {
        return newContext(o, parent, new LinkedHashMap<>());
    }

    public TraverserContext newContext(T curNode, TraverserContext parent, Map, Object> vars) {
        assertNotNull(vars);

        return new TraverserContext() {
            Object result;

            @Override
            public T thisNode() {
                return curNode;
            }

            @Override
            public TraverserContext getParentContext() {
                return parent;
            }

            @Override
            public Object getParentResult() {
                return parent.getResult();
            }

            @Override
            public Set visitedNodes() {
                return visited;
            }

            @Override
            public boolean isVisited() {
                return visited.contains(curNode);
            }

            @Override
            public  S getVar(Class key) {
                return (S) key.cast(vars.get(key));
            }

            @Override
            public  TraverserContext setVar(Class key, S value) {
                vars.put(key, value);
                return this;
            }

            @Override
            public void setResult(Object result) {
                this.result = result;
            }

            @Override
            public Object getResult() {
                return this.result;
            }

            @Override
            public Object getInitialData() {
                return initialData;
            }


        };
    }

    private static class ReverseIterator implements Iterator {
        private final ListIterator delegate;

        private ReverseIterator(List list) {
            assertNotNull(list);

            this.delegate = list.listIterator(list.size());
        }

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

        @Override
        public T next() {
            return delegate.previous();
        }

        @Override
        public void remove() {
            delegate.remove();
        }
    }
}