question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Replace all string parameters in Draw methods by System.ReadOnlySpan<char> to avoid allocations?

See original GitHub issue

I’m developing a custom UI system with FontStashSharp. I love this library. Thanks for developing it. It’s so easy to use and so beautiful. And the newest aditions (like IFontStashRenderer2) are amazing.

I would propose one small but useful change. To swap the string text parameter in all the Draw overloads by a System.ReadOnlySpan<char>. This would allow to draw multiline text without extra allocations.

This wouldn’t break any compatibility because string has an implicit conversion to ReadOnlySpan<char>

For example, currently if I want to draw a string with word wraping, I would need to do the following in my TextBlock class:

private string _text = string.Empty;
private List<string> _textLines = new List<string>();

public string Text
{
    get => this._text;
    set
    {
        _text = value;
        _textLines.Clear();
        // Apply word wrapping logic and split the string and put every line inside the text lines list.
        // The problem is that every string is immutable, thus generating a new allocation
    }
}

protected void Draw()
{
    foreach (var line in _textLines)
    {
        _font.Draw(line, ...etc);
    }
}

If the argument type is changed by a ReadOnlySpan, this would allow to apply word wrapping, per word, or per sentence effects without the need of extra allocations.

ReadOnlySpan<char> is a struct (so it does not allocates in the heap) and it is defined as ReadOnlySpan(char[]? array, int start, int length). So for a word wrapping system (or something similar) the system would need to create a List<ReadOnlySpan<char>> _textLines.

For example, a simple WordWrap alogorithm without extra allocations would be like this:

private void WordWrap()
{
    this._textLines.Clear();
    int firstCharIndex = 0;
    int charCount = 0;
    for (int i = 0; i < this.Text.Length; i++)
    {
        charCount++;
        if (this.Text[i] == ' ')
        {
            var span = new ReadOnlySpan<char>(this.Text, firstCharIndex, charCount);
            Vector2 size = this._font.MeasureText(span, ...etc);
            if (size.X > this.Width)
            {
                  this._textLines.Add(span);
                  firstCharIndex += charCount + 1;
             }
        }
    }

    var span = new ReadOnlySpan<char>(this.Text, firstCharIndex, charCount);
    this._textLines.Add(span);
}

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:10

github_iconTop GitHub Comments

2reactions
rds1983commented, Jul 2, 2022

well, custom type would let even a BRUTE user to use the new functionality.

1reaction
rds1983commented, Jul 2, 2022

Yeah, that’s correct BRUTE. That tool is used to run MG/FNA apps on platforms that don’t have .NET support like Nintendo Switch. AFAIK BRUTE supports maximum “net452”. Hence I’ve chosen “.net standard 2.0”(well, it’s not really “net452”, but closest among targets that arent deprecated yet). BRUTE doesnt support Span in any form. Hence I’ve would have to go with my own type.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to trim a string without additional memory allocations ...
Therefore, the correct way to avoid allocations is: ReadOnlySpan<char> input = "Hello World-"; Console.Out.WriteLine(input.TrimEnd(' ...
Read more >
ReadOnlySpan<char> Replace extensions #29758
I think this covers almost all use cases including those where the user wants to provide their own refillable buffer to reduce allocations....
Read more >
String-like extension methods to ReadOnlySpan<char> Epic
Removed the allocating versions of the API; Fixed Replace; Fixed argument names and return values of the non-allocating versions of the APIs.
Read more >
What is Span in C# and why you should be using it - YouTube
NET alongside a series of optimisations all the way back in . ... Keep coding merch: https://keepcoding.shop #csharp #dotnet #span.
Read more >
Split a string into lines without any allocation
In our case, ReadOnlySpan<char> will allow us to substring the string line by line by using the Slice method. Unless Substring , it...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found