FormatWith
FormatWith copied to clipboard
Span<T> goodness
Need to investigate updating the parser to return ReadOnlySpan<T> instead of the current struct. Probably won't make much of a difference to performance, since the current implementation is already using structs on the stack, but it should be good for code style points.
I've put together a PR with an initial implementation for your review (#20)
@JeremySkinner I've finally got your PR merged, apologies it took so long!
It's still a work in progress, but I've overhauled the public FormatWith API to enable ReadOnlySpan<char> based scenarios. All of the existing FormatWith overloads are also now wrapping the lower level Span based overload.
The work is happening in the release-4.0 branch.
The main Span API usage looks like this:
HandlerAction handlerAction = static (key, format, result) =>
{
if (key.Equals("KeyNumber1".AsSpan(), StringComparison.Ordinal))
{
result("A Nice Value".AsSpan());
return true;
}
return false;
};
FallbackAction fallbackAction = static (result) =>
{
result("A good fallback value".AsSpan());
};
string replacement = "abc {KeyNumber1} {DoesntExist}".AsSpan().FormatWith(handlerAction, MissingKeyBehaviour.ReplaceWithFallback, fallbackAction);
Assert.Equal("abc A Nice Value A good fallback value", replacement);
Currently there aren't any more "convenient" Span overloads (that take a dictionary or object lookup, for example), but I think they'll probably be needed. Also, the string returning overloads use a cache of ThreadLocal WeakReference'd StringBuilders which should provide a balance of performance and memory consumption.
There is also a lower level overload that accepts a callback delegate to write the result, and doesn't use StringBuilder at all:
public static void FormatWith(
ReadOnlySpan<char> formatString,
HandlerAction handlerAction,
ResultAction destinationWriterAction,
MissingKeyBehaviour missingKeyBehaviour,
FallbackAction fallbackReplacementAction = null,
char openBraceChar = '{',
char closeBraceChar = '}')
Please let me know if you have any thoughts on the shape of these APIs, I'd love to get some feedback on their practicality and usability.