internal void Resize(int numArraySlots, int numNodes) { #if DEBUG Debug.Assert(!isResizing); isResizing = true; #endif Debug.Assert(numArraySlots >= 0 && numNodes >= 0); var oldArray = array; int oldArraySlots = oldArray != null ? oldArray.Length : 0; array = numArraySlots != 0 ? new CompactValue[numArraySlots] : null; var oldNodes = nodes; if (numNodes > 0) { int logNumNodes = Helpers.CeilLog2(numNodes); if (logNumNodes > MaxBits) { throw new InvalidOperationException("Table overflow"); } numNodes = 1 << logNumNodes; nodes = new Node[numNodes]; for (int i = 0; i < nodes.Length; i++) { nodes[i].Next = -1; } } else { nodes = EmptyNodes; } lastFreeNode = numNodes; //copy from the old array to the new int copyArraySlots = oldArraySlots < numArraySlots ? oldArraySlots : numArraySlots; if (copyArraySlots != 0) { Array.Copy(oldArray, array, copyArraySlots); } //move the remaining elements to the new nodes array if (oldArray != null) { //we know that none of these values will land in the array, //so we temporarily null it out in order to prevent InsertNewKey //from doing an unnecessary "does it land in the array part" check var newArr = array; array = null; for (int i = copyArraySlots; i < oldArray.Length; i++) { var val = oldArray[i]; if (val.Val == null) { continue; } var key = new CompactValue(i); var loc = InsertNewKey(key, true); Debug.Assert(loc < 0); nodes[-loc - 1].Value = val; } array = newArr; oldArray = null; } //on to the nodes! for (int i = oldNodes.Length; i-- != 0;) { var node = oldNodes[i]; if (node.Value.Val == null) { continue; } int loc = InsertNewKey(node.Key, true); if (loc > 0) { array[loc - 1] = node.Value; } else { nodes[-loc - 1].Value = node.Value; } } #if DEBUG isResizing = false; #endif }
private void Grow(CompactValue newKey) { var arrayHist = new int[MaxBits + 1]; //count the used slots in the array part int numArrayKeys = 0; if (array != null) { for (int lg = 0, ttlg = 1, i = 1; lg <= MaxBits; lg++, ttlg *= 2) { int lc = 0; int lim = ttlg; if (lim > array.Length) { lim = array.Length; if (i > lim) { break; } } for ( ; i <= lim; i++) { if (array[i - 1].Val != null) { lc++; } } arrayHist[lg] += lc; numArrayKeys += lc; } } //and sum up the rest int asIdx; int numNodeKeys = 0, numNodeIndexKeys = 0; for (int i = 0; i < nodes.Length; i++) { if (nodes[i].Value.Val == null) { continue; } numNodeKeys++; asIdx = ValueToInt(nodes[i].Key); if (asIdx > 0 && asIdx <= MaxSize) { arrayHist[Helpers.CeilLog2(asIdx)]++; numNodeIndexKeys++; } } //and figure out the sizes int totalKeys = numArrayKeys + numNodeKeys; int totalIndexKeys = numArrayKeys + numNodeIndexKeys; //including the new key totalKeys++; asIdx = ValueToInt(newKey); if (asIdx > 0 && asIdx <= MaxSize) { arrayHist[Helpers.CeilLog2(asIdx)]++; totalIndexKeys++; } //moving on... int newArrayLen = 0, newArrayKeys = 0; for (int i = 0, a = 0, twoToI = 1; twoToI / 2 < totalIndexKeys; i++, twoToI *= 2) { int hist = arrayHist[i]; if (hist != 0) { a += hist; if (a > twoToI / 2) { newArrayLen = twoToI; newArrayKeys = a; } } if (a == totalIndexKeys) { //we've counted everything break; } } Debug.Assert(newArrayLen / 2 <= newArrayKeys && newArrayKeys <= newArrayLen); //aaaaand, resize! Resize(newArrayLen, totalKeys - newArrayKeys); }