List implementation of Span<T>
for .NET / Unity
Runtime/System/SpanList.cs
HeaderDoc
(c) 2025 Sator Imaging, Licensed under the MIT License https://github.com/sator-imaging/Unity-Fundamentals
Simple container especially designed to work in conjunction with multiple Span<char>
s for
formatting and replacing text at once.
It's similar with Memory<T>
but by contrast from that, SpanList<T>
provides segmented range
access to its internal buffer so that it can be used for cache store of list of span objects.
Example Usage
Formatting text by replacing named holes: https://messagetemplates.org/
// you can stored list of `Span<char>` on class or struct field.
private SpanList<char> m_fromList = new(null, 3, "{foo}", "{bar}", "{baz}");
// helper function that automatically manage array pool buffer.
using (SpanList.GetTransientScope(out var toList, 3, "Blah", "blah", "..."))
{
// replace result
// --> Blah blah ...
var result = "{foo} {bar} {baz}".ReplaceNonAlloc(m_fromList, toList);
// when 'from' list consists of tokens starting with '{' and ending with '}',
// use `FormatNonAlloc` instead to achieve more efficient operation by reducing required buffer size.
return "{foo} {bar} {baz}".FormatNonAlloc(m_fromList, toList);
// buffer return to array pool automatically on using-block exit
}
Advanced Usage
You can take direct reference to internal data of SpanList<T>
.
// take 64 x 3 span from pool
using var _ SpanList.GetTransientScope(out var spanList, stackalloc int[] { 64, 64, 64 });
// you can perform validation and formatting without extra heap allocation
ref var range = ref spanList.GetSpanUnsafe(0, out var span);
~~~~~~~ ~~~ taking `ref Range`
// write validated result into taken span
int charsWritten = Validate(rawFoo, span);
range = range.SetLength(charsWritten); // update internal span range directly by `ref var`
// thanks to C#'s `ref return` feature, we can set new length on the fly
spanList.GetSpanUnsafe(1, out span).SetLength(Validate(rawBar, span);
// but, there is safe API to write data into internal buffer ^_^
spanList.Write(2, "my text", static (span, arg) => Validate(arg, span));
s = spanList[2]; // "my text"
spanList.Write(2, "updated text", static (span, arg) => Validate(arg, span));
s = spanList[2]; // "updated text"
return "{foo} {bar} {baz}".FormatNonAlloc(m_fromList, spanList);