Skip to content

Instantly share code, notes, and snippets.

@AnsisMalins
Last active August 12, 2020 21:22
Show Gist options
  • Save AnsisMalins/25bc00a5c7f904400aab3738ee2caafa to your computer and use it in GitHub Desktop.
Save AnsisMalins/25bc00a5c7f904400aab3738ee2caafa to your computer and use it in GitHub Desktop.
Non-growing, zero allocation string builder
using System.IO;
using UnityEngine;
public sealed class UnsafeStringBuilder
{
public int Capacity => _buffer.Length;
public int Length { get; private set; }
private string _buffer;
public UnsafeStringBuilder(int capacity)
{
_buffer = new string('\0', capacity);
}
public unsafe UnsafeStringBuilder Clear()
{
fixed (char* buffer = _buffer)
buffer[0] = '\0';
Length = 0;
return this;
}
public unsafe UnsafeStringBuilder Append(string value)
{
if (Length + value.Length >= Capacity)
throw new InternalBufferOverflowException();
fixed (char* buffer = _buffer)
{
char* ptr = buffer + Length;
for (int i = 0; i < value.Length; i++)
*ptr++ = value[i];
*ptr = '\0';
Length += value.Length;
}
return this;
}
public unsafe UnsafeStringBuilder Append(float value, int precision = 3)
{
bool negative = value < 0f;
if (negative)
value = -value;
int units = (int)value;
int pow = (int)Mathf.Pow(10f, precision);
int fraction = (int)(value * pow) % pow;
fixed (char* buffer = _buffer)
{
char* start = buffer + Length;
char* endOfBuffer = buffer + Capacity;
char* ptr = start;
while (precision > 0 && fraction % 10 == 0)
{
fraction /= 10;
precision--;
}
try
{
while (precision > 0)
{
if (ptr == endOfBuffer)
throw new InternalBufferOverflowException();
*ptr++ = (char)('0' + fraction % 10);
fraction /= 10;
precision--;
}
if (ptr > start)
{
if (ptr == endOfBuffer)
throw new InternalBufferOverflowException();
*ptr++ = '.';
}
do
{
if (ptr == endOfBuffer)
throw new InternalBufferOverflowException();
*ptr++ = (char)('0' + (units % 10));
units /= 10;
} while (units > 0);
if (negative)
{
if (ptr == endOfBuffer)
throw new InternalBufferOverflowException();
*ptr++ = '-';
}
}
catch (InternalBufferOverflowException)
{
*start = '\0';
throw;
}
*ptr = '\0';
Length += (int)(ptr - start);
ptr--;
while (start < ptr)
{
char temp = *start;
*start = *ptr;
*ptr = temp;
start++;
ptr--;
}
}
return this;
}
public override string ToString()
{
return _buffer;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment