您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
137 行
4.6 KiB
137 行
4.6 KiB
using System.Collections.Generic;
|
|
|
|
namespace Unity.Services.Core
|
|
{
|
|
/// <summary>
|
|
/// Helper object to sort <see cref="IInitializablePackage"/> stored into a
|
|
/// <see cref="DependencyTree"/> in order they can be initialized successfully.
|
|
/// It adapts the Depth-first Search algorithm.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Algorithm source: <see href="https://en.wikipedia.org/wiki/Topological_sorting#Depth-first_search"/>
|
|
/// </remarks>
|
|
struct DependencyTreeInitializeOrderSorter
|
|
{
|
|
enum ExplorationMark
|
|
{
|
|
None,
|
|
Viewed,
|
|
Sorted
|
|
}
|
|
|
|
public DependencyTree Tree;
|
|
|
|
/// <summary>
|
|
/// The collection containing the sorted package type hashes.
|
|
/// </summary>
|
|
public ICollection<int> Target;
|
|
|
|
/// <summary>
|
|
/// History to track packages' exploration state.
|
|
/// Key: Hash code of a <see cref="IInitializablePackage"/> type.
|
|
/// Value: Its exploration state.
|
|
/// </summary>
|
|
Dictionary<int, ExplorationMark> m_PackageTypeHashExplorationHistory;
|
|
|
|
public DependencyTreeInitializeOrderSorter(DependencyTree tree, ICollection<int> target)
|
|
{
|
|
Tree = tree;
|
|
Target = target;
|
|
m_PackageTypeHashExplorationHistory = null;
|
|
}
|
|
|
|
public void SortRegisteredPackagesIntoTarget()
|
|
{
|
|
Target.Clear();
|
|
|
|
RemoveUnprovidedOptionalDependenciesFromTree();
|
|
|
|
var registeredPackageTypeHashes = GetPackageTypeHashes();
|
|
m_PackageTypeHashExplorationHistory = new Dictionary<int, ExplorationMark>(registeredPackageTypeHashes.Count);
|
|
|
|
foreach (var packageTypeHash in registeredPackageTypeHashes)
|
|
{
|
|
SortTreeThrough(packageTypeHash);
|
|
}
|
|
|
|
m_PackageTypeHashExplorationHistory = null;
|
|
}
|
|
|
|
void RemoveUnprovidedOptionalDependenciesFromTree()
|
|
{
|
|
foreach (var dependencyTypeHashes in Tree.PackageTypeHashToComponentTypeHashDependencies.Values)
|
|
{
|
|
RemoveUnprovidedOptionalDependencies(dependencyTypeHashes);
|
|
}
|
|
}
|
|
|
|
void RemoveUnprovidedOptionalDependencies(IList<int> dependencyTypeHashes)
|
|
{
|
|
for (var i = dependencyTypeHashes.Count - 1; i >= 0; i--)
|
|
{
|
|
var dependencyTypeHash = dependencyTypeHashes[i];
|
|
if (IsOptional(dependencyTypeHash)
|
|
&& !IsProvided(dependencyTypeHash))
|
|
{
|
|
dependencyTypeHashes.RemoveAt(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SortTreeThrough(int packageTypeHash)
|
|
{
|
|
m_PackageTypeHashExplorationHistory.TryGetValue(packageTypeHash, out var explorationMark);
|
|
switch (explorationMark)
|
|
{
|
|
case ExplorationMark.Viewed:
|
|
throw new CircularDependencyException();
|
|
|
|
case ExplorationMark.Sorted:
|
|
return;
|
|
}
|
|
|
|
MarkPackage(packageTypeHash, ExplorationMark.Viewed);
|
|
|
|
var dependencyTypeHashes = GetDependencyTypeHashesFor(packageTypeHash);
|
|
SortTreeThrough(dependencyTypeHashes);
|
|
|
|
Target.Add(packageTypeHash);
|
|
|
|
MarkPackage(packageTypeHash, ExplorationMark.Sorted);
|
|
}
|
|
|
|
void SortTreeThrough(IEnumerable<int> dependencyTypeHashes)
|
|
{
|
|
foreach (var dependency in dependencyTypeHashes)
|
|
{
|
|
var dependencyPackageTypeHash = GetPackageTypeHashFor(dependency);
|
|
SortTreeThrough(dependencyPackageTypeHash);
|
|
}
|
|
}
|
|
|
|
void MarkPackage(int packageTypeHash, ExplorationMark mark)
|
|
{
|
|
m_PackageTypeHashExplorationHistory[packageTypeHash] = mark;
|
|
}
|
|
|
|
IReadOnlyCollection<int> GetPackageTypeHashes()
|
|
=> Tree.PackageTypeHashToInstance.Keys;
|
|
|
|
int GetPackageTypeHashFor(int componentTypeHash)
|
|
=> Tree.ComponentTypeHashToPackageTypeHash[componentTypeHash];
|
|
|
|
IEnumerable<int> GetDependencyTypeHashesFor(int packageTypeHash)
|
|
=> Tree.PackageTypeHashToComponentTypeHashDependencies[packageTypeHash];
|
|
|
|
bool IsOptional(int componentTypeHash)
|
|
{
|
|
return Tree.ComponentTypeHashToInstance.TryGetValue(componentTypeHash, out var component)
|
|
&& component is null;
|
|
}
|
|
|
|
bool IsProvided(int componentTypeHash)
|
|
{
|
|
return Tree.ComponentTypeHashToPackageTypeHash.ContainsKey(componentTypeHash);
|
|
}
|
|
}
|
|
}
|