/// <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)); }
/// <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)); }
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); }
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)); }
/// <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); }
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); }