using System.Collections.Concurrent;
namespace GFramework.Core.resource;
///
/// 资源缓存条目
///
internal sealed class ResourceCacheEntry(object resource, Type resourceType)
{
public object Resource { get; } = resource ?? throw new ArgumentNullException(nameof(resource));
public Type ResourceType { get; } = resourceType ?? throw new ArgumentNullException(nameof(resourceType));
public int ReferenceCount { get; set; }
public DateTime LastAccessTime { get; set; } = DateTime.UtcNow;
}
///
/// 资源缓存系统,管理已加载资源的缓存和引用计数
/// 线程安全:所有公共方法都是线程安全的
///
internal sealed class ResourceCache
{
///
/// Path 参数验证错误消息常量
///
private const string PathCannotBeNullOrEmptyMessage = "Path cannot be null or whitespace.";
private readonly ConcurrentDictionary _cache = new();
private readonly object _lock = new();
///
/// 获取已缓存资源的数量
///
public int Count => _cache.Count;
///
/// 添加资源到缓存
///
/// 资源类型
/// 资源路径
/// 资源实例
/// 如果成功添加返回 true,如果已存在返回 false
public bool Add(string path, T resource) where T : class
{
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentException(PathCannotBeNullOrEmptyMessage, nameof(path));
ArgumentNullException.ThrowIfNull(resource);
var entry = new ResourceCacheEntry(resource, typeof(T));
return _cache.TryAdd(path, entry);
}
///
/// 从缓存中获取资源
///
/// 资源类型
/// 资源路径
/// 资源实例,如果不存在或类型不匹配返回 null
public T? Get(string path) where T : class
{
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentException(PathCannotBeNullOrEmptyMessage, nameof(path));
if (_cache.TryGetValue(path, out var entry))
{
lock (_lock)
{
entry.LastAccessTime = DateTime.UtcNow;
}
if (entry.Resource is T typedResource)
{
return typedResource;
}
}
return null;
}
///
/// 检查资源是否在缓存中
///
/// 资源路径
/// 如果存在返回 true,否则返回 false
public bool Contains(string path)
{
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentException(PathCannotBeNullOrEmptyMessage, nameof(path));
return _cache.ContainsKey(path);
}
///
/// 从缓存中移除资源
///
/// 资源路径
/// 如果成功移除返回 true,否则返回 false
public bool Remove(string path)
{
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentException(PathCannotBeNullOrEmptyMessage, nameof(path));
return _cache.TryRemove(path, out _);
}
///
/// 清空所有缓存
///
public void Clear()
{
_cache.Clear();
}
///
/// 增加资源的引用计数
///
/// 资源路径
/// 如果成功增加返回 true,如果资源不存在返回 false
public bool AddReference(string path)
{
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentException(PathCannotBeNullOrEmptyMessage, nameof(path));
if (_cache.TryGetValue(path, out var entry))
{
lock (_lock)
{
entry.ReferenceCount++;
entry.LastAccessTime = DateTime.UtcNow;
}
return true;
}
return false;
}
///
/// 减少资源的引用计数
///
/// 资源路径
/// 减少后的引用计数,如果资源不存在返回 -1
public int RemoveReference(string path)
{
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentException(PathCannotBeNullOrEmptyMessage, nameof(path));
if (_cache.TryGetValue(path, out var entry))
{
lock (_lock)
{
entry.ReferenceCount--;
return entry.ReferenceCount;
}
}
return -1;
}
///
/// 获取资源的引用计数
///
/// 资源路径
/// 引用计数,如果资源不存在返回 -1
public int GetReferenceCount(string path)
{
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentException(PathCannotBeNullOrEmptyMessage, nameof(path));
if (_cache.TryGetValue(path, out var entry))
{
lock (_lock)
{
return entry.ReferenceCount;
}
}
return -1;
}
///
/// 获取所有已缓存资源的路径
///
/// 资源路径集合
public IEnumerable GetAllPaths()
{
return _cache.Keys.ToList();
}
///
/// 获取所有引用计数为 0 的资源路径
///
/// 资源路径集合
public IEnumerable GetUnreferencedPaths()
{
var unreferencedPaths = new List();
foreach (var kvp in _cache)
{
lock (_lock)
{
if (kvp.Value.ReferenceCount <= 0)
{
unreferencedPaths.Add(kvp.Key);
}
}
}
return unreferencedPaths;
}
}