@@ -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 ;
}
}
}