Skip to content

Commit b68ab4d

Browse files
committed
feat: add PadLeft and PadRight methods for padding strings
1 parent 19acbe7 commit b68ab4d

File tree

3 files changed

+156
-0
lines changed

3 files changed

+156
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ All notable changes to **ValueStringBuilder** will be documented in this file. T
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- Added `PadLeft(ReadOnlySpan<char>, int, char)` and `PadRight(ReadOnlySpan<char>, int, char)` methods to append padded strings without allocating additional memory (by [@SMAH1](https://github.com/SMAH1) in #260)
12+
913
## [3.0.0] - 2025-10-30
1014

1115
This is the `v3` major release. The API is almost the same as in `v2` - there is only a slight change in the `Concat` static helper method to reflect a less-boxed API.

src/LinkDotNet.StringBuilder/ValueStringBuilder.Pad.cs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,54 @@ public void PadRight(int totalWidth, char paddingChar)
4343
buffer[bufferPosition..totalWidth].Fill(paddingChar);
4444
bufferPosition = totalWidth;
4545
}
46+
47+
/// <summary>
48+
/// Appends the source string padded on the left with the given character to reach the specified total width.
49+
/// </summary>
50+
/// <param name="source">The source string to pad and append.</param>
51+
/// <param name="totalWidth">Total width of the padded string.</param>
52+
/// <param name="paddingChar">Character to pad the string with. Defaults to space.</param>
53+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
54+
public void PadLeft(ReadOnlySpan<char> source, int totalWidth, char paddingChar = ' ')
55+
{
56+
if (totalWidth <= source.Length)
57+
{
58+
Append(source);
59+
return;
60+
}
61+
62+
var padding = totalWidth - source.Length;
63+
EnsureCapacity(bufferPosition + totalWidth);
64+
65+
buffer.Slice(bufferPosition, padding).Fill(paddingChar);
66+
bufferPosition += padding;
67+
68+
source.CopyTo(buffer[bufferPosition..]);
69+
bufferPosition += source.Length;
70+
}
71+
72+
/// <summary>
73+
/// Appends the source string padded on the right with the given character to reach the specified total width.
74+
/// </summary>
75+
/// <param name="source">The source string to pad and append.</param>
76+
/// <param name="totalWidth">Total width of the padded string.</param>
77+
/// <param name="paddingChar">Character to pad the string with. Defaults to space.</param>
78+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
79+
public void PadRight(ReadOnlySpan<char> source, int totalWidth, char paddingChar = ' ')
80+
{
81+
if (totalWidth <= source.Length)
82+
{
83+
Append(source);
84+
return;
85+
}
86+
87+
var padding = totalWidth - source.Length;
88+
EnsureCapacity(bufferPosition + totalWidth);
89+
90+
source.CopyTo(buffer[bufferPosition..]);
91+
bufferPosition += source.Length;
92+
93+
buffer.Slice(bufferPosition, padding).Fill(paddingChar);
94+
bufferPosition += padding;
95+
}
4696
}

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

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,106 @@ public void GivenTotalWidthIsSmallerThanCurrentLength_WhenPadRight_ThenShouldNot
4141

4242
stringBuilder.ToString().ShouldBe("Hello");
4343
}
44+
45+
[Fact]
46+
public void ShouldPadLeftWithSource()
47+
{
48+
using var stringBuilder = new ValueStringBuilder();
49+
50+
stringBuilder.PadLeft("Hello".AsSpan(), 10, ' ');
51+
52+
stringBuilder.ToString().ShouldBe(" Hello");
53+
}
54+
55+
[Fact]
56+
public void ShouldPadRightWithSource()
57+
{
58+
using var stringBuilder = new ValueStringBuilder();
59+
60+
stringBuilder.PadRight("Hello".AsSpan(), 10, ' ');
61+
62+
stringBuilder.ToString().ShouldBe("Hello ");
63+
}
64+
65+
[Fact]
66+
public void ShouldPadLeftWithSourceAndCustomChar()
67+
{
68+
using var stringBuilder = new ValueStringBuilder();
69+
70+
stringBuilder.PadLeft("42".AsSpan(), 5, '0');
71+
72+
stringBuilder.ToString().ShouldBe("00042");
73+
}
74+
75+
[Fact]
76+
public void ShouldPadRightWithSourceAndCustomChar()
77+
{
78+
using var stringBuilder = new ValueStringBuilder();
79+
80+
stringBuilder.PadRight("Test".AsSpan(), 8, '*');
81+
82+
stringBuilder.ToString().ShouldBe("Test****");
83+
}
84+
85+
[Fact]
86+
public void GivenTotalWidthIsSmallerThanSourceLength_WhenPadLeftWithSource_ThenShouldAppendSourceOnly()
87+
{
88+
using var stringBuilder = new ValueStringBuilder();
89+
90+
stringBuilder.PadLeft("Hello".AsSpan(), 3, ' ');
91+
92+
stringBuilder.ToString().ShouldBe("Hello");
93+
}
94+
95+
[Fact]
96+
public void GivenTotalWidthIsSmallerThanSourceLength_WhenPadRightWithSource_ThenShouldAppendSourceOnly()
97+
{
98+
using var stringBuilder = new ValueStringBuilder();
99+
100+
stringBuilder.PadRight("Hello".AsSpan(), 3, ' ');
101+
102+
stringBuilder.ToString().ShouldBe("Hello");
103+
}
104+
105+
[Fact]
106+
public void ShouldPadLeftWithSourceMultipleTimes()
107+
{
108+
using var stringBuilder = new ValueStringBuilder();
109+
110+
stringBuilder.PadLeft("A".AsSpan(), 3, '-');
111+
stringBuilder.PadLeft("B".AsSpan(), 3, '-');
112+
113+
stringBuilder.ToString().ShouldBe("--A--B");
114+
}
115+
116+
[Fact]
117+
public void ShouldPadRightWithSourceMultipleTimes()
118+
{
119+
using var stringBuilder = new ValueStringBuilder();
120+
121+
stringBuilder.PadRight("A".AsSpan(), 3, '-');
122+
stringBuilder.PadRight("B".AsSpan(), 3, '-');
123+
124+
stringBuilder.ToString().ShouldBe("A--B--");
125+
}
126+
127+
[Fact]
128+
public void ShouldPadLeftWithSourceAndExistingContent()
129+
{
130+
using var stringBuilder = new ValueStringBuilder("Start ");
131+
132+
stringBuilder.PadLeft("End".AsSpan(), 10, '.');
133+
134+
stringBuilder.ToString().ShouldBe("Start .......End");
135+
}
136+
137+
[Fact]
138+
public void ShouldPadRightWithSourceAndExistingContent()
139+
{
140+
using var stringBuilder = new ValueStringBuilder("Start ");
141+
142+
stringBuilder.PadRight("End".AsSpan(), 10, '.');
143+
144+
stringBuilder.ToString().ShouldBe("Start End.......");
145+
}
44146
}

0 commit comments

Comments
 (0)