summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Text/StringBuilder.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Text/StringBuilder.cs')
-rw-r--r--src/mscorlib/src/System/Text/StringBuilder.cs309
1 files changed, 191 insertions, 118 deletions
diff --git a/src/mscorlib/src/System/Text/StringBuilder.cs b/src/mscorlib/src/System/Text/StringBuilder.cs
index 8026c98e78..f20146fe00 100644
--- a/src/mscorlib/src/System/Text/StringBuilder.cs
+++ b/src/mscorlib/src/System/Text/StringBuilder.cs
@@ -20,7 +20,9 @@ namespace System.Text {
using System.Security;
using System.Threading;
using System.Globalization;
+ using System.Diagnostics;
using System.Diagnostics.Contracts;
+ using System.Collections.Generic;
// 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
@@ -55,7 +57,7 @@ namespace System.Text {
internal char[] m_ChunkChars; // The characters in this block
internal StringBuilder m_ChunkPrevious; // Link to the block logically before this block
internal int m_ChunkLength; // The index in m_ChunkChars that represent the end of the block
- internal int m_ChunkOffset; // The logial offset (sum of all characters in previous blocks)
+ internal int m_ChunkOffset; // The logical offset (sum of all characters in previous blocks)
internal int m_MaxCapacity = 0;
//
@@ -117,18 +119,17 @@ namespace System.Text {
// Creates a new string builder from the specifed substring with the specified
// capacity. The maximum number of characters is set by capacity.
//
- [System.Security.SecuritySafeCritical] // auto-generated
public StringBuilder(String value, int startIndex, int length, int capacity) {
if (capacity<0) {
- throw new ArgumentOutOfRangeException("capacity",
- Environment.GetResourceString("ArgumentOutOfRange_MustBePositive", "capacity"));
+ throw new ArgumentOutOfRangeException(nameof(capacity),
+ Environment.GetResourceString("ArgumentOutOfRange_MustBePositive", nameof(capacity)));
}
if (length<0) {
- throw new ArgumentOutOfRangeException("length",
- Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegNum", "length"));
+ throw new ArgumentOutOfRangeException(nameof(length),
+ Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegNum", nameof(length)));
}
if (startIndex<0) {
- throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
+ throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
}
Contract.EndContractBlock();
@@ -136,7 +137,7 @@ namespace System.Text {
value = String.Empty;
}
if (startIndex > value.Length - length) {
- throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_IndexLength"));
+ throw new ArgumentOutOfRangeException(nameof(length), Environment.GetResourceString("ArgumentOutOfRange_IndexLength"));
}
m_MaxCapacity = Int32.MaxValue;
if (capacity == 0) {
@@ -158,14 +159,14 @@ namespace System.Text {
// and a maximum capacity of maxCapacity.
public StringBuilder(int capacity, int maxCapacity) {
if (capacity>maxCapacity) {
- throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_Capacity"));
+ throw new ArgumentOutOfRangeException(nameof(capacity), Environment.GetResourceString("ArgumentOutOfRange_Capacity"));
}
if (maxCapacity<1) {
- throw new ArgumentOutOfRangeException("maxCapacity", Environment.GetResourceString("ArgumentOutOfRange_SmallMaxCapacity"));
+ throw new ArgumentOutOfRangeException(nameof(maxCapacity), Environment.GetResourceString("ArgumentOutOfRange_SmallMaxCapacity"));
}
if (capacity<0) {
- throw new ArgumentOutOfRangeException("capacity",
- Environment.GetResourceString("ArgumentOutOfRange_MustBePositive", "capacity"));
+ throw new ArgumentOutOfRangeException(nameof(capacity),
+ Environment.GetResourceString("ArgumentOutOfRange_MustBePositive", nameof(capacity)));
}
Contract.EndContractBlock();
@@ -177,10 +178,9 @@ namespace System.Text {
m_ChunkChars = new char[capacity];
}
- [System.Security.SecurityCritical] // auto-generated
private StringBuilder(SerializationInfo info, StreamingContext context) {
if (info == null)
- throw new ArgumentNullException("info");
+ throw new ArgumentNullException(nameof(info));
Contract.EndContractBlock();
int persistedCapacity = 0;
@@ -240,11 +240,10 @@ namespace System.Text {
VerifyClassInvariant();
}
- [System.Security.SecurityCritical] // auto-generated
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info==null) {
- throw new ArgumentNullException("info");
+ throw new ArgumentNullException(nameof(info));
}
Contract.EndContractBlock();
@@ -264,21 +263,21 @@ namespace System.Text {
for (; ; )
{
// All blocks have copy of the maxCapacity.
- Contract.Assert(currentBlock.m_MaxCapacity == maxCapacity, "Bad maxCapacity");
- Contract.Assert(currentBlock.m_ChunkChars != null, "Empty Buffer");
+ Debug.Assert(currentBlock.m_MaxCapacity == maxCapacity, "Bad maxCapacity");
+ Debug.Assert(currentBlock.m_ChunkChars != null, "Empty Buffer");
- Contract.Assert(currentBlock.m_ChunkLength <= currentBlock.m_ChunkChars.Length, "Out of range length");
- Contract.Assert(currentBlock.m_ChunkLength >= 0, "Negative length");
- Contract.Assert(currentBlock.m_ChunkOffset >= 0, "Negative offset");
+ Debug.Assert(currentBlock.m_ChunkLength <= currentBlock.m_ChunkChars.Length, "Out of range length");
+ Debug.Assert(currentBlock.m_ChunkLength >= 0, "Negative length");
+ Debug.Assert(currentBlock.m_ChunkOffset >= 0, "Negative offset");
StringBuilder prevBlock = currentBlock.m_ChunkPrevious;
if (prevBlock == null)
{
- Contract.Assert(currentBlock.m_ChunkOffset == 0, "First chunk's offset is not 0");
+ Debug.Assert(currentBlock.m_ChunkOffset == 0, "First chunk's offset is not 0");
break;
}
// There are no gaps in the blocks.
- Contract.Assert(currentBlock.m_ChunkOffset == prevBlock.m_ChunkOffset + prevBlock.m_ChunkLength, "There is a gap between chunks!");
+ Debug.Assert(currentBlock.m_ChunkOffset == prevBlock.m_ChunkOffset + prevBlock.m_ChunkLength, "There is a gap between chunks!");
currentBlock = prevBlock;
}
}
@@ -287,13 +286,13 @@ namespace System.Text {
get { return m_ChunkChars.Length + m_ChunkOffset; }
set {
if (value < 0) {
- throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NegativeCapacity"));
+ throw new ArgumentOutOfRangeException(nameof(value), Environment.GetResourceString("ArgumentOutOfRange_NegativeCapacity"));
}
if (value > MaxCapacity) {
- throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_Capacity"));
+ throw new ArgumentOutOfRangeException(nameof(value), Environment.GetResourceString("ArgumentOutOfRange_Capacity"));
}
if (value < Length) {
- throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
+ throw new ArgumentOutOfRangeException(nameof(value), Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
}
Contract.EndContractBlock();
@@ -317,7 +316,7 @@ namespace System.Text {
//
public int EnsureCapacity(int capacity) {
if (capacity < 0) {
- throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NegativeCapacity"));
+ throw new ArgumentOutOfRangeException(nameof(capacity), Environment.GetResourceString("ArgumentOutOfRange_NegativeCapacity"));
}
Contract.EndContractBlock();
@@ -326,7 +325,6 @@ namespace System.Text {
return Capacity;
}
- [System.Security.SecuritySafeCritical] // auto-generated
public override String ToString() {
Contract.Ensures(Contract.Result<String>() != null);
@@ -357,7 +355,7 @@ namespace System.Text {
}
else
{
- throw new ArgumentOutOfRangeException("chunkLength", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(chunkLength), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
}
chunk = chunk.m_ChunkPrevious;
@@ -370,26 +368,25 @@ namespace System.Text {
// Converts a substring of this string builder to a String.
- [System.Security.SecuritySafeCritical] // auto-generated
public String ToString(int startIndex, int length) {
Contract.Ensures(Contract.Result<String>() != null);
int currentLength = this.Length;
if (startIndex < 0)
{
- throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
+ throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
}
if (startIndex > currentLength)
{
- throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndexLargerThanLength"));
+ throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_StartIndexLargerThanLength"));
}
if (length < 0)
{
- throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
+ throw new ArgumentOutOfRangeException(nameof(length), Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
}
if (startIndex > (currentLength - length))
{
- throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_IndexLength"));
+ throw new ArgumentOutOfRangeException(nameof(length), Environment.GetResourceString("ArgumentOutOfRange_IndexLength"));
}
VerifyClassInvariant();
@@ -433,7 +430,7 @@ namespace System.Text {
}
else
{
- throw new ArgumentOutOfRangeException("chunkCount", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(chunkCount), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
}
}
@@ -463,11 +460,11 @@ namespace System.Text {
set {
//If the new length is less than 0 or greater than our Maximum capacity, bail.
if (value<0) {
- throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
+ throw new ArgumentOutOfRangeException(nameof(value), Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
}
if (value>MaxCapacity) {
- throw new ArgumentOutOfRangeException("value", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
+ throw new ArgumentOutOfRangeException(nameof(value), Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
}
Contract.EndContractBlock();
@@ -477,7 +474,7 @@ namespace System.Text {
{
m_ChunkLength = 0;
m_ChunkOffset = 0;
- Contract.Assert(Capacity >= originalCapacity, "setting the Length should never decrease the Capacity");
+ Debug.Assert(Capacity >= originalCapacity, "setting the Length should never decrease the Capacity");
return;
}
@@ -499,7 +496,7 @@ namespace System.Text {
int newLen = originalCapacity - chunk.m_ChunkOffset;
char[] newArray = new char[newLen];
- Contract.Assert(newLen > chunk.m_ChunkChars.Length, "the new chunk should be larger than the one it is replacing");
+ Debug.Assert(newLen > chunk.m_ChunkChars.Length, "the new chunk should be larger than the one it is replacing");
Array.Copy(chunk.m_ChunkChars, newArray, chunk.m_ChunkLength);
m_ChunkChars = newArray;
@@ -509,7 +506,7 @@ namespace System.Text {
m_ChunkLength = value - chunk.m_ChunkOffset;
VerifyClassInvariant();
}
- Contract.Assert(Capacity >= originalCapacity, "setting the Length should never decrease the Capacity");
+ Debug.Assert(Capacity >= originalCapacity, "setting the Length should never decrease the Capacity");
}
}
@@ -539,13 +536,13 @@ namespace System.Text {
if (indexInBlock >= 0)
{
if (indexInBlock >= chunk.m_ChunkLength)
- throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index"));
chunk.m_ChunkChars[indexInBlock] = value;
return;
}
chunk = chunk.m_ChunkPrevious;
if (chunk == null)
- throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
}
}
@@ -553,7 +550,7 @@ namespace System.Text {
// 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) {
- throw new ArgumentOutOfRangeException("repeatCount", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
+ throw new ArgumentOutOfRangeException(nameof(repeatCount), Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
}
Contract.Ensures(Contract.Result<StringBuilder>() != null);
Contract.EndContractBlock();
@@ -561,6 +558,14 @@ namespace System.Text {
if (repeatCount==0) {
return this;
}
+
+ // this is where we can check if the repeatCount will put us over m_MaxCapacity
+ // We are doing the check here to prevent the corruption of the StringBuilder.
+ int newLength = Length + repeatCount;
+ if (newLength > m_MaxCapacity || newLength < repeatCount) {
+ throw new ArgumentOutOfRangeException(nameof(repeatCount), Environment.GetResourceString("ArgumentOutOfRange_LengthGreaterThanCapacity"));
+ }
+
int idx = m_ChunkLength;
while (repeatCount > 0)
{
@@ -573,7 +578,7 @@ namespace System.Text {
{
m_ChunkLength = idx;
ExpandByABlock(repeatCount);
- Contract.Assert(m_ChunkLength == 0, "Expand should create a new block");
+ Debug.Assert(m_ChunkLength == 0, "Expand should create a new block");
idx = 0;
}
}
@@ -583,10 +588,9 @@ namespace System.Text {
}
// Appends an array of characters at the end of this string builder. The capacity is adjusted as needed.
- [System.Security.SecuritySafeCritical] // auto-generated
public StringBuilder Append(char[] value, int startIndex, int charCount) {
if (startIndex < 0) {
- throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
+ throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
}
if (charCount<0) {
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
@@ -598,7 +602,7 @@ namespace System.Text {
if (startIndex == 0 && charCount == 0) {
return this;
}
- throw new ArgumentNullException("value");
+ throw new ArgumentNullException(nameof(value));
}
if (charCount > value.Length - startIndex) {
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Index"));
@@ -620,7 +624,6 @@ namespace System.Text {
// Appends a copy of this string at the end of this string builder.
- [System.Security.SecuritySafeCritical] // auto-generated
public StringBuilder Append(String value) {
Contract.Ensures(Contract.Result<StringBuilder>() != null);
@@ -659,7 +662,6 @@ namespace System.Text {
// We put this fixed in its own helper to avoid the cost zero initing valueChars in the
// case we don't actually use it.
- [System.Security.SecuritySafeCritical] // auto-generated
private void AppendHelper(string value) {
unsafe {
fixed (char* valueChars = value)
@@ -668,23 +670,20 @@ namespace System.Text {
}
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [SecurityCritical]
internal unsafe extern void ReplaceBufferInternal(char* newBuffer, int newLength);
[MethodImplAttribute(MethodImplOptions.InternalCall)]
- [SecurityCritical]
internal unsafe extern void ReplaceBufferAnsiInternal(sbyte* newBuffer, int newLength);
// Appends a copy of the characters in value from startIndex to startIndex +
// count at the end of this string builder.
- [System.Security.SecuritySafeCritical] // auto-generated
public StringBuilder Append(String value, int startIndex, int count) {
if (startIndex < 0) {
- throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
if (count < 0) {
- throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
+ throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_GenericPositive"));
}
Contract.Ensures(Contract.Result<StringBuilder>() != null);
@@ -694,7 +693,7 @@ namespace System.Text {
if (startIndex == 0 && count == 0) {
return this;
}
- throw new ArgumentNullException("value");
+ throw new ArgumentNullException(nameof(value));
}
if (count == 0) {
@@ -702,7 +701,7 @@ namespace System.Text {
}
if (startIndex > value.Length - count) {
- throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
unsafe
@@ -730,19 +729,18 @@ namespace System.Text {
}
[System.Runtime.InteropServices.ComVisible(false)]
- [SecuritySafeCritical]
public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count) {
if (destination == null) {
- throw new ArgumentNullException("destination");
+ throw new ArgumentNullException(nameof(destination));
}
if (count < 0) {
- throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("Arg_NegativeArgCount"));
+ throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("Arg_NegativeArgCount"));
}
if (destinationIndex < 0) {
- throw new ArgumentOutOfRangeException("destinationIndex",
- Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegNum", "destinationIndex"));
+ throw new ArgumentOutOfRangeException(nameof(destinationIndex),
+ Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegNum", nameof(destinationIndex)));
}
if (destinationIndex > destination.Length - count) {
@@ -750,7 +748,7 @@ namespace System.Text {
}
if ((uint)sourceIndex > (uint)Length) {
- throw new ArgumentOutOfRangeException("sourceIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(sourceIndex), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
if (sourceIndex > Length - count) {
@@ -794,10 +792,9 @@ namespace System.Text {
// The capacity is adjusted as needed. If value equals String.Empty, this
// string builder is not changed.
//
- [System.Security.SecuritySafeCritical] // auto-generated
public StringBuilder Insert(int index, String value, int count) {
if (count < 0) {
- throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+ throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
}
Contract.Ensures(Contract.Result<StringBuilder>() != null);
Contract.EndContractBlock();
@@ -805,7 +802,7 @@ namespace System.Text {
//Range check the index.
int currentLength = Length;
if ((uint)index > (uint)currentLength) {
- throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
//If value is null, empty or count is 0, do nothing. This is ECMA standard.
@@ -819,7 +816,7 @@ namespace System.Text {
if (insertingChars > MaxCapacity - this.Length) {
throw new OutOfMemoryException();
}
- Contract.Assert(insertingChars + this.Length < Int32.MaxValue);
+ Debug.Assert(insertingChars + this.Length < Int32.MaxValue);
StringBuilder chunk;
int indexInChunk;
@@ -843,11 +840,11 @@ namespace System.Text {
//
public StringBuilder Remove(int startIndex, int length) {
if (length<0) {
- throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
+ throw new ArgumentOutOfRangeException(nameof(length), Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
}
if (startIndex<0) {
- throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
+ throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
}
if (length > Length - startIndex) {
@@ -989,7 +986,6 @@ namespace System.Text {
}
// Appends all of the characters in value to the current instance.
- [System.Security.SecuritySafeCritical] // auto-generated
public StringBuilder Append(char[] value) {
Contract.Ensures(Contract.Result<StringBuilder>() != null);
@@ -1003,6 +999,88 @@ namespace System.Text {
return this;
}
+ // Append joined values with a separator between each value.
+ public unsafe StringBuilder AppendJoin<T>(char separator, params T[] values)
+ {
+ // Defer argument validation to the internal function
+ return AppendJoinCore(&separator, 1, values);
+ }
+
+ public unsafe StringBuilder AppendJoin<T>(string separator, params T[] values)
+ {
+ separator = separator ?? string.Empty;
+ fixed (char* pSeparator = separator)
+ {
+ // Defer argument validation to the internal function
+ return AppendJoinCore(pSeparator, separator.Length, values);
+ }
+ }
+
+ public unsafe StringBuilder AppendJoin<T>(char separator, IEnumerable<T> values)
+ {
+ // Defer argument validation to the internal function
+ return AppendJoinCore(&separator, 1, values);
+ }
+
+ public unsafe StringBuilder AppendJoin<T>(string separator, IEnumerable<T> values)
+ {
+ separator = separator ?? string.Empty;
+ fixed (char* pSeparator = separator)
+ {
+ // Defer argument validation to the internal function
+ return AppendJoinCore(pSeparator, separator.Length, values);
+ }
+ }
+
+ private unsafe StringBuilder AppendJoinCore<T>(char* separator, int separatorLength, params T[] values)
+ {
+ if (values == null)
+ throw new ArgumentNullException(nameof(values));
+ Contract.Ensures(Contract.Result<StringBuilder>() != null);
+
+ if (values.Length == 0)
+ return this;
+
+ var value = values[0];
+ if (value != null)
+ Append(value.ToString());
+
+ for (var i = 1; i < values.Length; i++)
+ {
+ Append(separator, separatorLength);
+ value = values[i];
+ if (value != null)
+ Append(value.ToString());
+ }
+ return this;
+ }
+
+ private unsafe StringBuilder AppendJoinCore<T>(char* separator, int separatorLength, IEnumerable<T> values)
+ {
+ if (values == null)
+ throw new ArgumentNullException(nameof(values));
+ Contract.Ensures(Contract.Result<StringBuilder>() != null);
+
+ using (var en = values.GetEnumerator())
+ {
+ if (!en.MoveNext())
+ return this;
+
+ var value = en.Current;
+ if (value != null)
+ Append(value.ToString());
+
+ while (en.MoveNext())
+ {
+ Append(separator, separatorLength);
+ value = en.Current;
+ if (value != null)
+ Append(value.ToString());
+ }
+ }
+ return this;
+ }
+
/*====================================Insert====================================
**
==============================================================================*/
@@ -1012,10 +1090,9 @@ namespace System.Text {
// The capacity is adjusted as needed. If value equals String.Empty, the
// StringBuilder is not changed.
//
- [System.Security.SecuritySafeCritical] // auto-generated
public StringBuilder Insert(int index, String value) {
if ((uint)index > (uint)Length) {
- throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
Contract.Ensures(Contract.Result<StringBuilder>() != null);
Contract.EndContractBlock();
@@ -1075,7 +1152,6 @@ namespace System.Text {
// 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.
- [SecuritySafeCritical]
public StringBuilder Insert(int index, char value) {
Contract.Ensures(Contract.Result<StringBuilder>() != null);
@@ -1092,7 +1168,7 @@ namespace System.Text {
//
public StringBuilder Insert(int index, char[] value) {
if ((uint)index > (uint)Length) {
- throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
Contract.Ensures(Contract.Result<StringBuilder>() != null);
Contract.EndContractBlock();
@@ -1106,13 +1182,12 @@ namespace System.Text {
// 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.
- [System.Security.SecuritySafeCritical] // auto-generated
public StringBuilder Insert(int index, char[] value, int startIndex, int charCount) {
Contract.Ensures(Contract.Result<StringBuilder>() != null);
int currentLength = Length;
if ((uint)index > (uint)currentLength) {
- throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
//If they passed in a null char array, just jump out quickly.
@@ -1121,12 +1196,12 @@ namespace System.Text {
{
return this;
}
- throw new ArgumentNullException("value", Environment.GetResourceString("ArgumentNull_String"));
+ throw new ArgumentNullException(nameof(value), Environment.GetResourceString("ArgumentNull_String"));
}
//Range check the array.
if (startIndex < 0) {
- throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
+ throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
}
if (charCount < 0) {
@@ -1134,7 +1209,7 @@ namespace System.Text {
}
if (startIndex > value.Length - charCount) {
- throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
if (charCount > 0)
@@ -1255,7 +1330,7 @@ namespace System.Text {
{
// To preserve the original exception behavior, throw an exception about format if both
// args and format are null. The actual null check for format is in AppendFormatHelper.
- throw new ArgumentNullException((format == null) ? "format" : "args");
+ throw new ArgumentNullException((format == null) ? nameof(format) : nameof(args));
}
Contract.Ensures(Contract.Result<String>() != null);
Contract.EndContractBlock();
@@ -1283,7 +1358,7 @@ namespace System.Text {
{
// To preserve the original exception behavior, throw an exception about format if both
// args and format are null. The actual null check for format is in AppendFormatHelper.
- throw new ArgumentNullException((format == null) ? "format" : "args");
+ throw new ArgumentNullException((format == null) ? nameof(format) : nameof(args));
}
Contract.Ensures(Contract.Result<String>() != null);
Contract.EndContractBlock();
@@ -1301,7 +1376,7 @@ namespace System.Text {
internal StringBuilder AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args) {
if (format == null) {
- throw new ArgumentNullException("format");
+ throw new ArgumentNullException(nameof(format));
}
Contract.Ensures(Contract.Result<StringBuilder>() != null);
Contract.EndContractBlock();
@@ -1582,19 +1657,19 @@ namespace System.Text {
int currentLength = Length;
if ((uint)startIndex > (uint)currentLength)
{
- throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
if (count < 0 || startIndex > currentLength - count)
{
- throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
if (oldValue == null)
{
- throw new ArgumentNullException("oldValue");
+ throw new ArgumentNullException(nameof(oldValue));
}
if (oldValue.Length == 0)
{
- throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "oldValue");
+ throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), nameof(oldValue));
}
if (newValue == null)
@@ -1648,7 +1723,7 @@ namespace System.Text {
chunk = FindChunkForIndex(index);
indexInChunk = index - chunk.m_ChunkOffset;
- Contract.Assert(chunk != null || count == 0, "Chunks ended prematurely");
+ Debug.Assert(chunk != null || count == 0, "Chunks ended prematurely");
}
}
VerifyClassInvariant();
@@ -1668,11 +1743,11 @@ namespace System.Text {
int currentLength = Length;
if ((uint)startIndex > (uint)currentLength) {
- throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(startIndex), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
if (count < 0 || startIndex > currentLength - count) {
- throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(count), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
int endIndex = startIndex + count;
@@ -1702,14 +1777,20 @@ namespace System.Text {
/// <summary>
/// Appends 'value' of length 'count' to the stringBuilder.
/// </summary>
- [SecurityCritical]
[System.CLSCompliantAttribute(false)]
public unsafe StringBuilder Append(char* value, int valueCount)
{
// We don't check null value as this case will throw null reference exception anyway
if (valueCount < 0)
{
- throw new ArgumentOutOfRangeException("valueCount", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
+ throw new ArgumentOutOfRangeException(nameof(valueCount), Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
+ }
+
+ // this is where we can check if the valueCount will put us over m_MaxCapacity
+ // We are doing the check here to prevent the corruption of the StringBuilder.
+ int newLength = Length + valueCount;
+ if (newLength > m_MaxCapacity || newLength < valueCount) {
+ throw new ArgumentOutOfRangeException(nameof(valueCount), Environment.GetResourceString("ArgumentOutOfRange_LengthGreaterThanCapacity"));
}
// This case is so common we want to optimize for it heavily.
@@ -1732,7 +1813,7 @@ namespace System.Text {
// Expand the builder to add another chunk.
int restLength = valueCount - firstLength;
ExpandByABlock(restLength);
- Contract.Assert(m_ChunkLength == 0, "Expand did not make a new block");
+ Debug.Assert(m_ChunkLength == 0, "Expand did not make a new block");
// Copy the second chunk
ThreadSafeCopy(value + firstLength, m_ChunkChars, 0, restLength);
@@ -1745,12 +1826,11 @@ namespace System.Text {
/// <summary>
/// Inserts 'value' of length 'cou
/// </summary>
- [SecurityCritical]
unsafe private void Insert(int index, char* value, int valueCount)
{
if ((uint)index > (uint)Length)
{
- throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(index), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
if (valueCount > 0)
@@ -1768,7 +1848,6 @@ namespace System.Text {
/// replacements in bulk (and therefore very efficiently.
/// with the string 'value'.
/// </summary>
- [System.Security.SecuritySafeCritical] // auto-generated
private void ReplaceAllInChunk(int[] replacements, int replacementsCount, StringBuilder sourceChunk, int removeCount, string value)
{
if (replacementsCount <= 0)
@@ -1798,9 +1877,9 @@ namespace System.Text {
break;
int gapEnd = replacements[i];
- Contract.Assert(gapStart < sourceChunk.m_ChunkChars.Length, "gap starts at end of buffer. Should not happen");
- Contract.Assert(gapStart <= gapEnd, "negative gap size");
- Contract.Assert(gapEnd <= sourceChunk.m_ChunkLength, "gap too big");
+ Debug.Assert(gapStart < sourceChunk.m_ChunkChars.Length, "gap starts at end of buffer. Should not happen");
+ Debug.Assert(gapStart <= gapEnd, "negative gap size");
+ Debug.Assert(gapEnd <= sourceChunk.m_ChunkLength, "gap too big");
if (delta != 0) // can skip the sliding of gaps if source an target string are the same size.
{
// Copy the gap data between the current replacement and the the next replacement
@@ -1810,7 +1889,7 @@ namespace System.Text {
else
{
targetIndexInChunk += gapEnd - gapStart;
- Contract.Assert(targetIndexInChunk <= targetChunk.m_ChunkLength, "gap not in chunk");
+ Debug.Assert(targetIndexInChunk <= targetChunk.m_ChunkLength, "gap not in chunk");
}
}
@@ -1855,7 +1934,6 @@ namespace System.Text {
/// point at the end of the characters just copyied (thus you can splice in strings from multiple
/// places by calling this mulitple times.
/// </summary>
- [SecurityCritical]
unsafe private void ReplaceInPlaceAtChunk(ref StringBuilder chunk, ref int indexInChunk, char* value, int count)
{
if (count != 0)
@@ -1863,7 +1941,7 @@ namespace System.Text {
for (; ; )
{
int lengthInChunk = chunk.m_ChunkLength - indexInChunk;
- Contract.Assert(lengthInChunk >= 0, "index not in chunk");
+ Debug.Assert(lengthInChunk >= 0, "index not in chunk");
int lengthToCopy = Math.Min(lengthInChunk, count);
ThreadSafeCopy(value, chunk.m_ChunkChars, indexInChunk, lengthToCopy);
@@ -1888,7 +1966,6 @@ namespace System.Text {
/// The only way to do this is to copy all interesting variables out of the heap and then do the
/// bounds check. This is what we do here.
/// </summary>
- [SecurityCritical]
unsafe private static void ThreadSafeCopy(char* sourcePtr, char[] destination, int destinationIndex, int count)
{
if (count > 0)
@@ -1900,11 +1977,10 @@ namespace System.Text {
}
else
{
- throw new ArgumentOutOfRangeException("destinationIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(destinationIndex), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
}
}
- [SecurityCritical]
private static void ThreadSafeCopy(char[] source, int sourceIndex, char[] destination, int destinationIndex, int count)
{
if (count > 0)
@@ -1918,13 +1994,12 @@ namespace System.Text {
}
else
{
- throw new ArgumentOutOfRangeException("sourceIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+ throw new ArgumentOutOfRangeException(nameof(sourceIndex), Environment.GetResourceString("ArgumentOutOfRange_Index"));
}
}
}
// Copies the source StringBuilder to the destination IntPtr memory allocated with len bytes.
- [System.Security.SecurityCritical] // auto-generated
internal unsafe void InternalCopy(IntPtr dest, int len) {
if(len ==0)
return;
@@ -1957,13 +2032,13 @@ namespace System.Text {
/// <returns></returns>
private StringBuilder FindChunkForIndex(int index)
{
- Contract.Assert(0 <= index && index <= Length, "index not in string");
+ Debug.Assert(0 <= index && index <= Length, "index not in string");
StringBuilder ret = this;
while (ret.m_ChunkOffset > index)
ret = ret.m_ChunkPrevious;
- Contract.Assert(ret != null, "index not in string");
+ Debug.Assert(ret != null, "index not in string");
return ret;
}
@@ -1974,13 +2049,13 @@ namespace System.Text {
/// <returns></returns>
private StringBuilder FindChunkForByte(int byteIndex)
{
- Contract.Assert(0 <= byteIndex && byteIndex <= Length*sizeof(char), "Byte Index not in string");
+ Debug.Assert(0 <= byteIndex && byteIndex <= Length*sizeof(char), "Byte Index not in string");
StringBuilder ret = this;
while (ret.m_ChunkOffset*sizeof(char) > byteIndex)
ret = ret.m_ChunkPrevious;
- Contract.Assert(ret != null, "Byte Index not in string");
+ Debug.Assert(ret != null, "Byte Index not in string");
return ret;
}
@@ -2063,12 +2138,11 @@ namespace System.Text {
/// If dontMoveFollowingChars is true, then the room must be made by inserting a chunk BEFORE the
/// current chunk (this is what it does most of the time anyway)
/// </summary>
- [System.Security.SecuritySafeCritical] // auto-generated
private void MakeRoom(int index, int count, out StringBuilder chunk, out int indexInChunk, bool doneMoveFollowingChars)
{
VerifyClassInvariant();
- Contract.Assert(count > 0, "Count must be strictly positive");
- Contract.Assert(index >= 0, "Index can't be negative");
+ Debug.Assert(count > 0, "Count must be strictly positive");
+ Debug.Assert(index >= 0, "Index can't be negative");
if (count + Length > m_MaxCapacity || count + Length < count)
throw new ArgumentOutOfRangeException("requiredLength", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity"));
@@ -2133,8 +2207,8 @@ namespace System.Text {
/// </summary>
private StringBuilder(int size, int maxCapacity, StringBuilder previousBlock)
{
- Contract.Assert(size > 0, "size not positive");
- Contract.Assert(maxCapacity > 0, "maxCapacity not positive");
+ Debug.Assert(size > 0, "size not positive");
+ Debug.Assert(maxCapacity > 0, "maxCapacity not positive");
m_ChunkChars = new char[size];
m_MaxCapacity = maxCapacity;
m_ChunkPrevious = previousBlock;
@@ -2147,11 +2221,10 @@ namespace System.Text {
/// Removes 'count' characters from the logical index 'startIndex' and returns the chunk and
/// index in the chunk of that logical index in the out parameters.
/// </summary>
- [SecuritySafeCritical]
private void Remove(int startIndex, int count, out StringBuilder chunk, out int indexInChunk)
{
VerifyClassInvariant();
- Contract.Assert(startIndex >= 0 && startIndex < Length, "startIndex not in string");
+ Debug.Assert(startIndex >= 0 && startIndex < Length, "startIndex not in string");
int endIndex = startIndex + count;
@@ -2180,7 +2253,7 @@ namespace System.Text {
}
chunk = chunk.m_ChunkPrevious;
}
- Contract.Assert(chunk != null, "fell off beginning of string!");
+ Debug.Assert(chunk != null, "fell off beginning of string!");
int copyTargetIndexInChunk = indexInChunk;
int copyCount = endChunk.m_ChunkLength - endIndexInChunk;
@@ -2210,7 +2283,7 @@ namespace System.Text {
if (copyTargetIndexInChunk != endIndexInChunk) // Sometimes no move is necessary
ThreadSafeCopy(endChunk.m_ChunkChars, endIndexInChunk, endChunk.m_ChunkChars, copyTargetIndexInChunk, copyCount);
- Contract.Assert(chunk != null, "fell off beginning of string!");
+ Debug.Assert(chunk != null, "fell off beginning of string!");
VerifyClassInvariant();
}
}