AsReadOnlySpan -> AsSpan rename to fix build breaks
[platform/upstream/coreclr.git] / src / mscorlib / shared / System / StringSpanHelpers.cs
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 // See the LICENSE file in the project root for more information.
4
5 using System.Globalization;
6
7 namespace System
8 {
9     /// <summary>Helpers for string-like operations on spans of chars.</summary>
10     internal static class StringSpanHelpers
11     {
12         // TODO https://github.com/dotnet/corefx/issues/21395: Provide public, efficient implementations
13
14         public static bool Equals(this ReadOnlySpan<char> left, ReadOnlySpan<char> right, StringComparison comparisonType) =>
15             comparisonType == StringComparison.Ordinal ? Equals(left, right) :
16             comparisonType == StringComparison.OrdinalIgnoreCase ? EqualsOrdinalIgnoreCase(left, right) :
17             throw new ArgumentOutOfRangeException(nameof(comparisonType));
18
19         public static bool Equals(this ReadOnlySpan<char> left, string right) =>
20             Equals(left, right.AsSpan());
21
22         public static bool Equals(this ReadOnlySpan<char> left, ReadOnlySpan<char> right)
23         {
24             if (left.Length != right.Length)
25             {
26                 return false;
27             }
28
29             for (int i = 0; i < left.Length; i++)
30             {
31                 if (left[i] != right[i])
32                 {
33                     return false;
34                 }
35             }
36
37             return true;
38         }
39
40         private static bool EqualsOrdinalIgnoreCase(this ReadOnlySpan<char> left, ReadOnlySpan<char> right)
41         {
42             if (left.Length != right.Length)
43             {
44                 return false;
45             }
46
47             for (int i = 0; i < left.Length; i++)
48             {
49                 char x = left[i], y = right[i];
50                 if (x != y &&
51                     TextInfo.ToUpperAsciiInvariant(x) != TextInfo.ToUpperAsciiInvariant(y))
52                 {
53                     return false;
54                 }
55             }
56
57             return true;
58         }
59
60         public static ReadOnlySpan<char> Trim(this ReadOnlySpan<char> source)
61         {
62             int startIndex = 0, endIndex = source.Length - 1;
63
64             while (startIndex <= endIndex && char.IsWhiteSpace(source[startIndex]))
65             {
66                 startIndex++;
67             }
68
69             while (endIndex >= startIndex && char.IsWhiteSpace(source[endIndex]))
70             {
71                 endIndex--;
72             }
73
74             return source.Slice(startIndex, endIndex - startIndex + 1);
75         }
76
77         public static int IndexOf(this ReadOnlySpan<char> source, char value) =>
78             IndexOf(source, value, 0);
79
80         public static int IndexOf(this ReadOnlySpan<char> source, char value, int startIndex)
81         {
82             for (int i = startIndex; i < source.Length; i++)
83             {
84                 if (source[i] == value)
85                 {
86                     return i;
87                 }
88             }
89
90             return -1;
91         }
92
93         public static bool Contains(this ReadOnlySpan<char> source, char value)
94         {
95             for (int i = 0; i < source.Length; i++)
96             {
97                 if (source[i] == value)
98                 {
99                     return true;
100                 }
101             }
102
103             return false;
104         }
105
106         public static ReadOnlySpan<char> Remove(this ReadOnlySpan<char> source, int startIndex, int count)
107         {
108             if (startIndex < 0)
109                 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
110             if (count < 0)
111                 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_NegativeCount);
112             if (count > source.Length - startIndex)
113                 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_IndexCount);
114
115             if (count == 0)
116             {
117                 return source;
118             }
119
120             int newLength = source.Length - count;
121             if (newLength == 0)
122             {
123                 return ReadOnlySpan<char>.Empty;
124             }
125
126             Span<char> result = new char[newLength];
127             source.Slice(0, startIndex).CopyTo(result);
128             source.Slice(startIndex + count).CopyTo(result.Slice(startIndex));
129             return result;
130         }
131
132         // Returns the index of the last occurrence of a specified character in the current instance.
133         public static int LastIndexOf(this ReadOnlySpan<char> source, char value)
134         {
135             if (source.Length == 0)
136                 return -1;
137
138             for (int i = source.Length - 1; i >= 0; i--)
139             {
140                 if (source[i] == value)
141                     return i;
142             }
143
144             return -1;
145         }
146
147         public static void CheckStringComparison(StringComparison comparisonType)
148         {
149             // Single comparison to check if comparisonType is within [CurrentCulture .. OrdinalIgnoreCase]
150             if ((uint)(comparisonType - StringComparison.CurrentCulture) > (StringComparison.OrdinalIgnoreCase - StringComparison.CurrentCulture))
151             {
152                 throw new ArgumentException(SR.NotSupported_StringComparison, nameof(comparisonType));
153             }
154         }
155     }
156 }