2025-11-20 17:29:16 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Runtime.InteropServices;
|
2025-12-05 16:25:40 +08:00
|
|
|
|
using Unity.Collections;
|
2025-11-20 17:29:16 +08:00
|
|
|
|
|
|
|
|
|
|
namespace Convention.Collections
|
|
|
|
|
|
{
|
|
|
|
|
|
namespace Generic
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T">ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><D4AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD></typeparam>
|
|
|
|
|
|
public sealed class LinkedCacheList<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly LinkedList<T> m_LinkedList;
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// ֮<><D6AE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><D7BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƣ<EFBFBD><C6A3><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ô<EFBFBD><C3B4><EFBFBD>
|
|
|
|
|
|
/// <list type="bullet"><3E><><EFBFBD><EFBFBD> GC ѹ<><D1B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD>IJ<EFBFBD><C4B2><EFBFBD>/ɾ<><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܶ<EFBFBD><DCB6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵĽڵ<C4BD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><CDA8><EFBFBD><EFBFBD><EFBFBD>ÿ<EFBFBD><C3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>йܶѵķ<D1B5><C4B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>մ<EFBFBD><D5B4><EFBFBD></list>
|
|
|
|
|
|
/// <list type="bullet"><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܣ<EFBFBD><DCA3><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5> new <20><> GC<47><43><EFBFBD>ܼ<EFBFBD><DCBC><EFBFBD>ͣ<EFBFBD><CDA3>ʱ<EFBFBD>䣬<EFBFBD><E4A3AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڸ<EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><C2B5><EFBFBD><EFBFBD><EFBFBD></list>
|
|
|
|
|
|
/// <list type="bullet"><3E><><EFBFBD>ڹ۲<DAB9><DBB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>л<EFBFBD><D0BB>ṩ<EFBFBD><E1B9A9> CachedNodeCount <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͳ<EFBFBD>ƻ<EFBFBD><C6BB><EFBFBD><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD>Ҫʱ<D2AA><CAB1>ͨ<EFBFBD><CDA8> ClearCachedNodes <20><><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD></list>
|
|
|
|
|
|
/// <20><><EFBFBD>ó<EFBFBD><C3B3><EFBFBD><EFBFBD>ǽڵ<C7BD>ʹ<EFBFBD><CAB9>ģʽ<C4A3><CABD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ޡ<EFBFBD><DEA1><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȶ<EFBFBD><C8B6><EFBFBD><EFBFBD>ܣ<EFBFBD><DCA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʼ<C4A3><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һ<EFBFBD><D2BA><EFBFBD><EFBFBD>ͷţ<CDB7><C5A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵ͡<CFB5>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private readonly Queue<LinkedListNode<T>> m_CachedNodes;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>Ϸ<EFBFBD><CFB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public LinkedCacheList()
|
|
|
|
|
|
{
|
|
|
|
|
|
m_LinkedList = new LinkedList<T>();
|
|
|
|
|
|
m_CachedNodes = new Queue<LinkedListNode<T>>();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD>ʰ<EFBFBD><CAB0><EFBFBD><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int Count
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_LinkedList.Count;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㻺<EFBFBD><E3BBBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public int CachedNodeCount
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_CachedNodes.Count;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public LinkedListNode<T> First
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_LinkedList.First;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public LinkedListNode<T> Last
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_LinkedList.Last;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ȡһ<C8A1><D2BB>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>ֵָʾ <see cref="ICollection{T}"/> <20>Ƿ<EFBFBD>Ϊֻ<CEAA><D6BB>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool IsReadOnly
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return ((ICollection<T>)m_LinkedList).IsReadOnly;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD> <see cref="ICollection"/> <20>ķ<EFBFBD><C4B7>ʵĶ<CAB5><C4B6><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public object SyncRoot
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return ((ICollection)m_LinkedList).SyncRoot;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ȡһ<C8A1><D2BB>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD>ֵָʾ<D6B8>Ƿ<EFBFBD>ͬ<EFBFBD><CDAC><EFBFBD><EFBFBD> <see cref="ICollection"/> <20>ķ<EFBFBD><C4B7>ʣ<EFBFBD><CAA3>̰߳<DFB3>ȫ<EFBFBD><C8AB><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool IsSynchronized
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return ((ICollection)m_LinkedList).IsSynchronized;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><D0BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD><D6B5><EFBFBD>½<EFBFBD><C2BD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="node">ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><D0BD><EFBFBD></param>
|
|
|
|
|
|
/// <param name="value">ָ<><D6B8>ֵ</param>
|
|
|
|
|
|
/// <returns><3E><><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD><D6B5><EFBFBD>½<EFBFBD><C2BD><EFBFBD></returns>
|
|
|
|
|
|
public LinkedListNode<T> AddAfter(LinkedListNode<T> node, T value)
|
|
|
|
|
|
{
|
|
|
|
|
|
LinkedListNode<T> newNode = AcquireNode(value);
|
|
|
|
|
|
m_LinkedList.AddAfter(node, newNode);
|
|
|
|
|
|
return newNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><D0BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="node">ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><D0BD><EFBFBD></param>
|
|
|
|
|
|
/// <param name="newNode">ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD><EFBFBD></param>
|
|
|
|
|
|
public void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_LinkedList.AddAfter(node, newNode);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><D0BD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD><D6B5><EFBFBD>½<EFBFBD><C2BD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="node">ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><D0BD><EFBFBD></param>
|
|
|
|
|
|
/// <param name="value">ָ<><D6B8>ֵ</param>
|
|
|
|
|
|
/// <returns><3E><><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD><D6B5><EFBFBD>½<EFBFBD><C2BD><EFBFBD></returns>
|
|
|
|
|
|
public LinkedListNode<T> AddBefore(LinkedListNode<T> node, T value)
|
|
|
|
|
|
{
|
|
|
|
|
|
LinkedListNode<T> newNode = AcquireNode(value);
|
|
|
|
|
|
m_LinkedList.AddBefore(node, newNode);
|
|
|
|
|
|
return newNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><D0BD><EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="node">ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>н<EFBFBD><D0BD><EFBFBD></param>
|
|
|
|
|
|
/// <param name="newNode">ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD><EFBFBD></param>
|
|
|
|
|
|
public void AddBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_LinkedList.AddBefore(node, newNode);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD><D6B5><EFBFBD>½<EFBFBD><C2BD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="value">ָ<><D6B8>ֵ</param>
|
|
|
|
|
|
/// <returns><3E><><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD><D6B5><EFBFBD>½<EFBFBD><C2BD><EFBFBD></returns>
|
|
|
|
|
|
public LinkedListNode<T> AddFirst(T value)
|
|
|
|
|
|
{
|
|
|
|
|
|
LinkedListNode<T> node = AcquireNode(value);
|
|
|
|
|
|
m_LinkedList.AddFirst(node);
|
|
|
|
|
|
return node;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ<EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="node">ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD><EFBFBD></param>
|
|
|
|
|
|
public void AddFirst(LinkedListNode<T> node)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_LinkedList.AddFirst(node);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ľ<EFBFBD>β<EFBFBD><CEB2><EFBFBD><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD><D6B5><EFBFBD>½<EFBFBD><C2BD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="value">ָ<><D6B8>ֵ</param>
|
|
|
|
|
|
/// <returns><3E><><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD><D6B5><EFBFBD>½<EFBFBD><C2BD><EFBFBD></returns>
|
|
|
|
|
|
public LinkedListNode<T> AddLast(T value)
|
|
|
|
|
|
{
|
|
|
|
|
|
LinkedListNode<T> node = AcquireNode(value);
|
|
|
|
|
|
m_LinkedList.AddLast(node);
|
|
|
|
|
|
return node;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ľ<EFBFBD>β<EFBFBD><CEB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="node">ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD>½<EFBFBD><C2BD><EFBFBD></param>
|
|
|
|
|
|
public void AddLast(LinkedListNode<T> node)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_LinkedList.AddLast(node);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD>н<EFBFBD><D0BD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Clear()
|
|
|
|
|
|
{
|
|
|
|
|
|
LinkedListNode<T> current = m_LinkedList.First;
|
|
|
|
|
|
while (current != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
ReleaseNode(current);
|
|
|
|
|
|
current = current.Next;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_LinkedList.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>㻺<EFBFBD><E3BBBA>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void ClearCachedNodes()
|
|
|
|
|
|
{
|
|
|
|
|
|
m_CachedNodes.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// ȷ<><C8B7>ijֵ<C4B3>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="value">ָ<><D6B8>ֵ</param>
|
|
|
|
|
|
/// <returns>ijֵ<C4B3>Ƿ<EFBFBD><C7B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD></returns>
|
|
|
|
|
|
public bool Contains(T value)
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_LinkedList.Contains(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD>ݵ<EFBFBD>һά<D2BB><CEAC><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="array">һά<D2BB><CEAC><EFBFBD>飬<EFBFBD><E9A3AC><EFBFBD>Ǵ<EFBFBD><C7B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD>Ԫ<EFBFBD>ص<EFBFBD>Ŀ<EFBFBD>ꡣ<EFBFBD><EAA1A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>㿪ʼ<E3BFAA><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
|
|
|
|
|
/// <param name="index">array <20>д<EFBFBD><D0B4>㿪ʼ<E3BFAA><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӵ˴<D3B4><CBB4><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD></param>
|
|
|
|
|
|
public void CopyTo(T[] array, int index)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_LinkedList.CopyTo(array, index);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD>ض<EFBFBD><D8B6><EFBFBD> ICollection <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><D8B8>Ƶ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="array">һά<D2BB><CEAC><EFBFBD>飬<EFBFBD><E9A3AC><EFBFBD>Ǵ<EFBFBD> ICollection <20><><EFBFBD>Ƶ<EFBFBD>Ԫ<EFBFBD>ص<EFBFBD>Ŀ<EFBFBD>ꡣ<EFBFBD><EAA1A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>㿪ʼ<E3BFAA><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD></param>
|
|
|
|
|
|
/// <param name="index">array <20>д<EFBFBD><D0B4>㿪ʼ<E3BFAA><CABC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӵ˴<D3B4><CBB4><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD></param>
|
|
|
|
|
|
public void CopyTo(Array array, int index)
|
|
|
|
|
|
{
|
|
|
|
|
|
((ICollection)m_LinkedList).CopyTo(array, index);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD>Ұ<EFBFBD><D2B0><EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD>ĵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="value">Ҫ<><D2AA><EFBFBD>ҵ<EFBFBD>ָ<EFBFBD><D6B8>ֵ</param>
|
|
|
|
|
|
/// <returns><3E><><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD>ĵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD></returns>
|
|
|
|
|
|
public LinkedListNode<T> Find(T value)
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_LinkedList.Find(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD>Ұ<EFBFBD><D2B0><EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="value">Ҫ<><D2AA><EFBFBD>ҵ<EFBFBD>ָ<EFBFBD><D6B8>ֵ</param>
|
|
|
|
|
|
/// <returns><3E><><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD></returns>
|
|
|
|
|
|
public LinkedListNode<T> FindLast(T value)
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_LinkedList.FindLast(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD>ָ<EFBFBD><D6B8>ֵ<EFBFBD>ĵ<EFBFBD>һ<EFBFBD><D2BB>ƥ<EFBFBD><C6A5><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="value">ָ<><D6B8>ֵ</param>
|
|
|
|
|
|
/// <returns><3E>Ƿ<EFBFBD><C7B7>Ƴ<EFBFBD><C6B3>ɹ<EFBFBD></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>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD>ָ<EFBFBD><D6B8><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="node">ָ<><D6B8><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD></param>
|
|
|
|
|
|
public void Remove(LinkedListNode<T> node)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_LinkedList.Remove(node);
|
|
|
|
|
|
ReleaseNode(node);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20>Ƴ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD>Ľ<EFBFBD><C4BD><EFBFBD>
|
|
|
|
|
|
/// </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>
|
|
|
|
|
|
/// <20>Ƴ<EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD><CEB2><EFBFBD>Ľ<EFBFBD><C4BD>㡣
|
|
|
|
|
|
/// </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>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>ϵ<EFBFBD>ö<EFBFBD><C3B6><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>ѭ<><D1AD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>ϵ<EFBFBD>ö<EFBFBD><C3B6><EFBFBD><EFBFBD></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>
|
|
|
|
|
|
/// <20><>ֵ<EFBFBD><D6B5><EFBFBD>ӵ<EFBFBD> ICollection`1 <20>Ľ<EFBFBD>β<EFBFBD><CEB2>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="value">Ҫ<><D2AA><EFBFBD>ӵ<EFBFBD>ֵ</param>
|
|
|
|
|
|
void ICollection<T>.Add(T value)
|
|
|
|
|
|
{
|
|
|
|
|
|
AddLast(value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>ϵ<EFBFBD>ö<EFBFBD><C3B6><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>ѭ<><D1AD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>ϵ<EFBFBD>ö<EFBFBD><C3B6><EFBFBD><EFBFBD></returns>
|
|
|
|
|
|
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
|
|
|
|
{
|
|
|
|
|
|
return GetEnumerator();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD>ѭ<EFBFBD><D1AD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>ϵ<EFBFBD>ö<EFBFBD><C3B6><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns>ѭ<><D1AD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>ϵ<EFBFBD>ö<EFBFBD><C3B6><EFBFBD><EFBFBD></returns>
|
|
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
|
|
|
|
{
|
|
|
|
|
|
return GetEnumerator();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// ѭ<><D1AD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>ϵ<EFBFBD>ö<EFBFBD><C3B6><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </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>
|
|
|
|
|
|
/// <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD><C7B0><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public T Current
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_Enumerator.Current;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ȡ<EFBFBD><C8A1>ǰ<EFBFBD><C7B0>ö<EFBFBD><C3B6><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
object IEnumerator.Current
|
|
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_Enumerator.Current;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD>ö<EFBFBD><C3B6><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
|
{
|
|
|
|
|
|
m_Enumerator.Dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ȡ<EFBFBD><C8A1>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns><3E><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD></returns>
|
|
|
|
|
|
public bool MoveNext()
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_Enumerator.MoveNext();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD><EFBFBD>ö<EFBFBD><C3B6><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
void IEnumerator.Reset()
|
|
|
|
|
|
{
|
|
|
|
|
|
((IEnumerator<T>)m_Enumerator).Reset();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-05 16:25:40 +08:00
|
|
|
|
|
|
|
|
|
|
namespace Cache
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Native LRUCache - <20><><EFBFBD><EFBFBD>Unity.Collections<6E>ĸ<EFBFBD><C4B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>û<EFBFBD><C3BB><EFBFBD>
|
|
|
|
|
|
/// Burst<73><74><EFBFBD>ݣ<EFBFBD><DDA3><EFBFBD>Ҫ<EFBFBD>ֶ<EFBFBD>Dispose
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="TKey"><3E><><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>unmanaged<65><64><EFBFBD>ͣ<EFBFBD></typeparam>
|
|
|
|
|
|
/// <typeparam name="TValue">ֵ<><D6B5><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>unmanaged<65><64><EFBFBD>ͣ<EFBFBD></typeparam>
|
|
|
|
|
|
public struct NativeLRUCache<TKey, TValue> : IDisposable
|
|
|
|
|
|
where TKey : unmanaged, IEquatable<TKey>
|
|
|
|
|
|
where TValue : unmanaged
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD>
|
|
|
|
|
|
private struct Node
|
|
|
|
|
|
{
|
|
|
|
|
|
public TKey key;
|
|
|
|
|
|
public TValue value;
|
|
|
|
|
|
public int prevIndex; // ǰһ<C7B0><D2BB><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
public int nextIndex; // <20><>һ<EFBFBD><D2BB><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private NativeList<Node> nodes; // <20>ڵ<EFBFBD><DAB5><EFBFBD>
|
|
|
|
|
|
private readonly NativeHashMap<TKey, int> hashMap; // key -> <20>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
private readonly NativeList<int> freeList; // <20><><EFBFBD>нڵ<D0BD><DAB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
|
|
private readonly int capacity;
|
|
|
|
|
|
private int headIndex; // <20><><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δʹ<CEB4>ã<EFBFBD>
|
|
|
|
|
|
private int tailIndex; // <20><><EFBFBD><EFBFBD>β<EFBFBD><CEB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ã<EFBFBD>
|
|
|
|
|
|
private int count;
|
|
|
|
|
|
|
|
|
|
|
|
// <20>Ƿ<EFBFBD>Ϊ<EFBFBD><CEAA>Ч<EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
// Ԥ<><D4A4><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>
|
|
|
|
|
|
nodes.Length = capacity;
|
|
|
|
|
|
for (int i = capacity - 1; i >= 0; i--)
|
|
|
|
|
|
{
|
|
|
|
|
|
freeList.Add(i);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ֵ
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool TryGetValue(TKey key, out TValue value)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (hashMap.TryGetValue(key, out int nodeIndex))
|
|
|
|
|
|
{
|
|
|
|
|
|
MoveToTail(nodeIndex); // <20>ƶ<EFBFBD><C6B6><EFBFBD>β<EFBFBD><CEB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD>ã<EFBFBD>
|
|
|
|
|
|
value = nodes[nodeIndex].value;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
value = default;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD>ӻ<EFBFBD><D3BB><EFBFBD><EFBFBD>»<EFBFBD><C2BB><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Put(TKey key, TValue value)
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20>Ѵ<EFBFBD><D1B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>²<EFBFBD><C2B2>ƶ<EFBFBD><C6B6><EFBFBD>β<EFBFBD><CEB2>
|
|
|
|
|
|
if (hashMap.TryGetValue(key, out int nodeIndex))
|
|
|
|
|
|
{
|
|
|
|
|
|
Node node = nodes[nodeIndex];
|
|
|
|
|
|
node.value = value;
|
|
|
|
|
|
nodes[nodeIndex] = node;
|
|
|
|
|
|
MoveToTail(nodeIndex);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̭ͷ<CCAD><CDB7><EFBFBD>ڵ<EFBFBD>
|
|
|
|
|
|
if (count >= capacity)
|
|
|
|
|
|
{
|
|
|
|
|
|
EvictHead();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>½ڵ<C2BD>
|
|
|
|
|
|
nodeIndex = AllocateNode();
|
|
|
|
|
|
nodes[nodeIndex] = new Node
|
|
|
|
|
|
{
|
|
|
|
|
|
key = key,
|
|
|
|
|
|
value = value,
|
|
|
|
|
|
prevIndex = tailIndex,
|
|
|
|
|
|
nextIndex = -1
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
hashMap.Add(key, nodeIndex);
|
|
|
|
|
|
AddToTail(nodeIndex);
|
|
|
|
|
|
count++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// ɾ<><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </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>
|
|
|
|
|
|
/// <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Clear()
|
|
|
|
|
|
{
|
|
|
|
|
|
hashMap.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>нڵ㵽<DAB5><E3B5BD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
|
|
|
|
|
|
freeList.Clear();
|
|
|
|
|
|
for (int i = 0; i < capacity; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
freeList.Add(i);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
headIndex = -1;
|
|
|
|
|
|
tailIndex = -1;
|
|
|
|
|
|
count = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
private readonly int AllocateNode()
|
|
|
|
|
|
{
|
|
|
|
|
|
int index = freeList[^1];
|
|
|
|
|
|
freeList.RemoveAtSwapBack(freeList.Length - 1);
|
|
|
|
|
|
return index;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20>ͷŽڵ<C5BD><DAB5><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
private readonly void FreeNode(int index)
|
|
|
|
|
|
{
|
|
|
|
|
|
freeList.Add(index);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ڵ<EFBFBD><DAB5>ƶ<EFBFBD><C6B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD><CEB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD>ʹ<EFBFBD>ã<EFBFBD>
|
|
|
|
|
|
private void MoveToTail(int nodeIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (nodeIndex == tailIndex)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
RemoveFromList(nodeIndex);
|
|
|
|
|
|
AddToTail(nodeIndex);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD>ӵ<EFBFBD>β<EFBFBD><CEB2>
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>գ<EFBFBD>ͷβָ<CEB2><D6B8>ͬһ<CDAC>ڵ<EFBFBD>
|
|
|
|
|
|
if (!IsValidIndex(headIndex))
|
|
|
|
|
|
{
|
|
|
|
|
|
headIndex = nodeIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD><C6B3>ڵ<EFBFBD>
|
|
|
|
|
|
private void RemoveFromList(int nodeIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node node = nodes[nodeIndex];
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>ǰһ<C7B0><D2BB><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>nextָ<74><D6B8>
|
|
|
|
|
|
if (IsValidIndex(node.prevIndex))
|
|
|
|
|
|
{
|
|
|
|
|
|
Node prev = nodes[node.prevIndex];
|
|
|
|
|
|
prev.nextIndex = node.nextIndex;
|
|
|
|
|
|
nodes[node.prevIndex] = prev;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// û<><C3BB>ǰһ<C7B0><D2BB><EFBFBD>ڵ㣬˵<E3A3AC><CBB5><EFBFBD><EFBFBD>ͷ<EFBFBD>ڵ<EFBFBD>
|
|
|
|
|
|
headIndex = node.nextIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>º<EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>prevָ<76><D6B8>
|
|
|
|
|
|
if (IsValidIndex(node.nextIndex))
|
|
|
|
|
|
{
|
|
|
|
|
|
Node next = nodes[node.nextIndex];
|
|
|
|
|
|
next.prevIndex = node.prevIndex;
|
|
|
|
|
|
nodes[node.nextIndex] = next;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// û<>к<EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ڵ㣬˵<E3A3AC><CBB5><EFBFBD><EFBFBD>β<EFBFBD>ڵ<EFBFBD>
|
|
|
|
|
|
tailIndex = node.prevIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>̭ͷ<CCAD><CDB7><EFBFBD>ڵ㣨<DAB5><E3A3A8><EFBFBD><EFBFBD>δʹ<CEB4>ã<EFBFBD>
|
|
|
|
|
|
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; // <20><><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>Է<EFBFBD><D4B7><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
public readonly int Count => count;
|
|
|
|
|
|
public readonly int Capacity => capacity;
|
|
|
|
|
|
public readonly bool IsCreated => hashMap.IsCreated;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Native LFUCache - <20><><EFBFBD><EFBFBD>Unity.Collections<6E>ĸ<EFBFBD><C4B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EEB2BB><C6B5>ʹ<EFBFBD>û<EFBFBD><C3BB><EFBFBD>
|
|
|
|
|
|
/// Burst<73><74><EFBFBD>ݣ<EFBFBD><DDA3><EFBFBD>Ҫ<EFBFBD>ֶ<EFBFBD>Dispose
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="TKey"><3E><><EFBFBD><EFBFBD><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>unmanaged<65><64><EFBFBD>ͣ<EFBFBD></typeparam>
|
|
|
|
|
|
/// <typeparam name="TValue">ֵ<><D6B5><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>unmanaged<65><64><EFBFBD>ͣ<EFBFBD></typeparam>
|
|
|
|
|
|
public struct NativeLFUCache<TKey, TValue> : IDisposable
|
|
|
|
|
|
where TKey : unmanaged, IEquatable<TKey>
|
|
|
|
|
|
where TValue : unmanaged
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD>
|
|
|
|
|
|
private struct Node
|
|
|
|
|
|
{
|
|
|
|
|
|
public TKey key;
|
|
|
|
|
|
public TValue value;
|
|
|
|
|
|
public int frequency; // <20><><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5>
|
|
|
|
|
|
public int prevIndex; // ͬƵ<CDAC><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD>ǰһ<C7B0><D2BB><EFBFBD>ڵ<EFBFBD>
|
|
|
|
|
|
public int nextIndex; // ͬƵ<CDAC><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>еĺ<D0B5>һ<EFBFBD><D2BB><EFBFBD>ڵ<EFBFBD>
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Ƶ<><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷβ
|
|
|
|
|
|
private struct FrequencyList
|
|
|
|
|
|
{
|
|
|
|
|
|
public int headIndex; // <20><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD>ڵ㣨<DAB5><E3A3A8><EFBFBD><EFBFBD>δʹ<CEB4>ã<EFBFBD>
|
|
|
|
|
|
public int tailIndex; // <20><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD>ڵ㣨<DAB5><E3A3A8><EFBFBD><EFBFBD>ʹ<EFBFBD>ã<EFBFBD>
|
|
|
|
|
|
|
|
|
|
|
|
public readonly bool IsEmpty => headIndex == -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private readonly NativeHashMap<TKey, int> keyToNodeIndex; // key -> nodeIndex
|
|
|
|
|
|
private NativeList<Node> nodes; // <20>ڵ<EFBFBD><DAB5><EFBFBD>
|
|
|
|
|
|
private readonly NativeList<int> freeList; // <20><><EFBFBD>нڵ<D0BD><DAB5><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
private NativeHashMap<int, FrequencyList> freqToList; // frequency -> FrequencyList
|
|
|
|
|
|
|
|
|
|
|
|
private readonly int capacity;
|
|
|
|
|
|
private int count;
|
|
|
|
|
|
private int minFrequency; // <20><>ǰ<EFBFBD><C7B0>СƵ<D0A1><C6B5>
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
// Ԥ<><D4A4><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>
|
|
|
|
|
|
nodes.Length = capacity;
|
|
|
|
|
|
for (int i = capacity - 1; i >= 0; i--)
|
|
|
|
|
|
{
|
|
|
|
|
|
freeList.Add(i);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><C6B5>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool TryGetValue(TKey key, out TValue value)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (keyToNodeIndex.TryGetValue(key, out int nodeIndex))
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD>ӷ<EFBFBD><D3B7><EFBFBD>Ƶ<EFBFBD><C6B5>
|
|
|
|
|
|
IncreaseFrequency(nodeIndex);
|
|
|
|
|
|
|
|
|
|
|
|
value = nodes[nodeIndex].value;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
value = default;
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD>ӻ<EFBFBD><D3BB><EFBFBD><EFBFBD>»<EFBFBD><C2BB><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Put(TKey key, TValue value)
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
|
|
|
|
|
if (keyToNodeIndex.TryGetValue(key, out int nodeIndex))
|
|
|
|
|
|
{
|
|
|
|
|
|
Node node = nodes[nodeIndex];
|
|
|
|
|
|
node.value = value;
|
|
|
|
|
|
nodes[nodeIndex] = node;
|
|
|
|
|
|
|
|
|
|
|
|
IncreaseFrequency(nodeIndex);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̭<EFBFBD><CCAD>СƵ<D0A1>ʵĽڵ<C4BD>
|
|
|
|
|
|
if (count >= capacity)
|
|
|
|
|
|
{
|
|
|
|
|
|
EvictMinFrequencyNode();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>½ڵ㣬<DAB5><E3A3AC>ʼƵ<CABC><C6B5>Ϊ1
|
|
|
|
|
|
nodeIndex = AllocateNode();
|
|
|
|
|
|
nodes[nodeIndex] = new Node
|
|
|
|
|
|
{
|
|
|
|
|
|
key = key,
|
|
|
|
|
|
value = value,
|
|
|
|
|
|
frequency = 1,
|
|
|
|
|
|
prevIndex = -1,
|
|
|
|
|
|
nextIndex = -1
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
keyToNodeIndex.Add(key, nodeIndex);
|
|
|
|
|
|
AddToFrequencyList(nodeIndex, 1);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>СƵ<D0A1><C6B5>
|
|
|
|
|
|
if (minFrequency == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
minFrequency = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
count++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// ɾ<><C9BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public bool Remove(TKey key)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!keyToNodeIndex.TryGetValue(key, out int nodeIndex))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
RemoveNode(nodeIndex);
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public void Clear()
|
|
|
|
|
|
{
|
|
|
|
|
|
keyToNodeIndex.Clear();
|
|
|
|
|
|
freqToList.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>нڵ㵽<DAB5><E3B5BD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
|
|
|
|
|
|
freeList.Clear();
|
|
|
|
|
|
for (int i = 0; i < capacity; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
freeList.Add(i);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
minFrequency = 0;
|
|
|
|
|
|
count = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>
|
|
|
|
|
|
/// </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 <EFBFBD>ڲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
|
|
private int AllocateNode()
|
|
|
|
|
|
{
|
|
|
|
|
|
int index = freeList[^1];
|
|
|
|
|
|
freeList.RemoveAtSwapBack(freeList.Length - 1);
|
|
|
|
|
|
return index;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void FreeNode(int index)
|
|
|
|
|
|
{
|
|
|
|
|
|
freeList.Add(index);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD>ӽڵ<D3BD><DAB5>ķ<EFBFBD><C4B7><EFBFBD>Ƶ<EFBFBD><C6B5>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void IncreaseFrequency(int nodeIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node node = nodes[nodeIndex];
|
|
|
|
|
|
int oldFreq = node.frequency;
|
|
|
|
|
|
int newFreq = oldFreq + 1;
|
|
|
|
|
|
|
|
|
|
|
|
// <20>Ӿ<EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD>
|
|
|
|
|
|
RemoveFromFrequencyList(nodeIndex, oldFreq);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>СƵ<D0A1><C6B5>
|
|
|
|
|
|
if (oldFreq == minFrequency && GetFrequencyListHead(oldFreq) == -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
minFrequency = newFreq;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>½ڵ<C2BD>Ƶ<EFBFBD><C6B5>
|
|
|
|
|
|
node.frequency = newFreq;
|
|
|
|
|
|
nodes[nodeIndex] = node;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ӵ<EFBFBD><D3B5><EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
AddToFrequencyList(nodeIndex, newFreq);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD><C6B3>ڵ<EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void RemoveFromFrequencyList(int nodeIndex, int frequency)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!freqToList.TryGetValue(frequency, out var list))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
Node node = nodes[nodeIndex];
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD>ڵ<EFBFBD>
|
|
|
|
|
|
if (node.prevIndex == -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
list.headIndex = node.nextIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>ǰһ<C7B0><D2BB><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>nextָ<74><D6B8>
|
|
|
|
|
|
Node prevNode = nodes[node.prevIndex];
|
|
|
|
|
|
prevNode.nextIndex = node.nextIndex;
|
|
|
|
|
|
nodes[node.prevIndex] = prevNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD>ڵ<EFBFBD>
|
|
|
|
|
|
if (node.nextIndex == -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
list.tailIndex = node.prevIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD>º<EFBFBD>һ<EFBFBD><D2BB><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD>prevָ<76><D6B8>
|
|
|
|
|
|
Node nextNode = nodes[node.nextIndex];
|
|
|
|
|
|
nextNode.prevIndex = node.prevIndex;
|
|
|
|
|
|
nodes[node.nextIndex] = nextNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>գ<EFBFBD><D5A3>Ƴ<EFBFBD><C6B3><EFBFBD>Ƶ<EFBFBD><C6B5>
|
|
|
|
|
|
if (list.headIndex == -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
freqToList.Remove(frequency);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
freqToList[frequency] = list;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><><EFBFBD>ڵ<EFBFBD><DAB5><EFBFBD><EFBFBD>ӵ<EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD><CEB2>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void AddToFrequencyList(int nodeIndex, int frequency)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!freqToList.TryGetValue(frequency, out var list))
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
list = new FrequencyList { headIndex = nodeIndex, tailIndex = nodeIndex };
|
|
|
|
|
|
freqToList.Add(frequency, list);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>ýڵ<C3BD>ָ<EFBFBD><D6B8>
|
|
|
|
|
|
Node node = nodes[nodeIndex];
|
|
|
|
|
|
node.prevIndex = -1;
|
|
|
|
|
|
node.nextIndex = -1;
|
|
|
|
|
|
nodes[nodeIndex] = node;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20><><EFBFBD>ӵ<EFBFBD><D3B5><EFBFBD><EFBFBD><EFBFBD>β<EFBFBD><CEB2>
|
|
|
|
|
|
int oldTail = list.tailIndex;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>ԭβ<D4AD>ڵ<EFBFBD>
|
|
|
|
|
|
Node oldTailNode = nodes[oldTail];
|
|
|
|
|
|
oldTailNode.nextIndex = nodeIndex;
|
|
|
|
|
|
nodes[oldTail] = oldTailNode;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>½ڵ<C2BD>
|
|
|
|
|
|
Node newNode = nodes[nodeIndex];
|
|
|
|
|
|
newNode.prevIndex = oldTail;
|
|
|
|
|
|
newNode.nextIndex = -1;
|
|
|
|
|
|
nodes[nodeIndex] = newNode;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β
|
|
|
|
|
|
list.tailIndex = nodeIndex;
|
|
|
|
|
|
freqToList[frequency] = list;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>ȡƵ<C8A1><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD>ڵ<EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private int GetFrequencyListHead(int frequency)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (freqToList.TryGetValue(frequency, out var list))
|
|
|
|
|
|
{
|
|
|
|
|
|
return list.headIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20><>̭<EFBFBD><CCAD>СƵ<D0A1>ʵĽڵ㣨<DAB5><E3A3A8>̭<EFBFBD><CCAD>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD>ڵ㣩
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void EvictMinFrequencyNode()
|
|
|
|
|
|
{
|
|
|
|
|
|
// <20>ҵ<EFBFBD><D2B5>нڵ<D0BD><DAB5><EFBFBD><EFBFBD><EFBFBD>СƵ<D0A1><C6B5>
|
|
|
|
|
|
while (minFrequency <= capacity && GetFrequencyListHead(minFrequency) == -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
minFrequency++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (minFrequency > capacity) return;
|
|
|
|
|
|
|
|
|
|
|
|
int headIndex = GetFrequencyListHead(minFrequency);
|
|
|
|
|
|
if (headIndex == -1) return;
|
|
|
|
|
|
|
|
|
|
|
|
RemoveNode(headIndex);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// <20>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ㣨<DAB5><E3A3A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݽṹ<DDBD><E1B9B9>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD>
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void RemoveNode(int nodeIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node node = nodes[nodeIndex];
|
|
|
|
|
|
|
|
|
|
|
|
// <20><>Ƶ<EFBFBD><C6B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƴ<EFBFBD>
|
|
|
|
|
|
RemoveFromFrequencyList(nodeIndex, node.frequency);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>HashMap<61>Ƴ<EFBFBD>
|
|
|
|
|
|
keyToNodeIndex.Remove(node.key);
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>սڵ<D5BD>
|
|
|
|
|
|
FreeNode(nodeIndex);
|
|
|
|
|
|
count--;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>Է<EFBFBD><D4B7><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
|
|
// <20>ĸ<EFBFBD><C4B8><EFBFBD><EFBFBD><EFBFBD>ͷβָ<CEB2><D6B8>
|
|
|
|
|
|
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]; // <20>ȶ<EFBFBD>ȡ
|
|
|
|
|
|
|
|
|
|
|
|
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; // д<><D0B4>
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4>Replace
|
|
|
|
|
|
int totalSize = t1Count + t2Count;
|
|
|
|
|
|
if (totalSize >= capacity)
|
|
|
|
|
|
{
|
|
|
|
|
|
Replace();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>½ڵ㵽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;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>pֵ
|
|
|
|
|
|
if (isB1) p = Math.Min(p + delta, capacity);
|
|
|
|
|
|
else p = Math.Max(p - delta, 0);
|
|
|
|
|
|
|
|
|
|
|
|
// ִ<><D6B4><EFBFBD>滻
|
|
|
|
|
|
Replace();
|
|
|
|
|
|
|
|
|
|
|
|
// <20>ƶ<EFBFBD><C6B6>ڵ<EFBFBD>
|
|
|
|
|
|
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 <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
|
|
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]; // <20><>ȡ
|
|
|
|
|
|
node.listType = listType;
|
|
|
|
|
|
node.prevIndex = -1;
|
|
|
|
|
|
|
|
|
|
|
|
switch (listType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case LIST_T1:
|
|
|
|
|
|
node.nextIndex = t1Head;
|
|
|
|
|
|
nodes[nodeIndex] = node; // д<><D0B4>
|
|
|
|
|
|
if (t1Head != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node headNode = nodes[t1Head];
|
|
|
|
|
|
headNode.prevIndex = nodeIndex;
|
|
|
|
|
|
nodes[t1Head] = headNode; // д<><D0B4>
|
|
|
|
|
|
}
|
|
|
|
|
|
t1Head = nodeIndex;
|
|
|
|
|
|
if (t1Tail == -1) t1Tail = nodeIndex;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case LIST_T2:
|
|
|
|
|
|
node.nextIndex = t2Head;
|
|
|
|
|
|
nodes[nodeIndex] = node; // д<><D0B4>
|
|
|
|
|
|
if (t2Head != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node headNode = nodes[t2Head];
|
|
|
|
|
|
headNode.prevIndex = nodeIndex;
|
|
|
|
|
|
nodes[t2Head] = headNode; // д<><D0B4>
|
|
|
|
|
|
}
|
|
|
|
|
|
t2Head = nodeIndex;
|
|
|
|
|
|
if (t2Tail == -1) t2Tail = nodeIndex;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case LIST_B1:
|
|
|
|
|
|
node.nextIndex = b1Head;
|
|
|
|
|
|
nodes[nodeIndex] = node; // д<><D0B4>
|
|
|
|
|
|
if (b1Head != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node headNode = nodes[b1Head];
|
|
|
|
|
|
headNode.prevIndex = nodeIndex;
|
|
|
|
|
|
nodes[b1Head] = headNode; // д<><D0B4>
|
|
|
|
|
|
}
|
|
|
|
|
|
b1Head = nodeIndex;
|
|
|
|
|
|
if (b1Tail == -1) b1Tail = nodeIndex;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case LIST_B2:
|
|
|
|
|
|
node.nextIndex = b2Head;
|
|
|
|
|
|
nodes[nodeIndex] = node; // д<><D0B4>
|
|
|
|
|
|
if (b2Head != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node headNode = nodes[b2Head];
|
|
|
|
|
|
headNode.prevIndex = nodeIndex;
|
|
|
|
|
|
nodes[b2Head] = headNode; // д<><D0B4>
|
|
|
|
|
|
}
|
|
|
|
|
|
b2Head = nodeIndex;
|
|
|
|
|
|
if (b2Tail == -1) b2Tail = nodeIndex;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void RemoveFromList(int nodeIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node node = nodes[nodeIndex]; // <20><>ȡ
|
|
|
|
|
|
int prev = node.prevIndex;
|
|
|
|
|
|
int next = node.nextIndex;
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><CDB8><EFBFBD>ͷβָ<CEB2><D6B8>
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>ھ<EFBFBD>
|
|
|
|
|
|
if (prev != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node prevNode = nodes[prev];
|
|
|
|
|
|
prevNode.nextIndex = next;
|
|
|
|
|
|
nodes[prev] = prevNode; // д<><D0B4>
|
|
|
|
|
|
}
|
|
|
|
|
|
if (next != -1)
|
|
|
|
|
|
{
|
|
|
|
|
|
Node nextNode = nodes[next];
|
|
|
|
|
|
nextNode.prevIndex = prev;
|
|
|
|
|
|
nodes[next] = nextNode; // д<><D0B4>
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
node.prevIndex = node.nextIndex = -1;
|
|
|
|
|
|
nodes[nodeIndex] = node; // д<><D0B4>
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#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]; // <20><>ȡ
|
|
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>¼<EFBFBD><C2BC><EFBFBD>
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-11-20 17:29:16 +08:00
|
|
|
|
}
|