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