Class Transformation<T extends JobParameters>

java.lang.Object
io.github.douira.glsl_transformer.transform.LifecycleUserImpl<T>
io.github.douira.glsl_transformer.transform.Transformation<T>
All Implemented Interfaces:
Activatable, ActivatableLifecycleUser<T>, LifecycleUser<T>
Direct Known Subclasses:
ConfigurableTransformation

public class Transformation<T extends JobParameters> extends LifecycleUserImpl<T>
The transformation holds information about dependencies between transformation phases and nested transformations. It also has a root node and an end node. The root node dependents on all nodes that have no dependents while the end node is depended on by all nodes that have no dependencies. Any directed acyclic graph of dependencies may be created between the nodes within a transformation. A dependency relationship between two nodes consists of a dependent and a dependency node. The dependency node must be executed at some point before the dependent node. As a transformation is a lifecycle user, its internal state can be reset before each transformation job. A stateless (no inter-phase state) transformation can be created by simply making an instance of this class and adding transformations to it. If state between phases is needed, make a subclass and add any state as instance fields. Then phases are created and added within the subclass' constructor. There cannot be any state stored as local variables either in the scope that created the Transformation instance or in a subclass' constructor as it will not be reset if a transformation is run multiple times. In the same vein, state should only be initialized in the LifecycleUser.init() and LifecycleUser.resetState() methods. An interesting effect of the automatic root and end node linking is that it's impossible to create cycles that don't have dangling bits since a bare cycle will be completely disconnected from the rest of the graph. Since phases are deduplicated within transformations and during execution planning, adding a single phase instance multiple times either doesn't do anything or causes a execution planning error. In order repeat the execution of a phase multiple times, simply create a lambda function (a Supplier<TransformationPhase<T>>) that generates a phase and run it each time you need an independent instance of it. TODO: unclear if sharing phases between transformation managers is problematic since then the compiled paths/patterns in phases have a different parser than the one being used for the transformation. Probably it doesn't matter, and the parser is just used to figure out how the rules of the tree are.
  • Constructor Details

    • Transformation

      public Transformation(LifecycleUser<T> content)
      Creates a stateless transformation and adds a single lifecycle user to it.
      Parameters:
      content - The only lifecycle user to add to this transformation. Typically a transformation phase.
    • Transformation

      public Transformation()
      Creates a stateless transformation with no content, which can be added later.
  • Method Details

    • triggerJobInternal

      protected void triggerJobInternal()
      An alternative reset method that is also called like LifecycleUser.resetState() but should be used for core transformation internals. This is one so that users of core transformations don't have to remember to call the super implementation of LifecycleUser.resetState() themselves.
    • setupGraph

      protected void setupGraph()
      If conditional dependencies are required for this transformation, all dependencies should be added within this method. Fixed job parameters may be accessed through LifecycleUser.getJobParameters(). Only either dependencies added in this method or statically set dependencies may be used at once. If dependencies are added statically, this method is never run and no conditional dependencies can be created. For more efficient memory usage, it's recommended to create the dependencies that are setup within this method once and then simply add their references as dependencies in this method. Creating them in this method will generate copies of the created phases.
    • addDependency

      public void addDependency(LifecycleUser<T> dependent, LifecycleUser<T> dependency)
      Creates a dependency relationship between two nodes. This means the dependency will be run before the dependent. Both of them are added to this transformation if not already present.
      Parameters:
      dependent - The node depending on the dependency to have been run first
      dependency - The node that needs to be run before the dependent
    • addDependent

      public void addDependent(LifecycleUser<T> dependency, LifecycleUser<T> dependent)
      Creates a dependency relationship between two nodes. The meaning of dependent and dependency are the same as in addDependency(LifecycleUser, LifecycleUser) but the positions are switched. This is useful for constructing the dual algorithm in the dependent/dependency structure. Usually the one is just the dependency graph of the other but upside down.
      Parameters:
      dependency - The node being depended on that is executed first
      dependent - The node depending on the dependency that is executed second
      See Also:
      addDependency(LifecycleUser, LifecycleUser)
    • chainDependency

      public <L extends LifecycleUser<T>> L chainDependency(L dependency)
      Adds a dependency to the last added dependency. If this is the first dependency added to this transformation, this adds it as a dependency of the root node.
      Type Parameters:
      L - The input and output type
      Parameters:
      dependency - The node to add as a further dependency
      Returns:
      The added node
    • chainDependent

      public <L extends LifecycleUser<T>> L chainDependent(L dependent)
      Adds a dependent to the last added dependent. If this is the first dependent added to this transformation, this adds it as a dependent of the end node.
      Type Parameters:
      L - The input and output type
      Parameters:
      dependent - The node to add as a further dependent
      Returns:
      The added node
    • addRootDependency

      public <L extends LifecycleUser<T>> L addRootDependency(L dependency)
      Adds a dependency to the root node. All dependencies added by this method can be run concurrently.
      Type Parameters:
      L - The input and output type
      Parameters:
      dependency - The node to add as a root dependency
      Returns:
      The added node
    • addEndDependent

      public <L extends LifecycleUser<T>> L addEndDependent(L dependent)
      Adds a dependent to the end node. All dependents added by this method can be run concurrently.
      Type Parameters:
      L - The input and output type
      Parameters:
      dependent - The node to add as a end dependent
      Returns:
      The added node
    • appendDependent

      public <L extends LifecycleUser<T>> L appendDependent(L newSoleEndDependent)
      Adds a dependency between the end node and all of its dependents. This replaces the end node with a new end node. This method is called appendDependent because it adds a new node that is the only dependent of the root node after this operation. Furthermore, chaining after this method will see the node with the new content as the dependent and the new end node as the dependency.
      Type Parameters:
      L - The input and output type
      Parameters:
      newSoleEndDependent - The node to place after all present dependencies
      Returns:
      The added node
    • prependDependency

      public <L extends LifecycleUser<T>> L prependDependency(L newSoleRootDependency)
      Adds a dependency between the root node and all of its dependencies. This replaces the root node with a new root node. See appendDependent(LifecycleUser) for why this method is called this way. The argument is the same.
      Type Parameters:
      L - The input and output type
      Parameters:
      newSoleRootDependency - The node to place before all present dependencies
      Returns:
      The added node
    • chainConcurrentDependency

      public <L extends LifecycleUser<T>> L chainConcurrentDependency(L dependency)
      Adds a dependency to the last added dependent. The newly added dependency and the last added dependency can be executed concurrently.
      Type Parameters:
      L - The input and output type
      Parameters:
      dependency - The node to add as a dependency of the last added dependent
      Returns:
      The added node
    • chainConcurrentDependent

      public <L extends LifecycleUser<T>> L chainConcurrentDependent(L dependent)
      Adds a dependent to the last added dependency. The newly added dependent and the last added dependent can be executed concurrently.
      Type Parameters:
      L - The input and output type
      Parameters:
      dependent - The node to add as a dependent of the last added dependency
      Returns:
      The added node
    • chainConcurrentSibling

      public <L extends LifecycleUser<T>> L chainConcurrentSibling(L sibling)
      Adds the same node as a dependent to the last added dependency and as a dependency to the last added dependent. The newly added node must be executed before the last added dependency and after the last added dependent. This is similar to inserting it directly between the two but is less invasive.
      Type Parameters:
      L - The input and output type
      Parameters:
      sibling - The node to add between the last added dependency and dependent without breaking the existing dependency link between them
      Returns:
      The added node
    • repeat

      public static <R extends JobParameters> Transformation<R> repeat(int count, BiConsumer<Transformation<R>,​LifecycleUser<R>> consumer, Supplier<LifecycleUser<R>> generator)
      Generates a transformation that contains the lifecycle user generated by the given supplier a given number of times. Since a single instance can't be
      Type Parameters:
      R - The job parameter type
      Parameters:
      count - How many copies should be generated
      consumer - The function that takes the generates lifecycle users and adds them to a transformation
      generator - The function that generates lifecycle users
      Returns:
      A transformation with the added lifecycle users
    • repeatSequential

      public static <R extends JobParameters> Transformation<R> repeatSequential(int count, Supplier<LifecycleUser<R>> generator)
      Generates a transformation that runs a given number of copies of the given lifecycle user (given by the generator function) in series.
      Type Parameters:
      R - The job parameter type
      Parameters:
      count - How many copies should be generated
      generator - The function that generates lifecycle users
      Returns:
      A transformation with the added lifecycle users
    • repeatParallel

      public static <R extends JobParameters> Transformation<R> repeatParallel(int count, Supplier<LifecycleUser<R>> generator)
      Generates a transformation that runs a given number of copies of the given lifecycle user (given by the generator function) in parallel.
      Type Parameters:
      R - The job parameter type
      Parameters:
      count - How many copies should be generated
      generator - The function that generates lifecycle users
      Returns:
      A transformation with the added lifecycle users