Beispiel #1
0
        int IMutableBidirectionalGraph <TVertex, TEdge> .RemoveInEdgeIf(TVertex v, EdgePredicate <TVertex, TEdge> predicate)
        {
            IMutableBidirectionalGraph <TVertex, TEdge> ithis = this;

            Contract.Requires(v != null);
            Contract.Requires(predicate != null);
            Contract.Requires(ithis.ContainsVertex(v));
            Contract.Ensures(ithis.ContainsVertex(v));
            Contract.Ensures(ithis.InEdges(v).All(e => predicate(e)));
            Contract.Ensures(Contract.Result <int>() == Contract.OldValue(ithis.InEdges(v).Count(e => predicate(e))));
            Contract.Ensures(ithis.InDegree(v) == Contract.OldValue(ithis.InDegree(v)) - Contract.Result <int>());

            return(default(int));
        }
        protected static IEnumerable <T> GetPath(IMutableBidirectionalGraph <T, IEdge <T> > graph)
        {
            var result     = new LinkedList <T>();
            var candidates = new HashSet <T>(graph.Vertices.Where(graph.IsOutEdgesEmpty), new IdentityComparer <T>());

            while (candidates.Count > 0)
            {
                var component = candidates.First();
                candidates.Remove(component);

                result.AddFirst(component);

                var inEdges = graph.InEdges(component).ToList();
                graph.RemoveVertex(component);

                foreach (var inEdge in inEdges)
                {
                    if (graph.IsOutEdgesEmpty(inEdge.Source))
                    {
                        candidates.Add(inEdge.Source);
                    }
                }
            }

            return(result);
        }
        public static void DeleteVerticesAndMergeEdges <TVertex, TEdge>
            (this IMutableBidirectionalGraph <TVertex, TEdge> graph, TVertex vertexToDelete,
            Func <TEdge, TEdge, TEdge> mergeFunc)
            where TEdge : IEdge <TVertex>
        {
            if (graph.IsInEdgesEmpty(vertexToDelete) || graph.IsOutEdgesEmpty(vertexToDelete))
            {
                //simple case
                graph.RemoveVertex(vertexToDelete);
            }
            else
            {
                //need to keep connections
                var newEdges = from e1 in graph.InEdges(vertexToDelete)
                               from e2 in graph.OutEdges(vertexToDelete)
                               select mergeFunc(e1, e2);

                //create edges
                var newEdgesList = newEdges.ToList();

                graph.AddEdgeRange(newEdgesList);
                graph.RemoveVertex(vertexToDelete);
            }
        }
Beispiel #4
0
        private void PlaceBlock(int modeIndex, LeftRightMode leftRightMode, UpperLowerEdges upperLowerEdges, SugiVertex v)
        {
            if (!double.IsNaN(v.HorizontalPositions[modeIndex]))
            {
                return;
            }

            double delta = Parameters.VertexDistance;

            v.HorizontalPositions[modeIndex] = 0;
            Data w = v;

            do
            {
                SugiVertex wVertex  = w as SugiVertex;
                Segment    wSegment = w as Segment;
                if (_sparseCompactionGraph.ContainsVertex(w) &&
                    ((leftRightMode == LeftRightMode.Left && _sparseCompactionGraph.InDegree(w) > 0) ||
                     (leftRightMode == LeftRightMode.Right && _sparseCompactionGraph.OutDegree(w) > 0)))
                {
                    var edges = leftRightMode == LeftRightMode.Left
                        ? _sparseCompactionGraph.InEdges(w)
                        : _sparseCompactionGraph.OutEdges(w);
                    foreach (var edge in edges)
                    {
                        SugiVertex u    = null;
                        Data       pred = leftRightMode == LeftRightMode.Left ? edge.Source : edge.Target;
                        if (pred is SugiVertex)
                        {
                            u = ((SugiVertex)pred).Roots[modeIndex];
                        }
                        else
                        {
                            var segment = (Segment)pred;
                            u = upperLowerEdges == UpperLowerEdges.Upper ? segment.PVertex.Roots[modeIndex] : segment.QVertex.Roots[modeIndex];
                        }
                        PlaceBlock(modeIndex, leftRightMode, upperLowerEdges, u);
                        if (v.Sinks[modeIndex] == v)
                        {
                            v.Sinks[modeIndex] = u.Sinks[modeIndex];
                        }
                        //var xDelta = delta + (v.Roots[modeIndex].BlockWidths[modeIndex] + u.BlockWidths[modeIndex]) / 2.0;
                        var xDelta = delta + ((wVertex != null ? wVertex.Size.Width : 0.0) + ((pred is SugiVertex) ? ((SugiVertex)pred).Size.Width : u.BlockWidths[modeIndex])) / 2.0;
                        if (v.Sinks[modeIndex] != u.Sinks[modeIndex])
                        {
                            var s = leftRightMode == LeftRightMode.Left
                                ? v.HorizontalPositions[modeIndex] - u.HorizontalPositions[modeIndex] - xDelta
                                : u.HorizontalPositions[modeIndex] - v.HorizontalPositions[modeIndex] - xDelta;

                            u.Sinks[modeIndex].Shifts[modeIndex] = leftRightMode == LeftRightMode.Left
                                ? Math.Min(u.Sinks[modeIndex].Shifts[modeIndex], s)
                                : Math.Max(u.Sinks[modeIndex].Shifts[modeIndex], s);
                        }
                        else
                        {
                            v.HorizontalPositions[modeIndex] =
                                leftRightMode == LeftRightMode.Left
                                    ? Math.Max(v.HorizontalPositions[modeIndex], u.HorizontalPositions[modeIndex] + xDelta)
                                    : Math.Min(v.HorizontalPositions[modeIndex], u.HorizontalPositions[modeIndex] - xDelta);
                        }
                    }
                }
                if (wSegment != null)
                {
                    w = (upperLowerEdges == UpperLowerEdges.Upper) ? wSegment.QVertex : wSegment.PVertex;
                }
                else if (wVertex.Type == VertexTypes.PVertex && upperLowerEdges == UpperLowerEdges.Upper)
                {
                    w = wVertex.Segment;
                }
                else if (wVertex.Type == VertexTypes.QVertex && upperLowerEdges == UpperLowerEdges.Lower)
                {
                    w = wVertex.Segment;
                }
                else
                {
                    w = wVertex.Aligns[modeIndex];
                }
            } while (w != v);
        }
Beispiel #5
0
 /// <summary>
 /// Returns every edge connected with the vertex <code>v</code>.
 /// </summary>
 /// <param name="v">The vertex.</param>
 /// <returns>Edges, adjacent to the vertex <code>v</code>.</returns>
 protected IEnumerable <TEdge> EdgesFor(TVertex v)
 {
     return(_graph.InEdges(v).Concat(_graph.OutEdges(v)));
 }
Beispiel #6
0
        private void PlaceBlock(
            int modeIndex,
            LeftRightMode leftRightMode,
            UpperLowerEdges upperLowerEdges,
            [NotNull] SugiVertex v)
        {
            if (!double.IsNaN(v.SlicePositions[modeIndex]))
            {
                return;
            }

            double delta = Parameters.SliceGap;

            v.SlicePositions[modeIndex] = 0;
            Data w = v;

            do
            {
                var wVertex  = w as SugiVertex;
                var wSegment = w as Segment;
                if (_sparseCompactionGraph.ContainsVertex(w) &&
                    (leftRightMode == LeftRightMode.Left && _sparseCompactionGraph.InDegree(w) > 0 ||
                     leftRightMode == LeftRightMode.Right && _sparseCompactionGraph.OutDegree(w) > 0))
                {
                    IEnumerable <IEdge <Data> > edges = leftRightMode == LeftRightMode.Left
                        ? _sparseCompactionGraph.InEdges(w)
                        : _sparseCompactionGraph.OutEdges(w);

                    foreach (IEdge <Data> edge in edges)
                    {
                        SugiVertex u;
                        Data       predecessor = leftRightMode == LeftRightMode.Left ? edge.Source : edge.Target;
                        if (predecessor is SugiVertex vertex)
                        {
                            u = vertex.Roots[modeIndex];
                        }
                        else
                        {
                            var segment = (Segment)predecessor;
                            u = upperLowerEdges == UpperLowerEdges.Upper ? segment.PVertex.Roots[modeIndex] : segment.QVertex.Roots[modeIndex];
                        }

                        PlaceBlock(modeIndex, leftRightMode, upperLowerEdges, u);

                        if (v.Sinks[modeIndex] == v)
                        {
                            v.Sinks[modeIndex] = u.Sinks[modeIndex];
                        }

                        double xDelta = delta
                                        + (
                            (wVertex?.Size.Width ?? 0.0)
                            + (predecessor is SugiVertex sugiVertex
                                                ? sugiVertex.Size.Width
                                                : u.BlockWidths[modeIndex])
                            ) / 2.0;

                        if (v.Sinks[modeIndex] != u.Sinks[modeIndex])
                        {
                            double s = leftRightMode == LeftRightMode.Left
                                ? v.SlicePositions[modeIndex] - u.SlicePositions[modeIndex] - xDelta
                                : u.SlicePositions[modeIndex] - v.SlicePositions[modeIndex] - xDelta;

                            u.Sinks[modeIndex].Shifts[modeIndex] = leftRightMode == LeftRightMode.Left
                                ? Math.Min(u.Sinks[modeIndex].Shifts[modeIndex], s)
                                : Math.Max(u.Sinks[modeIndex].Shifts[modeIndex], s);
                        }
                        else
                        {
                            v.SlicePositions[modeIndex] = leftRightMode == LeftRightMode.Left
                                ? Math.Max(v.SlicePositions[modeIndex], u.SlicePositions[modeIndex] + xDelta)
                                : Math.Min(v.SlicePositions[modeIndex], u.SlicePositions[modeIndex] - xDelta);
                        }
                    }
                }

                if (wSegment != null)
                {
                    w = upperLowerEdges == UpperLowerEdges.Upper ? wSegment.QVertex : wSegment.PVertex;
                }
                // ReSharper disable once PossibleNullReferenceException
                // Justification: If not a segment then it's a vertex
                else if (wVertex.Type == VertexTypes.PVertex && upperLowerEdges == UpperLowerEdges.Upper)
                {
                    w = wVertex.Segment;
                }
                else if (wVertex.Type == VertexTypes.QVertex && upperLowerEdges == UpperLowerEdges.Lower)
                {
                    w = wVertex.Segment;
                }
                else
                {
                    w = wVertex.Aligns[modeIndex];
                }
            } while (w != v);
        }
        public async Task <UpdateResult> Recompile(Project gameProject, LoggerResult logger)
        {
            var result = new UpdateResult(logger);

            if (solution is null)
            {
                solution = gameProject.Solution;
            }

            // Detect new groups
            var gameProjectCompilation = await gameProject.GetCompilationAsync();

            // Generate source dependency graph
            var sourceDependencyGraph = new SourceGroup();

            // Make sure all vertices are added
            foreach (var syntaxTree in gameProjectCompilation.SyntaxTrees)
            {
                sourceDependencyGraph.AddVertex(syntaxTree);
            }

            foreach (var syntaxTree in gameProjectCompilation.SyntaxTrees)
            {
                var syntaxRoot    = syntaxTree.GetRoot();
                var semanticModel = gameProjectCompilation.GetSemanticModel(syntaxTree);

                var dependencies = new SourceDependencySyntaxVisitor(new HashSet <SyntaxTree>(gameProjectCompilation.SyntaxTrees), semanticModel).DefaultVisit(syntaxRoot);

                foreach (var dependency in dependencies)
                {
                    sourceDependencyGraph.AddEdge(new SEdge <SyntaxTree>(syntaxTree, dependency));
                }
            }

            // Generate strongly connected components for sources (group of sources that needs to be compiled together, and their dependencies)
            var stronglyConnected     = sourceDependencyGraph.CondensateStronglyConnected <SyntaxTree, SEdge <SyntaxTree>, SourceGroup>();
            var sortedConnectedGroups = stronglyConnected.TopologicalSort().ToArray();
            var connectedGroups       = ImmutableHashSet.Create(SourceGroupComparer.Default, sortedConnectedGroups);

            // Merge changes since previous time
            // 1. Tag obsolete groups (everything that don't match, and their dependencies)
            var groupsToUnload = new HashSet <SourceGroup>(SourceGroupComparer.Default);

            foreach (var sourceGroup in previousSortedConnectedGroups.Reverse())
            {
                // Does this group needs reload?
                if (connectedGroups.TryGetValue(sourceGroup, out SourceGroup newSourceGroup))
                {
                    // Transfer project, as it can be reused
                    newSourceGroup.Project  = sourceGroup.Project;
                    newSourceGroup.PE       = sourceGroup.PE;
                    newSourceGroup.PDB      = sourceGroup.PDB;
                    newSourceGroup.Assembly = sourceGroup.Assembly;
                }
                else
                {
                    groupsToUnload.Add(sourceGroup);
                }

                // Mark dependencies
                if (groupsToUnload.Contains(sourceGroup))
                {
                    foreach (var test in previousStronglyConnected.InEdges(sourceGroup))
                    {
                        groupsToUnload.Add(test.Source);
                    }
                }
            }

            // Generate common InternalsVisibleTo attributes
            // TODO: Find more graceful solution
            var internalsVisibleToBuilder = new StringBuilder();

            internalsVisibleToBuilder.Append("using System.Runtime.CompilerServices;");

            for (int i = 0; i < 1000; i++)
            {
                internalsVisibleToBuilder.AppendFormat(@"[assembly: InternalsVisibleTo(""{0}.Part{1}"")]", gameProject.AssemblyName, i);
            }

            var internalsVisibleToSource = CSharpSyntaxTree.ParseText(internalsVisibleToBuilder.ToString(), null, "", Encoding.UTF8).GetText();

            // 2. Compile assemblies
            foreach (var sourceGroup in sortedConnectedGroups.Reverse())
            {
                // Check if it's either a new group, or one that has been unloaded
                if (!previousConnectedGroups.Contains(sourceGroup) || groupsToUnload.Contains(sourceGroup))
                {
                    var assemblyName = gameProject.AssemblyName + ".Part" + assemblyCounter++;

                    // Create a project out of the source group
                    var project = solution.AddProject(assemblyName, assemblyName, LanguageNames.CSharp)
                                  .WithMetadataReferences(gameProject.MetadataReferences)
                                  .WithProjectReferences(gameProject.AllProjectReferences)
                                  .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

                    // Add sources
                    foreach (var syntaxTree in sourceGroup.Vertices)
                    {
                        project = project.AddDocument(syntaxTree.FilePath, syntaxTree.GetText()).Project;
                    }

                    // Add references to other sources
                    foreach (var dependencySourceGroup in stronglyConnected.OutEdges(sourceGroup))
                    {
                        project = project.AddProjectReference(new ProjectReference(dependencySourceGroup.Target.Project.Id));
                    }

                    // Make internals visible to other assembly parts
                    project = project.AddDocument("GeneratedInternalsVisibleTo", internalsVisibleToSource).Project;

                    sourceGroup.Project = project;
                    solution            = project.Solution;

                    var compilation = await project.GetCompilationAsync();

                    using (var peStream = new MemoryStream())
                        using (var pdbStream = new MemoryStream())
                        {
                            var emitResult = compilation.Emit(peStream, pdbStream);
                            result.Info($"Compiling assembly containing {sourceGroup}.");

                            foreach (var diagnostic in emitResult.Diagnostics)
                            {
                                switch (diagnostic.Severity)
                                {
                                case DiagnosticSeverity.Error:
                                    result.Error(diagnostic.GetMessage());
                                    break;

                                case DiagnosticSeverity.Warning:
                                    result.Warning(diagnostic.GetMessage());
                                    break;

                                case DiagnosticSeverity.Info:
                                    result.Info(diagnostic.GetMessage());
                                    break;
                                }
                            }

                            if (!emitResult.Success)
                            {
                                result.Error($"Error compiling assembly containing {sourceGroup}.");
                                break;
                            }

                            // Load .csproj to evaluate Assembly Processor parameters
                            var msbuildProject = await Task.Run(() => VSProjectHelper.LoadProject(gameProject.FilePath));

                            if (msbuildProject.GetPropertyValue("StrideAssemblyProcessor") == "true")
                            {
                                var referenceBuild = await Task.Run(() => VSProjectHelper.CompileProjectAssemblyAsync(gameProject.FilePath, result, "ResolveReferences", flags: Microsoft.Build.Execution.BuildRequestDataFlags.ProvideProjectStateAfterBuild));

                                if (referenceBuild is null)
                                {
                                    result.Error("Could not properly run ResolveAssemblyReferences.");
                                    break;
                                }
                                var referenceBuildResult = await referenceBuild.BuildTask;
                                if (referenceBuild.IsCanceled || result.HasErrors)
                                {
                                    break;
                                }

                                var assemblyProcessorParameters = "--parameter-key --auto-module-initializer --serialization";
                                var assemblyProcessorApp        = AssemblyProcessorProgram.CreateAssemblyProcessorApp(SplitCommandLine(assemblyProcessorParameters).ToArray(), new LoggerAssemblyProcessorWrapper(result));

                                foreach (var referencePath in referenceBuildResult.ProjectStateAfterBuild.Items.Where(x => x.ItemType == "ReferencePath"))
                                {
                                    assemblyProcessorApp.References.Add(referencePath.EvaluatedInclude);
                                    // TODO: Hard-coded references! Needs to go when plugin system is in.
                                    if (referencePath.EvaluatedInclude.EndsWith("Stride.SpriteStudio.Runtime.dll"))
                                    {
                                        assemblyProcessorApp.ReferencesToAdd.Add(referencePath.EvaluatedInclude);
                                    }
                                    else if (referencePath.EvaluatedInclude.EndsWith("Stride.Physics.dll"))
                                    {
                                        assemblyProcessorApp.ReferencesToAdd.Add(referencePath.EvaluatedInclude);
                                    }
                                    else if (referencePath.EvaluatedInclude.EndsWith("Stride.Particles.dll"))
                                    {
                                        assemblyProcessorApp.ReferencesToAdd.Add(referencePath.EvaluatedInclude);
                                    }
                                    else if (referencePath.EvaluatedInclude.EndsWith("Stride.Native.dll"))
                                    {
                                        assemblyProcessorApp.ReferencesToAdd.Add(referencePath.EvaluatedInclude);
                                    }
                                    else if (referencePath.EvaluatedInclude.EndsWith("Stride.UI.dll"))
                                    {
                                        assemblyProcessorApp.ReferencesToAdd.Add(referencePath.EvaluatedInclude);
                                    }
                                    else if (referencePath.EvaluatedInclude.EndsWith("Stride.Video.dll"))
                                    {
                                        assemblyProcessorApp.ReferencesToAdd.Add(referencePath.EvaluatedInclude);
                                    }
                                }

                                var assemblyResolver = assemblyProcessorApp.CreateAssemblyResolver();

                                // Add dependencies to assembly resolver
                                var recursiveDependencies = stronglyConnected.OutEdges(sourceGroup).SelectDeep(edge => stronglyConnected.OutEdges(edge.Target));
                                foreach (var dependencySourceGroup in recursiveDependencies)
                                {
                                    assemblyResolver.Register(dependencySourceGroup.Target.Assembly, dependencySourceGroup.Target.PE);
                                }

                                // Rewind streams
                                peStream.Position  = 0;
                                pdbStream.Position = 0;

                                var assemblyDefinition = AssemblyDefinition.ReadAssembly(peStream,
                                                                                         new ReaderParameters {
                                    AssemblyResolver = assemblyResolver, ReadSymbols = true, SymbolStream = pdbStream
                                });

                                // Run assembly processor
                                assemblyProcessorApp.SerializationAssembly = true;
                                if (!assemblyProcessorApp.Run(ref assemblyDefinition, out _, out _))
                                {
                                    result.Error("Error running assembly processor.");
                                    break;
                                }

                                sourceGroup.Assembly = assemblyDefinition;

                                // Write to file for now, since Cecil does not use the SymbolStream
                                var peFileName  = Path.ChangeExtension(Path.GetTempFileName(), ".dll");
                                var pdbFileName = Path.ChangeExtension(peFileName, ".pdb");
                                assemblyDefinition.Write(peFileName, new WriterParameters {
                                    WriteSymbols = true
                                });

                                sourceGroup.PE  = File.ReadAllBytes(peFileName);
                                sourceGroup.PDB = File.ReadAllBytes(pdbFileName);

                                File.Delete(peFileName);
                                File.Delete(pdbFileName);
                            }
                            else
                            {
                                sourceGroup.PE  = peStream.ToArray();
                                sourceGroup.PDB = pdbStream.ToArray();
                            }
                        }
                }
            }

            // We register unloading/loading only if everything succeeded
            if (!result.HasErrors)
            {
                // 3. Register old assemblies to unload
                foreach (var sourceGroup in previousSortedConnectedGroups)
                {
                    if (groupsToUnload.Contains(sourceGroup))
                    {
                        sourceGroup.Project  = null;
                        sourceGroup.Assembly = null;
                        result.UnloadedProjects.Add(sourceGroup);
                    }
                }

                // 4. Register new assemblies to load
                foreach (var sourceGroup in sortedConnectedGroups.Reverse())
                {
                    // Check if it's either a new group, or one that has been unloaded
                    if (!previousConnectedGroups.Contains(sourceGroup) || groupsToUnload.Contains(sourceGroup))
                    {
                        result.LoadedProjects.Add(sourceGroup);
                    }
                }

                // Set as new state
                previousSortedConnectedGroups = sortedConnectedGroups;
                previousStronglyConnected     = stronglyConnected;
                previousConnectedGroups       = connectedGroups;
            }

            return(result);
        }
 private IEnumerable <TEdge> EdgesFor([NotNull] TVertex vertex)
 {
     Debug.Assert(vertex != null);
     return(_graph.InEdges(vertex)
            .Concat(_graph.OutEdges(vertex).Where(e => !e.IsSelfEdge())));
 }