Skip to content

Instantly share code, notes, and snippets.

@dtao
Created August 25, 2012 22:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dtao/3471636 to your computer and use it in GitHub Desktop.
Save dtao/3471636 to your computer and use it in GitHub Desktop.
Proof of concept for an immutable string class optimized for concatenation with the + operator
using System;
using System.Text;
namespace FastStringConcatenation
{
public class FastString
{
const int DefaultCapacity = 32;
readonly StringBuilder buffer;
readonly int length;
string value;
private FastString(StringBuilder buffer)
{
this.buffer = buffer;
this.length = this.buffer.Length;
}
private FastString(string value) : this(new StringBuilder(value, Math.Max(value.Length * 2, DefaultCapacity)))
{
this.value = value;
}
public FastString() : this(new StringBuilder(DefaultCapacity))
{ }
private bool OwnsBuffer
{
get { return this.buffer.Length == this.length; }
}
public override string ToString()
{
return this.value ?? (this.value = this.buffer.ToString(0, this.length));
}
public static implicit operator FastString(string value)
{
return new FastString(value);
}
public static explicit operator string(FastString fastString)
{
return fastString.ToString();
}
public static FastString operator +(FastString x, string y)
{
if (x.OwnsBuffer)
{
x.buffer.Append(y);
return new FastString(x.buffer);
}
else
{
return new FastString(x.ToString() + y);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace FastStringConcatenation
{
class FastStringDemo
{
const int RandomStringCount = 20000;
const int RandomStringLength = 10;
public static void Main(string[] args)
{
IList<string> strings = GetRandomStrings(RandomStringCount);
Console.WriteLine("Output equal? {0}", ConcatenateFast(strings) == Concatenate(strings));
Console.ReadLine();
}
static string ConcatenateFast(IList<string> strings)
{
GC.Collect();
Stopwatch sw = Stopwatch.StartNew();
FastString fs = "";
for (int i = 0; i < strings.Count; ++i)
{
fs += strings[i];
}
var result = (string)fs;
sw.Stop();
Console.WriteLine("Finished concatenating {0} strings the 'fast' way in {1} ms.", strings.Count, sw.Elapsed.TotalMilliseconds);
return result;
}
static string Concatenate(IList<string> strings)
{
GC.Collect();
Stopwatch sw = Stopwatch.StartNew();
string s = "";
for (int i = 0; i < strings.Count; ++i)
{
s += strings[i];
}
sw.Stop();
Console.WriteLine("Finished concatenating {0} strings the 'slow' way in {1} ms.", strings.Count, sw.Elapsed.TotalMilliseconds);
return s;
}
static IList<string> GetRandomStrings(int count)
{
var strings = new List<string>(count);
var random = new Random();
for (int i = 0; i < count; i++)
{
strings.Add(GetRandomString(random, RandomStringLength));
}
return strings;
}
static string GetRandomString(Random random, int length)
{
var chars = new char[length];
for (int i = 0; i < chars.Length; i++)
{
chars[i] = (char)random.Next(1, 256);
}
return new string(chars);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment