diff --git a/nanoFramework.System.Text/Text/StringBuilder.cs b/nanoFramework.System.Text/Text/StringBuilder.cs
index 467f35d..01bd5e7 100644
--- a/nanoFramework.System.Text/Text/StringBuilder.cs
+++ b/nanoFramework.System.Text/Text/StringBuilder.cs
@@ -4,6 +4,8 @@
// See LICENSE file in the project root for full license information.
//
+using System.Diagnostics;
+
namespace System.Text
{
///
@@ -358,37 +360,21 @@ private StringBuilder(StringBuilder from)
#endregion
- #region Methods
-
- ///
- /// Removes all characters from the current instance.
- ///
- /// An object whose is 0 (zero).
- public StringBuilder Clear()
- {
- Length = 0;
- return this;
- }
+ #region Append methods
///
/// Appends the string representation of a specified value to this instance.
///
- /// The value to append.
+ /// The Boolean value to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(bool value)
- {
- return Append(value.ToString());
- }
+ public StringBuilder Append(bool value) => Append(value.ToString());
///
/// Appends the string representation of a specified 8-bit unsigned integer to this instance.
///
/// The value to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(byte value)
- {
- return Append(value.ToString());
- }
+ public StringBuilder Append(byte value) => Append(value.ToString());
///
/// Appends the string representation of a specified Unicode character to this instance.
@@ -397,8 +383,14 @@ public StringBuilder Append(byte value)
/// A reference to this instance after the append operation has completed.
public StringBuilder Append(char value)
{
- if (_chunkLength < _chunkChars.Length) _chunkChars[_chunkLength++] = value;
- else Append(value, 1);
+ if (_chunkLength < _chunkChars.Length)
+ {
+ _chunkChars[_chunkLength++] = value;
+ }
+ else
+ {
+ Append(value, 1);
+ }
return this;
}
@@ -408,32 +400,30 @@ public StringBuilder Append(char value)
///
/// The value to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(double value)
- {
- return Append(value.ToString());
- }
+ public StringBuilder Append(double value) => Append(value.ToString());
///
/// Appends the string representation of a specified 16-bit signed integer to this instance.
///
/// The value to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(short value)
- {
- return Append(value.ToString());
- }
+ public StringBuilder Append(short value) => Append(value.ToString());
///
/// Appends the string representation of the Unicode characters in a specified array to this instance.
///
/// The array of characters to append.
/// A reference to this instance after the append operation has completed.
+ ///
+ /// This method appends all the characters in the specified array to the current instance in the same order as they appear in value. If value is , no changes are made.
+ ///
public StringBuilder Append(char[] value)
{
if (value != null && value.Length > 0)
{
Append(value, value.Length);
}
+
return this;
}
@@ -442,30 +432,21 @@ public StringBuilder Append(char[] value)
///
/// The value to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(int value)
- {
- return Append(value.ToString());
- }
+ public StringBuilder Append(int value) => Append(value.ToString());
///
/// Appends the string representation of a specified 64-bit unsigned integer to this instance.
///
/// The value to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(long value)
- {
- return Append(value.ToString());
- }
+ public StringBuilder Append(long value) => Append(value.ToString());
///
/// Appends the string representation of a specified object to this instance.
///
/// The object to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(object value)
- {
- return value == null ? this : Append(value.ToString());
- }
+ public StringBuilder Append(object value) => value == null ? this : Append(value.ToString());
///
/// Appends a copy of the specified string to this instance.
@@ -474,28 +455,23 @@ public StringBuilder Append(object value)
/// A reference to this instance after the append operation has completed.
public StringBuilder Append(string value)
{
- if (value != null && value != string.Empty)
+ if (!string.IsNullOrEmpty(value))
{
- var chunkChars = _chunkChars;
- var chunkLength = _chunkLength;
- var length = value.Length;
- var num3 = chunkLength + length;
+ char[] chunkChars = _chunkChars;
+ int chunkLength = _chunkLength;
+ int length = value.Length;
+ int num3 = chunkLength + length;
+
if (num3 < chunkChars.Length)
{
- if (length <= 2)
- {
- if (length > 0)
- {
- chunkChars[chunkLength] = value.GetCharByIndex(0);
- }
+ char[] tmp = value.ToCharArray();
+ Array.Copy(
+ tmp,
+ 0,
+ chunkChars,
+ chunkLength,
+ length);
- if (length > 1) chunkChars[chunkLength + 1] = value.GetCharByIndex(1);
- }
- else
- {
- var tmp = value.ToCharArray();
- Array.Copy(tmp, 0, chunkChars, chunkLength, length);
- }
_chunkLength = num3;
}
else
@@ -503,6 +479,7 @@ public StringBuilder Append(string value)
AppendHelper(ref value);
}
}
+
return this;
}
@@ -512,21 +489,15 @@ public StringBuilder Append(string value)
///
/// The value to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(sbyte value)
-#pragma warning restore CS3001 // Argument type 'sbyte' is not CLS-compliant
- {
- return Append(value.ToString());
- }
+ public StringBuilder Append(sbyte value) => Append(value.ToString());
+#pragma warning restore CS3001
///
/// Appends the string representation of a specified double-precision floating-point number to this instance.
///
/// The value to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(float value)
- {
- return Append(value.ToString());
- }
+ public StringBuilder Append(float value) => Append(value.ToString());
#pragma warning disable CS3001 // Argument type 'ushort' is not CLS-compliant
///
@@ -534,11 +505,8 @@ public StringBuilder Append(float value)
///
/// The value to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(ushort value)
-#pragma warning restore CS3001 // Argument type 'ushort' is not CLS-compliant
- {
- return Append(value.ToString());
- }
+ public StringBuilder Append(ushort value) => Append(value.ToString());
+#pragma warning restore CS3001
#pragma warning disable CS3001 // Argument type 'uint' is not CLS-compliant
///
@@ -546,11 +514,8 @@ public StringBuilder Append(ushort value)
///
/// The value to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(uint value)
-#pragma warning restore CS3001 // Argument type 'uint' is not CLS-compliant
- {
- return Append(value.ToString());
- }
+ public StringBuilder Append(uint value) => Append(value.ToString());
+#pragma warning restore CS3001
#pragma warning disable CS3001 // Argument type 'ulong' is not CLS-compliant
///
@@ -558,11 +523,8 @@ public StringBuilder Append(uint value)
///
/// The value to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(ulong value)
-#pragma warning restore CS3001 // Argument type 'ulong' is not CLS-compliant
- {
- return Append(value.ToString());
- }
+ public StringBuilder Append(ulong value) => Append(value.ToString());
+#pragma warning restore CS3001
///
/// Appends a copy of a specified substring to this instance.
@@ -571,20 +533,26 @@ public StringBuilder Append(ulong value)
/// The starting position of the substring within value.
/// The number of characters in value to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(string value, int startIndex, int count)
+ public StringBuilder Append(
+ string value,
+ int startIndex,
+ int count)
{
- if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex");
- if (count < 0) throw new ArgumentOutOfRangeException("count");
- if (value == null)
+ if (startIndex < 0
+ || count < 0
+ || value == null
+ || startIndex > value.Length - count)
{
- if (startIndex != 0 || count != 0) throw new ArgumentNullException("value");
- return this;
+#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentOutOfRangeException();
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
}
+
if (count != 0)
{
- if (startIndex > value.Length - count) throw new ArgumentOutOfRangeException("startIndex");
Append(value.Substring(startIndex, count));
}
+
return this;
}
@@ -595,27 +563,29 @@ public StringBuilder Append(string value, int startIndex, int count)
/// The starting position in value.
/// The number of characters to append.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(char[] value, int startIndex, int charCount)
+ public StringBuilder Append(
+ char[] value,
+ int startIndex,
+ int charCount)
{
- if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex");
-#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
- if (charCount < 0) throw new ArgumentOutOfRangeException("count");
-#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
- if (value == null)
+ if (startIndex < 0
+ || charCount < 0
+ || value == null
+ || startIndex > value.Length - charCount)
{
- if (startIndex != 0 || charCount != 0) throw new ArgumentNullException("value");
- return this;
- }
#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
- if (charCount > value.Length - startIndex) throw new ArgumentOutOfRangeException("count");
-#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentOutOfRangeException();
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
+ }
+
if (charCount != 0)
{
- for (var i = startIndex; i < startIndex + charCount; ++i)
+ for (int i = startIndex; i < startIndex + charCount; ++i)
{
Append(value[i], 1);
}
}
+
return this;
}
@@ -625,12 +595,21 @@ public StringBuilder Append(char[] value, int startIndex, int charCount)
/// The character to append.
/// The number of times to append value.
/// A reference to this instance after the append operation has completed.
- public StringBuilder Append(char value, int repeatCount)
+ public StringBuilder Append(
+ char value,
+ int repeatCount)
{
- if (repeatCount < 0) throw new ArgumentOutOfRangeException("repeatCount");
+ if (repeatCount < 0)
+ {
+#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentOutOfRangeException();
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
+ }
+
if (repeatCount != 0)
{
- var chunkLength = _chunkLength;
+ int chunkLength = _chunkLength;
+
while (repeatCount > 0)
{
if (chunkLength < _chunkChars.Length)
@@ -647,111 +626,51 @@ public StringBuilder Append(char value, int repeatCount)
}
_chunkLength = chunkLength;
}
+
return this;
}
+ #endregion
+
+ #region Remove methods
+
///
/// Removes the specified range of characters from this instance.
///
/// The zero-based position in this instance where removal begins.
/// The number of characters to remove.
/// A reference to this instance after the excise operation has completed.
- public StringBuilder Remove(int startIndex, int length)
+ public StringBuilder Remove(
+ int startIndex,
+ int length)
{
- if (length < 0) throw new ArgumentOutOfRangeException("length");
- if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex");
+ if (length < 0
+ || startIndex < 0
+ || length > Length - startIndex)
+ {
#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
- if (length > Length - startIndex) throw new ArgumentOutOfRangeException("index");
-#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentOutOfRangeException();
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
+ }
+
if (Length == length && startIndex == 0)
{
Length = 0;
+
return this;
}
+
if (length > 0)
{
- StringBuilder builder;
- int num;
- Remove(startIndex, length, out builder, out num);
+ Remove(startIndex, length, out _, out _);
}
+
return this;
}
- ///
- /// Converts the value of this instance to a String. (Overrides ().)
- ///
- /// A string whose value is the same as this instance.
- public override string ToString()
- {
- var result = new char[Length];
- var chunkPrevious = this;
- do
- {
- if (chunkPrevious._chunkLength > 0)
- {
- var chunkChars = chunkPrevious._chunkChars;
- var chunkOffset = chunkPrevious._chunkOffset;
- var chunkLength = chunkPrevious._chunkLength;
- Array.Copy(chunkChars, 0, result, chunkOffset, chunkLength);
- }
- chunkPrevious = chunkPrevious._chunkPrevious;
- }
- while (chunkPrevious != null);
- return new string(result);
- }
+ #endregion
- ///
- /// Converts the value of a substring of this instance to a String.
- ///
- /// The starting position of the substring in this instance.
- /// The length of the substring.
- /// A string whose value is the same as the specified substring of this instance.
- public string ToString(int startIndex, int length)
- {
- var currentLength = Length;
- if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex");
- if (startIndex > currentLength) throw new ArgumentOutOfRangeException("startIndex");
- if (length < 0) throw new ArgumentOutOfRangeException("length");
- if (startIndex > currentLength - length) throw new ArgumentOutOfRangeException("length");
-
- var chunk = this;
- var sourceEndIndex = startIndex + length;
- var result = new char[length];
- var destinationIndex = length;
- while (destinationIndex > 0)
- {
- var chunkLength = sourceEndIndex - chunk._chunkOffset;
- if (chunkLength >= 0)
- {
- if (chunkLength > chunk._chunkLength)
- {
- chunkLength = chunk._chunkLength;
- }
- var leftChars = destinationIndex;
- var charCount = leftChars;
- var index = chunkLength - leftChars;
- if (index < 0)
- {
- charCount += index;
- index = 0;
- }
- destinationIndex -= charCount;
- if (charCount > 0)
- {
- var chunkChars = chunk._chunkChars;
- if (charCount + destinationIndex > length || charCount + index > chunkChars.Length)
- {
-#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
- throw new ArgumentOutOfRangeException("chunkCount");
-#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
- }
- Array.Copy(chunkChars, index, result, destinationIndex, charCount);
- }
- }
- chunk = chunk._chunkPrevious;
- }
- return new string(result);
- }
+ #region Insert methods
///
/// Inserts one or more copies of a specified string into this instance at the specified character position.
@@ -760,30 +679,55 @@ public string ToString(int startIndex, int length)
/// The string to insert.
/// The number of times to insert value.
/// A reference to this instance after insertion has completed.
- public StringBuilder Insert(int index, string value, int count)
+ public StringBuilder Insert(
+ int index,
+ string value,
+ int count)
{
- if (count < 0) throw new ArgumentOutOfRangeException("count");
+ if (count < 0
+ || index > Length)
+ {
+#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentOutOfRangeException();
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
+ }
- var length = Length;
- if (index > length) throw new ArgumentOutOfRangeException("index");
- if (value != null && value.Length != 0 && count != 0)
+ if (!string.IsNullOrEmpty(value) && count != 0)
{
- StringBuilder builder;
- int num3;
long num2 = value.Length * count;
-#pragma warning disable S112 // General exceptions should never be thrown
- if (num2 > MaxCapacity - Length) throw new OutOfMemoryException();
-#pragma warning restore S112 // General exceptions should never be thrown
- MakeRoom(index, (int)num2, out builder, out num3, false);
- var chars = value.ToCharArray();
- var charLength = chars.Length;
+
+ if (num2 > MaxCapacity - Length)
+ {
+#pragma warning disable S112 // General or reserved exceptions should never be thrown
+ throw new OutOfMemoryException();
+#pragma warning restore S112 // OK to use in .NET nanoFramework context
+ }
+
+ MakeRoom(
+ index,
+ (int)num2,
+ out StringBuilder builder,
+ out int num3,
+ false);
+
+ char[] chars = value.ToCharArray();
+ int charLength = chars.Length;
+
while (count > 0)
{
- var cindex = 0;
- ReplaceInPlaceAtChunk(ref builder, ref num3, chars, ref cindex, charLength);
+ int cindex = 0;
+
+ ReplaceInPlaceAtChunk(
+ ref builder,
+ ref num3,
+ chars,
+ ref cindex,
+ charLength);
+
--count;
}
}
+
return this;
}
@@ -795,25 +739,35 @@ public StringBuilder Insert(int index, string value, int count)
/// The starting index within value.
/// The number of characters to insert.
/// A reference to this instance after the insert operation has completed.
- public StringBuilder Insert(int index, char[] value, int startIndex, int charCount)
+ public StringBuilder Insert(
+ int index,
+ char[] value,
+ int startIndex,
+ int charCount)
{
- var length = Length;
- if (index > length) throw new ArgumentOutOfRangeException("index");
- if (value == null)
+ if (index > Length
+ || value == null
+ || startIndex < 0
+ || charCount < 0
+ || startIndex > value.Length - charCount)
{
- if (startIndex != 0 || charCount != 0) throw new ArgumentNullException("index");
- return this;
- }
- if (startIndex < 0) throw new ArgumentOutOfRangeException("startIndex");
#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
- if (charCount < 0) throw new ArgumentOutOfRangeException("count");
-#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
- if (startIndex > value.Length - charCount) throw new ArgumentOutOfRangeException("startIndex");
- if (charCount > 0) Insert(index, new string(value, startIndex, charCount), 1);
+ throw new ArgumentOutOfRangeException();
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
+ }
+
+ if (charCount > 0)
+ {
+ Insert(index, new string(value, startIndex, charCount), 1);
+ }
return this;
}
+ #endregion
+
+ #region Replace methods
+
///
/// Replaces, within a substring of this instance, all occurrences of a specified character with another specified character.
///
@@ -822,35 +776,55 @@ public StringBuilder Insert(int index, char[] value, int startIndex, int charCou
/// The position in this instance where the substring begins.
/// The length of the substring.
/// A reference to this instance with replaced by in the range from to + - 1.
- public StringBuilder Replace(char oldChar, char newChar, int startIndex, int count)
+ public StringBuilder Replace(
+ char oldChar,
+ char newChar,
+ int startIndex,
+ int count)
{
- var length = Length;
- if (startIndex > length) throw new ArgumentOutOfRangeException("startIndex");
- if (count < 0 || startIndex > length - count) throw new ArgumentOutOfRangeException("count");
-
- var num2 = startIndex + count;
- var chunkPrevious = this;
- Label_0048:
- var num3 = num2 - chunkPrevious._chunkOffset;
- var num4 = startIndex - chunkPrevious._chunkOffset;
- if (num3 >= 0)
+ if (startIndex > Length
+ || count < 0
+ || startIndex > Length - count)
+ {
+#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentOutOfRangeException();
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
+ }
+
+ int num2 = startIndex + count;
+ StringBuilder chunkPrevious = this;
+
+ while (true)
{
- var index = MathInternal.Max(num4, 0);
- var num6 = MathInternal.Min(chunkPrevious._chunkLength, num3);
- while (index < num6)
+ int num3 = num2 - chunkPrevious._chunkOffset;
+ int num4 = startIndex - chunkPrevious._chunkOffset;
+
+ if (num3 >= 0)
{
- if (chunkPrevious._chunkChars[index] == oldChar)
+ int index = MathInternal.Max(num4, 0);
+ int num6 = MathInternal.Min(chunkPrevious._chunkLength, num3);
+
+ while (index < num6)
{
- chunkPrevious._chunkChars[index] = newChar;
+ if (chunkPrevious._chunkChars[index] == oldChar)
+ {
+ chunkPrevious._chunkChars[index] = newChar;
+ }
+
+ index++;
}
- index++;
+ }
+
+ if (num4 < 0)
+ {
+ chunkPrevious = chunkPrevious._chunkPrevious;
+ }
+ else
+ {
+ break;
}
}
- if (num4 < 0)
- {
- chunkPrevious = chunkPrevious._chunkPrevious;
- goto Label_0048;
- }
+
return this;
}
@@ -860,10 +834,7 @@ public StringBuilder Replace(char oldChar, char newChar, int startIndex, int cou
/// The character to replace.
/// The character that replaces .
/// A reference to this instance with replaced by .
- public StringBuilder Replace(char oldChar, char newChar)
- {
- return Replace(oldChar, newChar, 0, Length);
- }
+ public StringBuilder Replace(char oldChar, char newChar) => Replace(oldChar, newChar, 0, Length);
///
/// Replaces, within a substring of this instance, all occurrences of a specified string with another specified string.
@@ -873,73 +844,78 @@ public StringBuilder Replace(char oldChar, char newChar)
/// The position in this instance where the substring begins.
/// The length of the substring.
/// A reference to this instance with all instances of replaced by in the range from to + - 1.
- public StringBuilder Replace(string oldValue, string newValue, int startIndex, int count)
+ public StringBuilder Replace(
+ string oldValue,
+ string newValue,
+ int startIndex,
+ int count)
{
- var length = Length;
- if (startIndex > length) throw new ArgumentOutOfRangeException("startIndex");
- if (count < 0 || startIndex > length - count) throw new ArgumentOutOfRangeException("count");
- if (oldValue == null) throw new ArgumentNullException("oldValue");
- if (oldValue.Length == 0) throw new ArgumentException("oldValue");
- if (newValue == null) newValue = string.Empty;
-
- var newLength = newValue.Length;
- var oldLength = oldValue.Length;
+ if (startIndex > Length
+ || count < 0
+ || startIndex > Length - count
+ || oldValue == null
+ || oldValue.Length == 0)
+ {
+#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentOutOfRangeException();
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
+ }
+
+ newValue ??= string.Empty;
+
+ int newLength = newValue.Length;
+ int oldLength = oldValue.Length;
int[] sourceArray = null;
- var replacementsCount = 0;
- var chunk = FindChunkForIndex(startIndex);
- var indexInChunk = startIndex - chunk._chunkOffset;
- //While there is a replacement remaining
+ int replacementsCount = 0;
+ StringBuilder chunk = FindChunkForIndex(startIndex);
+ int indexInChunk = startIndex - chunk._chunkOffset;
+
while (count > 0)
{
- //If the old value if found in the chunk at the index
if (StartsWith(chunk, indexInChunk, count, oldValue))
{
- //If we need to allocate for a match then do so
if (sourceArray == null)
{
sourceArray = new int[5];
}
else if (replacementsCount >= sourceArray.Length)
{
- //We have more matches than allocated for resize the buffer
- var destinationArray = new int[sourceArray.Length * 3 / 2 + 4];
- Array.Copy(sourceArray, destinationArray, sourceArray.Length);
+ int[] destinationArray = new int[sourceArray.Length * 3 / 2 + 4];
+
+ Array.Copy(
+ sourceArray,
+ destinationArray,
+ sourceArray.Length);
+
sourceArray = destinationArray;
}
- //Save the index in the next avilable replacement slot
+
sourceArray[replacementsCount] = indexInChunk;
++replacementsCount;
- //Move the index pointer
indexInChunk += oldLength;
- //Decrement the count
count -= oldLength;
}
else
{
-
- //A match at the index was not found
- //Move the pointer
++indexInChunk;
- //Decrement the count
--count;
}
- //If we are past the chunk boundry or the no replacements remaining
+
if (indexInChunk >= chunk._chunkLength || count == 0)
{
- //Determine the index
- var index = indexInChunk + chunk._chunkOffset;
- //Replace the remaining characters
+ int index = indexInChunk + chunk._chunkOffset;
+
ReplaceAllInChunk(sourceArray, replacementsCount, chunk, oldLength, newValue);
- //Move the index
+
index += (newLength - oldLength) * replacementsCount;
- //Resert the replacements count
replacementsCount = 0;
- //Find the next chunk and continue
+
chunk = FindChunkForIndex(index);
- //Move the index reletive to inside the chunk
+
indexInChunk = index - chunk._chunkOffset;
}
}
+
return this;
}
@@ -949,9 +925,135 @@ public StringBuilder Replace(string oldValue, string newValue, int startIndex, i
/// The string to replace.
/// The string that replaces , or .
/// A reference to this instance with all instances of replaced by .
- public StringBuilder Replace(string oldValue, string newValue)
+ public StringBuilder Replace(
+ string oldValue,
+ string newValue) => Replace(
+ oldValue,
+ newValue,
+ 0,
+ Length);
+
+ #endregion
+
+ #region Other methods
+
+ ///
+ /// Removes all characters from the current instance.
+ ///
+ /// An object whose is 0 (zero).
+ public StringBuilder Clear()
+ {
+ Length = 0;
+ return this;
+ }
+
+ ///
+ /// Converts the value of this instance to a String. (Overrides ().)
+ ///
+ /// A string whose value is the same as this instance.
+ public override string ToString()
+ {
+ char[] result = new char[Length];
+ StringBuilder chunkPrevious = this;
+
+ do
+ {
+ if (chunkPrevious._chunkLength > 0)
+ {
+ char[] chunkChars = chunkPrevious._chunkChars;
+ int chunkOffset = chunkPrevious._chunkOffset;
+ int chunkLength = chunkPrevious._chunkLength;
+
+ Array.Copy(
+ chunkChars,
+ 0,
+ result,
+ chunkOffset,
+ chunkLength);
+ }
+
+ chunkPrevious = chunkPrevious._chunkPrevious;
+ }
+ while (chunkPrevious != null);
+
+ return new string(result);
+ }
+
+ ///
+ /// Converts the value of a substring of this instance to a .
+ ///
+ /// The starting position of the substring in this instance.
+ /// The length of the substring.
+ /// A string whose value is the same as the specified substring of this instance.
+ public string ToString(
+ int startIndex,
+ int length)
{
- return Replace(oldValue, newValue, 0, Length);
+ int currentLength = Length;
+
+ if (startIndex < 0
+ || startIndex > currentLength
+ || length < 0
+ || startIndex > currentLength - length)
+ {
+#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentOutOfRangeException();
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
+ }
+
+ StringBuilder chunk = this;
+ int sourceEndIndex = startIndex + length;
+ char[] result = new char[length];
+ int destinationIndex = length;
+
+ while (destinationIndex > 0)
+ {
+ int chunkLength = sourceEndIndex - chunk._chunkOffset;
+
+ if (chunkLength >= 0)
+ {
+ if (chunkLength > chunk._chunkLength)
+ {
+ chunkLength = chunk._chunkLength;
+ }
+
+ int leftChars = destinationIndex;
+ int charCount = leftChars;
+ int index = chunkLength - leftChars;
+
+ if (index < 0)
+ {
+ charCount += index;
+ index = 0;
+ }
+
+ destinationIndex -= charCount;
+
+ if (charCount > 0)
+ {
+ char[] chunkChars = chunk._chunkChars;
+
+ if (charCount + destinationIndex > length
+ || charCount + index > chunkChars.Length)
+ {
+#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentOutOfRangeException();
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
+ }
+
+ Array.Copy(
+ chunkChars,
+ index,
+ result,
+ destinationIndex,
+ charCount);
+ }
+ }
+
+ chunk = chunk._chunkPrevious;
+ }
+
+ return new string(result);
}
///
@@ -968,10 +1070,7 @@ public StringBuilder AppendLine(string str)
/// Appends the default line terminator to the end of the current object.
///
/// A reference to this instance after the append operation has completed.
- public StringBuilder AppendLine()
- {
- return Append("\r\n");
- }
+ public StringBuilder AppendLine() => Append("\r\n");
#endregion
@@ -979,8 +1078,17 @@ public StringBuilder AppendLine()
internal int EnsureCapacity(int capacity)
{
- if (capacity < 0) throw new ArgumentOutOfRangeException("capacity");
- if (Capacity < capacity) Capacity = capacity;
+ if (capacity < 0)
+ {
+#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ throw new ArgumentOutOfRangeException();
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
+ }
+
+ if (Capacity < capacity)
+ {
+ Capacity = capacity;
+ }
return Capacity;
}
@@ -989,135 +1097,253 @@ internal bool StartsWith(StringBuilder chunk, int indexInChunk, int count, strin
{
for (int i = 0, e = value.Length; i < e; ++i)
{
- if (count == 0) return false;
+ if (count == 0)
+ {
+ return false;
+ }
+
if (indexInChunk >= chunk._chunkLength)
{
chunk = Next(chunk);
- if (chunk == null) return false;
+
+ if (chunk == null)
+ {
+ return false;
+ }
+
indexInChunk = 0;
}
- if (value.GetCharByIndex(i) != chunk._chunkChars[indexInChunk]) return false;
+
+ if (value.GetCharByIndex(i) != chunk._chunkChars[indexInChunk])
+ {
+ return false;
+ }
+
++indexInChunk;
--count;
}
+
return true;
}
- internal void ReplaceAllInChunk(int[] replacements, int replacementsCount, StringBuilder sourceChunk, int removeCount, string value)
+ internal void ReplaceAllInChunk(
+ int[] replacements,
+ int replacementsCount,
+ StringBuilder sourceChunk,
+ int removeCount,
+ string value)
{
//If there is a replacement to occur
if (replacementsCount > 0)
{
- //Determine the amount of characters to remove
- var count = (value.Length - removeCount) * replacementsCount;
- //Scope the working chunk
- var chunk = sourceChunk;
- //Determine the index of the first replacement
- var indexInChunk = replacements[0];
- //If there is a character being added make room
- if (count > 0) MakeRoom(chunk._chunkOffset + indexInChunk, count, out chunk, out indexInChunk, true);
- //Start at the first replacement
- var index = 0;
- var replacementIndex = 0;
- var chars = value.ToCharArray();
+ // Determine the amount of characters to remove
+ int count = (value.Length - removeCount) * replacementsCount;
+
+ // Scope the working chunk
+ StringBuilder chunk = sourceChunk;
+
+ // Determine the index of the first replacement
+ int indexInChunk = replacements[0];
+
+ // If there is a character being added make room
+ if (count > 0)
+ {
+ MakeRoom(
+ chunk._chunkOffset + indexInChunk,
+ count,
+ out chunk,
+ out indexInChunk,
+ true);
+ }
+
+ // Start at the first replacement
+ int index = 0;
+ int replacementIndex = 0;
+ char[] chars = value.ToCharArray();
+
ReplaceValue:
- //Replace the value
- ReplaceInPlaceAtChunk(ref chunk, ref indexInChunk, chars, ref replacementIndex, value.Length);
- if (replacementIndex == value.Length) replacementIndex = 0;
+ // Replace the value
+ ReplaceInPlaceAtChunk(
+ ref chunk,
+ ref indexInChunk,
+ chars,
+ ref replacementIndex,
+ value.Length);
+
+ if (replacementIndex == value.Length)
+ {
+ replacementIndex = 0;
+ }
- //Determine the next replacement
- var valueIndex = replacements[index] + removeCount;
- //Move the pointer of the working replacement
+ // Determine the next replacement
+ int valueIndex = replacements[index] + removeCount;
+
+ // Move the pointer of the working replacement
++index;
- //If we are not past the replacement boundry
+
+ // If we are not past the replacement boundary
if (index < replacementsCount)
{
- //Determine the next replacement
- var nextIndex = replacements[index];
- //If there is a character remaining to be replaced
+ // Determine the next replacement
+ int nextIndex = replacements[index];
+
+ // If there is a character remaining to be replaced
if (count != 0)
{
- //Replace it
- ReplaceInPlaceAtChunk(ref chunk, ref indexInChunk, sourceChunk._chunkChars, ref valueIndex, nextIndex - valueIndex);
- }//Move the pointer
- else indexInChunk += nextIndex - valueIndex;
- goto ReplaceValue;//Finish replacing
+ // Replace it
+ ReplaceInPlaceAtChunk(
+ ref chunk,
+ ref indexInChunk,
+ sourceChunk._chunkChars,
+ ref valueIndex,
+ nextIndex - valueIndex);
+ }
+ //Move the pointer
+ else
+ {
+ indexInChunk += nextIndex - valueIndex;
+ }
+
+ // Finish replacing
+ goto ReplaceValue;
}
- //We are are done and there is charcters to be removed they are at the end
+
+ // We are are done and there is charcters to be removed they are at the end
if (count < 0)
{
- //Remove them by negating the count to make it positive the chars removed are from (chunk.m_ChunkOffset + indexInChunk) to -count
- Remove(chunk._chunkOffset + indexInChunk, -count, out chunk, out indexInChunk);
+ // Remove them by negating the count to make it positive the chars removed are from (chunk.m_ChunkOffset + indexInChunk) to -count
+ Remove(
+ chunk._chunkOffset + indexInChunk,
+ -count,
+ out chunk,
+ out indexInChunk);
}
}
}
internal StringBuilder Next(StringBuilder chunk)
{
- return chunk == this ? null : FindChunkForIndex(chunk._chunkOffset + chunk._chunkLength);
+ return chunk == this ? null : FindChunkForIndex(chunk._chunkOffset
+ + chunk._chunkLength);
}
- private void ReplaceInPlaceAtChunk(ref StringBuilder chunk, ref int indexInChunk, char[] value, ref int valueIndex, int count)
+ private void ReplaceInPlaceAtChunk(
+ ref StringBuilder chunk,
+ ref int indexInChunk,
+ char[] value,
+ ref int valueIndex,
+ int count)
{
- if (count == 0) return;
+ if (count == 0)
+ {
+ return;
+ }
while (true)
{
- //int num = chunk.m_ChunkLength - indexInChunk;
- var length = MathInternal.Min(chunk._chunkLength - indexInChunk, count);
- //ThreadSafeCopy(value, ref valueIndex, chunk.m_ChunkChars, ref indexInChunk, num2);
- Array.Copy(value, valueIndex, chunk._chunkChars, indexInChunk, length);
+ int length = MathInternal.Min(chunk._chunkLength - indexInChunk, count);
+
+ Array.Copy(
+ value,
+ valueIndex,
+ chunk._chunkChars,
+ indexInChunk,
+ length);
+
indexInChunk += length;
+
if (indexInChunk >= chunk._chunkLength)
{
chunk = Next(chunk);
indexInChunk = 0;
}
+
count -= length;
valueIndex += length;
- if (count == 0) return;
+
+ if (count == 0)
+ {
+ return;
+ }
}
}
- internal void MakeRoom(int index, int count, out StringBuilder chunk, out int indexInChunk, bool doneMoveFollowingChars)
+ internal void MakeRoom(
+ int index,
+ int count,
+ out StringBuilder chunk,
+ out int indexInChunk,
+ bool doneMoveFollowingChars)
{
#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
- if (count + Length > _maxCapacity) throw new ArgumentOutOfRangeException("requiredLength");
-#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
+ if (count + Length > _maxCapacity)
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
+
chunk = this;
+
while (chunk._chunkOffset > index)
{
chunk._chunkOffset += count;
chunk = chunk._chunkPrevious;
}
+
indexInChunk = index - chunk._chunkOffset;
- if (!doneMoveFollowingChars && chunk._chunkLength <= 0x20 && chunk._chunkChars.Length - chunk._chunkLength >= count)
+
+ if (!doneMoveFollowingChars
+ && chunk._chunkLength <= 0x20
+ && chunk._chunkChars.Length - chunk._chunkLength >= count)
{
- var chunkLength = chunk._chunkLength;
+ int chunkLength = chunk._chunkLength;
+
while (chunkLength > indexInChunk)
{
chunkLength--;
chunk._chunkChars[chunkLength + count] = chunk._chunkChars[chunkLength];
}
+
chunk._chunkLength += count;
}
else
{
- var builder = new StringBuilder(MathInternal.Max(count, 0x10), chunk._maxCapacity, chunk._chunkPrevious);
+ StringBuilder builder = new(
+ MathInternal.Max(count, DefaultCapacity),
+ chunk._maxCapacity,
+ chunk._chunkPrevious);
+
builder._chunkLength = count;
- var length = MathInternal.Min(count, indexInChunk);
+
+ int length = MathInternal.Min(count, indexInChunk);
+
if (length > 0)
{
- Array.Copy(chunk._chunkChars, 0, builder._chunkChars, 0, length);
- var nextLength = indexInChunk - length;
+ Array.Copy(
+ chunk._chunkChars,
+ 0,
+ builder._chunkChars,
+ 0,
+ length);
+
+ int nextLength = indexInChunk - length;
+
if (nextLength >= 0)
{
- Array.Copy(chunk._chunkChars, length, chunk._chunkChars, 0, nextLength);
+ Array.Copy(
+ chunk._chunkChars,
+ length,
+ chunk._chunkChars,
+ 0,
+ nextLength);
+
indexInChunk = nextLength;
}
}
+
chunk._chunkPrevious = builder;
chunk._chunkOffset += count;
+
if (length < count)
{
chunk = builder;
@@ -1128,43 +1354,67 @@ internal void MakeRoom(int index, int count, out StringBuilder chunk, out int in
internal StringBuilder FindChunkForIndex(int index)
{
- var chunkPrevious = this;
- while (chunkPrevious._chunkOffset > index) chunkPrevious = chunkPrevious._chunkPrevious;
+ StringBuilder chunkPrevious = this;
+
+ while (chunkPrevious._chunkOffset > index)
+ {
+ chunkPrevious = chunkPrevious._chunkPrevious;
+ }
+
return chunkPrevious;
}
internal void AppendHelper(ref string value)
{
- if (value == null || value == string.Empty) return;
+ if (value == null || value == string.Empty)
+ {
+ return;
+ }
+
Append(value.ToCharArray(), value.Length);
}
internal void ExpandByABlock(int minBlockCharCount)
{
+ Debug.Assert(Capacity == Length, nameof(ExpandByABlock) + " should only be called when there is no space left.");
+ Debug.Assert(minBlockCharCount > 0);
+
#pragma warning disable S3928 // Parameter names used into ArgumentException constructors should match an existing one
- if (minBlockCharCount + Length > _maxCapacity) throw new ArgumentOutOfRangeException("requiredLength");
-#pragma warning restore S3928 // Parameter names used into ArgumentException constructors should match an existing one
- var num = MathInternal.Max(minBlockCharCount, MathInternal.Min(Length, 0x1f40));
+ if (minBlockCharCount + Length > _maxCapacity || minBlockCharCount + Length < minBlockCharCount)
+ {
+ throw new ArgumentOutOfRangeException();
+ }
+#pragma warning restore S3928 // OK to use in .NET nanoFramework context
+
+ // - We always need to make the new chunk at least as big as was requested (`minBlockCharCount`).
+ // - We'd also prefer to make it at least at big as the current length (thus doubling capacity).
+ // - But this is only up to a maximum, so we stay in the small object heap, and never allocate
+ // really big chunks even if the string gets really big.
+ int newBlockLength = MathInternal.Max(
+ minBlockCharCount,
+ MathInternal.Min(Length, MaxChunkSize));
+
+
+ // Allocate the array before updating any state to avoid leaving inconsistent state behind in case of out of memory exception
+ char[] chunkChars = new char[newBlockLength];
+
+ // Move all of the data from this chunk to a new one, via a few O(1) reference adjustments.
+ // Then, have this chunk point to the new one as its predecessor.
_chunkPrevious = new StringBuilder(this);
_chunkOffset += _chunkLength;
_chunkLength = 0;
- //If Allocated does not match required storage
- if (_chunkOffset + num < num)
- {
- _chunkChars = null;
-#pragma warning disable S112 // General exceptions should never be thrown
- throw new OutOfMemoryException();
-#pragma warning restore S112 // General exceptions should never be thrown
- }
- _chunkChars = new char[num];
+
+ _chunkChars = chunkChars;
}
internal void Remove(int startIndex, int count, out StringBuilder chunk, out int indexInChunk)
{
- var num = startIndex + count;
+ int num = startIndex + count;
chunk = this;
+
StringBuilder builder = null;
- var sourceIndex = 0;
+ int sourceIndex = 0;
+
while (true)
{
if (num - chunk._chunkOffset >= 0)
@@ -1174,59 +1424,99 @@ internal void Remove(int startIndex, int count, out StringBuilder chunk, out int
builder = chunk;
sourceIndex = num - builder._chunkOffset;
}
+
if (startIndex - chunk._chunkOffset >= 0)
{
indexInChunk = startIndex - chunk._chunkOffset;
- var destinationIndex = indexInChunk;
- var num4 = builder._chunkLength - sourceIndex;
+ int destinationIndex = indexInChunk;
+ int num4 = builder._chunkLength - sourceIndex;
+
if (builder != chunk)
{
destinationIndex = 0;
chunk._chunkLength = indexInChunk;
builder._chunkPrevious = chunk;
builder._chunkOffset = chunk._chunkOffset + chunk._chunkLength;
+
if (indexInChunk == 0)
{
builder._chunkPrevious = chunk._chunkPrevious;
chunk = builder;
}
}
+
builder._chunkLength -= sourceIndex - destinationIndex;
+
if (destinationIndex != sourceIndex)
{
- //ThreadSafeCopy(builder.m_ChunkChars, ref sourceIndex, builder.m_ChunkChars, ref destinationIndex, num4);
- Array.Copy(builder._chunkChars, sourceIndex, builder._chunkChars, destinationIndex, num4);
+ Array.Copy(
+ builder._chunkChars,
+ sourceIndex,
+ builder._chunkChars,
+ destinationIndex,
+ num4);
}
return;
}
}
- else chunk._chunkOffset -= count;
+ else
+ {
+ chunk._chunkOffset -= count;
+ }
+
chunk = chunk._chunkPrevious;
}
}
- internal void Append(char[] value, int valueCount)
+ internal void Append(
+ char[] value,
+ int valueCount)
{
- var num = valueCount + _chunkLength;
+ if (value == null)
+ {
+ return;
+ }
+
+ int num = valueCount + _chunkLength;
+
if (num <= _chunkChars.Length)
{
- //ThreadSafeCopy(value, this.m_ChunkChars, this.m_ChunkLength, valueCount);
- Array.Copy(value, 0, _chunkChars, _chunkLength, valueCount);
+ Array.Copy(
+ value,
+ 0,
+ _chunkChars,
+ _chunkLength,
+ valueCount);
+
_chunkLength = num;
}
else
{
- var count = _chunkChars.Length - _chunkLength;
+ int count = _chunkChars.Length - _chunkLength;
+
if (count > 0)
{
- //ThreadSafeCopy(value, this.m_ChunkChars, this.m_ChunkLength, count);
- Array.Copy(value, 0, _chunkChars, _chunkLength, count);
+ Array.Copy(
+ value,
+ 0,
+ _chunkChars,
+ _chunkLength,
+ count);
+
_chunkLength = _chunkChars.Length;
}
- var minBlockCharCount = valueCount - count;
+
+ int minBlockCharCount = valueCount - count;
+
ExpandByABlock(minBlockCharCount);
- //ThreadSafeCopy(value + count, this.m_ChunkChars, 0, minBlockCharCount);
- Array.Copy(value, count, _chunkChars, 0, minBlockCharCount);
+
+ Array.Copy(
+ value,
+ count,
+ _chunkChars,
+ 0,
+ minBlockCharCount);
+
_chunkLength = minBlockCharCount;
}
}