I was just rereading this i don’t know if you ever saw my wrapped StringBuilder class i posted a while back.
I should have posted it before. It might be of some use to you, in case your still dealing with garbage, even under stringbuilder.
In most of my screen shots i post there is basically no garbage. Primarily because of two things.
- MonoGame itself is awesome and generates little to no collectable garbage except in a select few edge cases.
- The below class… While it doesn’t address any problem with monogame, it instead address a problem with c# numerics tostring or tochar conversions creating garbage.
This is a thin wrapper on stringbuilder that basically augments stringbuilder to prevent garbage created by numeric to text conversion by c#. It simply does it instead of letting c# do it and create garbage. A couple extra temp stringbuilders handle edge case copying by holding onto references until they can be cleared during certain copy operations.
All the methods are proven so far at least in my tests, except the vector versions that are new and untested, so i commented them out. Some edge cases that are commented “//just append it” are not handled but they are pretty rare.
using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
namespace MyText
{
public sealed class MgStringBuilder
{
private static char decimalseperator = '.';
private static char minus = '-';
private static char plus = '+';
private static StringBuilder last;
private StringBuilder sb;
public StringBuilder StringBuilder
{
get { return sb; }
private set { sb = value; last = sb; }
}
public int Length
{
get { return StringBuilder.Length; }
set { StringBuilder.Length = value; }
}
public int Capacity
{
get { return StringBuilder.Capacity; }
set { StringBuilder.Capacity = value; }
}
public void Clear()
{
Length = 0;
sb.Length = 0;
}
// constructors
public MgStringBuilder()
{
StringBuilder = StringBuilder;
if (sb == null) { sb = new StringBuilder(); }
if (last == null) { last = new StringBuilder(); }
}
public MgStringBuilder(int capacity)
{
StringBuilder = new StringBuilder(capacity);
if (sb == null) { sb = new StringBuilder(); }
if (last == null) { last = new StringBuilder(); }
}
public MgStringBuilder(StringBuilder sb)
{
StringBuilder = sb;
if (sb == null) { sb = new StringBuilder(); }
if (last == null) { last = new StringBuilder(); }
}
public MgStringBuilder(string s)
{
StringBuilder = new StringBuilder(s);
if (sb == null) { sb = new StringBuilder(); }
if (last == null) { last = new StringBuilder(); }
}
public static void CheckSeperator()
{
decimalseperator = Convert.ToChar(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
}
// operators
public static implicit operator MgStringBuilder(StringBuilder sb)
{
return new MgStringBuilder(sb);
}
//public static implicit operator StringBuilder(MgStringBuilder msb)
//{
// StringBuilder b = new StringBuilder().Append(msb.sb);
// return b;
//}
public static implicit operator StringBuilder(MgStringBuilder msb)
{
return msb.StringBuilder;
}
public static MgStringBuilder operator +(MgStringBuilder sbm, MgStringBuilder s)
{
sbm.StringBuilder.Append(s);
return sbm;
}
public void AppendAt(int index, StringBuilder s)
{
int len = this.StringBuilder.Length;
int reqcapacity = (index + s.Length + 1) - this.StringBuilder.Capacity;
if (reqcapacity > 0)
this.StringBuilder.Capacity += reqcapacity;
for (int i = 0; i < s.Length; i++)
{
this.StringBuilder[i + index] = (char)(s[i]);
}
}
public void Append(StringBuilder s)
{
int len = this.StringBuilder.Length;
int reqcapacity = (s.Length + len) - this.StringBuilder.Capacity;
//int reqcapacity = (s.Length + len +1) - this.StringBuilder.Capacity;
if (reqcapacity > 0)
this.StringBuilder.Capacity += reqcapacity;
this.StringBuilder.Length = len + s.Length;
for(int i = 0;i< s.Length;i++)
{
this.StringBuilder[i + len] = (char)(s[i]);
}
}
public void Append(string s)
{
this.StringBuilder.Append(s);
}
public void Append(bool value)
{
this.StringBuilder.Append(value);
}
public void Append(byte value)
{
// basics
int num = value;
if (num == 0)
{
sb.Append('0');
return;
}
int place = 100;
if (num >= place * 10)
{
// just append it
sb.Append(num);
return;
}
// part 1 pull integer digits
bool addzeros = false;
while (place > 0)
{
if (num >= place)
{
addzeros = true;
int modulator = place * 10;
int val = num % modulator;
int dc = val / place;
sb.Append((char)(dc + 48));
}
else
{
if (addzeros) { sb.Append('0'); }
}
place = (int)(place * .1);
}
}
public void Append(short value)
{
int num = value;
// basics
if (num < 0)
{
// Negative.
sb.Append(minus);
num = -num;
}
if (value == 0)
{
sb.Append('0');
return;
}
int place = 10000;
if (num >= place * 10)
{
// just append it, if its this big, this isn't a science calculator, its a edge case.
sb.Append(num);
return;
}
// part 1 pull integer digits
bool addzeros = false;
while (place > 0)
{
if (num >= place)
{
addzeros = true;
int modulator = place * 10;
int val = num % modulator;
int dc = val / place;
sb.Append((char)(dc + 48));
}
else
{
if (addzeros) { sb.Append('0'); }
}
place = (int)(place * .1);
}
}
public void Append(int value)
{
// basics
if (value < 0)
{
// Negative.
sb.Append(minus);
value = -value;
}
if (value == 0)
{
sb.Append('0');
return;
}
int place = 1000000000;
if (value >= place * 10)
{
// just append it
sb.Append(value);
return;
}
// part 1 pull integer digits
int n = (int)(value);
bool addzeros = false;
while (place > 0)
{
if (n >= place)
{
addzeros = true;
int modulator = place * 10;
int val = n % modulator;
int dc = val / place;
sb.Append((char)(dc + 48));
}
else
{
if (addzeros) { sb.Append('0'); }
}
place = (int)(place * .1);
}
}
public void Append(long value)
{
// basics
if (value < 0)
{
// Negative.
sb.Append(minus);
value = -value;
}
if (value == 0)
{
sb.Append('0');
return;
}
long place = 10000000000000000L;
if (value >= place * 10)
{
// just append it,
sb.Append(value);
return;
}
// part 1 pull integer digits
long n = (long)(value);
bool addzeros = false;
while (place > 0)
{
if (n >= place)
{
addzeros = true;
long modulator = place * 10L;
long val = n % modulator;
long dc = val / place;
sb.Append((char)(dc + 48));
}
else
{
if (addzeros) { sb.Append('0'); }
}
place = (long)(place * .1);
}
}
public void Append(float value)
{
// basics
if (value < 0)
{
// Negative.
sb.Append(minus);
value = -value;
}
if (value == 0)
{
sb.Append('0');
return;
}
int place = 100000000;
if (value >= place * 10)
{
// just append it, if its this big its a edge case.
sb.Append(value);
return;
}
// part 1 pull integer digits
int n = (int)(value);
bool addzeros = false;
while (place > 0)
{
if (n >= place)
{
addzeros = true;
int modulator = place * 10;
int val = n % modulator;
int dc = val / place;
sb.Append((char)(dc + 48));
}
else
{
if (addzeros) { sb.Append('0'); }
}
place = (int)(place * .1);
}
// ok lets try again
// nd > 0 wont let us see the decimal
float nd = value - (float)(n);
if (nd > -1 && nd < 1)
{
sb.Append(decimalseperator);
}
addzeros = true;
//nd = value;
float placed = .1f;
while (placed > 0.00000001)
{
if (nd > placed)
{
float modulator = placed * 10;
float val = nd % modulator;
float dc = val / placed;
sb.Append((char)(dc + 48));
}
else
{
if (addzeros) { sb.Append('0'); }
}
placed = placed * .1f;
}
}
public void Append(double number)
{
// basics
if (number < 0)
{
// Negative.
sb.Append(minus);
number = -number;
}
if (number == 0)
{
sb.Append('0');
return;
}
long place = 10000000000000000L;
if (number >= place * 10)
{
// just append it, if its this big its a edge case.
sb.Append(number);
return;
}
// part 1 pull integer digits
long n = (long)(number);
bool addzeros = false;
while (place > 0)
{
if (n >= place)
{
addzeros = true;
long modulator = place * 10L;
long val = n % modulator;
long dc = val / place;
sb.Append((char)(dc + 48));
}
else
{
if (addzeros) { sb.Append('0'); }
}
place = (long)(place * .1);
}
// the decimal part
double nd = number - (double)(n);
if (nd > 0 && nd < 1)
{
sb.Append(decimalseperator);
}
addzeros = true;
//nd = number;
double placed = .1;
while (placed > 0.0000000000001)
{
if (nd > placed)
{
double modulator = placed * 10;
double val = nd % modulator;
double dc = val / placed;
sb.Append((char)(dc + 48));
}
else
{
if (addzeros) { sb.Append('0'); }
}
placed = placed * .1;
}
}
//public void Append(Vector2 value)
//{
// Append("(");
// Append(value.X);
// Append(",");
// Append(value.Y);
// Append(")");
//}
//public void Append(Vector3 value)
//{
// Append("(");
// Append(value.X);
// Append(",");
// Append(value.Y);
// Append(",");
// Append(value.Z);
// Append(")");
//}
//public void Append(Vector4 value)
//{
// Append("(");
// Append(value.X);
// Append(",");
// Append(value.Y);
// Append(",");
// Append(value.Z);
// Append(",");
// Append(value.W);
// Append(")");
//}
public void Append(Color value)
{
Append("(");
Append(value.R);
Append(",");
Append(value.G);
Append(",");
Append(value.B);
Append(",");
Append(value.A);
Append(")");
}
public void AppendTrim(float value)
{
// basics
if (value < 0)
{
// Negative.
sb.Append(minus);
value = -value;
}
if (value == 0)
{
sb.Append('0');
return;
}
int place = 100000000;
if (value >= place * 10)
{
// just append it, if its this big its a edge case.
sb.Append(value);
return;
}
// part 1 pull integer digits
int n = (int)(value);
bool addzeros = false;
while (place > 0)
{
if (n >= place)
{
addzeros = true;
int modulator = place * 10;
int val = n % modulator;
int dc = val / place;
sb.Append((char)(dc + 48));
}
else
{
if (addzeros) { sb.Append('0'); }
}
place = (int)(place * .1);
}
// ok lets try again
float nd = value - (float)(n);
sb.Append(decimalseperator);
addzeros = true;
//nd = value;
float placed = .1f;
while (placed > 0.001)
{
if (nd > placed)
{
float modulator = placed * 10;
float val = nd % modulator;
float dc = val / placed;
sb.Append((char)(dc + 48));
}
else
{
if (addzeros) { sb.Append('0'); }
}
placed = placed * .1f;
}
}
public void AppendTrim(double number)
{
// basics
if (number < 0)
{
// Negative.
sb.Append(minus);
number = -number;
}
if (number == 0)
{
sb.Append('0');
return;
}
long place = 10000000000000000L;
if (number >= place * 10)
{
// just append it, if its this big its a edge case.
sb.Append(number);
return;
}
// part 1 pull integer digits
long n = (long)(number);
bool addzeros = false;
while (place > 0)
{
if (n >= place)
{
addzeros = true;
long modulator = place * 10L;
long val = n % modulator;
long dc = val / place;
sb.Append((char)(dc + 48));
}
else
{
if (addzeros) { sb.Append('0'); }
}
place = (long)(place * .1);
}
// ok lets try again
double nd = number - (double)(n);
sb.Append(decimalseperator);
addzeros = true;
//nd = number;
double placed = .1;
while (placed > 0.001)
{
if (nd > placed)
{
double modulator = placed * 10;
double val = nd % modulator;
double dc = val / placed;
sb.Append((char)(dc + 48));
}
else
{
if (addzeros) { sb.Append('0'); }
}
placed = placed * .1;
}
}
//public void AppendTrim(Vector2 value)
//{
// Append("(");
// AppendTrim(value.X);
// Append(",");
// AppendTrim(value.Y);
// Append(")");
//}
//public void AppendTrim(Vector3 value)
//{
// Append("(");
// AppendTrim(value.X);
// Append(",");
// AppendTrim(value.Y);
// Append(",");
// AppendTrim(value.Z);
// Append(")");
//}
//public void AppendTrim(Vector4 value)
//{
// Append("(");
// AppendTrim(value.X);
// Append(",");
// AppendTrim(value.Y);
// Append(",");
// AppendTrim(value.Z);
// Append(",");
// AppendTrim(value.W);
// Append(")");
//}
public void AppendLine(StringBuilder s)
{
sb.AppendLine();
Append(s);
}
public void AppendLine(string s)
{
sb.AppendLine();
sb.Append(s);
}
public void AppendLine()
{
sb.AppendLine();
}
public void Insert(int index, StringBuilder s)
{
this.StringBuilder.Insert(index, s);
}
public void Remove(int index, int length)
{
this.StringBuilder.Remove(index, length);
}
public char[] ToCharArray()
{
char[] a = new char[sb.Length];
sb.CopyTo(0, a, 0, sb.Length);
return a;
}
public override string ToString()
{
return sb.ToString();
}
}
}