/// <summary>
 /// set the comparer to use when getting the hash code.
 /// If comparer is null, the current comparer is not changed.
 /// </summary>
 public static void SetComparer <TKey>(SimpleSet <TKey> Set, IEqualityComparer <TKey> comparer)
 {
     if (comparer != null)
     {
         Set.Comparer = comparer;
     }
 }
        /// <summary>
        /// Adds the value to the set using the key.
        /// If replace is true and the key is already present on the set, we will replace the value,
        /// if false, we will return false to signal the failure.
        /// </summary>
        public static void Add <TKey>(SimpleSet <TKey> Set, TKey key)
        {
            var hash  = Set.Comparer.GetHashCode(key);
            var index = (hash & int.MaxValue) % Set.Capacity;

            var inserted = false;
            var entry    = Set.Entries[index];

            if (entry != null)
            {
                // If we find a entry with the given key, validate if it's the same key
                // this is needed because two keys can produce the same hash
                if (entry.HashCode != hash && !Set.Comparer.Equals(key, entry.Key))
                {
                    // It's a collision, create an entry and add to the linked list of collisions
                    var newEntry = CreateEntry(Set, key, hash);

                    // Find the last element of the collision chain
                    while (entry.Next != null)
                    {
                        entry = entry.Next;
                    }

                    entry.Next = newEntry;

                    inserted = true;

                    if (Set.Count >= Set.Capacity)
                    {
                        Expand(Set);
                    }
                }
            }
            // Did not found, create and add an entry
            else
            {
                var newEntry = CreateEntry(Set, key, hash);

                if (Set.Count >= Set.Capacity)
                {
                    Expand(Set);
                }

                Set.Entries[index] = newEntry;
                inserted           = true;
            }

            if (inserted)
            {
                Set.Count++;
            }
        }
        /// <summary>
        /// Creates a new set entry with the given values.
        /// </summary>
        private static SetEntry <TKey> CreateEntry <TKey>(SimpleSet <TKey> Set, TKey key, int hash)
        {
            SetEntry <TKey> newEntry;

            if (Set.EntryPool.Count > 0)
            {
                newEntry = Set.EntryPool[Set.EntryPool.Count - 1];
                SList.RemoveLast(Set.EntryPool); // remove last for better perfomance
            }
            else
            {
                newEntry = new SetEntry <TKey>();
            }

            newEntry.Key      = key;
            newEntry.HashCode = hash;
            return(newEntry);
        }
        /// <summary>
        /// Creates a fake hash set with the given capacity.
        /// This will also create an pool of SetEntry (the internal class used to store elements
        /// on the array) to reduce garbage generation and improve performance.
        /// If preWarmPool is true, this will pre-instantiate the elements on the pool.
        /// If preWarmPool is false, this will only create a SimpleSet of size 'size' and
        /// pool removed elements from the set for later reuse.
        /// </summary>
        public static SimpleSet <TKey> Create <TKey>(int size, bool preWarmPool)
        {
            var Set = new SimpleSet <TKey>();

            Set.Count          = 0;
            Set.Capacity       = GetNextLength(size);
            Set.Entries        = new SetEntry <TKey> [Set.Capacity];
            Set.Comparer       = EqualityComparer <TKey> .Default;
            Set.Enumerator     = new SimpleSetEnumerator <TKey>();
            Set.Enumerator.Set = Set;

            Set.EntryPool = SList.Create <SetEntry <TKey> >(size);
            if (preWarmPool)
            {
                for (int i = 0; i < size; i++)
                {
                    Set.EntryPool[i] = new SetEntry <TKey>();
                }
            }

            return(Set);
        }