Skip to content

Commit

Permalink
Use ValueArray in ParamsArray.
Browse files Browse the repository at this point in the history
  • Loading branch information
VSadov committed Oct 27, 2021
1 parent 88c2c84 commit b85d94a
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ public override void WriteLine(ReadOnlySpan<char> buffer)
}
}

private void WriteFormatHelper(string format, ParamsArray args, bool appendNewLine)
private void WriteFormatHelper<TArr>(string format, ParamsArray<TArr> args, bool appendNewLine) where TArr : IValueArray<object?>
{
StringBuilder sb =
StringBuilderCache.Acquire((format?.Length ?? 0) + args.Length * 8)
Expand All @@ -542,7 +542,7 @@ public override void Write(string format, object? arg0)
{
if (GetType() == typeof(StreamWriter))
{
WriteFormatHelper(format, new ParamsArray(arg0), appendNewLine: false);
WriteFormatHelper(format, ParamsArray.Create(arg0), appendNewLine: false);
}
else
{
Expand All @@ -554,7 +554,7 @@ public override void Write(string format, object? arg0, object? arg1)
{
if (GetType() == typeof(StreamWriter))
{
WriteFormatHelper(format, new ParamsArray(arg0, arg1), appendNewLine: false);
WriteFormatHelper(format, ParamsArray.Create(arg0, arg1), appendNewLine: false);
}
else
{
Expand All @@ -566,7 +566,7 @@ public override void Write(string format, object? arg0, object? arg1, object? ar
{
if (GetType() == typeof(StreamWriter))
{
WriteFormatHelper(format, new ParamsArray(arg0, arg1, arg2), appendNewLine: false);
WriteFormatHelper(format, ParamsArray.Create(arg0, arg1, arg2), appendNewLine: false);
}
else
{
Expand All @@ -582,7 +582,7 @@ public override void Write(string format, params object?[] arg)
{
throw new ArgumentNullException((format == null) ? nameof(format) : nameof(arg)); // same as base logic
}
WriteFormatHelper(format, new ParamsArray(arg), appendNewLine: false);
WriteFormatHelper(format, ParamsArray.Create(arg), appendNewLine: false);
}
else
{
Expand All @@ -594,7 +594,7 @@ public override void WriteLine(string format, object? arg0)
{
if (GetType() == typeof(StreamWriter))
{
WriteFormatHelper(format, new ParamsArray(arg0), appendNewLine: true);
WriteFormatHelper(format, ParamsArray.Create(arg0), appendNewLine: true);
}
else
{
Expand All @@ -606,7 +606,7 @@ public override void WriteLine(string format, object? arg0, object? arg1)
{
if (GetType() == typeof(StreamWriter))
{
WriteFormatHelper(format, new ParamsArray(arg0, arg1), appendNewLine: true);
WriteFormatHelper(format, ParamsArray.Create(arg0, arg1), appendNewLine: true);
}
else
{
Expand All @@ -618,7 +618,7 @@ public override void WriteLine(string format, object? arg0, object? arg1, object
{
if (GetType() == typeof(StreamWriter))
{
WriteFormatHelper(format, new ParamsArray(arg0, arg1, arg2), appendNewLine: true);
WriteFormatHelper(format, ParamsArray.Create(arg0, arg1, arg2), appendNewLine: true);
}
else
{
Expand All @@ -634,7 +634,7 @@ public override void WriteLine(string format, params object?[] arg)
{
throw new ArgumentNullException(nameof(arg));
}
WriteFormatHelper(format, new ParamsArray(arg), appendNewLine: true);
WriteFormatHelper(format, ParamsArray.Create(arg), appendNewLine: true);
}
else
{
Expand Down
99 changes: 48 additions & 51 deletions src/libraries/System.Private.CoreLib/src/System/ParamsArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,73 +3,70 @@

namespace System
{
internal readonly struct ParamsArray
internal readonly struct ParamsArray<TArr> where TArr : IValueArray<object?>
{
// Sentinel fixed-length arrays eliminate the need for a "count" field keeping this
// struct down to just 4 fields. These are only used for their "Length" property,
// that is, their elements are never set or referenced.
private static readonly object?[] s_oneArgArray = new object?[1];
private static readonly object?[] s_twoArgArray = new object?[2];
private static readonly object?[] s_threeArgArray = new object?[3];
// NOTE: arguments in an array form are stored in element #0 of object?[MaxInlineArgs + 1].
// alternatively we could use object?[2] with element #0 storing a sentinel object and #2 the actual array
// that will take less space, but sentinel check is an actual compare vs. length compare that can be done at JIT time.
// This is a size/cycles tradeoff, which I did not have time to measure, but either way would work.
private const int MaxInlineArgs = 3;

private readonly object? _arg0;
private readonly object? _arg1;
private readonly object? _arg2;
private readonly TArr _args;

// After construction, the first three elements of this array will never be accessed
// because the indexer will retrieve those values from arg0, arg1, and arg2.
private readonly object?[] _args;

public ParamsArray(object? arg0)
internal ParamsArray(TArr args)
{
_arg0 = arg0;
_arg1 = null;
_arg2 = null;

// Always assign this.args to make use of its "Length" property
_args = s_oneArgArray;
_args = args;
}

public ParamsArray(object? arg0, object? arg1)
{
_arg0 = arg0;
_arg1 = arg1;
_arg2 = null;
// NB: _args.Length is a JIT-time constant.
public int Length => _args.Length > MaxInlineArgs ?
((object?[])_args[0]!).Length :
_args.Length;

// Always assign this.args to make use of its "Length" property
_args = s_twoArgArray;
}
public object? this[int index] => _args.Length > MaxInlineArgs ?
((object?[])_args[0]!)[index] :
_args[index];
}

public ParamsArray(object? arg0, object? arg1, object? arg2)
{
_arg0 = arg0;
_arg1 = arg1;
_arg2 = arg2;
internal static class ParamsArray
{
private static ParamsArray<TArr> Create<TArr>(TArr args) where TArr : IValueArray<object?>
=> new ParamsArray<TArr>(args);

// Always assign this.args to make use of its "Length" property
_args = s_threeArgArray;
public static ParamsArray<ValueArray<object?, object[]>> Create(object? arg0)
{
ValueArray<object?, object[]> args = default;
args[0] = arg0;
return Create(args);
}

public ParamsArray(object?[] args)
public static ParamsArray<ValueArray<object?, object[,]>> Create(object? arg0, object? arg1)
{
int len = args.Length;
_arg0 = len > 0 ? args[0] : null;
_arg1 = len > 1 ? args[1] : null;
_arg2 = len > 2 ? args[2] : null;
_args = args;
ValueArray<object?, object[,]> args = default;
args[0] = arg0;
args[1] = arg1;
return Create(args);
}

public int Length => _args.Length;

public object? this[int index] => index == 0 ? _arg0 : GetAtSlow(index);
#if NICE_SYNTAX
public static ParamsArray<object?[3]> Create(object? arg0, object? arg1, object? arg2)
=> Create(new object?[3] { arg0, arg1, arg2 });
#else
public static ParamsArray<ValueArray<object?, object[,,]>> Create(object? arg0, object? arg1, object? arg2)
{
ValueArray<object?, object[,,]> args = default;
args[0] = arg0;
args[1] = arg1;
args[2] = arg2;
return Create(args);
}
#endif

private object? GetAtSlow(int index)
public static ParamsArray<ValueArray<object?, object[,,,]>> Create(object?[] args)
{
if (index == 1)
return _arg1;
if (index == 2)
return _arg2;
return _args[index];
ValueArray<object?, object[,,,]> argsArr = default;
argsArr[0] = args;
return Create(argsArr);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -439,17 +439,17 @@ public static string Concat(params string?[] values)

public static string Format(string format, object? arg0)
{
return FormatHelper(null, format, new ParamsArray(arg0));
return FormatHelper(null, format, ParamsArray.Create(arg0));
}

public static string Format(string format, object? arg0, object? arg1)
{
return FormatHelper(null, format, new ParamsArray(arg0, arg1));
return FormatHelper(null, format, ParamsArray.Create(arg0, arg1));
}

public static string Format(string format, object? arg0, object? arg1, object? arg2)
{
return FormatHelper(null, format, new ParamsArray(arg0, arg1, arg2));
return FormatHelper(null, format, ParamsArray.Create(arg0, arg1, arg2));
}

public static string Format(string format, params object?[] args)
Expand All @@ -461,22 +461,22 @@ public static string Format(string format, params object?[] args)
throw new ArgumentNullException((format == null) ? nameof(format) : nameof(args));
}

return FormatHelper(null, format, new ParamsArray(args));
return FormatHelper(null, format, ParamsArray.Create(args));
}

public static string Format(IFormatProvider? provider, string format, object? arg0)
{
return FormatHelper(provider, format, new ParamsArray(arg0));
return FormatHelper(provider, format, ParamsArray.Create(arg0));
}

public static string Format(IFormatProvider? provider, string format, object? arg0, object? arg1)
{
return FormatHelper(provider, format, new ParamsArray(arg0, arg1));
return FormatHelper(provider, format, ParamsArray.Create(arg0, arg1));
}

public static string Format(IFormatProvider? provider, string format, object? arg0, object? arg1, object? arg2)
{
return FormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
return FormatHelper(provider, format, ParamsArray.Create(arg0, arg1, arg2));
}

public static string Format(IFormatProvider? provider, string format, params object?[] args)
Expand All @@ -488,10 +488,10 @@ public static string Format(IFormatProvider? provider, string format, params obj
throw new ArgumentNullException((format == null) ? nameof(format) : nameof(args));
}

return FormatHelper(provider, format, new ParamsArray(args));
return FormatHelper(provider, format, ParamsArray.Create(args));
}

private static string FormatHelper(IFormatProvider? provider, string format, ParamsArray args)
private static string FormatHelper<TArr>(IFormatProvider? provider, string format, ParamsArray<TArr> args) where TArr : IValueArray<object?>
{
if (format == null)
throw new ArgumentNullException(nameof(format));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1499,11 +1499,11 @@ public StringBuilder Insert(int index, ReadOnlySpan<char> value)
return this;
}

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

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

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

public StringBuilder AppendFormat(string format, params object?[] args)
{
Expand All @@ -1515,14 +1515,14 @@ public StringBuilder AppendFormat(string format, params object?[] args)
throw new ArgumentNullException(paramName);
}

return AppendFormatHelper(null, format, new ParamsArray(args));
return AppendFormatHelper(null, format, ParamsArray.Create(args));
}

public StringBuilder AppendFormat(IFormatProvider? provider, string format, object? arg0) => AppendFormatHelper(provider, format, new ParamsArray(arg0));
public StringBuilder AppendFormat(IFormatProvider? provider, string format, object? arg0) => AppendFormatHelper(provider, format, ParamsArray.Create(arg0));

public StringBuilder AppendFormat(IFormatProvider? provider, string format, object? arg0, object? arg1) => AppendFormatHelper(provider, format, new ParamsArray(arg0, arg1));
public StringBuilder AppendFormat(IFormatProvider? provider, string format, object? arg0, object? arg1) => AppendFormatHelper(provider, format, ParamsArray.Create(arg0, arg1));

public StringBuilder AppendFormat(IFormatProvider? provider, string format, object? arg0, object? arg1, object? arg2) => AppendFormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
public StringBuilder AppendFormat(IFormatProvider? provider, string format, object? arg0, object? arg1, object? arg2) => AppendFormatHelper(provider, format, ParamsArray.Create(arg0, arg1, arg2));

public StringBuilder AppendFormat(IFormatProvider? provider, string format, params object?[] args)
{
Expand All @@ -1534,7 +1534,7 @@ public StringBuilder AppendFormat(IFormatProvider? provider, string format, para
throw new ArgumentNullException(paramName);
}

return AppendFormatHelper(provider, format, new ParamsArray(args));
return AppendFormatHelper(provider, format, ParamsArray.Create(args));
}

private static void FormatError()
Expand All @@ -1546,7 +1546,7 @@ private static void FormatError()
private const int IndexLimit = 1000000; // Note: 0 <= ArgIndex < IndexLimit
private const int WidthLimit = 1000000; // Note: -WidthLimit < ArgAlign < WidthLimit

internal StringBuilder AppendFormatHelper(IFormatProvider? provider, string format, ParamsArray args)
internal StringBuilder AppendFormatHelper<TArr>(IFormatProvider? provider, string format, ParamsArray<TArr> args) where TArr : IValueArray<object?>
{
if (format == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ namespace System.Text
{
internal ref partial struct ValueStringBuilder
{
public void AppendFormat(string format, object? arg0) => AppendFormatHelper(null, format, new ParamsArray(arg0));
public void AppendFormat(string format, object? arg0) => AppendFormatHelper(null, format, ParamsArray.Create(arg0));

public void AppendFormat(string format, object? arg0, object? arg1) => AppendFormatHelper(null, format, new ParamsArray(arg0, arg1));
public void AppendFormat(string format, object? arg0, object? arg1) => AppendFormatHelper(null, format, ParamsArray.Create(arg0, arg1));

public void AppendFormat(string format, object? arg0, object? arg1, object? arg2) => AppendFormatHelper(null, format, new ParamsArray(arg0, arg1, arg2));
public void AppendFormat(string format, object? arg0, object? arg1, object? arg2) => AppendFormatHelper(null, format, ParamsArray.Create(arg0, arg1, arg2));

public void AppendFormat(string format, params object?[] args)
{
Expand All @@ -21,14 +21,14 @@ public void AppendFormat(string format, params object?[] args)
throw new ArgumentNullException(paramName);
}

AppendFormatHelper(null, format, new ParamsArray(args));
AppendFormatHelper(null, format, ParamsArray.Create(args));
}

public void AppendFormat(IFormatProvider? provider, string format, object? arg0) => AppendFormatHelper(provider, format, new ParamsArray(arg0));
public void AppendFormat(IFormatProvider? provider, string format, object? arg0) => AppendFormatHelper(provider, format, ParamsArray.Create(arg0));

public void AppendFormat(IFormatProvider? provider, string format, object? arg0, object? arg1) => AppendFormatHelper(provider, format, new ParamsArray(arg0, arg1));
public void AppendFormat(IFormatProvider? provider, string format, object? arg0, object? arg1) => AppendFormatHelper(provider, format, ParamsArray.Create(arg0, arg1));

public void AppendFormat(IFormatProvider? provider, string format, object? arg0, object? arg1, object? arg2) => AppendFormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
public void AppendFormat(IFormatProvider? provider, string format, object? arg0, object? arg1, object? arg2) => AppendFormatHelper(provider, format, ParamsArray.Create(arg0, arg1, arg2));

public void AppendFormat(IFormatProvider? provider, string format, params object?[] args)
{
Expand All @@ -40,7 +40,7 @@ public void AppendFormat(IFormatProvider? provider, string format, params object
throw new ArgumentNullException(paramName);
}

AppendFormatHelper(provider, format, new ParamsArray(args));
AppendFormatHelper(provider, format, ParamsArray.Create(args));
}

internal void AppendSpanFormattable<T>(T value, string? format, IFormatProvider? provider) where T : ISpanFormattable
Expand All @@ -57,7 +57,7 @@ internal void AppendSpanFormattable<T>(T value, string? format, IFormatProvider?

// Copied from StringBuilder, can't be done via generic extension
// as ValueStringBuilder is a ref struct and cannot be used in a generic.
internal void AppendFormatHelper(IFormatProvider? provider, string format, ParamsArray args)
internal void AppendFormatHelper<TArr>(IFormatProvider? provider, string format, ParamsArray<TArr> args) where TArr : IValueArray<object?>
{
// Undocumented exclusive limits on the range for Argument Hole Index and Argument Hole Alignment.
const int IndexLimit = 1000000; // Note: 0 <= ArgIndex < IndexLimit
Expand Down

0 comments on commit b85d94a

Please sign in to comment.