private void AllocateWriteHeadUnsynchronized(int sizeHint) { _operationState.BeginWrite(); if (_writingHead == null) { // We need to allocate memory to write since nobody has written before BufferSegment newSegment = CreateSegmentUnsynchronized(); newSegment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint))); // Set all the pointers _writingHead = _readHead = _readTail = newSegment; } else { int bytesLeftInBuffer = _writingHead.WritableBytes; if (bytesLeftInBuffer == 0 || bytesLeftInBuffer < sizeHint) { BufferSegment newSegment = CreateSegmentUnsynchronized(); newSegment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint))); _writingHead.SetNext(newSegment); _writingHead = newSegment; } } }
internal Memory <byte> GetMemory(int minimumSize) { if (_writerCompletion.IsCompleted) { ThrowHelper.ThrowInvalidOperationException_NoWritingAllowed(); } if (minimumSize < 0) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.minimumSize); } lock (_sync) { BufferSegment segment = _writingHead ?? AllocateWriteHeadUnsynchronized(minimumSize); int bytesLeftInBuffer = segment.WritableBytes; // If inadequate bytes left or if the segment is readonly if (bytesLeftInBuffer == 0 || bytesLeftInBuffer < minimumSize || segment.ReadOnly) { BufferSegment nextSegment = CreateSegmentUnsynchronized(); nextSegment.SetMemory(_pool.Rent(Math.Max(_minimumSegmentSize, minimumSize))); segment.SetNext(nextSegment); _writingHead = nextSegment; } } return(_writingHead.AvailableMemory.Slice(_writingHead.End, _writingHead.WritableBytes)); }
public static BufferSegment Clone(ReadCursor beginBuffer, ReadCursor endBuffer, out BufferSegment lastSegment) { var beginOrig = beginBuffer.Segment; var endOrig = endBuffer.Segment; if (beginOrig == endOrig) { lastSegment = new BufferSegment(); lastSegment.SetMemory(beginOrig._owned, beginBuffer.Index, endBuffer.Index); return(lastSegment); } var beginClone = new BufferSegment(); beginClone.SetMemory(beginOrig._owned, beginBuffer.Index, beginOrig.End); var endClone = beginClone; beginOrig = beginOrig.Next; while (beginOrig != endOrig) { var next = new BufferSegment(); next.SetMemory(beginOrig._owned, beginOrig.Start, beginOrig.End); endClone.SetNext(next); endClone = endClone.Next; beginOrig = beginOrig.Next; } lastSegment = new BufferSegment(); lastSegment.SetMemory(endOrig._owned, endOrig.Start, endBuffer.Index); endClone.SetNext(lastSegment); return(beginClone); }
public static BufferSegment Clone(BufferSegment start, int startIndex, BufferSegment end, int endIndex, out BufferSegment lastSegment) { var beginOrig = start; var endOrig = end; if (beginOrig == endOrig) { lastSegment = new BufferSegment(); lastSegment.SetMemory(beginOrig._ownedMemory, startIndex, endIndex); return(lastSegment); } var beginClone = new BufferSegment(); beginClone.SetMemory(beginOrig._ownedMemory, startIndex, beginOrig.End); var endClone = beginClone; beginOrig = beginOrig.Next; while (beginOrig != endOrig) { var next = new BufferSegment(); next.SetMemory(beginOrig._ownedMemory, beginOrig.Start, beginOrig.End); endClone.SetNext(next); endClone = endClone.Next; beginOrig = beginOrig.Next; } lastSegment = new BufferSegment(); lastSegment.SetMemory(endOrig._ownedMemory, endOrig.Start, endIndex); endClone.SetNext(lastSegment); return(beginClone); }
private void AllocateWriteHeadUnsynchronized(int sizeHint) { BufferSegment segment = null; if (_writingHead != null) { segment = _writingHead; int bytesLeftInBuffer = segment.WritableBytes; // If inadequate bytes left or if the segment is readonly if (bytesLeftInBuffer == 0 || bytesLeftInBuffer < sizeHint || segment.ReadOnly) { BufferSegment nextSegment = CreateSegmentUnsynchronized(); nextSegment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint))); segment.SetNext(nextSegment); _writingHead = nextSegment; } } else { if (_commitHead != null && !_commitHead.ReadOnly) { // Try to return the tail so the calling code can append to it int remaining = _commitHead.WritableBytes; if (sizeHint <= remaining && remaining > 0) { // Free tail space of the right amount, use that segment = _commitHead; // Set write head to assigned segment _writingHead = segment; return; } } // No free tail space, allocate a new segment segment = CreateSegmentUnsynchronized(); segment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint))); if (_commitHead == null) { // No previous writes have occurred _commitHead = segment; } else if (segment != _commitHead && _commitHead.Next == null) { // Append the segment to the commit head if writes have been committed // and it isn't the same segment (unused tail space) _commitHead.SetNext(segment); } // Set write head to assigned segment _writingHead = segment; } }
private void AdvanceTo(BufferSegment consumedSegment, int consumedIndex, BufferSegment examinedSegment, int examinedIndex) { if (consumedSegment == null) { return; } var returnStart = _readHead; var returnEnd = consumedSegment; var consumedBytes = new ReadOnlySequence <byte>(returnStart, _readIndex, consumedSegment, consumedIndex).Length; _bufferedBytes -= consumedBytes; Debug.Assert(_bufferedBytes >= 0); _examinedEverything = false; if (examinedSegment == _readTail) { // If we examined everything, we force ReadAsync to actually read from the underlying stream // instead of returning a ReadResult from TryRead. _examinedEverything = examinedIndex == _readTail.End; } // Three cases here: // 1. All data is consumed. If so, we reset _readHead and _readTail to _readTail's original memory owner // SetMemory on a IMemoryOwner will reset the internal Memory<byte> to be an empty segment // 2. A segment is entirely consumed but there is still more data in nextSegments // We are allowed to remove an extra segment. by setting returnEnd to be the next block. // 3. We are in the middle of a segment. // Move _readHead and _readIndex to consumedSegment and index if (_bufferedBytes == 0) { _readTail.SetMemory(_readTail.MemoryOwner); _readHead = _readTail; returnEnd = _readTail; _readIndex = 0; } else if (consumedIndex == returnEnd.Length) { var nextBlock = returnEnd.NextSegment; _readHead = nextBlock; _readIndex = 0; returnEnd = nextBlock; } else { _readHead = consumedSegment; _readIndex = consumedIndex; } // Remove all blocks that are freed (except the last one) while (returnStart != returnEnd) { returnStart.ResetMemory(); returnStart = returnStart.NextSegment; } }
private static ReadableBuffer CreateInternal(OwnedMemory <byte> data, int offset, int length) { var segment = new BufferSegment(); segment.SetMemory(data, offset, offset + length); return(new ReadableBuffer(new ReadCursor(segment, offset), new ReadCursor(segment, offset + length))); }
private BufferSegment AllocateSegment(int sizeHint) { BufferSegment newSegment = CreateSegmentUnsynchronized(); if (_pool is null) { // Use the array pool newSegment.SetMemory(ArrayPool <byte> .Shared.Rent(GetSegmentSize(sizeHint))); } else if (sizeHint <= _pool.MaxBufferSize) { // Use the specified pool if it fits newSegment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint, _pool.MaxBufferSize))); } else { // We can't use the pool so allocate an array newSegment.SetUnownedMemory(new byte[sizeHint]); } return(newSegment); }
private void AllocateReadTail() { if (_readHead == null) { Debug.Assert(_readTail == null); _readHead = CreateBufferSegment(); _readHead.SetMemory(_pool.Rent(GetSegmentSize())); _readTail = _readHead; } else if (_readTail.WritableBytes < _minimumReadThreshold) { CreateNewTailSegment(); } }
private BufferSegment AllocateWriteHeadUnsynchronized(int count) { BufferSegment segment = null; if (_commitHead != null && !_commitHead.ReadOnly) { // Try to return the tail so the calling code can append to it int remaining = _commitHead.WritableBytes; if (count <= remaining && remaining > 0) { // Free tail space of the right amount, use that segment = _commitHead; } } if (segment == null) { // No free tail space, allocate a new segment segment = CreateSegmentUnsynchronized(); segment.SetMemory(_pool.Rent(Math.Max(_minimumSegmentSize, count))); } if (_commitHead == null) { // No previous writes have occurred _commitHead = segment; } else if (segment != _commitHead && _commitHead.Next == null) { // Append the segment to the commit head if writes have been committed // and it isn't the same segment (unused tail space) _commitHead.SetNext(segment); } // Set write head to assigned segment _writingHead = segment; return(segment); }
internal Memory <byte> GetMemory(int sizeHint) { if (_writerCompletion.IsCompleted) { ThrowHelper.ThrowInvalidOperationException_NoWritingAllowed(); } if (sizeHint < 0) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.minimumSize); } lock (_sync) { BufferSegment segment = _writingHead ?? AllocateWriteHeadUnsynchronized(sizeHint); int bytesLeftInBuffer = segment.WritableBytes; // If inadequate bytes left or if the segment is readonly if (bytesLeftInBuffer == 0 || bytesLeftInBuffer < sizeHint || segment.ReadOnly) { BufferSegment nextSegment = CreateSegmentUnsynchronized(); nextSegment.SetMemory(_pool.Rent(GetSegmentSize(sizeHint))); segment.SetNext(nextSegment); _writingHead = nextSegment; } } // Slice the AvailableMemory to the WritableBytes size int end = _writingHead.End; Memory <byte> availableMemory = _writingHead.AvailableMemory; availableMemory = availableMemory.Slice(end, availableMemory.Length - end); return(availableMemory); }