1274 lines
53 KiB
C#
1274 lines
53 KiB
C#
// ==++==
|
|
//
|
|
// 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);
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder"]/*' />
|
|
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).
|
|
//| <include path='docs/doc[@for="StringBuilder.StringBuilder"]/*' />
|
|
public StringBuilder()
|
|
: this(DEFAULT_CAPACITY) {
|
|
}
|
|
|
|
// Create a new empty string builder (i.e., it represents String.Empty)
|
|
// with the specified capacity.
|
|
//| <include path='docs/doc[@for="StringBuilder.StringBuilder1"]/*' />
|
|
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).
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.StringBuilder2"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.StringBuilder3"]/*' />
|
|
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.
|
|
//
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.StringBuilder4"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="StringBuilder.StringBuilder5"]/*' />
|
|
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);
|
|
}
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.Capacity"]/*' />
|
|
public int Capacity {
|
|
get {return m_StringValue.Capacity;} //-1 to account for terminating null.
|
|
set {InternalSetCapacity(value);}
|
|
}
|
|
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.MaxCapacity"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.EnsureCapacity"]/*' />
|
|
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);
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.ToString"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="StringBuilder.ToString1"]/*' />
|
|
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.
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.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);
|
|
}
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.this"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append1"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append2"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append3"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Remove"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append4"]/*' />
|
|
public StringBuilder Append(bool value) {
|
|
return Append(value.ToString());
|
|
}
|
|
|
|
// Appends an sbyte to this string builder.
|
|
// The capacity is adjusted as needed.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append5"]/*' />
|
|
[CLSCompliant(false)]
|
|
public StringBuilder Append(sbyte value) {
|
|
return Append(value.ToString());
|
|
}
|
|
|
|
// Appends a ubyte to this string builder.
|
|
// The capacity is adjusted as needed.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append6"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append7"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append8"]/*' />
|
|
public StringBuilder Append(short value) {
|
|
return Append(value.ToString());
|
|
}
|
|
|
|
// Appends an int to this string builder.
|
|
// The capacity is adjusted as needed.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append9"]/*' />
|
|
public StringBuilder Append(int value) {
|
|
return Append(value.ToString());
|
|
}
|
|
|
|
// Appends a long to this string builder.
|
|
// The capacity is adjusted as needed.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append10"]/*' />
|
|
public StringBuilder Append(long value) {
|
|
return Append(value.ToString());
|
|
}
|
|
|
|
// Appends a float to this string builder.
|
|
// The capacity is adjusted as needed.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append11"]/*' />
|
|
public StringBuilder Append(float value) {
|
|
return Append(value.ToString());
|
|
}
|
|
|
|
// Appends a double to this string builder.
|
|
// The capacity is adjusted as needed.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append12"]/*' />
|
|
public StringBuilder Append(double value) {
|
|
return Append(value.ToString());
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.Append13"]/*' />
|
|
public StringBuilder Append(decimal value) {
|
|
return Append(value.ToString());
|
|
}
|
|
|
|
// Appends an ushort to this string builder.
|
|
// The capacity is adjusted as needed.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append14"]/*' />
|
|
[CLSCompliant(false)]
|
|
public StringBuilder Append(ushort value) {
|
|
return Append(value.ToString());
|
|
}
|
|
|
|
// Appends an uint to this string builder.
|
|
// The capacity is adjusted as needed.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append15"]/*' />
|
|
[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.
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.Append16"]/*' />
|
|
[CLSCompliant(false)]
|
|
public StringBuilder Append(ulong value) {
|
|
return Append(value.ToString());
|
|
}
|
|
|
|
// Appends an Object to this string builder.
|
|
// The capacity is adjusted as needed.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append17"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="StringBuilder.Append18"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert1"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert2"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert3"]/*' />
|
|
[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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert4"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert5"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert6"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert7"]/*' />
|
|
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.
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert8"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert9"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert10"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert11"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert12"]/*' />
|
|
public StringBuilder Insert(int index, double value) {
|
|
return Insert(index,value.ToString(),1);
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert13"]/*' />
|
|
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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert14"]/*' />
|
|
[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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert15"]/*' />
|
|
[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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert16"]/*' />
|
|
[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.
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Insert17"]/*' />
|
|
public StringBuilder Insert(int index, Object value) {
|
|
//If we get a null
|
|
if (null == value) {
|
|
return this;
|
|
}
|
|
return Insert(index,value.ToString(),1);
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.AppendFormat"]/*' />
|
|
public StringBuilder AppendFormat(String format, Object arg0) {
|
|
return AppendFormat(format, new Object[] {arg0});
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.AppendFormat1"]/*' />
|
|
public StringBuilder AppendFormat(String format, Object arg0, Object arg1) {
|
|
return AppendFormat(format, new Object[] {arg0, arg1});
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.AppendFormat2"]/*' />
|
|
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");
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.AppendFormat4"]/*' />
|
|
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.).
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Replace"]/*' />
|
|
public StringBuilder Replace(String oldValue, String newValue) {
|
|
return Replace(oldValue, newValue, 0, Length);
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.Replace1"]/*' />
|
|
public StringBuilder Replace(String oldValue, String newValue, int startIndex, int count)
|
|
{
|
|
throw new Exception("System.Text.StringBuilder.Replace not implemented in Bartok");
|
|
}
|
|
|
|
//| <include path='docs/doc[@for="StringBuilder.Equals"]/*' />
|
|
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
|
|
//
|
|
//| <include path='docs/doc[@for="StringBuilder.Replace2"]/*' />
|
|
public StringBuilder Replace(char oldChar, char newChar) {
|
|
return Replace(oldChar, newChar, 0, Length);
|
|
}
|
|
//| <include path='docs/doc[@for="StringBuilder.Replace3"]/*' />
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|