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.
///