Files
plugin-library/Assets/01.HybridCLR/Editor/Meta/AssemblySorter.cs
2025-06-12 18:00:06 +08:00

106 lines
3.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HybridCLR.Editor.Meta
{
public class AssemblySorter
{
class Node
{
public string Name;
public List<Node> Dependencies = new List<Node>();
public Node(string name)
{
Name = name;
}
}
class TopologicalSorter
{
public static List<Node> Sort(List<Node> nodes)
{
List<Node> sorted = new List<Node>();
HashSet<Node> visited = new HashSet<Node>();
HashSet<Node> tempMarks = new HashSet<Node>();
foreach (var node in nodes)
{
if (!visited.Contains(node))
{
Visit(node, visited, tempMarks, sorted);
}
}
return sorted;
}
private static void Visit(Node node, HashSet<Node> visited, HashSet<Node> tempMarks, List<Node> sorted)
{
if (tempMarks.Contains(node))
{
throw new Exception("Detected cyclic dependency!");
}
if (!visited.Contains(node))
{
tempMarks.Add(node);
foreach (var dependency in node.Dependencies)
{
Visit(dependency, visited, tempMarks, sorted);
}
tempMarks.Remove(node);
visited.Add(node);
sorted.Add(node);
}
}
}
private static List<string> SortAssemblyByReferenceOrder(IEnumerable<string> assemblies, Dictionary<string, HashSet<string>> refs)
{
var nodes = new List<Node>();
var nodeMap = new Dictionary<string, Node>();
foreach (var assembly in assemblies)
{
var node = new Node(assembly);
nodes.Add(node);
nodeMap.Add(assembly, node);
}
foreach (var assembly in assemblies)
{
var node = nodeMap[assembly];
foreach (var refAssembly in refs[assembly])
{
node.Dependencies.Add(nodeMap[refAssembly]);
}
}
var sortedNodes = TopologicalSorter.Sort(nodes);
return sortedNodes.Select(node => node.Name).ToList();
}
public static List<string> SortAssemblyByReferenceOrder(IEnumerable<string> assemblies, IAssemblyResolver assemblyResolver)
{
var assCache = new AssemblyCache(assemblyResolver);
var assRefAssemblies = new Dictionary<string, HashSet<string>>();
foreach (var assName in assemblies)
{
var refAssemblies = new HashSet<string>();
var mod = assCache.LoadModule(assName, false);
foreach (var refAss in mod.GetAssemblyRefs())
{
if (assemblies.Contains(refAss.Name.ToString()))
{
refAssemblies.Add(refAss.Name.ToString());
}
}
assRefAssemblies.Add(assName, refAssemblies);
}
return SortAssemblyByReferenceOrder(assemblies, assRefAssemblies);
}
}
}