Exemple #1
0
        /// <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
        }