private static void RemoveHashItem(ref DynamicBuffer <BufferHashSetElementData> hashMapBuffer, int hashMapIndex, int bufferIndex,
                                       int bufferCapacity)
    {
        //get buffer element hash index
        var currentItemHashIndex = GetHashItemIndex(ref hashMapBuffer, hashMapIndex, bufferIndex);

        //get chain last item
        var chainLastHashItemIndex = GetChainLastHashItemIndex(ref hashMapBuffer, hashMapIndex);

        // if root item
        if (currentItemHashIndex < bufferCapacity)
        {
            // single item chain
            if (hashMapBuffer[hashMapIndex].NextItem < 0)
            {
                hashMapBuffer[hashMapIndex] = new BufferHashSetElementData(-1, true, -1, -1, hashMapBuffer[hashMapIndex].HashMapIndex);
            }
            else
            {
                RemoveHashItemInChain(ref hashMapBuffer, currentItemHashIndex, chainLastHashItemIndex);
                MoveTailToAndCut(ref hashMapBuffer, chainLastHashItemIndex);
            }
        }
        //if not root item
        else
        {
            RemoveHashItemInChain(ref hashMapBuffer, currentItemHashIndex, chainLastHashItemIndex);
            MoveTailToAndCut(ref hashMapBuffer, chainLastHashItemIndex);
        }
    }
    private static void SetHashItemIndex(ref DynamicBuffer <BufferHashSetElementData> hashMapBuffer, int index, int bufferItemIndex)
    {
        var hashMapBufferIndex = hashMapBuffer[bufferItemIndex].HashMapIndex;

        BufferHashSetElementData hashSetItem = hashMapBuffer[hashMapBufferIndex];

        for (int i = 0; i < hashMapBuffer.Capacity; i++)
        {
            if (hashMapBuffer[hashMapBufferIndex].Index == bufferItemIndex)
            {
                break;
            }

            hashMapBufferIndex = hashMapBuffer[hashMapBufferIndex].NextItem;
            hashSetItem        = hashMapBuffer[hashMapBufferIndex];
        }

        hashSetItem.Index = index;

        if (index < 0)
        {
            hashSetItem.Empty = true;
        }

        hashMapBuffer[hashMapBufferIndex] = hashSetItem;
    }
    private static void SetHashItemHashIndex(ref DynamicBuffer <BufferHashSetElementData> hashMapBuffer, int index, int bufferItemIndex)
    {
        BufferHashSetElementData hashSetItem = hashMapBuffer[bufferItemIndex];

        hashSetItem.HashMapIndex = index;

        hashMapBuffer[bufferItemIndex] = hashSetItem;
    }
    public static bool TryAdd <T>(DynamicBuffer <T> buffer, DynamicBuffer <BufferHashSetElementData> hashMapBuffer, T element)
        where T : struct, IBufferElementData, IEqualityComparer <T>
    {
        if (buffer.Length >= buffer.Capacity)
        {
            Debug.Log("Error, buffer is full");
            return(false);
        }

        int index = GetIndex(element, buffer.Capacity);

        if (hashMapBuffer[index].Empty)
        {
            int newElementIndex = buffer.Add(element);

            var hashMapBufferItem = hashMapBuffer[index];
            hashMapBufferItem.Index = newElementIndex;
            hashMapBufferItem.Empty = false;
            hashMapBuffer[index]    = hashMapBufferItem;

            var hashMapItemByIndex = hashMapBuffer[newElementIndex];
            hashMapItemByIndex.HashMapIndex = index;
            hashMapBuffer[newElementIndex]  = hashMapItemByIndex;

            return(true);
        }

        int hashIndex = index;
        int nextIndex = hashMapBuffer[hashIndex].NextItem;

        for (int i = 0; i < buffer.Capacity; i++)
        {
            if (nextIndex < 0)
            {
                int newElementIndex = buffer.Add(element);

                hashMapBuffer.Add(new BufferHashSetElementData(newElementIndex, false, hashIndex, -1, index));

                hashMapBuffer[hashIndex] = new BufferHashSetElementData
                                               (hashMapBuffer[hashIndex].Index, hashMapBuffer[hashIndex].Empty, hashMapBuffer[hashIndex].PrevItem, hashMapBuffer.Length - 1,
                                               hashMapBuffer[hashIndex].HashMapIndex);

                var hashMapItemByIndex = hashMapBuffer[newElementIndex];
                hashMapItemByIndex.HashMapIndex = index;
                hashMapBuffer[newElementIndex]  = hashMapItemByIndex;

                return(true);
            }

            if (hashMapBuffer[nextIndex].Empty)
            {
                int newElementIndex = buffer.Add(element);

                hashMapBuffer.Add(new BufferHashSetElementData(newElementIndex, false, hashIndex, -1, index));

                hashMapBuffer[hashIndex] = new BufferHashSetElementData
                                               (hashMapBuffer[hashIndex].Index, hashMapBuffer[hashIndex].Empty, hashMapBuffer[hashIndex].PrevItem, hashMapBuffer.Length - 1,
                                               hashMapBuffer[hashIndex].HashMapIndex);

                var hashMapItemByIndex = hashMapBuffer[newElementIndex];
                hashMapItemByIndex.HashMapIndex = index;
                hashMapBuffer[newElementIndex]  = hashMapItemByIndex;

                return(true);
            }

            if (buffer[hashMapBuffer[nextIndex].Index].Equals(element, buffer[hashMapBuffer[nextIndex].Index]))
            {
#if UNITY_EDITOR || DEBUG
                Debug.Log("Already has item, add error::" + index);
#endif
                return(false);
            }

            hashIndex = nextIndex;
            nextIndex = hashMapBuffer[nextIndex].NextItem;
        }

        return(false);
    }