示例#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)
                    {
                        object primary, secondary;
                        depHnd.GetPrimaryAndSecondary(out primary, out secondary);
                        if (primary != null)
                        {
                            // Entry is used and has not expired. Link it into the appropriate bucket list.
                            newEntries[newEntriesIndex].HashCode = hashCode;
                            newEntries[newEntriesIndex].depHnd   = depHnd;
                            int bucket = hashCode & (newBuckets.Length - 1);
                            newEntries[newEntriesIndex].Next = newBuckets[bucket];
                            newBuckets[bucket] = newEntriesIndex;
                            newEntriesIndex++;
                        }
                        else
                        {
                            // Pretend the item was removed, so that this container's finalizer
                            // will clean up this dependent handle.
                            Volatile.Write(ref _entries[entriesIndex].HashCode, -1);
                        }
                    }
                }

                // Create the new container.  We want to transfer the responsibility of freeing the handles from
                // the old container to the new container, and also ensure that the new container isn't finalized
                // while the old container may still be in use.  As such, we store a reference from the old container
                // to the new one, which will keep the new container alive as long as the old one is.
                var newContainer = new Container(_parent, newBuckets, newEntries, newEntriesIndex);

                _oldKeepAlive = newContainer; // once this is set, the old container's finalizer will not free transferred dependent handles

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

                return(newContainer);
            }