com.alicizax.unity.framework/Runtime/ObjectPool/StringOpenHashMap.cs
2026-04-24 14:33:26 +08:00

184 lines
5.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

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

using System;
using System.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;
}
}
}