/// <summary> /// Capacity specifies the initial size of the StringDictionary. The StringDictionary grows too accomodate more entries as they are added. /// </summary> /// <param name="capacity"></param> public StringDictionary(int capacity) { _capacity = (capacity > _minCapacity ? GetNextCapacity(capacity) : _minCapacity); _capacityLess1 = _capacity - 1; // Minimum capacity of StringDictionary = 1024 entries _entries = new StringDictionaryEntry <T> [_capacity]; // Initialize the space map _spaceMap = new BitArray(_capacity); }
/// <summary> /// This methods adds a given Key value pair to the StringDictionary. Keys need to be unique. Values need not be unique. /// Complexity Average Case: O(log((n + 1/)n)), Worst Case: O(n) /// </summary> /// <param name="key"></param> /// <param name="keyValue"></param> public void Add(string key, T keyValue) { //GetHashCodes(key, out hashA, out hashB); uint hashA = 0, hashB = 0; for (int i = 0; i < key.Length; i++) { hashA = ((hashA << 5) + hashA ^ (uint)key[i]); hashB = ((hashB << 6) + (hashB << 16) - hashB + (uint)key[i]); } uint hash; bool inserted = false; lock (_syncRoot) { for (int i = 0; i < _numHashes; i++) { hash = hashA + _primes[i] * hashB; if (!_spaceMap[(int)(hash & _capacityLess1)]) { _entries[hash & _capacityLess1] = new StringDictionaryEntry <T>(hashA, hashB, keyValue); inserted = true; _spaceMap[(int)(hash & (_capacityLess1))] = true; break; } } if (!inserted) { while (!inserted) { Resize(); for (int i = 0; i < _numHashes; i++) { hash = hashA + _primes[i] * hashB; if (!_spaceMap[(int)(hash & _capacityLess1)]) { _entries[hash & _capacityLess1] = new StringDictionaryEntry <T>(hashA, hashB, keyValue); inserted = true; _spaceMap[(int)(hash & _capacityLess1)] = true; break; } } } } Count++; } }
///// <summary> ///// Determines whether a given key exists in the StringDictionary. ///// Complexity O(1) ///// </summary> ///// <param name="key"></param> ///// <returns></returns> //public bool Remove(string key) //{ // //GetHashCodes(key, out hashA, out hashB); // uint hashA = 0, hashB = 0; // for (int i = 0; i < key.Length; i++) // { // hashA = ((hashA << 5) + hashA ^ (uint)key[i]); // hashB = ((hashB << 6) + (hashB << 16) - hashB + (uint)key[i]); // } // int index; // uint hash; // lock (_syncRoot) // { // for (int i = 0; i < _numHashes; i++) // { // hash = hashA + _primes[i] * hashB; // index = (int)(hash & _capacityLess1); // if (!_spaceMap[index]) // { // break; // } // else if (_entries[index].HashA == hashA && _entries[index].HashB == hashB) // { // _entries[index] = null; // _spaceMap[index] = false; // return true; // } // } // } // return false; //} /// <summary> /// The number of hashes to generate for insertions / lookups in the StringDictionary. /// The default value is 31. Possible values range from 5 to 277 inclusive. A lower value leads to greater performance at the cost of a low load factor. /// A higher value leads to lesser performance but higher load factor. /// </summary> //public int NumHashes //{ // get { return _numHashes; } // set { _numHashes = ((value < 16) && (value > 278) ? value : 31); } //} // Indexer //public T this[string key] //{ // get // { // //int index; // //if ((index = ContainsKeyInternal(key)) >= 0) // // return _entries[index].Value; // //else // // return default(T); // return this.GetContainsKey(key); // } // //set // //{ // // int index; // // if ((index = ContainsKeyInternal(key)) >= 0) // // _entries[index].Value = value; // // else // // throw new KeyNotFoundException("Key not found. Key: " + key); // //} //} #endregion #region Utility Functions /// <summary> ///// The internal method used by ContainsKey(string) method. ///// </summary> ///// <param name="key"></param> ///// <returns></returns> //private int ContainsKeyInternal(string key) //{ // uint hashA, hashB; // uint hash; // GetHashCodes(key, out hashA, out hashB); // for (int i = 0; i < _numHashes; i++) // { // hash = hashA + _primes[i] * hashB; // if (!_spaceMap[(int)(hash & _capacityLess1)]) // break; // else if (_entries[hash & _capacityLess1].HashA == hashA && _entries[hash & _capacityLess1].HashB == hashB) // return (int)(hash & _capacityLess1); // } // return -1; //} /// <summary> /// The internal method called to resize the _entries array. /// Complexity O(n) /// </summary> private void Resize() { start: _capacity = _capacity << 1; _capacityLess1 = _capacity - 1; StringDictionaryEntry <T>[] newEntries = new StringDictionaryEntry <T> [_capacity]; BitArray newSpaceMap = new BitArray(_capacity); uint hash; for (int i = 0; i < _entries.Length; i++) { if (_spaceMap[i]) { //for (int j = 0; j < _numHashes; j++) //{ // hash = _entries[i].HashA + _primes[j] * _entries[i].HashB; // if (! newSpaceMap[(int)(hash & _capacityLess1)]) // { // newEntries[hash & _capacityLess1] = _entries[i]; // newSpaceMap[(int)(hash & _capacityLess1)] = true; // break; // } //} bool rehashed = false; for (int j = 0; j < _numHashes; j++) { hash = _entries[i].HashA + _primes[j] * _entries[i].HashB; if (!newSpaceMap[(int)(hash & _capacityLess1)]) { newEntries[hash & _capacityLess1] = _entries[i]; newSpaceMap[(int)(hash & _capacityLess1)] = true; rehashed = true; break; } } if (!rehashed) { //Debug.Assert(false, "rehash goto accured."); goto start; } } } _entries = newEntries; _spaceMap = newSpaceMap; }