Cleanup most code in StringBuilder (dotnet/coreclr#10156)
authorJames Ko <jamesqko@gmail.com>
Sun, 18 Jun 2017 13:53:45 +0000 (09:53 -0400)
committerStephen Toub <stoub@microsoft.com>
Sun, 18 Jun 2017 13:53:45 +0000 (09:53 -0400)
* Cleanup most code in StringBuilder

* Respond to PR feedback

* Document StringBuilder's fields

* VerifyClassInvariant -> AssertInvariants

* Fix always-true assert

* Respond to PR feedback from @stephentoub

Commit migrated from https://github.com/dotnet/coreclr/commit/a8aa9b6c8ef0ce6e1f0cb482a1fbe619926e7c05

src/coreclr/src/mscorlib/shared/System/Text/StringBuilder.cs
src/coreclr/src/mscorlib/src/System/Text/StringBuilder.CoreCLR.cs

index 1167016..34533a9 100644 (file)
@@ -25,15 +25,6 @@ namespace System.Text
     // 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);
-    // Console.WriteLine(sb1);
-    // Console.WriteLine(sb2);
-    // 
     [Serializable]
     [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
     public sealed partial class StringBuilder : ISerializable
@@ -42,27 +33,42 @@ namespace System.Text
         // a chunk of the string.  It turns out string as a whole can also be represented as just a chunk, 
         // so that is what we do.  
 
-        //
-        //
-        //  CLASS VARIABLES
-        //
-        //
-        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 logical offset (sum of all characters in previous blocks)
-        internal int m_MaxCapacity = 0;
-
-        //
-        //
-        // STATIC CONSTANTS
-        //
-        //
+        /// <summary>
+        /// The character buffer for this chunk.
+        /// </summary>
+        internal char[] m_ChunkChars;
+
+        /// <summary>
+        /// The chunk that logically precedes this chunk.
+        /// </summary>
+        internal StringBuilder m_ChunkPrevious;
+
+        /// <summary>
+        /// The number of characters in this chunk.
+        /// This is the number of elements in <see cref="m_ChunkChars"/> that are in use, from the start of the buffer.
+        /// </summary>
+        internal int m_ChunkLength;
+
+        /// <summary>
+        /// The logical offset of this chunk's characters in the string it is a part of.
+        /// This is the sum of the number of characters in preceding blocks.
+        /// </summary>
+        internal int m_ChunkOffset;
+
+        /// <summary>
+        /// The maximum capacity this builder is allowed to have.
+        /// </summary>
+        internal int m_MaxCapacity;
+
+        /// <summary>
+        /// The default capacity of a <see cref="StringBuilder"/>.
+        /// </summary>
         internal const int DefaultCapacity = 16;
-        private const String CapacityField = "Capacity"; // Do not rename (binary serialization)
-        private const String MaxCapacityField = "m_MaxCapacity"; // Do not rename (binary serialization)
-        private const String StringValueField = "m_StringValue"; // Do not rename (binary serialization)
-        private const String ThreadIDField = "m_currentThread"; // Do not rename (binary serialization)
+
+        private const string CapacityField = "Capacity"; // Do not rename (binary serialization)
+        private const string MaxCapacityField = "m_MaxCapacity"; // Do not rename (binary serialization)
+        private const string StringValueField = "m_StringValue"; // Do not rename (binary serialization)
+        private const string ThreadIDField = "m_currentThread"; // Do not rename (binary serialization)
 
         // We want to keep chunk arrays out of large object heap (< 85K bytes ~ 40K chars) to be sure.
         // Making the maximum chunk size big means less allocation code called, but also more waste
@@ -70,62 +76,59 @@ namespace System.Text
         // within a buffer).  
         internal const int MaxChunkSize = 8000;
 
-        //
-        //
-        //CONSTRUCTORS
-        //
-        //
-
-        // Creates a new empty string builder (i.e., it represents String.Empty)
-        // with the default capacity (16 characters).
+        /// <summary>
+        /// Initializes a new instance of the <see cref="StringBuilder"/> class.
+        /// </summary>
         public StringBuilder()
         {
             m_MaxCapacity = int.MaxValue;
             m_ChunkChars = new char[DefaultCapacity];
         }
 
-        // Create a new empty string builder (i.e., it represents String.Empty)
-        // with the specified capacity.
+        /// <summary>
+        /// Initializes a new instance of the <see cref="StringBuilder"/> class.
+        /// </summary>
+        /// <param name="capacity">The initial capacity of this builder.</param>
         public StringBuilder(int capacity)
             : this(capacity, int.MaxValue)
         {
         }
 
-        // Creates a new string builder from the specified string.  If value
-        // is a null String (i.e., if it represents String.NullString)
-        // then the new string builder will also be null (i.e., it will also represent
-        //  String.NullString).
-        // 
-        public StringBuilder(String value)
+        /// <summary>
+        /// Initializes a new instance of the <see cref="StringBuilder"/> class.
+        /// </summary>
+        /// <param name="value">The initial contents of this builder.</param>
+        public StringBuilder(string value)
             : this(value, DefaultCapacity)
         {
         }
 
-        // Creates a new string builder from the specified string with the specified 
-        // capacity.  If value is a null String (i.e., if it represents 
-        // String.NullString) then the new string builder will also be null 
-        // (i.e., it will also represent String.NullString).
-        // The maximum number of characters this string may contain is set by capacity.
-        // 
-        public StringBuilder(String value, int capacity)
-            : this(value, 0, ((value != null) ? value.Length : 0), capacity)
+        /// <summary>
+        /// Initializes a new instance of the <see cref="StringBuilder"/> class.
+        /// </summary>
+        /// <param name="value">The initial contents of this builder.</param>
+        /// <param name="capacity">The initial capacity of this builder.</param>
+        public StringBuilder(string value, int capacity)
+            : this(value, 0, value?.Length ?? 0, capacity)
         {
         }
 
-        // Creates a new string builder from the specifed substring with the specified
-        // capacity.  The maximum number of characters is set by capacity.
-        // 
-        public StringBuilder(String value, int startIndex, int length, int capacity)
+        /// <summary>
+        /// Initializes a new instance of the <see cref="StringBuilder"/> class.
+        /// </summary>
+        /// <param name="value">The initial contents of this builder.</param>
+        /// <param name="startIndex">The index to start in <paramref name="value"/>.</param>
+        /// <param name="length">The number of characters to read in <paramref name="value"/>.</param>
+        /// <param name="capacity">The initial capacity of this builder.</param>
+        public StringBuilder(string value, int startIndex, int length, int capacity)
         {
             if (capacity < 0)
             {
-                throw new ArgumentOutOfRangeException(nameof(capacity),
-                    SR.Format(SR.ArgumentOutOfRange_MustBePositive, nameof(capacity)));
+                throw new ArgumentOutOfRangeException(nameof(capacity), SR.Format(SR.ArgumentOutOfRange_MustBePositive, nameof(capacity)));
             }
             if (length < 0)
             {
-                throw new ArgumentOutOfRangeException(nameof(length),
-                    SR.Format(SR.ArgumentOutOfRange_MustBeNonNegNum, nameof(length)));
+                throw new ArgumentOutOfRangeException(nameof(length), SR.Format(SR.ArgumentOutOfRange_MustBeNonNegNum, nameof(length)));
             }
             if (startIndex < 0)
             {
@@ -135,19 +138,19 @@ namespace System.Text
 
             if (value == null)
             {
-                value = String.Empty;
+                value = string.Empty;
             }
             if (startIndex > value.Length - length)
             {
                 throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_IndexLength);
             }
-            m_MaxCapacity = Int32.MaxValue;
+
+            m_MaxCapacity = int.MaxValue;
             if (capacity == 0)
             {
                 capacity = DefaultCapacity;
             }
-            if (capacity < length)
-                capacity = length;
+            capacity = Math.Max(capacity, length);
 
             m_ChunkChars = new char[capacity];
             m_ChunkLength = length;
@@ -155,12 +158,17 @@ namespace System.Text
             unsafe
             {
                 fixed (char* sourcePtr = value)
+                {
                     ThreadSafeCopy(sourcePtr + startIndex, m_ChunkChars, 0, length);
+                }
             }
         }
 
-        // Creates an empty StringBuilder with a minimum capacity of capacity
-        // and a maximum capacity of maxCapacity.
+        /// <summary>
+        /// Initializes a new instance of the <see cref="StringBuilder"/> class.
+        /// </summary>
+        /// <param name="capacity">The initial capacity of this builder.</param>
+        /// <param name="maxCapacity">The maximum capacity of this builder.</param>
         public StringBuilder(int capacity, int maxCapacity)
         {
             if (capacity > maxCapacity)
@@ -173,8 +181,7 @@ namespace System.Text
             }
             if (capacity < 0)
             {
-                throw new ArgumentOutOfRangeException(nameof(capacity),
-                    SR.Format(SR.ArgumentOutOfRange_MustBePositive, nameof(capacity)));
+                throw new ArgumentOutOfRangeException(nameof(capacity), SR.Format(SR.ArgumentOutOfRange_MustBePositive, nameof(capacity)));
             }
             Contract.EndContractBlock();
 
@@ -190,7 +197,9 @@ namespace System.Text
         private StringBuilder(SerializationInfo info, StreamingContext context)
         {
             if (info == null)
+            {
                 throw new ArgumentNullException(nameof(info));
+            }
             Contract.EndContractBlock();
 
             int persistedCapacity = 0;
@@ -215,7 +224,7 @@ namespace System.Text
                         capacityPresent = true;
                         break;
                     default:
-                        // Ignore other fields for forward compatibility.
+                        // Ignore other fields for forwards-compatibility.
                         break;
                 }
             }
@@ -223,7 +232,7 @@ namespace System.Text
             // Check values and set defaults
             if (persistedString == null)
             {
-                persistedString = String.Empty;
+                persistedString = string.Empty;
             }
             if (persistedMaxCapacity < 1 || persistedString.Length > persistedMaxCapacity)
             {
@@ -233,16 +242,9 @@ namespace System.Text
             if (!capacityPresent)
             {
                 // StringBuilder in V1.X did not persist the Capacity, so this is a valid legacy code path.
-                persistedCapacity = DefaultCapacity;
-                if (persistedCapacity < persistedString.Length)
-                {
-                    persistedCapacity = persistedString.Length;
-                }
-                if (persistedCapacity > persistedMaxCapacity)
-                {
-                    persistedCapacity = persistedMaxCapacity;
-                }
+                persistedCapacity = Math.Min(Math.Max(DefaultCapacity, persistedString.Length), persistedMaxCapacity);
             }
+
             if (persistedCapacity < 0 || persistedCapacity < persistedString.Length || persistedCapacity > persistedMaxCapacity)
             {
                 throw new SerializationException(SR.Serialization_StringBuilderCapacity);
@@ -254,7 +256,7 @@ namespace System.Text
             persistedString.CopyTo(0, m_ChunkChars, 0, persistedString.Length);
             m_ChunkLength = persistedString.Length;
             m_ChunkPrevious = null;
-            VerifyClassInvariant();
+            AssertInvariants();
         }
 
         void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
@@ -265,7 +267,7 @@ namespace System.Text
             }
             Contract.EndContractBlock();
 
-            VerifyClassInvariant();
+            AssertInvariants();
             info.AddValue(MaxCapacityField, m_MaxCapacity);
             info.AddValue(CapacityField, Capacity);
             info.AddValue(StringValueField, ToString());
@@ -274,29 +276,30 @@ namespace System.Text
         }
 
         [System.Diagnostics.Conditional("_DEBUG")]
-        private void VerifyClassInvariant()
+        private void AssertInvariants()
         {
-            Debug.Assert((uint)(m_ChunkOffset + m_ChunkChars.Length) >= m_ChunkOffset, "Integer Overflow");
+            Debug.Assert(m_ChunkOffset + m_ChunkChars.Length >= m_ChunkOffset, "The length of the string is greater than int.MaxValue.");
+
             StringBuilder currentBlock = this;
             int maxCapacity = this.m_MaxCapacity;
             for (;;)
             {
-                // All blocks have copy of the maxCapacity.
-                Debug.Assert(currentBlock.m_MaxCapacity == maxCapacity, "Bad maxCapacity");
-                Debug.Assert(currentBlock.m_ChunkChars != null, "Empty Buffer");
+                // All blocks have the same max capacity.
+                Debug.Assert(currentBlock.m_MaxCapacity == maxCapacity);
+                Debug.Assert(currentBlock.m_ChunkChars != null);
 
-                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");
+                Debug.Assert(currentBlock.m_ChunkLength <= currentBlock.m_ChunkChars.Length);
+                Debug.Assert(currentBlock.m_ChunkLength >= 0);
+                Debug.Assert(currentBlock.m_ChunkOffset >= 0);
 
                 StringBuilder prevBlock = currentBlock.m_ChunkPrevious;
                 if (prevBlock == null)
                 {
-                    Debug.Assert(currentBlock.m_ChunkOffset == 0, "First chunk's offset is not 0");
+                    Debug.Assert(currentBlock.m_ChunkOffset == 0);
                     break;
                 }
-                // There are no gaps in the blocks. 
-                Debug.Assert(currentBlock.m_ChunkOffset == prevBlock.m_ChunkOffset + prevBlock.m_ChunkLength, "There is a gap between chunks!");
+                // There are no gaps in the blocks.
+                Debug.Assert(currentBlock.m_ChunkOffset == prevBlock.m_ChunkOffset + prevBlock.m_ChunkLength);
                 currentBlock = prevBlock;
             }
         }
@@ -330,15 +333,19 @@ namespace System.Text
             }
         }
 
-        public int MaxCapacity
-        {
-            get { return m_MaxCapacity; }
-        }
+        /// <summary>
+        /// Gets the maximum capacity this builder is allowed to have.
+        /// </summary>
+        public int MaxCapacity => m_MaxCapacity;
 
-        // 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.
-        // 
+        /// <summary>
+        /// Ensures that the capacity of this builder is at least the specified value.
+        /// </summary>
+        /// <param name="capacity">The new capacity for this builder.</param>
+        /// <remarks>
+        /// If <paramref name="capacity"/> is less than or equal to the current capacity of
+        /// this builder, the capacity remains unchanged.
+        /// </remarks>
         public int EnsureCapacity(int capacity)
         {
             if (capacity < 0)
@@ -354,18 +361,18 @@ namespace System.Text
 
         public override String ToString()
         {
-            Contract.Ensures(Contract.Result<String>() != null);
-
-            VerifyClassInvariant();
+            AssertInvariants();
 
             if (Length == 0)
-                return String.Empty;
+            {
+                return string.Empty;
+            }
 
-            string ret = string.FastAllocateString(Length);
+            string result = string.FastAllocateString(Length);
             StringBuilder chunk = this;
             unsafe
             {
-                fixed (char* destinationPtr = ret)
+                fixed (char* destinationPtr = result)
                 {
                     do
                     {
@@ -377,7 +384,7 @@ namespace System.Text
                             int chunkLength = chunk.m_ChunkLength;
 
                             // Check that we will not overrun our boundaries. 
-                            if ((uint)(chunkLength + chunkOffset) <= (uint)ret.Length && (uint)chunkLength <= (uint)sourceArray.Length)
+                            if ((uint)(chunkLength + chunkOffset) <= (uint)result.Length && (uint)chunkLength <= (uint)sourceArray.Length)
                             {
                                 fixed (char* sourcePtr = &sourceArray[0])
                                     string.wstrcpy(destinationPtr + chunkOffset, sourcePtr, chunkLength);
@@ -388,16 +395,20 @@ namespace System.Text
                             }
                         }
                         chunk = chunk.m_ChunkPrevious;
-                    } while (chunk != null);
+                    }
+                    while (chunk != null);
 
-                    return ret;
+                    return result;
                 }
             }
         }
 
-
-        // Converts a substring of this string builder to a String.
-        public String ToString(int startIndex, int length)
+        /// <summary>
+        /// Creates a string from a substring of this builder.
+        /// </summary>
+        /// <param name="startIndex">The index to start in this builder.</param>
+        /// <param name="length">The number of characters to read in this builder.</param>
+        public string ToString(int startIndex, int length)
         {
             Contract.Ensures(Contract.Result<String>() != null);
 
@@ -414,29 +425,28 @@ namespace System.Text
             {
                 throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_NegativeLength);
             }
-            if (startIndex > (currentLength - length))
+            if (startIndex > currentLength - length)
             {
                 throw new ArgumentOutOfRangeException(nameof(length), SR.ArgumentOutOfRange_IndexLength);
             }
 
-            VerifyClassInvariant();
+            AssertInvariants();
 
             StringBuilder chunk = this;
             int sourceEndIndex = startIndex + length;
 
-            string ret = string.FastAllocateString(length);
+            string result = string.FastAllocateString(length);
             int curDestIndex = length;
             unsafe
             {
-                fixed (char* destinationPtr = ret)
+                fixed (char* destinationPtr = result)
                 {
                     while (curDestIndex > 0)
                     {
                         int chunkEndIndex = sourceEndIndex - chunk.m_ChunkOffset;
                         if (chunkEndIndex >= 0)
                         {
-                            if (chunkEndIndex > chunk.m_ChunkLength)
-                                chunkEndIndex = chunk.m_ChunkLength;
+                            chunkEndIndex = Math.Min(chunkEndIndex, chunk.m_ChunkLength);
 
                             int countLeft = curDestIndex;
                             int chunkCount = countLeft;
@@ -450,7 +460,7 @@ namespace System.Text
 
                             if (chunkCount > 0)
                             {
-                                // work off of local variables so that they are stable even in the presence of race conditions
+                                // Work off of local variables so that they are stable even in the presence of race conditions
                                 char[] sourceArray = chunk.m_ChunkChars;
 
                                 // Check that we will not overrun our boundaries. 
@@ -468,22 +478,20 @@ namespace System.Text
                         chunk = chunk.m_ChunkPrevious;
                     }
 
-                    return ret;
+                    return result;
                 }
             }
         }
 
-        // Convenience method for sb.Length=0;
         public StringBuilder Clear()
         {
             this.Length = 0;
             return this;
         }
 
-        // 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.
-
+        /// <summary>
+        /// Gets or sets the length of this builder.
+        /// </summary>
         public int Length
         {
             get
@@ -511,29 +519,27 @@ namespace System.Text
                 {
                     m_ChunkLength = 0;
                     m_ChunkOffset = 0;
-                    Debug.Assert(Capacity >= originalCapacity, "setting the Length should never decrease the Capacity");
+                    Debug.Assert(Capacity >= originalCapacity);
                     return;
                 }
 
                 int delta = value - Length;
-                // if the specified length is greater than the current length
                 if (delta > 0)
                 {
-                    // the end of the string value of the current StringBuilder object is padded with the Unicode NULL character
-                    Append('\0', delta);        // We could improve on this, but who does this anyway?
+                    // Pad ourselves with null characters.
+                    Append('\0', delta);
                 }
-                // if the specified length is less than or equal to the current length
                 else
                 {
                     StringBuilder chunk = FindChunkForIndex(value);
                     if (chunk != this)
                     {
-                        // we crossed a chunk boundary when reducing the Length, we must replace this middle-chunk with a new
-                        // larger chunk to ensure the original capacity is preserved
+                        // We crossed a chunk boundary when reducing the Length. We must replace this middle-chunk with a new larger chunk,
+                        // to ensure the original capacity is preserved.
                         int newLen = originalCapacity - chunk.m_ChunkOffset;
                         char[] newArray = new char[newLen];
 
-                        Debug.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, 0, newArray, 0, chunk.m_ChunkLength);
 
                         m_ChunkChars = newArray;
@@ -541,13 +547,13 @@ namespace System.Text
                         m_ChunkOffset = chunk.m_ChunkOffset;
                     }
                     m_ChunkLength = value - chunk.m_ChunkOffset;
-                    VerifyClassInvariant();
+                    AssertInvariants();
                 }
-                Debug.Assert(Capacity >= originalCapacity, "setting the Length should never decrease the Capacity");
+                Debug.Assert(Capacity >= originalCapacity);
             }
         }
 
-        [System.Runtime.CompilerServices.IndexerName("Chars")]
+        [IndexerName("Chars")]
         public char this[int index]
         {
             get
@@ -559,12 +565,16 @@ namespace System.Text
                     if (indexInBlock >= 0)
                     {
                         if (indexInBlock >= chunk.m_ChunkLength)
+                        {
                             throw new IndexOutOfRangeException();
+                        }
                         return chunk.m_ChunkChars[indexInBlock];
                     }
                     chunk = chunk.m_ChunkPrevious;
                     if (chunk == null)
+                    {
                         throw new IndexOutOfRangeException();
+                    }
                 }
             }
             set
@@ -576,18 +586,26 @@ namespace System.Text
                     if (indexInBlock >= 0)
                     {
                         if (indexInBlock >= chunk.m_ChunkLength)
+                        {
                             throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
+                        }
                         chunk.m_ChunkChars[indexInBlock] = value;
                         return;
                     }
                     chunk = chunk.m_ChunkPrevious;
                     if (chunk == null)
+                    {
                         throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
+                    }
                 }
             }
         }
 
-        // Appends a character at the end of this string builder. The capacity is adjusted as needed.
+        /// <summary>
+        /// Appends a character 0 or more times to the end of this builder.
+        /// </summary>
+        /// <param name="value">The character to append.</param>
+        /// <param name="repeatCount">The number of times to append <paramref name="value"/>.</param>
         public StringBuilder Append(char value, int repeatCount)
         {
             if (repeatCount < 0)
@@ -610,28 +628,34 @@ namespace System.Text
                 throw new ArgumentOutOfRangeException(nameof(repeatCount), SR.ArgumentOutOfRange_LengthGreaterThanCapacity);
             }
 
-            int idx = m_ChunkLength;
+            int index = m_ChunkLength;
             while (repeatCount > 0)
             {
-                if (idx < m_ChunkChars.Length)
+                if (index < m_ChunkChars.Length)
                 {
-                    m_ChunkChars[idx++] = value;
+                    m_ChunkChars[index++] = value;
                     --repeatCount;
                 }
                 else
                 {
-                    m_ChunkLength = idx;
+                    m_ChunkLength = index;
                     ExpandByABlock(repeatCount);
-                    Debug.Assert(m_ChunkLength == 0, "Expand should create a new block");
-                    idx = 0;
+                    Debug.Assert(m_ChunkLength == 0);
+                    index = 0;
                 }
             }
-            m_ChunkLength = idx;
-            VerifyClassInvariant();
+
+            m_ChunkLength = index;
+            AssertInvariants();
             return this;
         }
 
-        // Appends an array of characters at the end of this string builder. The capacity is adjusted as needed. 
+        /// <summary>
+        /// Appends a range of characters to the end of this builder.
+        /// </summary>
+        /// <param name="value">The characters to append.</param>
+        /// <param name="startIndex">The index to start in <paramref name="value"/>.</param>
+        /// <param name="charCount">The number of characters to read in <paramref name="value"/>.</param>
         public StringBuilder Append(char[] value, int startIndex, int charCount)
         {
             if (startIndex < 0)
@@ -651,6 +675,7 @@ namespace System.Text
                 {
                     return this;
                 }
+
                 throw new ArgumentNullException(nameof(value));
             }
             if (charCount > value.Length - startIndex)
@@ -662,32 +687,35 @@ namespace System.Text
             {
                 return this;
             }
+
             unsafe
             {
                 fixed (char* valueChars = &value[startIndex])
                 {
                     Append(valueChars, charCount);
-
                     return this;
                 }
             }
         }
 
 
-        // Appends a copy of this string at the end of this string builder.
+        /// <summary>
+        /// Appends a string to the end of this builder.
+        /// </summary>
+        /// <param name="value">The string to append.</param>
         public StringBuilder Append(String value)
         {
             Contract.Ensures(Contract.Result<StringBuilder>() != null);
 
             if (value != null)
             {
-                // This is a hand specialization of the 'AppendHelper' code below. 
-                // We could have just called AppendHelper.  
+                // We could have just called AppendHelper here; this is a hand-specialization of that code.
                 char[] chunkChars = m_ChunkChars;
                 int chunkLength = m_ChunkLength;
                 int valueLen = value.Length;
                 int newCurrentIndex = chunkLength + valueLen;
-                if (newCurrentIndex < chunkChars.Length)    // Use strictly < to avoid issue if count == 0, newIndex == length
+
+                if (newCurrentIndex < chunkChars.Length) // Use strictly < to avoid issues if count == 0, newIndex == length
                 {
                     if (valueLen <= 2)
                     {
@@ -702,46 +730,54 @@ namespace System.Text
                         {
                             fixed (char* valuePtr = value)
                             fixed (char* destPtr = &chunkChars[chunkLength])
+                            {
                                 string.wstrcpy(destPtr, valuePtr, valueLen);
+                            }
                         }
                     }
+
                     m_ChunkLength = newCurrentIndex;
                 }
                 else
+                {
                     AppendHelper(value);
+                }
             }
+
             return this;
         }
 
-
-        // We put this fixed in its own helper to avoid the cost zero initing valueChars in the
+        // We put this fixed in its own helper to avoid the cost of zero-initing `valueChars` in the
         // case we don't actually use it.  
         private void AppendHelper(string value)
         {
             unsafe
             {
                 fixed (char* valueChars = value)
+                {
                     Append(valueChars, value.Length);
+                }
             }
         }
 
-        // Appends a copy of the characters in value from startIndex to startIndex +
-        // count at the end of this string builder.
-        public StringBuilder Append(String value, int startIndex, int count)
+        /// <summary>
+        /// Appends part of a string to the end of this builder.
+        /// </summary>
+        /// <param name="value">The string to append.</param>
+        /// <param name="startIndex">The index to start in <paramref name="value"/>.</param>
+        /// <param name="count">The number of characters to read in <paramref name="value"/>.</param>
+        public StringBuilder Append(string value, int startIndex, int count)
         {
             if (startIndex < 0)
             {
                 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_Index);
             }
-
             if (count < 0)
             {
                 throw new ArgumentOutOfRangeException(nameof(count), SR.ArgumentOutOfRange_GenericPositive);
             }
             Contract.Ensures(Contract.Result<StringBuilder>() != null);
 
-            //If the value being added is null, eat the null
-            //and return.
             if (value == null)
             {
                 if (startIndex == 0 && count == 0)
@@ -766,21 +802,15 @@ namespace System.Text
                 fixed (char* valueChars = value)
                 {
                     Append(valueChars + startIndex, count);
-
                     return this;
                 }
             }
         }
 
-        public StringBuilder AppendLine()
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(Environment.NewLine);
-        }
+        public StringBuilder AppendLine() => Append(Environment.NewLine);
 
         public StringBuilder AppendLine(string value)
         {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
             Append(value);
             return Append(Environment.NewLine);
         }
@@ -799,8 +829,7 @@ namespace System.Text
 
             if (destinationIndex < 0)
             {
-                throw new ArgumentOutOfRangeException(nameof(destinationIndex),
-                    SR.Format(SR.ArgumentOutOfRange_MustBeNonNegNum, nameof(destinationIndex)));
+                throw new ArgumentOutOfRangeException(nameof(destinationIndex), SR.Format(SR.ArgumentOutOfRange_MustBeNonNegNum, nameof(destinationIndex)));
             }
 
             if (destinationIndex > destination.Length - count)
@@ -819,7 +848,7 @@ namespace System.Text
             }
             Contract.EndContractBlock();
 
-            VerifyClassInvariant();
+            AssertInvariants();
 
             StringBuilder chunk = this;
             int sourceEndIndex = sourceIndex + count;
@@ -829,8 +858,7 @@ namespace System.Text
                 int chunkEndIndex = sourceEndIndex - chunk.m_ChunkOffset;
                 if (chunkEndIndex >= 0)
                 {
-                    if (chunkEndIndex > chunk.m_ChunkLength)
-                        chunkEndIndex = chunk.m_ChunkLength;
+                    chunkEndIndex = Math.Min(chunkEndIndex, chunk.m_ChunkLength);
 
                     int chunkCount = count;
                     int chunkStartIndex = chunkEndIndex - count;
@@ -842,19 +870,20 @@ namespace System.Text
                     curDestIndex -= chunkCount;
                     count -= chunkCount;
 
-                    // SafeCritical: we ensure that chunkStartIndex + chunkCount are within range of m_chunkChars
-                    // as well as ensuring that curDestIndex + chunkCount are within range of destination
+                    // We ensure that chunkStartIndex + chunkCount are within range of m_chunkChars as well as
+                    // ensuring that curDestIndex + chunkCount are within range of destination
                     ThreadSafeCopy(chunk.m_ChunkChars, chunkStartIndex, destination, curDestIndex, chunkCount);
                 }
                 chunk = chunk.m_ChunkPrevious;
             }
         }
 
-        // 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. 
-        // 
+        /// <summary>
+        /// Inserts a string 0 or more times into this builder at the specified position.
+        /// </summary>
+        /// <param name="index">The index to insert in this builder.</param>
+        /// <param name="value">The string to insert.</param>
+        /// <param name="count">The number of times to insert the string.</param>
         public StringBuilder Insert(int index, String value, int count)
         {
             if (count < 0)
@@ -864,27 +893,25 @@ namespace System.Text
             Contract.Ensures(Contract.Result<StringBuilder>() != null);
             Contract.EndContractBlock();
 
-            //Range check the index.
             int currentLength = Length;
             if ((uint)index > (uint)currentLength)
             {
                 throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
             }
 
-            //If value is null, empty or count is 0, do nothing. This is ECMA standard.
-            if (value == null || value.Length == 0 || count == 0)
+            if (string.IsNullOrEmpty(value) || count == 0)
             {
                 return this;
             }
 
-            //Ensure we don't insert more chars than we can hold, and we don't 
-            //have any integer overflow in our inserted characters.
+            // Ensure we don't insert more chars than we can hold, and we don't 
+            // have any integer overflow in our new length.
             long insertingChars = (long)value.Length * count;
             if (insertingChars > MaxCapacity - this.Length)
             {
                 throw new OutOfMemoryException();
             }
-            Debug.Assert(insertingChars + this.Length < Int32.MaxValue);
+            Debug.Assert(insertingChars + this.Length < int.MaxValue);
 
             StringBuilder chunk;
             int indexInChunk;
@@ -904,10 +931,12 @@ namespace System.Text
             }
         }
 
-        // Removes the specified characters from this string builder.
-        // The length of this string builder is reduced by 
-        // length, but the capacity is unaffected.
-        // 
+        /// <summary>
+        /// Removes a range of characters from this builder.
+        /// </summary>
+        /// <remarks>
+        /// This method does not reduce the capacity of this builder.
+        /// </remarks>
         public StringBuilder Remove(int startIndex, int length)
         {
             if (length < 0)
@@ -929,7 +958,6 @@ namespace System.Text
 
             if (Length == length && startIndex == 0)
             {
-                // Optimization.  If we are deleting everything  
                 Length = 0;
                 return this;
             }
@@ -940,150 +968,71 @@ namespace System.Text
                 int indexInChunk;
                 Remove(startIndex, length, out chunk, out indexInChunk);
             }
+
             return this;
         }
 
-        // Appends a boolean to the end of this string builder.
-        // The capacity is adjusted as needed. 
-        public StringBuilder Append(bool value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(value.ToString());
-        }
+        public StringBuilder Append(bool value) => Append(value.ToString());
 
-        // Appends an sbyte to this string builder.
-        // The capacity is adjusted as needed. 
         [CLSCompliant(false)]
-        public StringBuilder Append(sbyte value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(value.ToString());
-        }
+        public StringBuilder Append(sbyte value) => Append(value.ToString());
 
-        // Appends a ubyte to this string builder.
-        // The capacity is adjusted as needed. 
-        public StringBuilder Append(byte value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(value.ToString());
-        }
+        public StringBuilder Append(byte value) => Append(value.ToString());
 
-        // Appends a character at the end of this string builder. The capacity is adjusted as needed.
         public StringBuilder Append(char value)
         {
             Contract.Ensures(Contract.Result<StringBuilder>() != null);
 
             if (m_ChunkLength < m_ChunkChars.Length)
+            {
                 m_ChunkChars[m_ChunkLength++] = value;
+            }
             else
+            {
                 Append(value, 1);
+            }
+
             return this;
         }
 
-        // Appends a short to this string builder.
-        // The capacity is adjusted as needed. 
-        public StringBuilder Append(short value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(value.ToString());
-        }
+        public StringBuilder Append(short value) => Append(value.ToString());
 
-        // Appends an int to this string builder.
-        // The capacity is adjusted as needed. 
-        public StringBuilder Append(int value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(value.ToString());
-        }
+        public StringBuilder Append(int value) => Append(value.ToString());
 
-        // Appends a long to this string builder. 
-        // The capacity is adjusted as needed. 
-        public StringBuilder Append(long value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(value.ToString());
-        }
+        public StringBuilder Append(long value) => Append(value.ToString());
 
-        // Appends a float to this string builder. 
-        // The capacity is adjusted as needed. 
-        public StringBuilder Append(float value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(value.ToString());
-        }
+        public StringBuilder Append(float value) => Append(value.ToString());
 
-        // Appends a double to this string builder. 
-        // The capacity is adjusted as needed. 
-        public StringBuilder Append(double value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(value.ToString());
-        }
+        public StringBuilder Append(double value) => Append(value.ToString());
 
-        public StringBuilder Append(decimal value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(value.ToString());
-        }
+        public StringBuilder Append(decimal value) => Append(value.ToString());
 
-        // Appends an ushort to this string builder. 
-        // The capacity is adjusted as needed. 
         [CLSCompliant(false)]
-        public StringBuilder Append(ushort value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(value.ToString());
-        }
+        public StringBuilder Append(ushort value) => Append(value.ToString());
 
-        // Appends an uint to this string builder. 
-        // The capacity is adjusted as needed. 
         [CLSCompliant(false)]
-        public StringBuilder Append(uint value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(value.ToString());
-        }
+        public StringBuilder Append(uint value) => Append(value.ToString());
 
-        // Appends an unsigned long to this string builder. 
-        // The capacity is adjusted as needed. 
         [CLSCompliant(false)]
-        public StringBuilder Append(ulong value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Append(value.ToString());
-        }
-
-        // Appends an Object to this string builder. 
-        // The capacity is adjusted as needed. 
-        public StringBuilder Append(Object value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
+        public StringBuilder Append(ulong value) => Append(value.ToString());
 
-            if (null == value)
-            {
-                //Appending null is now a no-op.
-                return this;
-            }
-            return Append(value.ToString());
-        }
+        public StringBuilder Append(object value) => (value == null) ? this : Append(value.ToString());
 
-        // Appends all of the characters in value to the current instance.
         public StringBuilder Append(char[] value)
         {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-
-            if (null != value && value.Length > 0)
+            if (value?.Length > 0)
             {
                 unsafe
                 {
                     fixed (char* valueChars = &value[0])
+                    {
                         Append(valueChars, value.Length);
+                    }
                 }
             }
             return this;
         }
 
-        
         #region AppendJoin
 
         public unsafe StringBuilder AppendJoin(string separator, params object[] values)
@@ -1127,28 +1076,38 @@ namespace System.Text
         {
             return AppendJoinCore(&separator, 1, values);
         }
-
         
         private unsafe StringBuilder AppendJoinCore<T>(char* separator, int separatorLength, IEnumerable<T> values)
         {
+            Debug.Assert(separator != null);
+            Debug.Assert(separatorLength >= 0);
+
             if (values == null)
+            {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values);
+            }
 
-            using (var en = values.GetEnumerator())
+            using (IEnumerator<T> 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;
@@ -1157,35 +1116,33 @@ namespace System.Text
         private unsafe StringBuilder AppendJoinCore<T>(char* separator, int separatorLength, T[] values)
         {
             if (values == null)
+            {
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.values);
+            }
 
             if (values.Length == 0)
+            {
                 return this;
+            }
 
             if (values[0] != null)
+            {
                 Append(values[0].ToString());
+            }
 
-            for (var i = 1; i < values.Length; i++)
+            for (int i = 1; i < values.Length; i++)
             {
                 Append(separator, separatorLength);
                 if (values[i] != null)
+                {
                     Append(values[i].ToString());
+                }
             }
             return this;
         }
 
         #endregion
 
-
-        /*====================================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.
-        // 
         public StringBuilder Insert(int index, String value)
         {
             if ((uint)index > (uint)Length)
@@ -1206,55 +1163,15 @@ namespace System.Text
             return this;
         }
 
-        // 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.
-        // 
-        public StringBuilder Insert(int index, bool value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, bool value) => 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.
-        // 
         [CLSCompliant(false)]
-        public StringBuilder Insert(int index, sbyte value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, sbyte value) => 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.
-        // 
-        public StringBuilder Insert(int index, byte value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, byte value) => 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.
-        // 
-        public StringBuilder Insert(int index, short value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, short value) => 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.
         public StringBuilder Insert(int index, char value)
         {
             Contract.Ensures(Contract.Result<StringBuilder>() != null);
@@ -1266,11 +1183,6 @@ namespace System.Text
             return this;
         }
 
-        // 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.
-        // 
         public StringBuilder Insert(int index, char[] value)
         {
             if ((uint)index > (uint)Length)
@@ -1285,10 +1197,6 @@ namespace System.Text
             return this;
         }
 
-        // Returns a reference to the StringBuilder with charCount characters from 
-        // value inserted into the buffer at index.  Existing characters are shifted
-        // to make room for the new text and capacity is adjusted as required.  If value is null, the StringBuilder
-        // is unchanged.  Characters are taken from value starting at position startIndex.
         public StringBuilder Insert(int index, char[] value, int startIndex, int charCount)
         {
             Contract.Ensures(Contract.Result<StringBuilder>() != null);
@@ -1299,7 +1207,6 @@ namespace System.Text
                 throw new ArgumentOutOfRangeException(nameof(index), SR.ArgumentOutOfRange_Index);
             }
 
-            //If they passed in a null char array, just jump out quickly.
             if (value == null)
             {
                 if (startIndex == 0 && charCount == 0)
@@ -1309,7 +1216,6 @@ namespace System.Text
                 throw new ArgumentNullException(nameof(value), SR.ArgumentNull_String);
             }
 
-            //Range check the array.
             if (startIndex < 0)
             {
                 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.ArgumentOutOfRange_StartIndex);
@@ -1336,121 +1242,32 @@ namespace System.Text
             return this;
         }
 
-        // 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.
-        // 
-        public StringBuilder Insert(int index, int value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, int value) => 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.
-        // 
-        public StringBuilder Insert(int index, long value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, long value) => 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.
-        // 
-        public StringBuilder Insert(int index, float value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, float value) => 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. 
-        // 
-        public StringBuilder Insert(int index, double value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, double value) => Insert(index, value.ToString(), 1);
 
-        public StringBuilder Insert(int index, decimal value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, decimal value) => Insert(index, value.ToString(), 1);
 
-        // Returns a reference to the StringBuilder with value inserted into 
-        // the buffer at index. Existing characters are shifted to make room for the new text.
-        // The capacity is adjusted as needed. 
-        // 
         [CLSCompliant(false)]
-        public StringBuilder Insert(int index, ushort value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, ushort value) => Insert(index, value.ToString(), 1);
 
-        // Returns a reference to the StringBuilder with value inserted into 
-        // the buffer at index. Existing characters are shifted to make room for the new text.
-        // The capacity is adjusted as needed. 
-        // 
         [CLSCompliant(false)]
-        public StringBuilder Insert(int index, uint value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, uint value) => Insert(index, value.ToString(), 1);
 
-        // Returns a reference to the StringBuilder with value inserted into 
-        // the buffer at index. Existing characters are shifted to make room for the new text.
-        // The capacity is adjusted as needed. 
-        // 
         [CLSCompliant(false)]
-        public StringBuilder Insert(int index, ulong value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, ulong value) => Insert(index, value.ToString(), 1);
 
-        // Returns a reference to this string builder with value inserted into 
-        // the buffer at index. Existing characters are shifted to make room for the
-        // new text.  The capacity is adjusted as needed. If value equals String.Empty, the
-        // StringBuilder is not changed. No changes are made if value is null.
-        // 
-        public StringBuilder Insert(int index, Object value)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            if (null == value)
-            {
-                return this;
-            }
-            return Insert(index, value.ToString(), 1);
-        }
+        public StringBuilder Insert(int index, Object value) => (value == null) ? this : Insert(index, value.ToString(), 1);
 
-        public StringBuilder AppendFormat(String format, Object arg0)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return AppendFormatHelper(null, format, new ParamsArray(arg0));
-        }
+        public StringBuilder AppendFormat(String format, Object arg0) => AppendFormatHelper(null, format, new ParamsArray(arg0));
 
-        public StringBuilder AppendFormat(String format, Object arg0, Object arg1)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return AppendFormatHelper(null, format, new ParamsArray(arg0, arg1));
-        }
+        public StringBuilder AppendFormat(String format, Object arg0, Object arg1) => AppendFormatHelper(null, format, new ParamsArray(arg0, arg1));
 
-        public StringBuilder AppendFormat(String format, Object arg0, Object arg1, Object arg2)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return AppendFormatHelper(null, format, new ParamsArray(arg0, arg1, arg2));
-        }
+        public StringBuilder AppendFormat(String format, Object arg0, Object arg1, Object arg2) => AppendFormatHelper(null, format, new ParamsArray(arg0, arg1, arg2));
 
         public StringBuilder AppendFormat(String format, params Object[] args)
         {
@@ -1458,7 +1275,8 @@ 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) ? nameof(format) : nameof(args));
+                string paramName = (format == null) ? nameof(format) : nameof(args);
+                throw new ArgumentNullException(paramName);
             }
             Contract.Ensures(Contract.Result<String>() != null);
             Contract.EndContractBlock();
@@ -1466,23 +1284,11 @@ namespace System.Text
             return AppendFormatHelper(null, format, new ParamsArray(args));
         }
 
-        public StringBuilder AppendFormat(IFormatProvider provider, String format, Object arg0)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return AppendFormatHelper(provider, format, new ParamsArray(arg0));
-        }
+        public StringBuilder AppendFormat(IFormatProvider provider, String format, Object arg0) => AppendFormatHelper(provider, format, new ParamsArray(arg0));
 
-        public StringBuilder AppendFormat(IFormatProvider provider, String format, Object arg0, Object arg1)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return AppendFormatHelper(provider, format, new ParamsArray(arg0, arg1));
-        }
+        public StringBuilder AppendFormat(IFormatProvider provider, String format, Object arg0, Object arg1) => AppendFormatHelper(provider, format, new ParamsArray(arg0, arg1));
 
-        public StringBuilder AppendFormat(IFormatProvider provider, String format, Object arg0, Object arg1, Object arg2)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return AppendFormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
-        }
+        public StringBuilder AppendFormat(IFormatProvider provider, String format, Object arg0, Object arg1, Object arg2) => AppendFormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
 
         public StringBuilder AppendFormat(IFormatProvider provider, String format, params Object[] args)
         {
@@ -1490,7 +1296,8 @@ 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) ? nameof(format) : nameof(args));
+                string paramName = (format == null) ? nameof(format) : nameof(args);
+                throw new ArgumentNullException(paramName);
             }
             Contract.Ensures(Contract.Result<String>() != null);
             Contract.EndContractBlock();
@@ -1503,9 +1310,9 @@ namespace System.Text
             throw new FormatException(SR.Format_InvalidString);
         }
 
-        // undocumented exclusive limits on the range for Argument Hole Index and Argument Hole Alignment.
-        private const int Index_Limit = 1000000; // Note:            0 <= ArgIndex < Index_Limit
-        private const int Width_Limit = 1000000; // Note: -Width_Limit <  ArgAlign < Width_Limit
+        // Undocumented exclusive limits on the range for Argument Hole Index and Argument Hole Alignment.
+        private const int IndexLimit = 1000000; // Note:            0 <= ArgIndex < IndexLimit
+        private const int WidthLimit = 1000000; // Note:  -WidthLimit <  ArgAlign < WidthLimit
 
         internal StringBuilder AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args)
         {
@@ -1584,7 +1391,8 @@ namespace System.Text
                     if (pos == len) FormatError();
                     ch = format[pos];
                     // so long as character is digit and value of the index is less than 1000000 ( index limit )
-                } while (ch >= '0' && ch <= '9' && index < Index_Limit);
+                }
+                while (ch >= '0' && ch <= '9' && index < IndexLimit);
 
                 // If value of index is not within the range of the arguments passed in then error (Index out of range)
                 if (index >= args.Length) throw new FormatException(SR.Format_IndexOutOfRange);
@@ -1633,7 +1441,8 @@ namespace System.Text
                         if (pos == len) FormatError();
                         ch = format[pos];
                         // So long a current character is a digit and the value of width is less than 100000 ( width limit )
-                    } while (ch >= '0' && ch <= '9' && width < Width_Limit);
+                    }
+                    while (ch >= '0' && ch <= '9' && width < WidthLimit);
                     // end of parsing Argument Alignment
                 }
 
@@ -1743,18 +1552,21 @@ namespace System.Text
             return this;
         }
 
-        // Returns a reference to the current StringBuilder with all instances of oldString 
-        // replaced with newString.  If startIndex and count are specified,
-        // we only replace strings completely contained in the range of startIndex to startIndex + 
-        // count.  The strings to be replaced are checked on an ordinal basis (e.g. not culture aware).  If 
-        // newValue is null, instances of oldValue are removed (e.g. replaced with nothing.).
-        //
-        public StringBuilder Replace(String oldValue, String newValue)
-        {
-            Contract.Ensures(Contract.Result<StringBuilder>() != null);
-            return Replace(oldValue, newValue, 0, Length);
-        }
+        /// <summary>
+        /// Replaces all instances of one string with another in this builder.
+        /// </summary>
+        /// <param name="oldValue">The string to replace.</param>
+        /// <param name="newValue">The string to replace <paramref name="oldValue"/> with.</param>
+        /// <remarks>
+        /// If <paramref name="newValue"/> is <c>null</c>, instances of <paramref name="oldValue"/>
+        /// are removed from this builder.
+        /// </remarks>
+        public StringBuilder Replace(String oldValue, String newValue) => Replace(oldValue, newValue, 0, Length);
 
+        /// <summary>
+        /// Determines if the contents of this builder are equal to the contents of another builder.
+        /// </summary>
+        /// <param name="sb">The other builder.</param>
         public bool Equals(StringBuilder sb)
         {
             if (sb == null)
@@ -1770,7 +1582,6 @@ namespace System.Text
             int sbChunkIndex = sbChunk.m_ChunkLength;
             for (;;)
             {
-                // Decrement the pointer to the 'this' StringBuilder
                 --thisChunkIndex;
                 --sbChunkIndex;
 
@@ -1782,7 +1593,6 @@ namespace System.Text
                     thisChunkIndex = thisChunk.m_ChunkLength + thisChunkIndex;
                 }
 
-                // Decrement the pointer to the 'this' StringBuilder
                 while (sbChunkIndex < 0)
                 {
                     sbChunk = sbChunk.m_ChunkPrevious;
@@ -1800,6 +1610,17 @@ namespace System.Text
             }
         }
 
+        /// <summary>
+        /// Replaces all instances of one string with another in part of this builder.
+        /// </summary>
+        /// <param name="oldValue">The string to replace.</param>
+        /// <param name="newValue">The string to replace <paramref name="oldValue"/> with.</param>
+        /// <param name="startIndex">The index to start in this builder.</param>
+        /// <param name="count">The number of characters to read in this builder.</param>
+        /// <remarks>
+        /// If <paramref name="newValue"/> is <c>null</c>, instances of <paramref name="oldValue"/>
+        /// are removed from this builder.
+        /// </remarks>
         public StringBuilder Replace(String oldValue, String newValue, int startIndex, int count)
         {
             Contract.Ensures(Contract.Result<StringBuilder>() != null);
@@ -1822,12 +1643,11 @@ namespace System.Text
                 throw new ArgumentException(SR.Argument_EmptyName, nameof(oldValue));
             }
 
-            if (newValue == null)
-                newValue = "";
+            newValue = newValue ?? string.Empty;
 
             int deltaLength = newValue.Length - oldValue.Length;
 
-            int[] replacements = null;          // A list of replacement positions in a chunk to apply
+            int[] replacements = null; // A list of replacement positions in a chunk to apply
             int replacementsCount = 0;
 
             // Find the chunk, indexInChunk for the starting point
@@ -1838,14 +1658,16 @@ namespace System.Text
                 // Look for a match in the chunk,indexInChunk pointer 
                 if (StartsWith(chunk, indexInChunk, count, oldValue))
                 {
-                    // Push it on my replacements array (with growth), we will do all replacements in a
+                    // Push it on the replacements array (with growth), we will do all replacements in a
                     // given chunk in one operation below (see ReplaceAllInChunk) so we don't have to slide
-                    // many times.  
+                    // many times.
                     if (replacements == null)
+                    {
                         replacements = new int[5];
+                    }
                     else if (replacementsCount >= replacements.Length)
                     {
-                        Array.Resize(ref replacements, replacements.Length * 3 / 2 + 4); // grow by 1.5X but more in the beginning
+                        Array.Resize(ref replacements, replacements.Length * 3 / 2 + 4); // Grow by ~1.5x, but more in the begining
                     }
                     replacements[replacementsCount++] = indexInChunk;
                     indexInChunk += oldValue.Length;
@@ -1857,13 +1679,13 @@ namespace System.Text
                     --count;
                 }
 
-                if (indexInChunk >= chunk.m_ChunkLength || count == 0)       // Have we moved out of the current chunk
+                if (indexInChunk >= chunk.m_ChunkLength || count == 0) // Have we moved out of the current chunk?
                 {
-                    // Replacing mutates the blocks, so we need to convert to logical index and back afterward
+                    // Replacing mutates the blocks, so we need to convert to a logical index and back afterwards
                     int index = indexInChunk + chunk.m_ChunkOffset;
                     int indexBeforeAdjustment = index;
 
-                    // See if we accumulated any replacements, if so apply them 
+                    // See if we accumulated any replacements, if so apply them.
                     ReplaceAllInChunk(replacements, replacementsCount, chunk, oldValue.Length, newValue);
                     // The replacement has affected the logical index.  Adjust it.  
                     index += ((newValue.Length - oldValue.Length) * replacementsCount);
@@ -1871,22 +1693,31 @@ namespace System.Text
 
                     chunk = FindChunkForIndex(index);
                     indexInChunk = index - chunk.m_ChunkOffset;
-                    Debug.Assert(chunk != null || count == 0, "Chunks ended prematurely");
+                    Debug.Assert(chunk != null || count == 0, "Chunks ended prematurely!");
                 }
             }
-            VerifyClassInvariant();
+
+            AssertInvariants();
             return this;
         }
 
-        // 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
-        //
+        /// <summary>
+        /// Replaces all instances of one character with another in this builder.
+        /// </summary>
+        /// <param name="oldChar">The character to replace.</param>
+        /// <param name="newChar">The character to replace <paramref name="oldChar"/> with.</param>
         public StringBuilder Replace(char oldChar, char newChar)
         {
             return Replace(oldChar, newChar, 0, Length);
         }
+
+        /// <summary>
+        /// Replaces all instances of one character with another in this builder.
+        /// </summary>
+        /// <param name="oldChar">The character to replace.</param>
+        /// <param name="newChar">The character to replace <paramref name="oldChar"/> with.</param>
+        /// <param name="startIndex">The index to start in this builder.</param>
+        /// <param name="count">The number of characters to read in this builder.</param>
         public StringBuilder Replace(char oldChar, char newChar, int startIndex, int count)
         {
             Contract.Ensures(Contract.Result<StringBuilder>() != null);
@@ -1904,6 +1735,7 @@ namespace System.Text
 
             int endIndex = startIndex + count;
             StringBuilder chunk = this;
+
             for (;;)
             {
                 int endIndexInChunk = endIndex - chunk.m_ChunkOffset;
@@ -1923,12 +1755,16 @@ namespace System.Text
                     break;
                 chunk = chunk.m_ChunkPrevious;
             }
+
+            AssertInvariants();
             return this;
         }
 
         /// <summary>
-        /// Appends 'value' of length 'count' to the stringBuilder. 
+        /// Appends a character buffer to this builder.
         /// </summary>
+        /// <param name="value">The pointer to the start of the buffer.</param>
+        /// <param name="valueCount">The number of characters in the buffer.</param>
         [CLSCompliant(false)]
         public unsafe StringBuilder Append(char* value, int valueCount)
         {
@@ -1966,20 +1802,23 @@ namespace System.Text
                 // Expand the builder to add another chunk. 
                 int restLength = valueCount - firstLength;
                 ExpandByABlock(restLength);
-                Debug.Assert(m_ChunkLength == 0, "Expand did not make a new block");
+                Debug.Assert(m_ChunkLength == 0, "A new block was not created.");
 
                 // Copy the second chunk
                 ThreadSafeCopy(value + firstLength, m_ChunkChars, 0, restLength);
                 m_ChunkLength = restLength;
             }
-            VerifyClassInvariant();
+            AssertInvariants();
             return this;
         }
 
         /// <summary>
-        /// Inserts 'value' of length 'cou
+        /// Inserts a character buffer into this builder at the specified position.
         /// </summary>
-        unsafe private void Insert(int index, char* value, int valueCount)
+        /// <param name="index">The index to insert in this builder.</param>
+        /// <param name="value">The pointer to the start of the buffer.</param>
+        /// <param name="valueCount">The number of characters in the buffer.</param>
+        private unsafe void Insert(int index, char* value, int valueCount)
         {
             if ((uint)index > (uint)Length)
             {
@@ -1996,15 +1835,22 @@ namespace System.Text
         }
 
         /// <summary>
-        /// 'replacements' is a list of index (relative to the begining of the 'chunk' to remove
-        /// 'removeCount' characters and replace them with 'value'.   This routine does all those 
-        /// replacements in bulk (and therefore very efficiently. 
-        /// with the string 'value'.  
+        /// Replaces strings at specified indices with a new string in a chunk.
         /// </summary>
+        /// <param name="replacements">The list of indices, relative to the beginning of the chunk, to remove at.</param>
+        /// <param name="replacementsCount">The number of replacements to make.</param>
+        /// <param name="sourceChunk">The source chunk.</param>
+        /// <param name="removeCount">The number of characters to remove at each replacement.</param>
+        /// <param name="value">The string to insert at each replacement.</param>
+        /// <remarks>
+        /// This routine is very efficient because it does replacements in bulk.
+        /// </remarks>
         private void ReplaceAllInChunk(int[] replacements, int replacementsCount, StringBuilder sourceChunk, int removeCount, string value)
         {
             if (replacementsCount <= 0)
+            {
                 return;
+            }
 
             unsafe
             {
@@ -2028,7 +1874,9 @@ namespace System.Text
                         int gapStart = replacements[i] + removeCount;
                         i++;
                         if (i >= replacementsCount)
+                        {
                             break;
+                        }
 
                         int gapEnd = replacements[i];
                         Debug.Assert(gapStart < sourceChunk.m_ChunkChars.Length, "gap starts at end of buffer.  Should not happen");
@@ -2055,15 +1903,21 @@ namespace System.Text
         }
 
         /// <summary>
-        /// Returns true if the string that is starts at 'chunk' and 'indexInChunk, and has a logical
-        /// length of 'count' starts with the string 'value'. 
+        /// Returns a value indicating whether a substring of a builder starts with a specified prefix.
         /// </summary>
+        /// <param name="chunk">The chunk in which the substring starts.</param>
+        /// <param name="indexInChunk">The index in <paramref name="chunk"/> at which the substring starts.</param>
+        /// <param name="count">The logical count of the substring.</param>
+        /// <param name="value">The prefix.</param>
         private bool StartsWith(StringBuilder chunk, int indexInChunk, int count, string value)
         {
             for (int i = 0; i < value.Length; i++)
             {
                 if (count == 0)
+                {
                     return false;
+                }
+
                 if (indexInChunk >= chunk.m_ChunkLength)
                 {
                     chunk = Next(chunk);
@@ -2072,22 +1926,32 @@ namespace System.Text
                     indexInChunk = 0;
                 }
 
-                // See if there no match, break out of the inner for loop
                 if (value[i] != chunk.m_ChunkChars[indexInChunk])
+                {
                     return false;
+                }
 
                 indexInChunk++;
                 --count;
             }
+
             return true;
         }
 
         /// <summary>
-        /// ReplaceInPlaceAtChunk is the logical equivalent of 'memcpy'.  Given a chunk and ann index in
-        /// that chunk, it copies in 'count' characters from 'value' and updates 'chunk, and indexInChunk to 
-        /// point at the end of the characters just copyied (thus you can splice in strings from multiple 
-        /// places by calling this mulitple times.  
+        /// Replaces characters at a specified location with the contents of a character buffer.
+        /// This function is the logical equivalent of memcpy.
         /// </summary>
+        /// <param name="chunk">
+        /// The chunk in which to start replacing characters.
+        /// Receieves the chunk in which character replacement ends.
+        /// </param>
+        /// <param name="indexInChunk">
+        /// The index in <paramref name="chunk"/> to start replacing characters at.
+        /// Receives the index at which character replacement ends.
+        /// </param>
+        /// <param name="value">The pointer to the start of the character buffer.</param>
+        /// <param name="count">The number of characters in the buffer.</param>
         unsafe private void ReplaceInPlaceAtChunk(ref StringBuilder chunk, ref int indexInChunk, char* value, int count)
         {
             if (count != 0)
@@ -2095,7 +1959,7 @@ namespace System.Text
                 for (;;)
                 {
                     int lengthInChunk = chunk.m_ChunkLength - indexInChunk;
-                    Debug.Assert(lengthInChunk >= 0, "index not in chunk");
+                    Debug.Assert(lengthInChunk >= 0, "Index isn't in the chunk.");
 
                     int lengthToCopy = Math.Min(lengthInChunk, count);
                     ThreadSafeCopy(value, chunk.m_ChunkChars, indexInChunk, lengthToCopy);
@@ -2109,17 +1973,18 @@ namespace System.Text
                     }
                     count -= lengthToCopy;
                     if (count == 0)
+                    {
                         break;
+                    }
                     value += lengthToCopy;
                 }
             }
         }
 
-        /// <summary>
-        /// We have to prevent modification off the end of an array.
-        /// 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>
+        /// <remarks>
+        /// This method prevents out-of-bounds writes in the case a different thread updates a field in the builder just before a copy begins.
+        /// All interesting variables are copied out of the heap into the parameters of this method, and then bounds checks are run.
+        /// </remarks>
         private static unsafe void ThreadSafeCopy(char* sourcePtr, char[] destination, int destinationIndex, int count)
         {
             if (count > 0)
@@ -2156,81 +2021,90 @@ namespace System.Text
         }
 
         /// <summary>
-        /// Finds the chunk for the logical index (number of characters in the whole stringbuilder) 'index'
-        /// YOu can then get the offset in this chunk by subtracting the m_BlockOffset field from 'index' 
+        /// Gets the chunk corresponding to the logical index in this builder.
         /// </summary>
-        /// <param name="index"></param>
-        /// <returns></returns>
+        /// <param name="index">The logical index in this builder.</param>
+        /// <remarks>
+        /// After calling this method, you can obtain the actual index within the chunk by
+        /// subtracting <see cref="m_ChunkOffset"/> from <paramref name="index"/>.
+        /// </remarks>
         private StringBuilder FindChunkForIndex(int index)
         {
-            Debug.Assert(0 <= index && index <= Length, "index not in string");
+            Debug.Assert(0 <= index && index <= Length);
 
-            StringBuilder ret = this;
-            while (ret.m_ChunkOffset > index)
-                ret = ret.m_ChunkPrevious;
+            StringBuilder result = this;
+            while (result.m_ChunkOffset > index)
+            {
+                result = result.m_ChunkPrevious;
+            }
 
-            Debug.Assert(ret != null, "index not in string");
-            return ret;
+            Debug.Assert(result != null);
+            return result;
         }
 
         /// <summary>
-        /// Finds the chunk for the logical byte index 'byteIndex'
+        /// Gets the chunk corresponding to the logical byte index in this builder.
         /// </summary>
-        /// <param name="index"></param>
-        /// <returns></returns>
+        /// <param name="byteIndex">The logical byte index in this builder.</param>
         private StringBuilder FindChunkForByte(int byteIndex)
         {
-            Debug.Assert(0 <= byteIndex && byteIndex <= Length * sizeof(char), "Byte Index not in string");
+            Debug.Assert(0 <= byteIndex && byteIndex <= Length * sizeof(char));
 
-            StringBuilder ret = this;
-            while (ret.m_ChunkOffset * sizeof(char) > byteIndex)
-                ret = ret.m_ChunkPrevious;
+            StringBuilder result = this;
+            while (result.m_ChunkOffset * sizeof(char) > byteIndex)
+            {
+                result = result.m_ChunkPrevious;
+            }
 
-            Debug.Assert(ret != null, "Byte Index not in string");
-            return ret;
+            Debug.Assert(result != null);
+            return result;
         }
 
         /// <summary>
-        /// Finds the chunk that logically follows the 'chunk' chunk.  Chunks only persist the pointer to 
-        /// the chunk that is logically before it, so this routine has to start at the this pointer (which 
-        /// is a assumed to point at the chunk representing the whole stringbuilder) and search
-        /// until it finds the current chunk (thus is O(n)).  So it is more expensive than a field fetch!
+        /// Finds the chunk that logically succeeds the specified chunk.
         /// </summary>
-        private StringBuilder Next(StringBuilder chunk)
-        {
-            if (chunk == this)
-                return null;
-            return FindChunkForIndex(chunk.m_ChunkOffset + chunk.m_ChunkLength);
-        }
+        /// <param name="chunk">The chunk whose successor should be found.</param>
+        /// <remarks>
+        /// Each chunk only stores the pointer to its logical predecessor, so this routine has to start
+        /// from the 'this' pointer (which is assumed to represent the whole StringBuilder) and work its
+        /// way down until it finds the specified chunk (which is O(n)). Thus, it is more expensive than
+        /// a field fetch.
+        /// </remarks>
+        private StringBuilder Next(StringBuilder chunk) => chunk == this ? null : FindChunkForIndex(chunk.m_ChunkOffset + chunk.m_ChunkLength);
 
         /// <summary>
-        /// Assumes that 'this' is the last chunk in the list and that it is full.  Upon return the 'this'
-        /// block is updated so that it is a new block that has at least 'minBlockCharCount' characters.
-        /// that can be used to copy characters into it.   
+        /// Transfers the character buffer from this chunk to a new chunk, and allocates a new buffer with a minimum size for this chunk.
         /// </summary>
+        /// <param name="minBlockCharCount">The minimum size of the new buffer to be allocated for this chunk.</param>
+        /// <remarks>
+        /// This method requires that the current chunk is full. Otherwise, there's no point in shifting the characters over.
+        /// It also assumes that 'this' is the last chunk in the linked list.
+        /// </remarks>
         private void ExpandByABlock(int minBlockCharCount)
         {
-            Contract.Requires(Capacity == Length, "Expand expect to be called only when there is no space left");        // We are currently full
-            Contract.Requires(minBlockCharCount > 0, "Expansion request must be positive");
+            Contract.Requires(Capacity == Length, $"{nameof(ExpandByABlock)} should only be called when there is no space left.");
+            Contract.Requires(minBlockCharCount > 0);
 
-            VerifyClassInvariant();
+            AssertInvariants();
 
             if ((minBlockCharCount + Length) > m_MaxCapacity || minBlockCharCount + Length < minBlockCharCount)
+            {
                 throw new ArgumentOutOfRangeException("requiredLength", SR.ArgumentOutOfRange_SmallCapacity);
+            }
 
-            // Compute the length of the new block we need 
-            // We make the new chunk at least big enough for the current need (minBlockCharCount)
-            // But also as big as the current length (thus doubling capacity), 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. 
+            // - 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 = Math.Max(minBlockCharCount, Math.Min(Length, MaxChunkSize));
 
-            // Copy the current block to the new block, and initialize this to point at the new buffer. 
+            // Move all of the data from this chunk to a new one, via a few O(1) pointer adjustments.
+            // Then, have this chunk point to the new one as its predecessor.
             m_ChunkPrevious = new StringBuilder(this);
             m_ChunkOffset += m_ChunkLength;
             m_ChunkLength = 0;
 
-            // Check for integer overflow (logical buffer size > int.MaxInt)
+            // Check for integer overflow (logical buffer size > int.MaxValue)
             if (m_ChunkOffset + newBlockLength < newBlockLength)
             {
                 m_ChunkChars = null;
@@ -2238,14 +2112,24 @@ namespace System.Text
             }
             m_ChunkChars = new char[newBlockLength];
 
-            VerifyClassInvariant();
+            AssertInvariants();
         }
 
         /// <summary>
-        /// Used by ExpandByABlock to create a new chunk.  The new chunk is a copied from 'from'
-        /// In particular the buffer is shared.  It is expected that 'from' chunk (which represents
-        /// the whole list, is then updated to point to point to this new chunk. 
+        /// Creates a new chunk with fields copied from an existing chunk.
         /// </summary>
+        /// <param name="from">The chunk from which to copy fields.</param>
+        /// <remarks>
+        /// <para>
+        /// This method runs in O(1) time. It does not copy data within the character buffer
+        /// <paramref name="from"/> holds, but copies the reference to the character buffer itself
+        /// (plus a few other fields).
+        /// </para>
+        /// <para>
+        /// Callers are expected to update <paramref name="from"/> subsequently to point to this
+        /// chunk as its predecessor.
+        /// </para>
+        /// </remarks>
         private StringBuilder(StringBuilder from)
         {
             m_ChunkLength = from.m_ChunkLength;
@@ -2253,29 +2137,46 @@ namespace System.Text
             m_ChunkChars = from.m_ChunkChars;
             m_ChunkPrevious = from.m_ChunkPrevious;
             m_MaxCapacity = from.m_MaxCapacity;
-            VerifyClassInvariant();
+
+            AssertInvariants();
         }
 
         /// <summary>
-        /// Creates a gap of size 'count' at the logical offset (count of characters in the whole string
-        /// builder) 'index'.  It returns the 'chunk' and 'indexInChunk' which represents a pointer to
-        /// this gap that was just created.  You can then use 'ReplaceInPlaceAtChunk' to fill in the
-        /// chunk
-        ///
-        /// ReplaceAllChunks relies on the fact that indexes above 'index' are NOT moved outside 'chunk'
-        /// by this process (because we make the space by creating the cap BEFORE the chunk).  If we
-        /// change this ReplaceAllChunks needs to be updated. 
-        ///
-        /// 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)
+        /// Creates a gap at a logical index with the specified count.
         /// </summary>
-        private void MakeRoom(int index, int count, out StringBuilder chunk, out int indexInChunk, bool doneMoveFollowingChars)
-        {
-            VerifyClassInvariant();
-            Debug.Assert(count > 0, "Count must be strictly positive");
-            Debug.Assert(index >= 0, "Index can't be negative");
+        /// <param name="index">The logical index in this builder.</param>
+        /// <param name="count">The number of characters in the gap.</param>
+        /// <param name="chunk">Receives the chunk containing the gap.</param>
+        /// <param name="indexInChunk">The index in <paramref name="chunk"/> that points to the gap.</param>
+        /// <param name="doNotMoveFollowingChars">
+        /// - If <c>true</c>, then room must be made by inserting a chunk before the current chunk.
+        /// - If <c>false</c>, then room can be made by shifting characters ahead of <paramref name="index"/>
+        ///   in this block forward by <paramref name="count"/> provided the characters will still fit in
+        ///   the current chunk after being shifted.
+        ///   - Providing <c>false</c> does not make a difference most of the time, but it can matter when someone
+        ///     inserts lots of small strings at a position in the buffer.
+        /// </param>
+        /// <remarks>
+        /// <para>
+        /// Since chunks do not contain references to their successors, it is not always possible for us to make room
+        /// by inserting space after <paramref name="index"/> in case this chunk runs out of space. Thus, we make room
+        /// by inserting space before the specified index, and having logical indices refer to new locations by the end
+        /// of this method.
+        /// </para>
+        /// <para>
+        /// <see cref="ReplaceInPlaceAtChunk"/> can be used in conjunction with this method to fill in the newly created gap.
+        /// </para>
+        /// </remarks>
+        private void MakeRoom(int index, int count, out StringBuilder chunk, out int indexInChunk, bool doNotMoveFollowingChars)
+        {
+            AssertInvariants();
+            Debug.Assert(count > 0);
+            Debug.Assert(index >= 0);
+
             if (count + Length > m_MaxCapacity || count + Length < count)
+            {
                 throw new ArgumentOutOfRangeException("requiredLength", SR.ArgumentOutOfRange_SmallCapacity);
+            }
 
             chunk = this;
             while (chunk.m_ChunkOffset > index)
@@ -2285,12 +2186,11 @@ namespace System.Text
             }
             indexInChunk = index - chunk.m_ChunkOffset;
 
-            // Cool, we have some space in this block, and you don't have to copy much to get it, go ahead
-            // and use it.  This happens typically  when you repeatedly insert small strings at a spot
-            // (typically the absolute front) of the buffer.    
-            if (!doneMoveFollowingChars && chunk.m_ChunkLength <= DefaultCapacity * 2 && chunk.m_ChunkChars.Length - chunk.m_ChunkLength >= count)
+            // Cool, we have some space in this block, and we don't have to copy much to get at it, so go ahead and use it.
+            // This typically happens when someone repeatedly inserts small strings at a spot (usually the absolute front) of the buffer.
+            if (!doNotMoveFollowingChars && chunk.m_ChunkLength <= DefaultCapacity * 2 && chunk.m_ChunkChars.Length - chunk.m_ChunkLength >= count)
             {
-                for (int i = chunk.m_ChunkLength; i > indexInChunk;)
+                for (int i = chunk.m_ChunkLength; i > indexInChunk; )
                 {
                     --i;
                     chunk.m_ChunkChars[i + count] = chunk.m_ChunkChars[i];
@@ -2299,11 +2199,11 @@ namespace System.Text
                 return;
             }
 
-            // Allocate space for the new chunk (will go before this one)
+            // Allocate space for the new chunk, which will go before the current one.
             StringBuilder newChunk = new StringBuilder(Math.Max(count, DefaultCapacity), chunk.m_MaxCapacity, chunk.m_ChunkPrevious);
             newChunk.m_ChunkLength = count;
 
-            // Copy the head of the buffer to the  new buffer. 
+            // Copy the head of the current buffer to the new buffer.
             int copyCount1 = Math.Min(count, indexInChunk);
             if (copyCount1 > 0)
             {
@@ -2313,7 +2213,7 @@ namespace System.Text
                     {
                         ThreadSafeCopy(chunkCharsPtr, newChunk.m_ChunkChars, 0, copyCount1);
 
-                        // Slide characters in the current buffer over to make room. 
+                        // Slide characters over in the current buffer to make room.
                         int copyCount2 = indexInChunk - copyCount1;
                         if (copyCount2 >= 0)
                         {
@@ -2324,7 +2224,8 @@ namespace System.Text
                 }
             }
 
-            chunk.m_ChunkPrevious = newChunk;           // Wire in the new chunk
+            // Wire in the new chunk.
+            chunk.m_ChunkPrevious = newChunk;
             chunk.m_ChunkOffset += count;
             if (copyCount1 < count)
             {
@@ -2332,32 +2233,44 @@ namespace System.Text
                 indexInChunk = copyCount1;
             }
 
-            VerifyClassInvariant();
+            AssertInvariants();
         }
 
         /// <summary>
-        ///  Used by MakeRoom to allocate another chunk.  
+        /// Used by <see cref="MakeRoom"/> to allocate another chunk.
         /// </summary>
+        /// <param name="size">The size of the character buffer for this chunk.</param>
+        /// <param name="maxCapacity">The maximum capacity, to be stored in this chunk.</param>
+        /// <param name="previousBlock">The predecessor of this chunk.</param>
         private StringBuilder(int size, int maxCapacity, StringBuilder previousBlock)
         {
-            Debug.Assert(size > 0, "size not positive");
-            Debug.Assert(maxCapacity > 0, "maxCapacity not positive");
+            Debug.Assert(size > 0);
+            Debug.Assert(maxCapacity > 0);
+
             m_ChunkChars = new char[size];
             m_MaxCapacity = maxCapacity;
             m_ChunkPrevious = previousBlock;
             if (previousBlock != null)
+            {
                 m_ChunkOffset = previousBlock.m_ChunkOffset + previousBlock.m_ChunkLength;
-            VerifyClassInvariant();
+            }
+
+            AssertInvariants();
         }
 
         /// <summary>
-        /// 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.  
+        /// Removes a specified number of characters beginning at a logical index in this builder.
         /// </summary>
+        /// <param name="startIndex">The logical index in this builder to start removing characters.</param>
+        /// <param name="count">The number of characters to remove.</param>
+        /// <param name="chunk">Receives the new chunk containing the logical index.</param>
+        /// <param name="indexInChunk">
+        /// Receives the new index in <paramref name="chunk"/> that is associated with the logical index.
+        /// </param>
         private void Remove(int startIndex, int count, out StringBuilder chunk, out int indexInChunk)
         {
-            VerifyClassInvariant();
-            Debug.Assert(startIndex >= 0 && startIndex < Length, "startIndex not in string");
+            AssertInvariants();
+            Debug.Assert(startIndex >= 0 && startIndex < Length);
 
             int endIndex = startIndex + count;
 
@@ -2386,21 +2299,21 @@ namespace System.Text
                 }
                 chunk = chunk.m_ChunkPrevious;
             }
-            Debug.Assert(chunk != null, "fell off beginning of string!");
+            Debug.Assert(chunk != null, "We fell off the beginning of the string!");
 
             int copyTargetIndexInChunk = indexInChunk;
             int copyCount = endChunk.m_ChunkLength - endIndexInChunk;
             if (endChunk != chunk)
             {
                 copyTargetIndexInChunk = 0;
-                // Remove the characters after startIndex to end of the chunk
+                // Remove the characters after `startIndex` to the end of the chunk.
                 chunk.m_ChunkLength = indexInChunk;
 
-                // Remove the characters in chunks between start and end chunk
+                // Remove the characters in chunks between the start and the end chunk.
                 endChunk.m_ChunkPrevious = chunk;
                 endChunk.m_ChunkOffset = chunk.m_ChunkOffset + chunk.m_ChunkLength;
 
-                // If the start is 0 then we can throw away the whole start chunk
+                // If the start is 0, then we can throw away the whole start chunk.
                 if (indexInChunk == 0)
                 {
                     endChunk.m_ChunkPrevious = chunk.m_ChunkPrevious;
@@ -2409,15 +2322,17 @@ namespace System.Text
             }
             endChunk.m_ChunkLength -= (endIndexInChunk - copyTargetIndexInChunk);
 
-            // SafeCritical: We ensure that endIndexInChunk + copyCount is within range of m_ChunkChars and
-            // also ensure that copyTargetIndexInChunk + copyCount is within the chunk
-            //
+            // SafeCritical: We ensure that `endIndexInChunk + copyCount` is within range of `m_ChunkChars`, and
+            // also ensure that `copyTargetIndexInChunk + copyCount` is within the chunk.
+
             // Remove any characters in the end chunk, by sliding the characters down. 
-            if (copyTargetIndexInChunk != endIndexInChunk)  // Sometimes no move is necessary
+            if (copyTargetIndexInChunk != endIndexInChunk) // Sometimes no move is necessary
+            {
                 ThreadSafeCopy(endChunk.m_ChunkChars, endIndexInChunk, endChunk.m_ChunkChars, copyTargetIndexInChunk, copyCount);
+            }
 
-            Debug.Assert(chunk != null, "fell off beginning of string!");
-            VerifyClassInvariant();
+            Debug.Assert(chunk != null, "We fell off the beginning of the string!");
+            AssertInvariants();
         }
     }
 }
index db3895f..6455b48 100644 (file)
@@ -14,11 +14,17 @@ namespace System.Text
         [MethodImplAttribute(MethodImplOptions.InternalCall)]
         internal unsafe extern void ReplaceBufferAnsiInternal(sbyte* newBuffer, int newLength);
 
-        // Copies the source StringBuilder to the destination IntPtr memory allocated with len bytes.
+        /// <summary>
+        /// Copies the contents of this builder to the specified buffer.
+        /// </summary>
+        /// <param name="dest">The destination buffer.</param>
+        /// <param name="len">The number of bytes in the destination buffer.</param>
         internal unsafe void InternalCopy(IntPtr dest, int len)
         {
             if (len == 0)
+            {
                 return;
+            }
 
             bool isLastChunk = true;
             byte* dstPtr = (byte*)dest.ToPointer();
@@ -42,7 +48,8 @@ namespace System.Text
                     }
                 }
                 currentSrc = currentSrc.m_ChunkPrevious;
-            } while (currentSrc != null);
+            }
+            while (currentSrc != null);
         }
     }
 }