325 lines
10 KiB
C#
325 lines
10 KiB
C#
#nullable enable
|
|
using System.Collections.Generic;
|
|
using AdvChkSys.Interfaces;
|
|
|
|
namespace AdvChkSys.Dependencies
|
|
{
|
|
/// <summary>
|
|
/// Tracks dependencies between chunks.
|
|
/// </summary>
|
|
public class ChunkDependencyTracker
|
|
{
|
|
/// <summary>
|
|
/// Defines the type of dependency between chunks.
|
|
/// </summary>
|
|
public enum DependencyType
|
|
{
|
|
/// <summary>
|
|
/// Indicates a neighboring chunk relationship.
|
|
/// </summary>
|
|
Neighbor,
|
|
|
|
/// <summary>
|
|
/// Indicates a reference relationship between chunks.
|
|
/// </summary>
|
|
Reference,
|
|
|
|
/// <summary>
|
|
/// Indicates an update relationship between chunks.
|
|
/// </summary>
|
|
Update,
|
|
|
|
/// <summary>
|
|
/// Indicates a custom dependency relationship.
|
|
/// </summary>
|
|
Custom
|
|
}
|
|
|
|
// Dictionary to track dependencies: source chunk -> (target chunk, dependency type)
|
|
private readonly Dictionary<IChunk, HashSet<(IChunk Target, DependencyType Type)>> _dependencies = new();
|
|
|
|
// Dictionary to track dependents: target chunk -> (source chunk, dependency type)
|
|
private readonly Dictionary<IChunk, HashSet<(IChunk Source, DependencyType Type)>> _dependents = new();
|
|
|
|
// Lock object for thread safety
|
|
private readonly object _lock = new();
|
|
|
|
/// <summary>
|
|
/// Registers a dependency between two chunks.
|
|
/// </summary>
|
|
public void RegisterDependency(IChunk source, IChunk target, DependencyType type)
|
|
{
|
|
if (source == null || target == null)
|
|
return;
|
|
|
|
lock (_lock)
|
|
{
|
|
// Add to dependencies
|
|
if (!_dependencies.TryGetValue(source, out var targetSet))
|
|
{
|
|
targetSet = new HashSet<(IChunk, DependencyType)>();
|
|
_dependencies[source] = targetSet;
|
|
}
|
|
targetSet.Add((target, type));
|
|
|
|
// Add to dependents
|
|
if (!_dependents.TryGetValue(target, out var sourceSet))
|
|
{
|
|
sourceSet = new HashSet<(IChunk, DependencyType)>();
|
|
_dependents[target] = sourceSet;
|
|
}
|
|
sourceSet.Add((source, type));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes a dependency between two chunks.
|
|
/// </summary>
|
|
public void RemoveDependency(IChunk source, IChunk target)
|
|
{
|
|
if (source == null || target == null)
|
|
return;
|
|
|
|
lock (_lock)
|
|
{
|
|
// Remove from dependencies
|
|
if (_dependencies.TryGetValue(source, out var targetSet))
|
|
{
|
|
targetSet.RemoveWhere(t => t.Target.Equals(target));
|
|
if (targetSet.Count == 0)
|
|
{
|
|
_dependencies.Remove(source);
|
|
}
|
|
}
|
|
|
|
// Remove from dependents
|
|
if (_dependents.TryGetValue(target, out var sourceSet))
|
|
{
|
|
sourceSet.RemoveWhere(s => s.Source.Equals(source));
|
|
if (sourceSet.Count == 0)
|
|
{
|
|
_dependents.Remove(target);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all chunks that depend on the specified chunk.
|
|
/// </summary>
|
|
public IEnumerable<IChunk> GetDependents(IChunk chunk)
|
|
{
|
|
if (chunk == null)
|
|
return new List<IChunk>();
|
|
|
|
lock (_lock)
|
|
{
|
|
if (!_dependents.TryGetValue(chunk, out var sourceSet))
|
|
{
|
|
return new List<IChunk>();
|
|
}
|
|
|
|
var result = new List<IChunk>(sourceSet.Count);
|
|
foreach (var (source, _) in sourceSet)
|
|
{
|
|
result.Add(source);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all chunks that the specified chunk depends on.
|
|
/// </summary>
|
|
public IEnumerable<IChunk> GetDependencies(IChunk chunk)
|
|
{
|
|
if (chunk == null)
|
|
return new List<IChunk>();
|
|
|
|
lock (_lock)
|
|
{
|
|
if (!_dependencies.TryGetValue(chunk, out var targetSet))
|
|
{
|
|
return new List<IChunk>();
|
|
}
|
|
|
|
var result = new List<IChunk>(targetSet.Count);
|
|
foreach (var (target, _) in targetSet)
|
|
{
|
|
result.Add(target);
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all chunks that depend on the specified chunk with their dependency types.
|
|
/// </summary>
|
|
public IEnumerable<(IChunk Chunk, DependencyType Type)> GetDependentsWithTypes(IChunk chunk)
|
|
{
|
|
if (chunk == null)
|
|
return new List<(IChunk, DependencyType)>();
|
|
|
|
lock (_lock)
|
|
{
|
|
if (!_dependents.TryGetValue(chunk, out var sourceDependents))
|
|
{
|
|
return new List<(IChunk, DependencyType)>();
|
|
}
|
|
|
|
var result = new List<(IChunk, DependencyType)>(sourceDependents.Count);
|
|
foreach (var (source, type) in sourceDependents)
|
|
{
|
|
result.Add((source, type));
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all chunks that the specified chunk depends on with their dependency types.
|
|
/// </summary>
|
|
public IEnumerable<(IChunk Chunk, DependencyType Type)> GetDependenciesWithTypes(IChunk chunk)
|
|
{
|
|
if (chunk == null)
|
|
return new List<(IChunk, DependencyType)>();
|
|
|
|
lock (_lock)
|
|
{
|
|
if (!_dependencies.TryGetValue(chunk, out var targetSet))
|
|
{
|
|
return new List<(IChunk, DependencyType)>();
|
|
}
|
|
|
|
var result = new List<(IChunk, DependencyType)>(targetSet.Count);
|
|
foreach (var (target, type) in targetSet)
|
|
{
|
|
result.Add((target, type));
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a dependency exists between source and target chunks.
|
|
/// </summary>
|
|
public bool HasDependency(IChunk source, IChunk target)
|
|
{
|
|
if (source == null || target == null)
|
|
return false;
|
|
|
|
lock (_lock)
|
|
{
|
|
if (!_dependencies.TryGetValue(source, out var targetSet))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
foreach (var (t, _) in targetSet)
|
|
{
|
|
if (t.Equals(target))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the dependency type between source and target chunks, or null if no dependency exists.
|
|
/// </summary>
|
|
public DependencyType? GetDependencyType(IChunk source, IChunk target)
|
|
{
|
|
if (source == null || target == null)
|
|
return null;
|
|
|
|
lock (_lock)
|
|
{
|
|
if (!_dependencies.TryGetValue(source, out var targetSet))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
foreach (var (t, type) in targetSet)
|
|
{
|
|
if (t.Equals(target))
|
|
{
|
|
return type;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Clears all dependencies for a specific chunk.
|
|
/// </summary>
|
|
public void ClearDependencies(IChunk chunk)
|
|
{
|
|
if (chunk == null)
|
|
return;
|
|
|
|
lock (_lock)
|
|
{
|
|
// Remove all dependencies where this chunk is the source
|
|
if (_dependencies.TryGetValue(chunk, out var targetSet))
|
|
{
|
|
foreach (var (target, _) in targetSet)
|
|
{
|
|
if (_dependents.TryGetValue(target, out var depSources))
|
|
{
|
|
depSources.RemoveWhere(s => s.Source.Equals(chunk));
|
|
if (depSources.Count == 0)
|
|
{
|
|
_dependents.Remove(target);
|
|
}
|
|
}
|
|
}
|
|
_dependencies.Remove(chunk);
|
|
}
|
|
|
|
// Remove all dependencies where this chunk is the target
|
|
if (_dependents.TryGetValue(chunk, out var sourceSets))
|
|
{
|
|
foreach (var (source, _) in sourceSets)
|
|
{
|
|
if (_dependencies.TryGetValue(source, out var depTargets))
|
|
{
|
|
depTargets.RemoveWhere(t => t.Target.Equals(chunk));
|
|
if (depTargets.Count == 0)
|
|
{
|
|
_dependencies.Remove(source);
|
|
}
|
|
}
|
|
}
|
|
_dependents.Remove(chunk);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all chunks that have any dependencies.
|
|
/// </summary>
|
|
public IEnumerable<IChunk> GetAllChunksWithDependencies()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return new HashSet<IChunk>(_dependencies.Keys);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets all chunks that have any dependents.
|
|
/// </summary>
|
|
public IEnumerable<IChunk> GetAllChunksWithDependents()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
return new HashSet<IChunk>(_dependents.Keys);
|
|
}
|
|
}
|
|
}
|
|
} |