private static void GrowTable <VALUE>(Table <VALUE> oldTable, Monitor monitor, HashFunction hashFunction, ResizeMonitor <VALUE> resizeMonitor) { Debug.Assert(monitor.TableGrowing(oldTable.Capacity(), oldTable.Size())); Table <VALUE> newTable = oldTable.Grow(); // Install the new table before populating it with the old data, in case we find it needs to grow even more // while we are populating it. If that happens, we want to end up with the table installed by the final grow. resizeMonitor.TableGrew(newTable); long nullKey = oldTable.NullKey(); // place all entries in the new table int capacity = oldTable.Capacity(); for (int i = 0; i < capacity; i++) { long key = oldTable.Key(i); if (key != nullKey) { // Always use the table from the resize monitor, because any put can cause a grow. Table <VALUE> table = resizeMonitor.LastTable; VALUE putResult = Put(table, monitor, hashFunction, key, oldTable.Value(i), resizeMonitor); if (putResult != default(VALUE)) { // If we somehow fail to populate the new table, reinstall the old one. resizeMonitor.TableGrew(oldTable); newTable.Close(); throw new System.InvalidOperationException("Couldn't add " + key + " when growing table"); } } } Debug.Assert(monitor.TableGrew(oldTable.Capacity(), newTable.Capacity(), newTable.Size())); oldTable.Close(); }
public static VALUE Put <VALUE>(Table <VALUE> table, Monitor monitor, HashFunction hashFunction, long key, VALUE value, ResizeMonitor <VALUE> resizeMonitor) { long nullKey = table.NullKey(); Debug.Assert(key != nullKey); int tableMask = table.Mask(); int index = IndexOf(hashFunction, key, tableMask); long keyAtIndex = table.Key(index); if (keyAtIndex == nullKey) { // this index is free, just place it there table.Put(index, key, value); Debug.Assert(monitor.PlacedAtFreeAndIntendedIndex(key, index)); return(default(VALUE)); } else if (keyAtIndex == key) { // this index is occupied, but actually with the same key return(table.PutValue(index, value)); } else { // look at the neighbors of this entry to see if any is the requested key long hopBits = table.HopBits(index); while (hopBits > 0) { int hopIndex = NextIndex(index, numberOfTrailingZeros(hopBits) + 1, tableMask); if (table.Key(hopIndex) == key) { return(table.PutValue(hopIndex, value)); } hopBits &= hopBits - 1; } } // this key does not exist in this set. put it there using hop-scotching if (HopScotchPut(table, monitor, hashFunction, key, value, index, tableMask, nullKey)) { // we managed to wiggle our way to a free spot and put it there return(default(VALUE)); } // we couldn't add this value, even in the H-1 neighborhood, so grow table... GrowTable(table, monitor, hashFunction, resizeMonitor); Table <VALUE> resizedTable = resizeMonitor.LastTable; // ...and try again return(Put(resizedTable, monitor, hashFunction, key, value, resizeMonitor)); }