/// <summary> /// Makes room for a number of elements starting at the specified position. Elements already the specified position and beyond are moved toward the end of the <see cref="Partition{T}"/>. /// </summary> /// <param name="segmentIndex">The segment index of the position at which uninitialized elements should be inserted.</param> /// <param name="elementIndex">The element index of the position at which uninitialized elements should be inserted.</param> /// <param name="cacheIndex">The cache index of the position at which uninitialized elements should be inserted.</param> /// <param name="count">The number of elements to insert.</param> public void MakeRoom(int segmentIndex, int elementIndex, int cacheIndex, long count) { Debug.Assert(IsValidPosition(segmentIndex, elementIndex, true)); Debug.Assert(cacheIndex >= 0); Debug.Assert(count >= 0); long RemainingCount = count; int effectiveExtended; // First we try to make room in just one segment. int Extendable = SegmentTable[segmentIndex].Extendable; if (Extendable >= RemainingCount) { SegmentTable[segmentIndex].MakeRoom(elementIndex, (int)RemainingCount, out effectiveExtended); Capacity += effectiveExtended; } else { // Otherwise, we're going to need to move elements upward. int SegmentEndCount = SegmentTable[segmentIndex].Count - elementIndex; int NextExtendable = (segmentIndex + 1 < SegmentTable.Count) ? SegmentTable[segmentIndex + 1].Extendable : -1; Debug.Assert(SegmentEndCount >= 0); Debug.Assert(elementIndex + SegmentEndCount + RemainingCount > MaxSegmentCapacity); // If there is room for elements in the next segment, use it. if (SegmentEndCount <= NextExtendable) { Debug.Assert(NextExtendable >= 0); Debug.Assert(segmentIndex + 1 < SegmentTable.Count); Debug.Assert(SegmentTable[segmentIndex + 1].Count + SegmentEndCount <= MaxSegmentCapacity); SegmentTable[segmentIndex + 1].MakeRoom(0, SegmentEndCount, out effectiveExtended); Capacity += effectiveExtended; } // Otherwise, perform a split. else if (SegmentEndCount > 0) { ISegment <T> NewSegment = CreateSegment(SegmentEndCount); NewSegment.MakeRoom(0, SegmentEndCount, out effectiveExtended); Capacity += NewSegment.Capacity; SegmentTable.Insert(segmentIndex + 1, NewSegment); } // Move the end of the current segment to the new one. if (SegmentEndCount > 0) { SegmentTable[segmentIndex].MoveTo(SegmentTable[segmentIndex + 1], 0, elementIndex, SegmentEndCount); } // Check that we didn't do all this for nothing. Debug.Assert(elementIndex == SegmentTable[segmentIndex].Count); // Resume making room. Extendable = SegmentTable[segmentIndex].Extendable; if (Extendable > RemainingCount) { Extendable = (int)RemainingCount; } SegmentTable[segmentIndex].MakeRoom(elementIndex, Extendable, out effectiveExtended); Capacity += effectiveExtended; RemainingCount -= Extendable; Debug.Assert(RemainingCount >= 0); segmentIndex++; if (segmentIndex < SegmentTable.Count) { Extendable = SegmentTable[segmentIndex].Extendable; if (Extendable > RemainingCount) { Extendable = (int)RemainingCount; } SegmentTable[segmentIndex].MakeRoom(0, Extendable, out effectiveExtended); Capacity += effectiveExtended; RemainingCount -= Extendable; Debug.Assert(RemainingCount >= 0); } while (RemainingCount >= MaxSegmentCapacity) { ISegment <T> NewSegment = CreateMaxCapacitySegment(); NewSegment.MakeRoom(0, MaxSegmentCapacity, out effectiveExtended); Capacity += NewSegment.Capacity; SegmentTable.Insert(segmentIndex, NewSegment); RemainingCount -= MaxSegmentCapacity; segmentIndex++; } if (RemainingCount > 0) { ISegment <T> NewSegment = CreateSegment((int)RemainingCount); NewSegment.MakeRoom(0, (int)RemainingCount, out effectiveExtended); Capacity += NewSegment.Capacity; SegmentTable.Insert(segmentIndex, NewSegment); } } Count += count; ResizeCache(); RebuildCacheFrom(cacheIndex); #if DEBUG AssertInvariant(); #endif }