blob: e07bec114dc88d87e826730469b6b61ab9b92fae [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.tinkerpop.gremlin.process.traversal;
import org.apache.tinkerpop.gremlin.structure.util.Attachable;
import java.io.Serializable;
import java.util.Set;
import java.util.function.Function;
/**
* A {@code Traverser} represents the current state of an object flowing through a {@link Traversal}.
* A traverser maintains a reference to the current object, a traverser-local "sack", a traversal-global sideEffect,
* a bulk count, and a path history.
* <p/>
* Different types of traversers can exist depending on the semantics of the traversal and the desire for
* space/time optimizations of the developer.
*
* @author Marko A. Rodriguez (http://markorodriguez.com)
*/
public interface Traverser<T> extends Serializable, Comparable<Traverser<T>>, Cloneable {
/**
* Get the object that the traverser is current at.
*
* @return The current object of the traverser
*/
public T get();
/**
* Get the sack local sack object of this traverser.
*
* @param <S> the type of the sack object
* @return the sack object
*/
public <S> S sack();
/**
* Set the traversers sack object to the provided value ("sack the value").
*
* @param object the new value of the traverser's sack
* @param <S> the type of the object
*/
public <S> void sack(final S object);
/**
* Get the current path of the traverser.
*
* @return The path of the traverser
*/
public Path path();
/**
* Get the object associated with the specified step-label in the traverser's path history.
*
* @param stepLabel the step-label in the path to access
* @param <A> the type of the object
* @return the object associated with that path label (if more than one object occurs at that step, a list is returned)
*/
public default <A> A path(final String stepLabel) {
return this.path().get(stepLabel);
}
public default <A> A path(final Pop pop, final String stepLabel) {
return this.path().get(pop, stepLabel);
}
/**
* Return the number of times the traverser has gone through a looping section of a traversal.
*
* @return The number of times the traverser has gone through a loop
*/
public int loops();
/**
* Return the number of times the traverser has gone through the named looping section of a traversal.
*
* @param loopName the name applied to the loop or null for the containing loop
* @return The number of times the traverser has gone through a loop
* @throws IllegalArgumentException if the loopName is not defined
*/
public int loops(final String loopName);
/**
* A traverser may represent a grouping of traversers to allow for more efficient data propagation.
*
* @return the number of traversers represented in this traverser.
*/
public long bulk();
/**
* Get a particular value from the side-effects of the traverser (thus, traversal).
*
* @param sideEffectKey the key of the value to get from the sideEffects
* @param <A> the type of the returned object
* @return the object in the sideEffects of the respective key
*/
public default <A> A sideEffects(final String sideEffectKey) throws IllegalArgumentException {
return this.asAdmin().getSideEffects().<A>get(sideEffectKey);
}
/**
* Add a particular value to the respective side-effect of the traverser (thus, traversal).
*
* @param sideEffectKey the key of the value to set int the sideEffects
* @param sideEffectValue the value to set for the sideEffect key
*/
public default void sideEffects(final String sideEffectKey, final Object sideEffectValue) throws IllegalArgumentException {
this.asAdmin().getSideEffects().add(sideEffectKey, sideEffectValue);
}
/**
* If the underlying object of the traverser is comparable, compare it with the other traverser.
*
* @param other the other traverser that presumably has a comparable internal object
* @return the comparison of the two objects of the traversers
* @throws ClassCastException if the object of the traverser is not comparable
*/
@Override
public default int compareTo(final Traverser<T> other) throws ClassCastException {
return ((Comparable) this.get()).compareTo(other.get());
}
/**
* Typecast the traverser to a "system traverser" so {@link Traverser.Admin} methods can be accessed.
* This is used as a helper method to avoid the awkwardness of <code>((Traverser.Administrative)traverser)</code>.
* The default implementation simply returns "this" type casted to {@link Traverser.Admin}.
*
* @return The type-casted traverser
*/
public default Admin<T> asAdmin() {
return (Admin<T>) this;
}
/**
* Traverser cloning is important when splitting a traverser at a bifurcation point in a traversal.
*/
@SuppressWarnings("CloneDoesntDeclareCloneNotSupportedException")
public Traverser<T> clone();
/**
* The methods in System.Traverser are useful to underlying Step and Traversal implementations.
* They should not be accessed by the user during lambda-based manipulations.
*/
public interface Admin<T> extends Traverser<T>, Attachable<T> {
public static final String HALT = "halt";
/**
* When two traversers are have equality with each other, then they can be merged.
* This method is used to merge the traversers into a single traverser.
* This is used for optimization where instead of enumerating all traversers, they can be counted.
*
* @param other the other traverser to merge into this traverser. Once merged, the other can be garbage collected.
*/
public void merge(final Admin<?> other);
/**
* Generate a child traverser of the current traverser for current as step and new object location.
* The child has the path history, future, and loop information of the parent.
* The child extends that path history with the current as and provided R-object.
*
* @param r The current object of the child
* @param step The step yielding the split
* @param <R> The current object type of the child
* @return The split traverser
*/
public <R> Admin<R> split(final R r, final Step<T, R> step);
/**
* Generate a sibling traverser of the current traverser with a full copy of all state within the sibling.
*
* @return The split traverser
*/
public Admin<T> split();
public void addLabels(final Set<String> labels);
/**
* Drop all path information not associated with specified labels.
* This is an optimization method that allows a traverser to save memory and increase the likelihood of bulking.
*
* @param labels the labels to keep path information for.
*/
public void keepLabels(final Set<String> labels);
/**
* Drop all path information associated with specified labels.
* This is an optimization method that allows a traverser to save memory and increase the likelihood of bulking.
*
* @param labels the labels to drop path information for.
*/
public void dropLabels(final Set<String> labels);
/**
* Drop the path of the traverser.
* This is an optimization method that allows a traverser to save memory and increase the likelihood of bulking.
*/
public void dropPath();
/**
* Set the current object location of the traverser.
*
* @param t The current object of the traverser
*/
public void set(final T t);
/**
* Initialise a loop by setting up the looping construct.
* The step label is important to create a stack of loop counters when within a nested context.
* If the provided label is not the same as the current label on the stack, add a new loop counter.
* The loopName can be used to refer to the loops counter via the {@link LoopsStep}
*
* @param stepLabel the label of the step that is being set-up.
* @param loopName the user defined name for referencing the loop counter or null if not set
*/
public void initialiseLoops(final String stepLabel, final String loopName);
/**
* Increment the number of times the traverser has gone through a looping section of traversal.
*/
public void incrLoops();
/**
* Set the number of times the traverser has gone through a loop back to 0.
* When a traverser exits a looping construct, this method should be called.
* In a nested loop context, the highest stack loop counter should be removed.
*/
public void resetLoops();
/**
* Get the step id of where the traverser is located.
* This is typically used in multi-machine systems that require the movement of
* traversers between different traversal instances.
*
* @return The future step for the traverser
*/
public String getStepId();
/**
* Set the step id of where the traverser is located.
* If the future is {@link Traverser.Admin#HALT}, then {@link Traverser.Admin#isHalted()} is true.
*
* @param stepId The future step of the traverser
*/
public void setStepId(final String stepId);
/**
* If the traverser has "no future" then it is done with its lifecycle.
* This does not mean that the traverser is "dead," only that it has successfully passed through a
* {@link Traversal}.
*
* @return Whether the traverser is done executing or not
*/
public default boolean isHalted() {
return getStepId().equals(HALT);
}
/**
* Set the number of traversers represented by this traverser.
*
* @param count the number of traversers
*/
public void setBulk(final long count);
/**
* Prepare the traverser for migration across a JVM boundary.
*
* @return The deflated traverser
*/
public Admin<T> detach();
/**
* Regenerate the detached traverser given its location at a particular vertex.
*
* @param method The method by which to attach a {@code Traverser} to an vertex.
* @return The inflated traverser
*/
@Override
public T attach(final Function<Attachable<T>, T> method);
/**
* Set the sideEffects of the {@link Traversal}. Given that traversers can move between machines,
* it may be important to re-set this when the traverser crosses machine boundaries.
*
* @param sideEffects the sideEffects of the traversal.
*/
public void setSideEffects(final TraversalSideEffects sideEffects);
/**
* Get the sideEffects associated with the traversal of the traverser.
*
* @return the traversal sideEffects of the traverser
*/
public TraversalSideEffects getSideEffects();
/**
* Get the tags associated with the traverser.
* Tags are used to categorize historic behavior of a traverser.
* The returned set is mutable.
*
* @return the set of tags associated with the traverser.
*/
public Set<String> getTags();
}
}