StringWeaver 1.1.0

dotnet add package StringWeaver --version 1.1.0
                    
NuGet\Install-Package StringWeaver -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="StringWeaver" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="StringWeaver" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="StringWeaver" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add StringWeaver --version 1.1.0
                    
#r "nuget: StringWeaver, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package StringWeaver@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=StringWeaver&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=StringWeaver&version=1.1.0
                    
Install as a Cake Tool

The StringWeaver package exposes a custom high-performance builder for strings with a mutable, directly accessible buffer and a versatile API for manipulating the contents.

Consumption

The assembly multi-targets netstandard2.0 and several newer .NETs to support performance-focused APIs introduced in later versions.

  • Core functionality is exposed in the netstandard2.0 compilation, meaning any conforming project platform can use it.
  • A dependency on PCRE.NET is introduced to facilitate all regex operations on StringWeaver to meet performance goals/allocation minimums for < net7.0.
  • Several quality-of-life APIs are also introduced in their respective compilations, such as support for ISpanFormattable on >= net6.0.
  • For >= net7.0, for the Replace* methods that take a PcreRegex, analogous methods that take Regex instance and utilize the Span-based APIs introduced in System.Text.RegularExpressions are also exposed.
  • net8.0 introduced many Span-based APIs throughout the entire .NET ecosystem, allowing streamlined code paths on >= net8.0.

Unfortunately, neither PCRE.NET nor System.Text.RegularExpressions expose allocating APIs that would easily allow producing match details object instances using a Span input. This also means that typical (allocating) replacement operations that allow dynamically producing replacement content using a MatchEvaluator cannot be implemented.

Variants

General purpose

Namespace: global::StringWeaver

  • StringWeaver: Default and most versatile implementation. Offers the full API surface and sources its backing buffers by new'ing and resizing char[]s on demand.
    • The default StringWeaver should be the first choice for the ordinary consumer. Where profiling shows that a different implementation would be more beneficial, consider the alternatives described below.
  • UnsafeStringWeaver: Implements a StringWeaver that sources its backing buffers from unmanaged instead of managed memory. This has the benefit of not causing any GC pressure while exposing exactly the same APIs as the default StringWeaver.
    • Consider using this if you frequently create StringWeavers with capacities near int.MaxValue or instances which are very long-lived.
    • (!) UnsafeStringWeaver implements IDisposable (StringWeaver does not). Not disposing of instances of UnsafeStringWeaver is a memory leak.

Specialized

  • PooledStringWeaver: Implements a StringWeaver that sources its backing buffers from ArrayPool<char>.Shared (or your own passed implementation of ArrayPool<char>). This allows keeping GC pressure low while still using managed memory.
    • Consider using this if you frequently create and dispose of StringWeavers with moderate capacities (e.g. a few dozen kB or more).
    • (!) PooledStringWeaver implements IDisposable (StringWeaver does not). Not disposing of instances of PooledStringWeaver causes the buffer backing it to be lost to the pool, which is a memory leak and degrades performance of every other user of that ArrayPool<char> in your application.

Inheritance

StringWeaver itself is not sealed because UnsafeStringWeaver inherits from it. As such, inheritance from StringWeaver is allowed for external types as well. There are only a select few members you must override to make your implementation function correctly, everything else (functionality-wise) is handled for you (and not virtual, for that matter):

  • Memory<char> FullMemory: Gets a Memory<char> instance over the entire backing storage (NOT just the used portion).
  • void Grow(int requiredCapacity): WITHOUT checking whether it is required, expands the backing storage to at least the specified capacity (those checks are done for you before this virtual method is ever called). It is recommended you decorate your override with [MethodImpl(MethodImplOptions.NoInlining)].
  • (!) StringWeaver.ToString (the base version) is sealed override.
  • IBufferWriter<char> implementations and Stream support are both handled internally as well. Do not re-implement either of those.

Adding functionality on top of anything already handled for you is straightforward. All the base functionality can be used to compose your own methods or just use (Full)Memory/(Full)Span to access the backing storage directly. The Length property has an accessible setter that controls which portion of the buffer is considered "used".

(!) The above statement is true for disposal. As mentioned, StringWeaver does not implement IDisposable, so derived types must do so themselves if they require it. Ensure cleanup for your own types is sound.

Global configuration

The static class StringWeaverConfiguration exposes global configuration options for all StringWeaver variants where applicable. The options are usually strongly-typed and implemented in a thread-safe manner, however, altering options while the affected variants are in use will very likely lead to undefined behavior. I recommend very carefully thinking about what you're changing, why you're doing it and if it's really a good idea, then setting them on application startup and never touching the entire class again.

Contribution

Opening issues and submitting PRs are welcome. All changes must be appropriately covered by tests. Tests run exclusively under net9.0.

Support for netstandard2.0 must always be maintained. If possible, new functionality should be added to all target frameworks. New dependencies may be introduced after I vet the decision to do so.

Or get in touch on Discord @eyeoftheenemy

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 305 11/11/2025
1.0.2 175 9/5/2025
1.0.1 235 9/1/2025 1.0.1 is deprecated.
1.0.0 312 8/24/2025 1.0.0 is deprecated because it has critical bugs.