Files
riversong-code-showcase/Source/Engine/Helpers/TopologicalSort.cs
2026-05-21 16:04:49 +02:00

63 lines
1.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
namespace DanieleMarotta.RiversongCodeShowcase
{
public class TopologicalSort<T>
{
private HashSet<T> _currentDependencies;
private HashSet<T> _closed;
public TopologicalSort(IEqualityComparer<T> comparer)
{
_currentDependencies = new HashSet<T>(comparer);
_closed = new HashSet<T>(comparer);
}
public TopologicalSort() : this(EqualityComparer<T>.Default)
{
}
public static TopologicalSort<T> Default { get; } = new();
public IEnumerable<T> Sort(IEnumerable<T> source, Func<T, List<T>> dependenciesGetter, ICollection<T> sorted = null)
{
sorted ??= new List<T>();
try
{
foreach (var item in source) Visit(item, dependenciesGetter, sorted);
}
finally
{
_currentDependencies.Clear();
_closed.Clear();
}
return sorted;
}
private void Visit(T item, Func<T, List<T>> dependenciesGetter, ICollection<T> sorted)
{
if (!_currentDependencies.Add(item))
{
var ex = new StringBuilder();
ex.AppendLine(item.ToString());
foreach (var dependency in _currentDependencies) ex.AppendLine(dependency.ToString());
throw new InvalidOperationException(ex.ToString());
}
var dependencies = dependenciesGetter.Invoke(item);
if (dependencies != null)
foreach (var dependency in dependencies)
Visit(dependency, dependenciesGetter, sorted);
_currentDependencies.Remove(item);
if (_closed.Add(item)) sorted.Add(item);
}
}
}