Skip to content

Commit

Permalink
feat: More overloads for AppendFormat
Browse files Browse the repository at this point in the history
  • Loading branch information
linkdotnet committed Jan 9, 2023
1 parent 9c467d5 commit 978f162
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ All notable changes to **ValueStringBuilder** will be documented in this file. T

## [Unreleased]

### Added

- Two more overloads for `AppendFormat` for up to 5 generic arguments

## [1.11.5] - 2023-01-09

### Added
Expand Down
162 changes: 162 additions & 0 deletions src/LinkDotNet.StringBuilder/ValueStringBuilder.AppendFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,168 @@ public void AppendFormat<T1, T2, T3>(
}
}

/// <summary>
/// Appends the format string to the given <see cref="ValueStringBuilder"/> instance.
/// </summary>
/// <param name="format">Format string.</param>
/// <param name="arg1">Argument for <c>{0}</c>.</param>
/// <param name="arg2">Argument for <c>{1}</c>.</param>
/// <param name="arg3">Argument for <c>{2}</c>.</param>
/// <param name="arg4">Argument for <c>{3}</c>.</param>
/// <typeparam name="T1">Any type for <param name="arg1"></param>.</typeparam>
/// <typeparam name="T2">Any type for <param name="arg2"></param>.</typeparam>
/// <typeparam name="T3">Any type for <param name="arg3"></param>.</typeparam>
/// <typeparam name="T4">Any type for <param name="arg4"></param>.</typeparam>
/// <remarks>
/// The current version does not allow for a custom format.
/// So: <code>AppendFormat("{0:00}")</code> is not allowed and will result in an exception.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public void AppendFormat<T1, T2, T3, T4>(
[StringSyntax(StringSyntaxAttribute.CompositeFormat)] ReadOnlySpan<char> format,
T1 arg1,
T2 arg2,
T3 arg3,
T4 arg4)
{
var formatIndex = 0;
var start = 0;
while (formatIndex < format.Length)
{
var c = format[formatIndex];
if (c == '{')
{
var endIndex = format[(formatIndex + 1)..].IndexOf('}');
if (endIndex == -1)
{
Append(format);
return;
}

if (start != formatIndex)
{
Append(format[start..formatIndex]);
}

var placeholder = format.Slice(formatIndex, endIndex + 2);

var index = GetValidArgumentIndex(placeholder, 3);

switch (index)
{
case 0:
AppendInternal(arg1);
break;
case 1:
AppendInternal(arg2);
break;
case 2:
AppendInternal(arg3);
break;
case 3:
AppendInternal(arg4);
break;
}

formatIndex += endIndex + 2;
start = formatIndex;
}
else
{
formatIndex++;
}
}

if (start != formatIndex)
{
Append(format[start..formatIndex]);
}
}

/// <summary>
/// Appends the format string to the given <see cref="ValueStringBuilder"/> instance.
/// </summary>
/// <param name="format">Format string.</param>
/// <param name="arg1">Argument for <c>{0}</c>.</param>
/// <param name="arg2">Argument for <c>{1}</c>.</param>
/// <param name="arg3">Argument for <c>{2}</c>.</param>
/// <param name="arg4">Argument for <c>{3}</c>.</param>
/// <param name="arg5">Argument for <c>{4}</c>.</param>
/// <typeparam name="T1">Any type for <param name="arg1"></param>.</typeparam>
/// <typeparam name="T2">Any type for <param name="arg2"></param>.</typeparam>
/// <typeparam name="T3">Any type for <param name="arg3"></param>.</typeparam>
/// <typeparam name="T4">Any type for <param name="arg4"></param>.</typeparam>
/// <typeparam name="T5">Any type for <param name="arg5"></param>.</typeparam>
/// <remarks>
/// The current version does not allow for a custom format.
/// So: <code>AppendFormat("{0:00}")</code> is not allowed and will result in an exception.
/// </remarks>
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
public void AppendFormat<T1, T2, T3, T4, T5>(
[StringSyntax(StringSyntaxAttribute.CompositeFormat)] ReadOnlySpan<char> format,
T1 arg1,
T2 arg2,
T3 arg3,
T4 arg4,
T5 arg5)
{
var formatIndex = 0;
var start = 0;
while (formatIndex < format.Length)
{
var c = format[formatIndex];
if (c == '{')
{
var endIndex = format[(formatIndex + 1)..].IndexOf('}');
if (endIndex == -1)
{
Append(format);
return;
}

if (start != formatIndex)
{
Append(format[start..formatIndex]);
}

var placeholder = format.Slice(formatIndex, endIndex + 2);

var index = GetValidArgumentIndex(placeholder, 4);

switch (index)
{
case 0:
AppendInternal(arg1);
break;
case 1:
AppendInternal(arg2);
break;
case 2:
AppendInternal(arg3);
break;
case 3:
AppendInternal(arg4);
break;
case 4:
AppendInternal(arg5);
break;
}

formatIndex += endIndex + 2;
start = formatIndex;
}
else
{
formatIndex++;
}
}

if (start != formatIndex)
{
Append(format[start..formatIndex]);
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int GetValidArgumentIndex(ReadOnlySpan<char> placeholder, int allowedRange)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,32 @@ public void ShouldAppendFormatWithThreeArguments(string format, object arg1, obj

builder.ToString().Should().Be(expected);
}

[Theory]
[InlineData("Hello {0} {1} {2} {3}", 2, 3, 4, 5, "Hello 2 3 4 5")]
[InlineData("{0}{0}{1}{2}{3}", 2, 3, 3, 2, "22332")]
[InlineData("{0} World", "Hello", "", "", "", "Hello World")]
[InlineData("Hello World", "2", "", "", "", "Hello World")]
public void ShouldAppendFormatWithFourArguments(string format, object arg1, object arg2, object arg3, object arg4, string expected)
{
using var builder = new ValueStringBuilder();

builder.AppendFormat(format, arg1, arg2, arg3, arg4);

builder.ToString().Should().Be(expected);
}

[Theory]
[InlineData("Hello {0} {1} {2} {3} {4}", 2, 3, 4, 5, 3, "Hello 2 3 4 5 3")]
[InlineData("{0}{0}{1}{2}{3}{4}", 2, 3, 3, 2, 2, "223322")]
[InlineData("{0} World", "Hello", "", "", "", "", "Hello World")]
[InlineData("Hello World", "2", "", "", "", "", "Hello World")]
public void ShouldAppendFormatWithFiveArguments(string format, object arg1, object arg2, object arg3, object arg4, object arg5, string expected)
{
using var builder = new ValueStringBuilder();

builder.AppendFormat(format, arg1, arg2, arg3, arg4, arg5);

builder.ToString().Should().Be(expected);
}
}

0 comments on commit 978f162

Please sign in to comment.