184 lines
5.5 KiB
C#
184 lines
5.5 KiB
C#
using System;
|
||
using System.Runtime.CompilerServices;
|
||
|
||
namespace AlicizaX.ObjectPool
|
||
{
|
||
/// <summary>
|
||
/// 字符串键的开放寻址哈希表,零GC实现
|
||
/// </summary>
|
||
internal struct StringOpenHashMap
|
||
{
|
||
private int[] m_Buckets;
|
||
private string[] m_Keys;
|
||
private int[] m_Values;
|
||
private int[] m_Next;
|
||
private int m_Count;
|
||
private int m_FreeList;
|
||
private int m_Mask;
|
||
private int m_AllocCount;
|
||
|
||
private const int MinCapacity = 8;
|
||
|
||
public int Count => m_Count;
|
||
|
||
public StringOpenHashMap(int capacity)
|
||
{
|
||
int cap = NextPowerOf2(Math.Max(capacity, MinCapacity));
|
||
m_Mask = cap - 1;
|
||
m_Buckets = new int[cap];
|
||
m_Keys = new string[cap];
|
||
m_Values = new int[cap];
|
||
m_Next = new int[cap];
|
||
m_Count = 0;
|
||
m_FreeList = 0;
|
||
m_AllocCount = 0;
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public bool TryGetValue(string key, out int value)
|
||
{
|
||
if (m_Buckets == null || key == null) { value = -1; return false; }
|
||
int hash = key.GetHashCode() & 0x7FFFFFFF;
|
||
int i = m_Buckets[hash & m_Mask];
|
||
while (i > 0)
|
||
{
|
||
int idx = i - 1;
|
||
if (m_Keys[idx] == key) { value = m_Values[idx]; return true; }
|
||
i = m_Next[idx];
|
||
}
|
||
value = -1;
|
||
return false;
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public void AddOrUpdate(string key, int value)
|
||
{
|
||
if (key == null) return;
|
||
if (m_Count >= ((m_Mask + 1) * 3 >> 2))
|
||
Grow();
|
||
|
||
int hash = key.GetHashCode() & 0x7FFFFFFF;
|
||
int bucket = hash & m_Mask;
|
||
int i = m_Buckets[bucket];
|
||
while (i > 0)
|
||
{
|
||
int ei = i - 1;
|
||
if (m_Keys[ei] == key) { m_Values[ei] = value; return; }
|
||
i = m_Next[ei];
|
||
}
|
||
|
||
int idx;
|
||
if (m_FreeList > 0)
|
||
{
|
||
idx = m_FreeList - 1;
|
||
m_FreeList = m_Next[idx];
|
||
}
|
||
else
|
||
{
|
||
if (m_AllocCount > m_Mask) { Grow(); bucket = hash & m_Mask; }
|
||
idx = m_AllocCount++;
|
||
}
|
||
|
||
m_Keys[idx] = key;
|
||
m_Values[idx] = value;
|
||
m_Next[idx] = m_Buckets[bucket];
|
||
m_Buckets[bucket] = idx + 1;
|
||
m_Count++;
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public bool Remove(string key)
|
||
{
|
||
if (m_Buckets == null || key == null) return false;
|
||
int hash = key.GetHashCode() & 0x7FFFFFFF;
|
||
int bucket = hash & m_Mask;
|
||
int prev = 0;
|
||
int i = m_Buckets[bucket];
|
||
while (i > 0)
|
||
{
|
||
int idx = i - 1;
|
||
if (m_Keys[idx] == key)
|
||
{
|
||
if (prev == 0) m_Buckets[bucket] = m_Next[idx];
|
||
else m_Next[prev - 1] = m_Next[idx];
|
||
m_Keys[idx] = null;
|
||
m_Values[idx] = -1;
|
||
m_Next[idx] = m_FreeList;
|
||
m_FreeList = idx + 1;
|
||
m_Count--;
|
||
return true;
|
||
}
|
||
prev = i;
|
||
i = m_Next[idx];
|
||
}
|
||
return false;
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
public bool ContainsKey(string key)
|
||
{
|
||
return TryGetValue(key, out _);
|
||
}
|
||
|
||
public void Clear()
|
||
{
|
||
if (m_Buckets == null) return;
|
||
int cap = m_Mask + 1;
|
||
Array.Clear(m_Buckets, 0, cap);
|
||
Array.Clear(m_Keys, 0, cap);
|
||
Array.Clear(m_Values, 0, cap);
|
||
Array.Clear(m_Next, 0, cap);
|
||
m_Count = 0;
|
||
m_FreeList = 0;
|
||
m_AllocCount = 0;
|
||
}
|
||
|
||
private void Grow()
|
||
{
|
||
int newCap = (m_Mask + 1) << 1;
|
||
if (newCap < MinCapacity) newCap = MinCapacity;
|
||
int newMask = newCap - 1;
|
||
var newBuckets = new int[newCap];
|
||
var newKeys = new string[newCap];
|
||
var newValues = new int[newCap];
|
||
var newNext = new int[newCap];
|
||
|
||
int newAlloc = 0;
|
||
int oldCap = m_Mask + 1;
|
||
for (int b = 0; b < oldCap; b++)
|
||
{
|
||
int i = m_Buckets[b];
|
||
while (i > 0)
|
||
{
|
||
int old = i - 1;
|
||
int ni = newAlloc++;
|
||
newKeys[ni] = m_Keys[old];
|
||
newValues[ni] = m_Values[old];
|
||
int hash = newKeys[ni].GetHashCode() & 0x7FFFFFFF;
|
||
int nb = hash & newMask;
|
||
newNext[ni] = newBuckets[nb];
|
||
newBuckets[nb] = ni + 1;
|
||
i = m_Next[old];
|
||
}
|
||
}
|
||
|
||
m_Buckets = newBuckets;
|
||
m_Keys = newKeys;
|
||
m_Values = newValues;
|
||
m_Next = newNext;
|
||
m_Mask = newMask;
|
||
m_AllocCount = newAlloc;
|
||
m_FreeList = 0;
|
||
}
|
||
|
||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
private static int NextPowerOf2(int v)
|
||
{
|
||
v--;
|
||
v |= v >> 1; v |= v >> 2; v |= v >> 4;
|
||
v |= v >> 8; v |= v >> 16;
|
||
return v + 1;
|
||
}
|
||
}
|
||
}
|