/// <summary> /// Attempts to locate the target <paramref name="value"/> within this <see cref="Utf8Span"/> instance. /// If <paramref name="value"/> is found, returns <see langword="true"/> and sets <paramref name="range"/> to /// the location where <paramref name="value"/> occurs within this <see cref="Utf8Span"/> instance. /// If <paramref name="value"/> is not found, returns <see langword="false"/> and sets <paramref name="range"/> /// to <see langword="default"/>. /// </summary> /// <remarks> /// An ordinal search is performed. /// </remarks> public bool TryFind(Rune value, out Range range) { if (value.IsAscii) { // Special-case ASCII since it's a simple single byte search. int idx = Bytes.IndexOf((byte)value.Value); if (idx < 0) { range = default; return(false); } else { range = idx..(idx + 1); return(true); } } else { // Slower path: need to search a multi-byte sequence. // TODO_UTF8STRING: As an optimization, we could use unsafe APIs below since we // know Rune instances are well-formed and slicing is safe. Span <byte> runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; int utf8ByteLengthOfRune = value.EncodeToUtf8(runeBytes); return(TryFind(UnsafeCreateWithoutValidation(runeBytes.Slice(0, utf8ByteLengthOfRune)), out range)); } }
/// <summary> /// Returns a value stating whether the current <see cref="Utf8Span"/> instance contains /// the specified <see cref="Rune"/>. An ordinal comparison is used. /// </summary> public bool Contains(Rune value) { // TODO_UTF8STRING: This should be split into two methods: // One which operates on a single-byte (ASCII) search value, // the other which operates on a multi-byte (non-ASCII) search value. Span <byte> runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; int runeBytesWritten = value.EncodeToUtf8(runeBytes); return(this.Bytes.IndexOf(runeBytes.Slice(0, runeBytesWritten)) >= 0); }
/// <summary> /// Attempts to locate the target <paramref name="value"/> within this <see cref="Utf8Span"/> instance. /// If <paramref name="value"/> is found, returns <see langword="true"/> and sets <paramref name="range"/> to /// the location where <paramref name="value"/> occurs within this <see cref="Utf8Span"/> instance. /// If <paramref name="value"/> is not found, returns <see langword="false"/> and sets <paramref name="range"/> /// to <see langword="default"/>. /// </summary> /// <remarks> /// The search is performed using the specified <paramref name="comparisonType"/>. /// </remarks> public bool TryFind(Rune value, StringComparison comparisonType, out Range range) { if (comparisonType == StringComparison.Ordinal) { return(TryFind(value, out range)); } else { // Slower path: not an ordinal comparison. // TODO_UTF8STRING: As an optimization, we could use unsafe APIs below since we // know Rune instances are well-formed and slicing is safe. Span <byte> runeBytes = stackalloc byte[Utf8Utility.MaxBytesPerScalar]; int utf8ByteLengthOfRune = value.EncodeToUtf8(runeBytes); return(TryFind(UnsafeCreateWithoutValidation(runeBytes.Slice(0, utf8ByteLengthOfRune)), comparisonType, out range)); } }