Example #1
0
        private static SequencePosition SeekMultiSegment(IMemoryList <byte> start, int startIndex, IMemoryList <byte> end, int endPosition, long count, bool checkEndReachable)
        {
            SequencePosition   result      = default;
            bool               foundResult = false;
            IMemoryList <byte> current     = start;
            int currentIndex = startIndex;

            while (current != null)
            {
                // We need to loop up until the end to make sure start and end are connected
                // if end is not trusted
                if (!foundResult)
                {
                    var isEnd         = current == end;
                    int currentEnd    = isEnd ? endPosition : current.Memory.Length;
                    int currentLength = currentEnd - currentIndex;

                    // We would prefer to put position in the beginning of next segment
                    // then past the end of previous one, but only if we are not leaving current buffer
                    if (currentLength > count ||
                        (currentLength == count && isEnd))
                    {
                        result      = new SequencePosition(current, currentIndex + (int)count);
                        foundResult = true;
                        if (!checkEndReachable)
                        {
                            break;
                        }
                    }

                    count -= currentLength;
                }

                if (current.Next == null && current != end)
                {
                    ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
                }

                current      = current.Next;
                currentIndex = 0;
            }

            if (!foundResult)
            {
                ThrowHelper.ThrowArgumentOutOfRangeException_CountOutOfRange();
            }

            return(result);
        }
Example #2
0
        static internal void GetFirstSpan <T>(this ReadOnlySequence <T> sequence, out ReadOnlySpan <T> first, out SequencePosition next)
        {
            first = default;
            next  = default;
            SequencePosition start = sequence.Start;
            int    startIndex      = start.GetInteger();
            object startObject     = start.GetObject();

            if (startObject != null)
            {
                SequencePosition end     = sequence.End;
                int  endIndex            = end.GetInteger();
                bool hasMultipleSegments = startObject != end.GetObject();

                if (startIndex >= 0)
                {
                    if (endIndex >= 0)
                    {
                        // Positive start and end index == ReadOnlySequenceSegment<T>
                        ReadOnlySequenceSegment <T> segment = (ReadOnlySequenceSegment <T>)startObject;
                        next  = new SequencePosition(segment.Next, 0);
                        first = segment.Memory.Span;
                        if (hasMultipleSegments)
                        {
                            first = first.Slice(startIndex);
                        }
                        else
                        {
                            first = first.Slice(startIndex, endIndex - startIndex);
                        }
                    }
                    else
                    {
                        // Positive start and negative end index == T[]
                        if (hasMultipleSegments)
                        {
                            ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
                        }

                        first = new ReadOnlySpan <T>((T[])startObject, startIndex, (endIndex & ReadOnlySequence.IndexBitMask) - startIndex);
                    }
                }
                else
                {
                    first = GetFirstSpanSlow <T>(startObject, startIndex, endIndex, hasMultipleSegments);
                }
            }
        }
Example #3
0
        internal SequencePosition Seek(SequencePosition start, SequencePosition end, int count, bool checkEndReachable = true)
        {
            int          startIndex = start.Index;
            int          endIndex   = end.Index;
            SequenceType type       = GetSequenceType();

            startIndex = GetIndex(startIndex);
            endIndex   = GetIndex(endIndex);

            switch (type)
            {
            case SequenceType.MemoryList:
                if (start.Segment == end.Segment && endIndex - startIndex >= count)
                {
                    return(new SequencePosition(start.Segment, startIndex + count));
                }
                return(SeekMultiSegment((IMemoryList <byte>)start.Segment, startIndex, (IMemoryList <byte>)end.Segment, endIndex, count, checkEndReachable));

            case SequenceType.OwnedMemory:
            case SequenceType.Array:
                if (start.Segment != end.Segment)
                {
                    ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
                }

                if (endIndex - startIndex >= count)
                {
                    return(new SequencePosition(start.Segment, startIndex + count));
                }

                ThrowHelper.ThrowArgumentOutOfRangeException_CountOutOfRange();
                return(default);

            default:
                ThrowHelper.ThrowInvalidOperationException_UnexpectedSegmentType();
                return(default);
            }
        }
Example #4
0
        private static ReadOnlySpan <T> GetFirstSpanSlow <T>(object startObject, int startIndex, int endIndex, bool isMultiSegment)
        {
            Debug.Assert(startIndex < 0 || endIndex < 0);
            if (isMultiSegment)
            {
                ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
            }

            // The type == char check here is redundant. However, we still have it to allow
            // the JIT to see when that the code is unreachable and eliminate it.
            // A == 1 && B == 1 means SequenceType.String
            if (typeof(T) == typeof(char) && endIndex < 0)
            {
                var memory = (ReadOnlyMemory <T>)(object)((string)startObject).AsMemory();

                // No need to remove the FlagBitMask since (endIndex - startIndex) == (endIndex & ReadOnlySequence.IndexBitMask) - (startIndex & ReadOnlySequence.IndexBitMask)
                return(memory.Span.Slice(startIndex & IndexBitMask, endIndex - startIndex));
            }
            else             // endIndex >= 0, A == 1 && B == 0 means SequenceType.MemoryManager
            {
                startIndex &= IndexBitMask;
                return(((MemoryManager <T>)startObject).Memory.Span.Slice(startIndex, endIndex - startIndex));
            }
        }
Example #5
0
        internal bool TryGetBuffer(SequencePosition start, SequencePosition end, out ReadOnlyMemory <T> data, out SequencePosition next)
        {
            if (start.Segment == null)
            {
                data = default;
                next = default;
                return(false);
            }

            int          startIndex = start.Index;
            int          endIndex   = end.Index;
            SequenceType type       = GetSequenceType();

            startIndex = GetIndex(startIndex);
            endIndex   = GetIndex(endIndex);

            switch (type)
            {
            case SequenceType.MemoryList:
                var        segment             = (IMemoryList <T>)start.Segment;
                Memory <T> bufferSegmentMemory = segment.Memory;
                int        currentEndIndex     = bufferSegmentMemory.Length;

                if (segment == end.Segment)
                {
                    currentEndIndex = endIndex;
                    next            = default;
                }
                else
                {
                    IMemoryList <T> nextSegment = segment.Next;
                    if (nextSegment == null)
                    {
                        if (end.Segment != null)
                        {
                            ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
                        }

                        next = default;
                    }
                    else
                    {
                        next = new SequencePosition(nextSegment, 0);
                    }
                }

                data = bufferSegmentMemory.Slice(startIndex, currentEndIndex - startIndex);
                return(true);

            case SequenceType.OwnedMemory:
                var ownedMemory = (OwnedMemory <T>)start.Segment;
                if (ownedMemory != end.Segment)
                {
                    ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
                }

                data = ownedMemory.Memory.Slice(startIndex, endIndex - startIndex);
                next = default;
                return(true);

            case SequenceType.Array:
                var array = (T[])start.Segment;

                if (array != end.Segment)
                {
                    ThrowHelper.ThrowInvalidOperationException_EndPositionNotReached();
                }

                data = new Memory <T>(array, startIndex, endIndex - startIndex);
                next = default;
                return(true);

            default:
                ThrowHelper.ThrowInvalidOperationException_UnexpectedSegmentType();
                next = default;
                data = default;
                return(false);
            }
        }