Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,21 @@ All notable changes to **ValueStringBuilder** will be documented in this file. T

This is the `v2` release of the **ValueStringBuilder**. There aren't any noticeable changes. Only old framework versions were removed to make further development easier.

### Added

- Added `Append(Rune)` overload
- Added `AppendJoin(Rune, IEnumerable<string?>)` overload
- Added `AppendJoin<T>(Rune, IEnumerable<T>)` overload

### Removed

- Support for `net6.0` and `net7.0` was removed.

### Changed

- Added `OverloadResolutionPriority` for `Span` overload for the ctor to keep the current behavior. Reported by [@nsentinel])(https://github.com/nsentinel) in [#210](https://github.com/linkdotnet/StringBuilder/issues/210).
- Optimised `AppendLine(scoped ReadOnlySpan<char>)` by avoiding allocating a new string
- Removed erroneous null check in `AppendJoin<T>(ReadOnlySpan<char>, IEnumerable<T>)`

## [1.22.0] - 2024-12-18

Expand Down
20 changes: 18 additions & 2 deletions src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

namespace LinkDotNet.StringBuilder;

Expand Down Expand Up @@ -117,6 +118,20 @@ public void Append(char value)
bufferPosition++;
}

/// <summary>
/// Appends a single rune to the string builder.
/// </summary>
/// <param name="value">Rune to add.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(Rune value)
{
Span<char> valueChars = stackalloc char[2];
int valueCharsWritten = value.EncodeToUtf16(valueChars);
ReadOnlySpan<char> valueCharsReadOnly = valueChars[..valueCharsWritten];

Append(valueCharsReadOnly);
}

/// <summary>
/// Adds the default new line separator.
/// </summary>
Expand All @@ -129,11 +144,12 @@ public void AppendLine()
/// <summary>
/// Does the same as <see cref="Append(char)"/> but adds a newline at the end.
/// </summary>
/// <param name="str">String, which will be added to this builder.</param>
/// <param name="str">String to be added to this builder.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendLine(scoped ReadOnlySpan<char> str)
{
Append(string.Concat(str, Environment.NewLine));
Append(str);
Append(Environment.NewLine);
}

/// <summary>
Expand Down
60 changes: 50 additions & 10 deletions src/LinkDotNet.StringBuilder/ValueStringBuilder.AppendJoin.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Runtime.CompilerServices;
using System.Text;

namespace LinkDotNet.StringBuilder;

Expand All @@ -8,7 +9,7 @@ public ref partial struct ValueStringBuilder
/// Concatenates and appends all values with the given separator between each entry at the end of the string.
/// </summary>
/// <param name="separator">String used as separator between the entries.</param>
/// <param name="values">Array of strings, which will be concatenated.</param>
/// <param name="values">Enumerable of strings to be concatenated.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendJoin(ReadOnlySpan<char> separator, IEnumerable<string?> values)
=> AppendJoinInternalString(separator, values);
Expand All @@ -17,17 +18,26 @@ public void AppendJoin(ReadOnlySpan<char> separator, IEnumerable<string?> values
/// Concatenates and appends all values with the given separator between each entry at the end of the string.
/// </summary>
/// <param name="separator">Character used as separator between the entries.</param>
/// <param name="values">Array of strings, which will be concatenated.</param>
/// <param name="values">Enumerable of strings to be concatenated.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendJoin(char separator, IEnumerable<string?> values)
=> AppendJoinInternalChar(separator, values);

/// <summary>
/// Concatenates and appends all values with the given separator between each entry at the end of the string.
/// </summary>
/// <param name="separator">Rune used as separator between the entries.</param>
/// <param name="values">Enumerable of strings to be concatenated.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendJoin(Rune separator, IEnumerable<string?> values)
=> AppendJoinInternalRune(separator, values);

/// <summary>
/// Concatenates and appends all values with the given separator between each entry at the end of the string.
/// </summary>
/// <param name="separator">String used as separator between the entries.</param>
/// <param name="values">Array of strings, which will be concatenated.</param>
/// <typeparam name="T">Type of the given array.</typeparam>
/// <param name="values">Enumerable to be concatenated.</param>
/// <typeparam name="T">Type of the given enumerable.</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendJoin<T>(ReadOnlySpan<char> separator, IEnumerable<T> values)
=> AppendJoinInternalString(separator, values);
Expand All @@ -36,12 +46,22 @@ public void AppendJoin<T>(ReadOnlySpan<char> separator, IEnumerable<T> values)
/// Concatenates and appends all values with the given separator between each entry at the end of the string.
/// </summary>
/// <param name="separator">Character used as separator between the entries.</param>
/// <param name="values">Array of strings, which will be concatenated.</param>
/// <typeparam name="T">Type of the given array.</typeparam>
/// <param name="values">Enumerable to be concatenated.</param>
/// <typeparam name="T">Type of the given enumerable.</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendJoin<T>(char separator, IEnumerable<T> values)
=> AppendJoinInternalChar(separator, values);

/// <summary>
/// Concatenates and appends all values with the given separator between each entry at the end of the string.
/// </summary>
/// <param name="separator">Rune used as separator between the entries.</param>
/// <param name="values">Enumerable to be concatenated.</param>
/// <typeparam name="T">Type of the given enumerable.</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendJoin<T>(Rune separator, IEnumerable<T> values)
=> AppendJoinInternalRune(separator, values);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AppendJoinInternalString<T>(ReadOnlySpan<char> separator, IEnumerable<T> values)
{
Expand All @@ -55,10 +75,7 @@ private void AppendJoinInternalString<T>(ReadOnlySpan<char> separator, IEnumerab
}

var current = enumerator.Current;
if (current is not null)
{
AppendInternal(current);
}
AppendInternal(current);

while (enumerator.MoveNext())
{
Expand Down Expand Up @@ -91,6 +108,29 @@ private void AppendJoinInternalChar<T>(char separator, IEnumerable<T> values)
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AppendJoinInternalRune<T>(Rune separator, IEnumerable<T> values)
{
ArgumentNullException.ThrowIfNull(values);

using var enumerator = values.GetEnumerator();

if (!enumerator.MoveNext())
{
return;
}

var current = enumerator.Current;
AppendInternal(current);

while (enumerator.MoveNext())
{
Append(separator);
current = enumerator.Current;
AppendInternal(current);
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AppendInternal<T>(T value)
{
Expand Down
Loading