/// <summary> /// Forms a slice out of the given <see cref="ReadableBuffer"/>, beginning at 'start', and is at most length bytes /// </summary> /// <param name="start">The index at which to begin this slice.</param> /// <param name="length">The length of the slice</param> public ReadableBuffer Slice(long start, long length) { var begin = ReadCursorOperations.Seek(BufferStart, BufferEnd, start, false); var end = ReadCursorOperations.Seek(begin, BufferEnd, length, false); return(new ReadableBuffer(begin, end)); }
/// <summary> /// Forms a slice out of the given <see cref="ReadableBuffer"/>, beginning at 'start', ending at 'end' (inclusive). /// </summary> /// <param name="start">The starting (inclusive) <see cref="ReadCursor"/> at which to begin this slice.</param> /// <param name="end">The ending (inclusive) <see cref="ReadCursor"/> of the slice</param> public ReadableBuffer Slice(ReadCursor start, ReadCursor end) { ReadCursorOperations.BoundsCheck(BufferEnd, end); ReadCursorOperations.BoundsCheck(end, start); return(new ReadableBuffer(start, end)); }
/// <summary> /// Forms a slice out of the given <see cref="ReadableBuffer"/>, beginning at 'start', ending at 'end' (inclusive). /// </summary> /// <param name="start">The index at which to begin this slice.</param> /// <param name="end">The end (inclusive) of the slice</param> public ReadableBuffer Slice(long start, ReadCursor end) { ReadCursorOperations.BoundsCheck(BufferEnd, end); var begin = ReadCursorOperations.Seek(BufferStart, end, start); return(new ReadableBuffer(begin, end)); }
public ReadCursor Move(ReadCursor cursor, long count) { if (count < 0) { throw new ArgumentOutOfRangeException(nameof(count)); } return(ReadCursorOperations.Seek(cursor, BufferEnd, count, false)); }
/// <summary> /// Forms a slice out of the given <see cref="ReadableBuffer"/>, beginning at 'start', and is at most length bytes /// </summary> /// <param name="start">The starting (inclusive) <see cref="ReadCursor"/> at which to begin this slice.</param> /// <param name="length">The length of the slice</param> public ReadableBuffer Slice(ReadCursor start, long length) { ReadCursorOperations.BoundsCheck(BufferEnd, start); var end = ReadCursorOperations.Seek(start, BufferEnd, length, false); return(new ReadableBuffer(start, end)); }
/// <summary> /// Forms a slice out of the given <see cref="ReadableBuffer"/>, beginning at 'start', ending at the existing <see cref="ReadableBuffer"/>'s end. /// </summary> /// <param name="start">The start index at which to begin this slice.</param> public ReadableBuffer Slice(long start) { if (start == 0) { return(this); } var begin = ReadCursorOperations.Seek(BufferStart, BufferEnd, start, false); return(new ReadableBuffer(begin, BufferEnd)); }
public bool TryGet(ref Position position, out ReadOnlyMemory <byte> item, bool advance = true) { if (position == default) { item = default; return(false); } var(segment, index) = position.Get <object>(); var result = ReadCursorOperations.TryGetBuffer(new ReadCursor(segment, index), _buffer.End, out item, out var next); if (advance) { position = Position.Create(next.Segment, next.Index); } return(result); }
// Reading void IPipeReader.Advance(ReadCursor consumed, ReadCursor examined) { BufferSegment returnStart = null; BufferSegment returnEnd = null; // Reading commit head shared with writer Action continuation = null; lock (_sync) { bool examinedEverything = false; if (examined.Segment == _commitHead) { examinedEverything = _commitHead != null ? examined.Index == _commitHeadIndex - _commitHead.Start : examined.Index == 0; } if (!consumed.IsDefault) { if (_readHead == null) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.AdvanceToInvalidCursor); return; } var consumedSegment = consumed.Get <BufferSegment>(); returnStart = _readHead; returnEnd = consumedSegment; // Check if we crossed _maximumSizeLow and complete backpressure var consumedBytes = ReadCursorOperations.GetLength(returnStart, _readHeadIndex, consumedSegment, consumed.Index); var oldLength = _length; _length -= consumedBytes; if (oldLength >= _maximumSizeLow && _length < _maximumSizeLow) { continuation = _writerAwaitable.Complete(); } // Check if we consumed entire last segment // if we are going to return commit head // we need to check that there is no writing operation that // might be using tailspace if (consumed.Index == returnEnd.Length && !(_commitHead == returnEnd && _writingState.IsActive)) { var nextBlock = returnEnd.NextSegment; if (_commitHead == returnEnd) { _commitHead = nextBlock; _commitHeadIndex = 0; } _readHead = nextBlock; _readHeadIndex = 0; returnEnd = nextBlock; } else { _readHead = consumedSegment; _readHeadIndex = consumed.Index; } } // We reset the awaitable to not completed if we've examined everything the producer produced so far // but only if writer is not completed yet if (examinedEverything && !_writerCompletion.IsCompleted) { // Prevent deadlock where reader awaits new data and writer await backpressure if (!_writerAwaitable.IsCompleted) { PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.BackpressureDeadlock); } _readerAwaitable.Reset(); } _readingState.End(ExceptionResource.NoReadToComplete); while (returnStart != null && returnStart != returnEnd) { returnStart.ResetMemory(); ReturnSegmentUnsynchronized(returnStart); returnStart = returnStart.NextSegment; } } TrySchedule(_writerScheduler, continuation); }