Skip to content

Instantly share code, notes, and snippets.

@dpethes
Last active June 14, 2017 10:39
Show Gist options
  • Save dpethes/46f08c88bac0822fda05db4152fd00b2 to your computer and use it in GitHub Desktop.
Save dpethes/46f08c88bac0822fda05db4152fd00b2 to your computer and use it in GitHub Desktop.
public unsafe class Utf8Buffer
{
private const int BufferSize = 4 * 1024 * 20; //20k utf8 chars at least
private IntPtr _memPtr;
private byte* _buffer;
private int _usedBytes;
public Utf8Buffer()
{
Init();
}
public void Init()
{
if (_buffer != null)
return;
_memPtr = Marshal.AllocHGlobal(BufferSize);
_buffer = (byte*)_memPtr;
}
//free on ImGui.Shutdown
public void Free()
{
Marshal.FreeHGlobal(_memPtr);
}
//reset buffer position and make sure that any pointer into it will result in null-terminated string
public void Reset()
{
_usedBytes = 0;
_buffer[0] = 0;
_buffer[BufferSize - 1] = 0;
}
public byte* FromStr(string str)
{
//If the maximum possible string length doesn't fit our buffer, just return an empty string.
//Probly some message like <Utf8Buffer: couldn't convert text> would be better, so user knows what happened
//If _usedBytes equals 0, we could also re-allocate the buffer
var maxBytes = str.Length * 4 + 1;
if (BufferSize < maxBytes)
{
Reset();
return _buffer;
}
//Wrap if it's possible that the string won't fit.
//This is ok, assuming one ImGui call doesn't use longer strings (sum of their utf8 byte lengths) that would fit into our buffer.
if (BufferSize < _usedBytes + maxBytes)
{
Reset();
}
int bytesLeft = BufferSize - _usedBytes - 1;
int byteCount = 0;
byte* dest = _buffer + _usedBytes;
fixed (char* c = str)
{
byteCount = Encoding.UTF8.GetBytes(c, str.Length, dest, bytesLeft);
}
dest[byteCount] = 0;
_usedBytes += byteCount + 1;
return dest;
}
//Assumes that utf8Buffer is properly allocated and the str would fit
public byte* FromStr(string str, byte* utf8Buffer)
{
var maxBytes = str.Length * 4;
int byteCount = 0;
fixed (char* c = str)
{
byteCount = Encoding.UTF8.GetBytes(c, str.Length, utf8Buffer, maxBytes);
}
utf8Buffer[byteCount] = 0;
return utf8Buffer;
}
public string ToStr(byte* b)
{
if (b == null)
return string.Empty;
int length = 0;
while (b[length] != '\0')
length++;
//if .Net >= 4.5
//return Encoding.UTF8.GetString(b, length);
byte[] buffer = new byte[length];
Marshal.Copy((IntPtr)b, buffer, 0, length);
return Encoding.UTF8.GetString(buffer, 0, length);
}
}
//usage:
public static class ImGui
{
private static Utf8Buffer _utf8 = new Utf8Buffer();
...
public static unsafe void Text(string message)
{
ImGuiNative.igText(_utf8.FromStr(message));
//or
byte* utf8Ptr = stackalloc byte[message.Length * 4 + 1];
ImGuiNative.igText(_utf8.FromStr(message, utf8Ptr));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment