/// <summary> /// Gets a list containing all the keys in the collection. /// </summary> /// <returns>Returns all keys stored in <see cref="_table"/></returns> public List <TKey> GetKeys() { var keys = new List <TKey>(); foreach (var node in _table) { MapperNode <TKey, TValue> current = node; while (current != null) { keys.Add(current._key); current = current._next; } } return(keys); }
/// <summary> /// Double number of indices for each key properties. /// Increase <see cref="_table"/> capacity 2^KeySize times /// </summary> private void ExpandTable() { var newSize = 0; var newNonEmptyNodes = 0; var newRangePerKey = _rangePerKey * 2; var newTable = new MapperNode <TKey, TValue> [newRangePerKey.Pow(KeySize)]; lock (_table) { for (int i = 0; i < _table.Length; i++) { MapperNode <TKey, TValue> current = _table[i]; while (current != null) { var index = HashesToTableIndex(current._hashes, newRangePerKey); if (newTable[index] == null) { newTable[index] = new MapperNode <TKey, TValue>(current._key, current._value, current._hashes, null); newNonEmptyNodes++; newSize++; } else { newTable[index].Add(current._key, current._value, current._hashes, out var added); newSize += added; } current = current._next; } } _rangePerKey = newRangePerKey; _table = newTable; NonEmptyNodes = newNonEmptyNodes; Size = newSize; } }
/// <summary> /// Indexer, which allows to get and also set values of a collection by a key. /// </summary> /// <param name="key">Received key value</param> /// <exception cref="ArgumentNullException"></exception> public TValue this[TKey key] { set { if (key == null) { throw new ArgumentNullException(nameof(key)); } if (value == null) { throw new ArgumentNullException(nameof(value)); } lock (_keys) _keys.Add(key); // should contain unique values but cause performance if (NonEmptyNodes == Capacity) { ExpandTable(); } var hashes = HashesOfKey(key); var index = HashesToTableIndex(hashes, _rangePerKey); if (_table[index] == null) { _table[index] = new MapperNode <TKey, TValue>(key, value, hashes, null); NonEmptyNodes++; Size++; } else { lock (_table[index]) { _table[index].Add(key, value, hashes, out var added); Size += added; } } } get { if (key == null) { throw new ArgumentNullException(nameof(key)); } var index = KeyToTableIndex(key, _rangePerKey); var node = _table[index]; while (node != null) { MapperNode <TKey, TValue> next; lock (node) { if (IsKeysEqual(node._key, key)) { return(node._value); } next = node._next; } node = next; } return(default(TValue)); } }