diff --git a/src/Build/Evaluation/Expander.cs b/src/Build/Evaluation/Expander.cs index b3987d2a37a..99f7d355c4b 100644 --- a/src/Build/Evaluation/Expander.cs +++ b/src/Build/Evaluation/Expander.cs @@ -280,9 +280,6 @@ private void FlushFirstValueIfNeeded() /// Enabled by ExpanderOptions.Truncate. /// private const int ItemLimitPerExpansion = 3; - private static readonly char[] s_singleQuoteChar = { '\'' }; - private static readonly char[] s_backtickChar = { '`' }; - private static readonly char[] s_doubleQuoteChar = { '"' }; /// /// The CultureInfo from the invariant culture. Used to avoid allocations for @@ -785,37 +782,34 @@ private static void AddArgument(List arguments, SpanBasedStringBuilder a // we reached the end of an argument, add the builder's final result // to our arguments. argumentBuilder.Trim(); - string argValue = argumentBuilder.ToString(); // We support passing of null through the argument constant value null - if (String.Equals("null", argValue, StringComparison.OrdinalIgnoreCase)) + if (argumentBuilder.Equals("null", StringComparison.OrdinalIgnoreCase)) { arguments.Add(null); } else { - if (argValue.Length > 0) + if (argumentBuilder.Length > 0) { - if (argValue[0] == '\'' && argValue[argValue.Length - 1] == '\'') + if (argumentBuilder[0] == '\'' && argumentBuilder[argumentBuilder.Length - 1] == '\'') { - arguments.Add(argValue.Trim(s_singleQuoteChar)); + argumentBuilder.Trim('\''); } - else if (argValue[0] == '`' && argValue[argValue.Length - 1] == '`') + else if (argumentBuilder[0] == '`' && argumentBuilder[argumentBuilder.Length - 1] == '`') { - arguments.Add(argValue.Trim(s_backtickChar)); + argumentBuilder.Trim('`'); } - else if (argValue[0] == '"' && argValue[argValue.Length - 1] == '"') + else if (argumentBuilder[0] == '"' && argumentBuilder[argumentBuilder.Length - 1] == '"') { - arguments.Add(argValue.Trim(s_doubleQuoteChar)); - } - else - { - arguments.Add(argValue); + argumentBuilder.Trim('"'); } + + arguments.Add(argumentBuilder.ToString()); } else { - arguments.Add(argValue); + arguments.Add(string.Empty); } } } diff --git a/src/StringTools/SpanBasedStringBuilder.cs b/src/StringTools/SpanBasedStringBuilder.cs index dbdaed8617e..0d31bc8a635 100644 --- a/src/StringTools/SpanBasedStringBuilder.cs +++ b/src/StringTools/SpanBasedStringBuilder.cs @@ -120,7 +120,49 @@ public SpanBasedStringBuilder(int capacity = 4) /// public int Capacity => _spans.Capacity; - public bool Equals(ReadOnlySpan other) + public char this[int index] + { + get + { + if (index < 0 || index >= Length) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + int adjustedIndex = index; + foreach (ReadOnlyMemory span in _spans) + { + if (adjustedIndex < span.Length) + { + return span.Span[adjustedIndex]; + } + else + { + adjustedIndex -= span.Length; + } + } + + // Should never reach here if Length is correct + throw new IndexOutOfRangeException(); + } + } + + /// + /// Creates a new enumerator for enumerating characters in this string. Does not allocate. + /// + /// The enumerator. + public Enumerator GetEnumerator() + { + return new Enumerator(_spans); + } + + public bool Equals(string other) => Equals(other.AsSpan(), StringComparison.Ordinal); + + public bool Equals(string other, StringComparison comparison) => Equals(other.AsSpan(), comparison); + + public bool Equals(ReadOnlySpan other) => Equals(other, StringComparison.Ordinal); + + public bool Equals(ReadOnlySpan other, StringComparison comparison) { if (_spans.Count == 0 && other.IsEmpty) { @@ -135,7 +177,7 @@ public bool Equals(ReadOnlySpan other) int otherIndex = 0; foreach (ReadOnlyMemory internalSpan in _spans) { - if (!MemoryExtensions.Equals(other.Slice(otherIndex, internalSpan.Length), internalSpan.Span, StringComparison.Ordinal)) + if (!MemoryExtensions.Equals(other.Slice(otherIndex, internalSpan.Length), internalSpan.Span, comparison)) { return false; } @@ -146,15 +188,6 @@ public bool Equals(ReadOnlySpan other) return true; } - /// - /// Creates a new enumerator for enumerating characters in this string. Does not allocate. - /// - /// The enumerator. - public Enumerator GetEnumerator() - { - return new Enumerator(_spans); - } - /// /// Converts this instance to a System.String while first searching for a match in the intern table. /// @@ -252,6 +285,28 @@ public void TrimStart() } } + public void TrimStart(char c) + { + for (int spanIdx = 0; spanIdx < _spans.Count; spanIdx++) + { + ReadOnlySpan span = _spans[spanIdx].Span; + int i = 0; + while (i < span.Length && span[i] == c) + { + i++; + } + if (i > 0) + { + _spans[spanIdx] = _spans[spanIdx].Slice(i); + Length -= i; + } + if (!_spans[spanIdx].IsEmpty) + { + return; + } + } + } + /// /// Removes trailing white-space characters from the string. /// @@ -277,6 +332,28 @@ public void TrimEnd() } } + public void TrimEnd(char c) + { + for (int spanIdx = _spans.Count - 1; spanIdx >= 0; spanIdx--) + { + ReadOnlySpan span = _spans[spanIdx].Span; + int i = span.Length - 1; + while (i >= 0 && span[i] == c) + { + i--; + } + if (i + 1 < span.Length) + { + _spans[spanIdx] = _spans[spanIdx].Slice(0, i + 1); + Length -= span.Length - (i + 1); + } + if (!_spans[spanIdx].IsEmpty) + { + return; + } + } + } + /// /// Removes leading and trailing white-space characters from the string. /// @@ -286,6 +363,12 @@ public void Trim() TrimEnd(); } + public void Trim(char c) + { + TrimStart(c); + TrimEnd(c); + } + /// /// Clears this instance making it represent an empty string. ///