public static int Seek(ReadCursor begin, ReadCursor end, out ReadCursor result, byte byte0)
        {
            var enumerator = new SegmentEnumerator(begin, end);

            while (enumerator.MoveNext())
            {
                var segmentPart = enumerator.Current;
                var segment     = segmentPart.Segment;
                var span        = segment.Buffer.Span.Slice(segmentPart.Start, segmentPart.Length);

                int index = span.IndexOf(byte0);
                if (index != -1)
                {
                    result = new ReadCursor(segment, segmentPart.Start + index);
                    return(span[index]);
                }
            }

            result = end;
            return(-1);
        }
Example #2
0
        private void GetResult(ref ReadResult result)
        {
            if (_writerCompletion.IsCompletedOrThrow())
            {
                result.ResultFlags |= ResultFlags.Completed;
            }

            var isCancelled = _readerAwaitable.ObserveCancelation();

            if (isCancelled)
            {
                result.ResultFlags |= ResultFlags.Cancelled;
            }

            // No need to read end if there is no head
            var head = _readHead;

            if (head != null)
            {
                // Reading commit head shared with writer
                result.ResultBuffer.BufferEnd.Segment = _commitHead;
                result.ResultBuffer.BufferEnd.Index   = _commitHeadIndex;
                result.ResultBuffer.BufferLength      = ReadCursor.GetLength(head, head.Start, _commitHead, _commitHeadIndex);

                result.ResultBuffer.BufferStart.Segment = head;
                result.ResultBuffer.BufferStart.Index   = head.Start;
            }

            if (isCancelled)
            {
                _readingState.BeginTentative(ExceptionResource.AlreadyReading);
            }
            else
            {
                _readingState.Begin(ExceptionResource.AlreadyReading);
            }
        }
Example #3
0
        // 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)
            {
                var examinedEverything = examined.Segment == _commitHead && examined.Index == _commitHeadIndex;

                if (!consumed.IsDefault)
                {
                    if (_readHead == null)
                    {
                        PipelinesThrowHelper.ThrowInvalidOperationException(ExceptionResource.AdvanceToInvalidCursor);
                        return;
                    }

                    returnStart = _readHead;
                    returnEnd   = consumed.Segment;

                    // Check if we crossed _maximumSizeLow and complete backpressure
                    var consumedBytes = ReadCursor.GetLength(returnStart, returnStart.Start, consumed.Segment, 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.End &&
                        !(_commitHead == returnEnd && _writingState.IsActive))
                    {
                        var nextBlock = returnEnd.Next;
                        if (_commitHead == returnEnd)
                        {
                            _commitHead      = nextBlock;
                            _commitHeadIndex = nextBlock?.Start ?? 0;
                        }

                        _readHead = nextBlock;
                        returnEnd = nextBlock;
                    }
                    else
                    {
                        _readHead       = consumed.Segment;
                        _readHead.Start = 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.Dispose();
                returnStart = returnStart.Next;
            }

            TrySchedule(_writerScheduler, continuation);
        }
 public static void Advance(this IPipeReader input, ReadCursor cursor)
 {
     input.Advance(cursor, cursor);
 }
Example #5
0
 internal ReadableBuffer(ReadCursor start, ReadCursor end)
 {
     BufferStart  = start;
     BufferEnd    = end;
     BufferLength = start.GetLength(end);
 }
Example #6
0
 internal void ClearCursors()
 {
     BufferStart = default(ReadCursor);
     BufferEnd   = default(ReadCursor);
 }
Example #7
0
        /// <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 starting (inclusive) <see cref="ReadCursor"/> at which to begin this slice.</param>
        public ReadableBuffer Slice(ReadCursor start)
        {
            BufferEnd.BoundsCheck(start);

            return(new ReadableBuffer(start, BufferEnd));
        }
 /// <summary>
 ///
 /// </summary>
 public BufferEnumerator(ReadCursor start, ReadCursor end)
 {
     _segmentEnumerator = new SegmentEnumerator(start, end);
     _current           = default(Buffer <byte>);
 }