diff --git a/CHANGELOG.md b/CHANGELOG.md index 3017007..a8d17cd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ All notable changes to **ValueStringBuilder** will be documented in this file. T - Added `TrimPrefix(ReadOnlySpan, StringComparison)` (by yours truly (@Joy-less) in #226) - Added `TrimSuffix(ReadOnlySpan, StringComparison)` (also by yours truly (@Joy-less) in #226) +- Added `Insert(int, char)` overload (by yours truly (@Joy-less) in #225) +- Added `Insert(int, Rune)` overload (again by yours truly (@Joy-less) in #225) +- Added `Replace(Rune, Rune)` overload (see yours truly (@Joy-less) in #225) +- Improved `Replace(scoped ReadOnlySpan, scoped ReadOnlySpan, int, int)` fallback (achieved by yours truly (@Joy-less) in #225) ## [2.1.0] - 2025-01-14 diff --git a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs index d126ea8..716eef6 100644 --- a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs +++ b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Append.cs @@ -126,10 +126,10 @@ public void Append(char value) public void Append(Rune value) { Span valueChars = stackalloc char[2]; - int valueCharsWritten = value.EncodeToUtf16(valueChars); - ReadOnlySpan valueCharsReadOnly = valueChars[..valueCharsWritten]; + var valueCharsWritten = value.EncodeToUtf16(valueChars); + ReadOnlySpan valueCharsSlice = valueChars[..valueCharsWritten]; - Append(valueCharsReadOnly); + Append(valueCharsSlice); } /// diff --git a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Insert.cs b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Insert.cs index a6cc015..d3f9a30 100644 --- a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Insert.cs +++ b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Insert.cs @@ -1,4 +1,5 @@ using System.Runtime.CompilerServices; +using System.Text; namespace LinkDotNet.StringBuilder; @@ -12,6 +13,29 @@ public ref partial struct ValueStringBuilder [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Insert(int index, bool value) => Insert(index, value.ToString()); + /// + /// Insert the string representation of the character to the builder at the given index. + /// + /// Index where should be inserted. + /// Character to insert into this builder. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Insert(int index, char value) => Insert(index, [value]); + + /// + /// Insert the string representation of the rune to the builder at the given index. + /// + /// Index where should be inserted. + /// Rune to insert into this builder. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Insert(int index, Rune value) + { + Span valueChars = stackalloc char[2]; + var valueCharsWritten = value.EncodeToUtf16(valueChars); + ReadOnlySpan valueCharsSlice = valueChars[..valueCharsWritten]; + + Insert(index, valueCharsSlice); + } + /// /// Insert the string representation of the char to the builder at the given index. /// diff --git a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Replace.cs b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Replace.cs index 0994f28..d3284a0 100644 --- a/src/LinkDotNet.StringBuilder/ValueStringBuilder.Replace.cs +++ b/src/LinkDotNet.StringBuilder/ValueStringBuilder.Replace.cs @@ -13,17 +13,6 @@ public ref partial struct ValueStringBuilder [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Replace(char oldValue, char newValue) => Replace(oldValue, newValue, 0, Length); - /// - /// Replaces all instances of one rune with another in this builder. - /// - /// The rune to replace. - /// The rune to replace with. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Replace(Rune oldValue, Rune newValue) - { - Replace(oldValue, newValue, 0, Length); - } - /// /// Replaces all instances of one character with another in this builder. /// @@ -34,15 +23,8 @@ public void Replace(Rune oldValue, Rune newValue) [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Replace(char oldValue, char newValue, int startIndex, int count) { - if (startIndex < 0) - { - throw new ArgumentOutOfRangeException(nameof(startIndex), "Start index can't be smaller than 0."); - } - - if (count > bufferPosition) - { - throw new ArgumentOutOfRangeException(nameof(count), $"Count: {count} is bigger than the current size {bufferPosition}."); - } + ArgumentOutOfRangeException.ThrowIfLessThan(startIndex, 0); + ArgumentOutOfRangeException.ThrowIfGreaterThan(startIndex + count, Length); for (var i = startIndex; i < startIndex + count; i++) { @@ -53,6 +35,14 @@ public readonly void Replace(char oldValue, char newValue, int startIndex, int c } } + /// + /// Replaces all instances of one rune with another in this builder. + /// + /// The rune to replace. + /// The rune to replace with. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Replace(Rune oldValue, Rune newValue) => Replace(oldValue, newValue, 0, Length); + /// /// Replaces all instances of one rune with another in this builder. /// @@ -64,14 +54,14 @@ public readonly void Replace(char oldValue, char newValue, int startIndex, int c public void Replace(Rune oldValue, Rune newValue, int startIndex, int count) { Span oldValueChars = stackalloc char[2]; - int oldValueCharsWritten = oldValue.EncodeToUtf16(oldValueChars); - ReadOnlySpan oldValueCharsReadOnly = oldValueChars[..oldValueCharsWritten]; + var oldValueCharsWritten = oldValue.EncodeToUtf16(oldValueChars); + ReadOnlySpan oldValueCharsSlice = oldValueChars[..oldValueCharsWritten]; Span newValueChars = stackalloc char[2]; - int newValueCharsWritten = newValue.EncodeToUtf16(newValueChars); - ReadOnlySpan newValueCharsReadOnly = newValueChars[..newValueCharsWritten]; + var newValueCharsWritten = newValue.EncodeToUtf16(newValueChars); + ReadOnlySpan newValueCharsSlice = newValueChars[..newValueCharsWritten]; - Replace(oldValueCharsReadOnly, newValueCharsReadOnly, startIndex, count); + Replace(oldValueCharsSlice, newValueCharsSlice, startIndex, count); } /// @@ -99,6 +89,9 @@ public void Replace(scoped ReadOnlySpan oldValue, scoped ReadOnlySpan oldValue, scoped ReadOnlySpan newValue, int startIndex, int count) { + ArgumentOutOfRangeException.ThrowIfLessThan(startIndex, 0); + ArgumentOutOfRangeException.ThrowIfGreaterThan(startIndex + count, Length); + var length = startIndex + count; var slice = buffer[startIndex..length]; @@ -188,7 +181,7 @@ public void ReplaceGeneric(ReadOnlySpan oldValue, T newValue, int start } else { - Replace(oldValue, (ReadOnlySpan)newValue?.ToString(), startIndex, count); + Replace(oldValue, (newValue?.ToString() ?? string.Empty).AsSpan(), startIndex, count); } } } \ No newline at end of file