Mega Code Archive

 
Categories / C# / Data Types
 

Buffer for characters

// CharBuffer.cs //  // Copyright (C) 2003-2004 Ryan Seghers // // This software is provided AS IS. No warranty is granted,  // neither expressed nor implied. USE THIS SOFTWARE AT YOUR OWN RISK. // NO REPRESENTATION OF MERCHANTABILITY or FITNESS FOR ANY  // PURPOSE is given. // // License to use this software is limited by the following terms: // 1) This code may be used in any program, including programs developed //    for commercial purposes, provided that this notice is included verbatim. //     // Also, in return for using this code, please attempt to make your fixes and // updates available in some way, such as by sending your updates to the // author. using System; namespace RTools_NTS.Util {   /// <summary>   /// Buffer for characters.  This approximates StringBuilder   /// but is designed to be faster for specific operations.   /// This is about 30% faster for the operations I'm interested in   /// (Append, Clear, Length, ToString).   /// This trades off memory for speed.   /// </summary>   /// <remarks>   /// <para>To make Remove from the head fast, this is implemented   /// as a ring buffer.</para>   /// <para>This uses head and tail indices into a fixed-size    /// array. This will grow the array as necessary.</para>   /// </remarks>   public class CharBuffer   {     #region Fields     int capacity = 128;     char[] buffer;     int headIndex;  // index of first char     int tailIndex;  // index 1 past last char     #endregion     #region Properties     /// <summary>     /// Gets/Sets the number of characters in the character buffer.     /// Increasing the length this way provides indeterminate results.     /// </summary>     public int Length     {       get { return(tailIndex - headIndex); }       set        {          tailIndex = headIndex + value;         if (tailIndex >= capacity) throw new            IndexOutOfRangeException("Tail index greater than capacity");       }     }     /// <summary>     /// Returns the capacity of this character buffer.     /// </summary>     public int Capacity     {       get { return(capacity); }     }     #endregion     #region Constructors     /// <summary>     /// Default constructor.     /// </summary>     public CharBuffer()     {       buffer = new char[capacity];     }     /// <summary>     /// Construct with a specific capacity.     /// </summary>     /// <param name="capacity"></param>     public CharBuffer(int capacity)     {       this.capacity = capacity;       buffer = new char[capacity];     }     #endregion     #region Non-Public Methods     /// <summary>     /// Reallocate the buffer to be larger. For the new size, this     /// uses the max of the requested length and double the current     /// capacity.     /// This does not shift, meaning it does not change the head or     /// tail indices.     /// </summary>     /// <param name="requestedLen">The new requested length.</param>     protected void Grow(int requestedLen)     {       int newLen = Math.Max(capacity*2, requestedLen);       newLen = Math.Max(newLen, 16);       char[] newBuffer = new char[newLen];       Array.Copy(buffer, 0, newBuffer, 0, capacity);       buffer = newBuffer;       capacity = newLen;     }     /// <summary>     /// Ensure that we're set for the requested length by      /// potentially growing or shifting contents.     /// </summary>     /// <param name="requestedLength"></param>     protected void CheckCapacity(int requestedLength)     {       if (requestedLength + headIndex >= capacity)       {         // have to do something         if ((requestedLength + headIndex > (capacity >> 1))           && (requestedLength < capacity - 1))         {           // we're more than half-way through the buffer, and shifting is enough           // so just shift           ShiftToZero();         }         else         {           // not far into buffer or shift wouldn't be enough anyway           Grow(0);         }       }     }     /// <summary>     /// Move the buffer contents such that headIndex becomes 0.     /// </summary>     protected void ShiftToZero()     {       int len = Length;       for (int i = 0; i < len; i++)       {         buffer[i] = buffer[i + headIndex];       }       headIndex = 0;       tailIndex = len;     }     #endregion     #region Public Methods and Indexer     /// <summary>     /// Overwrite this object's underlying buffer with the specified     /// buffer.     /// </summary>     /// <param name="b">The character array.</param>     /// <param name="len">The number of characters to consider filled     /// in the input buffer.</param>     public void SetBuffer(char[] b, int len)     {       capacity = b.Length;       buffer = b;       headIndex = 0;       tailIndex = len;     }     /// <summary>     /// Append a character to this buffer.     /// </summary>     /// <param name="c"></param>     public void Append(char c)     {       if (tailIndex >= capacity) CheckCapacity(Length + 1);       buffer[tailIndex++] = c;     }     /// <summary>     /// Append a string to this buffer.     /// </summary>     /// <param name="s">The string to append.</param>     public void Append(string s)     {       if (s.Length + tailIndex >= capacity) CheckCapacity(Length + s.Length);       for(int i = 0; i < s.Length; i++)         buffer[tailIndex++] = s[i];     }     /// <summary>     /// Append a string to this buffer.     /// </summary>     /// <param name="s">The string to append.</param>     public void Append(CharBuffer s)     {       if (s.Length + tailIndex >= capacity) CheckCapacity(Length + s.Length);       for(int i = 0; i < s.Length; i++)         buffer[tailIndex++] = s[i];     }     /// <summary>     /// Remove a character at the specified index.     /// </summary>     /// <param name="i">The index of the character to remove.</param>     /// <returns></returns>     public void Remove(int i)     {       Remove(i, 1);     }     /// <summary>     /// Remove a specified number of characters at the specified index.     /// </summary>     /// <param name="i">The index of the characters to remove.</param>     /// <param name="n">The number of characters to remove.</param>     public void Remove(int i, int n)     {       n = Math.Min(n, Length);       if (i == 0)       {         headIndex += n;       }       else       {         Array.Copy(buffer, i + headIndex + n, buffer, i + headIndex,            tailIndex - (i + headIndex + n));       }     }     /// <summary>     /// Find the first instance of a character in the buffer, and     /// return its index.  This returns -1 if the character is     /// not found.     /// </summary>     /// <param name="c">The character to find.</param>     /// <returns>The index of the specified character, or -1     /// for not found.</returns>     public int IndexOf(char c)     {       for (int i = headIndex; i < tailIndex; i++)       {         if (buffer[i] == c) return(i - headIndex);       }       return(-1);     }     /// <summary>     /// Empty the buffer.     /// </summary>     public void Clear()     {       headIndex = 0;       tailIndex = 0;     }     /// <summary>     /// Indexer.     /// </summary>     public char this [int index]     {       get { return(buffer[index + headIndex]); }       set { buffer[index + headIndex] = value; }     }     /// <summary>     /// Return the current contents as a string.     /// </summary>     /// <returns>The new string.</returns>     public override String ToString()     {       return(new String(buffer, headIndex, tailIndex - headIndex));     }     #endregion       } }