StringWeaver 1.1.0
dotnet add package StringWeaver --version 1.1.0
NuGet\Install-Package StringWeaver -Version 1.1.0
<PackageReference Include="StringWeaver" Version="1.1.0" />
<PackageVersion Include="StringWeaver" Version="1.1.0" />
<PackageReference Include="StringWeaver" />
paket add StringWeaver --version 1.1.0
#r "nuget: StringWeaver, 1.1.0"
#:package StringWeaver@1.1.0
#addin nuget:?package=StringWeaver&version=1.1.0
#tool nuget:?package=StringWeaver&version=1.1.0
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.0compilation, meaning any conforming project platform can use it. - A dependency on
PCRE.NETis introduced to facilitate all regex operations onStringWeaverto meet performance goals/allocation minimums for< net7.0. - Several quality-of-life APIs are also introduced in their respective compilations, such as support for
ISpanFormattableon>= net6.0. - For
>= net7.0, for theReplace*methods that take aPcreRegex, analogous methods that takeRegexinstance and utilize the Span-based APIs introduced inSystem.Text.RegularExpressionsare also exposed. net8.0introduced manySpan-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 bynew'ing and resizingchar[]s on demand.- The default
StringWeavershould be the first choice for the ordinary consumer. Where profiling shows that a different implementation would be more beneficial, consider the alternatives described below.
- The default
UnsafeStringWeaver: Implements aStringWeaverthat 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 defaultStringWeaver.- Consider using this if you frequently create
StringWeavers with capacities nearint.MaxValueor instances which are very long-lived. - (!)
UnsafeStringWeaverimplementsIDisposable(StringWeaverdoes not). Not disposing of instances ofUnsafeStringWeaveris a memory leak.
- Consider using this if you frequently create
Specialized
PooledStringWeaver: Implements aStringWeaverthat sources its backing buffers fromArrayPool<char>.Shared(or your own passed implementation ofArrayPool<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). - (!)
PooledStringWeaverimplementsIDisposable(StringWeaverdoes not). Not disposing of instances ofPooledStringWeavercauses the buffer backing it to be lost to the pool, which is a memory leak and degrades performance of every other user of thatArrayPool<char>in your application.
- Consider using this if you frequently create and dispose of
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 aMemory<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 thisvirtualmethod is ever called). It is recommended you decorate youroverridewith[MethodImpl(MethodImplOptions.NoInlining)].- (!)
StringWeaver.ToString(the base version) issealed override. IBufferWriter<char>implementations andStreamsupport 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 | Versions 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. |
-
.NETStandard 2.0
- Microsoft.Bcl.Memory (>= 10.0.0)
- PCRE.NET (>= 1.3.0)
- System.Buffers (>= 4.6.1)
- System.Memory (>= 4.6.3)
-
net6.0
- PCRE.NET (>= 1.3.0)
-
net7.0
- PCRE.NET (>= 1.3.0)
-
net8.0
- PCRE.NET (>= 1.3.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.