public void Dispose() { if (StringPointer != null) { Debug.Assert(FirstFreeChunk == null); if (FirstFreeChunk != null) { throw new InvalidOperationException(); } if (Prev != null) { Prev.Next = Next; } if (Next != null) { Next.Prev = Prev; } else { Last = Prev; } StringPointer = null; StringHandle.Free(); } }
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(); }
public FreeChunk(PoolSegment segment, int index, int size) { Debug.Assert(segment.FirstFreeChunk == null && index >= 0 && size > 0 && index + size <= segment.Size); Segment = segment; Index = index; Size = size; segment.FirstFreeChunk = this; InsertIntoSizeList(); }
public PoolSegment(int size, int firstBufferSize) { Debug.Assert(firstBufferSize > 0 && firstBufferSize <= size && (size <= MaxSegmentSize || firstBufferSize == size)); // + 1, so that no chunk can span the full string, which helps avoiding accidentally passing a reference to the internal buffer string to the "outside world" String = new String('\u0000', size + 1); Size = size; StringHandle = GCHandle.Alloc(String, GCHandleType.Pinned); StringPointer = (char *)StringHandle.AddrOfPinnedObject(); if (Last != null) { Last.Next = this; Prev = Last; } Last = this; if (firstBufferSize < size) { new FreeChunk(this, firstBufferSize, size - firstBufferSize); // inserts itself into the lists } }
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)); } }
private StringBuffer(PoolSegment segment, int index, int length) { Segment = segment; Index = index; Length = length; }
public void Dispose() { if (StringPointer != null) { Debug.Assert(FirstFreeChunk == null); if (FirstFreeChunk != null) throw new InvalidOperationException(); if (Prev != null) Prev.Next = Next; if (Next != null) Next.Prev = Prev; else Last = Prev; StringPointer = null; StringHandle.Free(); } }
public PoolSegment(int size, int firstBufferSize) { Debug.Assert(firstBufferSize > 0 && firstBufferSize <= size && (size <= MaxSegmentSize || firstBufferSize == size)); // + 1, so that no chunk can span the full string, which helps avoiding accidentally passing a reference to the internal buffer string to the "outside world" String = new String('\u0000', size + 1); Size = size; StringHandle = GCHandle.Alloc(String, GCHandleType.Pinned); StringPointer = (char*)StringHandle.AddrOfPinnedObject(); if (Last != null) { Last.Next = this; Prev = Last; } Last = this; if (firstBufferSize < size) new FreeChunk(this, firstBufferSize, size - firstBufferSize); // inserts itself into the lists }