| | | 1 | | // Licensed to the .NET Foundation under one or more agreements. |
| | | 2 | | // The .NET Foundation licenses this file to you under the MIT license. |
| | | 3 | | |
| | | 4 | | using System.Collections.Generic; |
| | | 5 | | using System.Diagnostics; |
| | | 6 | | |
| | | 7 | | namespace System.Buffers |
| | | 8 | | { |
| | | 9 | | /// <summary> |
| | | 10 | | /// Implements the base <see cref="SearchValues{T}"/> {Last}IndexOfAny{Except} operations. |
| | | 11 | | /// While these operations are exposed such that you can call string[].IndexOfAny(searchValues), |
| | | 12 | | /// they are not expected to be used in performance-critical paths. |
| | | 13 | | /// <see cref="MemoryExtensions.IndexOfAny(ReadOnlySpan{char}, SearchValues{string})"/> is the main |
| | | 14 | | /// reason why someone would create an instance of <see cref="string"/> <see cref="SearchValues{T}"/>. |
| | | 15 | | /// </summary> |
| | | 16 | | internal abstract class StringSearchValuesBase : SearchValues<string> |
| | | 17 | | { |
| | | 18 | | private readonly HashSet<string>? _uniqueValues; |
| | | 19 | | |
| | | 20 | | /// <summary> |
| | | 21 | | /// This exists to allow <see cref="SingleStringSearchValuesThreeChars{TValueLength, TCaseSensitivity}"/> to avo |
| | | 22 | | /// </summary> |
| | 0 | 23 | | protected bool HasUniqueValues => _uniqueValues is not null; |
| | | 24 | | |
| | 0 | 25 | | public StringSearchValuesBase(HashSet<string>? uniqueValues) => |
| | 0 | 26 | | _uniqueValues = uniqueValues; |
| | | 27 | | |
| | | 28 | | internal override bool ContainsCore(string value) |
| | | 29 | | { |
| | 0 | 30 | | Debug.Assert(_uniqueValues is not null, "ContainsCore should be overridden if uniqueValues weren't provided. |
| | 0 | 31 | | return _uniqueValues.Contains(value); |
| | | 32 | | } |
| | | 33 | | |
| | | 34 | | internal override string[] GetValues() |
| | | 35 | | { |
| | 0 | 36 | | Debug.Assert(_uniqueValues is not null, "GetValues should be overridden if uniqueValues weren't provided."); |
| | 0 | 37 | | string[] values = new string[_uniqueValues.Count]; |
| | 0 | 38 | | _uniqueValues.CopyTo(values); |
| | 0 | 39 | | return values; |
| | | 40 | | } |
| | | 41 | | |
| | | 42 | | internal sealed override int IndexOfAny(ReadOnlySpan<string> span) => |
| | 0 | 43 | | IndexOfAny<IndexOfAnyAsciiSearcher.DontNegate>(span); |
| | | 44 | | |
| | | 45 | | internal sealed override int IndexOfAnyExcept(ReadOnlySpan<string> span) => |
| | 0 | 46 | | IndexOfAny<IndexOfAnyAsciiSearcher.Negate>(span); |
| | | 47 | | |
| | | 48 | | internal sealed override int LastIndexOfAny(ReadOnlySpan<string> span) => |
| | 0 | 49 | | LastIndexOfAny<IndexOfAnyAsciiSearcher.DontNegate>(span); |
| | | 50 | | |
| | | 51 | | internal sealed override int LastIndexOfAnyExcept(ReadOnlySpan<string> span) => |
| | 0 | 52 | | LastIndexOfAny<IndexOfAnyAsciiSearcher.Negate>(span); |
| | | 53 | | |
| | | 54 | | private int IndexOfAny<TNegator>(ReadOnlySpan<string> span) |
| | | 55 | | where TNegator : struct, IndexOfAnyAsciiSearcher.INegator |
| | | 56 | | { |
| | 0 | 57 | | for (int i = 0; i < span.Length; i++) |
| | | 58 | | { |
| | 0 | 59 | | if (TNegator.NegateIfNeeded(ContainsCore(span[i]))) |
| | | 60 | | { |
| | 0 | 61 | | return i; |
| | | 62 | | } |
| | | 63 | | } |
| | | 64 | | |
| | 0 | 65 | | return -1; |
| | | 66 | | } |
| | | 67 | | |
| | | 68 | | private int LastIndexOfAny<TNegator>(ReadOnlySpan<string> span) |
| | | 69 | | where TNegator : struct, IndexOfAnyAsciiSearcher.INegator |
| | | 70 | | { |
| | 0 | 71 | | for (int i = span.Length - 1; i >= 0; i--) |
| | | 72 | | { |
| | 0 | 73 | | if (TNegator.NegateIfNeeded(ContainsCore(span[i]))) |
| | | 74 | | { |
| | 0 | 75 | | return i; |
| | | 76 | | } |
| | | 77 | | } |
| | | 78 | | |
| | 0 | 79 | | return -1; |
| | | 80 | | } |
| | | 81 | | } |
| | | 82 | | } |
| | | 83 | | |