Files
Convention-Unity/Convention/[Runtime]/Convention.Collections.cs
2025-12-05 16:25:40 +08:00

1438 lines
46 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Unity.Collections;
namespace Convention.Collections
{
namespace Generic
{
/// <summary>
/// 附带有缓存机制的链表类
/// </summary>
/// <typeparam name="T">指定链表的元素类型</typeparam>
public sealed class LinkedCacheList<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable
{
private readonly LinkedList<T> m_LinkedList;
/// <summary>
/// 之所以需要这套缓存机制,主要有三点好处:
/// <list type="bullet">减少 GC 压力:大量频繁的插入/删除会产生很多短生命周期的节点对象,通过复用可以显著降低托管堆的分配与回收次数</list>
/// <list type="bullet">提升性能:避免频繁 new 和 GC能减少停顿时间提高链表在高频操作场景下的吞吐</list>
/// <list type="bullet">便于观察与管理:类中还提供了 CachedNodeCount 方便调试统计缓存规模,必要时可通过 ClearCachedNodes 主动释放</list>
/// 适用场景是节点使用模式“高频增删但总量有限”,此时缓存能稳定性能;若链表规模始终在增长且很少释放,缓存收益会较低。
/// </summary>
private readonly Queue<LinkedListNode<T>> m_CachedNodes;
/// <summary>
/// 初始化游戏框架链表类的新实例
/// </summary>
public LinkedCacheList()
{
m_LinkedList = new LinkedList<T>();
m_CachedNodes = new Queue<LinkedListNode<T>>();
}
/// <summary>
/// 获取链表中实际包含的结点数量
/// </summary>
public int Count
{
get
{
return m_LinkedList.Count;
}
}
/// <summary>
/// 获取链表结点缓存数量
/// </summary>
public int CachedNodeCount
{
get
{
return m_CachedNodes.Count;
}
}
/// <summary>
/// 获取链表的第一个结点
/// </summary>
public LinkedListNode<T> First
{
get
{
return m_LinkedList.First;
}
}
/// <summary>
/// 获取链表的最后一个结点
/// </summary>
public LinkedListNode<T> Last
{
get
{
return m_LinkedList.Last;
}
}
/// <summary>
/// 获取一个值,该值指示 <see cref="ICollection{T}"/> 是否为只读
/// </summary>
public bool IsReadOnly
{
get
{
return ((ICollection<T>)m_LinkedList).IsReadOnly;
}
}
/// <summary>
/// 获取可用于同步对 <see cref="ICollection"/> 的访问的对象。
/// </summary>
public object SyncRoot
{
get
{
return ((ICollection)m_LinkedList).SyncRoot;
}
}
/// <summary>
/// 获取一个值,该值指示是否同步对 <see cref="ICollection"/> 的访问(线程安全)。
/// </summary>
public bool IsSynchronized
{
get
{
return ((ICollection)m_LinkedList).IsSynchronized;
}
}
/// <summary>
/// 在链表中指定的现有结点后添加包含指定值的新结点
/// </summary>
/// <param name="node">指定的现有结点</param>
/// <param name="value">指定值</param>
/// <returns>包含指定值的新结点</returns>
public LinkedListNode<T> AddAfter(LinkedListNode<T> node, T value)
{
LinkedListNode<T> newNode = AcquireNode(value);
m_LinkedList.AddAfter(node, newNode);
return newNode;
}
/// <summary>
/// 在链表中指定的现有结点后添加指定的新结点
/// </summary>
/// <param name="node">指定的现有结点</param>
/// <param name="newNode">指定的新结点</param>
public void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
m_LinkedList.AddAfter(node, newNode);
}
/// <summary>
/// 在链表中指定的现有结点前添加包含指定值的新结点
/// </summary>
/// <param name="node">指定的现有结点</param>
/// <param name="value">指定值</param>
/// <returns>包含指定值的新结点</returns>
public LinkedListNode<T> AddBefore(LinkedListNode<T> node, T value)
{
LinkedListNode<T> newNode = AcquireNode(value);
m_LinkedList.AddBefore(node, newNode);
return newNode;
}
/// <summary>
/// 在链表中指定的现有结点前添加指定的新结点
/// </summary>
/// <param name="node">指定的现有结点</param>
/// <param name="newNode">指定的新结点</param>
public void AddBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
{
m_LinkedList.AddBefore(node, newNode);
}
/// <summary>
/// 在链表的开头处添加包含指定值的新结点
/// </summary>
/// <param name="value">指定值</param>
/// <returns>包含指定值的新结点</returns>
public LinkedListNode<T> AddFirst(T value)
{
LinkedListNode<T> node = AcquireNode(value);
m_LinkedList.AddFirst(node);
return node;
}
/// <summary>
/// 在链表的开头处添加指定的新结点
/// </summary>
/// <param name="node">指定的新结点</param>
public void AddFirst(LinkedListNode<T> node)
{
m_LinkedList.AddFirst(node);
}
/// <summary>
/// 在链表的结尾处添加包含指定值的新结点
/// </summary>
/// <param name="value">指定值</param>
/// <returns>包含指定值的新结点</returns>
public LinkedListNode<T> AddLast(T value)
{
LinkedListNode<T> node = AcquireNode(value);
m_LinkedList.AddLast(node);
return node;
}
/// <summary>
/// 在链表的结尾处添加指定的新结点
/// </summary>
/// <param name="node">指定的新结点</param>
public void AddLast(LinkedListNode<T> node)
{
m_LinkedList.AddLast(node);
}
/// <summary>
/// 从链表中移除所有结点
/// </summary>
public void Clear()
{
LinkedListNode<T> current = m_LinkedList.First;
while (current != null)
{
ReleaseNode(current);
current = current.Next;
}
m_LinkedList.Clear();
}
/// <summary>
/// 清除链表结点缓存
/// </summary>
public void ClearCachedNodes()
{
m_CachedNodes.Clear();
}
/// <summary>
/// 确定某值是否在链表中
/// </summary>
/// <param name="value">指定值</param>
/// <returns>某值是否在链表中</returns>
public bool Contains(T value)
{
return m_LinkedList.Contains(value);
}
/// <summary>
/// 从目标数组的指定索引处开始将整个链表复制到兼容的一维数组
/// </summary>
/// <param name="array">一维数组,它是从链表复制的元素的目标。数组必须具有从零开始的索引</param>
/// <param name="index">array 中从零开始的索引,从此处开始复制</param>
public void CopyTo(T[] array, int index)
{
m_LinkedList.CopyTo(array, index);
}
/// <summary>
/// 从特定的 ICollection 索引开始,将数组的元素复制到一个数组中
/// </summary>
/// <param name="array">一维数组,它是从 ICollection 复制的元素的目标。数组必须具有从零开始的索引</param>
/// <param name="index">array 中从零开始的索引,从此处开始复制</param>
public void CopyTo(Array array, int index)
{
((ICollection)m_LinkedList).CopyTo(array, index);
}
/// <summary>
/// 查找包含指定值的第一个结点
/// </summary>
/// <param name="value">要查找的指定值</param>
/// <returns>包含指定值的第一个结点</returns>
public LinkedListNode<T> Find(T value)
{
return m_LinkedList.Find(value);
}
/// <summary>
/// 查找包含指定值的最后一个结点
/// </summary>
/// <param name="value">要查找的指定值</param>
/// <returns>包含指定值的最后一个结点</returns>
public LinkedListNode<T> FindLast(T value)
{
return m_LinkedList.FindLast(value);
}
/// <summary>
/// 从链表中移除指定值的第一个匹配项
/// </summary>
/// <param name="value">指定值</param>
/// <returns>是否移除成功</returns>
public bool Remove(T value)
{
LinkedListNode<T> node = m_LinkedList.Find(value);
if (node != null)
{
m_LinkedList.Remove(node);
ReleaseNode(node);
return true;
}
return false;
}
/// <summary>
/// 从链表中移除指定的结点
/// </summary>
/// <param name="node">指定的结点</param>
public void Remove(LinkedListNode<T> node)
{
m_LinkedList.Remove(node);
ReleaseNode(node);
}
/// <summary>
/// 移除位于链表开头处的结点
/// </summary>
public void RemoveFirst()
{
LinkedListNode<T> first = m_LinkedList.First;
if (first == null)
{
throw new InvalidOperationException("Rmove first is invalid.");
}
m_LinkedList.RemoveFirst();
ReleaseNode(first);
}
/// <summary>
/// 移除位于链表结尾处的结点。
/// </summary>
public void RemoveLast()
{
LinkedListNode<T> last = m_LinkedList.Last;
if (last == null)
{
throw new InvalidOperationException("Remove last is invalid.");
}
m_LinkedList.RemoveLast();
ReleaseNode(last);
}
/// <summary>
/// 返回循环访问集合的枚举数
/// </summary>
/// <returns>循环访问集合的枚举数</returns>
public Enumerator GetEnumerator()
{
return new Enumerator(m_LinkedList);
}
private LinkedListNode<T> AcquireNode(T value)
{
LinkedListNode<T> node = null;
if (m_CachedNodes.Count > 0)
{
node = m_CachedNodes.Dequeue();
node.Value = value;
}
else
{
node = new LinkedListNode<T>(value);
}
return node;
}
private void ReleaseNode(LinkedListNode<T> node)
{
node.Value = default(T);
m_CachedNodes.Enqueue(node);
}
/// <summary>
/// 将值添加到 ICollection`1 的结尾处
/// </summary>
/// <param name="value">要添加的值</param>
void ICollection<T>.Add(T value)
{
AddLast(value);
}
/// <summary>
/// 返回循环访问集合的枚举数
/// </summary>
/// <returns>循环访问集合的枚举数</returns>
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 返回循环访问集合的枚举数
/// </summary>
/// <returns>循环访问集合的枚举数</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// 循环访问集合的枚举数
/// </summary>
[StructLayout(LayoutKind.Auto)]
public struct Enumerator : IEnumerator<T>, IEnumerator
{
private LinkedList<T>.Enumerator m_Enumerator;
internal Enumerator(LinkedList<T> linkedList)
{
if (linkedList == null)
{
throw new InvalidOperationException("Linked list is invalid.");
}
m_Enumerator = linkedList.GetEnumerator();
}
/// <summary>
/// 获取当前结点
/// </summary>
public T Current
{
get
{
return m_Enumerator.Current;
}
}
/// <summary>
/// 获取当前的枚举数
/// </summary>
object IEnumerator.Current
{
get
{
return m_Enumerator.Current;
}
}
/// <summary>
/// 清理枚举数
/// </summary>
public void Dispose()
{
m_Enumerator.Dispose();
}
/// <summary>
/// 获取下一个结点
/// </summary>
/// <returns>返回下一个结点</returns>
public bool MoveNext()
{
return m_Enumerator.MoveNext();
}
/// <summary>
/// 重置枚举数
/// </summary>
void IEnumerator.Reset()
{
((IEnumerator<T>)m_Enumerator).Reset();
}
}
}
}
namespace Cache
{
/// <summary>
/// Native LRUCache - 基于Unity.Collections的高性能最近最少使用缓存
/// Burst兼容需要手动Dispose
/// </summary>
/// <typeparam name="TKey">键类型必须是unmanaged类型</typeparam>
/// <typeparam name="TValue">值类型必须是unmanaged类型</typeparam>
public struct NativeLRUCache<TKey, TValue> : IDisposable
where TKey : unmanaged, IEquatable<TKey>
where TValue : unmanaged
{
// 链表节点
private struct Node
{
public TKey key;
public TValue value;
public int prevIndex; // 前一个节点索引
public int nextIndex; // 后一个节点索引
}
private NativeList<Node> nodes; // 节点池
private readonly NativeHashMap<TKey, int> hashMap; // key -> 节点索引
private readonly NativeList<int> freeList; // 空闲节点索引池
private readonly int capacity;
private int headIndex; // 链表头(最久未使用)
private int tailIndex; // 链表尾(最近使用)
private int count;
// 是否为有效节点索引
private readonly bool IsValidIndex(int index) => index >= 0;
public NativeLRUCache(int capacity, Allocator allocator)
{
this.capacity = capacity;
this.count = 0;
this.headIndex = -1;
this.tailIndex = -1;
hashMap = new NativeHashMap<TKey, int>(capacity, allocator);
nodes = new NativeList<Node>(capacity, allocator);
freeList = new NativeList<int>(capacity, allocator);
// 预分配节点池
nodes.Length = capacity;
for (int i = capacity - 1; i >= 0; i--)
{
freeList.Add(i);
}
}
/// <summary>
/// 获取缓存值
/// </summary>
public bool TryGetValue(TKey key, out TValue value)
{
if (hashMap.TryGetValue(key, out int nodeIndex))
{
MoveToTail(nodeIndex); // 移动到尾部(最近使用)
value = nodes[nodeIndex].value;
return true;
}
value = default;
return false;
}
/// <summary>
/// 添加或更新缓存
/// </summary>
public void Put(TKey key, TValue value)
{
// 已存在则更新并移动到尾部
if (hashMap.TryGetValue(key, out int nodeIndex))
{
Node node = nodes[nodeIndex];
node.value = value;
nodes[nodeIndex] = node;
MoveToTail(nodeIndex);
return;
}
// 容量已满,淘汰头部节点
if (count >= capacity)
{
EvictHead();
}
// 创建新节点
nodeIndex = AllocateNode();
nodes[nodeIndex] = new Node
{
key = key,
value = value,
prevIndex = tailIndex,
nextIndex = -1
};
hashMap.Add(key, nodeIndex);
AddToTail(nodeIndex);
count++;
}
/// <summary>
/// 删除缓存项
/// </summary>
public bool Remove(TKey key)
{
if (!hashMap.TryGetValue(key, out int nodeIndex))
return false;
hashMap.Remove(key);
RemoveFromList(nodeIndex);
FreeNode(nodeIndex);
count--;
return true;
}
/// <summary>
/// 清空缓存
/// </summary>
public void Clear()
{
hashMap.Clear();
// 重置所有节点到空闲列表
freeList.Clear();
for (int i = 0; i < capacity; i++)
{
freeList.Add(i);
}
headIndex = -1;
tailIndex = -1;
count = 0;
}
// 分配节点索引
private readonly int AllocateNode()
{
int index = freeList[^1];
freeList.RemoveAtSwapBack(freeList.Length - 1);
return index;
}
// 释放节点索引
private readonly void FreeNode(int index)
{
freeList.Add(index);
}
// 将节点移动到链表尾部(标记为最近使用)
private void MoveToTail(int nodeIndex)
{
if (nodeIndex == tailIndex)
return;
RemoveFromList(nodeIndex);
AddToTail(nodeIndex);
}
// 将节点添加到尾部
private void AddToTail(int nodeIndex)
{
Node node = nodes[nodeIndex];
node.prevIndex = tailIndex;
node.nextIndex = -1;
nodes[nodeIndex] = node;
if (IsValidIndex(tailIndex))
{
Node tail = nodes[tailIndex];
tail.nextIndex = nodeIndex;
nodes[tailIndex] = tail;
}
tailIndex = nodeIndex;
// 如果链表为空,头尾指向同一节点
if (!IsValidIndex(headIndex))
{
headIndex = nodeIndex;
}
}
// 从链表中移除节点
private void RemoveFromList(int nodeIndex)
{
Node node = nodes[nodeIndex];
// 更新前一个节点的next指针
if (IsValidIndex(node.prevIndex))
{
Node prev = nodes[node.prevIndex];
prev.nextIndex = node.nextIndex;
nodes[node.prevIndex] = prev;
}
else
{
// 没有前一个节点,说明是头节点
headIndex = node.nextIndex;
}
// 更新后一个节点的prev指针
if (IsValidIndex(node.nextIndex))
{
Node next = nodes[node.nextIndex];
next.prevIndex = node.prevIndex;
nodes[node.nextIndex] = next;
}
else
{
// 没有后一个节点,说明是尾节点
tailIndex = node.prevIndex;
}
}
// 淘汰头部节点(最久未使用)
private void EvictHead()
{
if (!IsValidIndex(headIndex)) return;
int oldHead = headIndex;
Node headNode = nodes[oldHead];
hashMap.Remove(headNode.key);
headIndex = headNode.nextIndex;
if (IsValidIndex(headIndex))
{
Node newHead = nodes[headIndex];
newHead.prevIndex = -1;
nodes[headIndex] = newHead;
}
else
{
tailIndex = -1; // 链表为空
}
FreeNode(oldHead);
count--;
}
public void Dispose()
{
if (hashMap.IsCreated) hashMap.Dispose();
if (nodes.IsCreated) nodes.Dispose();
if (freeList.IsCreated) freeList.Dispose();
headIndex = -1;
tailIndex = -1;
count = 0;
}
// 属性访问器
public readonly int Count => count;
public readonly int Capacity => capacity;
public readonly bool IsCreated => hashMap.IsCreated;
}
/// <summary>
/// Native LFUCache - 基于Unity.Collections的高性能最不频繁使用缓存
/// Burst兼容需要手动Dispose
/// </summary>
/// <typeparam name="TKey">键类型必须是unmanaged类型</typeparam>
/// <typeparam name="TValue">值类型必须是unmanaged类型</typeparam>
public struct NativeLFUCache<TKey, TValue> : IDisposable
where TKey : unmanaged, IEquatable<TKey>
where TValue : unmanaged
{
// 缓存节点
private struct Node
{
public TKey key;
public TValue value;
public int frequency; // 访问频率
public int prevIndex; // 同频率链表中的前一个节点
public int nextIndex; // 同频率链表中的后一个节点
}
// 频率链表头尾
private struct FrequencyList
{
public int headIndex; // 该频率链表的头节点(最久未使用)
public int tailIndex; // 该频率链表的尾节点(最近使用)
public readonly bool IsEmpty => headIndex == -1;
}
private readonly NativeHashMap<TKey, int> keyToNodeIndex; // key -> nodeIndex
private NativeList<Node> nodes; // 节点池
private readonly NativeList<int> freeList; // 空闲节点索引
private NativeHashMap<int, FrequencyList> freqToList; // frequency -> FrequencyList
private readonly int capacity;
private int count;
private int minFrequency; // 当前最小频率
public NativeLFUCache(int capacity, Allocator allocator)
{
this.capacity = capacity;
this.count = 0;
this.minFrequency = 0;
keyToNodeIndex = new NativeHashMap<TKey, int>(capacity, allocator);
nodes = new NativeList<Node>(capacity, allocator);
freeList = new NativeList<int>(capacity, allocator);
freqToList = new NativeHashMap<int, FrequencyList>(capacity, allocator);
// 预分配节点池
nodes.Length = capacity;
for (int i = capacity - 1; i >= 0; i--)
{
freeList.Add(i);
}
}
/// <summary>
/// 获取缓存值并增加频率
/// </summary>
public bool TryGetValue(TKey key, out TValue value)
{
if (keyToNodeIndex.TryGetValue(key, out int nodeIndex))
{
// 增加访问频率
IncreaseFrequency(nodeIndex);
value = nodes[nodeIndex].value;
return true;
}
value = default;
return false;
}
/// <summary>
/// 添加或更新缓存
/// </summary>
public void Put(TKey key, TValue value)
{
// 更新现有值
if (keyToNodeIndex.TryGetValue(key, out int nodeIndex))
{
Node node = nodes[nodeIndex];
node.value = value;
nodes[nodeIndex] = node;
IncreaseFrequency(nodeIndex);
return;
}
// 容量已满,淘汰最小频率的节点
if (count >= capacity)
{
EvictMinFrequencyNode();
}
// 创建新节点初始频率为1
nodeIndex = AllocateNode();
nodes[nodeIndex] = new Node
{
key = key,
value = value,
frequency = 1,
prevIndex = -1,
nextIndex = -1
};
keyToNodeIndex.Add(key, nodeIndex);
AddToFrequencyList(nodeIndex, 1);
// 更新最小频率
if (minFrequency == 0)
{
minFrequency = 1;
}
count++;
}
/// <summary>
/// 删除缓存项
/// </summary>
public bool Remove(TKey key)
{
if (!keyToNodeIndex.TryGetValue(key, out int nodeIndex))
return false;
RemoveNode(nodeIndex);
return true;
}
/// <summary>
/// 清空缓存
/// </summary>
public void Clear()
{
keyToNodeIndex.Clear();
freqToList.Clear();
// 重置所有节点到空闲列表
freeList.Clear();
for (int i = 0; i < capacity; i++)
{
freeList.Add(i);
}
minFrequency = 0;
count = 0;
}
/// <summary>
/// 释放所有内存
/// </summary>
public void Dispose()
{
if (keyToNodeIndex.IsCreated) keyToNodeIndex.Dispose();
if (nodes.IsCreated) nodes.Dispose();
if (freeList.IsCreated) freeList.Dispose();
if (freqToList.IsCreated) freqToList.Dispose();
minFrequency = 0;
count = 0;
}
#region
private int AllocateNode()
{
int index = freeList[^1];
freeList.RemoveAtSwapBack(freeList.Length - 1);
return index;
}
private void FreeNode(int index)
{
freeList.Add(index);
}
/// <summary>
/// 增加节点的访问频率
/// </summary>
private void IncreaseFrequency(int nodeIndex)
{
Node node = nodes[nodeIndex];
int oldFreq = node.frequency;
int newFreq = oldFreq + 1;
// 从旧频率链表移除
RemoveFromFrequencyList(nodeIndex, oldFreq);
// 检查是否需要更新最小频率
if (oldFreq == minFrequency && GetFrequencyListHead(oldFreq) == -1)
{
minFrequency = newFreq;
}
// 更新节点频率
node.frequency = newFreq;
nodes[nodeIndex] = node;
// 添加到新频率链表
AddToFrequencyList(nodeIndex, newFreq);
}
/// <summary>
/// 从频率链表中移除节点
/// </summary>
private void RemoveFromFrequencyList(int nodeIndex, int frequency)
{
if (!freqToList.TryGetValue(frequency, out var list))
return;
Node node = nodes[nodeIndex];
// 如果是头节点
if (node.prevIndex == -1)
{
list.headIndex = node.nextIndex;
}
else
{
// 更新前一个节点的next指针
Node prevNode = nodes[node.prevIndex];
prevNode.nextIndex = node.nextIndex;
nodes[node.prevIndex] = prevNode;
}
// 如果是尾节点
if (node.nextIndex == -1)
{
list.tailIndex = node.prevIndex;
}
else
{
// 更新后一个节点的prev指针
Node nextNode = nodes[node.nextIndex];
nextNode.prevIndex = node.prevIndex;
nodes[node.nextIndex] = nextNode;
}
// 如果链表变空,移除该频率
if (list.headIndex == -1)
{
freqToList.Remove(frequency);
}
else
{
freqToList[frequency] = list;
}
}
/// <summary>
/// 将节点添加到频率链表尾部
/// </summary>
private void AddToFrequencyList(int nodeIndex, int frequency)
{
if (!freqToList.TryGetValue(frequency, out var list))
{
// 创建新的频率链表
list = new FrequencyList { headIndex = nodeIndex, tailIndex = nodeIndex };
freqToList.Add(frequency, list);
// 设置节点指针
Node node = nodes[nodeIndex];
node.prevIndex = -1;
node.nextIndex = -1;
nodes[nodeIndex] = node;
}
else
{
// 添加到链表尾部
int oldTail = list.tailIndex;
// 更新原尾节点
Node oldTailNode = nodes[oldTail];
oldTailNode.nextIndex = nodeIndex;
nodes[oldTail] = oldTailNode;
// 设置新节点
Node newNode = nodes[nodeIndex];
newNode.prevIndex = oldTail;
newNode.nextIndex = -1;
nodes[nodeIndex] = newNode;
// 更新链表尾
list.tailIndex = nodeIndex;
freqToList[frequency] = list;
}
}
/// <summary>
/// 获取频率链表的头节点
/// </summary>
private int GetFrequencyListHead(int frequency)
{
if (freqToList.TryGetValue(frequency, out var list))
{
return list.headIndex;
}
return -1;
}
/// <summary>
/// 淘汰最小频率的节点(淘汰该频率链表的头节点)
/// </summary>
private void EvictMinFrequencyNode()
{
// 找到有节点的最小频率
while (minFrequency <= capacity && GetFrequencyListHead(minFrequency) == -1)
{
minFrequency++;
}
if (minFrequency > capacity) return;
int headIndex = GetFrequencyListHead(minFrequency);
if (headIndex == -1) return;
RemoveNode(headIndex);
}
/// <summary>
/// 移除完整节点(从所有数据结构中删除)
/// </summary>
private void RemoveNode(int nodeIndex)
{
Node node = nodes[nodeIndex];
// 从频率链表移除
RemoveFromFrequencyList(nodeIndex, node.frequency);
// 从主HashMap移除
keyToNodeIndex.Remove(node.key);
// 回收节点
FreeNode(nodeIndex);
count--;
}
#endregion
// 属性访问器
public readonly int Count => count;
public readonly int Capacity => capacity;
public readonly bool IsCreated => keyToNodeIndex.IsCreated;
}
public struct NativeARCCache<TKey, TValue> : IDisposable
where TKey : unmanaged, IEquatable<TKey>
where TValue : unmanaged
{
private const int LIST_T1 = 0, LIST_T2 = 1, LIST_B1 = 2, LIST_B2 = 3;
private struct Node
{
public TKey key;
public TValue value;
public byte listType;
public int prevIndex;
public int nextIndex;
}
private NativeHashMap<TKey, int> keyToNode;
private NativeList<Node> nodes;
private NativeList<int> freeList;
// 四个链表头尾指针
private int t1Head, t1Tail, t2Head, t2Tail, b1Head, b1Tail, b2Head, b2Tail;
private int capacity, t1Count, t2Count, b1Count, b2Count, p;
public NativeARCCache(int capacity, Allocator allocator)
{
this.capacity = capacity;
this.t1Count = this.t2Count = this.b1Count = this.b2Count = 0;
this.p = 0;
t1Head = t1Tail = t2Head = t2Tail = -1;
b1Head = b1Tail = b2Head = b2Tail = -1;
int totalNodes = capacity * 2;
keyToNode = new NativeHashMap<TKey, int>(totalNodes, allocator);
nodes = new NativeList<Node>(totalNodes, allocator);
freeList = new NativeList<int>(totalNodes, allocator);
nodes.Length = totalNodes;
for (int i = totalNodes - 1; i >= 0; i--)
{
freeList.Add(i);
}
}
public bool TryGetValue(TKey key, out TValue value)
{
if (keyToNode.TryGetValue(key, out int nodeIndex))
{
Node node = nodes[nodeIndex]; // 先读取
if (node.listType == LIST_T1 || node.listType == LIST_T2)
{
MoveToMRU(nodeIndex, LIST_T2);
value = node.value;
return true;
}
if (node.listType == LIST_B1)
{
node = ComputeNewPAndReplace(node, b2Count, b1Count, true);
b1Count--; t2Count++;
value = node.value;
return true;
}
if (node.listType == LIST_B2)
{
node = ComputeNewPAndReplace(node, b1Count, b2Count, false);
b2Count--; t2Count++;
value = node.value;
return true;
}
}
value = default;
return false;
}
public void Put(TKey key, TValue value)
{
if (keyToNode.TryGetValue(key, out int nodeIndex))
{
Node node = nodes[nodeIndex];
node.value = value;
if (node.listType == LIST_T1 || node.listType == LIST_T2)
{
MoveToMRU(nodeIndex, LIST_T2);
}
else if (node.listType == LIST_B1)
{
node = ComputeNewPAndReplace(node, b2Count, b1Count, true);
b1Count--; t2Count++;
}
else if (node.listType == LIST_B2)
{
node = ComputeNewPAndReplace(node, b1Count, b2Count, false);
b2Count--; t2Count++;
}
nodes[nodeIndex] = node; // 写回
return;
}
// 容量满执行Replace
int totalSize = t1Count + t2Count;
if (totalSize >= capacity)
{
Replace();
}
// 创建新节点到T1
nodeIndex = AllocateNode();
nodes[nodeIndex] = new Node
{
key = key,
value = value,
listType = LIST_T1,
prevIndex = -1,
nextIndex = -1
};
keyToNode.Add(key, nodeIndex);
AddToHead(nodeIndex, LIST_T1);
t1Count++;
}
private Node ComputeNewPAndReplace(Node node, int oppositeCount, int sameCount, bool isB1)
{
int delta = (oppositeCount >= sameCount) ? 1 : oppositeCount / sameCount + 1;
// 先修改p值
if (isB1) p = Math.Min(p + delta, capacity);
else p = Math.Max(p - delta, 0);
// 执行替换
Replace();
// 移动节点
MoveBetweenLists(node.prevIndex, node.listType, LIST_T2);
node.listType = LIST_T2;
return node;
}
private void Replace()
{
if (t1Count > 0 && (t1Count > p || (b2Count > 0 && t1Count == p)))
{
MoveBetweenLists(t1Head, LIST_T1, LIST_B1);
t1Count--; b1Count++;
if (b1Count > capacity)
{
int old = b1Head; Node n = nodes[old];
RemoveFromList(old);
keyToNode.Remove(n.key);
FreeNode(old);
b1Count--;
}
}
else
{
MoveBetweenLists(t2Head, LIST_T2, LIST_B2);
t2Count--; b2Count++;
if (b2Count > capacity)
{
int old = b2Head; Node n = nodes[old];
RemoveFromList(old);
keyToNode.Remove(n.key);
FreeNode(old);
b2Count--;
}
}
}
#region
private void MoveToMRU(int nodeIndex, byte targetList)
{
RemoveFromList(nodeIndex);
AddToHead(nodeIndex, targetList);
}
private void MoveBetweenLists(int nodeIndex, byte fromList, byte toList)
{
RemoveFromList(nodeIndex);
AddToHead(nodeIndex, toList);
}
private void AddToHead(int nodeIndex, byte listType)
{
Node node = nodes[nodeIndex]; // 读取
node.listType = listType;
node.prevIndex = -1;
switch (listType)
{
case LIST_T1:
node.nextIndex = t1Head;
nodes[nodeIndex] = node; // 写回
if (t1Head != -1)
{
Node headNode = nodes[t1Head];
headNode.prevIndex = nodeIndex;
nodes[t1Head] = headNode; // 写回
}
t1Head = nodeIndex;
if (t1Tail == -1) t1Tail = nodeIndex;
break;
case LIST_T2:
node.nextIndex = t2Head;
nodes[nodeIndex] = node; // 写回
if (t2Head != -1)
{
Node headNode = nodes[t2Head];
headNode.prevIndex = nodeIndex;
nodes[t2Head] = headNode; // 写回
}
t2Head = nodeIndex;
if (t2Tail == -1) t2Tail = nodeIndex;
break;
case LIST_B1:
node.nextIndex = b1Head;
nodes[nodeIndex] = node; // 写回
if (b1Head != -1)
{
Node headNode = nodes[b1Head];
headNode.prevIndex = nodeIndex;
nodes[b1Head] = headNode; // 写回
}
b1Head = nodeIndex;
if (b1Tail == -1) b1Tail = nodeIndex;
break;
case LIST_B2:
node.nextIndex = b2Head;
nodes[nodeIndex] = node; // 写回
if (b2Head != -1)
{
Node headNode = nodes[b2Head];
headNode.prevIndex = nodeIndex;
nodes[b2Head] = headNode; // 写回
}
b2Head = nodeIndex;
if (b2Tail == -1) b2Tail = nodeIndex;
break;
}
}
private void RemoveFromList(int nodeIndex)
{
Node node = nodes[nodeIndex]; // 读取
int prev = node.prevIndex;
int next = node.nextIndex;
// 根据类型更新头尾指针
switch (node.listType)
{
case LIST_T1:
if (nodeIndex == t1Head) t1Head = next;
if (nodeIndex == t1Tail) t1Tail = prev;
break;
case LIST_T2:
if (nodeIndex == t2Head) t2Head = next;
if (nodeIndex == t2Tail) t2Tail = prev;
break;
case LIST_B1:
if (nodeIndex == b1Head) b1Head = next;
if (nodeIndex == b1Tail) b1Tail = prev;
break;
case LIST_B2:
if (nodeIndex == b2Head) b2Head = next;
if (nodeIndex == b2Tail) b2Tail = prev;
break;
}
// 更新邻居
if (prev != -1)
{
Node prevNode = nodes[prev];
prevNode.nextIndex = next;
nodes[prev] = prevNode; // 写回
}
if (next != -1)
{
Node nextNode = nodes[next];
nextNode.prevIndex = prev;
nodes[next] = nextNode; // 写回
}
node.prevIndex = node.nextIndex = -1;
nodes[nodeIndex] = node; // 写回
}
#endregion
private int AllocateNode()
{
int index = freeList[^1];
freeList.RemoveAtSwapBack(freeList.Length - 1);
return index;
}
private void FreeNode(int index)
{
freeList.Add(index);
}
public bool Remove(TKey key)
{
if (!keyToNode.TryGetValue(key, out int nodeIndex))
return false;
Node node = nodes[nodeIndex]; // 读取
// 更新计数
if (node.listType == LIST_T1) t1Count--;
else if (node.listType == LIST_T2) t2Count--;
else if (node.listType == LIST_B1) b1Count--;
else if (node.listType == LIST_B2) b2Count--;
RemoveFromList(nodeIndex);
keyToNode.Remove(key);
FreeNode(nodeIndex);
return true;
}
public void Clear()
{
keyToNode.Clear();
freeList.Clear();
for (int i = 0; i < nodes.Length; i++)
{
freeList.Add(i);
}
t1Head = t1Tail = t2Head = t2Tail = -1;
b1Head = b1Tail = b2Head = b2Tail = -1;
t1Count = t2Count = b1Count = b2Count = 0;
p = 0;
}
public void Dispose()
{
if (keyToNode.IsCreated) keyToNode.Dispose();
if (nodes.IsCreated) nodes.Dispose();
if (freeList.IsCreated) freeList.Dispose();
t1Head = t1Tail = t2Head = t2Tail = -1;
b1Head = b1Tail = b2Head = b2Tail = -1;
t1Count = t2Count = b1Count = b2Count = 0;
p = 0;
}
public int Count => t1Count + t2Count;
public int Capacity => capacity;
public bool IsCreated => keyToNode.IsCreated;
public int T1Count => t1Count;
public int T2Count => t2Count;
public int PValue => p;
}
}
}