예제 #1
0
        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);
            }
        }
예제 #2
0
        /// <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);
            }
예제 #4
0
            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);
                    }
                }
            }
예제 #5
0
            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);
                }
            }
예제 #6
0
            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);
                }
            }
예제 #7
0
            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();
                }
            }