Main Site Documentation

Return a string from native side?


#1

Is there a good way to return a string from native side?
For now Im doing something like this


//native side
  int GetString(unsigned char *byteStr, void **args, unsigned int argsCount, unsigned int *argData)
	{
		char string[] = Hello;
			 
		for(int i = 0; i < 5;i++)
		{
			byteStr[i]= (unsigned char) string[i]; 
		}   
		return 0;
	}
//Managed side
            byte [] byteStr = new byte [5];
            char [] charArr = new char [5];

            GetString.InvokeEx( byteStr );

            for ( int i = 0; i < 5; i++ )
            {
                charArr [i] = (char) byteStr [i];
            }

            Debug.Print( new String( charArr ) );

Is there a way to return a char array so you would not have too perform a deep copy and a cast in the managed side.

I would like to implement a StringBuilder but this extra byte array and deep copy seems like an overhead.

Regards


#2

There is no other way.
StringBuilder implementation should buffer the data internally in a byte array.
All operations like Append(…)…etc will actually control the byte array directly. No strings are created.
The only place to make a string is when needed and you have to do something like new String(Encoding.UT8.GetChars(buffer)); …etc

The internal buffer will be dynamic. Increases size if needed …etc

It is not necessary to do this in native code (RLP). All this is easier in C# with slight performance overhead.

Anyways, this is not needed. NETMF already has a somewhat StringBuilder used internally in XML.
Grab it from here. Called BufferBuilder:
http://netmf.codeplex.com/SourceControl/changeset/view/10477#72467


#3

I created a StringBuilder class for one of my projects. Didn’t post it on code.tinyclr yet because the AppendFormat is not fully tested.

This is what I have for now:


using System;
using System.Collections;

namespace StringUtils
{
    /// <summary>
    /// StringBuilder class.
    /// </summary>
    public class StringBuilder : IDisposable
    {
        #region Declarations

        private ArrayList array;

        #endregion

        #region Construction / destruction

        /// <summary>
        /// Creates a new instance of the StringBuilder class with a given initial capacity.
        /// </summary>
        /// <param name="capacity">The initial capacity.</param>
        public StringBuilder(int capacity)
        {
            array = new ArrayList();
            array.Capacity = capacity;
        }

        /// <summary>
        /// Creates a new instance of the StringBuilder class with a default initial capacity of 32.
        /// </summary>
        public StringBuilder()
            : this(32)
        {
        }

        /// <summary>
        /// Free used resources.
        /// </summary>
        public void Dispose()
        {
            if (array != null)
            {
                array.Clear();
                array = null;
            }
        }

        #endregion

        #region Public methods

        /// <summary>
        /// Append a single char to the end of this StringBuilder instance.
        /// </summary>
        /// <param name="value">The char to append.</param>
        /// <returns>The modified StringBuilder instance.</returns>
        public StringBuilder Append(char value)
        {
            array.Add(value);
            return this;
        }

        /// <summary>
        /// Append a part of a char array to the end of this StringBuilder intance.
        /// </summary>
        /// <param name="value">The char array to append.</param>
        /// <param name="startIndex">The start index in the char array to start appending from.</param>
        /// <param name="count">The number of chars from the char array to append.</param>
        /// <returns>The modified StringBuilder instance.</returns>
        public StringBuilder Append(char[] value, int startIndex, int count)
        {
            for (int i = 0; i < count; i++)
                array.Add(value[startIndex + i]);

            return this;
        }

        /// <summary>
        /// Appends a char array to the end of this StringBuilder instance.
        /// </summary>
        /// <param name="value">The char array to append.</param>
        /// <returns>The modified StringBuilder instance.</returns>
        public StringBuilder Append(char[] value)
        {
            return Append(value, 0, value.Length);
        }

        /// <summary>
        /// Append a part of a string to the end of this StringBuilder instance.
        /// </summary>
        /// <param name="value">The string to append.</param>
        /// <param name="startIndex">The start index in the string to start appending from.</param>
        /// <param name="count">The number of chars from the string to append.</param>
        /// <returns>The modified StringBuilder instance.</returns>
        public StringBuilder Append(string value, int startIndex, int count)
        {
            return Append(value.ToCharArray(startIndex, count));
        }

        /// <summary>
        /// Append a string to the end of this StringBuilder instance.
        /// </summary>
        /// <param name="value">The string to append.</param>
        /// <returns>The modified StringBuilder instance.</returns>
        public StringBuilder Append(string value)
        {
            return Append(value.ToCharArray());
        }

        /// <summary>
        /// Append a formatted string to the end of this StringBuilder instance.
        /// </summary>
        /// <param name="value">The formatted string.</param>
        /// <param name="paramlist">The parameters to use in the formatted string.</param>
        /// <returns>The modified StringBuilder instance.</returns>
        public StringBuilder AppendFormat(string value, params object[] paramlist)
        {
            bool scraping = false;
            int workOffset = 0, tremaOffset = -1;

            char[] valueArray = value.ToCharArray();
            char prevChar = '\0';

            int i = 0;
            for (; i < valueArray.Length; i++)
            {
                char c = valueArray[i];

                switch (c)
                {
                    case '{':
                        if (i > workOffset)
                            Append(valueArray, workOffset, i - workOffset);

                        workOffset = i + 1;

                        if (prevChar != '{')
                        {
                            if (scraping) throw new Exception("Invalid formatting string");
                            scraping = true;
                        }
                        else
                        {
                            Append(c);
                            scraping = false;
                            c = '\0';
                        }
                        break;

                    case '}':
                        if (!scraping)
                            if (i > workOffset)
                                Append(valueArray, workOffset, i - workOffset);

                        if (prevChar != '}')
                        {
                            if (scraping)
                            {
                                int index = 0;
                                string format = null;

                                if (tremaOffset > workOffset)
                                {
                                    index = int.Parse(value.Substring(workOffset, tremaOffset - workOffset));

                                    tremaOffset++;

                                    if (i > tremaOffset)
                                        format = value.Substring(tremaOffset, i - tremaOffset);
                                }
                                else
                                    index = int.Parse(value.Substring(workOffset, i - workOffset));

                                object par = paramlist[index];

                                //Use reflection one day to find the ToString method
                                //Type parType = par.GetType();
                                //MethodInfo[] mi = parType.GetMethods();

                                if (par is byte)
                                    Append(((byte)par).ToString(format));
                                else if (par is sbyte)
                                    Append(((sbyte)par).ToString(format));
                                else if (par is ushort)
                                    Append(((ushort)par).ToString(format));
                                else if (par is short)
                                    Append(((ushort)par).ToString(format));
                                else if (par is uint)
                                    Append(((uint)par).ToString(format));
                                else if (par is int)
                                    Append(((int)par).ToString(format));
                                else if (par is ulong)
                                    Append(((ulong)par).ToString(format));
                                else if (par is long)
                                    Append(((long)par).ToString(format));
                                else if (par is float)
                                    Append(((float)par).ToString(format));
                                else if (par is double)
                                    Append(((double)par).ToString(format));
                                else
                                    Append(par.ToString());

                                scraping = false;
                                c = '\0';
                            }
                        }
                        else
                        {
                            if (scraping) throw new Exception("Invalid formatting string");
                            Append(c);
                            c = '\0';
                        }

                        workOffset = i + 1;
                        break;

                    case ':':
                        tremaOffset = i;
                        break;
                }

                prevChar = c;
            }

            if (i > workOffset)
                Append(valueArray, workOffset, i - workOffset);

            return this;
        }

        /// <summary>
        /// Returns the string representation of this StringBuilder instance.
        /// </summary>
        /// <returns>The string representation.</returns>
        public override string ToString()
        {
            return new string((char[])array.ToArray(typeof(char)));
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets the length of the string.
        /// </summary>
        public int Length
        {
            get { return array.Count; }
        }

        #endregion
    }
}


#4

I do have my own stringbuilder but i thought it was better do one in RLP to pick up speed. But it was not the case with my design.
But I think it is better to handle it in the managed side. So for me this thread is closed, if nothing better comes up. ???

Check it here .
Native code



struct Char
{
char charData;                 //ch stored in the Char
struct Char *next;          //pointer to next Char
struct Char *prev;          //pointer to previous Char
};
struct StringBuilder
{
struct Char *stNodeHead; //pointer to stNodeHead of list
struct Char *stNodeTail;//pointer to stNodeTail of list
unsigned int length;
unsigned int Id;
};
struct StringBuilderNode
{
   struct StringBuilder *strBuild;
   struct StringBuilderNode *next;    //pointer to next Char
   struct StringBuilderNode *prev;    //pointer to previous Char
};

int ConstructStrBuildRLP(void *none, void **args, unsigned int argsCount, unsigned int *argData)
	{
	return ConstructStringBuilder();
	}
int DisposeStrBuildRLP(void *none, void **args, unsigned int argsCount, unsigned int *argData)
	{
    unsigned int id = *(unsigned int*)args[0];
	struct  StringBuilderNode * strBuildNode = GetStringBuilderNode(id);
	ClearStrBuild(strBuildNode->strBuild);
    RemoveStrBuildNode(strBuildNode);
    return 0;
	}
int GetStringRLP(unsigned char *ch, void **args, unsigned int argsCount, unsigned int *argData)
	{
	int i, Length = *( int*)args[0];
    unsigned int id = *(unsigned int*)args[1];
	struct StringBuilder * strBuild = GetStringBuilder(id);

	struct Char* curr = strBuild->stNodeHead;

	for(i = 0; i < Length && (curr!=NULL); i++, curr=curr->next)
		{
		 ch[i] = (unsigned char) curr->charData;
		}

	return strBuild->length;
	}
int GetStringLengthRLP(void *none, void **args, unsigned int argsCount, unsigned int *argData)
	{
	  unsigned int id = *(unsigned int*)args[0];
	  struct StringBuilder * strBuild = GetStringBuilder(id);

	return strBuild->length;
	}
int AppendCharRLP(void *none, void **args, unsigned int argsCount, unsigned int *argData)
	{
    unsigned int id = *(unsigned int*)args[1];
	struct StringBuilder * strBuild = GetStringBuilder(id);

	AddBack(*(char*)args[0],strBuild);

    return strBuild->length;
	}
int AppendStringRLP(void *none, void **args, unsigned int argsCount, unsigned int *argData)
	{
	char * str = ( char*)args[0];
	int i, Length = *( int*)args[1];
	unsigned int id = *(unsigned int*)args[2];
	struct StringBuilder * strBuild = GetStringBuilder(id);

	for(i = 0; i < Length; i++)
		{
		AddBack(str[i],strBuild);
		}

	return strBuild->length;
	}
int ContainsStringRLP(void *none, void **args, unsigned int argsCount, unsigned int *argData)
	{
	char *find = ( char*)args[0];
	int find_Length = *( int*)args[1];
	unsigned int id = *(unsigned int*)args[2];

	struct StringBuilder * strBuild = GetStringBuilder(id);

	if(ContainsString(find,find_Length, strBuild) != NULL)
		return 1;

	return 0;
	}
int ClearStrBuildRLP(void *none, void **args, unsigned int argsCount, unsigned int *argData)
	{
	 unsigned int id = *(unsigned int*)args[0];
	 struct StringBuilder * strBuild = GetStringBuilder(id);

	 ClearStrBuild(strBuild);
	 strBuild->length = 0;
	 return 0;
	}

struct Char* ContainsString(char * find, int length, struct StringBuilder * strBuild)
	{
	 	struct Char* subject;
		struct Char* hold;
		int i;

		subject= strBuild->stNodeHead;

	while(subject!=NULL)
		{
			if(subject->charData == find[0] )
				{
				//Hold here while testing
				hold = subject;

				  for(i=0; i < length && subject != NULL; i++, subject=subject->next)
					{
							if (subject->charData != find [i] )
							break;
						else
								if ( i + 1 >= length )
								return hold;
					}

				  //Continue search from last stop
				   subject = hold;
				}

			subject=subject->next;
		}

   return NULL;
	}
void AddtBefore(char ch, struct Char *nodeB, struct StringBuilder * strBuild)
	{
	//insert a Char before nodeB
		struct Char *newNode;
		newNode= (struct Char *)  RLPext->malloc(sizeof(struct Char));  

		newNode->prev=nodeB->prev;
		newNode->next =nodeB;
		newNode->charData =ch;

		if(nodeB->prev==NULL)
		{
		strBuild->stNodeHead=newNode;
		}

	nodeB->prev=newNode;
	RemoveChar(newNode,strBuild);
	strBuild->length++;
	}
void AddFront (char ch, struct StringBuilder * strBuild)
		{
		//insert a Char before the front Char
			struct Char *newNode;

			if(strBuild->stNodeHead==NULL)
			{
				newNode= (struct Char *)  RLPext->malloc(sizeof(struct Char));   

				strBuild->stNodeHead=newNode;
				strBuild->stNodeTail =newNode;

				 newNode->prev=NULL;
				 newNode->next=NULL;
				 newNode->charData=ch;
				 strBuild->length++;
			}
			else
			{
				 AddtBefore(ch,strBuild->stNodeHead ,strBuild);
			}
		}
void AddAfter(char ch,struct  Char *nodeB, struct StringBuilder * strBuild)
	{
	//insert a Char after  nodeB
		struct Char *newNode;
		newNode= (struct Char *)  RLPext->malloc(sizeof(struct Char));  

		newNode->next= nodeB->next ;
		newNode->prev  =nodeB;
		newNode->charData =ch;

		if(nodeB->next==NULL)
		strBuild->stNodeTail =newNode;

		nodeB->next=newNode;
		strBuild->length++;
	}
void AddBack (char ch, struct StringBuilder * strBuild)
	{
	//insert a Char after the last Char
			if(strBuild->stNodeTail==NULL)
				AddFront(ch,strBuild);
			else
				AddAfter(ch, strBuild->stNodeTail,strBuild  );
	}
int RemoveChar(struct  Char *chNode, struct StringBuilder * strBuild)
{//remove a perticular Char
if((chNode==strBuild->stNodeTail) && (chNode==strBuild->stNodeHead) && (strBuild->stNodeHead != NULL))
		{
		 RLPext->free(chNode);
		chNode = NULL;
		strBuild->stNodeHead = NULL;
		strBuild->stNodeTail = NULL;
		return 1;
		}
else if( (chNode==strBuild->stNodeHead) && (strBuild->stNodeHead != NULL))
	{
		strBuild->stNodeHead=strBuild->stNodeHead->next;
		strBuild->stNodeHead->prev=NULL;
		 RLPext->free(chNode);
		return 1;
	}
	else if ( (chNode==strBuild->stNodeTail) && (strBuild->stNodeTail != NULL))
	{
		strBuild->stNodeTail=strBuild->stNodeTail->prev;
		strBuild->stNodeTail->next=NULL	;
		 RLPext->free(chNode);
		return 1;
	}
	else
	{
	chNode->prev->next=chNode->next;
	chNode->next->prev=chNode->prev;
	 RLPext->free(chNode);
	return 1;
	}

 return 0;
}
void ClearStrBuild(struct StringBuilder * strBuild)
	{ 
	while(strBuild->stNodeHead != NULL)
		  {
		  RemoveChar(strBuild->stNodeHead,strBuild);
		  }

	strBuild->length = 0;
	}

/***************************StringBuilder List******************************************/

struct StringBuilderNode *stNodeHead=NULL;
struct StringBuilderNode *stNodeTail = NULL;
static unsigned int stNodeIdCount = 10;

struct StringBuilderNode* GetStringBuilderNode(unsigned int id)
{
   struct StringBuilderNode* currBuff;

   for (currBuff = stNodeHead; currBuff != NULL; currBuff = currBuff->next)
	   {
	   if ( (currBuff->strBuild)->Id == id) return currBuff;
       }

   return NULL;
}
struct StringBuilder* GetStringBuilder(unsigned int id)
{
return GetStringBuilderNode(id)->strBuild;
}
struct StringBuilder* InitializeStringBuilder(unsigned int newId )
{
   struct StringBuilder* newStrBuild = (struct StringBuilder *)  RLPext->malloc(sizeof(struct StringBuilder)); 

   if(newStrBuild==NULL)
   {
      return NULL; //Error
   }

   ////Initializes the strBuild
   newStrBuild->stNodeTail = NULL;
   newStrBuild->stNodeHead = NULL;
   newStrBuild->length = 0;
   newStrBuild->Id = newId;

   return newStrBuild; //Return new strBuild
}
unsigned int ConstructStringBuilder()
	{
	unsigned int id = stNodeIdCount;
	struct StringBuilder* newStrBuild;

	newStrBuild = InitializeStringBuilder(id);
	stNodeIdCount++;

	InsertStrTail(newStrBuild);

	return id;
	}
void ClearAllStrBuildNode()
	{
	  while(stNodeHead != NULL)
		  {
		  RemoveStrBuildNode(stNodeHead);
		  }
	}
int RemoveStringBuilder(unsigned int id)
	{
	struct StringBuilderNode* currBuff;
	currBuff = GetStringBuilderNode(id);
	return RemoveStrBuildNode(currBuff);
	}
int RemoveStrBuildNode(struct  StringBuilderNode *strBuildNode)
{
    if((strBuildNode==stNodeTail) && (strBuildNode==stNodeHead) && (stNodeHead != NULL))
		{
		 RLPext->free(strBuildNode);
		strBuildNode = NULL;
		stNodeHead = NULL;
		stNodeTail = NULL;

		return 1;
		}
	else if( (strBuildNode==stNodeHead) && (stNodeHead != NULL))
	{
		stNodeHead=stNodeHead->next;
		stNodeHead->prev=NULL;
		 RLPext->free(strBuildNode);

		return 1;
	}
	else if ( (strBuildNode==stNodeTail) && (stNodeTail != NULL))
	{
		stNodeTail=stNodeTail->prev;
		stNodeTail->next=NULL	;
	     RLPext->free(strBuildNode);

		return 1;
	}
	else
	{
	strBuildNode->prev->next=strBuildNode->next;
	strBuildNode->next->prev=strBuildNode->prev;
    RLPext->free(strBuildNode);

	return 1;
	}

 return 0;
}
void InsertStrTail (struct StringBuilder *strBuild)
	{
			if(stNodeTail==NULL)
			InsertStrHead(strBuild);
			else
			InsertStrAfter(strBuild, stNodeTail);
	}
void InsertStrHead (struct StringBuilder* newBuff)
		{
			struct StringBuilderNode *newNode;

			if(stNodeHead==NULL)
			{
				newNode= (struct StringBuilderNode *)  RLPext->malloc(sizeof(struct StringBuilderNode));  

				stNodeHead=newNode;
				stNodeTail =newNode;

				 newNode->prev=NULL;
				 newNode->next=NULL;
				 newNode->strBuild=newBuff;
			}
			else
			{
				 InsertStrBefore(newBuff,stNodeHead );
			}
		}
void InsertStrAfter(struct StringBuilder* newBuff,struct  StringBuilderNode *nodeB)
	{
		struct StringBuilderNode* newNode;
		newNode = (struct StringBuilderNode *)  RLPext->malloc(sizeof(struct StringBuilderNode)); 

		newNode->next= nodeB->next ;
		newNode->prev  =nodeB;
		newNode->strBuild =newBuff;

		if(nodeB->next==NULL)
		stNodeTail = newNode;

		nodeB->next=newNode;
	}
void InsertStrBefore(struct StringBuilder* newBuff, struct StringBuilderNode *nodeB)
	{
		struct StringBuilderNode *newNode;
		newNode= (struct StringBuilderNode *)  RLPext->malloc(sizeof(struct StringBuilderNode));   

		newNode->prev = nodeB->prev;
		newNode->next = nodeB;
		newNode->strBuild =newBuff;

		if(nodeB->prev==NULL)
		{
		stNodeHead=newNode;
		}

	nodeB->prev=newNode;
	RemoveStrBuildNode(newNode);//HACK: countStrBuild--;
	}


And Managed code here


 public class StringBuilderRLP
    {
        #region [Fields ]
        static RLP.Procedure  ConstructStrBuildRLP;
        static RLP.Procedure  DisposeStrBuildRLP;
        static RLP.Procedure  GetStringRLP;
        static RLP.Procedure  GetStringLengthRLP;
        static RLP.Procedure  AppendCharRLP;
        static RLP.Procedure  AppendStringRLP;
        static RLP.Procedure  ContainsStringRLP;
        static RLP.Procedure  ClearStrBuildRLP;
        private int STRINGBUILDER_ID;
        #endregion [Fields ]

        #region [ Property ]

        /// <summary>
        /// Get the length of the string
        /// </summary>
        public int Length { get { if ( GetStringLengthRLP != null ) return GetStringLengthRLP.Invoke( STRINGBUILDER_ID ); else return 0; } }

        #endregion [ Property ]

        #region [ Constructors ]

        #region [RLP]
        public static void GetProcedure( byte [] elf_file )
        {
            try
            {
                if ( ConstructStrBuildRLP == null )
                {
                    ConstructStrBuildRLP = RLP.GetProcedure( elf_file, "ConstructStrBuildRLP" );
                    DisposeStrBuildRLP = RLP.GetProcedure( elf_file, "DisposeStrBuildRLP" );
                    GetStringRLP = RLP.GetProcedure( elf_file, "GetStringRLP" );
                    GetStringLengthRLP = RLP.GetProcedure( elf_file, "GetStringLengthRLP" );
                    AppendCharRLP = RLP.GetProcedure( elf_file, "AppendCharRLP" );
                    AppendStringRLP = RLP.GetProcedure( elf_file, "AppendStringRLP" );
                    ContainsStringRLP = RLP.GetProcedure( elf_file, "ContainsStringRLP" );
                    ClearStrBuildRLP = RLP.GetProcedure( elf_file, "ClearStrBuildRLP" );
                }
            }
            catch ( Exception )
            {
                throw;
            }
        }

        #endregion [RLP]

        public StringBuilderRLP( string InitialValue )
        {
            try
            {
                STRINGBUILDER_ID = ConstructStrBuildRLP.Invoke();
                Append( InitialValue );
            }
            catch ( Exception )
            {
                throw;
            }
        }

        public StringBuilderRLP()
        {
            try
            {
                STRINGBUILDER_ID = ConstructStrBuildRLP.Invoke();
            }
            catch ( Exception )
            {
            }
        }

        #endregion [ Constructors ]

        #region [ Public Methods ]

        public void Append( string stringToAppend )
        {
            if ( stringToAppend.Length == 0 ) return;

            try
            {
                AppendStringRLP.Invoke( stringToAppend, stringToAppend.Length, STRINGBUILDER_ID );
            }
            catch ( Exception )
            {
            }
        }

        public void Append( char charToAppend )
        {
            try
            {
                AppendCharRLP.Invoke( charToAppend, STRINGBUILDER_ID );
            }
            catch ( Exception )
            {
            }
        }

        /// <summary>
        /// Get the string
        /// </summary>
        /// <returns>The string that has been built</returns>
        public override string ToString()
        {
            byte [] temp = null;

            try
            {
                int size = Length;

                if ( !(size > 0) ) return string.Empty;

                temp = new byte [size];

                if ( GetStringRLP != null )
                    GetStringRLP.InvokeEx( temp, size, STRINGBUILDER_ID );

                return new string( temp.UTF8ByteArrayToChars() );
            }
            catch ( Exception )
            {
            }
            finally
            {
                temp = null;
            }

            return string.Empty;
        }

        /// <summary>
        /// Clear the string from memory
        /// </summary>
        public void Clear()
        {
            try
            {
                ClearStrBuildRLP.Invoke( STRINGBUILDER_ID );
            }
            catch ( Exception )
            {
            }
        }

        public bool Contains( string find )
        {
            try
            {
                if ( ContainsStringRLP.Invoke( find, find.Length, STRINGBUILDER_ID ) == 1 )
                    return true;
            }
            catch ( Exception )
            { }

            return false;
        }

        #endregion [ Public Methods ]

        #region [IDisposable Members]

        public void Dispose()
        {
            try
            {
                if ( DisposeStrBuildRLP != null )
                    DisposeStrBuildRLP.Invoke( STRINGBUILDER_ID );
            }
            catch ( Exception )
            {
            }
        }

        #endregion [IDisposable Members]
    }


#5

I think you will not be able to speed this up with native code. You need to many calls from/to native code which will not speed things up.

And I would also be concerned about memory. Your char struct uses 9 bytes per char…


struct Char
{
char charData;                 //ch stored in the Char
struct Char *next;          //pointer to next Char
struct Char *prev;          //pointer to previous Char
};

Do you have a finished AppendFormat method in managed code? If so, I would love to see it.


#6

I have dropped the ideawith RLP StringBuilder last night after some speed testing. I would stick to my manged StringBuilder.

here


using System;
using System.IO;
using System.Text;

namespace Utility.Text
{
    public class StringBuilder : IDisposable
    {
        #region [Fields ]

        /// <summary>
        /// The internal private copy of the string
        /// </summary>
        private char [] _storedString;
        /// <summary>
        /// The number of allocated characters
        /// </summary>
        private int lngAllocated;
        /// <summary>
        /// The number of used characters
        /// </summary>
        private int lngUsed;
        /// <summary>
        /// Number of characters to allocated with an increase
        /// </summary>
        private int lngAllocSize;

        #endregion [Fields ]

        #region [ Property ]

        /// <summary>
        /// Get the length of the string
        /// </summary>
        public int Length
        {
            get { return lngUsed; }
        }

        #endregion [ Property ]

        #region [ Constructors ]

        /// <summary>
        /// Constructor used to define a custom allocation size
        /// </summary>
        /// <param name="AllocationSize">The size of every allocation</param>
        public StringBuilder( int AllocationSize )
        {
            lngAllocSize = AllocationSize;
            lngAllocated = lngAllocSize;
            _storedString = new char [lngAllocSize];
        }

        /// <summary>
        /// The constructor used to set the initial value of the string
        /// </summary>
        /// <param name="InitialValue">The initial value of the string</param>
        /// <param name="AllocationSize">The size of every allocation</param>
        public StringBuilder( string InitialValue, int AllocationSize )
        {
            lngAllocSize = AllocationSize;
            lngAllocated = lngAllocSize;
            _storedString = new char [lngAllocSize];
            Append( InitialValue );
        }

        #endregion [ Constructors ]

        #region [ Public Methods ]

        /// <summary>
        /// Append a string to the internal string
        /// </summary>
        /// <param name="stringToAppend">The string to be appended</param>
        public void Append( string stringToAppend )
        {
            int lngLength;
            int lngToAllocate;

            lngLength = stringToAppend.Length;

            try
            {
                if ( lngLength > 0 )
                {
                    if ( lngLength + lngUsed > lngAllocated )
                    {
                        lngToAllocate = lngAllocSize * (1 + (lngUsed + lngLength - lngAllocated) / lngAllocSize);
                        lngAllocated += lngToAllocate;

                        _storedString = ResizeArray( _storedString, lngAllocated );
                    }
                    int counter = 0;

                    foreach ( char c in stringToAppend )
                    {
                        _storedString [lngUsed + counter] = c;
                        counter++;
                    }

                    lngUsed += lngLength;
                }
            }
            catch ( Exception )
            {
                throw;
            }
        }

        public void Append( char charToAppend )
        {
            int lngLength;
            int lngToAllocate;

            lngLength = 1;

            try
            {
                if ( lngLength > 0 )
                {
                    if ( lngLength + lngUsed > lngAllocated )
                    {
                        lngToAllocate = lngAllocSize * (1 + (lngUsed + lngLength - lngAllocated) / lngAllocSize);
                        lngAllocated += lngToAllocate;

                        _storedString = ResizeArray( _storedString, lngAllocated );
                    }
                    _storedString [lngUsed] = charToAppend;

                    lngUsed += lngLength;
                }
            }
            catch ( Exception )
            {
                throw;
            }
        }

        /// <summary>
        /// Overwrite the string with the specified string
        /// </summary>
        /// <param name="StringToWrite">The new string value of the string</param>
        public void Overwrite( string StringToWrite )
        {
            Clear();
            Append( StringToWrite );
        }

        /// <summary>
        /// Get the string
        /// </summary>
        /// <returns>The string that has been built</returns>
        public override string ToString()
        {
            string returnString = new string( _storedString, 0, lngUsed );
            return returnString;
        }

        /// <summary>
        /// Clear the string from memory
        /// </summary>
        public void Clear()
        {
            _storedString = null;
            lngUsed = 0;
            lngAllocated = lngAllocSize;
            _storedString = new char [lngAllocSize];
        }

        #endregion [ Public Methods ]

        #region [ Private Methods ]

        /// <summary>
        /// Resize the internal array
        /// </summary>
        /// <param name="oldArray">The old array to resize</param>
        /// <param name="newSize">The new size of the expanded array</param>
        /// <returns>a New bigger array with all the contents of the old array</returns>
        private char [] ResizeArray( System.Array oldArray, int newSize )
        {
            char [] newArray = new char [newSize];
            oldArray.CopyTo( newArray, 0 );

            return newArray;
        }

        #endregion [ Private Methods ]

        #region [IDisposable Members]

        public void Dispose()
        {
            _storedString = null;
        }

        #endregion [IDisposable Members]
    }
}