Click here to Skip to main content
15,896,153 members
Articles / Programming Languages / C#

StringBuilderPlus Improves Upon StringBuilder

Rate me:
Please Sign up or sign in to vote.
4.85/5 (62 votes)
1 Jun 2011CPOL9 min read 143.3K   809   88  
StringBuilderPlus facilitates prefixing and suffixing strings and StringBuilderPluses in an efficient manner.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace Zigrem.Text
{

	/// <summary>
	/// Acts like a StringBuilder, with the added benefits that strings
	/// can be added to the beginning of the builder+ without a significant
	/// performance hit and a builder+ can be added to another builder+ without
	/// a significant performance hit.
	/// </summary>
	public partial class StringBuilderPlus
	{

		#region Delegates

		private delegate void AffixDelegate(IString str);

		#endregion


		#region Variables

		private LinkedList<IString> strings;
		private int length;

		#endregion


		#region Properties

		/// <summary>
		/// The strings this builder+ is composed of.
		/// </summary>
		private LinkedList<IString> Strings
		{
			get
			{
				return this.strings;
			}
			set
			{
				this.strings = value;
			}
		}


		/// <summary>
		/// Returns the string stored by this builder+.
		/// </summary>
		public string Value
		{
			get
			{
				string str;
				if (this.Strings.Count == 0)
				{
					str = null;
				}
				else
				{
					StringBuilder builder = this.ToBuilder();
					str = builder.ToString();
					this.Strings.Clear();
					this.Strings.AddLast(new PlainString(str));
				}
				return str;
			}
		}


		/// <summary>
		/// The length of the string stored by this builder+.
		/// </summary>
		public int Length
		{
			get
			{
				return this.length;
			}
			private set
			{
				this.length = value;
			}
		}

		#endregion


		#region Constructors

		/// <summary>
		/// Creates a builder+ that contains a null string.
		/// </summary>
		public StringBuilderPlus()
			: this(null as string)
		{
		}


		/// <summary>
		/// Creates a builder+ that contains the specified string.
		/// </summary>
		/// <param name="str">The initial string.</param>
		public StringBuilderPlus(string str)
		{
			this.Strings = new LinkedList<IString>();
			if (str == null)
			{
				this.Length = 0;
				
			}
			else
			{
				this.Suffix(str);
				this.Length = str.Length;
			}
		}

		#endregion


		#region Methods


		/// <summary>
		/// Adds the specified builder+ to the beginning of this builder+.
		/// </summary>
		/// <param name="builder">The builder+ to prefix.</param>
		public void Prefix(StringBuilderPlus builder)
		{
			this.Affix(builder, AffixType.Before);
		}


		/// <summary>
		/// Adds the specified builder+ to the end of this builder+.
		/// </summary>
		/// <param name="builder">The builder+ to suffix.</param>
		public void Suffix(StringBuilderPlus builder)
		{
			this.Affix(builder, AffixType.After);
		}


		/// <summary>
		/// Adds the specified string to the beginning of this builder+.
		/// </summary>
		/// <param name="str">The string to prefix.</param>
		public void Prefix(string str)
		{
			this.Affix(str, AffixType.Before);
		}


		/// <summary>
		/// Adds the specified string to the end of this builder=.
		/// </summary>
		/// <param name="str">The string to suffix.</param>
		public void Suffix(string str)
		{
			this.Affix(str, AffixType.After);
		}


		/// <summary>
		/// Affixes a string to the beginning or end of this builder+.
		/// </summary>
		/// <param name="str">The string to affix.</param>
		/// <param name="type">Prefix or suffix?</param>
		private void Affix(string str, AffixType type)
		{

			// Prefix or suffix?
			AffixDelegate affix;
			if (type == AffixType.Before)
			{
				affix = new AffixDelegate(delegate(IString val)
				{
					this.Strings.AddFirst(val);
				});
			}
			else
			{
				affix = new AffixDelegate(delegate(IString val)
				{
					this.Strings.AddLast(val);
				});
			}


			// Nulls and empties require special handling.
			if (str != null)
			{
				if (str == string.Empty)
				{

					// Optimization: avoid affixing empty strings.
					if (this.Strings.Count == 0)
					{
						affix(PlainString.Empty);
					}

				}
				else
				{
					affix(new PlainString(str));
				}
				this.Length = this.Length + str.Length;
			}

		}


		/// <summary>
		/// Affixes a builder+ to the beginning or end of this builder+.
		/// </summary>
		/// <param name="builder">The builder+ to affix.</param>
		/// <param name="type">Prefix or suffix?</param>
		private void Affix(StringBuilderPlus builder, AffixType type)
		{

			// Prefix or suffix?
			AffixDelegate affix;
			if (type == AffixType.Before)
			{
				affix = new AffixDelegate(delegate(IString val)
				{
					this.Strings.AddFirst(val);
				});
			}
			else
			{
				affix = new AffixDelegate(delegate(IString val)
				{
					this.Strings.AddLast(val);
				});
			}


			// Wrap collection and affix.
			if (builder != null && builder.Strings.Count > 0)
			{
				StringsWrapper wrapper = new StringsWrapper(builder.Strings, builder.Length);
				builder.Strings = new LinkedList<IString>();
				builder.Strings.AddLast(wrapper);
				affix(wrapper);
				this.Length = this.Length + builder.Length;
			}

		}


		/// <summary>
		/// Appends all the strings this builder+ contains to a string builder.
		/// </summary>
		/// <param name="builder">The string builder to append to.</param>
		public void AppendTo(StringBuilder builder)
		{
			foreach (IString str in this.Strings)
			{
				str.AppendTo(builder);
			}
		}


		/// <summary>
		/// Creates a string builder from this builder+.
		/// </summary>
		/// <returns>The string builder.</returns>
		public StringBuilder ToBuilder()
		{
			StringBuilder builder = new StringBuilder();
			this.AppendTo(builder);
			return builder;
		}


		/// <summary>
		/// Returns the string stored by this builder+.
		/// </summary>
		/// <returns>The string.</returns>
		public override string ToString()
		{
			return this.Value;
		}

		#endregion

	}

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
United States United States

  • Managing Your JavaScript Library in ASP.NET (if you work with ASP.net and you don't read that, you are dead to me).
  • Graduated summa cum laude with a BS in Computer Science.
  • Wrote some articles and some tips.
  • DDR ("New high score? What does that mean? Did I break it?"), ping pong, and volleyball enthusiast.
  • Software I have donated to (you should too):

Comments and Discussions