新增性能容器
This commit is contained in:
@@ -109,6 +109,7 @@ namespace Convention.Experimental.Modules
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("This object does not belong to any pool.", instance);
|
||||
throw new PublicType.GameException("This object does not belong to any pool.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace Convention.Collections
|
||||
{
|
||||
@@ -453,4 +454,985 @@ namespace Convention.Collections
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user