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); } }
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); }
/// <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))); }
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()))); }