Skip to content

Commit

Permalink
Rewrite interpolated string handler again
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahStolk committed Oct 26, 2024
1 parent c85f3d8 commit d608344
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 73 deletions.
91 changes: 18 additions & 73 deletions src/ImGuiGlfw.Sample/Utils/Inline.cs
Original file line number Diff line number Diff line change
@@ -1,11 1,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;

namespace ImGuiGlfw.Sample.Utils;

#pragma warning disable CA1822, RCS1163

/// <summary>
/// <para>
/// Unsafe methods to quickly format values into a <see cref="Span{T}"/> without allocating heap memory.
Expand All @@ -15,62 11,33 @@ namespace ImGuiGlfw.Sample.Utils;
/// The <see cref="Span{T}"/> is backed by a static buffer of 2048 characters, so the total length of the formatted string cannot exceed this limit.
/// </para>
/// </summary>
[InterpolatedStringHandler]
internal ref struct Inline
internal static class Inline
{
private const int _bufferSize = 2048;

private static readonly byte[] _buffer = new byte[_bufferSize];

private int _charsWritten;

public Inline(int literalLength, int formattedCount)
{
}
private static readonly byte[] _buffer = new byte[2048];

public static implicit operator ReadOnlySpan<byte>(Inline handler)
{
return _buffer.AsSpan()[..handler._charsWritten];
}
public static Span<byte> Buffer => _buffer;

public static ReadOnlySpan<byte> Span(Inline handler)
public static ReadOnlySpan<byte> Span(InlineInterpolatedStringHandler interpolatedStringHandler)
{
return handler;
return interpolatedStringHandler;
}

public static ReadOnlySpan<byte> Span<T>(T t, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
where T : IUtf8SpanFormattable
{
return t.TryFormat(_buffer, out int charsWritten, format, provider) ? _buffer.AsSpan()[..charsWritten] : ReadOnlySpan<byte>.Empty;
t.TryFormat(Buffer, out int charsWritten, format, provider);
return Buffer[..charsWritten];
}

public static ReadOnlySpan<byte> Span(Vector2 value, ReadOnlySpan<char> format = default, IFormatProvider? provider = default)
{
int charsWritten = 0;
TryWrite(_buffer, ref charsWritten, value.X, format, provider);
TryWriteString(_buffer, ref charsWritten, ", "u8);
TryWrite(_buffer, ref charsWritten, value.Y, format, provider);
TryWrite(Buffer, ref charsWritten, value.X, format, provider);
TryWriteUtf8Span(Buffer, ref charsWritten, ", "u8);
TryWrite(Buffer, ref charsWritten, value.Y, format, provider);
return _buffer.AsSpan(0, charsWritten);
}

public static ReadOnlySpan<char> Span(string str)
{
return str.AsSpan();
}

private static bool TryWriteString(Span<byte> destination, ref int charsWritten, ReadOnlySpan<byte> value)
{
if (destination.IsEmpty)
return false;

if (charsWritten value.Length >= destination.Length)
return false;

value.CopyTo(destination[charsWritten..]);
charsWritten = value.Length;
return true;
}

private static bool TryWrite<T>(Span<byte> destination, ref int charsWritten, T value, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)

Check warning on line 41 in src/ImGuiGlfw.Sample/Utils/Inline.cs

View workflow job for this annotation

GitHub Actions / build

Change return type to 'void'; not a single caller uses the returned value. (https://rules.sonarsource.com/csharp/RSPEC-3241)
where T : IUtf8SpanFormattable
{
Expand All @@ -84,38 51,16 @@ private static bool TryWrite<T>(Span<byte> destination, ref int charsWritten, T
return true;
}

public void AppendLiteral(ReadOnlySpan<byte> s)
{
if (s.TryCopyTo(_buffer.AsSpan()[_charsWritten..]))
_charsWritten = s.Length;
}

public unsafe void AppendLiteral(string s)
private static bool TryWriteUtf8Span(Span<byte> destination, ref int charsWritten, ReadOnlySpan<byte> value)

Check warning on line 54 in src/ImGuiGlfw.Sample/Utils/Inline.cs

View workflow job for this annotation

GitHub Actions / build

Change return type to 'void'; not a single caller uses the returned value. (https://rules.sonarsource.com/csharp/RSPEC-3241)
{
fixed (char* utf16Ptr = s)
{
int utf8ByteCount = Encoding.UTF8.GetByteCount(utf16Ptr, s.Length);
if (utf8ByteCount == 0)
return;

if (utf8ByteCount > _bufferSize - _charsWritten)
throw new InvalidOperationException("The formatted string is too long.");

fixed (byte* bufferPtr = _buffer)
_ = Encoding.UTF8.GetBytes(utf16Ptr, s.Length, bufferPtr _charsWritten, utf8ByteCount);
}
}
if (destination.IsEmpty)
return false;

public void AppendFormatted(ReadOnlySpan<byte> s)
{
if (s.TryCopyTo(_buffer.AsSpan()[_charsWritten..]))
_charsWritten = s.Length;
}
if (charsWritten value.Length >= destination.Length)
return false;

public void AppendFormatted<T>(T t, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
where T : IUtf8SpanFormattable
{
t.TryFormat(_buffer.AsSpan()[_charsWritten..], out int charsWritten, format, provider);
_charsWritten = charsWritten;
value.CopyTo(destination[charsWritten..]);
charsWritten = value.Length;
return true;
}
}
55 changes: 55 additions & 0 deletions src/ImGuiGlfw.Sample/Utils/InlineInterpolatedStringHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 1,55 @@
using System.Runtime.CompilerServices;
using System.Text;

namespace ImGuiGlfw.Sample.Utils;

#pragma warning disable CA1822, RCS1163
[InterpolatedStringHandler]
internal ref struct InlineInterpolatedStringHandler
{
private int _charsWritten;

public InlineInterpolatedStringHandler(int literalLength, int formattedCount)
{
}

public static implicit operator ReadOnlySpan<byte>(InlineInterpolatedStringHandler handler)
{
return Inline.Buffer[..handler._charsWritten];
}

public void AppendLiteral(ReadOnlySpan<byte> s)
{
if (s.TryCopyTo(Inline.Buffer[_charsWritten..]))
_charsWritten = s.Length;
}

public unsafe void AppendLiteral(string s)
{
fixed (char* utf16Ptr = s)
{
int utf8ByteCount = Encoding.UTF8.GetByteCount(utf16Ptr, s.Length);
if (utf8ByteCount == 0)
return;

if (utf8ByteCount > Inline.Buffer.Length - _charsWritten)
throw new InvalidOperationException("The formatted string is too long.");

fixed (byte* bufferPtr = Inline.Buffer)
_ = Encoding.UTF8.GetBytes(utf16Ptr, s.Length, bufferPtr _charsWritten, utf8ByteCount);
}
}

public void AppendFormatted(ReadOnlySpan<byte> s)
{
if (s.TryCopyTo(Inline.Buffer[_charsWritten..]))
_charsWritten = s.Length;
}

public void AppendFormatted<T>(T t, ReadOnlySpan<char> format = default, IFormatProvider? provider = null)
where T : IUtf8SpanFormattable
{
t.TryFormat(Inline.Buffer[_charsWritten..], out int charsWritten, format, provider);
_charsWritten = charsWritten;
}
}

0 comments on commit d608344

Please sign in to comment.