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)); } }