From 55681c35e49cd537c5047849ee7ef123a62261a1 Mon Sep 17 00:00:00 2001 From: Joyless <65855333+Joy-less@users.noreply.github.com> Date: Sat, 11 Jan 2025 01:49:15 +0000 Subject: [PATCH 1/6] Add Append(Rune) --- .../ValueStringBuilder.Append.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs index 0bbc6bb..9f97141 100644 --- a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs +++ b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs @@ -1,5 +1,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; namespace LinkDotNet.StringBuilder; @@ -117,6 +118,19 @@ public void Append(char value) bufferPosition++; } + /// + /// Appends a single rune to the string builder. + /// + /// Rune to add. + public void Append(Rune value) + { + Span valueChars = stackalloc char[2]; + int valueCharsWritten = value.EncodeToUtf16(valueChars); + ReadOnlySpan valueCharsReadOnly = valueChars[..valueCharsWritten]; + + Append(valueCharsReadOnly); + } + /// /// Adds the default new line separator. /// From ec686ed78052d0b95883481931364edb7bef18d8 Mon Sep 17 00:00:00 2001 From: Joyless <65855333+Joy-less@users.noreply.github.com> Date: Sat, 11 Jan 2025 01:49:47 +0000 Subject: [PATCH 2/6] Add AppendJoin(Rune, IEnumerable) --- .../ValueStringBuilder.AppendJoin.cs | 60 +++++++++++++++---- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/src/LinkDotNet.StringBuilder/ValueStringBuilder.AppendJoin.cs b/src/LinkDotNet.StringBuilder/ValueStringBuilder.AppendJoin.cs index a6241c5..b7bdb76 100644 --- a/src/LinkDotNet.StringBuilder/ValueStringBuilder.AppendJoin.cs +++ b/src/LinkDotNet.StringBuilder/ValueStringBuilder.AppendJoin.cs @@ -1,4 +1,5 @@ using System.Runtime.CompilerServices; +using System.Text; namespace LinkDotNet.StringBuilder; @@ -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. /// /// String used as separator between the entries. - /// Array of strings, which will be concatenated. + /// Enumerable of strings to be concatenated. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AppendJoin(ReadOnlySpan separator, IEnumerable values) => AppendJoinInternalString(separator, values); @@ -17,17 +18,26 @@ public void AppendJoin(ReadOnlySpan separator, IEnumerable values /// Concatenates and appends all values with the given separator between each entry at the end of the string. /// /// Character used as separator between the entries. - /// Array of strings, which will be concatenated. + /// Enumerable of strings to be concatenated. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AppendJoin(char separator, IEnumerable values) => AppendJoinInternalChar(separator, values); + /// + /// Concatenates and appends all values with the given separator between each entry at the end of the string. + /// + /// Rune used as separator between the entries. + /// Enumerable of strings to be concatenated. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AppendJoin(Rune separator, IEnumerable values) + => AppendJoinInternalRune(separator, values); + /// /// Concatenates and appends all values with the given separator between each entry at the end of the string. /// /// String used as separator between the entries. - /// Array of strings, which will be concatenated. - /// Type of the given array. + /// Enumerable to be concatenated. + /// Type of the given enumerable. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AppendJoin(ReadOnlySpan separator, IEnumerable values) => AppendJoinInternalString(separator, values); @@ -36,12 +46,22 @@ public void AppendJoin(ReadOnlySpan separator, IEnumerable values) /// Concatenates and appends all values with the given separator between each entry at the end of the string. /// /// Character used as separator between the entries. - /// Array of strings, which will be concatenated. - /// Type of the given array. + /// Enumerable to be concatenated. + /// Type of the given enumerable. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AppendJoin(char separator, IEnumerable values) => AppendJoinInternalChar(separator, values); + /// + /// Concatenates and appends all values with the given separator between each entry at the end of the string. + /// + /// Rune used as separator between the entries. + /// Enumerable to be concatenated. + /// Type of the given enumerable. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AppendJoin(Rune separator, IEnumerable values) + => AppendJoinInternalRune(separator, values); + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AppendJoinInternalString(ReadOnlySpan separator, IEnumerable values) { @@ -55,10 +75,7 @@ private void AppendJoinInternalString(ReadOnlySpan separator, IEnumerab } var current = enumerator.Current; - if (current is not null) - { - AppendInternal(current); - } + AppendInternal(current); while (enumerator.MoveNext()) { @@ -91,6 +108,29 @@ private void AppendJoinInternalChar(char separator, IEnumerable values) } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void AppendJoinInternalRune(Rune separator, IEnumerable 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 value) { From 3a14027c2246e93e3d24c718fb509da546bed394 Mon Sep 17 00:00:00 2001 From: Joyless <65855333+Joy-less@users.noreply.github.com> Date: Sat, 11 Jan 2025 01:51:56 +0000 Subject: [PATCH 3/6] Avoid string allocation in AppendLine(ReadOnlySpan) --- src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs index 9f97141..b21c1c3 100644 --- a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs +++ b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs @@ -143,11 +143,12 @@ public void AppendLine() /// /// Does the same as but adds a newline at the end. /// - /// String, which will be added to this builder. + /// String to be added to this builder. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AppendLine(scoped ReadOnlySpan str) { - Append(string.Concat(str, Environment.NewLine)); + Append(str); + Append(Environment.NewLine); } /// From 136808cd481bd425e01598534cac806ec46afb7c Mon Sep 17 00:00:00 2001 From: Joyless <65855333+Joy-less@users.noreply.github.com> Date: Sat, 11 Jan 2025 01:58:11 +0000 Subject: [PATCH 4/6] Add missing AggressiveInlining attribute --- src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs index b21c1c3..c3259e0 100644 --- a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs +++ b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs @@ -122,6 +122,7 @@ public void Append(char value) /// Appends a single rune to the string builder. /// /// Rune to add. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Append(Rune value) { Span valueChars = stackalloc char[2]; From a0a918e4f98c0f4a1b7066d840621359590c8552 Mon Sep 17 00:00:00 2001 From: Joyless <65855333+Joy-less@users.noreply.github.com> Date: Sat, 11 Jan 2025 15:06:48 +0000 Subject: [PATCH 5/6] Update CHANGELOG.md --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 61f24ea..bc39f22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,14 @@ This is the `v2` release of the **ValueStringBuilder**. There aren't any noticea ### 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). +## [1.23.0] - 2025-01-11 + +- Added `Append(Rune)` overload +- Added `AppendJoin(Rune, IEnumerable)` overload +- Added `AppendJoin(Rune, IEnumerable)` overload +- Optimised `AppendLine(scoped ReadOnlySpan)` by avoiding allocating a new string +- Removed erroneous null check in `AppendJoin(ReadOnlySpan, IEnumerable)` + ## [1.22.0] - 2024-12-18 ### Added From 83662086913864ae2cd465466962fb8b7c5e21b9 Mon Sep 17 00:00:00 2001 From: Joyless <65855333+Joy-less@users.noreply.github.com> Date: Sat, 11 Jan 2025 16:01:24 +0000 Subject: [PATCH 6/6] Restructure CHANGELOG.md changes --- CHANGELOG.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc39f22..03005d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,17 +8,19 @@ 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)` overload +- Added `AppendJoin(Rune, IEnumerable)` 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). - -## [1.23.0] - 2025-01-11 -- Added `Append(Rune)` overload -- Added `AppendJoin(Rune, IEnumerable)` overload -- Added `AppendJoin(Rune, IEnumerable)` overload +- 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)` by avoiding allocating a new string - Removed erroneous null check in `AppendJoin(ReadOnlySpan, IEnumerable)`