// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== //============================================================ // // Class: StringBuilder // // Purpose: A prototype implementation of the StringBuilder // class. // //=========================================================== namespace System.Text { using System.Text; using System.Threading; using System; using System.Diagnostics; using System.Runtime.CompilerServices; // This class represents a mutable string. It is convenient for situations in // which it is desirable to modify a string, perhaps by removing, replacing, or // inserting characters, without creating a new String subsequent to // each modification. // // The methods contained within this class do not return a new StringBuilder // object unless specified otherwise. This class may be used in conjunction with the String // class to carry out modifications upon strings. // // When passing null into a constructor in VJ and VC, the null // should be explicitly type cast. // For Example: // StringBuilder sb1 = new StringBuilder((StringBuilder)null); // StringBuilder sb2 = new StringBuilder((String)null); // //| public sealed partial class StringBuilder { // // // CLASS VARIABLES // // internal int m_currentThread = InternalGetCurrentThread(); internal int m_MaxCapacity = 0; // // // STATIC CONSTANTS // // private const int DEFAULT_CAPACITY = 16; private const int DEFAULT_MAX_CAPACITY = 0x7FFFFFFF; // // //CONSTRUCTORS // // // Creates a new empty string builder (i.e., it represents String.Empty) // with the default capacity (16 characters). //| public StringBuilder() : this(DEFAULT_CAPACITY) { } // Create a new empty string builder (i.e., it represents String.Empty) // with the specified capacity. //| public StringBuilder(int capacity) { if (capacity < 0) { throw new ArgumentOutOfRangeException("capacity"); } if (capacity == 0) { // MakeFromString enforces this capacity = DEFAULT_CAPACITY; } m_StringValue = String.GetStringForStringBuilder(String.Empty, capacity); m_MaxCapacity = Int32.MaxValue; } //=======================CalculateCapacity=============================== // Calculates the new capacity of our buffer. If the size of the // buffer is less than a fixed number (10000 in this case), we just // double the buffer until we have enough space. Once we get larger // than 10000, we use a series of heuristics to determine the most // appropriate size. //====================================================================== private int CalculateCapacity(int currentCapacity, int neededCapacity) { // See also Lightning\Src\VM\COMStringBuffer.cpp::CalculateCapaity int newCapacity = neededCapacity; if (newCapacity == 0) { newCapacity = DEFAULT_CAPACITY; } if (neededCapacity > this.m_MaxCapacity) { throw new ArgumentOutOfRangeException("exceeding max capacity"); } while (newCapacity < neededCapacity && newCapacity > 0) { newCapacity <<= 1; } // Check for overflow if (newCapacity <= 0) { // The C++ code throws on overflow, but it really should not newCapacity = this.m_MaxCapacity; } else if (newCapacity > this.m_MaxCapacity) { // We doubled past the max capacity, so back down a bit newCapacity = this.m_MaxCapacity; } return newCapacity; } // Creates a new string builder from the specified string. If value // is a null String (i.e., if it represents String.NullString) // then the new string builder will also be null (i.e., it will also represent // String.NullString). // //| public StringBuilder(String value){ MakeFromString(value, 0, -1, -1); } // Creates a new string builder from the specified string with the specified // capacity. If value is a null String (i.e., if it represents // String.NullString) then the new string builder will also be null // (i.e., it will also represent String.NullString). // The maximum number of characters this string may contain is set by capacity. // //| public StringBuilder(String value, int capacity) { if (capacity < 0) { throw new ArgumentOutOfRangeException("capacity", String.Format("ArgumentOutOfRange_MustBePositive", "capacity")); } MakeFromString(value, 0, -1, capacity); } // Creates a new string builder from the specified substring with the specified // capacity. The maximum number of characters is set by capacity. // //| public StringBuilder(String value, int startIndex, int length, int capacity) { if (capacity < 0) { throw new ArgumentOutOfRangeException("capacity", String.Format("ArgumentOutOfRange_MustBePositive", "capacity")); } if (length < 0) { throw new ArgumentOutOfRangeException("length", String.Format("ArgumentOutOfRange_MustBeNonNegNum", "length")); } MakeFromString(value, startIndex, length, capacity); } // Creates an empty StringBuilder with a minimum capacity of capacity // and a maximum capacity of maxCapacity. //| public StringBuilder(int capacity, int maxCapacity) { if (capacity > maxCapacity) { throw new ArgumentOutOfRangeException("capacity", "ArgumentOutOfRange_Capacity"); } if (maxCapacity < 1) { throw new ArgumentOutOfRangeException("maxCapacity", "ArgumentOutOfRange_SmallMaxCapacity"); } if (capacity < 0) { throw new ArgumentOutOfRangeException("capacity", String.Format("ArgumentOutOfRange_MustBePositive", "capacity")); } if (capacity == 0) { capacity = DEFAULT_CAPACITY; } m_StringValue = String.GetStringForStringBuilder(String.Empty, capacity); m_MaxCapacity = maxCapacity; } private String GetThreadSafeString(out int tid) { String temp = m_StringValue; tid = InternalGetCurrentThread(); if (m_currentThread == tid) return temp; return String.GetStringForStringBuilder(temp, temp.Capacity); } private static int InternalGetCurrentThread() { return Thread.CurrentThread.GetThreadId(); } // // Private native functions // //=========================MakeFromString================================ // If value is null, we simply create an empty string with a default // length. If it does contain data, we allocate space for twice this // amount of data, copy the data, associate it with the StringBuffer // and clear the CopyOnWrite bit. //======================================================================= private void MakeFromString(String value, int startIndex, int length, int capacity) { // See also Lightning\Src\VM\COMStringBuffer.cpp::MakeFromString if (capacity <= 0) { capacity = DEFAULT_CAPACITY; } this.m_MaxCapacity = DEFAULT_MAX_CAPACITY; if (value != null) { if (startIndex < 0) { throw new ArgumentOutOfRangeException("negative startIndex"); } int stringLength = value.Length; if (length == -1) { length = stringLength - startIndex; } else if (length + startIndex > stringLength) { throw new ArgumentOutOfRangeException("exceeding string length"); } int newCapacity = this.CalculateCapacity(capacity, length); String newString = String.GetStringForStringBuilder(String.Empty, newCapacity); newString.AppendInPlace(value, startIndex, length, 0); this.m_StringValue = newString; } else if (capacity == 0) { this.m_StringValue = String.Empty; } else { this.m_StringValue = String.GetStringForStringBuilder(String.Empty, capacity); } } //| public int Capacity { get {return m_StringValue.Capacity;} //-1 to account for terminating null. set {InternalSetCapacity(value);} } //| public int MaxCapacity { get { return m_MaxCapacity; } } // Read-Only Property // Ensures that the capacity of this string builder is at least the specified value. // If capacity is greater than the capacity of this string builder, then the capacity // is set to capacity; otherwise the capacity is unchanged. // //| public int EnsureCapacity(int capacity) { if (capacity < 0) { throw new ArgumentOutOfRangeException("capacity", "ArgumentOutOfRange_NeedPosCapacity"); } int tid; String currentString = GetThreadSafeString(out tid); //If we need more space or the COW bit is set, copy the buffer. if (!NeedsAllocation(currentString,capacity)) { return currentString.Capacity; } String newString = GetNewString(currentString,capacity); ReplaceString(tid,newString); return newString.Capacity; } //Sets the capacity to be capacity. If capacity is less than the current //instance an ArgumentException is thrown. If capacity is greater than the current //instance, memory is allocated to allow the StringBuilder to grow. // internal int InternalSetCapacity(int capacity) { // See also Lighting\Src\VM\COMStringBuffer.cpp::SetCapacity // The return value of the native code is a pointer to 'this', but // since it isn't ever used, we return 0; int tid; String thisString = GetThreadSafeString(out tid); if (capacity < 0) { throw new ArgumentOutOfRangeException("capacity is negative"); } if (capacity < thisString.Length) { throw new ArgumentOutOfRangeException("capacity lesser than size"); } if (capacity > this.m_MaxCapacity) { throw new ArgumentOutOfRangeException("exceeds max capacity"); } if (capacity != this.m_StringValue.ArrayLength - 1) { this.m_StringValue = CopyString(this,thisString,capacity); this.m_currentThread = tid; } return 0; } private String CopyString(StringBuilder thisRef,String CurrString, int newCapacity) { int CurrLen = CurrString.Length; int copyLength; if (newCapacity >= CurrLen) { copyLength = CurrLen; } else { copyLength = newCapacity; } return String.NewString(CurrString,0,copyLength,newCapacity); } //| public override String ToString() { String currentString = m_StringValue; int currentThread = m_currentThread; if (currentThread != 0 && currentThread != InternalGetCurrentThread()) { return String.InternalCopy(currentString); } if ((2 * currentString.Length) < currentString.ArrayLength) { return String.InternalCopy(currentString); } currentString.ClearPostNullChar(); m_currentThread = 0; return currentString; } // Converts a substring of this string builder to a String. //| public String ToString(int startIndex, int length) { return m_StringValue.Substring(startIndex, length); } // Sets the length of the String in this buffer. If length is less than the current // instance, the StringBuilder is truncated. If length is greater than the current // instance, nulls are appended. The capacity is adjusted to be the same as the length. //| public int Length { get { return m_StringValue.Length; } set { int tid; String currentString = GetThreadSafeString(out tid); if (value == 0) { //the user is trying to clear the string currentString.SetLength(0); ReplaceString(tid,currentString); return; } int currentLength = currentString.Length; int newlength = value; //If our length is less than 0 or greater than our Maximum capacity, bail. if (newlength < 0) { throw new ArgumentOutOfRangeException("newlength", "ArgumentOutOfRange_NegativeLength"); } if (newlength > MaxCapacity) { throw new ArgumentOutOfRangeException("capacity", "ArgumentOutOfRange_SmallCapacity"); } //Jump out early if our requested length our currentlength. //This will be a pretty rare branch. if (newlength == currentLength) { return; } //If the StringBuilder has never been converted to a string, simply set the length //without allocating a new string. if (newlength <= currentString.Capacity) { if (newlength > currentLength) { for (int i = currentLength; i < newlength; i++) // This is a rare case anyway. currentString.InternalSetCharNoBoundsCheck(i,'\0'); } currentString.InternalSetCharNoBoundsCheck(newlength,'\0'); //Null terminate. currentString.SetLength(newlength); ReplaceString(tid,currentString); return; } // CopyOnWrite set we need to allocate a String int newCapacity = (newlength>currentString.Capacity)?newlength:currentString.Capacity; String newString = String.GetStringForStringBuilder(currentString, newCapacity); //We know exactly how many characters we need, so embed that knowledge in the String. newString.SetLength(newlength); ReplaceString(tid,newString); } } //| public char this[int index] { get { return m_StringValue[index]; } set { int tid; String currentString = GetThreadSafeString(out tid); currentString.SetChar(index, value); ReplaceString(tid,currentString); } } // Appends a character at the end of this string builder. The capacity is adjusted as needed. //| public StringBuilder Append(char value, int repeatCount) { if (repeatCount == 0) { return this; } if (repeatCount < 0) { throw new ArgumentOutOfRangeException("repeatCount", "ArgumentOutOfRange_NegativeCount"); } int tid; String currentString = GetThreadSafeString(out tid); int currentLength = currentString.Length; int requiredLength = currentLength + repeatCount; if (requiredLength < 0) throw new OutOfMemoryException(); if (!NeedsAllocation(currentString,requiredLength)) { currentString.AppendInPlace(value, repeatCount,currentLength); ReplaceString(tid,currentString); return this; } String newString = GetNewString(currentString,requiredLength); newString.AppendInPlace(value, repeatCount,currentLength); ReplaceString(tid,newString); return this; } // Appends an array of characters at the end of this string builder. The capacity is adjusted as needed. //| public StringBuilder Append(char[] value, int startIndex, int charCount) { int requiredLength; if (value == null) { if (startIndex == 0 && charCount == 0) { return this; } throw new ArgumentNullException("value"); } if (charCount == 0) { return this; } if (startIndex < 0) { throw new ArgumentOutOfRangeException("startIndex", "ArgumentOutOfRange_GenericPositive"); } if (charCount < 0) { throw new ArgumentOutOfRangeException("count", "ArgumentOutOfRange_GenericPositive"); } if (charCount > value.Length - startIndex) { throw new ArgumentOutOfRangeException("count", "ArgumentOutOfRange_Index"); } int tid; String currentString = GetThreadSafeString(out tid); int currentLength = currentString.Length; requiredLength = currentLength + charCount; if (NeedsAllocation(currentString,requiredLength)) { String newString = GetNewString(currentString,requiredLength); newString.AppendInPlace(value, startIndex, charCount,currentLength); ReplaceString(tid,newString); } else { currentString.AppendInPlace(value, startIndex, charCount,currentLength); ReplaceString(tid,currentString); } return this; } // Appends a copy of this string at the end of this string builder. //| public StringBuilder Append(String value) { //If the value being added is null, eat the null //and return. if (value == null) { return this; } int tid; // hand inlining of GetThreadSafeString String currentString = m_StringValue; tid = InternalGetCurrentThread(); if (m_currentThread != tid) currentString = String.GetStringForStringBuilder(currentString, currentString.Capacity); int currentLength = currentString.Length; int requiredLength = currentLength + value.Length; if (NeedsAllocation(currentString,requiredLength)) { String newString = GetNewString(currentString,requiredLength); newString.AppendInPlace(value,currentLength); ReplaceString(tid,newString); } else { currentString.AppendInPlace(value,currentLength); ReplaceString(tid,currentString); } return this; } internal unsafe StringBuilder Append(char *value, int count) { //If the value being added is null, eat the null //and return. if (value == null) { return this; } int tid; String currentString = GetThreadSafeString(out tid); int currentLength = currentString.Length; int requiredLength = currentLength + count; if (NeedsAllocation(currentString,requiredLength)) { String newString = GetNewString(currentString,requiredLength); newString.AppendInPlace(value, count,currentLength); ReplaceString(tid,newString); } else { currentString.AppendInPlace(value,count,currentLength); ReplaceString(tid,currentString); } return this; } private bool NeedsAllocation(String currentString,int requiredLength) { //<= accounts for the terminating 0 which we require on strings. return (currentString.ArrayLength<=requiredLength); } private String GetNewString(String currentString, int requiredLength) { int newCapacity; requiredLength++; //Include the terminating null. if (requiredLength < 0) { throw new OutOfMemoryException(); } if (requiredLength > m_MaxCapacity) { throw new ArgumentOutOfRangeException("ArgumentOutOfRange_NegativeCapacity", "requiredLength"); } newCapacity = ( currentString.Capacity)*2; // To force a predictable growth of 160,320 etc. for testing purposes if (newCapacity < requiredLength) { newCapacity = requiredLength; } if (newCapacity > m_MaxCapacity) { newCapacity = m_MaxCapacity; } if (newCapacity <= 0) { throw new ArgumentOutOfRangeException("ArgumentOutOfRange_NegativeCapacity"); } return String.GetStringForStringBuilder( currentString, newCapacity); } private void ReplaceString(int tid, String value) { Debug.Assert(value!=null, "[StringBuilder.ReplaceString]value!=null"); m_currentThread = tid; // new owner m_StringValue = value; } // Appends a copy of the characters in value from startIndex to startIndex + // count at the end of this string builder. //| public StringBuilder Append(String value, int startIndex, int count) { //If the value being added is null, eat the null //and return. if (value == null) { if (startIndex == 0 && count == 0) { return this; } throw new ArgumentNullException("value"); } if (count <= 0) { if (count == 0) { return this; } throw new ArgumentOutOfRangeException("count", "ArgumentOutOfRange_GenericPositive"); } if (startIndex < 0 || (startIndex > value.Length - count)) { throw new ArgumentOutOfRangeException("startIndex", "ArgumentOutOfRange_Index"); } int tid; String currentString = GetThreadSafeString(out tid); int currentLength = currentString.Length; int requiredLength = currentLength + count; if (NeedsAllocation(currentString,requiredLength)) { String newString = GetNewString(currentString,requiredLength); newString.AppendInPlace(value, startIndex, count, currentLength); ReplaceString(tid,newString); } else { currentString.AppendInPlace(value, startIndex, count, currentLength); ReplaceString(tid,currentString); } return this; } // Inserts multiple copies of a string into this string builder at the specified position. // Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. If value equals String.Empty, this // string builder is not changed. Inserts ";<;no object>;"; if value // is null. // //| public unsafe StringBuilder Insert(int index, String value, int count) { int tid; String currentString = GetThreadSafeString(out tid); int currentLength = currentString.Length; //If value isn't null, get all of our required values. if (value == null) { if (index == 0 && count == 0) { return this; } throw new ArgumentNullException("ArgumentNull_String"); } //Range check the index. if (index < 0 || index > currentLength) { throw new ArgumentOutOfRangeException("index","ArgumentOutOfRange_Index"); } if (count < 1) { throw new ArgumentOutOfRangeException("count","ArgumentOutOfRange_GenericPositive"); } //Calculate the new length, ensure that we have the space and set the space variable for this buffer int requiredLength; try { requiredLength = checked(currentLength + (value.Length * count)); } catch (Exception) { throw new OutOfMemoryException(); } if (NeedsAllocation(currentString,requiredLength)) { String newString = GetNewString(currentString,requiredLength); newString.InsertInPlace(index, value, count, currentLength, requiredLength); ReplaceString(tid,newString); } else { currentString.InsertInPlace(index, value, count, currentLength, requiredLength); ReplaceString(tid,currentString); } return this; } // Property. // Removes the specified characters from this string builder. // The length of this string builder is reduced by // length, but the capacity is unaffected. // //| public StringBuilder Remove(int startIndex, int length) { // See also Lightning\Src\VM\COMStringBuffer.cpp::Remove int tid; String thisString = GetThreadSafeString(out tid); int thisLength = thisString.ArrayLength-1; if (length < 0) { throw new ArgumentOutOfRangeException("Negative length"); } if (startIndex < 0) { throw new ArgumentOutOfRangeException("Negative start index"); } if (startIndex + length > thisLength) { throw new ArgumentOutOfRangeException("Exceeding string length"); } thisString.RemoveRange(startIndex, length); this.m_StringValue = thisString; this.m_currentThread = tid; return this; } // // // PUBLIC INSTANCE FUNCTIONS // // //====================================Append==================================== // //============================================================================== // Appends a boolean to the end of this string builder. // The capacity is adjusted as needed. //| public StringBuilder Append(bool value) { return Append(value.ToString()); } // Appends an sbyte to this string builder. // The capacity is adjusted as needed. //| [CLSCompliant(false)] public StringBuilder Append(sbyte value) { return Append(value.ToString()); } // Appends a ubyte to this string builder. // The capacity is adjusted as needed. //| public StringBuilder Append(byte value) { return Append(value.ToString()); } // Appends a character at the end of this string builder. The capacity is adjusted as needed. //| public StringBuilder Append(char value) { int tid; // hand inlining of GetThreadSafeString String currentString = m_StringValue; tid = InternalGetCurrentThread(); if (m_currentThread != tid) currentString = String.GetStringForStringBuilder(currentString, currentString.Capacity); int currentLength = currentString.Length; if (!NeedsAllocation(currentString,currentLength + 1)) { currentString.AppendInPlace(value,currentLength); ReplaceString(tid,currentString); return this; } String newString = GetNewString(currentString,currentLength+1); newString.AppendInPlace(value,currentLength); ReplaceString(tid,newString); return this; } // Appends a short to this string builder. // The capacity is adjusted as needed. //| public StringBuilder Append(short value) { return Append(value.ToString()); } // Appends an int to this string builder. // The capacity is adjusted as needed. //| public StringBuilder Append(int value) { return Append(value.ToString()); } // Appends a long to this string builder. // The capacity is adjusted as needed. //| public StringBuilder Append(long value) { return Append(value.ToString()); } // Appends a float to this string builder. // The capacity is adjusted as needed. //| public StringBuilder Append(float value) { return Append(value.ToString()); } // Appends a double to this string builder. // The capacity is adjusted as needed. //| public StringBuilder Append(double value) { return Append(value.ToString()); } //| public StringBuilder Append(decimal value) { return Append(value.ToString()); } // Appends an ushort to this string builder. // The capacity is adjusted as needed. //| [CLSCompliant(false)] public StringBuilder Append(ushort value) { return Append(value.ToString()); } // Appends an uint to this string builder. // The capacity is adjusted as needed. //| [CLSCompliant(false)] public StringBuilder Append(uint value) { return Append(value.ToString()); } // Appends an unsigned long to this string builder. // The capacity is adjusted as needed. //| [CLSCompliant(false)] public StringBuilder Append(ulong value) { return Append(value.ToString()); } // Appends an Object to this string builder. // The capacity is adjusted as needed. //| public StringBuilder Append(Object value) { if (null == value) { //Appending null is now a no-op. return this; } return Append(value.ToString()); } // Appends all of the characters in value to the current instance. //| public StringBuilder Append(char[] value) { if (null == value) { return this; } int valueLength = value.Length; int tid; String currentString = GetThreadSafeString(out tid); int currentLength = currentString.Length; int requiredLength = currentLength + value.Length; if (NeedsAllocation(currentString,requiredLength)) { String newString = GetNewString(currentString,requiredLength); newString.AppendInPlace(value, 0, valueLength,currentLength); ReplaceString(tid,newString); } else { currentString.AppendInPlace(value, 0, valueLength, currentLength); ReplaceString(tid,currentString); } return this; } //====================================Insert==================================== // //============================================================================== // Returns a reference to the StringBuilder with ; value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. If value equals String.Empty, the // StringBuilder is not changed. ; Inserts ";<;no object>;"; if value // is null. // //| public StringBuilder Insert(int index, String value) { if (value == null) // This is to do the index validation return Insert(index,value,0); else return Insert(index,value,1); } // Returns a reference to the StringBuilder with ; value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. If value equals String.Empty, the // StringBuilder is not changed. ; Inserts ";<;no object>;"; if value // is null. // //| public StringBuilder Insert( int index, bool value) { return Insert(index,value.ToString(),1); } // Returns a reference to the StringBuilder with ; value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. If value equals String.Empty, the // StringBuilder is not changed. ; Inserts ";<;no object>;"; if value // is null. // //| [CLSCompliant(false)] public StringBuilder Insert(int index, sbyte value) { return Insert(index,value.ToString(),1); } // Returns a reference to the StringBuilder with ; value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. If value equals String.Empty, the // StringBuilder is not changed. ; Inserts ";<;no object>;"; if value // is null. // //| public StringBuilder Insert(int index, byte value) { return Insert(index,value.ToString(),1); } // Returns a reference to the StringBuilder with ; value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. If value equals String.Empty, the // StringBuilder is not changed. ; Inserts ";<;no object>;"; if value // is null. // //| public StringBuilder Insert(int index, short value) { return Insert(index,value.ToString(),1); } // Returns a reference to the StringBuilder with ; value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. If value equals String.Empty, the // StringBuilder is not changed. ; Inserts ";<;no object>;"; if value // is null. // //| public StringBuilder Insert(int index, char value) { return Insert(index,Char.ToString(value),1); } // Returns a reference to the StringBuilder with ; value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. If value equals String.Empty, the // StringBuilder is not changed. ; Inserts ";<;no object>;"; if value // is null. // //| public StringBuilder Insert(int index, char[] value) { if (null == value) { return Insert(index, value, 0, 0); } return Insert(index, value, 0, value.Length); } // Returns a reference to the StringBuilder with charCount characters from // value inserted into the buffer at index. Existing characters are shifted // to make room for the new text and capacity is adjusted as required. If value is null, the StringBuilder // is unchanged. Characters are taken from value starting at position startIndex. //| public StringBuilder Insert(int index, char []value, int startIndex, int charCount) { throw new Exception("System.Text.StringBuilder.Insert not implemented in Bartok"); } // Returns a reference to the StringBuilder with ; value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. If value equals String.Empty, the // StringBuilder is not changed. ; Inserts ";<;no object>;"; if value // is null. // //| public StringBuilder Insert(int index, int value){ return Insert(index,value.ToString(),1); } // Returns a reference to the StringBuilder with ; value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. If value equals String.Empty, the // StringBuilder is not changed. ; Inserts ";<;no object>;"; if value // is null. // //| public StringBuilder Insert(int index, long value) { return Insert(index,value.ToString(),1); } // Returns a reference to the StringBuilder with ; value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. If value equals String.Empty, the // StringBuilder is not changed. ; Inserts ";<;no object>;"; if value // is null. // //| public StringBuilder Insert(int index, float value) { return Insert(index,value.ToString(),1); } // Returns a reference to the StringBuilder with ; value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. If value equals String.Empty, the // StringBuilder is not changed. ; Inserts ";<;no object>;"; if value // is null. // //| public StringBuilder Insert(int index, double value) { return Insert(index,value.ToString(),1); } //| public StringBuilder Insert(int index, decimal value) { return Insert(index,value.ToString(),1); } // Returns a reference to the StringBuilder with value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. // //| [CLSCompliant(false)] public StringBuilder Insert(int index, ushort value) { return Insert(index, value.ToString(),1); } // Returns a reference to the StringBuilder with value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. // //| [CLSCompliant(false)] public StringBuilder Insert(int index, uint value) { return Insert(index, value.ToString(), 1); } // Returns a reference to the StringBuilder with value inserted into // the buffer at index. Existing characters are shifted to make room for the new text. // The capacity is adjusted as needed. // //| [CLSCompliant(false)] public StringBuilder Insert(int index, ulong value) { return Insert(index, value.ToString(), 1); } // Returns a reference to this string builder with value inserted into // the buffer at index. Existing characters are shifted to make room for the // new text. The capacity is adjusted as needed. If value equals String.Empty, the // StringBuilder is not changed. No changes are made if value is null. // //| public StringBuilder Insert(int index, Object value) { //If we get a null if (null == value) { return this; } return Insert(index,value.ToString(),1); } //| public StringBuilder AppendFormat(String format, Object arg0) { return AppendFormat(format, new Object[] {arg0}); } //| public StringBuilder AppendFormat(String format, Object arg0, Object arg1) { return AppendFormat(format, new Object[] {arg0, arg1}); } //| public StringBuilder AppendFormat(String format, Object arg0, Object arg1, Object arg2) { return AppendFormat(format, new Object[] {arg0, arg1, arg2}); } private static void FormatError() { throw new FormatException("Format_InvalidString"); } //| public StringBuilder AppendFormat(String format, params Object[] args) { if (format == null || args == null) { throw new ArgumentNullException((format==null)?"format":"args"); } char[] chars = format.ToCharArray(0, format.Length); int pos = 0; int len = chars.Length; char ch = '\x0'; while (true) { int p = pos; int i = pos; while (pos < len) { ch = chars[pos]; pos++; if (ch == '}') { if (pos < len && chars[pos] =='}') // Treat as escape character for }} pos++; else FormatError(); } if (ch == '{') { if (pos < len && chars[pos] =='{') // Treat as escape character for {{ pos++; else { pos--; break; } } chars[i++] = ch; } if (i > p) Append(chars, p, i - p); if (pos == len) break; pos++; if (pos == len || (ch = chars[pos]) < '0' || ch > '9') FormatError(); int index = 0; do { index = index * 10 + ch - '0'; pos++; if (pos == len) FormatError(); ch = chars[pos]; } while (ch >= '0' && ch <= '9' && index < 1000000); if (index >= args.Length) throw new FormatException("Format_IndexOutOfRange"); while (pos < len && (ch = chars[pos]) == ' ') pos++; bool leftJustify = false; int width = 0; if (ch == ',') { pos++; while (pos < len && chars[pos] == ' ') pos++; if (pos == len) FormatError(); ch = chars[pos]; if (ch == '-') { leftJustify = true; pos++; if (pos == len) FormatError(); ch = chars[pos]; } if (ch < '0' || ch > '9') FormatError(); do { width = width * 10 + ch - '0'; pos++; if (pos == len) FormatError(); ch = chars[pos]; } while (ch >= '0' && ch <= '9' && width < 1000000); } while (pos < len && (ch = chars[pos]) == ' ') pos++; Object arg = args[index]; String fmt = null; if (ch == ':') { pos++; p = pos; i = pos; while (true) { if (pos == len) FormatError(); ch = chars[pos]; pos++; if (ch == '{') { if (pos < len && chars[pos] =='{') // Treat as escape character for {{ pos++; else FormatError(); } else if (ch == '}') { if (pos < len && chars[pos] =='}') // Treat as escape character for }} pos++; else { pos--; break; } } chars[i++] = ch; } if (i > p) fmt = new String(chars, p, i - p); } if (ch != '}') FormatError(); pos++; String s = null; if (s == null) { if (arg is IFormattable) { s = ((IFormattable)arg).ToString(fmt); } else if (arg != null) { s = arg.ToString(); } } if (s == null) s = String.Empty; int pad = width - s.Length; if (!leftJustify && pad > 0) Append(' ', pad); Append(s); if (leftJustify && pad > 0) Append(' ', pad); } return this; } // Returns a reference to the current StringBuilder with all instances of oldString // replaced with newString. If startIndex and count are specified, // we only replace strings completely contained in the range of startIndex to startIndex + // count. The strings to be replaced are checked on an ordinal basis (e.g. not culture aware). If // newValue is null, instances of oldValue are removed (e.g. replaced with nothing.). // //| public StringBuilder Replace(String oldValue, String newValue) { return Replace(oldValue, newValue, 0, Length); } //| public StringBuilder Replace(String oldValue, String newValue, int startIndex, int count) { throw new Exception("System.Text.StringBuilder.Replace not implemented in Bartok"); } //| public bool Equals(StringBuilder sb) { if (sb == null) return false; return ((this.Capacity == sb.Capacity) && (this.MaxCapacity == sb.MaxCapacity) && (this. m_StringValue.Equals(sb. m_StringValue))); } // Returns a StringBuilder with all instances of oldChar replaced with // newChar. The size of the StringBuilder is unchanged because we're only // replacing characters. If startIndex and count are specified, we // only replace characters in the range from startIndex to startIndex+count // //| public StringBuilder Replace(char oldChar, char newChar) { return Replace(oldChar, newChar, 0, Length); } //| public StringBuilder Replace(char oldChar, char newChar, int startIndex, int count) { int tid; String currentString = GetThreadSafeString(out tid); int currentLength = currentString.Length; if ((uint)startIndex > (uint)currentLength) { throw new ArgumentOutOfRangeException("startIndex", "ArgumentOutOfRange_Index"); } if (count < 0 || startIndex > currentLength - count) { throw new ArgumentOutOfRangeException("count", "ArgumentOutOfRange_Index"); } if (!NeedsAllocation(currentString,currentLength)) { currentString.ReplaceCharInPlace(oldChar, newChar, startIndex, count, currentLength); ReplaceString(tid,currentString); return this; } String newString = GetNewString(currentString,currentLength); newString.ReplaceCharInPlace(oldChar, newChar, startIndex, count, currentLength); ReplaceString(tid,newString); return this; } } }