/// <summary> /// This operation will grow the inner array and sweep up deleted nodes /// This is an expensive operation that we should minimize the usage of if possible /// </summary> /// <returns></returns> protected void GrowInnerArray() { var oldNodes = InnerArray; int newArraySize; if (PrimeNumberEnumerator.MoveNext() != false) { newArraySize = (int)PrimeNumberEnumerator.Current; } else { throw new ArgumentOutOfRangeException("The ODDictionary has reached its maximum capacity."); } InnerArray = new ODDictionaryNode <TKey, TValue> [newArraySize]; foreach (var node in oldNodes) { if (node != null && node.IsDeleted == false) { // get the initial probe value int keyLocation = GetIndexForKey(node.Key); // confirm that key is not present and get first available insert location bool keyAlreadyPresent; keyLocation = FirstAvailable(keyLocation, node.Key, out keyAlreadyPresent); //we don't need to worry about keyAlreadyPresent because we're repopulating a new array InnerArray[keyLocation] = node; } } }
/// <summary> /// Finds the first available non-key location in the index to perform an insert. Or the key location if it is already present. /// Instead of an out parameter, throw could be used, but in this case, finding a key is to be expected, and try/catch should not be used /// for control flow. /// </summary> /// <param name="keyLocation">Starting index to probe</param> /// <param name="key">The to be inserted</param> /// <param name="keyAlreadyPresent">Outpool boolean, flag is true is the key is already present</param> /// <returns>Location to perform insert or the location of the key if already present</returns> protected int FirstAvailable(int keyLocation, TKey key, out bool keyAlreadyPresent) { ODDictionaryNode <TKey, TValue> currentNode = InnerArray[keyLocation]; int firstGoodLocation = -1; keyAlreadyPresent = false; // probe the values, if it's null we're good while (currentNode != null) { // We found an indentical key, insert is not logically possible, stop searching if (currentNode.Key.Equals(key) && !currentNode.IsDeleted) { keyAlreadyPresent = true; break; } // we found a deleted location, remember it for later to use it if (currentNode.IsDeleted && firstGoodLocation == -1) { firstGoodLocation = keyLocation; } keyLocation = (keyLocation + 1) % InnerArray.Length; currentNode = InnerArray[keyLocation]; } // if we didn't find the key, but we found a first location that's prior to our first null, then return that. if (!keyAlreadyPresent && firstGoodLocation != -1) { keyLocation = firstGoodLocation; } return(keyLocation); }
private bool OptimisticConcurrencyControl; // simple control to detect concurrency exceptions rather than locking resources public ODDictionary() { PrimeNumberEnumerator = SetPrimeNumbers(); PrimeNumberEnumerator.MoveNext(); CurrentSize = 0; InnerArray = new ODDictionaryNode <TKey, TValue> [(int)PrimeNumberEnumerator.Current]; EnumeratorsToInvalidate = new List <ODDictionaryEnumerator <TKey, TValue> >(); OptimisticConcurrencyControl = false; }
/// <summary> /// Allows the user to set the initial value of the inner array /// </summary> /// <param name="initialArraySize">Int32 for the size of the inner array</param> public ODDictionary(int initialArraySize) { PrimeNumberEnumerator = SetPrimeNumbers(); while (PrimeNumberEnumerator.MoveNext() != false) { // next grow will be at least initialArraySize *2 if ((int)PrimeNumberEnumerator.Current > (initialArraySize * 2)) { break; } } CurrentSize = 0; InnerArray = new ODDictionaryNode <TKey, TValue> [initialArraySize]; EnumeratorsToInvalidate = new List <ODDictionaryEnumerator <TKey, TValue> >(); OptimisticConcurrencyControl = false; }
/// <summary> /// Add a Key/Value pair to the collection. Throws exception if key already present. /// </summary> /// <param name="key">Key to be used for retrieval, may not be null</param> /// <param name="value">Value to be returned on retrieval</param> public void Add(TKey key, TValue value) { // check concurrency control if (OptimisticConcurrencyControl == true) { throw new Exception("Optimistic concurrency control violated"); } // set control OptimisticConcurrencyControl = true; // validation if (key == null || value == null) { OptimisticConcurrencyControl = false; throw new ArgumentNullException("Neither key nor value may be null."); } // To minimize collisions, we will grow the collection when it is half full if (CurrentSize > InnerArray.Length / 2) { GrowInnerArray(); } // get the initial probe value int keyLocation = GetIndexForKey(key); // confirm that key is not present and get first available insert location bool keyAlreadyPresent; keyLocation = FirstAvailable(keyLocation, key, out keyAlreadyPresent); if (keyAlreadyPresent) { OptimisticConcurrencyControl = false; throw new ArgumentException("An item with the same key has already been added."); } var odDictionaryNode = new ODDictionaryNode <TKey, TValue>(key, value); InnerArray[keyLocation] = odDictionaryNode; OptimisticConcurrencyControl = false; // release control InvalidateEnumerators(); CurrentSize++; }
/// <summary> /// The find & return method. Specify a key and get the return value requested or set value. /// </summary> /// <param name="key"></param> /// <returns></returns> public TValue this[TKey key] { get { // check concurrency control if (OptimisticConcurrencyControl == true) { throw new Exception("Optimistic concurrency control violated"); } OptimisticConcurrencyControl = true; // validation if (key == null) { OptimisticConcurrencyControl = false; throw new ArgumentNullException("Key may not be null."); } int keyLocation = GetIndexForKey(key); // Find the key bool keyAlreadyPresent; keyLocation = FirstAvailable(keyLocation, key, out keyAlreadyPresent); if (!keyAlreadyPresent) { OptimisticConcurrencyControl = false; throw new KeyNotFoundException("The given key was not present in the dictionary."); } var value = InnerArray[keyLocation].Value; OptimisticConcurrencyControl = false; return(value); } set { // check concurrency control if (OptimisticConcurrencyControl == true) { throw new Exception("Optimistic concurrency control violated"); } OptimisticConcurrencyControl = true; int keyLocation = GetIndexForKey(key); // Find the key bool keyAlreadyPresent; keyLocation = FirstAvailable(keyLocation, key, out keyAlreadyPresent); // if it's not yet in the dictionary, add it if (!keyAlreadyPresent) { var odDictionaryNode = new ODDictionaryNode <TKey, TValue>(key, value); InnerArray[keyLocation] = odDictionaryNode; CurrentSize++; OptimisticConcurrencyControl = false; } else { // else just update the value InnerArray[keyLocation].Value = value; OptimisticConcurrencyControl = false; } InvalidateEnumerators(); } }