/// <summary> /// Removes all the elements that match the conditions defined by the specified predicate. /// </summary> /// <param name="match">The <see cref="System.Predicate{T}"/> delegate that defines the conditions of the elements to remove.</param> /// <returns> /// The number of elements removed from the <see cref="Partition{T}"/>. /// </returns> public long RemoveAll(Predicate <T> match) { long RemovedCount = 0; int SegmentCount = SegmentTable.Count; int SegmentIndex = 0; while (SegmentIndex < SegmentCount) { ISegment <T> Segment = SegmentTable[SegmentIndex]; RemovedCount += Segment.RemoveAll(match); if (Segment.Count == 0) { SegmentTable.RemoveAt(SegmentIndex); SegmentTable.Add(Segment); SegmentCount--; } else { SegmentIndex++; } } Count -= RemovedCount; RebuildCache(); #if DEBUG AssertInvariant(); #endif return(RemovedCount); }
/// <summary> /// Removes the first occurrence of a specific object from the <see cref="Partition{T}"/>. /// </summary> /// <param name="item">The object to remove from the <see cref="Partition{T}"/>. The value can be null for reference types.</param> /// <returns> /// true if <paramref name="item"/> is successfully removed; otherwise, false. This method also returns false if <paramref name="item"/> was not found in the <see cref="Partition{T}"/>. /// </returns> public bool Remove(T item) { bool Result = false; foreach (ISegment <T> Segment in SegmentTable) { if (Segment.Remove(item)) { Result = true; Count--; if (Segment.Count == 0) { SegmentTable.Remove(Segment); SegmentTable.Add(Segment); } break; } } RebuildCache(); #if DEBUG AssertInvariant(); #endif return(Result); }
/// <summary> /// Removes segments starting from the specified index in the <see cref="Partition{T}"/>. /// </summary> /// <param name="index">The zero-based index of the first segment to remove.</param> /// <param name="count">The number of segments to remove.</param> protected virtual void RemoveSegmentRange(int index, int count) { Debug.Assert(index >= 0); Debug.Assert(count >= 0); Debug.Assert(index + count <= SegmentTable.Count); SegmentTable.RemoveRange(index, count); }
/// <summary> /// Removes a range of elements from the <see cref="Partition{T}"/>. /// </summary> /// <param name="segmentIndex">The segment index of the position of the first element to remove.</param> /// <param name="elementIndex">The element index of the position of the first element to remove.</param> /// <param name="cacheIndex">The cache index of the position of the first element to remove.</param> /// <param name="count">The number of elements to remove.</param> public void RemoveRange(int segmentIndex, int elementIndex, int cacheIndex, long count) { Debug.Assert(IsValidPosition(segmentIndex, elementIndex, true)); Debug.Assert(cacheIndex >= 0); long RemainingCount = count; while (RemainingCount > 0) { Debug.Assert(segmentIndex >= 0 && segmentIndex < SegmentTable.Count); Debug.Assert(elementIndex >= 0 && elementIndex < SegmentTable[segmentIndex].Count); int Removable = SegmentTable[segmentIndex].Count - elementIndex; if (Removable > RemainingCount) { Removable = (int)RemainingCount; } SegmentTable[segmentIndex].RemoveRange(elementIndex, Removable); if (SegmentTable[segmentIndex].Count > 0) { segmentIndex++; } else { ISegment <T> Segment = SegmentTable[segmentIndex]; SegmentTable.RemoveAt(segmentIndex); SegmentTable.Add(Segment); } RemainingCount -= Removable; elementIndex = 0; } Debug.Assert(RemainingCount == 0); Count -= count; RebuildCacheFrom(cacheIndex); #if DEBUG AssertInvariant(); #endif }
/// <summary> /// Increases the <see cref="Partition{T}"/>.Capacity by the given amount. /// </summary> /// <param name="extended">The number of elements added to the <see cref="Partition{T}"/>.Capacity.</param> public void ExtendCapacity(long extended) { Debug.Assert(extended >= 0); long RemainingCapacity = extended; // We first extend the capacity of the last segment in the partition. if (SegmentTable[SegmentTable.Count - 1].Capacity < MaxSegmentCapacity) { int Extendable = SegmentTable[SegmentTable.Count - 1].Extendable; if (Extendable > RemainingCapacity) { Extendable = (int)RemainingCapacity; } int effectiveExtended; SegmentTable[SegmentTable.Count - 1].Extend(Extendable, out effectiveExtended); RemainingCapacity -= effectiveExtended; } Debug.Assert(RemainingCapacity >= 0); // Then we add as many empty segments as necessary to increase the partition capacity. while (RemainingCapacity > MaxSegmentCapacity) { SegmentTable.Add(CreateMaxCapacitySegment()); RemainingCapacity -= MaxSegmentCapacity; } Debug.Assert(RemainingCapacity >= 0 && RemainingCapacity <= MaxSegmentCapacity); if (RemainingCapacity > 0) { SegmentTable.Add(CreateSegment((int)RemainingCapacity)); } Capacity += extended; RebuildCache(); #if DEBUG AssertInvariant(); #endif }
/// <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 }