Example #1
0
            internal Container Resize(int newSize)
            {
                Debug.Assert(IsPowerOfTwo(newSize));

                // Reallocate both buckets and entries and rebuild the bucket and entries from scratch.
                // This serves both to scrub entries with expired keys and to put the new entries in the proper bucket.
                int[] newBuckets = new int[newSize];
                for (int bucketIndex = 0; bucketIndex < newSize; bucketIndex++)
                {
                    newBuckets[bucketIndex] = -1;
                }
                Entry[] newEntries      = new Entry[newSize];
                int     newEntriesIndex = 0;

                // Migrate existing entries to the new table.
                for (int entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++)
                {
                    int             hashCode = _entries[entriesIndex].hashCode;
                    DependentHandle depHnd   = _entries[entriesIndex].depHnd;
                    if (hashCode != -1 && depHnd.IsAllocated && depHnd.GetPrimary() != null)
                    {
                        // Entry is used and has not expired. Link it into the appropriate bucket list.
                        // Note that we have to copy the DependentHandle, since the original copy will be freed
                        // by the Container's finalizer.
                        newEntries[newEntriesIndex].hashCode = hashCode;
                        newEntries[newEntriesIndex].depHnd   = depHnd.AllocateCopy();
                        int bucket = hashCode & (newBuckets.Length - 1);
                        newEntries[newEntriesIndex].next = newBuckets[bucket];
                        newBuckets[bucket] = newEntriesIndex;
                        newEntriesIndex++;
                    }
                }

                GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles.

                return(new Container(newBuckets, newEntries, newEntriesIndex));
            }
Example #2
0
            internal Container Resize()
            {
                // Start by assuming we won't resize.
                int newSize = _buckets.Length;

                // If any expired or removed keys exist, we won't resize.
                bool hasExpiredEntries = false;
                int  entriesIndex;

                for (entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++)
                {
                    if (_entries[entriesIndex].hashCode == -1)
                    {
                        // the entry was removed
                        hasExpiredEntries = true;
                        break;
                    }

                    if (_entries[entriesIndex].depHnd.IsAllocated && _entries[entriesIndex].depHnd.GetPrimary() == null)
                    {
                        // the entry has expired
                        hasExpiredEntries = true;
                        break;
                    }
                }

                if (!hasExpiredEntries)
                {
                    newSize = System.Collections.HashHelpers.GetPrime(_buckets.Length == 0 ? _initialCapacity + 1 : _buckets.Length * 2);
                }


                // Reallocate both buckets and entries and rebuild the bucket and freelists from scratch.
                // This serves both to scrub entries with expired keys and to put the new entries in the proper bucket.
                int newFreeList = -1;

                int[] newBuckets = new int[newSize];
                for (int bucketIndex = 0; bucketIndex < newSize; bucketIndex++)
                {
                    newBuckets[bucketIndex] = -1;
                }
                Entry[] newEntries = new Entry[newSize];

                // Migrate existing entries to the new table.
                for (entriesIndex = 0; entriesIndex < _entries.Length; entriesIndex++)
                {
                    DependentHandle depHnd = _entries[entriesIndex].depHnd;
                    if (_entries[entriesIndex].hashCode != -1 && depHnd.IsAllocated && depHnd.GetPrimary() != null)
                    {
                        // Entry is used and has not expired. Link it into the appropriate bucket list.
                        // Note that we have to copy the DependentHandle, since the original copy will be freed
                        // by the Container's finalizer.
                        int bucket = _entries[entriesIndex].hashCode % newSize;
                        newEntries[entriesIndex].depHnd   = depHnd.AllocateCopy();
                        newEntries[entriesIndex].hashCode = _entries[entriesIndex].hashCode;
                        newEntries[entriesIndex].next     = newBuckets[bucket];
                        newBuckets[bucket] = entriesIndex;
                    }
                    else
                    {
                        // Entry has either expired or was on the freelist to begin with. Either way
                        // insert it on the new freelist.
                        // We do not free the underlying GC handle here, as we may be racing with readers who already saw
                        // the old Container.  The GC handle will be free'd in Container's finalizer.
                        newEntries[entriesIndex].depHnd = new DependentHandle();
                        newEntries[entriesIndex].next   = newFreeList;
                        newFreeList = entriesIndex;
                    }
                }

                // Add remaining entries to freelist.
                while (entriesIndex != newEntries.Length)
                {
                    newEntries[entriesIndex].depHnd = new DependentHandle();
                    newEntries[entriesIndex].next   = newFreeList;
                    newFreeList = entriesIndex;
                    entriesIndex++;
                }

                GC.KeepAlive(this); // ensure we don't get finalized while accessing DependentHandles.

                return(new Container()
                {
                    _buckets = newBuckets,
                    _entries = newEntries,
                    _freeList = newFreeList
                });
            }