public void MoveAfterSizeHasIncreased() { Debug.Assert(Size > NextInSize.Size); var next = NextInSize; var prev = PrevInSize; if (prev != null) { prev.NextInSize = next; } else { Smallest = next; } next.PrevInSize = prev; prev = next; next = next.NextInSize; while (next != null && next.Size < Size) { prev = next; next = next.NextInSize; } PrevInSize = prev; prev.NextInSize = this; NextInSize = next; if (next != null) { next.PrevInSize = this; } else { Largest = this; } }
public FreeChunk(PoolSegment segment, FreeChunk prevInSegment, FreeChunk nextInSegment, int index, int size) { Debug.Assert(index >= 0 && size > 0 && index + size <= segment.Size); Segment = segment; Index = index; Size = size; PrevInSegment = prevInSegment; NextInSegment = nextInSegment; if (prevInSegment != null) { Debug.Assert(prevInSegment.Index + prevInSegment.Size < index); prevInSegment.NextInSegment = this; } else { Debug.Assert(segment.FirstFreeChunk == nextInSegment); segment.FirstFreeChunk = this; } if (nextInSegment != null) { Debug.Assert(index + size < nextInSegment.Index); nextInSegment.PrevInSegment = this; } InsertIntoSizeList(); }
// the following two methods are dual to each other, // i.e. one can be transformed into the other by way of simple search & replace public void MoveAfterSizeHasDecreased() { Debug.Assert(Size < PrevInSize.Size); var prev = PrevInSize; var next = NextInSize; if (next != null) { next.PrevInSize = prev; } else { Largest = prev; } prev.NextInSize = next; next = prev; prev = prev.PrevInSize; while (prev != null && prev.Size > Size) { next = prev; prev = prev.PrevInSize; } NextInSize = next; next.PrevInSize = this; PrevInSize = prev; if (prev != null) { prev.NextInSize = this; } else { Smallest = this; } }
private void InsertIntoSizeList() { var largest = FreeChunk.Largest; if (largest != null) { if (largest.Size <= Size) { largest.NextInSize = this; PrevInSize = largest; FreeChunk.Largest = this; } else { NextInSize = largest; var prev = largest.PrevInSize; largest.PrevInSize = this; if (prev != null) { PrevInSize = prev; prev.NextInSize = this; if (Size < prev.Size) MoveAfterSizeHasDecreased(); } else FreeChunk.Smallest = this; } } else { FreeChunk.Smallest = this; FreeChunk.Largest = this; } }
private void InsertIntoSizeList() { var largest = FreeChunk.Largest; if (largest != null) { if (largest.Size <= Size) { largest.NextInSize = this; PrevInSize = largest; FreeChunk.Largest = this; } else { NextInSize = largest; var prev = largest.PrevInSize; largest.PrevInSize = this; if (prev != null) { PrevInSize = prev; prev.NextInSize = this; if (Size < prev.Size) { MoveAfterSizeHasDecreased(); } } else { FreeChunk.Smallest = this; } } } else { FreeChunk.Smallest = this; FreeChunk.Largest = this; } }
public void Remove() { var prev = PrevInSegment; var next = NextInSegment; if (prev != null) { prev.NextInSegment = next; } else { Segment.FirstFreeChunk = next; } if (next != null) { next.PrevInSegment = prev; } prev = PrevInSize; next = NextInSize; if (prev != null) { prev.NextInSize = next; } else { Smallest = next; } if (next != null) { next.PrevInSize = prev; } else { Largest = prev; } }
public void Dispose() { int size = Length; Length = -1; if (size > 0) { lock (SyncRoot) { Allocated -= size; if (size <= MaxSegmentSize) { FreeChunk prev = null; FreeChunk next = Segment.FirstFreeChunk; while (next != null && Index > next.Index) { prev = next; next = next.NextInSegment; } if (prev == null || prev.Index + prev.Size != Index) { if (next != null && Index + size == next.Index) { next.Index = Index; next.Size += size; var nextNext = next.NextInSize; if (nextNext != null && next.Size > nextNext.Size) { next.MoveAfterSizeHasIncreased(); } } else { new FreeChunk(Segment, prev, next, Index, size); // inserts itself into the lists } } else { if (next != null && Index + size == next.Index) { prev.Size += size + next.Size; next.Remove(); } else { prev.Size += size; } if (prev.NextInSize != null && prev.Size > prev.NextInSize.Size) { prev.MoveAfterSizeHasIncreased(); } } Segment.AssertIntegrity(); var first = Segment.FirstFreeChunk; if (first.Size == Segment.Size && ++NumberOfUnusedSegments > MaxNumberOfUnusedSegments) { --NumberOfUnusedSegments; first.Remove(); Segment.Dispose(); } } else // size > MaxSegmentSize { Debug.Assert(size == Segment.Size); Segment.Dispose(); } } } }
public static StringBuffer Create(int minLength) { int size = unchecked (minLength + (MinChunkSize - 1)); if (size > (MinChunkSize - 1)) // minLength > 0 && minLength <= System.Int32.MaxValue - (MinChunkSize - 1) { size -= (int)((uint)size % (uint)MinChunkSize); // round down to multiple of MinChunkSize lock (SyncRoot) { Allocated += size; FreeChunk chunk = FreeChunk.Largest; if (chunk != null) // find smallest free chunk that is large enough to hold the buffer { if (size > 10 * MinChunkSize) { var prev = chunk.PrevInSize; while (prev != null && prev.Size >= size) { chunk = prev; prev = prev.PrevInSize; } } else { chunk = FreeChunk.Smallest; var next = chunk.NextInSize; while (chunk.Size < size && next != null) { chunk = next; next = next.NextInSize; } } if (size <= chunk.Size) { int index = chunk.Index; if (index == 0 && chunk.Size == chunk.Segment.Size) { --NumberOfUnusedSegments; } if (size != chunk.Size) { chunk.Index += size; chunk.Size -= size; var prev = chunk.PrevInSize; if (prev != null && chunk.Size < prev.Size) { chunk.MoveAfterSizeHasDecreased(); } } else { chunk.Remove(); } chunk.Segment.AssertIntegrity(); return(new StringBuffer(chunk.Segment, index, size)); } } return(PoolSegment.AllocateStringBufferInNewSegment(size)); } } else { if (minLength < 0) { throw new ArgumentOutOfRangeException("minLength", "minLength is negative."); } else if (minLength > 0) { throw new ArgumentOutOfRangeException("minLength", "minLength is too large. The maximum string buffer length is approximately 2^30."); } return(new StringBuffer(null, 0, 0)); } }
public void MoveAfterSizeHasIncreased() { Debug.Assert(Size > NextInSize.Size); var next = NextInSize; var prev = PrevInSize; if (prev != null) prev.NextInSize = next; else Smallest = next; next.PrevInSize = prev; prev = next; next = next.NextInSize; while (next != null && next.Size < Size) { prev = next; next = next.NextInSize; } PrevInSize = prev; prev.NextInSize = this; NextInSize = next; if (next != null) next.PrevInSize = this; else Largest = this; }
// the following two methods are dual to each other, // i.e. one can be transformed into the other by way of simple search & replace public void MoveAfterSizeHasDecreased() { Debug.Assert(Size < PrevInSize.Size); var prev = PrevInSize; var next = NextInSize; if (next != null) next.PrevInSize = prev; else Largest = prev; prev.NextInSize = next; next = prev; prev = prev.PrevInSize; while (prev != null && prev.Size > Size) { next = prev; prev = prev.PrevInSize; } NextInSize = next; next.PrevInSize = this; PrevInSize = prev; if (prev != null) prev.NextInSize = this; else Smallest = this; }
public void Remove() { var prev = PrevInSegment; var next = NextInSegment; if (prev != null) prev.NextInSegment = next; else Segment.FirstFreeChunk = next; if (next != null) next.PrevInSegment = prev; prev = PrevInSize; next = NextInSize; if (prev != null) prev.NextInSize = next; else Smallest = next; if (next != null) next.PrevInSize = prev; else Largest = prev; }