AdvChkSys/src/AdvChkSys/Dependencies/ChunkDependencyTracker.cs
Stan44 0ae815cf2c XML comments added Builds cleanly.
oddly a ignore in the gitignore went missing.
restored.
2025-05-11 21:50:25 -05:00

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