walkByNodes<R> method

R? walkByNodes<R>(
  1. Iterable<Node<T>> from, {
  2. required GraphWalkNodeOutputsProvider<T> outputsProvider,
  3. required GraphWalkNodeProcessor<T, R> process,
  4. GraphWalkSideBranchProcessor<T, R>? processSideBranches,
  5. bool expandSideBranches = false,
  6. int? maxDepth,
})

A generic walk algorithm using Nodes.

Implementation

R? walkByNodes<R>(
  Iterable<Node<T>> from, {
  required GraphWalkNodeOutputsProvider<T> outputsProvider,
  required GraphWalkNodeProcessor<T, R> process,
  GraphWalkSideBranchProcessor<T, R>? processSideBranches,
  bool expandSideBranches = false,
  int? maxDepth,
}) {
  maxDepth ??= defaultMaxDepth;

  final processed = _processedNodes;
  final queue = ListQueue<GraphNodeStep<T>>();

  if (sortByInputDependency) {
    from = from.sortedByInputDependency();
  }

  queue.addAll(from.toGraphRootStep(this));

  while (queue.isNotEmpty) {
    final step = queue.removeFirst();
    final node = step.node;

    var processCount = processed.increment(node);

    if (processCount <= maxExpansion && step.depth <= maxDepth) {
      if (processRoots || step.isNotRoot) {
        var ret = process(step);

        if (ret == null && processSideBranches != null) {
          var sideBranches = _computeSideBranch(node, processed);
          if (sideBranches.isNotEmpty) {
            if (sortByInputDependency) {
              sideBranches = sideBranches.sortedByInputDependency();
            }
            ret = processSideBranches(step, sideBranches);
          }
        }

        if (ret != null) {
          if (ret is GraphWalkingInstructionResult) {
            return ret.result as R?;
          } else if (ret is GraphWalkingInstructionOperation) {
            switch (ret.operation) {
              case GraphWalkingOperation.stop:
                return null;
              case GraphWalkingOperation.next:
                continue;
            }
          } else if (ret is GraphWalkingInstructionSetExpansionCounter) {
            processed[node] = ret.count;
          } else if (ret is GraphWalkingInstructionSetNodesExpansionCounter) {
            processed.addCounter(ret.counter);
          } else {
            return _resolveWalkProcessReturn<T, R>(node, ret);
          }
        }
      }

      if (stopMatcher.matchesNode(node)) {
        return _resolveWalkProcessReturn<T, R>(node, true);
      }

      List<Node<T>>? sideBranches;
      if (expandSideBranches && processSideBranches == null) {
        sideBranches = _computeSideBranch(node, processed);
        if (sortByInputDependency) {
          sideBranches = sideBranches.sortedByInputDependency();
        }
      }

      var outputs = outputsProvider(step, node);
      if (sortByInputDependency) {
        outputs = outputs?.sortedByInputDependency();
      }

      var nextStepsSideBranches =
          sideBranches?.toGraphNodeStep(step, sideBranch: true);
      var nextStepsOutputs = outputs?.toGraphNodeStep(step);

      queue.addAllToScanQueue2(nextStepsSideBranches, nextStepsOutputs, bfs);
    }
  }

  return _resolveWalkProcessReturn<T, R>(null, false);
}