예제 #1
0
        /// <summary>Try to read everything up to the given <paramref name="delimiter"/>, ignoring delimiters that are
        /// preceded by <paramref name="delimiterEscape"/>.</summary>
        /// <param name="span">The read data, if any.</param>
        /// <param name="delimiter">The delimiter to look for.</param>
        /// <param name="delimiterEscape">If found prior to <paramref name="delimiter"/> it will skip that occurrence.</param>
        /// <param name="advancePastDelimiter">True to move past the <paramref name="delimiter"/> if found.</param>
        /// <returns>True if the <paramref name="delimiter"/> was found.</returns>
        public bool TryReadTo(out ReadOnlySpan <byte> span, byte delimiter, byte delimiterEscape, bool advancePastDelimiter = true)
        {
            ReadOnlySpan <byte> remaining = UnreadSpan;

#if NET
            int index = remaining.IndexOf(delimiter);
#else
            int index = SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(remaining), delimiter, remaining.Length);
#endif

            if ((index > 0 && remaining[index - 1] != delimiterEscape) || 0u >= (uint)index)
            {
                span = remaining.Slice(0, index);
                AdvanceCurrentSpan(index + (advancePastDelimiter ? 1 : 0));
                return(true);
            }

            // This delimiter might be skipped, go down the slow path
            return(TryReadToSlow(out span, delimiter, delimiterEscape, index, advancePastDelimiter));
        }
예제 #2
0
        /// <summary>Try to read everything up to the given <paramref name="delimiter"/>.</summary>
        /// <param name="span">The read data, if any.</param>
        /// <param name="delimiter">The delimiter to look for.</param>
        /// <param name="advancePastDelimiter">True to move past the <paramref name="delimiter"/> if found.</param>
        /// <returns>True if the <paramref name="delimiter"/> was found.</returns>
        public bool TryReadTo(out ReadOnlySpan <byte> span, byte delimiter, bool advancePastDelimiter = true)
        {
            ReadOnlySpan <byte> remaining = UnreadSpan;

#if NET
            int index = remaining.IndexOf(delimiter);
#else
            int index = SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(remaining), delimiter, remaining.Length);
#endif

            uint uIndex = (uint)index;
            if (SharedConstants.TooBigOrNegative >= uIndex) // index != -1
            {
                span = 0u >= uIndex ? default : remaining.Slice(0, index);
                       AdvanceCurrentSpan(index + (advancePastDelimiter ? 1 : 0));
                       return(true);
            }

            return(TryReadToSlow(out span, delimiter, advancePastDelimiter));
        }
예제 #3
0
        private bool TryReadToInternal(out ReadOnlySequence <byte> sequence, byte delimiter, bool advancePastDelimiter, int skip = 0)
        {
            Debug.Assert(skip >= 0);
            ByteBufferReader copy = this;

            if (skip > 0)
            {
                Advance(skip);
            }
            ReadOnlySpan <byte> remaining = UnreadSpan;

            while (_moreData)
            {
                int  index  = SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(remaining), delimiter, remaining.Length);
                uint uIndex = (uint)index;
                if (SharedConstants.TooBigOrNegative >= uIndex) // index != -1
                {
                    // Found the delimiter. Move to it, slice, then move past it.
                    if (uIndex > 0u) // 此时 index 为非负值
                    {
                        AdvanceCurrentSpan(index);
                    }

                    sequence = _sequence.Slice(copy.Position, Position);
                    if (advancePastDelimiter)
                    {
                        Advance(1);
                    }
                    return(true);
                }

                AdvanceCurrentSpan(remaining.Length);
                remaining = _currentSpan;
            }

            // Didn't find anything, reset our original state.
            this     = copy;
            sequence = default;
            return(false);
        }
예제 #4
0
        public int IndexOf(ICharSequence subString, int start)
        {
            int  thisLen  = this.length;
            uint uThisLen = (uint)thisLen;

            if (0u >= uThisLen)
            {
                return(IndexNotFound);
            }

            uint uStart = (uint)start;

            if (uStart > SharedConstants.TooBigOrNegative)
            {
                start  = 0;
                uStart = 0u;
            }

            int  subCount  = subString.Count;
            uint uSubCount = (uint)subCount;

            if (0u >= uSubCount)
            {
                return(uStart < uThisLen ? start : thisLen);
            }
            var searchLen = thisLen - start;

            if (uSubCount > (uint)searchLen)
            {
                return(IndexNotFound);
            }

            char firstChar = subString[0];

            if ((uint)firstChar > uMaxCharValue)
            {
                return(IndexNotFound);
            }

            if (0u >= uStart)
            {
                if (subString is IHasAsciiSpan hasAscii)
                {
                    return(SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(this.AsciiSpan), thisLen, ref MemoryMarshal.GetReference(hasAscii.AsciiSpan), subCount));
                }
                if (subString is IHasUtf16Span hasUtf16)
                {
                    return(SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(this.Utf16Span), thisLen, ref MemoryMarshal.GetReference(hasUtf16.Utf16Span), subCount));
                }
            }
            else
            {
                if (subString is IHasAsciiSpan hasAscii)
                {
                    var result = SpanHelpers.IndexOf(
                        ref Unsafe.Add(ref MemoryMarshal.GetReference(this.AsciiSpan), start), searchLen,
                        ref MemoryMarshal.GetReference(hasAscii.AsciiSpan), subCount);
                    return(SharedConstants.TooBigOrNegative >= (uint)result ? start + result : IndexNotFound);
                }
                if (subString is IHasUtf16Span hasUtf16)
                {
                    var result = SpanHelpers.IndexOf(
                        ref Unsafe.Add(ref MemoryMarshal.GetReference(this.Utf16Span), start), searchLen,
                        ref MemoryMarshal.GetReference(hasUtf16.Utf16Span), subCount);
                    return(SharedConstants.TooBigOrNegative >= (uint)result ? start + result : IndexNotFound);
                }
            }

            return(IndexOf0(subString, start));
        }
예제 #5
0
        /// <summary>Try to read everything up to the given <paramref name="delimiter"/>, ignoring delimiters that are
        /// preceded by <paramref name="delimiterEscape"/>.</summary>
        /// <param name="sequence">The read data, if any.</param>
        /// <param name="delimiter">The delimiter to look for.</param>
        /// <param name="delimiterEscape">If found prior to <paramref name="delimiter"/> it will skip that occurrence.</param>
        /// <param name="advancePastDelimiter">True to move past the <paramref name="delimiter"/> if found.</param>
        /// <returns>True if the <paramref name="delimiter"/> was found.</returns>
        public bool TryReadTo(out ReadOnlySequence <byte> sequence, byte delimiter, byte delimiterEscape, bool advancePastDelimiter = true)
        {
            ByteBufferReader copy = this;

            ReadOnlySpan <byte> remaining = UnreadSpan;
            bool priorEscape = false;

            while (_moreData)
            {
                int  index  = SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(remaining), delimiter, remaining.Length);
                uint uIndex = (uint)index;
                if (SharedConstants.TooBigOrNegative >= uIndex) // index != -1
                {
                    if (0u >= uIndex && priorEscape)            // index == 0
                    {
                        // We were in the escaped state, so skip this delimiter
                        priorEscape = false;
                        Advance(index + 1);
                        remaining = UnreadSpan;
                        continue;
                    }
                    else if (uIndex > 0u && remaining[index - 1] == delimiterEscape) // 此时 index 为非负值
                    {
                        // This delimiter might be skipped

                        // Count our escapes
                        var idx = SpanHelpers.LastIndexNotOf(
                            ref MemoryMarshal.GetReference(remaining),
                            delimiterEscape,
                            index);
                        int escapeCount = SharedConstants.TooBigOrNegative >= (uint)idx ? index - idx - 1 : index;

                        if (escapeCount == index && priorEscape)
                        {
                            // Started and ended with escape, increment once more
                            escapeCount++;
                        }

                        priorEscape = false;
                        if ((escapeCount & 1) != 0)
                        {
                            // Odd escape count means we're in the escaped state, so skip this delimiter
                            Advance(index + 1);
                            remaining = UnreadSpan;
                            continue;
                        }
                    }

                    // Found the delimiter. Move to it, slice, then move past it.
                    if (uIndex > 0u)
                    {
                        Advance(index);
                    }                                    // 此时 index 为非负值

                    sequence = _sequence.Slice(copy.Position, Position);
                    if (advancePastDelimiter)
                    {
                        Advance(1);
                    }
                    return(true);
                }

                // No delimiter, need to check the end of the span for odd number of escapes then advance
                {
                    var remainingLen = remaining.Length;
                    var idx          = SpanHelpers.LastIndexNotOf(
                        ref MemoryMarshal.GetReference(remaining),
                        delimiterEscape,
                        remainingLen);
                    int escapeCount = SharedConstants.TooBigOrNegative >= (uint)idx ? remainingLen - idx - 1 : remainingLen;

                    if (priorEscape && escapeCount == remainingLen)
                    {
                        escapeCount++;
                    }
                    priorEscape = escapeCount % 2 != 0;
                }

                // Nothing in the current span, move to the end, checking for the skip delimiter
                Advance(remaining.Length);
                remaining = _currentSpan;
            }

            // Didn't find anything, reset our original state.
            this     = copy;
            sequence = default;
            return(false);
        }
예제 #6
0
        private bool TryReadToSlow(out ReadOnlySequence <byte> sequence, byte delimiter, byte delimiterEscape, int index, bool advancePastDelimiter)
        {
            ByteBufferReader copy = this;

            ReadOnlySpan <byte> remaining = UnreadSpan;
            bool priorEscape = false;

            do
            {
                uint uIndex = (uint)index;
                if (SharedConstants.TooBigOrNegative >= uIndex) // index >= 0
                {
                    if (0u >= uIndex && priorEscape)            // index == 0
                    {
                        // We were in the escaped state, so skip this delimiter
                        priorEscape = false;
                        Advance(index + 1);
                        remaining = UnreadSpan;
                        goto Continue;
                    }
                    else if (index > 0 && remaining[index - 1] == delimiterEscape)
                    {
                        // This delimiter might be skipped

                        // Count our escapes
                        int escapeCount = 1;
                        var idx         = SpanHelpers.LastIndexNotOf(
                            ref MemoryMarshal.GetReference(remaining),
                            delimiterEscape,
                            index - 1);
                        if ((uint)idx > SharedConstants.TooBigOrNegative && priorEscape) // i < 0
                        {
                            // Started and ended with escape, increment once more
                            escapeCount++;
                        }
                        escapeCount += index - 2 - idx;

                        if ((escapeCount & 1) != 0)
                        {
                            // An odd escape count means we're currently escaped,
                            // skip the delimiter and reset escaped state.
                            Advance(index + 1);
                            priorEscape = false;
                            remaining   = UnreadSpan;
                            goto Continue;
                        }
                    }

                    // Found the delimiter. Move to it, slice, then move past it.
                    AdvanceCurrentSpan(index);

                    sequence = _sequence.Slice(copy.Position, Position);
                    if (advancePastDelimiter)
                    {
                        Advance(1);
                    }
                    return(true);
                }
                else
                {
                    // No delimiter, need to check the end of the span for odd number of escapes then advance
                    var remainingLen = remaining.Length;
                    if ((uint)remainingLen > 0u && remaining[remainingLen - 1] == delimiterEscape)
                    {
                        int escapeCount = 1;
                        var idx         = SpanHelpers.LastIndexNotOf(
                            ref MemoryMarshal.GetReference(remaining),
                            delimiterEscape,
                            remainingLen - 1);
                        escapeCount += remainingLen - 2 - idx;

                        if ((uint)idx > SharedConstants.TooBigOrNegative && priorEscape) // idx < 0
                        {
                            priorEscape = 0u >= (uint)(escapeCount & 1);                 // equivalent to incrementing escapeCount before setting priorEscape
                        }
                        else
                        {
                            priorEscape = (escapeCount & 1) != 0;
                        }
                    }
                    else
                    {
                        priorEscape = false;
                    }
                }

                // Nothing in the current span, move to the end, checking for the skip delimiter
                AdvanceCurrentSpan(remaining.Length);
                remaining = _currentSpan;

                Continue:
                index = SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(remaining), delimiter, remaining.Length);
            } while (!End);

            // Didn't find anything, reset our original state.
            this     = copy;
            sequence = default;
            return(false);
        }