Skip to content

Releases: linkdotnet/StringBuilder

v3.7.4

Choose a tag to compare

@linkdotnet linkdotnet released this 05 Oct 06:32
dacf319

Changed

  • Replace with a value of a different length searches the text once instead of twice.
  • AppendFormat searches for placeholders vectorized and reads single-digit indices like {0} without int.TryParse.
  • Append(bool) writes without pinning or bounds checks, Append(Rune) and Insert(int, Rune) skip the stack buffer for BMP runes, and string values in AppendJoin, AppendFormat and Concat skip the ISpanFormattable check.

v3.7.3

Choose a tag to compare

@linkdotnet linkdotnet released this 04 Oct 17:09
709cf6b

Fixed

  • AppendFormat with an unclosed { appended the whole format string a second time ("Hello {0} and {" gave "Hello 1Hello {0} and {"). Now only the not yet written rest is appended.
  • TrimPrefix and TrimSuffix with a culture-sensitive StringComparison removed value.Length characters instead of the actual match length, so ignorable or composed characters left the wrong content behind or made TrimSuffix throw.
  • Insert(int, ReadOnlySpan<char>) produced wrong content when the inserted span points into the builder itself (e.g. builder.Insert(0, builder.AsSpan(1))).
  • Interpolated strings passed no format to types that implement IFormattable but not ISpanFormattable, so $"{value:X}" called ToString() instead of ToString("X", null). Applies to ValueStringBuilder and FixedSizeValueStringBuilder.
  • AppendSpan with a negative length decreased Length before throwing. It now throws an ArgumentOutOfRangeException up front and leaves the builder untouched.
  • Insert<T> for ISpanFormattable values grows like Append<T> when the formatted value exceeds the default buffer size of 36 characters, instead of throwing an InvalidOperationException. A custom bufferSize still throws when it is too small.
  • Insert<T> stack-allocated the caller-provided bufferSize unbounded, so a large value crashed the process with a stack overflow. Sizes above 256 characters are now rented from the ArrayPool.

v3.7.2

Choose a tag to compare

@linkdotnet linkdotnet released this 04 Oct 09:21
eab9c83

Fixed

  • AsSpan(int startIndex, int length) and ToString(int startIndex, int length) throw an ArgumentOutOfRangeException when the requested range ends after Length, instead of returning characters from the unused part of the buffer.
  • The indexer throws an IndexOutOfRangeException for an index at or after Length, instead of giving access to the unused part of the buffer.
  • Append/AppendLine with an interpolated string could return the rented array to the ArrayPool twice when an interpolation hole threw after the buffer grew. Reported by @dhhoang in #324

v3.7.1

Choose a tag to compare

@linkdotnet linkdotnet released this 25 Sep 08:07
998e8e3

Added

  • ValueStringBuilder interpolated strings support alignment holes such as $"{value,10}" and $"{value,-10:F2}", like FixedSizeValueStringBuilder.
  • ValueStringBuilder.Append(char value, int repeatCount).

Changed

  • Any ISpanFormattable value type (not only the built-in well-known ones) is formatted without boxing in interpolated strings, AppendJoin, Concat, AppendFormat and ReplaceGeneric.
  • Append<T> for ISpanFormattable values first formats into the remaining buffer and only grows when the value does not fit, instead of reserving 36 characters up front.
  • AppendJoin with an IEnumerable<T> that is an array or List<T> no longer allocates an enumerator.
  • Growing the buffer is moved out of the inlined Append fast paths, which makes them smaller.
  • Append(char) does a single bounds check per character (about 40% faster in a tight loop).
  • AppendJoin and friends dispatch value types through a small inlinable helper instead of a 20-entry type table, which the JIT could not inline in deep call chains (AppendJoin over ints about 40% faster).

v3.7.0

Choose a tag to compare

@linkdotnet linkdotnet released this 19 Sep 19:46

Added

  • FixedSizeValueStringBuilder: a non-growing ref struct string builder backed by a caller-supplied buffer that never allocates on the heap. Appends are atomic and the first one that does not fit latches Overflowed, which ClearOverflow resets.
  • FixedSizeValueStringBuilder.MoveToValueStringBuilder: hands the buffer and its content over to a ValueStringBuilder which can grow beyond the fixed capacity. The move copies nothing and rents nothing, and consumes the source so both builders can never write into the same memory.

v3.6.1

Choose a tag to compare

@linkdotnet linkdotnet released this 12 Sep 12:22
7d3d25c

Changed

  • Removed some wrong [MethodImpl(MethodImplOptions.AggressiveInlining)] attributes that might made it worse.

v3.6.0

Choose a tag to compare

@linkdotnet linkdotnet released this 01 Sep 18:54
1935a64

Changed

  • Performance upgrades when growing

v3.5.0

Choose a tag to compare

@linkdotnet linkdotnet released this 01 Sep 13:47
4bd10a8

Added

  • Avoid boxing common value types (int, long, double, decimal, DateTime, DateTimeOffset, TimeSpan, Guid, and 12 more) when passed to AppendJoin, Concat, AppendFormat, ReplaceGeneric, or interpolated strings.
  • Vectorized Trim, TrimStart, and TrimEnd (both the whitespace and character overloads) via SearchValues<char>, making them significantly faster on large buffers.

### Changed

  • Small improvement to get the next "Grow" iteration

Fixed

  • Sizing bugs in Append and Trim

v3.4.2

Choose a tag to compare

@linkdotnet linkdotnet released this 04 Jul 13:02
eaf202c

Fixed

  • Resolved CS0121 overload ambiguity when passing a no-hole interpolated string (e.g. Append($"text")) to Append/AppendLine on C# 13 and earlier, by adding Append(string?) and AppendLine(string?) overloads. Reported by @SMAH1 in #283

v3.4.1

Choose a tag to compare

@linkdotnet linkdotnet released this 19 Feb 08:33
06d8825

Fixed

  • Use correct culture (CurrentCulture) when no FormatProvider is provided in Append and Insert methods.