Skip to content

Commit ffe108a

Browse files
committed
feat: Add culture for Insert and Append
1 parent 74d3957 commit ffe108a

File tree

4 files changed

+73
-9
lines changed

4 files changed

+73
-9
lines changed

src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Globalization;
12
using System.Runtime.CompilerServices;
23
using System.Runtime.InteropServices;
34
using System.Text;
@@ -52,10 +53,11 @@ public unsafe void Append(bool value)
5253
/// <param name="format">Optional formatter. If not provided the default of the given instance is taken.</param>
5354
/// <param name="bufferSize">Size of the buffer allocated. If you have a custom type that implements <see cref="ISpanFormattable"/> that
5455
/// requires more space than the default (36 characters), adjust the value.</param>
56+
/// <param name="formatProvider">Optional format provider. If null <see cref="CultureInfo.InvariantCulture"/> is used.</param>
5557
/// <typeparam name="T">Any <see cref="ISpanFormattable"/>.</typeparam>
5658
[MethodImpl(MethodImplOptions.AggressiveInlining)]
57-
public void Append<T>(T value, scoped ReadOnlySpan<char> format = default, int bufferSize = 36)
58-
where T : ISpanFormattable => AppendSpanFormattable(value, format, bufferSize);
59+
public void Append<T>(T value, scoped ReadOnlySpan<char> format = default, int bufferSize = 36, IFormatProvider? formatProvider = null)
60+
where T : ISpanFormattable => AppendSpanFormattable(value, format, bufferSize, formatProvider);
5961

6062
/// <summary>
6163
/// Appends a string.
@@ -181,7 +183,7 @@ public Span<char> AppendSpan(int length)
181183
}
182184

183185
[MethodImpl(MethodImplOptions.AggressiveInlining)]
184-
private void AppendSpanFormattable<T>(T value, scoped ReadOnlySpan<char> format = default, int bufferSize = 36)
186+
private void AppendSpanFormattable<T>(T value, scoped ReadOnlySpan<char> format = default, int bufferSize = 36, IFormatProvider? formatProvider = null)
185187
where T : ISpanFormattable
186188
{
187189
var newSize = bufferSize + bufferPosition;
@@ -190,7 +192,7 @@ private void AppendSpanFormattable<T>(T value, scoped ReadOnlySpan<char> format
190192
EnsureCapacity(newSize);
191193
}
192194

193-
if (!value.TryFormat(buffer[bufferPosition..], out var written, format, null))
195+
if (!value.TryFormat(buffer[bufferPosition..], out var written, format, formatProvider ?? CultureInfo.InvariantCulture))
194196
{
195197
throw new InvalidOperationException($"Could not insert {value} into given buffer. Is the buffer (size: {bufferSize}) large enough?");
196198
}

src/LinkDotNet.StringBuilder/ValueStringBuilder.Insert.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Runtime.CompilerServices;
1+
using System.Globalization;
2+
using System.Runtime.CompilerServices;
23
using System.Text;
34

45
namespace LinkDotNet.StringBuilder;
@@ -43,10 +44,11 @@ public void Insert(int index, Rune value)
4344
/// <param name="value">Formattable span to insert into this builder.</param>
4445
/// <param name="format">Optional formatter. If not provided the default of the given instance is taken.</param>
4546
/// <param name="bufferSize">Size of the buffer allocated on the stack.</param>
47+
/// <param name="formatProvider">Optional format provider. If null <see cref="CultureInfo.InvariantCulture"/> is used.</param>
4648
/// <typeparam name="T">Any <see cref="ISpanFormattable"/>.</typeparam>
4749
[MethodImpl(MethodImplOptions.AggressiveInlining)]
48-
public void Insert<T>(int index, T value, scoped ReadOnlySpan<char> format = default, int bufferSize = 36)
49-
where T : ISpanFormattable => InsertSpanFormattable(index, value, format, bufferSize);
50+
public void Insert<T>(int index, T value, scoped ReadOnlySpan<char> format = default, int bufferSize = 36, IFormatProvider? formatProvider = null)
51+
where T : ISpanFormattable => InsertSpanFormattable(index, value, format, bufferSize, formatProvider);
5052

5153
/// <summary>
5254
/// Appends the string representation of the boolean to the builder.
@@ -89,7 +91,7 @@ public void Insert(int index, scoped ReadOnlySpan<char> value)
8991
}
9092

9193
[MethodImpl(MethodImplOptions.AggressiveInlining)]
92-
private void InsertSpanFormattable<T>(int index, T value, scoped ReadOnlySpan<char> format, int bufferSize)
94+
private void InsertSpanFormattable<T>(int index, T value, scoped ReadOnlySpan<char> format, int bufferSize, IFormatProvider? formatProvider = null)
9395
where T : ISpanFormattable
9496
{
9597
if (index < 0)
@@ -103,7 +105,7 @@ private void InsertSpanFormattable<T>(int index, T value, scoped ReadOnlySpan<ch
103105
}
104106

105107
Span<char> tempBuffer = stackalloc char[bufferSize];
106-
if (value.TryFormat(tempBuffer, out var written, format, null))
108+
if (value.TryFormat(tempBuffer, out var written, format, formatProvider ?? CultureInfo.InvariantCulture))
107109
{
108110
var newLength = bufferPosition + written;
109111
if (newLength > buffer.Length)

tests/LinkDotNet.StringBuilder.UnitTests/ValueStringBuilder.Append.Tests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Globalization;
2+
13
namespace LinkDotNet.StringBuilder.UnitTests;
24

35
public class ValueStringBuilderAppendTests
@@ -87,6 +89,34 @@ public void ShouldAppendSpanFormattable()
8789
builder.ToString().ShouldBe("2.2");
8890
}
8991

92+
[Fact]
93+
public void ShouldAppendSpanFormattableWithGivenCulture()
94+
{
95+
using var builder = new ValueStringBuilder();
96+
97+
builder.Append(1.2m, formatProvider: CultureInfo.GetCultureInfo("de-DE"));
98+
99+
builder.ToString().ShouldBe("1,2");
100+
}
101+
102+
[Fact]
103+
public void ShouldAppendSpanFormattableWithInvariantCultureWhenFormatProviderIsNull()
104+
{
105+
using var builder = new ValueStringBuilder();
106+
var originalCulture = CultureInfo.CurrentCulture;
107+
try
108+
{
109+
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("de-DE");
110+
builder.Append(1.2m, formatProvider: null);
111+
}
112+
finally
113+
{
114+
CultureInfo.CurrentCulture = originalCulture;
115+
}
116+
117+
builder.ToString().ShouldBe("1.2");
118+
}
119+
90120
[Fact]
91121
public void ShouldAppendMultipleChars()
92122
{

tests/LinkDotNet.StringBuilder.UnitTests/ValueStringBuilder.Insert.Tests.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using System.Globalization;
2+
13
namespace LinkDotNet.StringBuilder.UnitTests;
24

35
public class ValueStringBuilderInsertTests
@@ -33,6 +35,34 @@ public void ShouldAppendSpanFormattable()
3335
builder.ToString().ShouldBe("2.2");
3436
}
3537

38+
[Fact]
39+
public void ShouldInsertSpanFormattableWithGivenCulture()
40+
{
41+
using var builder = new ValueStringBuilder();
42+
43+
builder.Insert(0, 1.2m, formatProvider: CultureInfo.GetCultureInfo("de-DE"));
44+
45+
builder.ToString().ShouldBe("1,2");
46+
}
47+
48+
[Fact]
49+
public void ShouldInsertSpanFormattableWithInvariantCultureWhenFormatProviderIsNull()
50+
{
51+
using var builder = new ValueStringBuilder();
52+
var originalCulture = CultureInfo.CurrentCulture;
53+
try
54+
{
55+
CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo("de-DE");
56+
builder.Insert(0, 1.2m, formatProvider: null);
57+
}
58+
finally
59+
{
60+
CultureInfo.CurrentCulture = originalCulture;
61+
}
62+
63+
builder.ToString().ShouldBe("1.2");
64+
}
65+
3666
[Fact]
3767
public void ShouldThrowWhenIndexIsNegative()
3868
{

0 commit comments

Comments
 (0)