void Resize() { Resize(HashHelpers.ExpandPrime(count)); }
private void Resize() { Resize(HashHelpers.ExpandPrime(count), false); }
bool AddValue(T key, ref W value) { //get the hash and bucket index int hash = key.GetHashCode() & int.MaxValue; int bucketIndex = hash % _buckets.Length; //buckets value -1 means it's empty var valueIndex = GetBucketIndex(_buckets[bucketIndex]); if (valueIndex == -1) { //create the infonode at the last position and fill it with the relevant information _valuesInfo[_freeValueCellIndex] = new Node(ref key, hash); } else { int currentValueIndex = valueIndex; do { //must check if the key already exists in the dictionary //for some reason this is way faster they use Comparer<T>.default, should investigate if (_valuesInfo[currentValueIndex].hashcode == hash && _valuesInfo[currentValueIndex].key.CompareTo(key) == 0) { return(false); } currentValueIndex = _valuesInfo[currentValueIndex].previous; }while (currentValueIndex != -1); //oops collision! _collisions++; //create a new one that points to the existing one //new one prev = the first in the bucket _valuesInfo[_freeValueCellIndex] = new Node(ref key, hash, valueIndex); //the first in the bucket next = new one _valuesInfo[valueIndex].next = (int)_freeValueCellIndex; } //item with this bucketIndex will point to the last value created _buckets[bucketIndex] = _freeValueCellIndex + 1; _values[_freeValueCellIndex] = value; if (++_freeValueCellIndex == _values.Length) { Array.Resize(ref _values, HashHelpers.ExpandPrime((int)_freeValueCellIndex)); Array.Resize(ref _valuesInfo, HashHelpers.ExpandPrime((int)_freeValueCellIndex)); } //too many collisions? if (_collisions > _buckets.Length) { //we need more space and less collisions _buckets = new int[HashHelpers.ExpandPrime(_collisions)]; _collisions = 0; //we need to scan all the values inserted so far //to recompute the collision indices for (int i = 0; i < _freeValueCellIndex; i++) { //get the original hash code and find the new bucketIndex bucketIndex = (_valuesInfo[i].hashcode) % _buckets.Length; //bucketsIndex can be -1 or a next value. If it's -1 //means no collisions. If there is collision, it will //link to the next value index and the bucket will //be updated with the current one. In this way we can //rebuild the linkedlist. valueIndex = GetBucketIndex(_buckets[bucketIndex]); if (valueIndex != -1) { _collisions++; _valuesInfo[i].previous = valueIndex; _valuesInfo[valueIndex].next = i; } else { _valuesInfo[i].next = -1; _valuesInfo[i].previous = -1; } //buckets at bucketIndex will remember the value/valueInfo //index for that bucketIndex. _buckets[bucketIndex] = i + 1; } } return(true); }
bool AddValue(TKey key, ref TValue value) { int hash = Hash(key); int bucketIndex = hash % _buckets.Length; //buckets value -1 means it's empty var valueIndex = GetValueIndexFromBuckets(_buckets, bucketIndex); if (valueIndex == -1) { //create the info node at the last position and fill it with the relevant information _valuesInfo[_freeValueCellIndex] = new Node(ref key, hash); } else //collision or already exists { { int currentValueIndex = valueIndex; do { //must check if the key already exists in the dictionary //for some reason this is faster than using Comparer<TKey>.default, should investigate if (_valuesInfo[currentValueIndex].hashcode == hash && _valuesInfo[currentValueIndex].key.CompareTo(key) == 0) {//the key already exists, simply replace the value! _values[currentValueIndex] = value; return(false); } currentValueIndex = _valuesInfo[currentValueIndex].previous; }while (currentValueIndex != -1); //-1 means no more values with key with the same hash } //oops collision! _collisions++; //create a new node which previous index points to node currently pointed in the bucket _valuesInfo[_freeValueCellIndex] = new Node(ref key, hash, valueIndex); //update the next of the existing cell to point to the new one //old one -> new one | old one <- next one _valuesInfo[valueIndex].next = _freeValueCellIndex; //Important: the new node is always the one that will be pointed by the bucket cell //so I can assume that the one pointed by the bucket is always the last value added //(next = -1) } //item with this bucketIndex will point to the last value created //ToDo: if instead I assume that the original one is the one in the bucket //I wouldn't need to update the bucket here. Small optimization but important SetValueIndexInBuckets(_buckets, bucketIndex, _freeValueCellIndex); _values[_freeValueCellIndex] = value; _freeValueCellIndex++; if (_freeValueCellIndex == _values.Length) { Array.Resize(ref _values, HashHelpers.ExpandPrime(_freeValueCellIndex)); Array.Resize(ref _valuesInfo, HashHelpers.ExpandPrime(_freeValueCellIndex)); } //too many collisions? if (_collisions > _buckets.Length) { //we need more space and less collisions //ToDo: need to change from prime to Fibonacci sequence (could be quite faster) _buckets = new int[HashHelpers.ExpandPrime(_collisions)]; _collisions = 0; //we need to get all the hash code of all the values stored so far and spread them over the new bucket //length for (int newValueIndex = 0; newValueIndex < _freeValueCellIndex; newValueIndex++) { //get the original hash code and find the new bucketIndex due to the new length bucketIndex = _valuesInfo[newValueIndex].hashcode % _buckets.Length; //bucketsIndex can be -1 or a next value. If it's -1 means no collisions. If there is collision, //we create a new node which prev points to the old one. Old one next points to the new one. //the bucket will now points to the new one //In this way we can rebuild the linkedlist. //get the current valueIndex, it's -1 if no collision happens int existingValueIndex = GetValueIndexFromBuckets(_buckets, bucketIndex); //update the bucket index to the index of the current item that share the bucketIndex //(last found is always the one in the bucket) SetValueIndexInBuckets(_buckets, bucketIndex, newValueIndex); if (existingValueIndex != -1) { //oops a value was already being pointed by this cell in the new bucket list, //it means there is a collision, problem _collisions++; //the bucket will point to this value, so //the previous index will be used as previous for the new value. _valuesInfo[newValueIndex].previous = existingValueIndex; _valuesInfo[newValueIndex].next = -1; //and update the previous next index to the new one _valuesInfo[existingValueIndex].next = newValueIndex; } else { //ok nothing was indexed, the bucket was empty. We need to update the previous //values of next and previous _valuesInfo[newValueIndex].next = -1; _valuesInfo[newValueIndex].previous = -1; } } } return(true); }
private void Resize() { Resize(HashHelpers.ExpandPrime(count), forceNewHashCodes: false); }
public void TestFasterDictionary() { FasterDictionary <int, Test> test = new FasterDictionary <int, Test>(); uint dictionarysize = 10000; int[] numbers = new int[dictionarysize]; for (int i = 1; i < dictionarysize; i++) { numbers[i] = numbers[i - 1] + i * HashHelpers.ExpandPrime((int)dictionarysize); } for (int i = 0; i < dictionarysize; i++) { test[i] = new Test(numbers[i]); } for (int i = 0; i < dictionarysize; i++) { if (test[i].i != numbers[i]) { throw new Exception(); } } for (int i = 0; i < dictionarysize; i += 2) { if (test.Remove(i) == false) { throw new Exception(); } } test.Trim(); for (int i = 0; i < dictionarysize; i++) { test[i] = new Test(numbers[i]); } for (int i = 1; i < dictionarysize - 1; i += 2) { if (test[i].i != numbers[i]) { throw new Exception(); } } for (int i = 0; i < dictionarysize; i++) { if (test[i].i != numbers[i]) { throw new Exception(); } } for (int i = (int)(dictionarysize - 1); i >= 0; i -= 3) { if (test.Remove(i) == false) { throw new Exception(); } } test.Trim(); for (int i = (int)(dictionarysize - 1); i >= 0; i -= 3) { test[i] = new Test(numbers[i]); } for (int i = 0; i < dictionarysize; i++) { if (test[i].i != numbers[i]) { throw new Exception(); } } for (int i = 0; i < dictionarysize; i++) { if (test.Remove(i) == false) { throw new Exception(); } } for (int i = 0; i < dictionarysize; i++) { if (test.Remove(i) == true) { throw new Exception(); } } test.Trim(); test.Clear(); for (int i = 0; i < dictionarysize; i++) { test[numbers[i]] = new Test(i); } for (int i = 0; i < dictionarysize; i++) { Test JapaneseCalendar = test[numbers[i]]; if (JapaneseCalendar.i != i) { throw new Exception("read back test failed"); } } }
public void TestSveltoDictionary(int dictionarysize) { SveltoDictionary <int, Test, NativeStrategy <SveltoDictionaryNode <int> >, NativeStrategy <Test>, NativeStrategy <int> > test = new SveltoDictionary <int, Test, NativeStrategy <SveltoDictionaryNode <int> >, NativeStrategy <Test>, NativeStrategy <int> >(1, Allocator.Persistent); int[] numbers = new int[dictionarysize]; for (int i = 1; i < dictionarysize; i++) { numbers[i] = numbers[i - 1] + i * HashHelpers.ExpandPrime((int)dictionarysize); } for (int i = 0; i < dictionarysize; i++) { test[i] = new Test(numbers[i]); } for (int i = 0; i < dictionarysize; i++) { if (test[i].i != numbers[i]) { throw new Exception(); } } for (int i = 0; i < dictionarysize; i += 2) { if (test.Remove(i) == false) { throw new Exception(); } } test.Clear(); for (int i = 0; i < dictionarysize; i++) { test[i] = new Test(numbers[i]); } for (int i = 1; i < dictionarysize - 1; i += 2) { if (test[i].i != numbers[i]) { throw new Exception(); } } for (int i = 0; i < dictionarysize; i++) { if (test[i].i != numbers[i]) { throw new Exception(); } } for (int i = (int)(dictionarysize - 1); i >= 0; i -= 3) { if (test.Remove(i) == false) { throw new Exception(); } } test.Clear(); for (int i = (int)(dictionarysize - 1); i >= 0; i -= 3) { test[i] = new Test(numbers[i]); } for (int i = (int)(dictionarysize - 1); i >= 0; i -= 3) { if (test[i].i != numbers[i]) { throw new Exception(); } } for (int i = (int)(dictionarysize - 1); i >= 0; i -= 3) { if (test.Remove(i) == false) { throw new Exception(); } } for (int i = (int)(dictionarysize - 1); i >= 0; i -= 3) { if (test.Remove(i) == true) { throw new Exception(); } } test.Clear(); for (int i = (int)(dictionarysize - 1); i >= 0; i -= 3) { test[i] = new Test(numbers[i]); } for (int i = (int)(dictionarysize - 1); i >= 0; i -= 3) { if (test.Remove(i) == false) { throw new Exception(); } } for (int i = (int)(dictionarysize - 1); i >= 0; i -= 3) { test[i] = new Test(numbers[i]); } for (int i = (int)(dictionarysize - 1); i >= 0; i -= 3) { if (test[i].i != numbers[i]) { throw new Exception(); } } test.Clear(); for (int i = 0; i < dictionarysize; i++) { test[numbers[i]] = new Test(i); } for (int i = 0; i < dictionarysize; i++) { Test JapaneseCalendar = test[numbers[i]]; if (JapaneseCalendar.i != i) { throw new Exception("read back test failed"); } } test.Clear(); for (int i = 0; i < dictionarysize; i++) { test[numbers[i]] = new Test(i); } for (int i = 0; i < dictionarysize; i++) { Test JapaneseCalendar = test[numbers[i]]; if (JapaneseCalendar.i != i) { throw new Exception("read back test failed"); } } test.Dispose(); }