Skip to content

Latest commit

 

History

History

Chasm.Formatting

Chasm.Formatting

Latest NuGet version MIT License

Provides various formatting and parsing utility types and methods.

SpanParser

A helper structure designed to quickly and efficiently parse text.

string text = """
$variable = [some value];
DoSomething();
""";

SpanParser parser = new SpanParser(text);

// returns true and moves forward, if the next character is '$' or '@'
if (parser.SkipAny('$', '@'))
{
    // reads "variable", moves past it and returns it
    ReadOnlySpan<char> name = parser.ReadAsciiLetters();
    parser.SkipWhitespaces();
    // returns true and moves forward, if the next character is '='
    if (parser.Skip('='))
    {
        parser.SkipWhitespaces();
        // reads "[some value]", moves past it and returns it
        ReadOnlySpan<char> value = parser.ReadUntil(c => c == ';');

        // at this point, the parser either reached the end, or is at ';'
        /* ... */
    }
}
// returns the current character, or '\0' if the parser reached the end
else if (parser.Peek() is >= 'A' and <= 'Z')
{
    char read = parser.Read(); // reads a character (or '\0') and moves forward
    /* ... */
}

Note

There's a very similar type in .NET called SequenceReader<T>, but it only works on Memory<T>, and not on Span<T>. I don't really know how it compares to my SpanParser though.

  • TODO: do a feature comparison and some benchmarks between SequenceReader<T> and SpanParser.

SpanBuilder

A helper structure designed to minimize formatting's memory allocation by allocating the exact required amount of memory and then formatting directly into it.

public readonly struct MyStruct : ISpanBuildable
{
    private readonly string? text;
    private readonly int number;

    public override string ToString()
        => SpanBuilder.Format(this);

    // Of course, on this scale, using SpanBuilder would be detrimental to performance.
    // You should use it in more complex scenarios, with lots of nesting.

    public void CalculateLength()
        => text?.Length ?? SpanBuilder.CalculateLength(number);

    public void BuildString(ref SpanBuilder sb)
    {
        if (text is not null)
            sb.Append(text);
        else
            sb.Append((uint)number);
    }
}

Note

The performance benefit isn't that great, and sometimes SpanBuilder is slightly slower than a regular StringBuilder. RAM is considered a relatively cheap resource in .NET for a reason, after all.

Caution

Implementations of ISpanBuildable are extremely prone to errors!

SpanBuilder will throw an exception if the sizes don't match. Make sure that it's all thoroughly tested.