171 lines
5.0 KiB
C#
171 lines
5.0 KiB
C#
|
|
using System;
|
||
|
|
using System.Runtime.CompilerServices;
|
||
|
|
|
||
|
|
namespace AlicizaX.ObjectPool
|
||
|
|
{
|
||
|
|
|
||
|
|
internal struct IntOpenHashMap
|
||
|
|
{
|
||
|
|
private int[] m_Buckets;
|
||
|
|
private int[] 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 IntOpenHashMap(int capacity)
|
||
|
|
{
|
||
|
|
int cap = NextPowerOf2(Math.Max(capacity, MinCapacity));
|
||
|
|
m_Mask = cap - 1;
|
||
|
|
m_Buckets = new int[cap];
|
||
|
|
m_Keys = new int[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(int key, out int value)
|
||
|
|
{
|
||
|
|
if (m_Buckets == null) { value = -1; return false; }
|
||
|
|
int i = m_Buckets[(key & 0x7FFFFFFF) & 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(int key, int value)
|
||
|
|
{
|
||
|
|
if (m_Count >= ((m_Mask + 1) * 3 >> 2))
|
||
|
|
Grow();
|
||
|
|
|
||
|
|
int bucket = (key & 0x7FFFFFFF) & 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 = (key & 0x7FFFFFFF) & 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(int key)
|
||
|
|
{
|
||
|
|
if (m_Buckets == null) return false;
|
||
|
|
int bucket = (key & 0x7FFFFFFF) & 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] = 0;
|
||
|
|
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;
|
||
|
|
}
|
||
|
|
|
||
|
|
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 int[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 nb = (newKeys[ni] & 0x7FFFFFFF) & 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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|