| File: System\Runtime\Serialization\ObjectIDGenerator.cs | Web Access |
| Project: src\runtime\src\libraries\System.Runtime.Serialization.Formatters\src\System.Runtime.Serialization.Formatters.csproj (System.Runtime.Serialization.Formatters) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; using System.Runtime.CompilerServices; namespace System.Runtime.Serialization { [Obsolete(Obsoletions.LegacyFormatterMessage, DiagnosticId = Obsoletions.LegacyFormatterDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] public class ObjectIDGenerator { private const int NumBins = 4; internal int _currentCount; private int _currentSize; private long[] _ids; private object[] _objs; // Constructs a new ObjectID generator, initializing all of the necessary variables. public ObjectIDGenerator() { _currentCount = 1; _currentSize = 3; // HashHelpers.Primes[0] _ids = new long[_currentSize * NumBins]; _objs = new object[_currentSize * NumBins]; } // Determines where element obj lives, or should live, // within the table. It calculates the hashcode and searches all of the // bins where the given object could live. If it's not found within the bin, // we rehash and go look for it in another bin. If we find the object, we // set found to true and return it's position. If we can't find the object, // we set found to false and return the position where the object should be inserted. private int FindElement(object obj, out bool found) { int hashcode = RuntimeHelpers.GetHashCode(obj); int hashIncrement = (1 + ((hashcode & 0x7FFFFFFF) % (_currentSize - 2))); do { int pos = ((hashcode & 0x7FFFFFFF) % _currentSize) * NumBins; for (int i = pos; i < pos + NumBins; i++) { if (_objs[i] == null) { found = false; return i; } if (_objs[i] == obj) { found = true; return i; } } hashcode += hashIncrement; //the seemingly infinite loop must be revisited later. Currently it is assumed that //always the array will be expanded (Rehash) when it is half full } while (true); } // Gets the id for a particular object, generating one if needed. GetID calls // FindElement to find out where the object lives or should live. If we didn't // find the element, we generate an object id for it and insert the pair into the // table. We return an Int64 for the object id. The out parameter firstTime // is set to true if this is the first time that we have seen this object. public virtual long GetId(object obj, out bool firstTime) { ArgumentNullException.ThrowIfNull(obj); bool found; int pos = FindElement(obj, out found); //We pull out foundID so that rehashing doesn't cause us to lose track of the id that we just found. long foundID; if (!found) { //We didn't actually find the object, so we should need to insert it into //the array and assign it an object id. _objs[pos] = obj; _ids[pos] = _currentCount++; foundID = _ids[pos]; if (_currentCount > (_currentSize * NumBins) / 2) { Rehash(); } } else { foundID = _ids[pos]; } firstTime = !found; return foundID; } // Checks to see if obj has already been assigned an id. If it has, // we return that id, otherwise we return 0. public virtual long HasId(object obj, out bool firstTime) { ArgumentNullException.ThrowIfNull(obj); bool found; int pos = FindElement(obj, out found); if (found) { firstTime = false; return _ids[pos]; } firstTime = true; return 0; } // Rehashes the table by finding the next larger size in the list provided, // allocating two new arrays of that size and rehashing all of the elements in // the old arrays into the new ones. Expensive but necessary. private void Rehash() { int currSize = _currentSize; int newSize = HashHelpers.ExpandPrime(currSize); if (newSize == currSize) { // We just walked off the end of the array. throw new SerializationException(SR.Serialization_TooManyElements); } _currentSize = newSize; long[] newIds = new long[_currentSize * NumBins]; object[] newObjs = new object[_currentSize * NumBins]; long[] oldIds = _ids; object[] oldObjs = _objs; _ids = newIds; _objs = newObjs; for (int j = 0; j < oldObjs.Length; j++) { if (oldObjs[j] != null) { int pos = FindElement(oldObjs[j], out _); _objs[pos] = oldObjs[j]; _ids[pos] = oldIds[j]; } } } } }