Revert "框架更新"

This reverts commit a2cb248512.
This commit is contained in:
2025-10-29 22:41:19 +08:00
parent a2cb248512
commit 9572cf1955
429 changed files with 38758 additions and 7183 deletions

View File

@@ -0,0 +1,346 @@
using System;
using System.Collections.Generic;
using System.IO;
#pragma warning disable CS8625 // Cannot convert null literal to non-nullable reference type.
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
namespace Fantasy.DataStructure.Collection
{
/// 环形缓存自增式缓存自动扩充、不会收缩缓存、所以不要用这个操作过大的IO流
/// 1、环大小8192溢出的会自动增加环的大小。
/// 2、每个块都是一个环形缓存当溢出的时候会自动添加到下一个环中。
/// 3、当读取完成后用过的环会放在缓存中不会销毁掉。
/// <summary>
/// 自增式缓存类,继承自 Stream 和 IDisposable 接口。
/// 环形缓存具有自动扩充的特性,但不会收缩,适用于操作不过大的 IO 流。
/// </summary>
public sealed class CircularBuffer : Stream, IDisposable
{
private byte[] _lastBuffer;
/// <summary>
/// 环形缓存块的默认大小
/// </summary>
public const int ChunkSize = 8192;
private readonly Queue<byte[]> _bufferCache = new Queue<byte[]>();
private readonly Queue<byte[]> _bufferQueue = new Queue<byte[]>();
/// <summary>
/// 获取或设置环形缓存的第一个索引位置
/// </summary>
public int FirstIndex { get; set; }
/// <summary>
/// 获取或设置环形缓存的最后一个索引位置
/// </summary>
public int LastIndex { get; set; }
/// <summary>
/// 获取环形缓存的总长度
/// </summary>
public override long Length
{
get
{
if (_bufferQueue.Count == 0)
{
return 0;
}
return (_bufferQueue.Count - 1) * ChunkSize + LastIndex - FirstIndex;
}
}
/// <summary>
/// 获取环形缓存的第一个块
/// </summary>
public byte[] First
{
get
{
if (_bufferQueue.Count == 0)
{
AddLast();
}
return _bufferQueue.Peek();
}
}
/// <summary>
/// 获取环形缓存的最后一个块
/// </summary>
public byte[] Last
{
get
{
if (_bufferQueue.Count == 0)
{
AddLast();
}
return _lastBuffer;
}
}
/// <summary>
/// 向环形缓存中添加一个新的块
/// </summary>
public void AddLast()
{
var buffer = _bufferCache.Count > 0 ? _bufferCache.Dequeue() : new byte[ChunkSize];
_bufferQueue.Enqueue(buffer);
_lastBuffer = buffer;
}
/// <summary>
/// 从环形缓存中移除第一个块
/// </summary>
public void RemoveFirst()
{
_bufferCache.Enqueue(_bufferQueue.Dequeue());
}
/// <summary>
/// 从流中读取指定数量的数据到缓存。
/// </summary>
/// <param name="stream">源数据流。</param>
/// <param name="count">要读取的字节数。</param>
public void Read(Stream stream, int count)
{
if (count > Length)
{
throw new Exception($"bufferList length < count, {Length} {count}");
}
var copyCount = 0;
while (copyCount < count)
{
var n = count - copyCount;
if (ChunkSize - FirstIndex > n)
{
stream.Write(First, FirstIndex, n);
FirstIndex += n;
copyCount += n;
}
else
{
stream.Write(First, FirstIndex, ChunkSize - FirstIndex);
copyCount += ChunkSize - FirstIndex;
FirstIndex = 0;
RemoveFirst();
}
}
}
/// <summary>
/// 从缓存中读取指定数量的数据到内存。
/// </summary>
/// <param name="memory">目标内存。</param>
/// <param name="count">要读取的字节数。</param>
public void Read(Memory<byte> memory, int count)
{
if (count > Length)
{
throw new Exception($"bufferList length < count, {Length} {count}");
}
var copyCount = 0;
while (copyCount < count)
{
var n = count - copyCount;
var asMemory = First.AsMemory();
if (ChunkSize - FirstIndex > n)
{
var slice = asMemory.Slice(FirstIndex, n);
slice.CopyTo(memory.Slice(copyCount, n));
FirstIndex += n;
copyCount += n;
}
else
{
var length = ChunkSize - FirstIndex;
var slice = asMemory.Slice(FirstIndex, length);
slice.CopyTo(memory.Slice(copyCount, length));
copyCount += ChunkSize - FirstIndex;
FirstIndex = 0;
RemoveFirst();
}
}
}
/// <summary>
/// 从自定义流中读取数据到指定的缓冲区。
/// </summary>
/// <param name="buffer">目标缓冲区,用于存储读取的数据。</param>
/// <param name="offset">目标缓冲区中的起始偏移量。</param>
/// <param name="count">要读取的字节数。</param>
/// <returns>实际读取的字节数。</returns>
public override int Read(byte[] buffer, int offset, int count)
{
if (buffer.Length < offset + count)
{
throw new Exception($"buffer length < count, buffer length: {buffer.Length} {offset} {count}");
}
var length = Length;
if (length < count)
{
count = (int) length;
}
var copyCount = 0;
// 循环直到成功读取所需的字节数
while (copyCount < count)
{
var copyLength = count - copyCount;
if (ChunkSize - FirstIndex > copyLength)
{
// 将数据从当前块的缓冲区复制到目标缓冲区
Array.Copy(First, FirstIndex, buffer, copyCount + offset, copyLength);
FirstIndex += copyLength;
copyCount += copyLength;
continue;
}
// 复制当前块中剩余的数据,并切换到下一个块
Array.Copy(First, FirstIndex, buffer, copyCount + offset, ChunkSize - FirstIndex);
copyCount += ChunkSize - FirstIndex;
FirstIndex = 0;
RemoveFirst();
}
return count;
}
/// <summary>
/// 将数据从给定的字节数组写入流中。
/// </summary>
/// <param name="buffer">包含要写入的数据的字节数组。</param>
public void Write(byte[] buffer)
{
Write(buffer, 0, buffer.Length);
}
/// <summary>
/// 将数据从给定的流写入流中。
/// </summary>
/// <param name="stream">包含要写入的数据的流。</param>
public void Write(Stream stream)
{
var copyCount = 0;
var count = (int) (stream.Length - stream.Position);
while (copyCount < count)
{
if (LastIndex == ChunkSize)
{
AddLast();
LastIndex = 0;
}
var n = count - copyCount;
if (ChunkSize - LastIndex > n)
{
_ = stream.Read(Last, LastIndex, n);
LastIndex += count - copyCount;
copyCount += n;
}
else
{
_ = stream.Read(Last, LastIndex, ChunkSize - LastIndex);
copyCount += ChunkSize - LastIndex;
LastIndex = ChunkSize;
}
}
}
/// <summary>
/// 将数据从给定的字节数组写入流中。
/// </summary>
/// <param name="buffer">包含要写入的数据的字节数组。</param>
/// <param name="offset">开始写入的缓冲区中的索引。</param>
/// <param name="count">要写入的字节数。</param>
public override void Write(byte[] buffer, int offset, int count)
{
var copyCount = 0;
while (copyCount < count)
{
if (ChunkSize == LastIndex)
{
AddLast();
LastIndex = 0;
}
var byteLength = count - copyCount;
if (ChunkSize - LastIndex > byteLength)
{
Array.Copy(buffer, copyCount + offset, Last, LastIndex, byteLength);
LastIndex += byteLength;
copyCount += byteLength;
}
else
{
Array.Copy(buffer, copyCount + offset, Last, LastIndex, ChunkSize - LastIndex);
copyCount += ChunkSize - LastIndex;
LastIndex = ChunkSize;
}
}
}
/// <summary>
/// 获取一个值,指示流是否支持读取操作。
/// </summary>
public override bool CanRead { get; } = true;
/// <summary>
/// 获取一个值,指示流是否支持寻找操作。
/// </summary>
public override bool CanSeek { get; } = false;
/// <summary>
/// 获取一个值,指示流是否支持写入操作。
/// </summary>
public override bool CanWrite { get; } = true;
/// <summary>
/// 获取或设置流中的位置。
/// </summary>
public override long Position { get; set; }
/// <summary>
/// 刷新流(在此实现中引发未实现异常)。
/// </summary>
public override void Flush()
{
throw new NotImplementedException();
}
/// <summary>
/// 在流中寻找特定位置(在此实现中引发未实现异常)。
/// </summary>
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
/// <summary>
/// 设置流的长度(在此实现中引发未实现异常)。
/// </summary>
public override void SetLength(long value)
{
throw new NotImplementedException();
}
/// <summary>
/// 释放 CustomStream 使用的所有资源。
/// </summary>
public new void Dispose()
{
_bufferQueue.Clear();
_lastBuffer = null;
FirstIndex = 0;
LastIndex = 0;
base.Dispose();
}
}
}

View File

@@ -0,0 +1,197 @@
#if !FANTASY_WEBGL
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Fantasy.Pool;
#pragma warning disable CS8603 // Possible null reference return.
namespace Fantasy.DataStructure.Collection
{
/// <summary>
/// 并发的一对多列表池,用于维护具有相同键的多个值的关联关系,实现了 <see cref="IDisposable"/> 接口。
/// </summary>
/// <typeparam name="TKey">关键字的类型,不能为空。</typeparam>
/// <typeparam name="TValue">值的类型。</typeparam>
public class ConcurrentOneToManyListPool<TKey, TValue> : ConcurrentOneToManyList<TKey, TValue>, IDisposable, IPool where TKey : notnull
{
private bool _isPool;
private bool _isDispose;
/// <summary>
/// 创建一个 <see cref="ConcurrentOneToManyListPool{TKey, TValue}"/> 的实例。
/// </summary>
/// <returns>创建的实例。</returns>
public static ConcurrentOneToManyListPool<TKey, TValue> Create()
{
var a = MultiThreadPool.Rent<ConcurrentOneToManyListPool<TKey, TValue>>();
a._isDispose = false;
a._isPool = true;
return a;
}
/// <summary>
/// 释放实例占用的资源。
/// </summary>
public void Dispose()
{
if (_isDispose)
{
return;
}
_isDispose = true;
// 清空实例的数据
Clear();
// 将实例返回到池中以便重用
MultiThreadPool.Return(this);
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
/// <summary>
/// 并发的一对多列表,用于维护具有相同键的多个值的关联关系。
/// </summary>
/// <typeparam name="TKey">关键字的类型,不能为空。</typeparam>
/// <typeparam name="TValue">值的类型。</typeparam>
public class ConcurrentOneToManyList<TKey, TValue> : ConcurrentDictionary<TKey, List<TValue>> where TKey : notnull
{
private readonly Queue<List<TValue>> _queue = new Queue<List<TValue>>();
private readonly int _recyclingLimit = 120;
/// <summary>
/// 初始化 <see cref="ConcurrentOneToManyList{TKey, TValue}"/> 类的新实例。
/// </summary>
public ConcurrentOneToManyList()
{
}
/// <summary>
/// 设置最大缓存数量
/// </summary>
/// <param name="recyclingLimit">
/// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC.
/// 2:设置成0不控制数量全部缓存
/// </param>
public ConcurrentOneToManyList(int recyclingLimit)
{
_recyclingLimit = recyclingLimit;
}
/// <summary>
/// 判断指定键的列表是否包含指定值。
/// </summary>
/// <param name="key">要搜索的键。</param>
/// <param name="value">要搜索的值。</param>
/// <returns>如果列表包含值,则为 true否则为 false。</returns>
public bool Contains(TKey key, TValue value)
{
TryGetValue(key, out var list);
return list != null && list.Contains(value);
}
/// <summary>
/// 向指定键的列表中添加一个值。
/// </summary>
/// <param name="key">要添加值的键。</param>
/// <param name="value">要添加的值。</param>
public void Add(TKey key, TValue value)
{
if (!TryGetValue(key, out var list))
{
list = Fetch();
list.Add(value);
base[key] = list;
return;
}
list.Add(value);
}
/// <summary>
/// 获取指定键的列表中的第一个值。
/// </summary>
/// <param name="key">要获取第一个值的键。</param>
/// <returns>指定键的列表中的第一个值,如果不存在则为默认值。</returns>
public TValue First(TKey key)
{
return !TryGetValue(key, out var list) ? default : list.FirstOrDefault();
}
/// <summary>
/// 从指定键的列表中移除一个值。
/// </summary>
/// <param name="key">要移除值的键。</param>
/// <param name="value">要移除的值。</param>
public void RemoveValue(TKey key, TValue value)
{
if (!TryGetValue(key, out var list)) return;
list.Remove(value);
if (list.Count == 0) RemoveKey(key);
}
/// <summary>
/// 从字典中移除指定键以及其关联的列表。
/// </summary>
/// <param name="key">要移除的键。</param>
public void RemoveKey(TKey key)
{
if (!TryRemove(key, out var list)) return;
Recycle(list);
}
/// <summary>
/// 从队列中获取一个列表,如果队列为空则创建一个新的列表。
/// </summary>
/// <returns>获取的列表。</returns>
private List<TValue> Fetch()
{
return _queue.Count <= 0 ? new List<TValue>() : _queue.Dequeue();
}
/// <summary>
/// 将一个列表回收到队列中。
/// </summary>
/// <param name="list">要回收的列表。</param>
private void Recycle(List<TValue> list)
{
list.Clear();
if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return;
_queue.Enqueue(list);
}
/// <summary>
/// 清空当前类的数据,包括从基类继承的数据以及自定义的数据队列。
/// </summary>
protected new void Clear()
{
base.Clear();
_queue.Clear();
}
}
}
#endif

View File

@@ -0,0 +1,194 @@
#if !FANTASY_WEBGL
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Fantasy.Pool;
#pragma warning disable CS8603
namespace Fantasy.DataStructure.Collection
{
/// <summary>
/// 表示一个并发的一对多队列池,用于维护具有相同键的多个值的关联关系,实现了 <see cref="IDisposable"/> 接口。
/// </summary>
/// <typeparam name="TKey">关键字的类型,不能为空。</typeparam>
/// <typeparam name="TValue">值的类型。</typeparam>
public class ConcurrentOneToManyQueuePool<TKey, TValue> : ConcurrentOneToManyQueue<TKey, TValue>, IDisposable, IPool where TKey : notnull
{
private bool _isPool;
private bool _isDispose;
/// <summary>
/// 创建并返回一个 <see cref="ConcurrentOneToManyQueuePool{TKey, TValue}"/> 的实例。
/// </summary>
/// <returns>创建的实例。</returns>
public static ConcurrentOneToManyQueuePool<TKey, TValue> Create()
{
var a = MultiThreadPool.Rent<ConcurrentOneToManyQueuePool<TKey, TValue>>();
a._isDispose = false;
a._isPool = true;
return a;
}
/// <summary>
/// 释放当前实例所占用的资源,并将实例返回到对象池中,以便重用。
/// </summary>
public void Dispose()
{
if (_isDispose)
{
return;
}
_isDispose = true;
Clear();
// 将实例返回到对象池中,以便重用
MultiThreadPool.Return(this);
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
/// <summary>
/// 表示一个并发的一对多队列,用于维护具有相同键的多个值的关联关系。
/// </summary>
/// <typeparam name="TKey">关键字的类型,不能为空。</typeparam>
/// <typeparam name="TValue">值的类型。</typeparam>
public class ConcurrentOneToManyQueue<TKey, TValue> : ConcurrentDictionary<TKey, Queue<TValue>> where TKey : notnull
{
private readonly Queue<Queue<TValue>> _queue = new Queue<Queue<TValue>>();
private readonly int _recyclingLimit;
/// <summary>
/// 设置最大缓存数量
/// </summary>
/// <param name="recyclingLimit">
/// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC.
/// 2:设置成0不控制数量全部缓存
/// </param>
public ConcurrentOneToManyQueue(int recyclingLimit = 0)
{
_recyclingLimit = recyclingLimit;
}
/// <summary>
/// 判断指定键的队列是否包含指定值。
/// </summary>
/// <param name="key">要搜索的键。</param>
/// <param name="value">要搜索的值。</param>
/// <returns>如果队列包含值,则为 true否则为 false。</returns>
public bool Contains(TKey key, TValue value)
{
TryGetValue(key, out var list);
return list != null && list.Contains(value);
}
/// <summary>
/// 向指定键的队列中添加一个值。
/// </summary>
/// <param name="key">要添加值的键。</param>
/// <param name="value">要添加的值。</param>
public void Enqueue(TKey key, TValue value)
{
if (!TryGetValue(key, out var list))
{
list = Fetch();
list.Enqueue(value);
TryAdd(key, list);
return;
}
list.Enqueue(value);
}
/// <summary>
/// 从指定键的队列中出队并返回一个值。
/// </summary>
/// <param name="key">要出队的键。</param>
/// <returns>出队的值,如果队列为空则为默认值。</returns>
public TValue Dequeue(TKey key)
{
if (!TryGetValue(key, out var list) || list.Count == 0) return default;
var value = list.Dequeue();
if (list.Count == 0) RemoveKey(key);
return value;
}
/// <summary>
/// 尝试从指定键的队列中出队一个值。
/// </summary>
/// <param name="key">要出队的键。</param>
/// <param name="value">出队的值,如果队列为空则为默认值。</param>
/// <returns>如果成功出队,则为 true否则为 false。</returns>
public bool TryDequeue(TKey key, out TValue value)
{
value = Dequeue(key);
return value != null;
}
/// <summary>
/// 从字典中移除指定键以及其关联的队列。
/// </summary>
/// <param name="key">要移除的键。</param>
public void RemoveKey(TKey key)
{
if (!TryGetValue(key, out var list)) return;
TryRemove(key, out _);
Recycle(list);
}
/// <summary>
/// 从队列中获取一个新的队列,如果队列为空则创建一个新的队列。
/// </summary>
/// <returns>获取的队列。</returns>
private Queue<TValue> Fetch()
{
return _queue.Count <= 0 ? new Queue<TValue>() : _queue.Dequeue();
}
/// <summary>
/// 将一个队列回收到队列池中。
/// </summary>
/// <param name="list">要回收的队列。</param>
private void Recycle(Queue<TValue> list)
{
list.Clear();
if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return;
_queue.Enqueue(list);
}
/// <summary>
/// 清空当前类的数据,包括从基类继承的键值对字典中的数据以及自定义的队列池。
/// </summary>
protected new void Clear()
{
base.Clear();
_queue.Clear();
}
}
}
#endif

View File

@@ -0,0 +1,134 @@
using System;
using System.Collections.Generic;
using Fantasy.Pool;
namespace Fantasy.DataStructure.Collection
{
/// <summary>
/// 可释放的哈希集合对象池。
/// </summary>
/// <typeparam name="T">哈希集合中元素的类型。</typeparam>
public sealed class HashSetPool<T> : HashSet<T>, IDisposable, IPool
{
private bool _isPool;
private bool _isDispose;
/// <summary>
/// 释放实例所占用的资源,并将实例返回到对象池中,以便重用。
/// </summary>
public void Dispose()
{
if (_isDispose)
{
return;
}
_isDispose = true;
Clear();
#if FANTASY_WEBGL
Pool<HashSetPool<T>>.Return(this);
#else
MultiThreadPool.Return(this);
#endif
}
/// <summary>
/// 创建一个 <see cref="HashSetPool{T}"/> 哈希集合池的实例。
/// </summary>
/// <returns>创建的实例。</returns>
public static HashSetPool<T> Create()
{
#if FANTASY_WEBGL
var list = Pool<HashSetPool<T>>.Rent();
list._isDispose = false;
list._isPool = true;
return list;
#else
var list = MultiThreadPool.Rent<HashSetPool<T>>();
list._isDispose = false;
list._isPool = true;
return list;
#endif
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
/// <summary>
/// 基本哈希集合对象池,他自持有实际的哈希集合。
/// </summary>
/// <typeparam name="T">哈希集合中元素的类型。</typeparam>
public sealed class HashSetBasePool<T> : IDisposable, IPool
{
private bool _isPool;
/// <summary>
/// 存储实际的哈希集合
/// </summary>
public HashSet<T> Set = new HashSet<T>();
/// <summary>
/// 创建一个 <see cref="HashSetBasePool{T}"/> 基本哈希集合对象池的实例。
/// </summary>
/// <returns>创建的实例。</returns>
public static HashSetBasePool<T> Create()
{
#if FANTASY_WEBGL
var hashSetBasePool = Pool<HashSetBasePool<T>>.Rent();
hashSetBasePool._isPool = true;
return hashSetBasePool;
#else
var hashSetBasePool = MultiThreadPool.Rent<HashSetBasePool<T>>();
hashSetBasePool._isPool = true;
return hashSetBasePool;
#endif
}
/// <summary>
/// 释放实例所占用的资源,并将实例返回到对象池中,以便重用。
/// </summary>
public void Dispose()
{
Set.Clear();
#if FANTASY_WEBGL
Pool<HashSetBasePool<T>>.Return(this);
#else
MultiThreadPool.Return(this);
#endif
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using Fantasy.Pool;
// ReSharper disable ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
namespace Fantasy.DataStructure.Collection
{
/// <summary>
/// 可释放的列表List对象池。
/// </summary>
/// <typeparam name="T">列表中元素的类型。</typeparam>
public sealed class ListPool<T> : List<T>, IDisposable, IPool
{
private bool _isPool;
private bool _isDispose;
/// <summary>
/// 释放实例所占用的资源,并将实例返回到对象池中,以便重用。
/// </summary>
public void Dispose()
{
if (_isDispose)
{
return;
}
_isDispose = true;
Clear();
#if FANTASY_WEBGL
Pool<ListPool<T>>.Return(this);
#else
MultiThreadPool.Return(this);
#endif
}
/// <summary>
/// 使用指定的元素创建一个 <see cref="ListPool{T}"/> 列表List对象池的实例。
/// </summary>
/// <param name="args">要添加到列表的元素。</param>
/// <returns>创建的实例。</returns>
public static ListPool<T> Create(params T[] args)
{
#if FANTASY_WEBGL
var list = Pool<ListPool<T>>.Rent();
#else
var list = MultiThreadPool.Rent<ListPool<T>>();
#endif
list._isDispose = false;
list._isPool = true;
if (args != null)
{
list.AddRange(args);
}
return list;
}
/// <summary>
/// 使用指定的列表创建一个 <see cref="ListPool{T}"/> 列表List对象池的实例。
/// </summary>
/// <param name="args">要添加到列表的元素列表。</param>
/// <returns>创建的实例。</returns>
public static ListPool<T> Create(List<T> args)
{
#if FANTASY_WEBGL
var list = Pool<ListPool<T>>.Rent();
#else
var list = MultiThreadPool.Rent<ListPool<T>>();
#endif
list._isDispose = false;
list._isPool = true;
if (args != null)
{
list.AddRange(args);
}
return list;
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
}

View File

@@ -0,0 +1,208 @@
using System;
using System.Collections.Generic;
using Fantasy.Pool;
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
namespace Fantasy.DataStructure.Collection
{
/// <summary>
/// 一对多哈希集合OneToManyHashSet对象池。
/// </summary>
/// <typeparam name="TKey">键的类型。</typeparam>
/// <typeparam name="TValue">值的类型。</typeparam>
public class OneToManyHashSetPool<TKey, TValue> : OneToManyHashSet<TKey, TValue>, IDisposable, IPool where TKey : notnull
{
private bool _isPool;
private bool _isDispose;
/// <summary>
/// 创建一个 <see cref="OneToManyHashSetPool{TKey, TValue}"/> 一对多哈希集合OneToManyHashSet对象池的实例。
/// </summary>
/// <returns>创建的实例。</returns>
public static OneToManyHashSetPool<TKey, TValue> Create()
{
#if FANTASY_WEBGL
var a = Pool<OneToManyHashSetPool<TKey, TValue>>.Rent();
#else
var a = MultiThreadPool.Rent<OneToManyHashSetPool<TKey, TValue>>();
#endif
a._isDispose = false;
a._isPool = true;
return a;
}
/// <summary>
/// 释放实例所占用的资源,并将实例返回到对象池中,以便重用。
/// </summary>
public void Dispose()
{
if (_isDispose)
{
return;
}
_isDispose = true;
Clear();
#if FANTASY_WEBGL
Pool<OneToManyHashSetPool<TKey, TValue>>.Return(this);
#else
MultiThreadPool.Return(this);
#endif
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
/// <summary>
/// 一对多哈希集合OneToManyHashSet用于创建和管理键对应多个值的集合。
/// </summary>
/// <typeparam name="TKey">键的类型。</typeparam>
/// <typeparam name="TValue">值的类型。</typeparam>
public class OneToManyHashSet<TKey, TValue> : Dictionary<TKey, HashSet<TValue>> where TKey : notnull
{
/// 用于回收和重用的空闲值集合队列。
private readonly Queue<HashSet<TValue>> _queue = new Queue<HashSet<TValue>>();
/// 设置最大回收限制,用于控制值集合的最大数量。
private readonly int _recyclingLimit = 120;
/// 一个空的、不包含任何元素的哈希集合,用于在查找失败时返回。
private static HashSet<TValue> _empty = new HashSet<TValue>();
/// <summary>
/// 初始化 <see cref="OneToManyHashSet{TKey, TValue}"/> 类的新实例。
/// </summary>
public OneToManyHashSet() { }
/// <summary>
/// 设置最大缓存数量
/// </summary>
/// <param name="recyclingLimit">
/// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC.
/// 2:设置成0不控制数量全部缓存
/// </param>
public OneToManyHashSet(int recyclingLimit)
{
_recyclingLimit = recyclingLimit;
}
/// <summary>
/// 判断指定的键值对是否存在于集合中。
/// </summary>
/// <param name="key">键。</param>
/// <param name="value">值。</param>
/// <returns>如果存在则为 true否则为 false。</returns>
public bool Contains(TKey key, TValue value)
{
TryGetValue(key, out var list);
return list != null && list.Contains(value);
}
/// <summary>
/// 添加指定的键值对到集合中。
/// </summary>
/// <param name="key">键。</param>
/// <param name="value">值。</param>
public void Add(TKey key, TValue value)
{
if (!TryGetValue(key, out var list))
{
list = Fetch();
list.Add(value);
Add(key, list);
return;
}
list.Add(value);
}
/// <summary>
/// 从集合中移除指定键对应的值。
/// </summary>
/// <param name="key">键。</param>
/// <param name="value">要移除的值。</param>
public void RemoveValue(TKey key, TValue value)
{
if (!TryGetValue(key, out var list)) return;
list.Remove(value);
if (list.Count == 0) RemoveKey(key);
}
/// <summary>
/// 从集合中移除指定键及其对应的值集合。
/// </summary>
/// <param name="key">键。</param>
public void RemoveKey(TKey key)
{
if (!TryGetValue(key, out var list)) return;
Remove(key);
Recycle(list);
}
/// <summary>
/// 获取指定键对应的值集合,如果不存在则返回一个空的哈希集合。
/// </summary>
/// <param name="key">键。</param>
/// <returns>对应的值集合或空的哈希集合。</returns>
public HashSet<TValue> GetValue(TKey key)
{
if (TryGetValue(key, out HashSet<TValue> value))
{
return value;
}
return _empty;
}
/// <summary>
/// 从队列中获取一个空闲的值集合,或者创建一个新的。
/// </summary>
/// <returns>值集合。</returns>
private HashSet<TValue> Fetch()
{
return _queue.Count <= 0 ? new HashSet<TValue>() : _queue.Dequeue();
}
/// <summary>
/// 回收值集合到队列中,以便重复利用。
/// </summary>
/// <param name="list">要回收的值集合。</param>
private void Recycle(HashSet<TValue> list)
{
list.Clear();
if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return;
_queue.Enqueue(list);
}
/// <summary>
/// 清空集合中的数据并和队列。
/// </summary>
protected new void Clear()
{
base.Clear();
_queue.Clear();
}
}
}

View File

@@ -0,0 +1,232 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Fantasy.Pool;
#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type.
#pragma warning disable CS8603 // Possible null reference return.
namespace Fantasy.DataStructure.Collection
{
/// <summary>
/// 可回收的、一对多关系的列表池。
/// </summary>
/// <typeparam name="TKey">键的类型。</typeparam>
/// <typeparam name="TValue">值的类型。</typeparam>
public class OneToManyListPool<TKey, TValue> : OneToManyList<TKey, TValue>, IDisposable, IPool where TKey : notnull
{
private bool _isPool;
private bool _isDispose;
/// <summary>
/// 创建一个 <see cref="OneToManyListPool{TKey, TValue}"/> 一对多关系的列表池的实例。
/// </summary>
/// <returns>创建的实例。</returns>
public static OneToManyListPool<TKey, TValue> Create()
{
#if FANTASY_WEBGL || FANTASY_EXPORTER
var list = Pool<OneToManyListPool<TKey, TValue>>.Rent();
#else
var list = MultiThreadPool.Rent<OneToManyListPool<TKey, TValue>>();
#endif
list._isDispose = false;
list._isPool = true;
return list;
}
/// <summary>
/// 释放当前对象所占用的资源,并将对象回收到对象池中。
/// </summary>
public void Dispose()
{
if (_isDispose)
{
return;
}
_isDispose = true;
Clear();
#if FANTASY_WEBGL || FANTASY_EXPORTER
Pool<OneToManyListPool<TKey, TValue>>.Return(this);
#else
MultiThreadPool.Return(this);
#endif
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
/// <summary>
/// 一对多关系的列表字典。
/// </summary>
/// <typeparam name="TKey">键的类型。</typeparam>
/// <typeparam name="TValue">值的类型。</typeparam>
public class OneToManyList<TKey, TValue> : Dictionary<TKey, List<TValue>> where TKey : notnull
{
private readonly int _recyclingLimit = 120;
private static readonly List<TValue> Empty = new List<TValue>();
private readonly Queue<List<TValue>> _queue = new Queue<List<TValue>>();
/// <summary>
/// 初始化一个新的 <see cref="OneToManyList{TKey, TValue}"/> 实例。
/// </summary>
public OneToManyList() { }
/// <summary>
/// 设置最大缓存数量
/// </summary>
/// <param name="recyclingLimit">
/// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC.
/// 2:设置成0不控制数量全部缓存
/// </param>
public OneToManyList(int recyclingLimit)
{
_recyclingLimit = recyclingLimit;
}
/// <summary>
/// 判断给定的键和值是否存在于列表中。
/// </summary>
/// <param name="key">要搜索的键。</param>
/// <param name="value">要搜索的值。</param>
/// <returns>如果存在则为 <see langword="true"/>,否则为 <see langword="false"/>。</returns>
public bool Contains(TKey key, TValue value)
{
TryGetValue(key, out var list);
return list != null && list.Contains(value);
}
/// <summary>
/// 向列表中添加指定键和值。
/// </summary>
/// <param name="key">要添加值的键。</param>
/// <param name="value">要添加的值。</param>
public void Add(TKey key, TValue value)
{
if (!TryGetValue(key, out var list))
{
list = Fetch();
list.Add(value);
Add(key, list);
return;
}
list.Add(value);
}
/// <summary>
/// 获取指定键对应的列表中的第一个值。
/// </summary>
/// <param name="key">要获取值的键。</param>
/// <returns>键对应的列表中的第一个值。</returns>
public TValue First(TKey key)
{
return !TryGetValue(key, out var list) ? default : list.FirstOrDefault();
}
/// <summary>
/// 从列表中移除指定键和值。
/// </summary>
/// <param name="key">要移除值的键。</param>
/// <param name="value">要移除的值。</param>
/// <returns>如果成功移除则为 <see langword="true"/>,否则为 <see langword="false"/>。</returns>
public bool RemoveValue(TKey key, TValue value)
{
if (!TryGetValue(key, out var list))
{
return true;
}
var isRemove = list.Remove(value);
if (list.Count == 0)
{
isRemove = RemoveByKey(key);
}
return isRemove;
}
/// <summary>
/// 从列表中移除指定键及其关联的所有值。
/// </summary>
/// <param name="key">要移除的键。</param>
/// <returns>如果成功移除则为 <see langword="true"/>,否则为 <see langword="false"/>。</returns>
public bool RemoveByKey(TKey key)
{
if (!TryGetValue(key, out var list))
{
return false;
}
Remove(key);
Recycle(list);
return true;
}
/// <summary>
/// 获取指定键关联的所有值的列表。
/// </summary>
/// <param name="key">要获取值的键。</param>
/// <returns>键关联的所有值的列表。</returns>
public List<TValue> GetValues(TKey key)
{
if (TryGetValue(key, out List<TValue> list))
{
return list;
}
return Empty;
}
/// <summary>
/// 清除字典中的所有键值对,并回收相关的值集合。
/// </summary>
public new void Clear()
{
foreach (var keyValuePair in this) Recycle(keyValuePair.Value);
base.Clear();
}
/// <summary>
/// 从空闲值集合队列中获取一个值集合,如果队列为空则创建一个新的值集合。
/// </summary>
/// <returns>从队列中获取的值集合。</returns>
private List<TValue> Fetch()
{
return _queue.Count <= 0 ? new List<TValue>() : _queue.Dequeue();
}
/// <summary>
/// 回收一个不再使用的值集合到空闲值集合队列中。
/// </summary>
/// <param name="list">要回收的值集合。</param>
private void Recycle(List<TValue> list)
{
list.Clear();
if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return;
_queue.Enqueue(list);
}
}
}

View File

@@ -0,0 +1,204 @@
using System;
using System.Collections.Generic;
using Fantasy.Pool;
#pragma warning disable CS8603
namespace Fantasy.DataStructure.Collection
{
/// <summary>
/// 支持一对多关系的队列池,用于存储具有相同键的值的队列集合。
/// </summary>
/// <typeparam name="TKey">键的类型。</typeparam>
/// <typeparam name="TValue">值的类型。</typeparam>
public class OneToManyQueuePool<TKey, TValue> : OneToManyQueue<TKey, TValue>, IDisposable, IPool where TKey : notnull
{
private bool _isPool;
private bool _isDispose;
/// <summary>
/// 创建一个 <see cref="OneToManyQueuePool{TKey, TValue}"/> 一对多关系的队列池的实例。
/// </summary>
/// <returns>创建的实例。</returns>
public static OneToManyQueuePool<TKey, TValue> Create()
{
#if FANTASY_WEBGL
var a = Pool<OneToManyQueuePool<TKey, TValue>>.Rent();
#else
var a = MultiThreadPool.Rent<OneToManyQueuePool<TKey, TValue>>();
#endif
a._isDispose = false;
a._isPool = true;
return a;
}
/// <summary>
/// 释放当前实例所占用的资源,并将实例回收到对象池中。
/// </summary>
public void Dispose()
{
if (_isDispose)
{
return;
}
_isDispose = true;
Clear();
#if FANTASY_WEBGL
Pool<OneToManyQueuePool<TKey, TValue>>.Return(this);
#else
MultiThreadPool.Return(this);
#endif
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
/// <summary>
/// 支持一对多关系的队列,用于存储具有相同键的值的队列集合。
/// </summary>
/// <typeparam name="TKey">键的类型。</typeparam>
/// <typeparam name="TValue">值的类型。</typeparam>
public class OneToManyQueue<TKey, TValue> : Dictionary<TKey, Queue<TValue>> where TKey : notnull
{
private readonly Queue<Queue<TValue>> _queue = new Queue<Queue<TValue>>();
private readonly int _recyclingLimit;
/// <summary>
/// 创建一个 <see cref="OneToManyQueue{TKey, TValue}"/> 一对多关系的队列的实例。设置最大缓存数量
/// </summary>
/// <param name="recyclingLimit">
/// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC.
/// 2:设置成0不控制数量全部缓存
/// </param>
public OneToManyQueue(int recyclingLimit = 0)
{
_recyclingLimit = recyclingLimit;
}
/// <summary>
/// 判断指定键的值队列是否包含指定的值。
/// </summary>
/// <param name="key">要查找的键。</param>
/// <param name="value">要查找的值。</param>
/// <returns>如果存在,则为 <c>true</c>;否则为 <c>false</c>。</returns>
public bool Contains(TKey key, TValue value)
{
TryGetValue(key, out var list);
return list != null && list.Contains(value);
}
/// <summary>
/// 将指定的值添加到指定键的值队列中。
/// </summary>
/// <param name="key">要添加值的键。</param>
/// <param name="value">要添加的值。</param>
public void Enqueue(TKey key, TValue value)
{
if (!TryGetValue(key, out var list))
{
list = Fetch();
list.Enqueue(value);
Add(key, list);
return;
}
list.Enqueue(value);
}
/// <summary>
/// 从指定键的值队列中出队一个值。
/// </summary>
/// <param name="key">要出队的键。</param>
/// <returns>出队的值。</returns>
public TValue Dequeue(TKey key)
{
if (!TryGetValue(key, out var list) || list.Count == 0)
{
return default;
}
var value = list.Dequeue();
if (list.Count == 0)
{
RemoveKey(key);
}
return value;
}
/// <summary>
/// 尝试从指定键的值队列中出队一个值。
/// </summary>
/// <param name="key">要出队的键。</param>
/// <param name="value">出队的值。</param>
/// <returns>如果成功出队,则为 <c>true</c>;否则为 <c>false</c>。</returns>
public bool TryDequeue(TKey key, out TValue value)
{
value = Dequeue(key);
return value != null;
}
/// <summary>
/// 从字典中移除指定键及其对应的值队列。
/// </summary>
/// <param name="key">要移除的键。</param>
public void RemoveKey(TKey key)
{
if (!TryGetValue(key, out var list)) return;
Remove(key);
Recycle(list);
}
/// <summary>
/// 从队列池中获取一个值队列。如果队列池为空,则创建一个新的值队列。
/// </summary>
/// <returns>获取的值队列。</returns>
private Queue<TValue> Fetch()
{
return _queue.Count <= 0 ? new Queue<TValue>() : _queue.Dequeue();
}
/// <summary>
/// 回收一个不再使用的值队列到队列池中,以便重用。
/// </summary>
/// <param name="list">要回收的值队列。</param>
private void Recycle(Queue<TValue> list)
{
list.Clear();
if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return;
_queue.Enqueue(list);
}
/// <summary>
/// 清空当前实例的数据,同时回收所有值队列。
/// </summary>
protected new void Clear()
{
base.Clear();
_queue.Clear();
}
}
}

View File

@@ -0,0 +1,69 @@
using System;
using System.Collections.Generic;
using Fantasy.Pool;
namespace Fantasy.DataStructure.Collection
{
/// <summary>
/// 可重用的列表,继承自 <see cref="List{T}"/> 类。该类支持通过对象池重用列表实例,以减少对象分配和释放的开销。
/// </summary>
/// <typeparam name="T">列表中元素的类型。</typeparam>
public sealed class ReuseList<T> : List<T>, IDisposable, IPool
{
private bool _isPool;
private bool _isDispose;
/// <summary>
/// 创建一个 <see cref="ReuseList{T}"/> 可重用的列表的实例。
/// </summary>
/// <returns>创建的实例。</returns>
public static ReuseList<T> Create()
{
#if FANTASY_WEBGL
var list = Pool<ReuseList<T>>.Rent();
#else
var list = MultiThreadPool.Rent<ReuseList<T>>();
#endif
list._isDispose = false;
list._isPool = true;
return list;
}
/// <summary>
/// 释放该实例所占用的资源,并将实例返回到对象池中,以便重用。
/// </summary>
public void Dispose()
{
if (_isDispose)
{
return;
}
_isDispose = true;
Clear();
#if FANTASY_WEBGL
Pool<ReuseList<T>>.Return(this);
#else
MultiThreadPool.Return(this);
#endif
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
}

View File

@@ -0,0 +1,226 @@
#if !FANTASY_WEBGL
using System;
using System.Collections.Generic;
using System.Linq;
using Fantasy.Pool;
#pragma warning disable CS8603
namespace Fantasy.DataStructure.Collection
{
/// <summary>
/// 基于排序字典和并发集合实现的一对多映射列表的对象池包装类,继承自 <see cref="SortedConcurrentOneToManyList{TKey, TValue}"/> 类,
/// 同时实现了 <see cref="IDisposable"/> 接口,以支持对象的重用和释放。
/// </summary>
/// <typeparam name="TKey">键的类型。</typeparam>
/// <typeparam name="TValue">值的类型。</typeparam>
public class SortedConcurrentOneToManyListPool<TKey, TValue> : SortedConcurrentOneToManyList<TKey, TValue>, IDisposable, IPool where TKey : notnull
{
private bool _isPool;
private bool _isDispose;
/// <summary>
/// 创建一个新的 <see cref="SortedConcurrentOneToManyListPool{TKey, TValue}"/> 实例,使用默认的参数设置。
/// </summary>
/// <returns>新创建的 <see cref="SortedConcurrentOneToManyListPool{TKey, TValue}"/> 实例。</returns>
public static SortedConcurrentOneToManyListPool<TKey, TValue> Create()
{
var a = MultiThreadPool.Rent<SortedConcurrentOneToManyListPool<TKey, TValue>>();
a._isDispose = false;
a._isPool = true;
return a;
}
/// <summary>
/// 释放当前对象池实例,将其返回到对象池以供重用。
/// </summary>
public void Dispose()
{
if (_isDispose)
{
return;
}
_isDispose = true;
Clear();
MultiThreadPool.Return(this);
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
/// <summary>
/// 基于排序字典和并发集合实现的一多对映射列表类,继承自 <see cref="SortedDictionary{TKey, TValue}"/> 类,
/// 用于在多个值与一个键关联的情况下进行管理和存储。该类支持并发操作,适用于多线程环境。
/// </summary>
/// <typeparam name="TKey">键的类型。</typeparam>
/// <typeparam name="TValue">值的类型。</typeparam>
public class SortedConcurrentOneToManyList<TKey, TValue> : SortedDictionary<TKey, List<TValue>> where TKey : notnull
{
/// 用于同步操作的锁对象,它确保在多线程环境下对数据的安全访问。
private readonly object _lockObject = new object();
/// 用于存储缓存的队列。
private readonly Queue<List<TValue>> _queue = new Queue<List<TValue>>();
/// 控制缓存回收的限制。当缓存的数量超过此限制时,旧的缓存将会被回收。
private readonly int _recyclingLimit;
/// <summary>
/// 初始化一个新的 <see cref="SortedConcurrentOneToManyList{TKey, TValue}"/> 类的实例,使用默认的参数设置。
/// </summary>
public SortedConcurrentOneToManyList()
{
}
/// <summary>
/// 初始化一个新的 <see cref="SortedConcurrentOneToManyList{TKey, TValue}"/> 类的实例,指定最大缓存数量。
/// </summary>
/// <param name="recyclingLimit">
/// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC.
/// 2:设置成0不控制数量全部缓存
/// </param>
public SortedConcurrentOneToManyList(int recyclingLimit = 0)
{
_recyclingLimit = recyclingLimit;
}
/// <summary>
/// 检查指定的键和值是否存在于映射列表中。
/// </summary>
/// <param name="key">要检查的键。</param>
/// <param name="value">要检查的值。</param>
/// <returns>如果存在,则为 true否则为 false。</returns>
public bool Contains(TKey key, TValue value)
{
lock (_lockObject)
{
TryGetValue(key, out var list);
return list != null && list.Contains(value);
}
}
/// <summary>
/// 将指定的值添加到与指定键关联的列表中。
/// </summary>
/// <param name="key">要关联值的键。</param>
/// <param name="value">要添加到列表的值。</param>
public void Add(TKey key, TValue value)
{
lock (_lockObject)
{
if (!TryGetValue(key, out var list))
{
list = Fetch();
list.Add(value);
base[key] = list;
return;
}
list.Add(value);
}
}
/// <summary>
/// 获取与指定键关联的列表中的第一个值。
/// 如果列表不存在或为空,则返回默认值。
/// </summary>
/// <param name="key">要获取第一个值的键。</param>
/// <returns>第一个值,或默认值。</returns>
public TValue First(TKey key)
{
lock (_lockObject)
{
return !TryGetValue(key, out var list) ? default : list.FirstOrDefault();
}
}
/// <summary>
/// 从与指定键关联的列表中移除指定的值。
/// 如果列表不存在或值不存在于列表中,则不执行任何操作。
/// </summary>
/// <param name="key">要移除值的键。</param>
/// <param name="value">要移除的值。</param>
public void RemoveValue(TKey key, TValue value)
{
lock (_lockObject)
{
if (!TryGetValue(key, out var list)) return;
list.Remove(value);
if (list.Count == 0) RemoveKey(key);
}
}
/// <summary>
/// 从映射列表中移除指定的键及其关联的列表。
/// 如果键不存在于映射列表中,则不执行任何操作。
/// </summary>
/// <param name="key">要移除的键。</param>
public void RemoveKey(TKey key)
{
lock (_lockObject)
{
if (!TryGetValue(key, out var list)) return;
Remove(key);
Recycle(list);
}
}
/// <summary>
/// 从缓存中获取一个可重用的列表。如果缓存中不存在列表,则创建一个新的列表并返回。
/// </summary>
/// <returns>可重用的列表。</returns>
private List<TValue> Fetch()
{
lock (_lockObject)
{
return _queue.Count <= 0 ? new List<TValue>() : _queue.Dequeue();
}
}
/// <summary>
/// 将不再使用的列表回收到缓存中,以便重复利用。如果缓存数量超过限制,则丢弃列表而不进行回收。
/// </summary>
/// <param name="list">要回收的列表。</param>
private void Recycle(List<TValue> list)
{
lock (_lockObject)
{
list.Clear();
if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return;
_queue.Enqueue(list);
}
}
/// <summary>
/// 清空映射列表以及队列。
/// </summary>
protected new void Clear()
{
base.Clear();
_queue.Clear();
}
}
}
#endif

View File

@@ -0,0 +1,192 @@
using System;
using System.Collections.Generic;
using Fantasy.Pool;
namespace Fantasy.DataStructure.Collection
{
/// <summary>
/// 基于排序字典实现的一对多关系的映射哈希集合的对象池包装类,将唯一键映射到多个值的哈希集合。
/// 同时实现了 <see cref="IDisposable"/> 接口,以支持对象的重用和释放。
/// </summary>
/// <typeparam name="TKey">字典中键的类型。</typeparam>
/// <typeparam name="TValue">哈希集合中值的类型。</typeparam>
public class SortedOneToManyHashSetPool<TKey, TValue> : SortedOneToManyHashSet<TKey, TValue>, IDisposable, IPool where TKey : notnull
{
private bool _isPool;
private bool _isDispose;
/// <summary>
/// 创建一个 <see cref="SortedOneToManyHashSetPool{TKey, TValue}"/> 实例。
/// </summary>
/// <returns>新创建的实例。</returns>
public static SortedOneToManyHashSetPool<TKey, TValue> Create()
{
#if FANTASY_WEBGL
var a = Pool<SortedOneToManyHashSetPool<TKey, TValue>>.Rent();
#else
var a = MultiThreadPool.Rent<SortedOneToManyHashSetPool<TKey, TValue>>();
#endif
a._isDispose = false;
a._isPool = true;
return a;
}
/// <summary>
/// 释放当前对象池实例,将其返回到对象池以供重用。
/// </summary>
public void Dispose()
{
if (_isDispose)
{
return;
}
_isDispose = true;
Clear();
#if FANTASY_WEBGL
Pool<SortedOneToManyHashSetPool<TKey, TValue>>.Return(this);
#else
MultiThreadPool.Return(this);
#endif
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
/// <summary>
/// 基于排序字典实现的一对多关系的映射哈希集合类,将唯一键映射到多个值的哈希集合。
/// 用于在多个值与一个键关联的情况下进行管理和存储。
/// </summary>
/// <typeparam name="TKey">字典中键的类型。</typeparam>
/// <typeparam name="TValue">集合中值的类型。</typeparam>
public class SortedOneToManyHashSet<TKey, TValue> : SortedDictionary<TKey, HashSet<TValue>> where TKey : notnull
{
private readonly Queue<HashSet<TValue>> _queue = new Queue<HashSet<TValue>>();
private readonly int _recyclingLimit = 120;
/// <summary>
/// 创建一个新的 <see cref="SortedOneToManyHashSet{TKey, TValue}"/> 实例。
/// </summary>
public SortedOneToManyHashSet() { }
/// <summary>
/// 创建一个新的 <see cref="SortedOneToManyHashSet{TKey, TValue}"/> 实例,设置最大缓存数量
/// </summary>
/// <param name="recyclingLimit">
/// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC.
/// 2:设置成0不控制数量全部缓存
/// </param>
public SortedOneToManyHashSet(int recyclingLimit)
{
_recyclingLimit = recyclingLimit;
}
/// <summary>
/// 判断哈希集合中是否包含指定的键值对。
/// </summary>
/// <param name="key">要查找的键。</param>
/// <param name="value">要查找的值。</param>
/// <returns>如果键值对存在,则为 true否则为 false。</returns>
public bool Contains(TKey key, TValue value)
{
TryGetValue(key, out var list);
return list != null && list.Contains(value);
}
/// <summary>
/// 将指定值添加到给定键关联的哈希集合中。
/// </summary>
/// <param name="key">要添加值的键。</param>
/// <param name="value">要添加的值。</param>
public void Add(TKey key, TValue value)
{
if (!TryGetValue(key, out var list))
{
list = Fetch();
list.Add(value);
Add(key, list);
return;
}
list.Add(value);
}
/// <summary>
/// 从指定键关联的哈希集合中移除特定值。
/// 如果哈希集合不存在或值不存在于集合中,则不执行任何操作。
/// </summary>
/// <param name="key">要移除值的键。</param>
/// <param name="value">要移除的值。</param>
public void RemoveValue(TKey key, TValue value)
{
if (!TryGetValue(key, out var list)) return;
list.Remove(value);
if (list.Count == 0) RemoveKey(key);
}
/// <summary>
/// 从字典中移除指定键以及关联的哈希集合,并将集合进行回收。
/// 如果键不存在于映射列表中,则不执行任何操作。
/// </summary>
/// <param name="key">要移除的键。</param>
public void RemoveKey(TKey key)
{
if (!TryGetValue(key, out var list)) return;
Remove(key);
Recycle(list);
}
/// <summary>
/// 获取一个空的或回收的哈希集合。
/// </summary>
/// <returns>获取的哈希集合实例。</returns>
private HashSet<TValue> Fetch()
{
return _queue.Count <= 0 ? new HashSet<TValue>() : _queue.Dequeue();
}
/// <summary>
/// 回收一个哈希集合,将其清空并放入回收队列中。
/// </summary>
/// <param name="list">要回收的哈希集合。</param>
private void Recycle(HashSet<TValue> list)
{
list.Clear();
if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit) return;
_queue.Enqueue(list);
}
/// <summary>
/// 重写 Clear 方法,清空字典并清空回收队列。
/// </summary>
protected new void Clear()
{
base.Clear();
_queue.Clear();
}
}
}

View File

@@ -0,0 +1,217 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Fantasy.Pool;
#pragma warning disable CS8603
namespace Fantasy.DataStructure.Collection
{
/// <summary>
/// 基于排序字典实现的一对多映射列表的对象池包装类,继承自 <see cref="SortedOneToManyList{TKey, TValue}"/> 类,
/// 同时实现了 <see cref="IDisposable"/> 接口,以支持对象的重用和释放。
/// </summary>
/// <typeparam name="TKey">字典中键的类型。</typeparam>
/// <typeparam name="TValue">列表中值的类型。</typeparam>
public class SortedOneToManyListPool<TKey, TValue> : SortedOneToManyList<TKey, TValue>, IDisposable, IPool where TKey : notnull
{
private bool _isPool;
private bool _isDispose;
/// <summary>
/// 创建一个 <see cref="SortedOneToManyListPool{TKey, TValue}"/> 实例。
/// </summary>
/// <returns>新创建的实例。</returns>
public static SortedOneToManyListPool<TKey, TValue> Create()
{
#if FANTASY_WEBGL
var a = Pool<SortedOneToManyListPool<TKey, TValue>>.Rent();
#else
var a = MultiThreadPool.Rent<SortedOneToManyListPool<TKey, TValue>>();
#endif
a._isDispose = false;
a._isPool = true;
return a;
}
/// <summary>
/// 释放当前对象池实例,将其返回到对象池以供重用。
/// </summary>
public void Dispose()
{
if (_isDispose)
{
return;
}
_isDispose = true;
Clear();
#if FANTASY_WEBGL
Pool<SortedOneToManyListPool<TKey, TValue>>.Return(this);
#else
MultiThreadPool.Return(this);
#endif
}
/// <summary>
/// 获取一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <returns></returns>
public bool IsPool()
{
return _isPool;
}
/// <summary>
/// 设置一个值,该值指示当前实例是否为对象池中的实例。
/// </summary>
/// <param name="isPool"></param>
public void SetIsPool(bool isPool)
{
_isPool = isPool;
}
}
/// <summary>
/// 基于排序字典实现的一对多关系的映射列表类,将唯一键映射到包含多个值的列表。
/// 用于在多个值与一个键关联的情况下进行管理和存储。
/// </summary>
/// <typeparam name="TKey">字典中键的类型。</typeparam>
/// <typeparam name="TValue">列表中值的类型。</typeparam>
public class SortedOneToManyList<TKey, TValue> : SortedDictionary<TKey, List<TValue>> where TKey : notnull
{
private readonly Queue<List<TValue>> _queue = new Queue<List<TValue>>();
private readonly int _recyclingLimit;
/// <summary>
/// 创建一个新的 <see cref="SortedOneToManyList{TKey, TValue}"/> 实例。
/// </summary>
public SortedOneToManyList()
{
}
/// <summary>
/// 创建一个新的 <see cref="SortedOneToManyList{TKey, TValue}"/> 实例,设置最大缓存数量
/// </summary>
/// <param name="recyclingLimit">
/// 1:防止数据量过大、所以超过recyclingLimit的数据还是走GC.
/// 2:设置成0不控制数量全部缓存
/// </param>
public SortedOneToManyList(int recyclingLimit = 0)
{
_recyclingLimit = recyclingLimit;
}
/// <summary>
/// 判断列表中是否包含指定的键值对。
/// </summary>
/// <param name="key">要查找的键。</param>
/// <param name="value">要查找的值。</param>
/// <returns>如果键值对存在,则为 true否则为 false。</returns>
public bool Contains(TKey key, TValue value)
{
TryGetValue(key, out var list);
return list != null && list.Contains(value);
}
/// <summary>
/// 将指定值添加到给定键关联的列表中。
/// </summary>
/// <param name="key">要添加值的键。</param>
/// <param name="value">要添加的值。</param>
public void Add(TKey key, TValue value)
{
if (!TryGetValue(key, out var list))
{
list = Fetch();
list.Add(value);
base[key] = list;
return;
}
list.Add(value);
}
/// <summary>
/// 获取指定键关联的列表中的第一个值。
/// </summary>
/// <param name="key">要查找值的键。</param>
/// <returns>指定键关联的列表中的第一个值,如果列表为空则返回默认值。</returns>
public TValue First(TKey key)
{
return !TryGetValue(key, out var list) ? default : list.FirstOrDefault();
}
/// <summary>
/// 从指定键关联的列表中移除特定值。
/// </summary>
/// <param name="key">要移除值的键。</param>
/// <param name="value">要移除的值。</param>
public void RemoveValue(TKey key, TValue value)
{
if (!TryGetValue(key, out var list))
{
return;
}
list.Remove(value);
if (list.Count == 0)
{
RemoveKey(key);
}
}
/// <summary>
/// 从字典中移除指定键以及关联的列表,并将列表进行回收。
/// </summary>
/// <param name="key">要移除的键。</param>
public void RemoveKey(TKey key)
{
if (!TryGetValue(key, out var list))
{
return;
}
Remove(key);
Recycle(list);
}
/// <summary>
/// 获取一个空的或回收的列表。
/// </summary>
/// <returns>获取的列表实例。</returns>
private List<TValue> Fetch()
{
return _queue.Count <= 0 ? new List<TValue>() : _queue.Dequeue();
}
/// <summary>
/// 回收一个列表,将其清空并放入回收队列中。如果缓存数量超过限制,则丢弃列表而不进行回收
/// </summary>
/// <param name="list">要回收的列表。</param>
private void Recycle(List<TValue> list)
{
list.Clear();
if (_recyclingLimit != 0 && _queue.Count > _recyclingLimit)
{
return;
}
_queue.Enqueue(list);
}
/// <summary>
/// 重写 Clear 方法,清空字典并清空回收队列。
/// </summary>
protected new void Clear()
{
base.Clear();
_queue.Clear();
}
}
}