private static void DetectCycle(AcyclicGraph <UTinySystem.Reference> graph) { var count = 0; var error = string.Empty; AcyclicGraphIterator.DetectCycle.Execute(graph, () => { error += $"[{UTinyConstants.ApplicationName}] SystemExecutionGraph detected cyclic reference ("; }, () => { error += ")"; }, system => { if (count != 0) { error += ", "; } error += system.Name; count++; }); if (!string.IsNullOrEmpty(error)) { Debug.LogError(error); } }
/// <summary> /// Builds an AcyclicGraph from the included systems /// </summary> private AcyclicGraph <UTinySystem.Reference> GetSystemGraph() { var graph = new AcyclicGraph <UTinySystem.Reference>(); // Add all systems foreach (var module in EnumerateDependencies()) { foreach (var systemRef in module.Systems) { graph.Add(systemRef); } } // Connect all first level dependencies foreach (var node in graph.Nodes.ToList()) { var systemRef = node.Data; var system = systemRef.Dereference(Registry); foreach (var dependencyRef in system.ExecuteAfter) { var depedencyNode = graph.GetOrAdd(dependencyRef); graph.AddDirectedConnection(node, depedencyNode); } foreach (var dependencyRef in system.ExecuteBefore) { var depedencyNode = graph.GetOrAdd(dependencyRef); graph.AddDirectedConnection(depedencyNode, node); } } return(graph); }
public static IEnumerable <Reference> DepthFirst(IEnumerable <UTinyType> types) { var graph = new AcyclicGraph <Reference>(); // Push all types into the graph foreach (var type in types) { graph.Add((Reference)type); } // Connect types foreach (var type in types) { var typeNode = graph.GetOrAdd((Reference)type); foreach (var fieldType in EnumerateFieldTypes(type)) { var fieldTypeNode = graph.GetOrAdd(fieldType); graph.AddDirectedConnection(typeNode, fieldTypeNode); } } var result = new List <Reference>(); AcyclicGraphIterator.DepthFirst.Execute(graph, type => { result.Add(type); }); return(result); }
public static void Execute <T>(AcyclicGraph <T> graph, Action startOfCycle, Action endOfCycle, Action <T> action) { var nodes = graph.Nodes; var count = nodes.Count; var vIndex = new int[count]; var vLowLink = new int[count]; var vOnStack = new bool[count]; var stack = new int[count]; for (var i = 0; i < count; ++i) { vIndex[i] = -1; vLowLink[i] = -1; } var context = new Context { UnusedIndex = 0, vIndex = vIndex, vLowLink = vLowLink, vOnStack = vOnStack, Stack = stack, }; for (var i = 0; i < nodes.Count; i++) { if (context.vIndex[i] == -1) { StrongConnect(graph, nodes[i], ref context, startOfCycle, endOfCycle, action); } } }
private static void Visit <T>(AcyclicGraph <T> .Node node, IList <MarkType> marks, Action <T> action) { var index = node.Index; switch (marks[index]) { case MarkType.Permanent: return; case MarkType.Temporary: return; } marks[index] = MarkType.Temporary; foreach (var connection in node.Connections) { Visit(connection, marks, action); } marks[index] = MarkType.Permanent; var data = node.Data; if (data != null) { action(data); } }
public static void Execute <T>(AcyclicGraph <T> graph, Action <T> action) { var nodes = graph.Nodes; var marks = new MarkType[nodes.Count]; foreach (var node in nodes) { Visit(node, marks, action); } }
private static void StrongConnect <T>(AcyclicGraph <T> graph, AcyclicGraph <T> .Node node, ref Context context, Action startOfCycle, Action endOfCycle, Action <T> action) { // Index of the current node being processed var index = node.Index; // Set the depth index for this node to the smallest unused index context.vIndex[index] = context.UnusedIndex; context.vLowLink[index] = context.UnusedIndex; context.UnusedIndex++; context.Stack[context.SP++] = index; context.vOnStack[index] = true; foreach (var connection in node.Connections) { if (context.vIndex[connection.Index] == -1) { // Successor has not yet been visited; recurse on it StrongConnect(graph, connection, ref context, startOfCycle, endOfCycle, action); context.vLowLink[index] = UnityEngine.Mathf.Min(context.vLowLink[index], context.vLowLink[connection.Index]); } else if (context.vOnStack[connection.Index]) { // Successor is on the stack and hence in the current SCC // Note: The next line may look odd - but is correct. // It says connection.index not connection.lowlink; that is deliberate and from the original paper context.vLowLink[index] = UnityEngine.Mathf.Min(context.vLowLink[index], context.vIndex[connection.Index]); } } if (context.vLowLink[index] != context.vIndex[index]) { return; } var report = context.Stack[context.SP - 1] != index; if (report) { // If is a root node, pop the stack and generate an SCC startOfCycle(); } int top; do { top = context.Stack[--context.SP]; context.vOnStack[top] = false; if (report) { action(graph.Nodes[top].Data); } } while (top != index); if (report) { endOfCycle(); } }