Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize StringBuilder.Insert. #64922

Merged
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1290,17 +1290,24 @@ public StringBuilder Insert(int index, string? value)
return this;
}

public StringBuilder Insert(int index, bool value) => Insert(index, value.ToString(), 1);
#pragma warning disable CA1830 // Prefer strongly-typed Append and Insert method overloads on StringBuilder. No need to fix for the builder itself
public StringBuilder Insert(int index, bool value) => Insert(index, value.ToString());
#pragma warning restore CA1830

[CLSCompliant(false)]
public StringBuilder Insert(int index, sbyte value) => Insert(index, value.ToString(), 1);
public StringBuilder Insert(int index, sbyte value) => InsertSpanFormattable(index, value);

public StringBuilder Insert(int index, byte value) => Insert(index, value.ToString(), 1);
public StringBuilder Insert(int index, byte value) => InsertSpanFormattable(index, value);

public StringBuilder Insert(int index, short value) => Insert(index, value.ToString(), 1);
public StringBuilder Insert(int index, short value) => InsertSpanFormattable(index, value);

public StringBuilder Insert(int index, char value)
{
if ((uint)index > (uint)Length)
{
throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
}

Insert(index, ref value, 1);
return this;
}
Expand All @@ -1314,7 +1321,7 @@ public StringBuilder Insert(int index, char[]? value)

if (value != null)
{
Insert(index, value, 0, value.Length);
Insert(index, ref MemoryMarshal.GetArrayDataReference(value), value.Length);
}
return this;
}
Expand Down Expand Up @@ -1359,26 +1366,26 @@ public StringBuilder Insert(int index, char[]? value, int startIndex, int charCo
return this;
}

public StringBuilder Insert(int index, int value) => Insert(index, value.ToString(), 1);
public StringBuilder Insert(int index, int value) => InsertSpanFormattable(index, value);

public StringBuilder Insert(int index, long value) => Insert(index, value.ToString(), 1);
public StringBuilder Insert(int index, long value) => InsertSpanFormattable(index, value);

public StringBuilder Insert(int index, float value) => Insert(index, value.ToString(), 1);
public StringBuilder Insert(int index, float value) => InsertSpanFormattable(index, value);

public StringBuilder Insert(int index, double value) => Insert(index, value.ToString(), 1);
public StringBuilder Insert(int index, double value) => InsertSpanFormattable(index, value);

public StringBuilder Insert(int index, decimal value) => Insert(index, value.ToString(), 1);
public StringBuilder Insert(int index, decimal value) => InsertSpanFormattable(index, value);

[CLSCompliant(false)]
public StringBuilder Insert(int index, ushort value) => Insert(index, value.ToString(), 1);
public StringBuilder Insert(int index, ushort value) => InsertSpanFormattable(index, value);

[CLSCompliant(false)]
public StringBuilder Insert(int index, uint value) => Insert(index, value.ToString(), 1);
public StringBuilder Insert(int index, uint value) => InsertSpanFormattable(index, value);

[CLSCompliant(false)]
public StringBuilder Insert(int index, ulong value) => Insert(index, value.ToString(), 1);
public StringBuilder Insert(int index, ulong value) => InsertSpanFormattable(index, value);

public StringBuilder Insert(int index, object? value) => (value == null) ? this : Insert(index, value.ToString(), 1);
public StringBuilder Insert(int index, object? value) => (value == null) ? this : Insert(index, value.ToString());

public StringBuilder Insert(int index, ReadOnlySpan<char> value)
{
Expand All @@ -1395,6 +1402,19 @@ public StringBuilder Insert(int index, ReadOnlySpan<char> value)
return this;
}

private StringBuilder InsertSpanFormattable<T>(int index, T value) where T : ISpanFormattable
{
Debug.Assert(typeof(T).Assembly.Equals(typeof(object).Assembly), "Implementation trusts the results of TryFormat because T is expected to be something known");

Span<char> buffer = stackalloc char[256];
if (value.TryFormat(buffer, out int charsWritten, format: default, provider: null))
{
return Insert(index, buffer.Slice(0, charsWritten));
}

return Insert(index, value.ToString());
}

public StringBuilder AppendFormat(string format, object? arg0) => AppendFormatHelper(null, format, new ParamsArray(arg0));

public StringBuilder AppendFormat(string format, object? arg0, object? arg1) => AppendFormatHelper(null, format, new ParamsArray(arg0, arg1));
Expand Down Expand Up @@ -2066,10 +2086,7 @@ private void AppendWithExpansion(ref char value, int valueCount)
/// <param name="valueCount">The number of characters in the buffer.</param>
private void Insert(int index, ref char value, int valueCount)
{
if ((uint)index > (uint)Length)
{
throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
}
Debug.Assert((uint)index <= (uint)Length, "Callers should check that index is a legal value.");

if (valueCount > 0)
{
Expand Down