Port String reorganization from CoreRT (#6985)
authorJames Ko <jamesqko@gmail.com>
Tue, 30 Aug 2016 22:53:10 +0000 (18:53 -0400)
committerJan Kotas <jkotas@microsoft.com>
Tue, 30 Aug 2016 22:53:10 +0000 (15:53 -0700)
src/mscorlib/mscorlib.shared.sources.props
src/mscorlib/src/System/String.Comparison.cs [new file with mode: 0644]
src/mscorlib/src/System/String.Manipulation.cs [new file with mode: 0644]
src/mscorlib/src/System/String.Searching.cs [new file with mode: 0644]
src/mscorlib/src/System/String.cs
src/mscorlib/src/System/StringSplitOptions.cs [new file with mode: 0644]

index ba4c214..454084f 100644 (file)
     <SystemSources Include="$(BclSourcesRoot)\System\ThrowHelper.cs" />
     <SystemSources Include="$(BclSourcesRoot)\System\Tuple.cs" />
     <SystemSources Include="$(BclSourcesRoot)\System\String.cs" />
+    <SystemSources Include="$(BclSourcesRoot)\System\String.Comparison.cs" />
+    <SystemSources Include="$(BclSourcesRoot)\System\String.Manipulation.cs" />
+    <SystemSources Include="$(BclSourcesRoot)\System\String.Searching.cs" />
     <SystemSources Include="$(BclSourcesRoot)\System\StringComparer.cs" />
     <SystemSources Include="$(BclSourcesRoot)\System\StringComparison.cs" />
+    <SystemSources Include="$(BclSourcesRoot)\System\StringSplitOptions.cs" />
     <SystemSources Include="$(BclSourcesRoot)\System\Text\StringBuilder.cs" />
     <SystemSources Include="$(BclSourcesRoot)\System\Text\StringBuilderCache.cs" />
     <SystemSources Include="$(BclSourcesRoot)\System\Exception.cs" />
diff --git a/src/mscorlib/src/System/String.Comparison.cs b/src/mscorlib/src/System/String.Comparison.cs
new file mode 100644 (file)
index 0000000..a05f9f2
--- /dev/null
@@ -0,0 +1,1160 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections;
+using System.Diagnostics.Contracts;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+
+namespace System
+{
+    public partial class String
+    {
+        //
+        //Native Static Methods
+        //
+
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        private unsafe static int CompareOrdinalIgnoreCaseHelper(String strA, String strB)
+        {
+            Contract.Requires(strA != null);
+            Contract.Requires(strB != null);
+            Contract.EndContractBlock();
+            int length = Math.Min(strA.Length, strB.Length);
+    
+            fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
+            {
+                char* a = ap;
+                char* b = bp;
+
+                while (length != 0) 
+                {
+                    int charA = *a;
+                    int charB = *b;
+
+                    Contract.Assert((charA | charB) <= 0x7F, "strings have to be ASCII");
+
+                    // uppercase both chars - notice that we need just one compare per char
+                    if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
+                    if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;
+
+                    //Return the (case-insensitive) difference between them.
+                    if (charA != charB)
+                        return charA - charB;
+
+                    // Next char
+                    a++; b++;
+                    length--;
+                }
+
+                return strA.Length - strB.Length;
+            }
+        }
+
+        // native call to COMString::CompareOrdinalEx
+        [System.Security.SecurityCritical]  // auto-generated
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        internal static extern int CompareOrdinalHelper(String strA, int indexA, int countA, String strB, int indexB, int countB);
+
+        //This will not work in case-insensitive mode for any character greater than 0x80.  
+        //We'll throw an ArgumentException.
+        [System.Security.SecurityCritical]  // auto-generated
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        unsafe internal static extern int nativeCompareOrdinalIgnoreCaseWC(String strA, sbyte *strBBytes);
+
+        //
+        //
+        // NATIVE INSTANCE METHODS
+        //
+        //
+    
+        //
+        // Search/Query methods
+        //
+
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+        private unsafe static bool EqualsHelper(String strA, String strB)
+        {
+            Contract.Requires(strA != null);
+            Contract.Requires(strB != null);
+            Contract.Requires(strA.Length == strB.Length);
+
+            int length = strA.Length;
+
+            fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
+            {
+                char* a = ap;
+                char* b = bp;
+
+#if BIT64
+                // Single int read aligns pointers for the following long reads
+                // PERF: No length check needed as there is always an int32 worth of string allocated
+                //       This read can also include the null terminator which both strings will have
+                if (*(int*)a != *(int*)b) return false;
+                length -= 2; a += 2; b += 2;
+
+                // for AMD64 bit platform we unroll by 12 and
+                // check 3 qword at a time. This is less code
+                // than the 32 bit case and is a shorter path length.
+
+                while (length >= 12)
+                {
+                    if (*(long*)a != *(long*)b) goto ReturnFalse;
+                    if (*(long*)(a + 4) != *(long*)(b + 4)) goto ReturnFalse;
+                    if (*(long*)(a + 8) != *(long*)(b + 8)) goto ReturnFalse;
+                    length -= 12; a += 12; b += 12;
+                }
+#else
+                while (length >= 10)
+                {
+                    if (*(int*)a != *(int*)b) goto ReturnFalse;
+                    if (*(int*)(a + 2) != *(int*)(b + 2)) goto ReturnFalse;
+                    if (*(int*)(a + 4) != *(int*)(b + 4)) goto ReturnFalse;
+                    if (*(int*)(a + 6) != *(int*)(b + 6)) goto ReturnFalse;
+                    if (*(int*)(a + 8) != *(int*)(b + 8)) goto ReturnFalse;
+                    length -= 10; a += 10; b += 10;
+                }
+#endif
+
+                // This depends on the fact that the String objects are
+                // always zero terminated and that the terminating zero is not included
+                // in the length. For odd string sizes, the last compare will include
+                // the zero terminator.
+                while (length > 0) 
+                {
+                    if (*(int*)a != *(int*)b) goto ReturnFalse;
+                    length -= 2; a += 2; b += 2;
+                }
+
+                return true;
+
+                ReturnFalse:
+                return false;
+            }
+        }
+
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+        private unsafe static bool StartsWithOrdinalHelper(String str, String startsWith)
+        {
+            Contract.Requires(str != null);
+            Contract.Requires(startsWith != null);
+            Contract.Requires(str.Length >= startsWith.Length);
+
+            int length = startsWith.Length;
+
+            fixed (char* ap = &str.m_firstChar) fixed (char* bp = &startsWith.m_firstChar)
+            {
+                char* a = ap;
+                char* b = bp;
+
+#if BIT64
+                // Single int read aligns pointers for the following long reads
+                // No length check needed as this method is called when length >= 2
+                Contract.Assert(length >= 2);
+                if (*(int*)a != *(int*)b) goto ReturnFalse;
+                length -= 2; a += 2; b += 2;
+
+                while (length >= 12)
+                {
+                    if (*(long*)a != *(long*)b) goto ReturnFalse;
+                    if (*(long*)(a + 4) != *(long*)(b + 4)) goto ReturnFalse;
+                    if (*(long*)(a + 8) != *(long*)(b + 8)) goto ReturnFalse;
+                    length -= 12; a += 12; b += 12;
+                }
+#else
+                while (length >= 10)
+                {
+                    if (*(int*)a != *(int*)b) goto ReturnFalse;
+                    if (*(int*)(a+2) != *(int*)(b+2)) goto ReturnFalse;
+                    if (*(int*)(a+4) != *(int*)(b+4)) goto ReturnFalse;
+                    if (*(int*)(a+6) != *(int*)(b+6)) goto ReturnFalse;
+                    if (*(int*)(a+8) != *(int*)(b+8)) goto ReturnFalse;
+                    length -= 10; a += 10; b += 10;
+                }
+#endif
+
+                while (length >= 2)
+                {
+                    if (*(int*)a != *(int*)b) goto ReturnFalse;
+                    length -= 2; a += 2; b += 2;
+                }
+
+                // PERF: This depends on the fact that the String objects are always zero terminated 
+                // and that the terminating zero is not included in the length. For even string sizes
+                // this compare can include the zero terminator. Bitwise OR avoids a branch.
+                return length == 0 | *a == *b;
+
+                ReturnFalse:
+                return false;
+            }
+        }
+
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        private unsafe static int CompareOrdinalHelper(String strA, String strB)
+        {
+            Contract.Requires(strA != null);
+            Contract.Requires(strB != null);
+
+            // NOTE: This may be subject to change if eliminating the check
+            // in the callers makes them small enough to be inlined by the JIT
+            Contract.Assert(strA.m_firstChar == strB.m_firstChar,
+                "For performance reasons, callers of this method should " +
+                "check/short-circuit beforehand if the first char is the same.");
+
+            int length = Math.Min(strA.Length, strB.Length);
+
+            fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
+            {
+                char* a = ap;
+                char* b = bp;
+
+                // Check if the second chars are different here
+                // The reason we check if m_firstChar is different is because
+                // it's the most common case and allows us to avoid a method call
+                // to here.
+                // The reason we check if the second char is different is because
+                // if the first two chars the same we can increment by 4 bytes,
+                // leaving us word-aligned on both 32-bit (12 bytes into the string)
+                // and 64-bit (16 bytes) platforms.
+        
+                // For empty strings, the second char will be null due to padding.
+                // The start of the string (not including sync block pointer)
+                // is the method table pointer + string length, which takes up
+                // 8 bytes on 32-bit, 12 on x64. For empty strings the null
+                // terminator immediately follows, leaving us with an object
+                // 10/14 bytes in size. Since everything needs to be a multiple
+                // of 4/8, this will get padded and zeroed out.
+                
+                // For one-char strings the second char will be the null terminator.
+
+                // NOTE: If in the future there is a way to read the second char
+                // without pinning the string (e.g. System.Runtime.CompilerServices.Unsafe
+                // is exposed to mscorlib, or a future version of C# allows inline IL),
+                // then do that and short-circuit before the fixed.
+
+                if (*(a + 1) != *(b + 1)) goto DiffOffset1;
+                
+                // Since we know that the first two chars are the same,
+                // we can increment by 2 here and skip 4 bytes.
+                // This leaves us 8-byte aligned, which results
+                // on better perf for 64-bit platforms.
+                length -= 2; a += 2; b += 2;
+
+                // unroll the loop
+#if BIT64
+                while (length >= 12)
+                {
+                    if (*(long*)a != *(long*)b) goto DiffOffset0;
+                    if (*(long*)(a + 4) != *(long*)(b + 4)) goto DiffOffset4;
+                    if (*(long*)(a + 8) != *(long*)(b + 8)) goto DiffOffset8;
+                    length -= 12; a += 12; b += 12;
+                }
+#else // BIT64
+                while (length >= 10)
+                {
+                    if (*(int*)a != *(int*)b) goto DiffOffset0;
+                    if (*(int*)(a + 2) != *(int*)(b + 2)) goto DiffOffset2;
+                    if (*(int*)(a + 4) != *(int*)(b + 4)) goto DiffOffset4;
+                    if (*(int*)(a + 6) != *(int*)(b + 6)) goto DiffOffset6;
+                    if (*(int*)(a + 8) != *(int*)(b + 8)) goto DiffOffset8;
+                    length -= 10; a += 10; b += 10; 
+                }
+#endif // BIT64
+
+                // Fallback loop:
+                // go back to slower code path and do comparison on 4 bytes at a time.
+                // This depends on the fact that the String objects are
+                // always zero terminated and that the terminating zero is not included
+                // in the length. For odd string sizes, the last compare will include
+                // the zero terminator.
+                while (length > 0)
+                {
+                    if (*(int*)a != *(int*)b) goto DiffNextInt;
+                    length -= 2;
+                    a += 2; 
+                    b += 2; 
+                }
+
+                // At this point, we have compared all the characters in at least one string.
+                // The longer string will be larger.
+                return strA.Length - strB.Length;
+                
+#if BIT64
+                DiffOffset8: a += 4; b += 4;
+                DiffOffset4: a += 4; b += 4;
+#else // BIT64
+                // Use jumps instead of falling through, since
+                // otherwise going to DiffOffset8 will involve
+                // 8 add instructions before getting to DiffNextInt
+                DiffOffset8: a += 8; b += 8; goto DiffOffset0;
+                DiffOffset6: a += 6; b += 6; goto DiffOffset0;
+                DiffOffset4: a += 2; b += 2;
+                DiffOffset2: a += 2; b += 2;
+#endif // BIT64
+                
+                DiffOffset0:
+                // If we reached here, we already see a difference in the unrolled loop above
+#if BIT64
+                if (*(int*)a == *(int*)b)
+                {
+                    a += 2; b += 2;
+                }
+#endif // BIT64
+
+                DiffNextInt:
+                if (*a != *b) return *a - *b;
+
+                DiffOffset1:
+                Contract.Assert(*(a + 1) != *(b + 1), "This char must be different if we reach here!");
+                return *(a + 1) - *(b + 1);
+            }
+        }
+    
+        // Provides a culture-correct string comparison. StrA is compared to StrB
+        // to determine whether it is lexicographically less, equal, or greater, and then returns
+        // either a negative integer, 0, or a positive integer; respectively.
+        //
+        [Pure]
+        public static int Compare(String strA, String strB)
+        {
+            return Compare(strA, strB, StringComparison.CurrentCulture);
+        }
+    
+
+        // Provides a culture-correct string comparison. strA is compared to strB
+        // to determine whether it is lexicographically less, equal, or greater, and then a
+        // negative integer, 0, or a positive integer is returned; respectively.
+        // The case-sensitive option is set by ignoreCase
+        //
+        [Pure]
+        public static int Compare(String strA, String strB, bool ignoreCase)
+        {
+            var comparisonType = ignoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture;
+            return Compare(strA, strB, comparisonType);
+        }
+
+  
+        // Provides a more flexible function for string comparision. See StringComparison 
+        // for meaning of different comparisonType.
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public static int Compare(String strA, String strB, StringComparison comparisonType) 
+        {
+            // Single comparison to check if comparisonType is within [CurrentCulture .. OrdinalIgnoreCase]
+            if ((uint)(comparisonType - StringComparison.CurrentCulture) > (uint)(StringComparison.OrdinalIgnoreCase - StringComparison.CurrentCulture))
+            {
+                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
+            }
+            Contract.EndContractBlock();
+
+            if (object.ReferenceEquals(strA, strB))
+            {
+                return 0;
+            }
+
+            // They can't both be null at this point.
+            if (strA == null)
+            {
+                return -1;
+            }
+            if (strB == null)
+            {
+                return 1;
+            }
+
+            switch (comparisonType) {
+                case StringComparison.CurrentCulture:
+                    return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
+
+                case StringComparison.CurrentCultureIgnoreCase:
+                    return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
+
+                case StringComparison.InvariantCulture:
+                    return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
+
+                case StringComparison.InvariantCultureIgnoreCase:
+                    return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
+
+                case StringComparison.Ordinal:
+                    // Most common case: first character is different.
+                    // Returns false for empty strings.
+                    if (strA.m_firstChar != strB.m_firstChar)
+                    {
+                        return strA.m_firstChar - strB.m_firstChar;
+                    }
+
+                    return CompareOrdinalHelper(strA, strB);
+
+                case StringComparison.OrdinalIgnoreCase:
+                    // If both strings are ASCII strings, we can take the fast path.
+                    if (strA.IsAscii() && strB.IsAscii()) {
+                        return (CompareOrdinalIgnoreCaseHelper(strA, strB));
+                    }
+
+#if FEATURE_COREFX_GLOBALIZATION
+                    return CompareInfo.CompareOrdinalIgnoreCase(strA, 0, strA.Length, strB, 0, strB.Length);
+#else
+                    // Take the slow path.
+                    return TextInfo.CompareOrdinalIgnoreCase(strA, strB);
+#endif
+
+                default:
+                    throw new NotSupportedException(Environment.GetResourceString("NotSupported_StringComparison"));
+            }
+        }
+
+
+        // Provides a culture-correct string comparison. strA is compared to strB
+        // to determine whether it is lexicographically less, equal, or greater, and then a
+        // negative integer, 0, or a positive integer is returned; respectively.
+        //
+        [Pure]
+        public static int Compare(String strA, String strB, CultureInfo culture, CompareOptions options) {
+            if (culture == null)
+            {
+                throw new ArgumentNullException("culture");
+            }
+            Contract.EndContractBlock();
+
+            return culture.CompareInfo.Compare(strA, strB, options);
+        }
+
+
+
+        // Provides a culture-correct string comparison. strA is compared to strB
+        // to determine whether it is lexicographically less, equal, or greater, and then a
+        // negative integer, 0, or a positive integer is returned; respectively.
+        // The case-sensitive option is set by ignoreCase, and the culture is set
+        // by culture
+        //
+        [Pure]
+        public static int Compare(String strA, String strB, bool ignoreCase, CultureInfo culture)
+        {
+            var options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
+            return Compare(strA, strB, culture, options);
+        }
+
+        // Determines whether two string regions match.  The substring of strA beginning
+        // at indexA of length count is compared with the substring of strB
+        // beginning at indexB of the same length.
+        //
+        [Pure]
+        public static int Compare(String strA, int indexA, String strB, int indexB, int length)
+        {
+            // NOTE: It's important we call the boolean overload, and not the StringComparison
+            // one. The two have some subtly different behavior (see notes in the former).
+            return Compare(strA, indexA, strB, indexB, length, ignoreCase: false);
+        }
+
+        // Determines whether two string regions match.  The substring of strA beginning
+        // at indexA of length count is compared with the substring of strB
+        // beginning at indexB of the same length.  Case sensitivity is determined by the ignoreCase boolean.
+        //
+        [Pure]
+        public static int Compare(String strA, int indexA, String strB, int indexB, int length, bool ignoreCase)
+        {
+            // Ideally we would just forward to the string.Compare overload that takes
+            // a StringComparison parameter, and just pass in CurrentCulture/CurrentCultureIgnoreCase.
+            // That function will return early if an optimization can be applied, e.g. if
+            // (object)strA == strB && indexA == indexB then it will return 0 straightaway.
+            // There are a couple of subtle behavior differences that prevent us from doing so
+            // however:
+            // - string.Compare(null, -1, null, -1, -1, StringComparison.CurrentCulture) works
+            //   since that method also returns early for nulls before validation. It shouldn't
+            //   for this overload.
+            // - Since we originally forwarded to CompareInfo.Compare for all of the argument
+            //   validation logic, the ArgumentOutOfRangeExceptions thrown will contain different
+            //   parameter names.
+            // Therefore, we have to duplicate some of the logic here.
+
+            int lengthA = length;
+            int lengthB = length;
+            
+            if (strA != null)
+            {
+                lengthA = Math.Min(lengthA, strA.Length - indexA);
+            }
+
+            if (strB != null)
+            {
+                lengthB = Math.Min(lengthB, strB.Length - indexB);
+            }
+
+            var options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
+            return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, options);
+        }
+
+        // Determines whether two string regions match.  The substring of strA beginning
+        // at indexA of length length is compared with the substring of strB
+        // beginning at indexB of the same length.  Case sensitivity is determined by the ignoreCase boolean,
+        // and the culture is set by culture.
+        //
+        [Pure]
+        public static int Compare(String strA, int indexA, String strB, int indexB, int length, bool ignoreCase, CultureInfo culture)
+        {
+            var options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
+            return Compare(strA, indexA, strB, indexB, length, culture, options);
+        }
+
+
+        // Determines whether two string regions match.  The substring of strA beginning
+        // at indexA of length length is compared with the substring of strB
+        // beginning at indexB of the same length.
+        //
+        [Pure]
+        public static int Compare(String strA, int indexA, String strB, int indexB, int length, CultureInfo culture, CompareOptions options)
+        {
+            if (culture == null)
+            {
+                throw new ArgumentNullException("culture");
+            }
+            Contract.EndContractBlock();
+
+            int lengthA = length;
+            int lengthB = length;
+
+            if (strA != null)
+            {
+                lengthA = Math.Min(lengthA, strA.Length - indexA);
+            }
+
+            if (strB != null)
+            {
+                lengthB = Math.Min(lengthB, strB.Length - indexB);
+            }
+    
+            return culture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, options);
+        }
+
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public static int Compare(String strA, int indexA, String strB, int indexB, int length, StringComparison comparisonType) {
+            if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
+                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
+            }
+            Contract.EndContractBlock();
+            
+            if (strA == null || strB == null)
+            {
+                if (object.ReferenceEquals(strA, strB))
+                {
+                    // They're both null
+                    return 0;
+                }
+
+                return strA == null ? -1 : 1;
+            }
+
+            if (length < 0)
+            {
+                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
+            }
+
+            if (indexA < 0 || indexB < 0)
+            {
+                string paramName = indexA < 0 ? "indexA" : "indexB";
+                throw new ArgumentOutOfRangeException(paramName, Environment.GetResourceString("ArgumentOutOfRange_Index"));
+            }
+
+            if (strA.Length - indexA < 0 || strB.Length - indexB < 0)
+            {
+                string paramName = strA.Length - indexA < 0 ? "indexA" : "indexB";
+                throw new ArgumentOutOfRangeException(paramName, Environment.GetResourceString("ArgumentOutOfRange_Index"));
+            }
+
+            if (length == 0 || (object.ReferenceEquals(strA, strB) && indexA == indexB))
+            {
+                return 0;
+            }
+
+            int lengthA = Math.Min(length, strA.Length - indexA);
+            int lengthB = Math.Min(length, strB.Length - indexB);
+
+            switch (comparisonType) {
+                case StringComparison.CurrentCulture:
+                    return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
+
+                case StringComparison.CurrentCultureIgnoreCase:
+                    return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
+
+                case StringComparison.InvariantCulture:
+                    return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
+
+                case StringComparison.InvariantCultureIgnoreCase:
+                    return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
+
+                case StringComparison.Ordinal:
+                    return CompareOrdinalHelper(strA, indexA, lengthA, strB, indexB, lengthB);
+
+                case StringComparison.OrdinalIgnoreCase:
+#if FEATURE_COREFX_GLOBALIZATION
+                    return (CompareInfo.CompareOrdinalIgnoreCase(strA, indexA, lengthA, strB, indexB, lengthB));
+#else
+                    return (TextInfo.CompareOrdinalIgnoreCaseEx(strA, indexA, strB, indexB, lengthA, lengthB));
+#endif
+
+                default:
+                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"));
+            }
+
+        }
+
+        // Compares strA and strB using an ordinal (code-point) comparison.
+        //
+        [Pure]
+        public static int CompareOrdinal(String strA, String strB)
+        {
+            if (object.ReferenceEquals(strA, strB))
+            {
+                return 0;
+            }
+
+            // They can't both be null at this point.
+            if (strA == null)
+            {
+                return -1;
+            }
+            if (strB == null)
+            {
+                return 1;
+            }
+
+            // Most common case, first character is different.
+            // This will return false for empty strings.
+            if (strA.m_firstChar != strB.m_firstChar)
+            {
+                return strA.m_firstChar - strB.m_firstChar;
+            }
+
+            return CompareOrdinalHelper(strA, strB);
+        }
+        
+
+        // Compares strA and strB using an ordinal (code-point) comparison.
+        //
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public static int CompareOrdinal(String strA, int indexA, String strB, int indexB, int length)
+        {
+            if (strA == null || strB == null)
+            {
+                if (object.ReferenceEquals(strA, strB))
+                {
+                    // They're both null
+                    return 0;
+                }
+
+                return strA == null ? -1 : 1;
+            }
+
+            // COMPAT: Checking for nulls should become before the arguments are validated,
+            // but other optimizations which allow us to return early should come after.
+
+            if (length < 0)
+            {
+                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
+            }
+
+            if (indexA < 0 || indexB < 0)
+            {
+                string paramName = indexA < 0 ? "indexA" : "indexB";
+                throw new ArgumentOutOfRangeException(paramName, Environment.GetResourceString("ArgumentOutOfRange_Index"));
+            }
+            
+            int lengthA = Math.Min(length, strA.Length - indexA);
+            int lengthB = Math.Min(length, strB.Length - indexB);
+
+            if (lengthA < 0 || lengthB < 0)
+            {
+                string paramName = lengthA < 0 ? "indexA" : "indexB";
+                throw new ArgumentOutOfRangeException(paramName, Environment.GetResourceString("ArgumentOutOfRange_Index"));
+            }
+
+            if (length == 0 || (object.ReferenceEquals(strA, strB) && indexA == indexB))
+            {
+                return 0;
+            }
+
+            return CompareOrdinalHelper(strA, indexA, lengthA, strB, indexB, lengthB);
+        }
+
+        // Compares this String to another String (cast as object), returning an integer that
+        // indicates the relationship. This method returns a value less than 0 if this is less than value, 0
+        // if this is equal to value, or a value greater than 0 if this is greater than value.
+        //
+        [Pure]
+        public int CompareTo(Object value)
+        {
+            if (value == null)
+            {
+                return 1;
+            }
+
+            string other = value as string;
+
+            if (other == null)
+            {
+                throw new ArgumentException(Environment.GetResourceString("Arg_MustBeString"));
+            }
+
+            return CompareTo(other); // will call the string-based overload
+        }
+    
+        // Determines the sorting relation of StrB to the current instance.
+        //
+        [Pure]
+        public int CompareTo(String strB)
+        {
+            return string.Compare(this, strB, StringComparison.CurrentCulture);
+        }
+
+        // Determines whether a specified string is a suffix of the the current instance.
+        //
+        // The case-sensitive and culture-sensitive option is set by options,
+        // and the default culture is used.
+        //        
+        [Pure]
+        public Boolean EndsWith(String value) {
+            return EndsWith(value, StringComparison.CurrentCulture);
+        }
+
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        [ComVisible(false)]
+        public Boolean EndsWith(String value, StringComparison comparisonType) {
+            if( (Object)value == null) {
+                throw new ArgumentNullException("value");                                
+            }
+
+            if( comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
+                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
+            }
+            Contract.EndContractBlock();
+
+            if( (Object)this == (Object)value) {
+                return true;
+            }
+
+            if( value.Length == 0) {
+                return true;
+            }
+            
+            switch (comparisonType) {
+                case StringComparison.CurrentCulture:
+                    return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(this, value, CompareOptions.None);
+
+                case StringComparison.CurrentCultureIgnoreCase:
+                    return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(this, value, CompareOptions.IgnoreCase);
+
+                case StringComparison.InvariantCulture:
+                    return CultureInfo.InvariantCulture.CompareInfo.IsSuffix(this, value, CompareOptions.None);
+
+                case StringComparison.InvariantCultureIgnoreCase:
+                    return CultureInfo.InvariantCulture.CompareInfo.IsSuffix(this, value, CompareOptions.IgnoreCase);                    
+
+                case StringComparison.Ordinal:
+                    return this.Length < value.Length ? false : (CompareOrdinalHelper(this, this.Length - value.Length, value.Length, value, 0, value.Length) == 0);
+
+                case StringComparison.OrdinalIgnoreCase:
+#if FEATURE_COREFX_GLOBALIZATION
+                    return this.Length < value.Length ? false : (CompareInfo.CompareOrdinalIgnoreCase(this, this.Length - value.Length, value.Length, value, 0, value.Length) == 0);
+#else                    
+                    return this.Length < value.Length ? false : (TextInfo.CompareOrdinalIgnoreCaseEx(this, this.Length - value.Length, value, 0, value.Length, value.Length) == 0);
+#endif
+                default:
+                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
+            }                        
+        }
+
+        [Pure]
+        public Boolean EndsWith(String value, Boolean ignoreCase, CultureInfo culture) {
+            if (null==value) {
+                throw new ArgumentNullException("value");
+            }
+            Contract.EndContractBlock();
+            
+            if((object)this == (object)value) {
+                return true;
+            }
+
+            CultureInfo referenceCulture;
+            if (culture == null)
+                referenceCulture = CultureInfo.CurrentCulture;
+            else
+                referenceCulture = culture;
+
+            return referenceCulture.CompareInfo.IsSuffix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
+        }
+
+        [Pure]
+        internal bool EndsWith(char value) {
+            int thisLen = this.Length;
+            if (thisLen != 0) {
+                if (this[thisLen - 1] == value)
+                    return true;
+            }
+            return false;
+        }
+
+        // Determines whether two strings match.
+        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+        public override bool Equals(Object obj)
+        {
+            if (this == null)                        // this is necessary to guard against reverse-pinvokes and
+                throw new NullReferenceException();  // other callers who do not use the callvirt instruction
+
+            if (object.ReferenceEquals(this, obj))
+                return true;
+
+            string str = obj as string;
+            if (str == null)
+                return false;
+
+            if (this.Length != str.Length)
+                return false;
+
+            return EqualsHelper(this, str);
+        }
+
+        // Determines whether two strings match.
+        [Pure]
+        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+        public bool Equals(String value)
+        {
+            if (this == null)                        // this is necessary to guard against reverse-pinvokes and
+                throw new NullReferenceException();  // other callers who do not use the callvirt instruction
+
+            if (object.ReferenceEquals(this, value))
+                return true;
+
+            // NOTE: No need to worry about casting to object here.
+            // If either side of an == comparison between strings
+            // is null, Roslyn generates a simple ceq instruction
+            // instead of calling string.op_Equality.
+            if (value == null)
+                return false;
+            
+            if (this.Length != value.Length)
+                return false;
+
+            return EqualsHelper(this, value);
+        }
+
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public bool Equals(String value, StringComparison comparisonType) {
+            if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase)
+                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
+            Contract.EndContractBlock();
+
+            if ((Object)this == (Object)value) {
+                return true;
+            }
+
+            if ((Object)value == null) {
+                return false;
+            }
+
+            switch (comparisonType) {
+                case StringComparison.CurrentCulture:
+                    return (CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0);
+
+                case StringComparison.CurrentCultureIgnoreCase:
+                    return (CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0);
+
+                case StringComparison.InvariantCulture:
+                    return (CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0);
+
+                case StringComparison.InvariantCultureIgnoreCase:
+                    return (CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0);
+
+                case StringComparison.Ordinal:
+                    if (this.Length != value.Length)
+                        return false;
+                    return EqualsHelper(this, value);
+
+                case StringComparison.OrdinalIgnoreCase:
+                    if (this.Length != value.Length)
+                        return false;
+
+                    // If both strings are ASCII strings, we can take the fast path.
+                    if (this.IsAscii() && value.IsAscii()) {
+                        return (CompareOrdinalIgnoreCaseHelper(this, value) == 0);
+                    }
+
+#if FEATURE_COREFX_GLOBALIZATION
+                    return (CompareInfo.CompareOrdinalIgnoreCase(this, 0, this.Length, value, 0, value.Length) == 0);
+#else
+                    // Take the slow path.
+                    return (TextInfo.CompareOrdinalIgnoreCase(this, value) == 0);
+#endif
+
+                default:
+                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
+            }
+        }
+
+
+        // Determines whether two Strings match.
+        [Pure]
+        public static bool Equals(String a, String b) {
+            if ((Object)a==(Object)b) {
+                return true;
+            }
+
+            if ((Object)a == null || (Object)b == null || a.Length != b.Length) {
+                return false;
+            }
+
+            return EqualsHelper(a, b);
+        }
+
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public static bool Equals(String a, String b, StringComparison comparisonType) {
+            if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase)
+                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
+            Contract.EndContractBlock();
+
+            if ((Object)a==(Object)b) {
+                return true;
+            }
+    
+            if ((Object)a==null || (Object)b==null) {
+                return false;
+            }
+
+            switch (comparisonType) {
+                case StringComparison.CurrentCulture:
+                    return (CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0);
+
+                case StringComparison.CurrentCultureIgnoreCase:
+                    return (CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0);
+
+                case StringComparison.InvariantCulture:
+                    return (CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0);
+
+                case StringComparison.InvariantCultureIgnoreCase:
+                    return (CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0);
+
+                case StringComparison.Ordinal:
+                    if (a.Length != b.Length)
+                        return false;
+
+                    return EqualsHelper(a, b);
+
+                case StringComparison.OrdinalIgnoreCase:
+                    if (a.Length != b.Length)
+                        return false;
+                    else {
+                        // If both strings are ASCII strings, we can take the fast path.
+                        if (a.IsAscii() && b.IsAscii()) {
+                            return (CompareOrdinalIgnoreCaseHelper(a, b) == 0);
+                        }
+                        // Take the slow path.
+
+#if FEATURE_COREFX_GLOBALIZATION
+                        return (CompareInfo.CompareOrdinalIgnoreCase(a, 0, a.Length, b, 0, b.Length) == 0);
+#else
+                        return (TextInfo.CompareOrdinalIgnoreCase(a, b) == 0);
+#endif
+                    }
+
+                default:
+                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
+            }
+        }
+
+        public static bool operator == (String a, String b) {
+           return String.Equals(a, b);
+        }
+
+        public static bool operator != (String a, String b) {
+           return !String.Equals(a, b);
+        }
+
+#if FEATURE_RANDOMIZED_STRING_HASHING
+        // Do not remove!
+        // This method is called by reflection in System.Xml
+        [System.Security.SecurityCritical]
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        internal static extern int InternalMarvin32HashString(string s, int strLen, long additionalEntropy);
+
+        [System.Security.SecuritySafeCritical]
+        internal static bool UseRandomizedHashing() {
+            return InternalUseRandomizedHashing();
+        }
+
+        [System.Security.SecurityCritical]
+        [System.Security.SuppressUnmanagedCodeSecurity]
+        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+        private static extern bool InternalUseRandomizedHashing();
+#endif
+
+        // Gets a hash code for this string.  If strings A and B are such that A.Equals(B), then
+        // they will return the same hash code.
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+        public override int GetHashCode()
+        {
+#if FEATURE_RANDOMIZED_STRING_HASHING
+            if (HashHelpers.s_UseRandomizedStringHashing)
+            {
+                return InternalMarvin32HashString(this, this.Length, 0);
+            }
+#endif // FEATURE_RANDOMIZED_STRING_HASHING
+
+            return GetLegacyNonRandomizedHashCode();
+        }
+
+        // Use this if and only if you need the hashcode to not change across app domains (e.g. you have an app domain agile
+        // hash table).
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+        internal int GetLegacyNonRandomizedHashCode() {
+            unsafe {
+                fixed (char* src = &m_firstChar) {
+                    Contract.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'");
+                    Contract.Assert( ((int)src)%4 == 0, "Managed string should start at 4 bytes boundary");
+#if BIT64
+                    int hash1 = 5381;
+#else // !BIT64 (32)
+                    int hash1 = (5381<<16) + 5381;
+#endif
+                    int hash2 = hash1;
+
+#if BIT64
+                    int     c;
+                    char *s = src;
+                    while ((c = s[0]) != 0) {
+                        hash1 = ((hash1 << 5) + hash1) ^ c;
+                        c = s[1];
+                        if (c == 0)
+                            break;
+                        hash2 = ((hash2 << 5) + hash2) ^ c;
+                        s += 2;
+                    }
+#else // !BIT64 (32)
+                    // 32 bit machines.
+                    int* pint = (int *)src;
+                    int len = this.Length;
+                    while (len > 2)
+                    {
+                        hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
+                        hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
+                        pint += 2;
+                        len  -= 4;
+                    }
+
+                    if (len > 0)
+                    {
+                        hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
+                    }
+#endif
+#if DEBUG
+                    // We want to ensure we can change our hash function daily.
+                    // This is perfectly fine as long as you don't persist the
+                    // value from GetHashCode to disk or count on String A 
+                    // hashing before string B.  Those are bugs in your code.
+                    hash1 ^= ThisAssembly.DailyBuildNumber;
+#endif
+                    return hash1 + (hash2 * 1566083941);
+                }
+            }
+        }
+    
+        // Determines whether a specified string is a prefix of the current instance
+        //
+        [Pure]
+        public Boolean StartsWith(String value) {
+            if ((Object)value == null) {
+                throw new ArgumentNullException("value");
+            }
+            Contract.EndContractBlock();
+            return StartsWith(value, StringComparison.CurrentCulture);
+        }
+
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        [ComVisible(false)]
+        public Boolean StartsWith(String value, StringComparison comparisonType) {
+            if( (Object)value == null) {
+                throw new ArgumentNullException("value");                                
+            }
+
+            if( comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
+                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
+            }
+            Contract.EndContractBlock();
+
+            if( (Object)this == (Object)value) {
+                return true;
+            }
+
+            if( value.Length == 0) {
+                return true;
+            }
+
+            switch (comparisonType) {
+                case StringComparison.CurrentCulture:
+                    return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None);
+
+                case StringComparison.CurrentCultureIgnoreCase:
+                    return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase);
+
+                case StringComparison.InvariantCulture:
+                    return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None);
+
+                case StringComparison.InvariantCultureIgnoreCase:
+                    return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase);                    
+
+                case StringComparison.Ordinal:
+                    if( this.Length < value.Length || m_firstChar != value.m_firstChar) {
+                        return false;
+                    }
+                    return (value.Length == 1) ?
+                            true :                 // First char is the same and thats all there is to compare
+                            StartsWithOrdinalHelper(this, value);
+
+                case StringComparison.OrdinalIgnoreCase:
+                    if( this.Length < value.Length) {
+                        return false;
+                    }
+                    
+#if FEATURE_COREFX_GLOBALIZATION
+                    return (CompareInfo.CompareOrdinalIgnoreCase(this, 0, value.Length, value, 0, value.Length) == 0);
+#else
+                    return (TextInfo.CompareOrdinalIgnoreCaseEx(this, 0, value, 0, value.Length, value.Length) == 0);
+#endif
+
+                default:
+                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
+            }                        
+        }
+
+        [Pure]
+        public Boolean StartsWith(String value, Boolean ignoreCase, CultureInfo culture) {
+            if (null==value) {
+                throw new ArgumentNullException("value");
+            }
+            Contract.EndContractBlock();
+
+            if((object)this == (object)value) {
+                return true;
+            }
+
+            CultureInfo referenceCulture;
+            if (culture == null)
+                referenceCulture = CultureInfo.CurrentCulture;
+            else
+                referenceCulture = culture;
+
+            return referenceCulture.CompareInfo.IsPrefix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/mscorlib/src/System/String.Manipulation.cs b/src/mscorlib/src/System/String.Manipulation.cs
new file mode 100644 (file)
index 0000000..e9568a6
--- /dev/null
@@ -0,0 +1,1596 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace System
+{
+    public partial class String
+    {
+        private const int TrimHead = 0;
+        private const int TrimTail = 1;
+        private const int TrimBoth = 2;
+
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        unsafe private static void FillStringChecked(String dest, int destPos, String src)
+        {
+            Contract.Requires(dest != null);
+            Contract.Requires(src != null);
+            if (src.Length > dest.Length - destPos) {
+                throw new IndexOutOfRangeException();
+            }
+            Contract.EndContractBlock();
+
+            fixed(char *pDest = &dest.m_firstChar)
+                fixed (char *pSrc = &src.m_firstChar) {
+                    wstrcpy(pDest + destPos, pSrc, src.Length);
+                }
+        }
+
+        public static String Concat(Object arg0) {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            if (arg0 == null)
+            {
+                return String.Empty;
+            }
+            return arg0.ToString();
+        }
+    
+        public static String Concat(Object arg0, Object arg1) {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            if (arg0 == null)
+            {
+                arg0 = String.Empty;
+            }
+    
+            if (arg1==null) {
+                arg1 = String.Empty;
+            }
+            return Concat(arg0.ToString(), arg1.ToString());
+        }
+    
+        public static String Concat(Object arg0, Object arg1, Object arg2) {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            if (arg0 == null)
+            {
+                arg0 = String.Empty;
+            }
+    
+            if (arg1==null) {
+                arg1 = String.Empty;
+            }
+    
+            if (arg2==null) {
+                arg2 = String.Empty;
+            }
+    
+            return Concat(arg0.ToString(), arg1.ToString(), arg2.ToString());
+        }
+
+        [CLSCompliant(false)] 
+        public static String Concat(Object arg0, Object arg1, Object arg2, Object arg3, __arglist) 
+        {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            Object[]   objArgs;
+            int        argCount;
+            
+            ArgIterator args = new ArgIterator(__arglist);
+
+            //+4 to account for the 4 hard-coded arguments at the beginning of the list.
+            argCount = args.GetRemainingCount() + 4;
+    
+            objArgs = new Object[argCount];
+            
+            //Handle the hard-coded arguments
+            objArgs[0] = arg0;
+            objArgs[1] = arg1;
+            objArgs[2] = arg2;
+            objArgs[3] = arg3;
+            
+            //Walk all of the args in the variable part of the argument list.
+            for (int i=4; i<argCount; i++) {
+                objArgs[i] = TypedReference.ToObject(args.GetNextArg());
+            }
+
+            return Concat(objArgs);
+        }
+
+        [System.Security.SecuritySafeCritical]
+        public static string Concat(params object[] args)
+        {
+            if (args == null)
+            {
+                throw new ArgumentNullException("args");
+            }
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            if (args.Length <= 1)
+            {
+                return args.Length == 0 ?
+                    string.Empty :
+                    args[0]?.ToString() ?? string.Empty;
+            }
+
+            // We need to get an intermediary string array
+            // to fill with each of the args' ToString(),
+            // and then just concat that in one operation.
+
+            // This way we avoid any intermediary string representations,
+            // or buffer resizing if we use StringBuilder (although the
+            // latter case is partially alleviated due to StringBuilder's
+            // linked-list style implementation)
+
+            var strings = new string[args.Length];
+            
+            int totalLength = 0;
+
+            for (int i = 0; i < args.Length; i++)
+            {
+                object value = args[i];
+
+                string toString = value?.ToString() ?? string.Empty; // We need to handle both the cases when value or value.ToString() is null
+                strings[i] = toString;
+
+                totalLength += toString.Length;
+
+                if (totalLength < 0) // Check for a positive overflow
+                {
+                    throw new OutOfMemoryException();
+                }
+            }
+
+            // If all of the ToStrings are null/empty, just return string.Empty
+            if (totalLength == 0)
+            {
+                return string.Empty;
+            }
+
+            string result = FastAllocateString(totalLength);
+            int position = 0; // How many characters we've copied so far
+
+            for (int i = 0; i < strings.Length; i++)
+            {
+                string s = strings[i];
+
+                Contract.Assert(s != null);
+                Contract.Assert(position <= totalLength - s.Length, "We didn't allocate enough space for the result string!");
+
+                FillStringChecked(result, position, s);
+                position += s.Length;
+            }
+
+            return result;
+        }
+
+        [ComVisible(false)]
+        public static string Concat<T>(IEnumerable<T> values)
+        {
+            if (values == null)
+                throw new ArgumentNullException("values");
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            using (IEnumerator<T> en = values.GetEnumerator())
+            {
+                if (!en.MoveNext())
+                    return string.Empty;
+                
+                // We called MoveNext once, so this will be the first item
+                T currentValue = en.Current;
+
+                // Call ToString before calling MoveNext again, since
+                // we want to stay consistent with the below loop
+                // Everything should be called in the order
+                // MoveNext-Current-ToString, unless further optimizations
+                // can be made, to avoid breaking changes
+                string firstString = currentValue?.ToString();
+
+                // If there's only 1 item, simply call ToString on that
+                if (!en.MoveNext())
+                {
+                    // We have to handle the case of either currentValue
+                    // or its ToString being null
+                    return firstString ?? string.Empty;
+                }
+
+                StringBuilder result = StringBuilderCache.Acquire();
+                
+                result.Append(firstString);
+
+                do
+                {
+                    currentValue = en.Current;
+
+                    if (currentValue != null)
+                    {
+                        result.Append(currentValue.ToString());
+                    }
+                }
+                while (en.MoveNext());
+
+                return StringBuilderCache.GetStringAndRelease(result);
+            }
+        }
+
+
+        [ComVisible(false)]
+        public static string Concat(IEnumerable<string> values)
+        {
+            if (values == null)
+                throw new ArgumentNullException("values");
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            using (IEnumerator<string> en = values.GetEnumerator())
+            {
+                if (!en.MoveNext())
+                    return string.Empty;
+                
+                string firstValue = en.Current;
+
+                if (!en.MoveNext())
+                {
+                    return firstValue ?? string.Empty;
+                }
+
+                StringBuilder result = StringBuilderCache.Acquire();
+                result.Append(firstValue);
+
+                do
+                {
+                    result.Append(en.Current);
+                }
+                while (en.MoveNext());
+
+                return StringBuilderCache.GetStringAndRelease(result);
+            }
+        }
+
+
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public static String Concat(String str0, String str1) {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.Ensures(Contract.Result<String>().Length ==
+                (str0 == null ? 0 : str0.Length) +
+                (str1 == null ? 0 : str1.Length));
+            Contract.EndContractBlock();
+
+            if (IsNullOrEmpty(str0)) {
+                if (IsNullOrEmpty(str1)) {
+                    return String.Empty;
+                }
+                return str1;
+            }
+
+            if (IsNullOrEmpty(str1)) {
+                return str0;
+            }
+
+            int str0Length = str0.Length;
+            
+            String result = FastAllocateString(str0Length + str1.Length);
+            
+            FillStringChecked(result, 0,        str0);
+            FillStringChecked(result, str0Length, str1);
+            
+            return result;
+        }
+
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public static String Concat(String str0, String str1, String str2) {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.Ensures(Contract.Result<String>().Length ==
+                (str0 == null ? 0 : str0.Length) +
+                (str1 == null ? 0 : str1.Length) +
+                (str2 == null ? 0 : str2.Length));
+            Contract.EndContractBlock();
+
+            if (IsNullOrEmpty(str0))
+            {
+                return Concat(str1, str2);
+            }
+
+            if (IsNullOrEmpty(str1))
+            {
+                return Concat(str0, str2);
+            }
+
+            if (IsNullOrEmpty(str2))
+            {
+                return Concat(str0, str1);
+            }
+
+            int totalLength = str0.Length + str1.Length + str2.Length;
+
+            String result = FastAllocateString(totalLength);
+            FillStringChecked(result, 0, str0);
+            FillStringChecked(result, str0.Length, str1);
+            FillStringChecked(result, str0.Length + str1.Length, str2);
+
+            return result;
+        }
+
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public static String Concat(String str0, String str1, String str2, String str3) {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.Ensures(Contract.Result<String>().Length == 
+                (str0 == null ? 0 : str0.Length) +
+                (str1 == null ? 0 : str1.Length) +
+                (str2 == null ? 0 : str2.Length) +
+                (str3 == null ? 0 : str3.Length));
+            Contract.EndContractBlock();
+
+            if (IsNullOrEmpty(str0))
+            {
+                return Concat(str1, str2, str3);
+            }
+
+            if (IsNullOrEmpty(str1))
+            {
+                return Concat(str0, str2, str3);
+            }
+
+            if (IsNullOrEmpty(str2))
+            {
+                return Concat(str0, str1, str3);
+            }
+
+            if (IsNullOrEmpty(str3))
+            {
+                return Concat(str0, str1, str2);
+            }
+
+            int totalLength = str0.Length + str1.Length + str2.Length + str3.Length;
+
+            String result = FastAllocateString(totalLength);
+            FillStringChecked(result, 0, str0);
+            FillStringChecked(result, str0.Length, str1);
+            FillStringChecked(result, str0.Length + str1.Length, str2);
+            FillStringChecked(result, str0.Length + str1.Length + str2.Length, str3);
+
+            return result;
+        }
+
+        [System.Security.SecuritySafeCritical]
+        public static String Concat(params String[] values) {
+            if (values == null)
+                throw new ArgumentNullException("values");
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            if (values.Length <= 1)
+            {
+                return values.Length == 0 ?
+                    string.Empty :
+                    values[0] ?? string.Empty;
+            }
+
+            // It's possible that the input values array could be changed concurrently on another
+            // thread, such that we can't trust that each read of values[i] will be equivalent.
+            // Worst case, we can make a defensive copy of the array and use that, but we first
+            // optimistically try the allocation and copies assuming that the array isn't changing,
+            // which represents the 99.999% case, in particular since string.Concat is used for
+            // string concatenation by the languages, with the input array being a params array.
+
+            // Sum the lengths of all input strings
+            long totalLengthLong = 0;
+            for (int i = 0; i < values.Length; i++)
+            {
+                string value = values[i];
+                if (value != null)
+                {
+                    totalLengthLong += value.Length;
+                }
+            }
+
+            // If it's too long, fail, or if it's empty, return an empty string.
+            if (totalLengthLong > int.MaxValue)
+            {
+                throw new OutOfMemoryException();
+            }
+            int totalLength = (int)totalLengthLong;
+            if (totalLength == 0)
+            {
+                return string.Empty;
+            }
+
+            // Allocate a new string and copy each input string into it
+            string result = FastAllocateString(totalLength);
+            int copiedLength = 0;
+            for (int i = 0; i < values.Length; i++)
+            {
+                string value = values[i];
+                if (!string.IsNullOrEmpty(value))
+                {
+                    int valueLen = value.Length;
+                    if (valueLen > totalLength - copiedLength)
+                    {
+                        copiedLength = -1;
+                        break;
+                    }
+
+                    FillStringChecked(result, copiedLength, value);
+                    copiedLength += valueLen;
+                }
+            }
+
+            // If we copied exactly the right amount, return the new string.  Otherwise,
+            // something changed concurrently to mutate the input array: fall back to
+            // doing the concatenation again, but this time with a defensive copy. This
+            // fall back should be extremely rare.
+            return copiedLength == totalLength ? result : Concat((string[])values.Clone());
+        }
+    
+        public static String Format(String format, Object arg0) {
+            Contract.Ensures(Contract.Result<String>() != null);
+            return FormatHelper(null, format, new ParamsArray(arg0));
+        }
+    
+        public static String Format(String format, Object arg0, Object arg1) {
+            Contract.Ensures(Contract.Result<String>() != null);
+            return FormatHelper(null, format, new ParamsArray(arg0, arg1));
+        }
+    
+        public static String Format(String format, Object arg0, Object arg1, Object arg2) {
+            Contract.Ensures(Contract.Result<String>() != null);
+            return FormatHelper(null, format, new ParamsArray(arg0, arg1, arg2));
+        }
+
+        public static String Format(String format, params Object[] args) {
+            if (args == null)
+            {
+                // 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 FormatHelper.
+                throw new ArgumentNullException((format == null) ? "format" : "args");
+            }
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+            
+            return FormatHelper(null, format, new ParamsArray(args));
+        }
+        
+        public static String Format(IFormatProvider provider, String format, Object arg0) {
+            Contract.Ensures(Contract.Result<String>() != null);
+            return FormatHelper(provider, format, new ParamsArray(arg0));
+        }
+    
+        public static String Format(IFormatProvider provider, String format, Object arg0, Object arg1) {
+            Contract.Ensures(Contract.Result<String>() != null);
+            return FormatHelper(provider, format, new ParamsArray(arg0, arg1));
+        }
+    
+        public static String Format(IFormatProvider provider, String format, Object arg0, Object arg1, Object arg2) {
+            Contract.Ensures(Contract.Result<String>() != null);
+            return FormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
+        }
+
+        public static String Format(IFormatProvider provider, String format, params Object[] args) {
+            if (args == null)
+            {
+                // 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 FormatHelper.
+                throw new ArgumentNullException((format == null) ? "format" : "args");
+            }
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+            
+            return FormatHelper(provider, format, new ParamsArray(args));
+        }
+        
+        private static String FormatHelper(IFormatProvider provider, String format, ParamsArray args) {
+            if (format == null)
+                throw new ArgumentNullException("format");
+            
+            return StringBuilderCache.GetStringAndRelease(
+                StringBuilderCache
+                    .Acquire(format.Length + args.Length * 8)
+                    .AppendFormatHelper(provider, format, args));
+        }
+    
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public String Insert(int startIndex, String value)
+        {
+            if (value == null)
+                throw new ArgumentNullException("value");
+            if (startIndex < 0 || startIndex > this.Length)
+                throw new ArgumentOutOfRangeException("startIndex");
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.Ensures(Contract.Result<String>().Length == this.Length + value.Length);
+            Contract.EndContractBlock();
+            
+            int oldLength = Length;
+            int insertLength = value.Length;
+            
+            if (oldLength == 0)
+                return value;
+            if (insertLength == 0)
+                return this;
+            
+            // In case this computation overflows, newLength will be negative and FastAllocateString throws OutOfMemoryException
+            int newLength = oldLength + insertLength;
+            String result = FastAllocateString(newLength);
+            unsafe
+            {
+                fixed (char* srcThis = &m_firstChar)
+                {
+                    fixed (char* srcInsert = &value.m_firstChar)
+                    {
+                        fixed (char* dst = &result.m_firstChar)
+                        {
+                            wstrcpy(dst, srcThis, startIndex);
+                            wstrcpy(dst + startIndex, srcInsert, insertLength);
+                            wstrcpy(dst + startIndex + insertLength, srcThis + startIndex, oldLength - startIndex);
+                        }
+                    }
+                }
+            }
+            return result;
+        }
+    
+        // Joins an array of strings together as one string with a separator between each original string.
+        //
+        public static String Join(String separator, params String[] value) {
+            if (value==null)
+                throw new ArgumentNullException("value");
+            Contract.EndContractBlock();
+            return Join(separator, value, 0, value.Length);
+        }
+
+        [ComVisible(false)]
+        public static string Join(string separator, params object[] values)
+        {
+            if (values == null)
+                throw new ArgumentNullException("values");
+            Contract.EndContractBlock();
+
+            if (values.Length == 0 || values[0] == null)
+                return string.Empty;
+
+            string firstString = values[0].ToString();
+
+            if (values.Length == 1)
+            {
+                return firstString ?? string.Empty;
+            }
+
+            StringBuilder result = StringBuilderCache.Acquire();
+            result.Append(firstString);
+
+            for (int i = 1; i < values.Length; i++)
+            {
+                result.Append(separator);
+                object value = values[i];
+                if (value != null)
+                {
+                    result.Append(value.ToString());
+                }
+            }
+
+            return StringBuilderCache.GetStringAndRelease(result);
+        }
+
+        [ComVisible(false)]
+        public static String Join<T>(String separator, IEnumerable<T> values)
+        {
+            if (values == null)
+                throw new ArgumentNullException("values");
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            using (IEnumerator<T> en = values.GetEnumerator())
+            {
+                if (!en.MoveNext())
+                    return string.Empty;
+                
+                // We called MoveNext once, so this will be the first item
+                T currentValue = en.Current;
+
+                // Call ToString before calling MoveNext again, since
+                // we want to stay consistent with the below loop
+                // Everything should be called in the order
+                // MoveNext-Current-ToString, unless further optimizations
+                // can be made, to avoid breaking changes
+                string firstString = currentValue?.ToString();
+
+                // If there's only 1 item, simply call ToString on that
+                if (!en.MoveNext())
+                {
+                    // We have to handle the case of either currentValue
+                    // or its ToString being null
+                    return firstString ?? string.Empty;
+                }
+
+                StringBuilder result = StringBuilderCache.Acquire();
+                
+                result.Append(firstString);
+
+                do
+                {
+                    currentValue = en.Current;
+
+                    result.Append(separator);
+                    if (currentValue != null)
+                    {
+                        result.Append(currentValue.ToString());
+                    }
+                }
+                while (en.MoveNext());
+
+                return StringBuilderCache.GetStringAndRelease(result);
+            }
+        }
+
+        [ComVisible(false)]
+        public static String Join(String separator, IEnumerable<String> values) {
+            if (values == null)
+                throw new ArgumentNullException("values");
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            using(IEnumerator<String> en = values.GetEnumerator()) {
+                if (!en.MoveNext())
+                    return String.Empty;
+
+                String firstValue = en.Current;
+
+                if (!en.MoveNext()) {
+                    // Only one value available
+                    return firstValue ?? String.Empty;
+                }
+
+                // Null separator and values are handled by the StringBuilder
+                StringBuilder result = StringBuilderCache.Acquire();
+                result.Append(firstValue);
+
+                do {
+                    result.Append(separator);
+                    result.Append(en.Current);
+                } while (en.MoveNext());
+                return StringBuilderCache.GetStringAndRelease(result);
+            }
+        }
+
+        // Joins an array of strings together as one string with a separator between each original string.
+        //
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public unsafe static String Join(String separator, String[] value, int startIndex, int count) {
+            //Range check the array
+            if (value == null)
+                throw new ArgumentNullException("value");
+
+            if (startIndex < 0)
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
+            if (count < 0)
+                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
+
+            if (startIndex > value.Length - count)
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
+            Contract.EndContractBlock();
+
+            //Treat null as empty string.
+            if (separator == null) {
+                separator = String.Empty;
+            }
+
+            //If count is 0, that skews a whole bunch of the calculations below, so just special case that.
+            if (count == 0) {
+                return String.Empty;
+            }
+
+            if (count == 1) {
+                return value[startIndex] ?? String.Empty;
+            }
+
+            int jointLength = 0;
+            //Figure out the total length of the strings in value
+            int endIndex = startIndex + count - 1;
+            for (int stringToJoinIndex = startIndex; stringToJoinIndex <= endIndex; stringToJoinIndex++) {
+                string currentValue = value[stringToJoinIndex];
+
+                if (currentValue != null) {
+                    jointLength += currentValue.Length;
+                }
+            }
+            
+            //Add enough room for the separator.
+            jointLength += (count - 1) * separator.Length;
+
+            // Note that we may not catch all overflows with this check (since we could have wrapped around the 4gb range any number of times
+            // and landed back in the positive range.) The input array might be modifed from other threads, 
+            // so we have to do an overflow check before each append below anyway. Those overflows will get caught down there.
+            if ((jointLength < 0) || ((jointLength + 1) < 0) ) {
+                throw new OutOfMemoryException();
+            }
+
+            //If this is an empty string, just return.
+            if (jointLength == 0) {
+                return String.Empty;
+            }
+
+            string jointString = FastAllocateString( jointLength );
+            fixed (char * pointerToJointString = &jointString.m_firstChar) {
+                UnSafeCharBuffer charBuffer = new UnSafeCharBuffer( pointerToJointString, jointLength);                
+                
+                // Append the first string first and then append each following string prefixed by the separator.
+                charBuffer.AppendString( value[startIndex] );
+                for (int stringToJoinIndex = startIndex + 1; stringToJoinIndex <= endIndex; stringToJoinIndex++) {
+                    charBuffer.AppendString( separator );
+                    charBuffer.AppendString( value[stringToJoinIndex] );
+                }
+                Contract.Assert(*(pointerToJointString + charBuffer.Length) == '\0', "String must be null-terminated!");
+            }
+
+            return jointString;
+        }
+        
+        //
+        //
+        [Pure]
+        public String PadLeft(int totalWidth) {
+            return PadLeft(totalWidth, ' ');
+        }
+
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public String PadLeft(int totalWidth, char paddingChar) {
+            if (totalWidth < 0)
+                throw new ArgumentOutOfRangeException("totalWidth", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+            int oldLength = Length;
+            int count = totalWidth - oldLength;
+            if (count <= 0)
+                return this;
+            String result = FastAllocateString(totalWidth);
+            unsafe
+            {
+                fixed (char* dst = &result.m_firstChar)
+                {
+                    for (int i = 0; i < count; i++)
+                        dst[i] = paddingChar;
+                    fixed (char* src = &m_firstChar)
+                    {
+                        wstrcpy(dst + count, src, oldLength);
+                    }
+                }
+            }
+            return result;
+        }
+
+        [Pure]
+        public String PadRight(int totalWidth) {
+            return PadRight(totalWidth, ' ');
+        }
+
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public String PadRight(int totalWidth, char paddingChar) {
+            if (totalWidth < 0)
+                throw new ArgumentOutOfRangeException("totalWidth", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+            int oldLength = Length;
+            int count = totalWidth - oldLength;
+            if (count <= 0)
+                return this;
+            String result = FastAllocateString(totalWidth);
+            unsafe
+            {
+                fixed (char* dst = &result.m_firstChar)
+                {
+                    fixed (char* src = &m_firstChar)
+                    {
+                        wstrcpy(dst, src, oldLength);
+                    }
+                    for (int i = 0; i < count; i++)
+                        dst[oldLength + i] = paddingChar;
+                }
+            }
+            return result;
+        }
+
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public String Remove(int startIndex, int count)
+        {
+            if (startIndex < 0)
+                throw new ArgumentOutOfRangeException("startIndex", 
+                    Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
+            if (count < 0)
+                throw new ArgumentOutOfRangeException("count", 
+                    Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
+            if (count > Length - startIndex)
+                throw new ArgumentOutOfRangeException("count", 
+                    Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.Ensures(Contract.Result<String>().Length == this.Length - count);
+            Contract.EndContractBlock();
+            
+            if (count == 0)
+                return this;
+            int newLength = Length - count;
+            if (newLength == 0)
+                return String.Empty;
+            
+            String result = FastAllocateString(newLength);
+            unsafe
+            {
+                fixed (char* src = &m_firstChar)
+                {
+                    fixed (char* dst = &result.m_firstChar)
+                    {
+                        wstrcpy(dst, src, startIndex);
+                        wstrcpy(dst + startIndex, src + startIndex + count, newLength - startIndex);
+                    }
+                }
+            }
+            return result;
+        }
+
+        // a remove that just takes a startindex. 
+        public string Remove( int startIndex ) {
+            if (startIndex < 0) {
+                throw new ArgumentOutOfRangeException("startIndex", 
+                        Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
+            }
+            
+            if (startIndex >= Length) {
+                throw new ArgumentOutOfRangeException("startIndex", 
+                        Environment.GetResourceString("ArgumentOutOfRange_StartIndexLessThanLength"));                
+            }
+            
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            return Substring(0, startIndex);
+        }   
+
+        // Replaces all instances of oldChar with newChar.
+        //
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public String Replace(char oldChar, char newChar)
+        {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.Ensures(Contract.Result<String>().Length == this.Length);
+            Contract.EndContractBlock();
+
+            if (oldChar == newChar)
+                return this;
+
+            unsafe
+            {
+                int remainingLength = Length;
+
+                fixed (char* pChars = &m_firstChar)
+                {
+                    char* pSrc = pChars;
+
+                    while (remainingLength > 0)
+                    {
+                        if (*pSrc == oldChar)
+                        {
+                            break;
+                        }
+
+                        remainingLength--;
+                        pSrc++;
+                    }
+                }
+
+                if (remainingLength == 0)
+                    return this;
+
+                String result = FastAllocateString(Length);
+
+                fixed (char* pChars = &m_firstChar)
+                {
+                    fixed (char* pResult = &result.m_firstChar)
+                    {
+                        int copyLength = Length - remainingLength;
+
+                        //Copy the characters already proven not to match.
+                        if (copyLength > 0)
+                        {
+                            wstrcpy(pResult, pChars, copyLength);
+                        }
+
+                        //Copy the remaining characters, doing the replacement as we go.
+                        char* pSrc = pChars + copyLength;
+                        char* pDst = pResult + copyLength;
+
+                        do
+                        {
+                            char currentChar = *pSrc;
+                            if (currentChar == oldChar)
+                                currentChar = newChar;
+                            *pDst = currentChar;
+
+                            remainingLength--;
+                            pSrc++;
+                            pDst++;
+                        } while (remainingLength > 0);
+                    }
+                }
+
+                return result;
+            }
+        }
+
+        // This method contains the same functionality as StringBuilder Replace. The only difference is that
+        // a new String has to be allocated since Strings are immutable
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        private extern String ReplaceInternal(String oldValue, String newValue);
+
+        public String Replace(String oldValue, String newValue)
+        {
+            if (oldValue == null)
+                throw new ArgumentNullException("oldValue");
+            // Note that if newValue is null, we treat it like String.Empty.
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            return ReplaceInternal(oldValue, newValue);
+        }
+
+        [ComVisible(false)]
+        public String[] Split(char separator) {
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            return SplitInternal(separator, Int32.MaxValue, StringSplitOptions.None);
+        }
+
+        [ComVisible(false)]
+        public String[] Split(char separator, StringSplitOptions options) {
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            return SplitInternal(separator, Int32.MaxValue, options);
+        }
+
+        [ComVisible(false)]
+        public String[] Split(char separator, int count, StringSplitOptions options) {
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            return SplitInternal(separator, count, options);
+        }
+
+        // Creates an array of strings by splitting this string at each
+        // occurrence of a separator.  The separator is searched for, and if found,
+        // the substring preceding the occurrence is stored as the first element in
+        // the array of strings.  We then continue in this manner by searching
+        // the substring that follows the occurrence.  On the other hand, if the separator
+        // is not found, the array of strings will contain this instance as its only element.
+        // If the separator is null
+        // whitespace (i.e., Character.IsWhitespace) is used as the separator.
+        //
+        public String [] Split(params char [] separator) {
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            return SplitInternal(separator, Int32.MaxValue, StringSplitOptions.None);
+        }
+
+        // Creates an array of strings by splitting this string at each
+        // occurrence of a separator.  The separator is searched for, and if found,
+        // the substring preceding the occurrence is stored as the first element in
+        // the array of strings.  We then continue in this manner by searching
+        // the substring that follows the occurrence.  On the other hand, if the separator
+        // is not found, the array of strings will contain this instance as its only element.
+        // If the separator is the empty string (i.e., String.Empty), then
+        // whitespace (i.e., Character.IsWhitespace) is used as the separator.
+        // If there are more than count different strings, the last n-(count-1)
+        // elements are concatenated and added as the last String.
+        //
+        public string[] Split(char[] separator, int count) {
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            return SplitInternal(separator, count, StringSplitOptions.None);
+        }
+
+        [ComVisible(false)]
+        public String[] Split(char[] separator, StringSplitOptions options) {
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            return SplitInternal(separator, Int32.MaxValue, options);
+        }
+
+        [ComVisible(false)]
+        public String[] Split(char[] separator, int count, StringSplitOptions options)
+        {
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            return SplitInternal(separator, count, options);
+        }
+
+        [System.Security.SecuritySafeCritical]
+        private unsafe String[] SplitInternal(char separator, int count, StringSplitOptions options)
+        {
+            char* pSeparators = stackalloc char[1];
+            pSeparators[0] = separator;
+            return SplitInternal(pSeparators, /*separatorsLength*/ 1, count, options);
+        }
+
+        [ComVisible(false)]
+        [System.Security.SecuritySafeCritical]
+        internal String[] SplitInternal(char[] separator, int count, StringSplitOptions options)
+        {
+            unsafe
+            {
+                fixed (char* pSeparators = separator)
+                {
+                    int separatorsLength = separator == null ? 0 : separator.Length;
+                    return SplitInternal(pSeparators, separatorsLength, count, options);
+                }
+            }
+        }
+
+        [System.Security.SecurityCritical]
+        private unsafe String[] SplitInternal(char* separators, int separatorsLength, int count, StringSplitOptions options)
+        {
+            if (count < 0)
+                throw new ArgumentOutOfRangeException("count",
+                    Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
+
+            if (options < StringSplitOptions.None || options > StringSplitOptions.RemoveEmptyEntries)
+                throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", options));
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            Contract.EndContractBlock();
+
+            bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries);
+
+            if ((count == 0) || (omitEmptyEntries && this.Length == 0)) 
+            {           
+#if FEATURE_CORECLR
+                return EmptyArray<String>.Value;
+#else
+                // Keep the old behavior of returning a new empty array
+                // to mitigate any potential compat risk.
+                return new String[0];
+#endif
+            }
+
+            if (count == 1)
+            {
+                return new String[] { this };
+            }
+            
+            int[] sepList = new int[Length];            
+            int numReplaces = MakeSeparatorList(separators, separatorsLength, sepList);
+            
+            // Handle the special case of no replaces.
+            if (0 == numReplaces) {
+                return new String[] { this };
+            }            
+
+            if(omitEmptyEntries) 
+            {
+                return InternalSplitOmitEmptyEntries(sepList, null, 1, numReplaces, count);
+            }
+            else 
+            {
+                return InternalSplitKeepEmptyEntries(sepList, null, 1, numReplaces, count);
+            }            
+        }
+
+        [ComVisible(false)]
+        public String[] Split(String separator) {
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            return SplitInternal(separator ?? String.Empty, null, Int32.MaxValue, StringSplitOptions.None);
+        }
+
+        [ComVisible(false)]
+        public String[] Split(String separator, StringSplitOptions options) {
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            return SplitInternal(separator ?? String.Empty, null, Int32.MaxValue, options);
+        }
+
+        [ComVisible(false)]
+        public String[] Split(String separator, Int32 count, StringSplitOptions options) {
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            return SplitInternal(separator ?? String.Empty, null, count, options);
+        }
+
+        [ComVisible(false)]
+        public String [] Split(String[] separator, StringSplitOptions options) {
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            return SplitInternal(null, separator, Int32.MaxValue, options);
+        }
+
+        [ComVisible(false)]
+        public String[] Split(String[] separator, Int32 count, StringSplitOptions options) {
+            Contract.Ensures(Contract.Result<String[]>() != null);
+            return SplitInternal(null, separator, count, options);
+        }
+
+        private String[] SplitInternal(String separator, String[] separators, Int32 count, StringSplitOptions options)
+        {
+            if (count < 0) {
+                throw new ArgumentOutOfRangeException("count",
+                    Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
+            }
+
+            if (options < StringSplitOptions.None || options > StringSplitOptions.RemoveEmptyEntries) {
+                throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)options));
+            }
+            Contract.EndContractBlock();
+
+            bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries);
+
+            bool singleSeparator = separator != null;
+
+            if (!singleSeparator && (separators == null || separators.Length == 0)) {
+                return SplitInternal((char[]) null, count, options);
+            }
+            
+            if ((count == 0) || (omitEmptyEntries && this.Length ==0)) {
+#if FEATURE_CORECLR
+                return EmptyArray<String>.Value;
+#else
+                // Keep the old behavior of returning a new empty array
+                // to mitigate any potential compat risk.
+                return new String[0];
+#endif
+            }
+
+            if (count == 1) {
+                return new String[] { this };
+            }
+
+            if (singleSeparator && separator.Length == 0) {
+                return new[] { this };
+            }
+
+            int[] sepList = new int[Length];
+            int[] lengthList;
+            int defaultLength;
+            int numReplaces;
+
+            if (singleSeparator) {
+                lengthList = null;
+                defaultLength = separator.Length;
+                numReplaces = MakeSeparatorList(separator, sepList);
+            }
+            else {
+                lengthList = new int[Length];
+                defaultLength = 0;
+                numReplaces = MakeSeparatorList(separators, sepList, lengthList);
+            }
+
+            // Handle the special case of no replaces.
+            if (0 == numReplaces) {
+                return new String[] { this };
+            }
+            
+            if (omitEmptyEntries) {
+                return InternalSplitOmitEmptyEntries(sepList, lengthList, defaultLength, numReplaces, count);
+            }
+            else {
+                return InternalSplitKeepEmptyEntries(sepList, lengthList, defaultLength, numReplaces, count);
+            }
+        }                        
+        
+        // Note a special case in this function:
+        //     If there is no separator in the string, a string array which only contains 
+        //     the original string will be returned regardless of the count. 
+        //
+
+        private String[] InternalSplitKeepEmptyEntries(Int32[] sepList, Int32[] lengthList, Int32 defaultLength, Int32 numReplaces, int count) {
+            Contract.Requires(numReplaces >= 0);
+            Contract.Requires(count >= 2);
+            Contract.Ensures(Contract.Result<String[]>() != null);
+        
+            int currIndex = 0;
+            int arrIndex = 0;
+
+            count--;
+            int numActualReplaces = (numReplaces < count) ? numReplaces : count;
+
+            //Allocate space for the new array.
+            //+1 for the string from the end of the last replace to the end of the String.
+            String[] splitStrings = new String[numActualReplaces+1];
+
+            for (int i = 0; i < numActualReplaces && currIndex < Length; i++) {
+                splitStrings[arrIndex++] = Substring(currIndex, sepList[i]-currIndex );                            
+                currIndex=sepList[i] + ((lengthList == null) ? defaultLength : lengthList[i]);
+            }
+
+            //Handle the last string at the end of the array if there is one.
+            if (currIndex < Length && numActualReplaces >= 0) {
+                splitStrings[arrIndex] = Substring(currIndex);
+            } 
+            else if (arrIndex==numActualReplaces) {
+                //We had a separator character at the end of a string.  Rather than just allowing
+                //a null character, we'll replace the last element in the array with an empty string.
+                splitStrings[arrIndex] = String.Empty;
+
+            }
+
+            return splitStrings;
+        }
+
+        
+        // This function will not keep the Empty String 
+        private String[] InternalSplitOmitEmptyEntries(Int32[] sepList, Int32[] lengthList, Int32 defaultLength, Int32 numReplaces, int count) {
+            Contract.Requires(numReplaces >= 0);
+            Contract.Requires(count >= 2);
+            Contract.Ensures(Contract.Result<String[]>() != null);
+
+            // Allocate array to hold items. This array may not be 
+            // filled completely in this function, we will create a 
+            // new array and copy string references to that new array.
+
+            int maxItems = (numReplaces < count) ? (numReplaces+1): count ;
+            String[] splitStrings = new String[maxItems];
+
+            int currIndex = 0;
+            int arrIndex = 0;
+
+            for(int i=0; i< numReplaces && currIndex < Length; i++) {
+                if( sepList[i]-currIndex > 0) { 
+                    splitStrings[arrIndex++] = Substring(currIndex, sepList[i]-currIndex );                            
+                }
+                currIndex=sepList[i] + ((lengthList == null) ? defaultLength : lengthList[i]);
+                if( arrIndex == count -1 )  {
+                    // If all the remaining entries at the end are empty, skip them
+                    while( i < numReplaces - 1 && currIndex == sepList[++i]) { 
+                        currIndex += ((lengthList == null) ? defaultLength : lengthList[i]);
+                    }
+                    break;
+                }
+            }
+
+            // we must have at least one slot left to fill in the last string.
+            Contract.Assert(arrIndex < maxItems);
+
+            //Handle the last string at the end of the array if there is one.
+            if (currIndex< Length) {                
+                splitStrings[arrIndex++] = Substring(currIndex);
+            }
+
+            String[] stringArray = splitStrings;
+            if( arrIndex!= maxItems) { 
+                stringArray = new String[arrIndex];
+                for( int j = 0; j < arrIndex; j++) {
+                    stringArray[j] = splitStrings[j];
+                }   
+            }
+            return stringArray;
+        }       
+
+        //--------------------------------------------------------------------    
+        // This function returns the number of the places within this instance where 
+        // characters in Separator occur.
+        // Args: separator  -- A string containing all of the split characters.
+        //       sepList    -- an array of ints for split char indicies.
+        //--------------------------------------------------------------------    
+        [System.Security.SecurityCritical]
+        private unsafe int MakeSeparatorList(char* separators, int separatorsLength, int[] sepList) {
+            Contract.Assert(separatorsLength >= 0, "separatorsLength >= 0");
+            int foundCount=0;
+
+            if (separators == null || separatorsLength == 0) {
+                fixed (char* pwzChars = &this.m_firstChar) {
+                    //If they passed null or an empty string, look for whitespace.
+                    for (int i=0; i < Length && foundCount < sepList.Length; i++) {
+                        if (Char.IsWhiteSpace(pwzChars[i])) {
+                            sepList[foundCount++]=i;
+                        }
+                    }
+                }
+            } 
+            else {
+                int sepListCount = sepList.Length;
+                //If they passed in a string of chars, actually look for those chars.
+                fixed (char* pwzChars = &this.m_firstChar) {
+                    for (int i=0; i< Length && foundCount < sepListCount; i++) {                        
+                        char* pSep = separators;
+                        for (int j = 0; j < separatorsLength; j++, pSep++) {
+                           if ( pwzChars[i] == *pSep) {
+                               sepList[foundCount++]=i;
+                               break;
+                           }
+                        }
+                    }
+                }
+            }
+            return foundCount;
+        }        
+        
+        //--------------------------------------------------------------------
+        // This function returns number of the places within baseString where
+        // instances of the separator string occurs.
+        // Args: separator  -- the separator
+        //       sepList    -- an array of ints for split string indicies.
+        //--------------------------------------------------------------------
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        private unsafe int MakeSeparatorList(string separator, int[] sepList) {
+            Contract.Assert(!string.IsNullOrEmpty(separator), "!string.IsNullOrEmpty(separator)");
+
+            int foundCount = 0;
+            int sepListCount = sepList.Length;
+            int currentSepLength = separator.Length;
+
+            fixed (char* pwzChars = &this.m_firstChar) {
+                for (int i = 0; i < Length && foundCount < sepListCount; i++) {
+                    if (pwzChars[i] == separator[0] && currentSepLength <= Length - i) {
+                        if (currentSepLength == 1
+                            || String.CompareOrdinal(this, i, separator, 0, currentSepLength) == 0) {
+                            sepList[foundCount] = i;
+                            foundCount++;
+                            i += currentSepLength - 1;
+                        }
+                    }
+                }
+            }
+            return foundCount;
+        }
+
+        //--------------------------------------------------------------------    
+        // This function returns the number of the places within this instance where 
+        // instances of separator strings occur.
+        // Args: separators -- An array containing all of the split strings.
+        //       sepList    -- an array of ints for split string indicies.
+        //       lengthList -- an array of ints for split string lengths.
+        //--------------------------------------------------------------------    
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        private unsafe int MakeSeparatorList(String[] separators, int[] sepList, int[] lengthList) {
+            Contract.Assert(separators != null && separators.Length > 0, "separators != null && separators.Length > 0");
+            
+            int foundCount = 0;
+            int sepListCount = sepList.Length;
+            int sepCount = separators.Length;
+
+            fixed (char* pwzChars = &this.m_firstChar) {
+                for (int i=0; i< Length && foundCount < sepListCount; i++) {                        
+                    for( int j =0; j < separators.Length; j++) {
+                        String separator = separators[j];
+                        if (String.IsNullOrEmpty(separator)) {
+                            continue;
+                        }
+                        Int32 currentSepLength = separator.Length;
+                        if ( pwzChars[i] == separator[0] && currentSepLength <= Length - i) {
+                            if (currentSepLength == 1 
+                                || String.CompareOrdinal(this, i, separator, 0, currentSepLength) == 0) {
+                                sepList[foundCount] = i;
+                                lengthList[foundCount] = currentSepLength;
+                                foundCount++;
+                                i += currentSepLength - 1;
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+            return foundCount;
+        }
+       
+        // Returns a substring of this string.
+        //
+        public String Substring (int startIndex) {
+            return this.Substring (startIndex, Length-startIndex);
+        }
+    
+        // Returns a substring of this string.
+        //
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public String Substring(int startIndex, int length) {
+                    
+            //Bounds Checking.
+            if (startIndex < 0) {
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
+            }
+
+            if (startIndex > Length) {
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndexLargerThanLength"));
+            }
+
+            if (length < 0) {
+                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
+            }
+
+            if (startIndex > Length - length) {
+                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_IndexLength"));
+            }
+            Contract.EndContractBlock();
+
+            if( length == 0) {
+                return String.Empty;
+            }
+
+            if( startIndex == 0 && length == this.Length) {
+                return this;
+            }
+
+            return InternalSubString(startIndex, length);
+        }
+
+        [System.Security.SecurityCritical]  // auto-generated
+        unsafe string InternalSubString(int startIndex, int length) {
+            Contract.Assert( startIndex >= 0 && startIndex <= this.Length, "StartIndex is out of range!");
+            Contract.Assert( length >= 0 && startIndex <= this.Length - length, "length is out of range!");            
+            
+            String result = FastAllocateString(length);
+
+            fixed(char* dest = &result.m_firstChar)
+                fixed(char* src = &this.m_firstChar) {
+                    wstrcpy(dest, src + startIndex, length);
+                }
+
+            return result;
+        }
+  
+        // Creates a copy of this string in lower case.
+        [Pure]
+        public String ToLower() {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+            return this.ToLower(CultureInfo.CurrentCulture);
+        }
+    
+        // Creates a copy of this string in lower case.  The culture is set by culture.
+        [Pure]
+        public String ToLower(CultureInfo culture) {
+            if (culture == null)
+            {
+                throw new ArgumentNullException("culture");
+            }
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+            return culture.TextInfo.ToLower(this);
+        }
+
+        // Creates a copy of this string in lower case based on invariant culture.
+        [Pure]
+        public String ToLowerInvariant() {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+            return this.ToLower(CultureInfo.InvariantCulture);
+        }
+    
+        // Creates a copy of this string in upper case.
+        [Pure]
+        public String ToUpper() {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+            return this.ToUpper(CultureInfo.CurrentCulture);
+        }
+   
+
+        // Creates a copy of this string in upper case.  The culture is set by culture.
+        [Pure]
+        public String ToUpper(CultureInfo culture) {
+            if (culture == null)
+            {
+                throw new ArgumentNullException("culture");
+            }
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+            return culture.TextInfo.ToUpper(this);
+        }
+
+
+        //Creates a copy of this string in upper case based on invariant culture.
+        [Pure]
+        public String ToUpperInvariant() {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+            return this.ToUpper(CultureInfo.InvariantCulture);
+        }
+    
+        // Removes a set of characters from the end of this string.
+        [Pure]
+        public String Trim(params char[] trimChars) {
+            if (null==trimChars || trimChars.Length == 0) {
+                return TrimHelper(TrimBoth);
+            }
+            return TrimHelper(trimChars,TrimBoth);
+        }
+    
+        // Removes a set of characters from the beginning of this string.
+        public String TrimStart(params char[] trimChars) {
+            if (null==trimChars || trimChars.Length == 0) {
+                return TrimHelper(TrimHead);
+            }
+            return TrimHelper(trimChars,TrimHead);
+        }
+    
+    
+        // Removes a set of characters from the end of this string.
+        public String TrimEnd(params char[] trimChars) {
+            if (null==trimChars || trimChars.Length == 0) {
+                return TrimHelper(TrimTail);
+            }
+            return TrimHelper(trimChars,TrimTail);
+        }
+
+        // Trims the whitespace from both ends of the string.  Whitespace is defined by
+        // Char.IsWhiteSpace.
+        //
+        [Pure]
+        public String Trim() {
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
+
+            return TrimHelper(TrimBoth);        
+        }
+
+       
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        private String TrimHelper(int trimType) {
+            //end will point to the first non-trimmed character on the right
+            //start will point to the first non-trimmed character on the Left
+            int end = this.Length-1;
+            int start=0;
+
+            //Trim specified characters.
+            if (trimType !=TrimTail)  {
+                for (start=0; start < this.Length; start++) {
+                    if (!Char.IsWhiteSpace(this[start])) break;
+                }
+            }
+            
+            if (trimType !=TrimHead) {
+                for (end= Length -1; end >= start;  end--) {
+                    if (!Char.IsWhiteSpace(this[end])) break;
+                }
+            }
+
+            return CreateTrimmedString(start, end);
+        }
+    
+    
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        private String TrimHelper(char[] trimChars, int trimType) {
+            //end will point to the first non-trimmed character on the right
+            //start will point to the first non-trimmed character on the Left
+            int end = this.Length-1;
+            int start=0;
+
+            //Trim specified characters.
+            if (trimType !=TrimTail)  {
+                for (start=0; start < this.Length; start++) {
+                    int i = 0;
+                    char ch = this[start];
+                    for( i = 0; i < trimChars.Length; i++) {
+                        if( trimChars[i] == ch) break;
+                    }
+                    if( i == trimChars.Length) { // the character is not white space
+                        break;  
+                    }
+                }
+            }
+            
+            if (trimType !=TrimHead) {
+                for (end= Length -1; end >= start;  end--) {
+                    int i = 0;    
+                    char ch = this[end];                    
+                    for(i = 0; i < trimChars.Length; i++) {
+                        if( trimChars[i] == ch) break;
+                    }
+                    if( i == trimChars.Length) { // the character is not white space
+                        break;  
+                    }                    
+                }
+            }
+
+            return CreateTrimmedString(start, end);
+        }
+
+
+        [System.Security.SecurityCritical]  // auto-generated
+        private String CreateTrimmedString(int start, int end) {
+            int len = end -start + 1;
+            if (len == this.Length) {
+                // Don't allocate a new string as the trimmed string has not changed.
+                return this;
+            }
+
+            if( len == 0) {
+                return String.Empty;
+            }
+            return InternalSubString(start, len);
+        }
+    }
+}
diff --git a/src/mscorlib/src/System/String.Searching.cs b/src/mscorlib/src/System/String.Searching.cs
new file mode 100644 (file)
index 0000000..b972529
--- /dev/null
@@ -0,0 +1,358 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Contracts;
+using System.Globalization;
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+    public partial class String
+    {
+        [Pure]
+        public bool Contains( string value ) {
+            return ( IndexOf(value, StringComparison.Ordinal) >=0 );
+        }
+    
+        // Returns the index of the first occurrence of a specified character in the current instance.
+        // The search starts at startIndex and runs thorough the next count characters.
+        //
+        [Pure]
+        public int IndexOf(char value) {
+            return IndexOf(value, 0, this.Length);
+        }
+
+        [Pure]
+        public int IndexOf(char value, int startIndex) {
+            return IndexOf(value, startIndex, this.Length - startIndex);
+        }
+
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public unsafe int IndexOf(char value, int startIndex, int count) {
+            if (startIndex < 0 || startIndex > Length)
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+
+            if (count < 0 || count > Length - startIndex)
+                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
+
+            fixed (char* pChars = &m_firstChar)
+            {
+                char* pCh = pChars + startIndex;
+
+                while (count >= 4)
+                {
+                    if (*pCh == value) goto ReturnIndex;
+                    if (*(pCh + 1) == value) goto ReturnIndex1;
+                    if (*(pCh + 2) == value) goto ReturnIndex2;
+                    if (*(pCh + 3) == value) goto ReturnIndex3;
+
+                    count -= 4;
+                    pCh += 4;
+                }
+
+                while (count > 0)
+                {
+                    if (*pCh == value)
+                        goto ReturnIndex;
+
+                    count--;
+                    pCh++;
+                }
+
+                return -1;
+
+                ReturnIndex3: pCh++;
+                ReturnIndex2: pCh++;
+                ReturnIndex1: pCh++;
+                ReturnIndex:
+                return (int)(pCh - pChars);
+            }
+        }
+    
+        // Returns the index of the first occurrence of any specified character in the current instance.
+        // The search starts at startIndex and runs to startIndex + count -1.
+        //
+        [Pure]        
+        public int IndexOfAny(char [] anyOf) {
+            return IndexOfAny(anyOf,0, this.Length);
+        }
+    
+        [Pure]
+        public int IndexOfAny(char [] anyOf, int startIndex) {
+            return IndexOfAny(anyOf, startIndex, this.Length - startIndex);
+        }
+    
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        public extern int IndexOfAny(char [] anyOf, int startIndex, int count);
+    
+        
+        // Determines the position within this string of the first occurrence of the specified
+        // string, according to the specified search criteria.  The search begins at
+        // the first character of this string, it is case-sensitive and the current culture
+        // comparison is used.
+        //
+        [Pure]
+        public int IndexOf(String value) {
+            return IndexOf(value, StringComparison.CurrentCulture);
+        }
+
+        // Determines the position within this string of the first occurrence of the specified
+        // string, according to the specified search criteria.  The search begins at
+        // startIndex, it is case-sensitive and the current culture comparison is used.
+        //
+        [Pure]
+        public int IndexOf(String value, int startIndex) {
+            return IndexOf(value, startIndex, StringComparison.CurrentCulture);
+        }
+
+        // Determines the position within this string of the first occurrence of the specified
+        // string, according to the specified search criteria.  The search begins at
+        // startIndex, ends at endIndex and the current culture comparison is used.
+        //
+        [Pure]
+        public int IndexOf(String value, int startIndex, int count) {
+            if (startIndex < 0 || startIndex > this.Length) {
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+            }
+
+            if (count < 0 || count > this.Length - startIndex) {
+                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
+            }
+            Contract.EndContractBlock();
+            
+            return IndexOf(value, startIndex, count, StringComparison.CurrentCulture);
+        }
+
+        [Pure]
+        public int IndexOf(String value, StringComparison comparisonType) {
+            return IndexOf(value, 0, this.Length, comparisonType);
+        }
+
+        [Pure]
+        public int IndexOf(String value, int startIndex, StringComparison comparisonType) {
+            return IndexOf(value, startIndex, this.Length - startIndex, comparisonType);
+        }
+
+        [Pure]
+        [System.Security.SecuritySafeCritical]
+        public int IndexOf(String value, int startIndex, int count, StringComparison comparisonType) {
+            // Validate inputs
+            if (value == null)
+                throw new ArgumentNullException("value");
+
+            if (startIndex < 0 || startIndex > this.Length)
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+
+            if (count < 0 || startIndex > this.Length - count)
+                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
+            Contract.EndContractBlock();
+
+            switch (comparisonType) {
+                case StringComparison.CurrentCulture:
+                    return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None);
+
+                case StringComparison.CurrentCultureIgnoreCase:
+                    return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
+
+                case StringComparison.InvariantCulture:
+                    return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None);
+
+                case StringComparison.InvariantCultureIgnoreCase:
+                    return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
+
+                case StringComparison.Ordinal:
+                    return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.Ordinal);
+
+                case StringComparison.OrdinalIgnoreCase:
+                    if (value.IsAscii() && this.IsAscii())
+                        return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
+                    else
+                        return TextInfo.IndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
+
+                default:
+                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
+            }  
+        }
+
+        // Returns the index of the last occurrence of a specified character in the current instance.
+        // The search starts at startIndex and runs backwards to startIndex - count + 1.
+        // The character at position startIndex is included in the search.  startIndex is the larger
+        // index within the string.
+        //
+        [Pure]
+        public int LastIndexOf(char value) {
+            return LastIndexOf(value, this.Length-1, this.Length);
+        }
+
+        [Pure]
+        public int LastIndexOf(char value, int startIndex){
+            return LastIndexOf(value,startIndex,startIndex + 1);
+        }
+
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public unsafe int LastIndexOf(char value, int startIndex, int count) {
+            if (Length == 0)
+                return -1;
+
+            if (startIndex < 0 || startIndex >= Length)
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+
+            if (count < 0 || count - 1 > startIndex)
+                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
+
+            fixed (char* pChars = &m_firstChar)
+            {
+                char* pCh = pChars + startIndex;
+
+                //We search [startIndex..EndIndex]
+                while (count >= 4)
+                {
+                    if (*pCh == value) goto ReturnIndex;
+                    if (*(pCh - 1) == value) goto ReturnIndex1;
+                    if (*(pCh - 2) == value) goto ReturnIndex2;
+                    if (*(pCh - 3) == value) goto ReturnIndex3;
+
+                    count -= 4;
+                    pCh -= 4;
+                }
+
+                while (count > 0)
+                {
+                    if (*pCh == value)
+                        goto ReturnIndex;
+
+                    count--;
+                    pCh--;
+                }
+
+                return -1;
+
+                ReturnIndex3: pCh--;
+                ReturnIndex2: pCh--;
+                ReturnIndex1: pCh--;
+                ReturnIndex:
+                return (int)(pCh - pChars);
+            }
+        }
+    
+        // Returns the index of the last occurrence of any specified character in the current instance.
+        // The search starts at startIndex and runs backwards to startIndex - count + 1.
+        // The character at position startIndex is included in the search.  startIndex is the larger
+        // index within the string.
+        //
+        
+        //ForceInline ... Jit can't recognize String.get_Length to determine that this is "fluff"
+        [Pure]
+        public int LastIndexOfAny(char [] anyOf) {
+            return LastIndexOfAny(anyOf,this.Length-1,this.Length);
+        }
+    
+        [Pure]
+        public int LastIndexOfAny(char [] anyOf, int startIndex) {
+            return LastIndexOfAny(anyOf,startIndex,startIndex + 1);
+        }
+
+        [Pure]
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        public extern int LastIndexOfAny(char [] anyOf, int startIndex, int count);
+    
+    
+        // Returns the index of the last occurrence of any character in value in the current instance.
+        // The search starts at startIndex and runs backwards to startIndex - count + 1.
+        // The character at position startIndex is included in the search.  startIndex is the larger
+        // index within the string.
+        //
+        [Pure]
+        public int LastIndexOf(String value) {
+            return LastIndexOf(value, this.Length-1,this.Length, StringComparison.CurrentCulture);
+        }
+
+        [Pure]
+        public int LastIndexOf(String value, int startIndex) {
+            return LastIndexOf(value, startIndex, startIndex + 1, StringComparison.CurrentCulture);
+        }
+
+        [Pure]
+        public int LastIndexOf(String value, int startIndex, int count) {
+            if (count<0) {
+                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
+            }
+            Contract.EndContractBlock();
+
+            return LastIndexOf(value, startIndex, count, StringComparison.CurrentCulture);
+        }
+
+        [Pure]
+        public int LastIndexOf(String value, StringComparison comparisonType) {
+            return LastIndexOf(value, this.Length-1, this.Length, comparisonType);
+        }
+
+        [Pure]
+        public int LastIndexOf(String value, int startIndex, StringComparison comparisonType) {
+            return LastIndexOf(value, startIndex, startIndex + 1, comparisonType);
+        }
+
+        [Pure]
+        [System.Security.SecuritySafeCritical]
+        public int LastIndexOf(String value, int startIndex, int count, StringComparison comparisonType) {
+            if (value == null)
+                throw new ArgumentNullException("value");
+            Contract.EndContractBlock();
+
+            // Special case for 0 length input strings
+            if (this.Length == 0 && (startIndex == -1 || startIndex == 0))
+                return (value.Length == 0) ? 0 : -1;
+
+            // Now after handling empty strings, make sure we're not out of range
+            if (startIndex < 0 || startIndex > this.Length)
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+            
+            // Make sure that we allow startIndex == this.Length
+            if (startIndex == this.Length)
+            {
+                startIndex--;
+                if (count > 0)
+                    count--;
+
+                // If we are looking for nothing, just return 0
+                if (value.Length == 0 && count >= 0 && startIndex - count + 1 >= 0)
+                    return startIndex;
+            }
+
+            // 2nd half of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
+            if (count < 0 || startIndex - count + 1 < 0)
+                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
+
+
+            switch (comparisonType) {
+                case StringComparison.CurrentCulture:
+                    return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.None);
+
+                case StringComparison.CurrentCultureIgnoreCase:
+                    return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
+
+                case StringComparison.InvariantCulture:
+                    return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.None);
+
+                case StringComparison.InvariantCultureIgnoreCase:
+                    return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
+                case StringComparison.Ordinal:
+                    return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.Ordinal);
+                     
+                case StringComparison.OrdinalIgnoreCase:
+                    if (value.IsAscii() && this.IsAscii())
+                        return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
+                    else
+                        return TextInfo.LastIndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
+                default:
+                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
+            }  
+        }
+    }
+}
index 86a367a..d406fd0 100644 (file)
@@ -38,7 +38,7 @@ namespace System {
     
     [ComVisible(true)]
     [Serializable]
-    public sealed class String : IComparable, ICloneable, IConvertible, IEnumerable
+    public sealed partial class String : IComparable, ICloneable, IConvertible, IEnumerable
         , IComparable<String>, IEnumerable<char>, IEquatable<String>
     {
         
@@ -51,10 +51,6 @@ namespace System {
         // For empty strings, this will be '\0' since
         // strings are both null-terminated and length prefixed
         [NonSerialized] private char m_firstChar;
-
-        private const int TrimHead = 0;
-        private const int TrimTail = 1;
-        private const int TrimBoth = 2;
     
         // The Empty constant holds the empty string value. It is initialized by the EE during startup.
         // It is treated as intrinsic by the JIT as so the static constructor would never run.
@@ -65,255 +61,7 @@ namespace System {
         //from native.
         public static readonly String Empty;
 
-        //
-        //Native Static Methods
-        //
-    
-        // Joins an array of strings together as one string with a separator between each original string.
-        //
-        public static String Join(String separator, params String[] value) {
-            if (value==null)
-                throw new ArgumentNullException("value");
-            Contract.EndContractBlock();
-            return Join(separator, value, 0, value.Length);
-        }
-
-        [ComVisible(false)]
-        public static string Join(string separator, params object[] values)
-        {
-            if (values == null)
-                throw new ArgumentNullException("values");
-            Contract.EndContractBlock();
-
-            if (values.Length == 0 || values[0] == null)
-                return string.Empty;
-
-            string firstString = values[0].ToString();
-
-            if (values.Length == 1)
-            {
-                return firstString ?? string.Empty;
-            }
-
-            StringBuilder result = StringBuilderCache.Acquire();
-            result.Append(firstString);
-
-            for (int i = 1; i < values.Length; i++)
-            {
-                result.Append(separator);
-                object value = values[i];
-                if (value != null)
-                {
-                    result.Append(value.ToString());
-                }
-            }
-
-            return StringBuilderCache.GetStringAndRelease(result);
-        }
-
-        [ComVisible(false)]
-        public static String Join<T>(String separator, IEnumerable<T> values)
-        {
-            if (values == null)
-                throw new ArgumentNullException("values");
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-
-            using (IEnumerator<T> en = values.GetEnumerator())
-            {
-                if (!en.MoveNext())
-                    return string.Empty;
-                
-                // We called MoveNext once, so this will be the first item
-                T currentValue = en.Current;
-
-                // Call ToString before calling MoveNext again, since
-                // we want to stay consistent with the below loop
-                // Everything should be called in the order
-                // MoveNext-Current-ToString, unless further optimizations
-                // can be made, to avoid breaking changes
-                string firstString = currentValue?.ToString();
-
-                // If there's only 1 item, simply call ToString on that
-                if (!en.MoveNext())
-                {
-                    // We have to handle the case of either currentValue
-                    // or its ToString being null
-                    return firstString ?? string.Empty;
-                }
-
-                StringBuilder result = StringBuilderCache.Acquire();
-                
-                result.Append(firstString);
-
-                do
-                {
-                    currentValue = en.Current;
-
-                    result.Append(separator);
-                    if (currentValue != null)
-                    {
-                        result.Append(currentValue.ToString());
-                    }
-                }
-                while (en.MoveNext());
-
-                return StringBuilderCache.GetStringAndRelease(result);
-            }
-        }
-
-        [ComVisible(false)]
-        public static String Join(String separator, IEnumerable<String> values) {
-            if (values == null)
-                throw new ArgumentNullException("values");
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-
-            using(IEnumerator<String> en = values.GetEnumerator()) {
-                if (!en.MoveNext())
-                    return String.Empty;
-
-                String firstValue = en.Current;
-
-                if (!en.MoveNext()) {
-                    // Only one value available
-                    return firstValue ?? String.Empty;
-                }
-
-                // Null separator and values are handled by the StringBuilder
-                StringBuilder result = StringBuilderCache.Acquire();
-                result.Append(firstValue);
-
-                do {
-                    result.Append(separator);
-                    result.Append(en.Current);
-                } while (en.MoveNext());
-                return StringBuilderCache.GetStringAndRelease(result);
-            }
-        }
-
         internal char FirstChar { get { return m_firstChar; } }
-
-        // Joins an array of strings together as one string with a separator between each original string.
-        //
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public unsafe static String Join(String separator, String[] value, int startIndex, int count) {
-            //Range check the array
-            if (value == null)
-                throw new ArgumentNullException("value");
-
-            if (startIndex < 0)
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
-            if (count < 0)
-                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
-
-            if (startIndex > value.Length - count)
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCountBuffer"));
-            Contract.EndContractBlock();
-
-            //Treat null as empty string.
-            if (separator == null) {
-                separator = String.Empty;
-            }
-
-            //If count is 0, that skews a whole bunch of the calculations below, so just special case that.
-            if (count == 0) {
-                return String.Empty;
-            }
-
-            if (count == 1) {
-                return value[startIndex] ?? String.Empty;
-            }
-
-            int jointLength = 0;
-            //Figure out the total length of the strings in value
-            int endIndex = startIndex + count - 1;
-            for (int stringToJoinIndex = startIndex; stringToJoinIndex <= endIndex; stringToJoinIndex++) {
-                string currentValue = value[stringToJoinIndex];
-
-                if (currentValue != null) {
-                    jointLength += currentValue.Length;
-                }
-            }
-            
-            //Add enough room for the separator.
-            jointLength += (count - 1) * separator.Length;
-
-            // Note that we may not catch all overflows with this check (since we could have wrapped around the 4gb range any number of times
-            // and landed back in the positive range.) The input array might be modifed from other threads, 
-            // so we have to do an overflow check before each append below anyway. Those overflows will get caught down there.
-            if ((jointLength < 0) || ((jointLength + 1) < 0) ) {
-                throw new OutOfMemoryException();
-            }
-
-            //If this is an empty string, just return.
-            if (jointLength == 0) {
-                return String.Empty;
-            }
-
-            string jointString = FastAllocateString( jointLength );
-            fixed (char * pointerToJointString = &jointString.m_firstChar) {
-                UnSafeCharBuffer charBuffer = new UnSafeCharBuffer( pointerToJointString, jointLength);                
-                
-                // Append the first string first and then append each following string prefixed by the separator.
-                charBuffer.AppendString( value[startIndex] );
-                for (int stringToJoinIndex = startIndex + 1; stringToJoinIndex <= endIndex; stringToJoinIndex++) {
-                    charBuffer.AppendString( separator );
-                    charBuffer.AppendString( value[stringToJoinIndex] );
-                }
-                Contract.Assert(*(pointerToJointString + charBuffer.Length) == '\0', "String must be null-terminated!");
-            }
-
-            return jointString;
-        }
-
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        private unsafe static int CompareOrdinalIgnoreCaseHelper(String strA, String strB)
-        {
-            Contract.Requires(strA != null);
-            Contract.Requires(strB != null);
-            Contract.EndContractBlock();
-            int length = Math.Min(strA.Length, strB.Length);
-    
-            fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
-            {
-                char* a = ap;
-                char* b = bp;
-
-                while (length != 0) 
-                {
-                    int charA = *a;
-                    int charB = *b;
-
-                    Contract.Assert((charA | charB) <= 0x7F, "strings have to be ASCII");
-
-                    // uppercase both chars - notice that we need just one compare per char
-                    if ((uint)(charA - 'a') <= (uint)('z' - 'a')) charA -= 0x20;
-                    if ((uint)(charB - 'a') <= (uint)('z' - 'a')) charB -= 0x20;
-
-                    //Return the (case-insensitive) difference between them.
-                    if (charA != charB)
-                        return charA - charB;
-
-                    // Next char
-                    a++; b++;
-                    length--;
-                }
-
-                return strA.Length - strB.Length;
-            }
-        }
-
-        // native call to COMString::CompareOrdinalEx
-        [System.Security.SecurityCritical]  // auto-generated
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal static extern int CompareOrdinalHelper(String strA, int indexA, int countA, String strB, int indexB, int countB);
-
-        //This will not work in case-insensitive mode for any character greater than 0x80.  
-        //We'll throw an ArgumentException.
-        [System.Security.SecurityCritical]  // auto-generated
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        unsafe internal static extern int nativeCompareOrdinalIgnoreCaseWC(String strA, sbyte *strBBytes);
         //
         // This is a helper method for the security team.  They need to uppercase some strings (guaranteed to be less 
         // than 0x80) before security is fully initialized.  Without security initialized, we can't grab resources (the nlp's)
@@ -347,3453 +95,633 @@ namespace System {
             }
             return strOut;
         }
-
-        //
-        //
-        // NATIVE INSTANCE METHODS
-        //
-        //
     
+        // Gets the character at a specified position.
         //
-        // Search/Query methods
-        //
+        // Spec#: Apply the precondition here using a contract assembly.  Potential perf issue.
+        [System.Runtime.CompilerServices.IndexerName("Chars")]
+        public extern char this[int index] {
+            [MethodImpl(MethodImplOptions.InternalCall)]
+            [System.Security.SecuritySafeCritical] // public member
+            get;
+        }
 
+        // Converts a substring of this string to an array of characters.  Copies the
+        // characters of this string beginning at position sourceIndex and ending at
+        // sourceIndex + count - 1 to the character array buffer, beginning
+        // at destinationIndex.
+        //
         [System.Security.SecuritySafeCritical]  // auto-generated
-        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
-        private unsafe static bool EqualsHelper(String strA, String strB)
+        unsafe public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
         {
-            Contract.Requires(strA != null);
-            Contract.Requires(strB != null);
-            Contract.Requires(strA.Length == strB.Length);
-
-            int length = strA.Length;
+            if (destination == null)
+                throw new ArgumentNullException("destination");
+            if (count < 0)
+                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
+            if (sourceIndex < 0)
+                throw new ArgumentOutOfRangeException("sourceIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+            if (count > Length - sourceIndex)
+                throw new ArgumentOutOfRangeException("sourceIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
+            if (destinationIndex > destination.Length - count || destinationIndex < 0)
+                throw new ArgumentOutOfRangeException("destinationIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
+            Contract.EndContractBlock();
 
-            fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
+            // Note: fixed does not like empty arrays
+            if (count > 0)
             {
-                char* a = ap;
-                char* b = bp;
-
-#if BIT64
-                // Single int read aligns pointers for the following long reads
-                // PERF: No length check needed as there is always an int32 worth of string allocated
-                //       This read can also include the null terminator which both strings will have
-                if (*(int*)a != *(int*)b) return false;
-                length -= 2; a += 2; b += 2;
-
-                // for AMD64 bit platform we unroll by 12 and
-                // check 3 qword at a time. This is less code
-                // than the 32 bit case and is a shorter path length.
-
-                while (length >= 12)
-                {
-                    if (*(long*)a != *(long*)b) goto ReturnFalse;
-                    if (*(long*)(a + 4) != *(long*)(b + 4)) goto ReturnFalse;
-                    if (*(long*)(a + 8) != *(long*)(b + 8)) goto ReturnFalse;
-                    length -= 12; a += 12; b += 12;
-                }
-#else
-                while (length >= 10)
-                {
-                    if (*(int*)a != *(int*)b) goto ReturnFalse;
-                    if (*(int*)(a + 2) != *(int*)(b + 2)) goto ReturnFalse;
-                    if (*(int*)(a + 4) != *(int*)(b + 4)) goto ReturnFalse;
-                    if (*(int*)(a + 6) != *(int*)(b + 6)) goto ReturnFalse;
-                    if (*(int*)(a + 8) != *(int*)(b + 8)) goto ReturnFalse;
-                    length -= 10; a += 10; b += 10;
-                }
-#endif
-
-                // This depends on the fact that the String objects are
-                // always zero terminated and that the terminating zero is not included
-                // in the length. For odd string sizes, the last compare will include
-                // the zero terminator.
-                while (length > 0) 
-                {
-                    if (*(int*)a != *(int*)b) goto ReturnFalse;
-                    length -= 2; a += 2; b += 2;
-                }
-
-                return true;
-
-                ReturnFalse:
-                return false;
+                fixed (char* src = &this.m_firstChar)
+                    fixed (char* dest = destination)
+                        wstrcpy(dest + destinationIndex, src + sourceIndex, count);
             }
         }
-
+        
+        // Returns the entire string as an array of characters.
         [System.Security.SecuritySafeCritical]  // auto-generated
-        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
-        private unsafe static bool StartsWithOrdinalHelper(String str, String startsWith)
-        {
-            Contract.Requires(str != null);
-            Contract.Requires(startsWith != null);
-            Contract.Requires(str.Length >= startsWith.Length);
-
-            int length = startsWith.Length;
-
-            fixed (char* ap = &str.m_firstChar) fixed (char* bp = &startsWith.m_firstChar)
+        unsafe public char[] ToCharArray() {
+            int length = Length;
+            if (length > 0)
             {
-                char* a = ap;
-                char* b = bp;
-
-#if BIT64
-                // Single int read aligns pointers for the following long reads
-                // No length check needed as this method is called when length >= 2
-                Contract.Assert(length >= 2);
-                if (*(int*)a != *(int*)b) goto ReturnFalse;
-                length -= 2; a += 2; b += 2;
-
-                while (length >= 12)
+                char[] chars = new char[length];
+                fixed (char* src = &this.m_firstChar) fixed (char* dest = chars)
                 {
-                    if (*(long*)a != *(long*)b) goto ReturnFalse;
-                    if (*(long*)(a + 4) != *(long*)(b + 4)) goto ReturnFalse;
-                    if (*(long*)(a + 8) != *(long*)(b + 8)) goto ReturnFalse;
-                    length -= 12; a += 12; b += 12;
+                    wstrcpy(dest, src, length);
                 }
+                return chars;
+            }
+            
+#if FEATURE_CORECLR
+            return Array.Empty<char>();
 #else
-                while (length >= 10)
-                {
-                    if (*(int*)a != *(int*)b) goto ReturnFalse;
-                    if (*(int*)(a+2) != *(int*)(b+2)) goto ReturnFalse;
-                    if (*(int*)(a+4) != *(int*)(b+4)) goto ReturnFalse;
-                    if (*(int*)(a+6) != *(int*)(b+6)) goto ReturnFalse;
-                    if (*(int*)(a+8) != *(int*)(b+8)) goto ReturnFalse;
-                    length -= 10; a += 10; b += 10;
-                }
+            return new char[0];
 #endif
-
-                while (length >= 2)
-                {
-                    if (*(int*)a != *(int*)b) goto ReturnFalse;
-                    length -= 2; a += 2; b += 2;
-                }
-
-                // PERF: This depends on the fact that the String objects are always zero terminated 
-                // and that the terminating zero is not included in the length. For even string sizes
-                // this compare can include the zero terminator. Bitwise OR avoids a branch.
-                return length == 0 | *a == *b;
-
-                ReturnFalse:
-                return false;
-            }
         }
-
+    
+        // Returns a substring of this string as an array of characters.
+        //
         [System.Security.SecuritySafeCritical]  // auto-generated
-        private unsafe static int CompareOrdinalHelper(String strA, String strB)
+        unsafe public char[] ToCharArray(int startIndex, int length)
         {
-            Contract.Requires(strA != null);
-            Contract.Requires(strB != null);
-
-            // NOTE: This may be subject to change if eliminating the check
-            // in the callers makes them small enough to be inlined by the JIT
-            Contract.Assert(strA.m_firstChar == strB.m_firstChar,
-                "For performance reasons, callers of this method should " +
-                "check/short-circuit beforehand if the first char is the same.");
-
-            int length = Math.Min(strA.Length, strB.Length);
+            // Range check everything.
+            if (startIndex < 0 || startIndex > Length || startIndex > Length - length)
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+            if (length < 0)
+                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_Index"));
+            Contract.EndContractBlock();
 
-            fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
+            if (length > 0)
             {
-                char* a = ap;
-                char* b = bp;
-
-                // Check if the second chars are different here
-                // The reason we check if m_firstChar is different is because
-                // it's the most common case and allows us to avoid a method call
-                // to here.
-                // The reason we check if the second char is different is because
-                // if the first two chars the same we can increment by 4 bytes,
-                // leaving us word-aligned on both 32-bit (12 bytes into the string)
-                // and 64-bit (16 bytes) platforms.
-        
-                // For empty strings, the second char will be null due to padding.
-                // The start of the string (not including sync block pointer)
-                // is the method table pointer + string length, which takes up
-                // 8 bytes on 32-bit, 12 on x64. For empty strings the null
-                // terminator immediately follows, leaving us with an object
-                // 10/14 bytes in size. Since everything needs to be a multiple
-                // of 4/8, this will get padded and zeroed out.
-                
-                // For one-char strings the second char will be the null terminator.
-
-                // NOTE: If in the future there is a way to read the second char
-                // without pinning the string (e.g. System.Runtime.CompilerServices.Unsafe
-                // is exposed to mscorlib, or a future version of C# allows inline IL),
-                // then do that and short-circuit before the fixed.
-
-                if (*(a + 1) != *(b + 1)) goto DiffOffset1;
-                
-                // Since we know that the first two chars are the same,
-                // we can increment by 2 here and skip 4 bytes.
-                // This leaves us 8-byte aligned, which results
-                // on better perf for 64-bit platforms.
-                length -= 2; a += 2; b += 2;
-
-                // unroll the loop
-#if BIT64
-                while (length >= 12)
-                {
-                    if (*(long*)a != *(long*)b) goto DiffOffset0;
-                    if (*(long*)(a + 4) != *(long*)(b + 4)) goto DiffOffset4;
-                    if (*(long*)(a + 8) != *(long*)(b + 8)) goto DiffOffset8;
-                    length -= 12; a += 12; b += 12;
-                }
-#else // BIT64
-                while (length >= 10)
-                {
-                    if (*(int*)a != *(int*)b) goto DiffOffset0;
-                    if (*(int*)(a + 2) != *(int*)(b + 2)) goto DiffOffset2;
-                    if (*(int*)(a + 4) != *(int*)(b + 4)) goto DiffOffset4;
-                    if (*(int*)(a + 6) != *(int*)(b + 6)) goto DiffOffset6;
-                    if (*(int*)(a + 8) != *(int*)(b + 8)) goto DiffOffset8;
-                    length -= 10; a += 10; b += 10; 
-                }
-#endif // BIT64
-
-                // Fallback loop:
-                // go back to slower code path and do comparison on 4 bytes at a time.
-                // This depends on the fact that the String objects are
-                // always zero terminated and that the terminating zero is not included
-                // in the length. For odd string sizes, the last compare will include
-                // the zero terminator.
-                while (length > 0)
-                {
-                    if (*(int*)a != *(int*)b) goto DiffNextInt;
-                    length -= 2;
-                    a += 2; 
-                    b += 2; 
-                }
-
-                // At this point, we have compared all the characters in at least one string.
-                // The longer string will be larger.
-                return strA.Length - strB.Length;
-                
-#if BIT64
-                DiffOffset8: a += 4; b += 4;
-                DiffOffset4: a += 4; b += 4;
-#else // BIT64
-                // Use jumps instead of falling through, since
-                // otherwise going to DiffOffset8 will involve
-                // 8 add instructions before getting to DiffNextInt
-                DiffOffset8: a += 8; b += 8; goto DiffOffset0;
-                DiffOffset6: a += 6; b += 6; goto DiffOffset0;
-                DiffOffset4: a += 2; b += 2;
-                DiffOffset2: a += 2; b += 2;
-#endif // BIT64
-                
-                DiffOffset0:
-                // If we reached here, we already see a difference in the unrolled loop above
-#if BIT64
-                if (*(int*)a == *(int*)b)
+                char[] chars = new char[length];
+                fixed (char* src = &this.m_firstChar) fixed (char* dest = chars)
                 {
-                    a += 2; b += 2;
+                    wstrcpy(dest, src + startIndex, length);
                 }
-#endif // BIT64
-
-                DiffNextInt:
-                if (*a != *b) return *a - *b;
-
-                DiffOffset1:
-                Contract.Assert(*(a + 1) != *(b + 1), "This char must be different if we reach here!");
-                return *(a + 1) - *(b + 1);
+                return chars;
             }
+            
+#if FEATURE_CORECLR
+            return Array.Empty<char>();
+#else
+            return new char[0];
+#endif
         }
 
-        // Determines whether two strings match.
-        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
-        public override bool Equals(Object obj)
-        {
-            if (this == null)                        // this is necessary to guard against reverse-pinvokes and
-                throw new NullReferenceException();  // other callers who do not use the callvirt instruction
-
-            if (object.ReferenceEquals(this, obj))
-                return true;
-
-            string str = obj as string;
-            if (str == null)
-                return false;
-
-            if (this.Length != str.Length)
-                return false;
-
-            return EqualsHelper(this, str);
-        }
-
-        // Determines whether two strings match.
         [Pure]
-        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
-        public bool Equals(String value)
-        {
-            if (this == null)                        // this is necessary to guard against reverse-pinvokes and
-                throw new NullReferenceException();  // other callers who do not use the callvirt instruction
-
-            if (object.ReferenceEquals(this, value))
-                return true;
-
-            // NOTE: No need to worry about casting to object here.
-            // If either side of an == comparison between strings
-            // is null, Roslyn generates a simple ceq instruction
-            // instead of calling string.op_Equality.
-            if (value == null)
-                return false;
-            
-            if (this.Length != value.Length)
-                return false;
-
-            return EqualsHelper(this, value);
+        public static bool IsNullOrEmpty(String value) {
+            return (value == null || value.Length == 0);
         }
 
         [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public bool Equals(String value, StringComparison comparisonType) {
-            if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase)
-                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
-            Contract.EndContractBlock();
-
-            if ((Object)this == (Object)value) {
-                return true;
-            }
+        public static bool IsNullOrWhiteSpace(String value) {
+            if (value == null) return true;
 
-            if ((Object)value == null) {
-                return false;
+            for(int i = 0; i < value.Length; i++) {
+                if(!Char.IsWhiteSpace(value[i])) return false;
             }
 
-            switch (comparisonType) {
-                case StringComparison.CurrentCulture:
-                    return (CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0);
+            return true;
+        }
 
-                case StringComparison.CurrentCultureIgnoreCase:
-                    return (CultureInfo.CurrentCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0);
-
-                case StringComparison.InvariantCulture:
-                    return (CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.None) == 0);
-
-                case StringComparison.InvariantCultureIgnoreCase:
-                    return (CultureInfo.InvariantCulture.CompareInfo.Compare(this, value, CompareOptions.IgnoreCase) == 0);
-
-                case StringComparison.Ordinal:
-                    if (this.Length != value.Length)
-                        return false;
-                    return EqualsHelper(this, value);
-
-                case StringComparison.OrdinalIgnoreCase:
-                    if (this.Length != value.Length)
-                        return false;
-
-                    // If both strings are ASCII strings, we can take the fast path.
-                    if (this.IsAscii() && value.IsAscii()) {
-                        return (CompareOrdinalIgnoreCaseHelper(this, value) == 0);
-                    }
-
-#if FEATURE_COREFX_GLOBALIZATION
-                    return (CompareInfo.CompareOrdinalIgnoreCase(this, 0, this.Length, value, 0, value.Length) == 0);
-#else
-                    // Take the slow path.
-                    return (TextInfo.CompareOrdinalIgnoreCase(this, value) == 0);
-#endif
-
-                default:
-                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
-            }
-        }
-
-
-        // Determines whether two Strings match.
-        [Pure]
-        public static bool Equals(String a, String b) {
-            if ((Object)a==(Object)b) {
-                return true;
-            }
-
-            if ((Object)a == null || (Object)b == null || a.Length != b.Length) {
-                return false;
-            }
-
-            return EqualsHelper(a, b);
-        }
-
-        [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public static bool Equals(String a, String b, StringComparison comparisonType) {
-            if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase)
-                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
-            Contract.EndContractBlock();
-
-            if ((Object)a==(Object)b) {
-                return true;
-            }
-    
-            if ((Object)a==null || (Object)b==null) {
-                return false;
-            }
-
-            switch (comparisonType) {
-                case StringComparison.CurrentCulture:
-                    return (CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0);
-
-                case StringComparison.CurrentCultureIgnoreCase:
-                    return (CultureInfo.CurrentCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0);
-
-                case StringComparison.InvariantCulture:
-                    return (CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.None) == 0);
-
-                case StringComparison.InvariantCultureIgnoreCase:
-                    return (CultureInfo.InvariantCulture.CompareInfo.Compare(a, b, CompareOptions.IgnoreCase) == 0);
-
-                case StringComparison.Ordinal:
-                    if (a.Length != b.Length)
-                        return false;
-
-                    return EqualsHelper(a, b);
-
-                case StringComparison.OrdinalIgnoreCase:
-                    if (a.Length != b.Length)
-                        return false;
-                    else {
-                        // If both strings are ASCII strings, we can take the fast path.
-                        if (a.IsAscii() && b.IsAscii()) {
-                            return (CompareOrdinalIgnoreCaseHelper(a, b) == 0);
-                        }
-                        // Take the slow path.
-
-#if FEATURE_COREFX_GLOBALIZATION
-                        return (CompareInfo.CompareOrdinalIgnoreCase(a, 0, a.Length, b, 0, b.Length) == 0);
-#else
-                        return (TextInfo.CompareOrdinalIgnoreCase(a, b) == 0);
-#endif
-                    }
-
-                default:
-                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
-            }
-        }
-
-        public static bool operator == (String a, String b) {
-           return String.Equals(a, b);
-        }
-
-        public static bool operator != (String a, String b) {
-           return !String.Equals(a, b);
-        }
-    
-        // Gets the character at a specified position.
-        //
-        // Spec#: Apply the precondition here using a contract assembly.  Potential perf issue.
-        [System.Runtime.CompilerServices.IndexerName("Chars")]
-        public extern char this[int index] {
-            [MethodImpl(MethodImplOptions.InternalCall)]
-            [System.Security.SecuritySafeCritical] // public member
-            get;
-        }
-
-        // Converts a substring of this string to an array of characters.  Copies the
-        // characters of this string beginning at position sourceIndex and ending at
-        // sourceIndex + count - 1 to the character array buffer, beginning
-        // at destinationIndex.
-        //
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        unsafe public void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
-        {
-            if (destination == null)
-                throw new ArgumentNullException("destination");
-            if (count < 0)
-                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
-            if (sourceIndex < 0)
-                throw new ArgumentOutOfRangeException("sourceIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
-            if (count > Length - sourceIndex)
-                throw new ArgumentOutOfRangeException("sourceIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
-            if (destinationIndex > destination.Length - count || destinationIndex < 0)
-                throw new ArgumentOutOfRangeException("destinationIndex", Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
-            Contract.EndContractBlock();
-
-            // Note: fixed does not like empty arrays
-            if (count > 0)
-            {
-                fixed (char* src = &this.m_firstChar)
-                    fixed (char* dest = destination)
-                        wstrcpy(dest + destinationIndex, src + sourceIndex, count);
-            }
-        }
-        
-        // Returns the entire string as an array of characters.
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        unsafe public char[] ToCharArray() {
-            int length = Length;
-            if (length > 0)
-            {
-                char[] chars = new char[length];
-                fixed (char* src = &this.m_firstChar) fixed (char* dest = chars)
-                {
-                    wstrcpy(dest, src, length);
-                }
-                return chars;
-            }
-            
-#if FEATURE_CORECLR
-            return Array.Empty<char>();
-#else
-            return new char[0];
-#endif
-        }
-    
-        // Returns a substring of this string as an array of characters.
-        //
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        unsafe public char[] ToCharArray(int startIndex, int length)
-        {
-            // Range check everything.
-            if (startIndex < 0 || startIndex > Length || startIndex > Length - length)
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
-            if (length < 0)
-                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_Index"));
-            Contract.EndContractBlock();
-
-            if (length > 0)
-            {
-                char[] chars = new char[length];
-                fixed (char* src = &this.m_firstChar) fixed (char* dest = chars)
-                {
-                    wstrcpy(dest, src + startIndex, length);
-                }
-                return chars;
-            }
-            
-#if FEATURE_CORECLR
-            return Array.Empty<char>();
-#else
-            return new char[0];
-#endif
-        }
-
-        [Pure]
-        public static bool IsNullOrEmpty(String value) {
-            return (value == null || value.Length == 0);
-        }
-
-        [Pure]
-        public static bool IsNullOrWhiteSpace(String value) {
-            if (value == null) return true;
-
-            for(int i = 0; i < value.Length; i++) {
-                if(!Char.IsWhiteSpace(value[i])) return false;
-            }
-
-            return true;
-        }
-
-#if FEATURE_RANDOMIZED_STRING_HASHING
-        // Do not remove!
-        // This method is called by reflection in System.Xml
-        [System.Security.SecurityCritical]
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal static extern int InternalMarvin32HashString(string s, int strLen, long additionalEntropy);
-
-        [System.Security.SecuritySafeCritical]
-        internal static bool UseRandomizedHashing() {
-            return InternalUseRandomizedHashing();
-        }
-
-        [System.Security.SecurityCritical]
-        [System.Security.SuppressUnmanagedCodeSecurity]
-        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
-        private static extern bool InternalUseRandomizedHashing();
-#endif
-
-        // Gets a hash code for this string.  If strings A and B are such that A.Equals(B), then
-        // they will return the same hash code.
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
-        public override int GetHashCode()
-        {
-#if FEATURE_RANDOMIZED_STRING_HASHING
-            if (HashHelpers.s_UseRandomizedStringHashing)
-            {
-                return InternalMarvin32HashString(this, this.Length, 0);
-            }
-#endif // FEATURE_RANDOMIZED_STRING_HASHING
-
-            return GetLegacyNonRandomizedHashCode();
-        }
-
-        // Use this if and only if you need the hashcode to not change across app domains (e.g. you have an app domain agile
-        // hash table).
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
-        internal int GetLegacyNonRandomizedHashCode() {
-            unsafe {
-                fixed (char* src = &m_firstChar) {
-                    Contract.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'");
-                    Contract.Assert( ((int)src)%4 == 0, "Managed string should start at 4 bytes boundary");
-#if BIT64
-                    int hash1 = 5381;
-#else // !BIT64 (32)
-                    int hash1 = (5381<<16) + 5381;
-#endif
-                    int hash2 = hash1;
-
-#if BIT64
-                    int     c;
-                    char *s = src;
-                    while ((c = s[0]) != 0) {
-                        hash1 = ((hash1 << 5) + hash1) ^ c;
-                        c = s[1];
-                        if (c == 0)
-                            break;
-                        hash2 = ((hash2 << 5) + hash2) ^ c;
-                        s += 2;
-                    }
-#else // !BIT64 (32)
-                    // 32 bit machines.
-                    int* pint = (int *)src;
-                    int len = this.Length;
-                    while (len > 2)
-                    {
-                        hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
-                        hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ pint[1];
-                        pint += 2;
-                        len  -= 4;
-                    }
-
-                    if (len > 0)
-                    {
-                        hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ pint[0];
-                    }
-#endif
-#if DEBUG
-                    // We want to ensure we can change our hash function daily.
-                    // This is perfectly fine as long as you don't persist the
-                    // value from GetHashCode to disk or count on String A 
-                    // hashing before string B.  Those are bugs in your code.
-                    hash1 ^= ThisAssembly.DailyBuildNumber;
-#endif
-                    return hash1 + (hash2 * 1566083941);
-                }
-            }
-        }
-
-        // Gets the length of this string
-        //
-        /// This is a EE implemented function so that the JIT can recognise is specially
-        /// and eliminate checks on character fetchs in a loop like:
-        ///        for(int i = 0; i < str.Length; i++) str[i]
-        /// The actually code generated for this will be one instruction and will be inlined.
-        //
-        // Spec#: Add postcondition in a contract assembly.  Potential perf problem.
-        public extern int Length {
-            [System.Security.SecuritySafeCritical]  // auto-generated
-            [MethodImplAttribute(MethodImplOptions.InternalCall)]
-            get;
-        }
-
-        [ComVisible(false)]
-        public String[] Split(char separator) {
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            return SplitInternal(separator, Int32.MaxValue, StringSplitOptions.None);
-        }
-
-        [ComVisible(false)]
-        public String[] Split(char separator, StringSplitOptions options) {
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            return SplitInternal(separator, Int32.MaxValue, options);
-        }
-
-        [ComVisible(false)]
-        public String[] Split(char separator, int count, StringSplitOptions options) {
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            return SplitInternal(separator, count, options);
-        }
-
-        // Creates an array of strings by splitting this string at each
-        // occurrence of a separator.  The separator is searched for, and if found,
-        // the substring preceding the occurrence is stored as the first element in
-        // the array of strings.  We then continue in this manner by searching
-        // the substring that follows the occurrence.  On the other hand, if the separator
-        // is not found, the array of strings will contain this instance as its only element.
-        // If the separator is null
-        // whitespace (i.e., Character.IsWhitespace) is used as the separator.
-        //
-        public String [] Split(params char [] separator) {
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            return SplitInternal(separator, Int32.MaxValue, StringSplitOptions.None);
-        }
-
-        // Creates an array of strings by splitting this string at each
-        // occurrence of a separator.  The separator is searched for, and if found,
-        // the substring preceding the occurrence is stored as the first element in
-        // the array of strings.  We then continue in this manner by searching
-        // the substring that follows the occurrence.  On the other hand, if the separator
-        // is not found, the array of strings will contain this instance as its only element.
-        // If the separator is the empty string (i.e., String.Empty), then
-        // whitespace (i.e., Character.IsWhitespace) is used as the separator.
-        // If there are more than count different strings, the last n-(count-1)
-        // elements are concatenated and added as the last String.
-        //
-        public string[] Split(char[] separator, int count) {
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            return SplitInternal(separator, count, StringSplitOptions.None);
-        }
-
-        [ComVisible(false)]
-        public String[] Split(char[] separator, StringSplitOptions options) {
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            return SplitInternal(separator, Int32.MaxValue, options);
-        }
-
-        [ComVisible(false)]
-        public String[] Split(char[] separator, int count, StringSplitOptions options)
-        {
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            return SplitInternal(separator, count, options);
-        }
-
-        [System.Security.SecuritySafeCritical]
-        private unsafe String[] SplitInternal(char separator, int count, StringSplitOptions options)
-        {
-            char* pSeparators = stackalloc char[1];
-            pSeparators[0] = separator;
-            return SplitInternal(pSeparators, /*separatorsLength*/ 1, count, options);
-        }
-
-        [ComVisible(false)]
-        [System.Security.SecuritySafeCritical]
-        internal String[] SplitInternal(char[] separator, int count, StringSplitOptions options)
-        {
-            unsafe
-            {
-                fixed (char* pSeparators = separator)
-                {
-                    int separatorsLength = separator == null ? 0 : separator.Length;
-                    return SplitInternal(pSeparators, separatorsLength, count, options);
-                }
-            }
-        }
-
-        [System.Security.SecurityCritical]
-        private unsafe String[] SplitInternal(char* separators, int separatorsLength, int count, StringSplitOptions options)
-        {
-            if (count < 0)
-                throw new ArgumentOutOfRangeException("count",
-                    Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
-
-            if (options < StringSplitOptions.None || options > StringSplitOptions.RemoveEmptyEntries)
-                throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", options));
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            Contract.EndContractBlock();
-
-            bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries);
-
-            if ((count == 0) || (omitEmptyEntries && this.Length == 0)) 
-            {           
-#if FEATURE_CORECLR
-                return EmptyArray<String>.Value;
-#else
-                // Keep the old behavior of returning a new empty array
-                // to mitigate any potential compat risk.
-                return new String[0];
-#endif
-            }
-
-            if (count == 1)
-            {
-                return new String[] { this };
-            }
-            
-            int[] sepList = new int[Length];            
-            int numReplaces = MakeSeparatorList(separators, separatorsLength, sepList);
-            
-            // Handle the special case of no replaces.
-            if (0 == numReplaces) {
-                return new String[] { this };
-            }            
-
-            if(omitEmptyEntries) 
-            {
-                return InternalSplitOmitEmptyEntries(sepList, null, 1, numReplaces, count);
-            }
-            else 
-            {
-                return InternalSplitKeepEmptyEntries(sepList, null, 1, numReplaces, count);
-            }            
-        }
-
-        [ComVisible(false)]
-        public String[] Split(String separator) {
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            return SplitInternal(separator ?? String.Empty, null, Int32.MaxValue, StringSplitOptions.None);
-        }
-
-        [ComVisible(false)]
-        public String[] Split(String separator, StringSplitOptions options) {
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            return SplitInternal(separator ?? String.Empty, null, Int32.MaxValue, options);
-        }
-
-        [ComVisible(false)]
-        public String[] Split(String separator, Int32 count, StringSplitOptions options) {
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            return SplitInternal(separator ?? String.Empty, null, count, options);
-        }
-
-        [ComVisible(false)]
-        public String [] Split(String[] separator, StringSplitOptions options) {
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            return SplitInternal(null, separator, Int32.MaxValue, options);
-        }
-
-        [ComVisible(false)]
-        public String[] Split(String[] separator, Int32 count, StringSplitOptions options) {
-            Contract.Ensures(Contract.Result<String[]>() != null);
-            return SplitInternal(null, separator, count, options);
-        }
-
-        private String[] SplitInternal(String separator, String[] separators, Int32 count, StringSplitOptions options)
-        {
-            if (count < 0) {
-                throw new ArgumentOutOfRangeException("count",
-                    Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
-            }
-
-            if (options < StringSplitOptions.None || options > StringSplitOptions.RemoveEmptyEntries) {
-                throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)options));
-            }
-            Contract.EndContractBlock();
-
-            bool omitEmptyEntries = (options == StringSplitOptions.RemoveEmptyEntries);
-
-            bool singleSeparator = separator != null;
-
-            if (!singleSeparator && (separators == null || separators.Length == 0)) {
-                return SplitInternal((char[]) null, count, options);
-            }
-            
-            if ((count == 0) || (omitEmptyEntries && this.Length ==0)) {
-#if FEATURE_CORECLR
-                return EmptyArray<String>.Value;
-#else
-                // Keep the old behavior of returning a new empty array
-                // to mitigate any potential compat risk.
-                return new String[0];
-#endif
-            }
-
-            if (count == 1) {
-                return new String[] { this };
-            }
-
-            if (singleSeparator && separator.Length == 0) {
-                return new[] { this };
-            }
-
-            int[] sepList = new int[Length];
-            int[] lengthList;
-            int defaultLength;
-            int numReplaces;
-
-            if (singleSeparator) {
-                lengthList = null;
-                defaultLength = separator.Length;
-                numReplaces = MakeSeparatorList(separator, sepList);
-            }
-            else {
-                lengthList = new int[Length];
-                defaultLength = 0;
-                numReplaces = MakeSeparatorList(separators, sepList, lengthList);
-            }
-
-            // Handle the special case of no replaces.
-            if (0 == numReplaces) {
-                return new String[] { this };
-            }
-            
-            if (omitEmptyEntries) {
-                return InternalSplitOmitEmptyEntries(sepList, lengthList, defaultLength, numReplaces, count);
-            }
-            else {
-                return InternalSplitKeepEmptyEntries(sepList, lengthList, defaultLength, numReplaces, count);
-            }
-        }                        
-        
-        // Note a special case in this function:
-        //     If there is no separator in the string, a string array which only contains 
-        //     the original string will be returned regardless of the count. 
-        //
-
-        private String[] InternalSplitKeepEmptyEntries(Int32[] sepList, Int32[] lengthList, Int32 defaultLength, Int32 numReplaces, int count) {
-            Contract.Requires(numReplaces >= 0);
-            Contract.Requires(count >= 2);
-            Contract.Ensures(Contract.Result<String[]>() != null);
-        
-            int currIndex = 0;
-            int arrIndex = 0;
-
-            count--;
-            int numActualReplaces = (numReplaces < count) ? numReplaces : count;
-
-            //Allocate space for the new array.
-            //+1 for the string from the end of the last replace to the end of the String.
-            String[] splitStrings = new String[numActualReplaces+1];
-
-            for (int i = 0; i < numActualReplaces && currIndex < Length; i++) {
-                splitStrings[arrIndex++] = Substring(currIndex, sepList[i]-currIndex );                            
-                currIndex=sepList[i] + ((lengthList == null) ? defaultLength : lengthList[i]);
-            }
-
-            //Handle the last string at the end of the array if there is one.
-            if (currIndex < Length && numActualReplaces >= 0) {
-                splitStrings[arrIndex] = Substring(currIndex);
-            } 
-            else if (arrIndex==numActualReplaces) {
-                //We had a separator character at the end of a string.  Rather than just allowing
-                //a null character, we'll replace the last element in the array with an empty string.
-                splitStrings[arrIndex] = String.Empty;
-
-            }
-
-            return splitStrings;
-        }
-
-        
-        // This function will not keep the Empty String 
-        private String[] InternalSplitOmitEmptyEntries(Int32[] sepList, Int32[] lengthList, Int32 defaultLength, Int32 numReplaces, int count) {
-            Contract.Requires(numReplaces >= 0);
-            Contract.Requires(count >= 2);
-            Contract.Ensures(Contract.Result<String[]>() != null);
-
-            // Allocate array to hold items. This array may not be 
-            // filled completely in this function, we will create a 
-            // new array and copy string references to that new array.
-
-            int maxItems = (numReplaces < count) ? (numReplaces+1): count ;
-            String[] splitStrings = new String[maxItems];
-
-            int currIndex = 0;
-            int arrIndex = 0;
-
-            for(int i=0; i< numReplaces && currIndex < Length; i++) {
-                if( sepList[i]-currIndex > 0) { 
-                    splitStrings[arrIndex++] = Substring(currIndex, sepList[i]-currIndex );                            
-                }
-                currIndex=sepList[i] + ((lengthList == null) ? defaultLength : lengthList[i]);
-                if( arrIndex == count -1 )  {
-                    // If all the remaining entries at the end are empty, skip them
-                    while( i < numReplaces - 1 && currIndex == sepList[++i]) { 
-                        currIndex += ((lengthList == null) ? defaultLength : lengthList[i]);
-                    }
-                    break;
-                }
-            }
-
-            // we must have at least one slot left to fill in the last string.
-            Contract.Assert(arrIndex < maxItems);
-
-            //Handle the last string at the end of the array if there is one.
-            if (currIndex< Length) {                
-                splitStrings[arrIndex++] = Substring(currIndex);
-            }
-
-            String[] stringArray = splitStrings;
-            if( arrIndex!= maxItems) { 
-                stringArray = new String[arrIndex];
-                for( int j = 0; j < arrIndex; j++) {
-                    stringArray[j] = splitStrings[j];
-                }   
-            }
-            return stringArray;
-        }       
-
-        //--------------------------------------------------------------------    
-        // This function returns the number of the places within this instance where 
-        // characters in Separator occur.
-        // Args: separator  -- A string containing all of the split characters.
-        //       sepList    -- an array of ints for split char indicies.
-        //--------------------------------------------------------------------    
-        [System.Security.SecurityCritical]
-        private unsafe int MakeSeparatorList(char* separators, int separatorsLength, int[] sepList) {
-            Contract.Assert(separatorsLength >= 0, "separatorsLength >= 0");
-            int foundCount=0;
-
-            if (separators == null || separatorsLength == 0) {
-                fixed (char* pwzChars = &this.m_firstChar) {
-                    //If they passed null or an empty string, look for whitespace.
-                    for (int i=0; i < Length && foundCount < sepList.Length; i++) {
-                        if (Char.IsWhiteSpace(pwzChars[i])) {
-                            sepList[foundCount++]=i;
-                        }
-                    }
-                }
-            } 
-            else {
-                int sepListCount = sepList.Length;
-                //If they passed in a string of chars, actually look for those chars.
-                fixed (char* pwzChars = &this.m_firstChar) {
-                    for (int i=0; i< Length && foundCount < sepListCount; i++) {                        
-                        char* pSep = separators;
-                        for (int j = 0; j < separatorsLength; j++, pSep++) {
-                           if ( pwzChars[i] == *pSep) {
-                               sepList[foundCount++]=i;
-                               break;
-                           }
-                        }
-                    }
-                }
-            }
-            return foundCount;
-        }        
-        
-        //--------------------------------------------------------------------
-        // This function returns number of the places within baseString where
-        // instances of the separator string occurs.
-        // Args: separator  -- the separator
-        //       sepList    -- an array of ints for split string indicies.
-        //--------------------------------------------------------------------
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        private unsafe int MakeSeparatorList(string separator, int[] sepList) {
-            Contract.Assert(!string.IsNullOrEmpty(separator), "!string.IsNullOrEmpty(separator)");
-
-            int foundCount = 0;
-            int sepListCount = sepList.Length;
-            int currentSepLength = separator.Length;
-
-            fixed (char* pwzChars = &this.m_firstChar) {
-                for (int i = 0; i < Length && foundCount < sepListCount; i++) {
-                    if (pwzChars[i] == separator[0] && currentSepLength <= Length - i) {
-                        if (currentSepLength == 1
-                            || String.CompareOrdinal(this, i, separator, 0, currentSepLength) == 0) {
-                            sepList[foundCount] = i;
-                            foundCount++;
-                            i += currentSepLength - 1;
-                        }
-                    }
-                }
-            }
-            return foundCount;
-        }
-
-        //--------------------------------------------------------------------    
-        // This function returns the number of the places within this instance where 
-        // instances of separator strings occur.
-        // Args: separators -- An array containing all of the split strings.
-        //       sepList    -- an array of ints for split string indicies.
-        //       lengthList -- an array of ints for split string lengths.
-        //--------------------------------------------------------------------    
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        private unsafe int MakeSeparatorList(String[] separators, int[] sepList, int[] lengthList) {
-            Contract.Assert(separators != null && separators.Length > 0, "separators != null && separators.Length > 0");
-            
-            int foundCount = 0;
-            int sepListCount = sepList.Length;
-            int sepCount = separators.Length;
-
-            fixed (char* pwzChars = &this.m_firstChar) {
-                for (int i=0; i< Length && foundCount < sepListCount; i++) {                        
-                    for( int j =0; j < separators.Length; j++) {
-                        String separator = separators[j];
-                        if (String.IsNullOrEmpty(separator)) {
-                            continue;
-                        }
-                        Int32 currentSepLength = separator.Length;
-                        if ( pwzChars[i] == separator[0] && currentSepLength <= Length - i) {
-                            if (currentSepLength == 1 
-                                || String.CompareOrdinal(this, i, separator, 0, currentSepLength) == 0) {
-                                sepList[foundCount] = i;
-                                lengthList[foundCount] = currentSepLength;
-                                foundCount++;
-                                i += currentSepLength - 1;
-                                break;
-                            }
-                        }
-                    }
-                }
-            }
-            return foundCount;
-        }
-       
-        // Returns a substring of this string.
-        //
-        public String Substring (int startIndex) {
-            return this.Substring (startIndex, Length-startIndex);
-        }
-    
-        // Returns a substring of this string.
-        //
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public String Substring(int startIndex, int length) {
-                    
-            //Bounds Checking.
-            if (startIndex < 0) {
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
-            }
-
-            if (startIndex > Length) {
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndexLargerThanLength"));
-            }
-
-            if (length < 0) {
-                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
-            }
-
-            if (startIndex > Length - length) {
-                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_IndexLength"));
-            }
-            Contract.EndContractBlock();
-
-            if( length == 0) {
-                return String.Empty;
-            }
-
-            if( startIndex == 0 && length == this.Length) {
-                return this;
-            }
-
-            return InternalSubString(startIndex, length);
-        }
-
-        [System.Security.SecurityCritical]  // auto-generated
-        unsafe string InternalSubString(int startIndex, int length) {
-            Contract.Assert( startIndex >= 0 && startIndex <= this.Length, "StartIndex is out of range!");
-            Contract.Assert( length >= 0 && startIndex <= this.Length - length, "length is out of range!");            
-            
-            String result = FastAllocateString(length);
-
-            fixed(char* dest = &result.m_firstChar)
-                fixed(char* src = &this.m_firstChar) {
-                    wstrcpy(dest, src + startIndex, length);
-                }
-
-            return result;
-        }
-    
-    
-        // Removes a set of characters from the end of this string.
-        [Pure]
-        public String Trim(params char[] trimChars) {
-            if (null==trimChars || trimChars.Length == 0) {
-                return TrimHelper(TrimBoth);
-            }
-            return TrimHelper(trimChars,TrimBoth);
-        }
-    
-        // Removes a set of characters from the beginning of this string.
-        public String TrimStart(params char[] trimChars) {
-            if (null==trimChars || trimChars.Length == 0) {
-                return TrimHelper(TrimHead);
-            }
-            return TrimHelper(trimChars,TrimHead);
-        }
-    
-    
-        // Removes a set of characters from the end of this string.
-        public String TrimEnd(params char[] trimChars) {
-            if (null==trimChars || trimChars.Length == 0) {
-                return TrimHelper(TrimTail);
-            }
-            return TrimHelper(trimChars,TrimTail);
-        }
-    
-        // Creates a new string with the characters copied in from ptr. If
-        // ptr is null, a 0-length string (like String.Empty) is returned.
-        //
-        [System.Security.SecurityCritical]  // auto-generated
-        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
-        unsafe public extern String(char *value);
-        [System.Security.SecurityCritical]  // auto-generated
-        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
-        unsafe public extern String(char *value, int startIndex, int length);
-    
-        [System.Security.SecurityCritical]  // auto-generated
-        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
-        unsafe public extern String(sbyte *value);
-        [System.Security.SecurityCritical]  // auto-generated
-        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
-        unsafe public extern String(sbyte *value, int startIndex, int length);
-
-        [System.Security.SecurityCritical]  // auto-generated
-        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
-        unsafe public extern String(sbyte *value, int startIndex, int length, Encoding enc);
-        
-        [System.Security.SecurityCritical]  // auto-generated
-        unsafe static private String CreateString(sbyte *value, int startIndex, int length, Encoding enc) {            
-            if (enc == null)
-                return new String(value, startIndex, length); // default to ANSI
-
-            if (length < 0)
-                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-            if (startIndex < 0)
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
-            if ((value + startIndex) < value) {
-                // overflow check
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
-            }
-
-            byte [] b = new byte[length];
-
-            try {
-                Buffer.Memcpy(b, 0, (byte*)value, startIndex, length);
-            }
-            catch(NullReferenceException) {
-                // If we got a NullReferencException. It means the pointer or 
-                // the index is out of range
-                throw new ArgumentOutOfRangeException("value", 
-                        Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));                
-            }
-
-            return enc.GetString(b);
-        }
-        
-        // Helper for encodings so they can talk to our buffer directly
-        // stringLength must be the exact size we'll expect
-        [System.Security.SecurityCritical]  // auto-generated
-        unsafe static internal String CreateStringFromEncoding(
-            byte* bytes, int byteLength, Encoding encoding)
-        {
-            Contract.Requires(bytes != null);
-            Contract.Requires(byteLength >= 0);
-
-            // Get our string length
-            int stringLength = encoding.GetCharCount(bytes, byteLength, null);
-            Contract.Assert(stringLength >= 0, "stringLength >= 0");
-            
-            // They gave us an empty string if they needed one
-            // 0 bytelength might be possible if there's something in an encoder
-            if (stringLength == 0)
-                return String.Empty;
-            
-            String s = FastAllocateString(stringLength);
-            fixed(char* pTempChars = &s.m_firstChar)
-            {
-                int doubleCheck = encoding.GetChars(bytes, byteLength, pTempChars, stringLength, null);
-                Contract.Assert(stringLength == doubleCheck, 
-                    "Expected encoding.GetChars to return same length as encoding.GetCharCount");
-            }
-
-            return s;
-        }
-
-        // This is only intended to be used by char.ToString.
-        // It is necessary to put the code in this class instead of Char, since m_firstChar is a private member.
-        // Making m_firstChar internal would be dangerous since it would make it much easier to break String's immutability.
-        [SecuritySafeCritical]
-        internal static string CreateFromChar(char c)
-        {
-            string result = FastAllocateString(1);
-            result.m_firstChar = c;
-            return result;
-        }
-                
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        unsafe internal int GetBytesFromEncoding(byte* pbNativeBuffer, int cbNativeBuffer,Encoding encoding)
-        {
-            // encoding == Encoding.UTF8
-            fixed (char* pwzChar = &this.m_firstChar)
-            {
-                return encoding.GetBytes(pwzChar, m_stringLength, pbNativeBuffer, cbNativeBuffer);
-            }            
-        }
-
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        unsafe internal int ConvertToAnsi(byte *pbNativeBuffer, int cbNativeBuffer, bool fBestFit, bool fThrowOnUnmappableChar)
-        {
-            Contract.Assert(cbNativeBuffer >= (Length + 1) * Marshal.SystemMaxDBCSCharSize, "Insufficient buffer length passed to ConvertToAnsi");
-
-            const uint CP_ACP = 0;
-            int nb;
-
-            const uint WC_NO_BEST_FIT_CHARS = 0x00000400;
-
-            uint flgs = (fBestFit ? 0 : WC_NO_BEST_FIT_CHARS);
-            uint DefaultCharUsed = 0;
-
-            fixed (char* pwzChar = &this.m_firstChar)
-            {
-                nb = Win32Native.WideCharToMultiByte(
-                    CP_ACP,
-                    flgs,
-                    pwzChar,
-                    this.Length,
-                    pbNativeBuffer,
-                    cbNativeBuffer,
-                    IntPtr.Zero,
-                    (fThrowOnUnmappableChar ? new IntPtr(&DefaultCharUsed) : IntPtr.Zero));
-            }
-
-            if (0 != DefaultCharUsed)
-            {
-                throw new ArgumentException(Environment.GetResourceString("Interop_Marshal_Unmappable_Char"));
-            }
-
-            pbNativeBuffer[nb] = 0;
-            return nb;
-        }
-
-        // Normalization Methods
-        // These just wrap calls to Normalization class
-        public bool IsNormalized()
-        {
-#if !FEATURE_NORM_IDNA_ONLY
-            // Default to Form C
-            return IsNormalized(NormalizationForm.FormC);
-#else
-            // Default to Form IDNA
-            return IsNormalized((NormalizationForm)ExtendedNormalizationForms.FormIdna);
-#endif
-        }
-
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public bool IsNormalized(NormalizationForm normalizationForm)
-        {
-#if !FEATURE_NORM_IDNA_ONLY
-            if (this.IsFastSort())
-            {
-                // If its FastSort && one of the 4 main forms, then its already normalized
-                if( normalizationForm == NormalizationForm.FormC ||
-                    normalizationForm == NormalizationForm.FormKC ||
-                    normalizationForm == NormalizationForm.FormD ||
-                    normalizationForm == NormalizationForm.FormKD )
-                    return true;
-            }            
-#endif // !FEATURE_NORM_IDNA_ONLY            
-            return Normalization.IsNormalized(this, normalizationForm);
-        }
-
-        public String Normalize()
-        {
-#if !FEATURE_NORM_IDNA_ONLY
-            // Default to Form C
-            return Normalize(NormalizationForm.FormC);
-#else
-            // Default to Form IDNA
-            return Normalize((NormalizationForm)ExtendedNormalizationForms.FormIdna);
-#endif
-        }
-
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public String Normalize(NormalizationForm normalizationForm)
-        {
-#if !FEATURE_NORM_IDNA_ONLY        
-            if (this.IsAscii())
-            {
-                // If its FastSort && one of the 4 main forms, then its already normalized
-                if( normalizationForm == NormalizationForm.FormC ||
-                    normalizationForm == NormalizationForm.FormKC ||
-                    normalizationForm == NormalizationForm.FormD ||
-                    normalizationForm == NormalizationForm.FormKD )
-                    return this;
-            }
-#endif // !FEATURE_NORM_IDNA_ONLY            
-            return Normalization.Normalize(this, normalizationForm);
-        }
-
-        [System.Security.SecurityCritical]  // auto-generated
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal extern static String FastAllocateString(int length);
-
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        unsafe private static void FillStringChecked(String dest, int destPos, String src)
-        {
-            Contract.Requires(dest != null);
-            Contract.Requires(src != null);
-            if (src.Length > dest.Length - destPos) {
-                throw new IndexOutOfRangeException();
-            }
-            Contract.EndContractBlock();
-
-            fixed(char *pDest = &dest.m_firstChar)
-                fixed (char *pSrc = &src.m_firstChar) {
-                    wstrcpy(pDest + destPos, pSrc, src.Length);
-                }
-        }
-
-        // Creates a new string from the characters in a subarray.  The new string will
-        // be created from the characters in value between startIndex and
-        // startIndex + length - 1.
-        //
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public extern String(char [] value, int startIndex, int length);
-    
-        // Creates a new string from the characters in a subarray.  The new string will be
-        // created from the characters in value.
-        //
-        
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public extern String(char [] value);
-
-        [System.Security.SecurityCritical]  // auto-generated
-        internal static unsafe void wstrcpy(char *dmem, char *smem, int charCount)
-        {
-            Buffer.Memcpy((byte*)dmem, (byte*)smem, charCount * 2); // 2 used everywhere instead of sizeof(char)
-        }
-
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        private String CtorCharArray(char [] value)
-        {
-            if (value != null && value.Length != 0) {
-                String result = FastAllocateString(value.Length);
-
-                unsafe {
-                    fixed (char* dest = &result.m_firstChar, source = value) {
-                        wstrcpy(dest, source, value.Length);
-                    }
-                }
-                return result;
-            }
-            else
-                return String.Empty;
-        }
-
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        private String CtorCharArrayStartLength(char [] value, int startIndex, int length)
-        {
-            if (value == null)
-                throw new ArgumentNullException("value");
-
-            if (startIndex < 0)
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
-
-            if (length < 0)
-                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
-
-            if (startIndex > value.Length - length)
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
-            Contract.EndContractBlock();
-
-            if (length > 0) {
-                String result = FastAllocateString(length);
-
-                unsafe {
-                    fixed (char* dest = &result.m_firstChar, source = value) {
-                        wstrcpy(dest, source + startIndex, length);
-                    }
-                }
-                return result;
-            }
-            else
-                return String.Empty;
-        }
-
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        private String CtorCharCount(char c, int count)
-        {
-            if (count > 0) {
-                String result = FastAllocateString(count);
-                if (c != 0)
-                {
-                    unsafe {
-                        fixed (char* dest = &result.m_firstChar) {
-                            char *dmem = dest;
-                            while (((uint)dmem & 3) != 0 && count > 0) {
-                                *dmem++ = c;
-                                count--;
-                            }
-                            uint cc = (uint)((c << 16) | c);
-                            if (count >= 4) {
-                                count -= 4;
-                                do{
-                                    ((uint *)dmem)[0] = cc;
-                                    ((uint *)dmem)[1] = cc;
-                                    dmem += 4;
-                                    count -= 4;
-                                } while (count >= 0);
-                            }
-                            if ((count & 2) != 0) {
-                                ((uint *)dmem)[0] = cc;
-                                dmem += 2;
-                            }
-                            if ((count & 1) != 0)
-                                dmem[0] = c;
-                        }
-                    }
-                }
-                return result;
-            }
-            else if (count == 0)
-                return String.Empty;
-            else
-                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegNum", "count"));
-        }
-
-        [System.Security.SecurityCritical]  // auto-generated
-        private static unsafe int wcslen(char *ptr)
-        {
-            char *end = ptr;
-            
-            // First make sure our pointer is aligned on a word boundary
-            int alignment = IntPtr.Size - 1;
-
-            // If ptr is at an odd address (e.g. 0x5), this loop will simply iterate all the way
-            while (((uint)end & (uint)alignment) != 0)
-            {
-                if (*end == 0) goto FoundZero;
-                end++;
-            }
-
-#if !BIT64
-            // The following code is (somewhat surprisingly!) significantly faster than a naive loop,
-            // at least on x86 and the current jit.
-
-            // The loop condition below works because if "end[0] & end[1]" is non-zero, that means
-            // neither operand can have been zero. If is zero, we have to look at the operands individually,
-            // but we hope this going to fairly rare.
-
-            // In general, it would be incorrect to access end[1] if we haven't made sure
-            // end[0] is non-zero. However, we know the ptr has been aligned by the loop above
-            // so end[0] and end[1] must be in the same word (and therefore page), so they're either both accessible, or both not.
-
-            while ((end[0] & end[1]) != 0 || (end[0] != 0 && end[1] != 0)) {
-                end += 2;
-            }
-
-            Contract.Assert(end[0] == 0 || end[1] == 0);
-            if (end[0] != 0) end++;
-#else // !BIT64
-            // Based on https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
-
-            // 64-bit implementation: process 1 ulong (word) at a time
-
-            // What we do here is add 0x7fff from each of the
-            // 4 individual chars within the ulong, using MagicMask.
-            // If the char > 0 and < 0x8001, it will have its high bit set.
-            // We then OR with MagicMask, to set all the other bits.
-            // This will result in all bits set (ulong.MaxValue) for any
-            // char that fits the above criteria, and something else otherwise.
-
-            // Note that for any char > 0x8000, this will be a false
-            // positive and we will fallback to the slow path and
-            // check each char individually. This is OK though, since
-            // we optimize for the common case (ASCII chars, which are < 0x80).
-
-            // NOTE: We can access a ulong a time since the ptr is aligned,
-            // and therefore we're only accessing the same word/page. (See notes
-            // for the 32-bit version above.)
-            
-            const ulong MagicMask = 0x7fff7fff7fff7fff;
-
-            while (true)
-            {
-                ulong word = *(ulong*)end;
-                word += MagicMask; // cause high bit to be set if not zero, and <= 0x8000
-                word |= MagicMask; // set everything besides the high bits
-
-                if (word == ulong.MaxValue) // 0xffff...
-                {
-                    // all of the chars have their bits set (and therefore none can be 0)
-                    end += 4;
-                    continue;
-                }
-
-                // at least one of them didn't have their high bit set!
-                // go through each char and check for 0.
-
-                if (end[0] == 0) goto EndAt0;
-                if (end[1] == 0) goto EndAt1;
-                if (end[2] == 0) goto EndAt2;
-                if (end[3] == 0) goto EndAt3;
-
-                // if we reached here, it was a false positive-- just continue
-                end += 4;
-            }
-
-            EndAt3: end++;
-            EndAt2: end++;
-            EndAt1: end++;
-            EndAt0:
-#endif // !BIT64
-
-            FoundZero:
-            Contract.Assert(*end == 0);
-
-            int count = (int)(end - ptr);
-
-            return count;
-        }
-
-        [System.Security.SecurityCritical]  // auto-generated
-        private unsafe String CtorCharPtr(char *ptr)
-        {
-            if (ptr == null)
-                return String.Empty;
-
-#if !FEATURE_PAL
-            if (ptr < (char*)64000)
-                throw new ArgumentException(Environment.GetResourceString("Arg_MustBeStringPtrNotAtom"));
-#endif // FEATURE_PAL
-
-            Contract.Assert(this == null, "this == null");        // this is the string constructor, we allocate it
-
-            try {
-                int count = wcslen(ptr);
-                if (count == 0)
-                    return String.Empty;
-
-                String result = FastAllocateString(count);
-                fixed (char* dest = &result.m_firstChar)
-                    wstrcpy(dest, ptr, count);
-                return result;
-            }
-            catch (NullReferenceException) {
-                throw new ArgumentOutOfRangeException("ptr", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
-            }
-        }
-
-        [System.Security.SecurityCritical]  // auto-generated
-        private unsafe String CtorCharPtrStartLength(char *ptr, int startIndex, int length)
-        {
-            if (length < 0) {
-                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
-            }
-
-            if (startIndex < 0) {
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
-            }
-            Contract.EndContractBlock();
-            Contract.Assert(this == null, "this == null");        // this is the string constructor, we allocate it
-
-            char *pFrom = ptr + startIndex;
-            if (pFrom < ptr) {
-                // This means that the pointer operation has had an overflow
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
-            }
-
-            if (length == 0)
-                return String.Empty;
-
-            String result = FastAllocateString(length);
-
-            try {
-                fixed (char* dest = &result.m_firstChar)
-                    wstrcpy(dest, pFrom, length);
-                return result;
-            }
-            catch (NullReferenceException) {
-                throw new ArgumentOutOfRangeException("ptr", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
-            }
-        }
-
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public extern String(char c, int count);
-    
-        // Provides a culture-correct string comparison. StrA is compared to StrB
-        // to determine whether it is lexicographically less, equal, or greater, and then returns
-        // either a negative integer, 0, or a positive integer; respectively.
-        //
-        [Pure]
-        public static int Compare(String strA, String strB)
-        {
-            return Compare(strA, strB, StringComparison.CurrentCulture);
-        }
-    
-
-        // Provides a culture-correct string comparison. strA is compared to strB
-        // to determine whether it is lexicographically less, equal, or greater, and then a
-        // negative integer, 0, or a positive integer is returned; respectively.
-        // The case-sensitive option is set by ignoreCase
-        //
-        [Pure]
-        public static int Compare(String strA, String strB, bool ignoreCase)
-        {
-            var comparisonType = ignoreCase ? StringComparison.CurrentCultureIgnoreCase : StringComparison.CurrentCulture;
-            return Compare(strA, strB, comparisonType);
-        }
-
-  
-        // Provides a more flexible function for string comparision. See StringComparison 
-        // for meaning of different comparisonType.
-        [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public static int Compare(String strA, String strB, StringComparison comparisonType) 
-        {
-            // Single comparison to check if comparisonType is within [CurrentCulture .. OrdinalIgnoreCase]
-            if ((uint)(comparisonType - StringComparison.CurrentCulture) > (uint)(StringComparison.OrdinalIgnoreCase - StringComparison.CurrentCulture))
-            {
-                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
-            }
-            Contract.EndContractBlock();
-
-            if (object.ReferenceEquals(strA, strB))
-            {
-                return 0;
-            }
-
-            // They can't both be null at this point.
-            if (strA == null)
-            {
-                return -1;
-            }
-            if (strB == null)
-            {
-                return 1;
-            }
-
-            switch (comparisonType) {
-                case StringComparison.CurrentCulture:
-                    return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
-
-                case StringComparison.CurrentCultureIgnoreCase:
-                    return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
-
-                case StringComparison.InvariantCulture:
-                    return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.None);
-
-                case StringComparison.InvariantCultureIgnoreCase:
-                    return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreCase);
-
-                case StringComparison.Ordinal:
-                    // Most common case: first character is different.
-                    // Returns false for empty strings.
-                    if (strA.m_firstChar != strB.m_firstChar)
-                    {
-                        return strA.m_firstChar - strB.m_firstChar;
-                    }
-
-                    return CompareOrdinalHelper(strA, strB);
-
-                case StringComparison.OrdinalIgnoreCase:
-                    // If both strings are ASCII strings, we can take the fast path.
-                    if (strA.IsAscii() && strB.IsAscii()) {
-                        return (CompareOrdinalIgnoreCaseHelper(strA, strB));
-                    }
-
-#if FEATURE_COREFX_GLOBALIZATION
-                    return CompareInfo.CompareOrdinalIgnoreCase(strA, 0, strA.Length, strB, 0, strB.Length);
-#else
-                    // Take the slow path.
-                    return TextInfo.CompareOrdinalIgnoreCase(strA, strB);
-#endif
-
-                default:
-                    throw new NotSupportedException(Environment.GetResourceString("NotSupported_StringComparison"));
-            }
-        }
-
-
-        // Provides a culture-correct string comparison. strA is compared to strB
-        // to determine whether it is lexicographically less, equal, or greater, and then a
-        // negative integer, 0, or a positive integer is returned; respectively.
-        //
-        [Pure]
-        public static int Compare(String strA, String strB, CultureInfo culture, CompareOptions options) {
-            if (culture == null)
-            {
-                throw new ArgumentNullException("culture");
-            }
-            Contract.EndContractBlock();
-
-            return culture.CompareInfo.Compare(strA, strB, options);
-        }
-
-
-
-        // Provides a culture-correct string comparison. strA is compared to strB
-        // to determine whether it is lexicographically less, equal, or greater, and then a
-        // negative integer, 0, or a positive integer is returned; respectively.
-        // The case-sensitive option is set by ignoreCase, and the culture is set
-        // by culture
-        //
-        [Pure]
-        public static int Compare(String strA, String strB, bool ignoreCase, CultureInfo culture)
-        {
-            var options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
-            return Compare(strA, strB, culture, options);
-        }
-
-        // Determines whether two string regions match.  The substring of strA beginning
-        // at indexA of length count is compared with the substring of strB
-        // beginning at indexB of the same length.
-        //
-        [Pure]
-        public static int Compare(String strA, int indexA, String strB, int indexB, int length)
-        {
-            // NOTE: It's important we call the boolean overload, and not the StringComparison
-            // one. The two have some subtly different behavior (see notes in the former).
-            return Compare(strA, indexA, strB, indexB, length, ignoreCase: false);
-        }
-
-        // Determines whether two string regions match.  The substring of strA beginning
-        // at indexA of length count is compared with the substring of strB
-        // beginning at indexB of the same length.  Case sensitivity is determined by the ignoreCase boolean.
-        //
-        [Pure]
-        public static int Compare(String strA, int indexA, String strB, int indexB, int length, bool ignoreCase)
-        {
-            // Ideally we would just forward to the string.Compare overload that takes
-            // a StringComparison parameter, and just pass in CurrentCulture/CurrentCultureIgnoreCase.
-            // That function will return early if an optimization can be applied, e.g. if
-            // (object)strA == strB && indexA == indexB then it will return 0 straightaway.
-            // There are a couple of subtle behavior differences that prevent us from doing so
-            // however:
-            // - string.Compare(null, -1, null, -1, -1, StringComparison.CurrentCulture) works
-            //   since that method also returns early for nulls before validation. It shouldn't
-            //   for this overload.
-            // - Since we originally forwarded to CompareInfo.Compare for all of the argument
-            //   validation logic, the ArgumentOutOfRangeExceptions thrown will contain different
-            //   parameter names.
-            // Therefore, we have to duplicate some of the logic here.
-
-            int lengthA = length;
-            int lengthB = length;
-            
-            if (strA != null)
-            {
-                lengthA = Math.Min(lengthA, strA.Length - indexA);
-            }
-
-            if (strB != null)
-            {
-                lengthB = Math.Min(lengthB, strB.Length - indexB);
-            }
-
-            var options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
-            return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, options);
-        }
-
-        // Determines whether two string regions match.  The substring of strA beginning
-        // at indexA of length length is compared with the substring of strB
-        // beginning at indexB of the same length.  Case sensitivity is determined by the ignoreCase boolean,
-        // and the culture is set by culture.
-        //
-        [Pure]
-        public static int Compare(String strA, int indexA, String strB, int indexB, int length, bool ignoreCase, CultureInfo culture)
-        {
-            var options = ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None;
-            return Compare(strA, indexA, strB, indexB, length, culture, options);
-        }
-
-
-        // Determines whether two string regions match.  The substring of strA beginning
-        // at indexA of length length is compared with the substring of strB
-        // beginning at indexB of the same length.
-        //
-        [Pure]
-        public static int Compare(String strA, int indexA, String strB, int indexB, int length, CultureInfo culture, CompareOptions options)
-        {
-            if (culture == null)
-            {
-                throw new ArgumentNullException("culture");
-            }
-            Contract.EndContractBlock();
-
-            int lengthA = length;
-            int lengthB = length;
-
-            if (strA != null)
-            {
-                lengthA = Math.Min(lengthA, strA.Length - indexA);
-            }
-
-            if (strB != null)
-            {
-                lengthB = Math.Min(lengthB, strB.Length - indexB);
-            }
-    
-            return culture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, options);
-        }
-
-        [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public static int Compare(String strA, int indexA, String strB, int indexB, int length, StringComparison comparisonType) {
-            if (comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
-                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
-            }
-            Contract.EndContractBlock();
-            
-            if (strA == null || strB == null)
-            {
-                if (object.ReferenceEquals(strA, strB))
-                {
-                    // They're both null
-                    return 0;
-                }
-
-                return strA == null ? -1 : 1;
-            }
-
-            if (length < 0)
-            {
-                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
-            }
-
-            if (indexA < 0 || indexB < 0)
-            {
-                string paramName = indexA < 0 ? "indexA" : "indexB";
-                throw new ArgumentOutOfRangeException(paramName, Environment.GetResourceString("ArgumentOutOfRange_Index"));
-            }
-
-            if (strA.Length - indexA < 0 || strB.Length - indexB < 0)
-            {
-                string paramName = strA.Length - indexA < 0 ? "indexA" : "indexB";
-                throw new ArgumentOutOfRangeException(paramName, Environment.GetResourceString("ArgumentOutOfRange_Index"));
-            }
-
-            if (length == 0 || (object.ReferenceEquals(strA, strB) && indexA == indexB))
-            {
-                return 0;
-            }
-
-            int lengthA = Math.Min(length, strA.Length - indexA);
-            int lengthB = Math.Min(length, strB.Length - indexB);
-
-            switch (comparisonType) {
-                case StringComparison.CurrentCulture:
-                    return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
-
-                case StringComparison.CurrentCultureIgnoreCase:
-                    return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
-
-                case StringComparison.InvariantCulture:
-                    return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.None);
-
-                case StringComparison.InvariantCultureIgnoreCase:
-                    return CultureInfo.InvariantCulture.CompareInfo.Compare(strA, indexA, lengthA, strB, indexB, lengthB, CompareOptions.IgnoreCase);
-
-                case StringComparison.Ordinal:
-                    return CompareOrdinalHelper(strA, indexA, lengthA, strB, indexB, lengthB);
-
-                case StringComparison.OrdinalIgnoreCase:
-#if FEATURE_COREFX_GLOBALIZATION
-                    return (CompareInfo.CompareOrdinalIgnoreCase(strA, indexA, lengthA, strB, indexB, lengthB));
-#else
-                    return (TextInfo.CompareOrdinalIgnoreCaseEx(strA, indexA, strB, indexB, lengthA, lengthB));
-#endif
-
-                default:
-                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"));
-            }
-
-        }
-
-        // Compares this String to another String (cast as object), returning an integer that
-        // indicates the relationship. This method returns a value less than 0 if this is less than value, 0
-        // if this is equal to value, or a value greater than 0 if this is greater than value.
-        //
-        [Pure]
-        public int CompareTo(Object value)
-        {
-            if (value == null)
-            {
-                return 1;
-            }
-
-            string other = value as string;
-
-            if (other == null)
-            {
-                throw new ArgumentException(Environment.GetResourceString("Arg_MustBeString"));
-            }
-
-            return CompareTo(other); // will call the string-based overload
-        }
-    
-        // Determines the sorting relation of StrB to the current instance.
-        //
-        [Pure]
-        public int CompareTo(String strB)
-        {
-            return string.Compare(this, strB, StringComparison.CurrentCulture);
-        }
-
-        // Compares strA and strB using an ordinal (code-point) comparison.
-        //
-        [Pure]
-        public static int CompareOrdinal(String strA, String strB)
-        {
-            if (object.ReferenceEquals(strA, strB))
-            {
-                return 0;
-            }
-
-            // They can't both be null at this point.
-            if (strA == null)
-            {
-                return -1;
-            }
-            if (strB == null)
-            {
-                return 1;
-            }
-
-            // Most common case, first character is different.
-            // This will return false for empty strings.
-            if (strA.m_firstChar != strB.m_firstChar)
-            {
-                return strA.m_firstChar - strB.m_firstChar;
-            }
-
-            return CompareOrdinalHelper(strA, strB);
-        }
-        
-
-        // Compares strA and strB using an ordinal (code-point) comparison.
-        //
-        [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public static int CompareOrdinal(String strA, int indexA, String strB, int indexB, int length)
-        {
-            if (strA == null || strB == null)
-            {
-                if (object.ReferenceEquals(strA, strB))
-                {
-                    // They're both null
-                    return 0;
-                }
-
-                return strA == null ? -1 : 1;
-            }
-
-            // COMPAT: Checking for nulls should become before the arguments are validated,
-            // but other optimizations which allow us to return early should come after.
-
-            if (length < 0)
-            {
-                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
-            }
-
-            if (indexA < 0 || indexB < 0)
-            {
-                string paramName = indexA < 0 ? "indexA" : "indexB";
-                throw new ArgumentOutOfRangeException(paramName, Environment.GetResourceString("ArgumentOutOfRange_Index"));
-            }
-            
-            int lengthA = Math.Min(length, strA.Length - indexA);
-            int lengthB = Math.Min(length, strB.Length - indexB);
-
-            if (lengthA < 0 || lengthB < 0)
-            {
-                string paramName = lengthA < 0 ? "indexA" : "indexB";
-                throw new ArgumentOutOfRangeException(paramName, Environment.GetResourceString("ArgumentOutOfRange_Index"));
-            }
-
-            if (length == 0 || (object.ReferenceEquals(strA, strB) && indexA == indexB))
-            {
-                return 0;
-            }
-
-            return CompareOrdinalHelper(strA, indexA, lengthA, strB, indexB, lengthB);
-        }
-
-
-        [Pure]
-        public bool Contains( string value ) {
-            return ( IndexOf(value, StringComparison.Ordinal) >=0 );
-        }
-
-        // Determines whether a specified string is a suffix of the the current instance.
-        //
-        // The case-sensitive and culture-sensitive option is set by options,
-        // and the default culture is used.
-        //        
-        [Pure]
-        public Boolean EndsWith(String value) {
-            return EndsWith(value, StringComparison.CurrentCulture);
-        }
-
-        [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        [ComVisible(false)]
-        public Boolean EndsWith(String value, StringComparison comparisonType) {
-            if( (Object)value == null) {
-                throw new ArgumentNullException("value");                                
-            }
-
-            if( comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
-                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
-            }
-            Contract.EndContractBlock();
-
-            if( (Object)this == (Object)value) {
-                return true;
-            }
-
-            if( value.Length == 0) {
-                return true;
-            }
-            
-            switch (comparisonType) {
-                case StringComparison.CurrentCulture:
-                    return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(this, value, CompareOptions.None);
-
-                case StringComparison.CurrentCultureIgnoreCase:
-                    return CultureInfo.CurrentCulture.CompareInfo.IsSuffix(this, value, CompareOptions.IgnoreCase);
-
-                case StringComparison.InvariantCulture:
-                    return CultureInfo.InvariantCulture.CompareInfo.IsSuffix(this, value, CompareOptions.None);
-
-                case StringComparison.InvariantCultureIgnoreCase:
-                    return CultureInfo.InvariantCulture.CompareInfo.IsSuffix(this, value, CompareOptions.IgnoreCase);                    
-
-                case StringComparison.Ordinal:
-                    return this.Length < value.Length ? false : (CompareOrdinalHelper(this, this.Length - value.Length, value.Length, value, 0, value.Length) == 0);
-
-                case StringComparison.OrdinalIgnoreCase:
-#if FEATURE_COREFX_GLOBALIZATION
-                    return this.Length < value.Length ? false : (CompareInfo.CompareOrdinalIgnoreCase(this, this.Length - value.Length, value.Length, value, 0, value.Length) == 0);
-#else                    
-                    return this.Length < value.Length ? false : (TextInfo.CompareOrdinalIgnoreCaseEx(this, this.Length - value.Length, value, 0, value.Length, value.Length) == 0);
-#endif
-                default:
-                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
-            }                        
-        }
-
-        [Pure]
-        public Boolean EndsWith(String value, Boolean ignoreCase, CultureInfo culture) {
-            if (null==value) {
-                throw new ArgumentNullException("value");
-            }
-            Contract.EndContractBlock();
-            
-            if((object)this == (object)value) {
-                return true;
-            }
-
-            CultureInfo referenceCulture;
-            if (culture == null)
-                referenceCulture = CultureInfo.CurrentCulture;
-            else
-                referenceCulture = culture;
-
-            return referenceCulture.CompareInfo.IsSuffix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
-        }
-
-        [Pure]
-        internal bool EndsWith(char value) {
-            int thisLen = this.Length;
-            if (thisLen != 0) {
-                if (this[thisLen - 1] == value)
-                    return true;
-            }
-            return false;
-        }
-    
-    
-        // Returns the index of the first occurrence of a specified character in the current instance.
-        // The search starts at startIndex and runs thorough the next count characters.
-        //
-        [Pure]
-        public int IndexOf(char value) {
-            return IndexOf(value, 0, this.Length);
-        }
-
-        [Pure]
-        public int IndexOf(char value, int startIndex) {
-            return IndexOf(value, startIndex, this.Length - startIndex);
-        }
-
-        [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public unsafe int IndexOf(char value, int startIndex, int count) {
-            if (startIndex < 0 || startIndex > Length)
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
-
-            if (count < 0 || count > Length - startIndex)
-                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
-
-            fixed (char* pChars = &m_firstChar)
-            {
-                char* pCh = pChars + startIndex;
-
-                while (count >= 4)
-                {
-                    if (*pCh == value) goto ReturnIndex;
-                    if (*(pCh + 1) == value) goto ReturnIndex1;
-                    if (*(pCh + 2) == value) goto ReturnIndex2;
-                    if (*(pCh + 3) == value) goto ReturnIndex3;
-
-                    count -= 4;
-                    pCh += 4;
-                }
-
-                while (count > 0)
-                {
-                    if (*pCh == value)
-                        goto ReturnIndex;
-
-                    count--;
-                    pCh++;
-                }
-
-                return -1;
-
-                ReturnIndex3: pCh++;
-                ReturnIndex2: pCh++;
-                ReturnIndex1: pCh++;
-                ReturnIndex:
-                return (int)(pCh - pChars);
-            }
-        }
-    
-        // Returns the index of the first occurrence of any specified character in the current instance.
-        // The search starts at startIndex and runs to startIndex + count -1.
-        //
-        [Pure]        
-        public int IndexOfAny(char [] anyOf) {
-            return IndexOfAny(anyOf,0, this.Length);
-        }
-    
-        [Pure]
-        public int IndexOfAny(char [] anyOf, int startIndex) {
-            return IndexOfAny(anyOf, startIndex, this.Length - startIndex);
-        }
-    
-        [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public extern int IndexOfAny(char [] anyOf, int startIndex, int count);
-    
-        
-        // Determines the position within this string of the first occurrence of the specified
-        // string, according to the specified search criteria.  The search begins at
-        // the first character of this string, it is case-sensitive and the current culture
-        // comparison is used.
-        //
-        [Pure]
-        public int IndexOf(String value) {
-            return IndexOf(value, StringComparison.CurrentCulture);
-        }
-
-        // Determines the position within this string of the first occurrence of the specified
-        // string, according to the specified search criteria.  The search begins at
-        // startIndex, it is case-sensitive and the current culture comparison is used.
-        //
-        [Pure]
-        public int IndexOf(String value, int startIndex) {
-            return IndexOf(value, startIndex, StringComparison.CurrentCulture);
-        }
-
-        // Determines the position within this string of the first occurrence of the specified
-        // string, according to the specified search criteria.  The search begins at
-        // startIndex, ends at endIndex and the current culture comparison is used.
-        //
-        [Pure]
-        public int IndexOf(String value, int startIndex, int count) {
-            if (startIndex < 0 || startIndex > this.Length) {
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
-            }
-
-            if (count < 0 || count > this.Length - startIndex) {
-                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
-            }
-            Contract.EndContractBlock();
-            
-            return IndexOf(value, startIndex, count, StringComparison.CurrentCulture);
-        }
-
-        [Pure]
-        public int IndexOf(String value, StringComparison comparisonType) {
-            return IndexOf(value, 0, this.Length, comparisonType);
-        }
-
-        [Pure]
-        public int IndexOf(String value, int startIndex, StringComparison comparisonType) {
-            return IndexOf(value, startIndex, this.Length - startIndex, comparisonType);
-        }
-
-        [Pure]
-        [System.Security.SecuritySafeCritical]
-        public int IndexOf(String value, int startIndex, int count, StringComparison comparisonType) {
-            // Validate inputs
-            if (value == null)
-                throw new ArgumentNullException("value");
-
-            if (startIndex < 0 || startIndex > this.Length)
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
-
-            if (count < 0 || startIndex > this.Length - count)
-                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
-            Contract.EndContractBlock();
-
-            switch (comparisonType) {
-                case StringComparison.CurrentCulture:
-                    return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None);
-
-                case StringComparison.CurrentCultureIgnoreCase:
-                    return CultureInfo.CurrentCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
-
-                case StringComparison.InvariantCulture:
-                    return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.None);
-
-                case StringComparison.InvariantCultureIgnoreCase:
-                    return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
-
-                case StringComparison.Ordinal:
-                    return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.Ordinal);
-
-                case StringComparison.OrdinalIgnoreCase:
-                    if (value.IsAscii() && this.IsAscii())
-                        return CultureInfo.InvariantCulture.CompareInfo.IndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
-                    else
-                        return TextInfo.IndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
-
-                default:
-                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
-            }  
-        }
-
-        // Returns the index of the last occurrence of a specified character in the current instance.
-        // The search starts at startIndex and runs backwards to startIndex - count + 1.
-        // The character at position startIndex is included in the search.  startIndex is the larger
-        // index within the string.
-        //
-        [Pure]
-        public int LastIndexOf(char value) {
-            return LastIndexOf(value, this.Length-1, this.Length);
-        }
-
-        [Pure]
-        public int LastIndexOf(char value, int startIndex){
-            return LastIndexOf(value,startIndex,startIndex + 1);
-        }
-
-        [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public unsafe int LastIndexOf(char value, int startIndex, int count) {
-            if (Length == 0)
-                return -1;
-
-            if (startIndex < 0 || startIndex >= Length)
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
-
-            if (count < 0 || count - 1 > startIndex)
-                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
-
-            fixed (char* pChars = &m_firstChar)
-            {
-                char* pCh = pChars + startIndex;
-
-                //We search [startIndex..EndIndex]
-                while (count >= 4)
-                {
-                    if (*pCh == value) goto ReturnIndex;
-                    if (*(pCh - 1) == value) goto ReturnIndex1;
-                    if (*(pCh - 2) == value) goto ReturnIndex2;
-                    if (*(pCh - 3) == value) goto ReturnIndex3;
-
-                    count -= 4;
-                    pCh -= 4;
-                }
-
-                while (count > 0)
-                {
-                    if (*pCh == value)
-                        goto ReturnIndex;
-
-                    count--;
-                    pCh--;
-                }
-
-                return -1;
-
-                ReturnIndex3: pCh--;
-                ReturnIndex2: pCh--;
-                ReturnIndex1: pCh--;
-                ReturnIndex:
-                return (int)(pCh - pChars);
-            }
-        }
-    
-        // Returns the index of the last occurrence of any specified character in the current instance.
-        // The search starts at startIndex and runs backwards to startIndex - count + 1.
-        // The character at position startIndex is included in the search.  startIndex is the larger
-        // index within the string.
-        //
-        
-        //ForceInline ... Jit can't recognize String.get_Length to determine that this is "fluff"
-        [Pure]
-        public int LastIndexOfAny(char [] anyOf) {
-            return LastIndexOfAny(anyOf,this.Length-1,this.Length);
-        }
-    
-        [Pure]
-        public int LastIndexOfAny(char [] anyOf, int startIndex) {
-            return LastIndexOfAny(anyOf,startIndex,startIndex + 1);
-        }
-
-        [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        public extern int LastIndexOfAny(char [] anyOf, int startIndex, int count);
-    
-    
-        // Returns the index of the last occurrence of any character in value in the current instance.
-        // The search starts at startIndex and runs backwards to startIndex - count + 1.
-        // The character at position startIndex is included in the search.  startIndex is the larger
-        // index within the string.
-        //
-        [Pure]
-        public int LastIndexOf(String value) {
-            return LastIndexOf(value, this.Length-1,this.Length, StringComparison.CurrentCulture);
-        }
-
-        [Pure]
-        public int LastIndexOf(String value, int startIndex) {
-            return LastIndexOf(value, startIndex, startIndex + 1, StringComparison.CurrentCulture);
-        }
-
-        [Pure]
-        public int LastIndexOf(String value, int startIndex, int count) {
-            if (count<0) {
-                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
-            }
-            Contract.EndContractBlock();
-
-            return LastIndexOf(value, startIndex, count, StringComparison.CurrentCulture);
-        }
-
-        [Pure]
-        public int LastIndexOf(String value, StringComparison comparisonType) {
-            return LastIndexOf(value, this.Length-1, this.Length, comparisonType);
-        }
-
-        [Pure]
-        public int LastIndexOf(String value, int startIndex, StringComparison comparisonType) {
-            return LastIndexOf(value, startIndex, startIndex + 1, comparisonType);
-        }
-
-        [Pure]
-        [System.Security.SecuritySafeCritical]
-        public int LastIndexOf(String value, int startIndex, int count, StringComparison comparisonType) {
-            if (value == null)
-                throw new ArgumentNullException("value");
-            Contract.EndContractBlock();
-
-            // Special case for 0 length input strings
-            if (this.Length == 0 && (startIndex == -1 || startIndex == 0))
-                return (value.Length == 0) ? 0 : -1;
-
-            // Now after handling empty strings, make sure we're not out of range
-            if (startIndex < 0 || startIndex > this.Length)
-                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
-            
-            // Make sure that we allow startIndex == this.Length
-            if (startIndex == this.Length)
-            {
-                startIndex--;
-                if (count > 0)
-                    count--;
-
-                // If we are looking for nothing, just return 0
-                if (value.Length == 0 && count >= 0 && startIndex - count + 1 >= 0)
-                    return startIndex;
-            }
-
-            // 2nd half of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
-            if (count < 0 || startIndex - count + 1 < 0)
-                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
-
-
-            switch (comparisonType) {
-                case StringComparison.CurrentCulture:
-                    return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.None);
-
-                case StringComparison.CurrentCultureIgnoreCase:
-                    return CultureInfo.CurrentCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
-
-                case StringComparison.InvariantCulture:
-                    return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.None);
-
-                case StringComparison.InvariantCultureIgnoreCase:
-                    return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
-                case StringComparison.Ordinal:
-                    return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.Ordinal);
-                     
-                case StringComparison.OrdinalIgnoreCase:
-                    if (value.IsAscii() && this.IsAscii())
-                        return CultureInfo.InvariantCulture.CompareInfo.LastIndexOf(this, value, startIndex, count, CompareOptions.IgnoreCase);
-                    else
-                        return TextInfo.LastIndexOfStringOrdinalIgnoreCase(this, value, startIndex, count);
-                default:
-                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
-            }  
-        }
-        
+        // Gets the length of this string
         //
+        /// This is a EE implemented function so that the JIT can recognise is specially
+        /// and eliminate checks on character fetchs in a loop like:
+        ///        for(int i = 0; i < str.Length; i++) str[i]
+        /// The actually code generated for this will be one instruction and will be inlined.
         //
-        [Pure]
-        public String PadLeft(int totalWidth) {
-            return PadLeft(totalWidth, ' ');
-        }
-
-        [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public String PadLeft(int totalWidth, char paddingChar) {
-            if (totalWidth < 0)
-                throw new ArgumentOutOfRangeException("totalWidth", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-            int oldLength = Length;
-            int count = totalWidth - oldLength;
-            if (count <= 0)
-                return this;
-            String result = FastAllocateString(totalWidth);
-            unsafe
-            {
-                fixed (char* dst = &result.m_firstChar)
-                {
-                    for (int i = 0; i < count; i++)
-                        dst[i] = paddingChar;
-                    fixed (char* src = &m_firstChar)
-                    {
-                        wstrcpy(dst + count, src, oldLength);
-                    }
-                }
-            }
-            return result;
-        }
-
-        [Pure]
-        public String PadRight(int totalWidth) {
-            return PadRight(totalWidth, ' ');
-        }
-
-        [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public String PadRight(int totalWidth, char paddingChar) {
-            if (totalWidth < 0)
-                throw new ArgumentOutOfRangeException("totalWidth", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
-            int oldLength = Length;
-            int count = totalWidth - oldLength;
-            if (count <= 0)
-                return this;
-            String result = FastAllocateString(totalWidth);
-            unsafe
-            {
-                fixed (char* dst = &result.m_firstChar)
-                {
-                    fixed (char* src = &m_firstChar)
-                    {
-                        wstrcpy(dst, src, oldLength);
-                    }
-                    for (int i = 0; i < count; i++)
-                        dst[oldLength + i] = paddingChar;
-                }
-            }
-            return result;
+        // Spec#: Add postcondition in a contract assembly.  Potential perf problem.
+        public extern int Length {
+            [System.Security.SecuritySafeCritical]  // auto-generated
+            [MethodImplAttribute(MethodImplOptions.InternalCall)]
+            get;
         }
     
-        // Determines whether a specified string is a prefix of the current instance
+        // Creates a new string with the characters copied in from ptr. If
+        // ptr is null, a 0-length string (like String.Empty) is returned.
         //
-        [Pure]
-        public Boolean StartsWith(String value) {
-            if ((Object)value == null) {
-                throw new ArgumentNullException("value");
-            }
-            Contract.EndContractBlock();
-            return StartsWith(value, StringComparison.CurrentCulture);
-        }
-
-        [Pure]
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        [ComVisible(false)]
-        public Boolean StartsWith(String value, StringComparison comparisonType) {
-            if( (Object)value == null) {
-                throw new ArgumentNullException("value");                                
-            }
-
-            if( comparisonType < StringComparison.CurrentCulture || comparisonType > StringComparison.OrdinalIgnoreCase) {
-                throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
-            }
-            Contract.EndContractBlock();
-
-            if( (Object)this == (Object)value) {
-                return true;
-            }
-
-            if( value.Length == 0) {
-                return true;
-            }
-
-            switch (comparisonType) {
-                case StringComparison.CurrentCulture:
-                    return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None);
-
-                case StringComparison.CurrentCultureIgnoreCase:
-                    return CultureInfo.CurrentCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase);
-
-                case StringComparison.InvariantCulture:
-                    return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.None);
-
-                case StringComparison.InvariantCultureIgnoreCase:
-                    return CultureInfo.InvariantCulture.CompareInfo.IsPrefix(this, value, CompareOptions.IgnoreCase);                    
-
-                case StringComparison.Ordinal:
-                    if( this.Length < value.Length || m_firstChar != value.m_firstChar) {
-                        return false;
-                    }
-                    return (value.Length == 1) ?
-                            true :                 // First char is the same and thats all there is to compare
-                            StartsWithOrdinalHelper(this, value);
-
-                case StringComparison.OrdinalIgnoreCase:
-                    if( this.Length < value.Length) {
-                        return false;
-                    }
-                    
-#if FEATURE_COREFX_GLOBALIZATION
-                    return (CompareInfo.CompareOrdinalIgnoreCase(this, 0, value.Length, value, 0, value.Length) == 0);
-#else
-                    return (TextInfo.CompareOrdinalIgnoreCaseEx(this, 0, value, 0, value.Length, value.Length) == 0);
-#endif
-
-                default:
-                    throw new ArgumentException(Environment.GetResourceString("NotSupported_StringComparison"), "comparisonType");
-            }                        
-        }
+        [System.Security.SecurityCritical]  // auto-generated
+        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
+        unsafe public extern String(char *value);
+        [System.Security.SecurityCritical]  // auto-generated
+        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
+        unsafe public extern String(char *value, int startIndex, int length);
+    
+        [System.Security.SecurityCritical]  // auto-generated
+        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
+        unsafe public extern String(sbyte *value);
+        [System.Security.SecurityCritical]  // auto-generated
+        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
+        unsafe public extern String(sbyte *value, int startIndex, int length);
 
-        [Pure]
-        public Boolean StartsWith(String value, Boolean ignoreCase, CultureInfo culture) {
-            if (null==value) {
-                throw new ArgumentNullException("value");
-            }
-            Contract.EndContractBlock();
+        [System.Security.SecurityCritical]  // auto-generated
+        [CLSCompliant(false), MethodImplAttribute(MethodImplOptions.InternalCall)]
+        unsafe public extern String(sbyte *value, int startIndex, int length, Encoding enc);
+        
+        [System.Security.SecurityCritical]  // auto-generated
+        unsafe static private String CreateString(sbyte *value, int startIndex, int length, Encoding enc) {            
+            if (enc == null)
+                return new String(value, startIndex, length); // default to ANSI
 
-            if((object)this == (object)value) {
-                return true;
+            if (length < 0)
+                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
+            if (startIndex < 0)
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
+            if ((value + startIndex) < value) {
+                // overflow check
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
             }
 
-            CultureInfo referenceCulture;
-            if (culture == null)
-                referenceCulture = CultureInfo.CurrentCulture;
-            else
-                referenceCulture = culture;
+            byte [] b = new byte[length];
 
-            return referenceCulture.CompareInfo.IsPrefix(this, value, ignoreCase ? CompareOptions.IgnoreCase : CompareOptions.None);
-        }
-  
-        // Creates a copy of this string in lower case.
-        [Pure]
-        public String ToLower() {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-            return this.ToLower(CultureInfo.CurrentCulture);
-        }
-    
-        // Creates a copy of this string in lower case.  The culture is set by culture.
-        [Pure]
-        public String ToLower(CultureInfo culture) {
-            if (culture == null)
-            {
-                throw new ArgumentNullException("culture");
+            try {
+                Buffer.Memcpy(b, 0, (byte*)value, startIndex, length);
             }
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-            return culture.TextInfo.ToLower(this);
-        }
-
-        // Creates a copy of this string in lower case based on invariant culture.
-        [Pure]
-        public String ToLowerInvariant() {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-            return this.ToLower(CultureInfo.InvariantCulture);
-        }
-    
-        // Creates a copy of this string in upper case.
-        [Pure]
-        public String ToUpper() {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-            return this.ToUpper(CultureInfo.CurrentCulture);
-        }
-   
-
-        // Creates a copy of this string in upper case.  The culture is set by culture.
-        [Pure]
-        public String ToUpper(CultureInfo culture) {
-            if (culture == null)
-            {
-                throw new ArgumentNullException("culture");
+            catch(NullReferenceException) {
+                // If we got a NullReferencException. It means the pointer or 
+                // the index is out of range
+                throw new ArgumentOutOfRangeException("value", 
+                        Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));                
             }
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-            return culture.TextInfo.ToUpper(this);
-        }
-
-
-        //Creates a copy of this string in upper case based on invariant culture.
-        [Pure]
-        public String ToUpperInvariant() {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-            return this.ToUpper(CultureInfo.InvariantCulture);
-        }
-
-   
-        // Returns this string.
-        public override String ToString() {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-            return this;
-        }
-
-        public String ToString(IFormatProvider provider) {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-            return this;
-        }
-    
-        // Method required for the ICloneable interface.
-        // There's no point in cloning a string since they're immutable, so we simply return this.
-        public Object Clone() {
-            Contract.Ensures(Contract.Result<Object>() != null);
-            Contract.EndContractBlock();
-            return this;
-        }
-
-        // Trims the whitespace from both ends of the string.  Whitespace is defined by
-        // Char.IsWhiteSpace.
-        //
-        [Pure]
-        public String Trim() {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
 
-            return TrimHelper(TrimBoth);        
+            return enc.GetString(b);
         }
+        
+        // Helper for encodings so they can talk to our buffer directly
+        // stringLength must be the exact size we'll expect
+        [System.Security.SecurityCritical]  // auto-generated
+        unsafe static internal String CreateStringFromEncoding(
+            byte* bytes, int byteLength, Encoding encoding)
+        {
+            Contract.Requires(bytes != null);
+            Contract.Requires(byteLength >= 0);
 
-       
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        private String TrimHelper(int trimType) {
-            //end will point to the first non-trimmed character on the right
-            //start will point to the first non-trimmed character on the Left
-            int end = this.Length-1;
-            int start=0;
-
-            //Trim specified characters.
-            if (trimType !=TrimTail)  {
-                for (start=0; start < this.Length; start++) {
-                    if (!Char.IsWhiteSpace(this[start])) break;
-                }
-            }
+            // Get our string length
+            int stringLength = encoding.GetCharCount(bytes, byteLength, null);
+            Contract.Assert(stringLength >= 0, "stringLength >= 0");
             
-            if (trimType !=TrimHead) {
-                for (end= Length -1; end >= start;  end--) {
-                    if (!Char.IsWhiteSpace(this[end])) break;
-                }
-            }
-
-            return CreateTrimmedString(start, end);
-        }
-    
-    
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        private String TrimHelper(char[] trimChars, int trimType) {
-            //end will point to the first non-trimmed character on the right
-            //start will point to the first non-trimmed character on the Left
-            int end = this.Length-1;
-            int start=0;
-
-            //Trim specified characters.
-            if (trimType !=TrimTail)  {
-                for (start=0; start < this.Length; start++) {
-                    int i = 0;
-                    char ch = this[start];
-                    for( i = 0; i < trimChars.Length; i++) {
-                        if( trimChars[i] == ch) break;
-                    }
-                    if( i == trimChars.Length) { // the character is not white space
-                        break;  
-                    }
-                }
-            }
+            // They gave us an empty string if they needed one
+            // 0 bytelength might be possible if there's something in an encoder
+            if (stringLength == 0)
+                return String.Empty;
             
-            if (trimType !=TrimHead) {
-                for (end= Length -1; end >= start;  end--) {
-                    int i = 0;    
-                    char ch = this[end];                    
-                    for(i = 0; i < trimChars.Length; i++) {
-                        if( trimChars[i] == ch) break;
-                    }
-                    if( i == trimChars.Length) { // the character is not white space
-                        break;  
-                    }                    
-                }
+            String s = FastAllocateString(stringLength);
+            fixed(char* pTempChars = &s.m_firstChar)
+            {
+                int doubleCheck = encoding.GetChars(bytes, byteLength, pTempChars, stringLength, null);
+                Contract.Assert(stringLength == doubleCheck, 
+                    "Expected encoding.GetChars to return same length as encoding.GetCharCount");
             }
 
-            return CreateTrimmedString(start, end);
+            return s;
         }
 
-
-        [System.Security.SecurityCritical]  // auto-generated
-        private String CreateTrimmedString(int start, int end) {
-            int len = end -start + 1;
-            if (len == this.Length) {
-                // Don't allocate a new string as the trimmed string has not changed.
-                return this;
-            }
-
-            if( len == 0) {
-                return String.Empty;
-            }
-            return InternalSubString(start, len);
-        }
-    
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public String Insert(int startIndex, String value)
+        // This is only intended to be used by char.ToString.
+        // It is necessary to put the code in this class instead of Char, since m_firstChar is a private member.
+        // Making m_firstChar internal would be dangerous since it would make it much easier to break String's immutability.
+        [SecuritySafeCritical]
+        internal static string CreateFromChar(char c)
         {
-            if (value == null)
-                throw new ArgumentNullException("value");
-            if (startIndex < 0 || startIndex > this.Length)
-                throw new ArgumentOutOfRangeException("startIndex");
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.Ensures(Contract.Result<String>().Length == this.Length + value.Length);
-            Contract.EndContractBlock();
-            
-            int oldLength = Length;
-            int insertLength = value.Length;
-            
-            if (oldLength == 0)
-                return value;
-            if (insertLength == 0)
-                return this;
-            
-            // In case this computation overflows, newLength will be negative and FastAllocateString throws OutOfMemoryException
-            int newLength = oldLength + insertLength;
-            String result = FastAllocateString(newLength);
-            unsafe
-            {
-                fixed (char* srcThis = &m_firstChar)
-                {
-                    fixed (char* srcInsert = &value.m_firstChar)
-                    {
-                        fixed (char* dst = &result.m_firstChar)
-                        {
-                            wstrcpy(dst, srcThis, startIndex);
-                            wstrcpy(dst + startIndex, srcInsert, insertLength);
-                            wstrcpy(dst + startIndex + insertLength, srcThis + startIndex, oldLength - startIndex);
-                        }
-                    }
-                }
-            }
+            string result = FastAllocateString(1);
+            result.m_firstChar = c;
             return result;
         }
-
-        // Replaces all instances of oldChar with newChar.
-        //
+                
         [System.Security.SecuritySafeCritical]  // auto-generated
-        public String Replace(char oldChar, char newChar)
+        unsafe internal int GetBytesFromEncoding(byte* pbNativeBuffer, int cbNativeBuffer,Encoding encoding)
         {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.Ensures(Contract.Result<String>().Length == this.Length);
-            Contract.EndContractBlock();
-
-            if (oldChar == newChar)
-                return this;
-
-            unsafe
+            // encoding == Encoding.UTF8
+            fixed (char* pwzChar = &this.m_firstChar)
             {
-                int remainingLength = Length;
-
-                fixed (char* pChars = &m_firstChar)
-                {
-                    char* pSrc = pChars;
-
-                    while (remainingLength > 0)
-                    {
-                        if (*pSrc == oldChar)
-                        {
-                            break;
-                        }
+                return encoding.GetBytes(pwzChar, m_stringLength, pbNativeBuffer, cbNativeBuffer);
+            }            
+        }
 
-                        remainingLength--;
-                        pSrc++;
-                    }
-                }
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        unsafe internal int ConvertToAnsi(byte *pbNativeBuffer, int cbNativeBuffer, bool fBestFit, bool fThrowOnUnmappableChar)
+        {
+            Contract.Assert(cbNativeBuffer >= (Length + 1) * Marshal.SystemMaxDBCSCharSize, "Insufficient buffer length passed to ConvertToAnsi");
 
-                if (remainingLength == 0)
-                    return this;
+            const uint CP_ACP = 0;
+            int nb;
 
-                String result = FastAllocateString(Length);
+            const uint WC_NO_BEST_FIT_CHARS = 0x00000400;
 
-                fixed (char* pChars = &m_firstChar)
-                {
-                    fixed (char* pResult = &result.m_firstChar)
-                    {
-                        int copyLength = Length - remainingLength;
-
-                        //Copy the characters already proven not to match.
-                        if (copyLength > 0)
-                        {
-                            wstrcpy(pResult, pChars, copyLength);
-                        }
+            uint flgs = (fBestFit ? 0 : WC_NO_BEST_FIT_CHARS);
+            uint DefaultCharUsed = 0;
 
-                        //Copy the remaining characters, doing the replacement as we go.
-                        char* pSrc = pChars + copyLength;
-                        char* pDst = pResult + copyLength;
-
-                        do
-                        {
-                            char currentChar = *pSrc;
-                            if (currentChar == oldChar)
-                                currentChar = newChar;
-                            *pDst = currentChar;
-
-                            remainingLength--;
-                            pSrc++;
-                            pDst++;
-                        } while (remainingLength > 0);
-                    }
-                }
+            fixed (char* pwzChar = &this.m_firstChar)
+            {
+                nb = Win32Native.WideCharToMultiByte(
+                    CP_ACP,
+                    flgs,
+                    pwzChar,
+                    this.Length,
+                    pbNativeBuffer,
+                    cbNativeBuffer,
+                    IntPtr.Zero,
+                    (fThrowOnUnmappableChar ? new IntPtr(&DefaultCharUsed) : IntPtr.Zero));
+            }
 
-                return result;
+            if (0 != DefaultCharUsed)
+            {
+                throw new ArgumentException(Environment.GetResourceString("Interop_Marshal_Unmappable_Char"));
             }
-        }
 
-        // This method contains the same functionality as StringBuilder Replace. The only difference is that
-        // a new String has to be allocated since Strings are immutable
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private extern String ReplaceInternal(String oldValue, String newValue);
+            pbNativeBuffer[nb] = 0;
+            return nb;
+        }
 
-        public String Replace(String oldValue, String newValue)
+        // Normalization Methods
+        // These just wrap calls to Normalization class
+        public bool IsNormalized()
         {
-            if (oldValue == null)
-                throw new ArgumentNullException("oldValue");
-            // Note that if newValue is null, we treat it like String.Empty.
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-
-            return ReplaceInternal(oldValue, newValue);
+#if !FEATURE_NORM_IDNA_ONLY
+            // Default to Form C
+            return IsNormalized(NormalizationForm.FormC);
+#else
+            // Default to Form IDNA
+            return IsNormalized((NormalizationForm)ExtendedNormalizationForms.FormIdna);
+#endif
         }
 
         [System.Security.SecuritySafeCritical]  // auto-generated
-        public String Remove(int startIndex, int count)
+        public bool IsNormalized(NormalizationForm normalizationForm)
         {
-            if (startIndex < 0)
-                throw new ArgumentOutOfRangeException("startIndex", 
-                    Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
-            if (count < 0)
-                throw new ArgumentOutOfRangeException("count", 
-                    Environment.GetResourceString("ArgumentOutOfRange_NegativeCount"));
-            if (count > Length - startIndex)
-                throw new ArgumentOutOfRangeException("count", 
-                    Environment.GetResourceString("ArgumentOutOfRange_IndexCount"));
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.Ensures(Contract.Result<String>().Length == this.Length - count);
-            Contract.EndContractBlock();
-            
-            if (count == 0)
-                return this;
-            int newLength = Length - count;
-            if (newLength == 0)
-                return String.Empty;
-            
-            String result = FastAllocateString(newLength);
-            unsafe
+#if !FEATURE_NORM_IDNA_ONLY
+            if (this.IsFastSort())
             {
-                fixed (char* src = &m_firstChar)
-                {
-                    fixed (char* dst = &result.m_firstChar)
-                    {
-                        wstrcpy(dst, src, startIndex);
-                        wstrcpy(dst + startIndex, src + startIndex + count, newLength - startIndex);
-                    }
-                }
-            }
-            return result;
+                // If its FastSort && one of the 4 main forms, then its already normalized
+                if( normalizationForm == NormalizationForm.FormC ||
+                    normalizationForm == NormalizationForm.FormKC ||
+                    normalizationForm == NormalizationForm.FormD ||
+                    normalizationForm == NormalizationForm.FormKD )
+                    return true;
+            }            
+#endif // !FEATURE_NORM_IDNA_ONLY            
+            return Normalization.IsNormalized(this, normalizationForm);
         }
 
-        // a remove that just takes a startindex. 
-        public string Remove( int startIndex ) {
-            if (startIndex < 0) {
-                throw new ArgumentOutOfRangeException("startIndex", 
-                        Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
-            }
-            
-            if (startIndex >= Length) {
-                throw new ArgumentOutOfRangeException("startIndex", 
-                        Environment.GetResourceString("ArgumentOutOfRange_StartIndexLessThanLength"));                
-            }
-            
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-
-            return Substring(0, startIndex);
-        }   
-    
-        public static String Format(String format, Object arg0) {
-            Contract.Ensures(Contract.Result<String>() != null);
-            return FormatHelper(null, format, new ParamsArray(arg0));
-        }
-    
-        public static String Format(String format, Object arg0, Object arg1) {
-            Contract.Ensures(Contract.Result<String>() != null);
-            return FormatHelper(null, format, new ParamsArray(arg0, arg1));
-        }
-    
-        public static String Format(String format, Object arg0, Object arg1, Object arg2) {
-            Contract.Ensures(Contract.Result<String>() != null);
-            return FormatHelper(null, format, new ParamsArray(arg0, arg1, arg2));
+        public String Normalize()
+        {
+#if !FEATURE_NORM_IDNA_ONLY
+            // Default to Form C
+            return Normalize(NormalizationForm.FormC);
+#else
+            // Default to Form IDNA
+            return Normalize((NormalizationForm)ExtendedNormalizationForms.FormIdna);
+#endif
         }
 
-        public static String Format(String format, params Object[] args) {
-            if (args == null)
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        public String Normalize(NormalizationForm normalizationForm)
+        {
+#if !FEATURE_NORM_IDNA_ONLY        
+            if (this.IsAscii())
             {
-                // 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 FormatHelper.
-                throw new ArgumentNullException((format == null) ? "format" : "args");
+                // If its FastSort && one of the 4 main forms, then its already normalized
+                if( normalizationForm == NormalizationForm.FormC ||
+                    normalizationForm == NormalizationForm.FormKC ||
+                    normalizationForm == NormalizationForm.FormD ||
+                    normalizationForm == NormalizationForm.FormKD )
+                    return this;
             }
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-            
-            return FormatHelper(null, format, new ParamsArray(args));
-        }
-        
-        public static String Format(IFormatProvider provider, String format, Object arg0) {
-            Contract.Ensures(Contract.Result<String>() != null);
-            return FormatHelper(provider, format, new ParamsArray(arg0));
-        }
-    
-        public static String Format(IFormatProvider provider, String format, Object arg0, Object arg1) {
-            Contract.Ensures(Contract.Result<String>() != null);
-            return FormatHelper(provider, format, new ParamsArray(arg0, arg1));
-        }
-    
-        public static String Format(IFormatProvider provider, String format, Object arg0, Object arg1, Object arg2) {
-            Contract.Ensures(Contract.Result<String>() != null);
-            return FormatHelper(provider, format, new ParamsArray(arg0, arg1, arg2));
+#endif // !FEATURE_NORM_IDNA_ONLY            
+            return Normalization.Normalize(this, normalizationForm);
         }
 
-        public static String Format(IFormatProvider provider, String format, params Object[] args) {
-            if (args == null)
-            {
-                // 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 FormatHelper.
-                throw new ArgumentNullException((format == null) ? "format" : "args");
-            }
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-            
-            return FormatHelper(provider, format, new ParamsArray(args));
-        }
-        
-        private static String FormatHelper(IFormatProvider provider, String format, ParamsArray args) {
-            if (format == null)
-                throw new ArgumentNullException("format");
-            
-            return StringBuilderCache.GetStringAndRelease(
-                StringBuilderCache
-                    .Acquire(format.Length + args.Length * 8)
-                    .AppendFormatHelper(provider, format, args));
-        }
+        [System.Security.SecurityCritical]  // auto-generated
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        internal extern static String FastAllocateString(int length);
+
+        // Creates a new string from the characters in a subarray.  The new string will
+        // be created from the characters in value between startIndex and
+        // startIndex + length - 1.
+        //
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        public extern String(char [] value, int startIndex, int length);
     
+        // Creates a new string from the characters in a subarray.  The new string will be
+        // created from the characters in value.
+        //
+        
         [System.Security.SecuritySafeCritical]  // auto-generated
-        unsafe public static String Copy (String str) {
-            if (str==null) {
-                throw new ArgumentNullException("str");
-            }
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        public extern String(char [] value);
 
-            int length = str.Length;
+        [System.Security.SecurityCritical]  // auto-generated
+        internal static unsafe void wstrcpy(char *dmem, char *smem, int charCount)
+        {
+            Buffer.Memcpy((byte*)dmem, (byte*)smem, charCount * 2); // 2 used everywhere instead of sizeof(char)
+        }
 
-            String result = FastAllocateString(length);
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        private String CtorCharArray(char [] value)
+        {
+            if (value != null && value.Length != 0) {
+                String result = FastAllocateString(value.Length);
 
-            fixed(char* dest = &result.m_firstChar)
-                fixed(char* src = &str.m_firstChar) {
-                     wstrcpy(dest, src, length);
+                unsafe {
+                    fixed (char* dest = &result.m_firstChar, source = value) {
+                        wstrcpy(dest, source, value.Length);
+                    }
                 }
-             return result;
+                return result;
+            }
+            else
+                return String.Empty;
         }
 
-        public static String Concat(Object arg0) {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        private String CtorCharArrayStartLength(char [] value, int startIndex, int length)
+        {
+            if (value == null)
+                throw new ArgumentNullException("value");
 
-            if (arg0 == null)
-            {
-                return String.Empty;
-            }
-            return arg0.ToString();
-        }
-    
-        public static String Concat(Object arg0, Object arg1) {
-            Contract.Ensures(Contract.Result<String>() != null);
+            if (startIndex < 0)
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
+
+            if (length < 0)
+                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
+
+            if (startIndex > value.Length - length)
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
             Contract.EndContractBlock();
 
-            if (arg0 == null)
-            {
-                arg0 = String.Empty;
-            }
-    
-            if (arg1==null) {
-                arg1 = String.Empty;
+            if (length > 0) {
+                String result = FastAllocateString(length);
+
+                unsafe {
+                    fixed (char* dest = &result.m_firstChar, source = value) {
+                        wstrcpy(dest, source + startIndex, length);
+                    }
+                }
+                return result;
             }
-            return Concat(arg0.ToString(), arg1.ToString());
+            else
+                return String.Empty;
         }
-    
-        public static String Concat(Object arg0, Object arg1, Object arg2) {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
 
-            if (arg0 == null)
-            {
-                arg0 = String.Empty;
-            }
-    
-            if (arg1==null) {
-                arg1 = String.Empty;
-            }
-    
-            if (arg2==null) {
-                arg2 = String.Empty;
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        private String CtorCharCount(char c, int count)
+        {
+            if (count > 0) {
+                String result = FastAllocateString(count);
+                if (c != 0)
+                {
+                    unsafe {
+                        fixed (char* dest = &result.m_firstChar) {
+                            char *dmem = dest;
+                            while (((uint)dmem & 3) != 0 && count > 0) {
+                                *dmem++ = c;
+                                count--;
+                            }
+                            uint cc = (uint)((c << 16) | c);
+                            if (count >= 4) {
+                                count -= 4;
+                                do{
+                                    ((uint *)dmem)[0] = cc;
+                                    ((uint *)dmem)[1] = cc;
+                                    dmem += 4;
+                                    count -= 4;
+                                } while (count >= 0);
+                            }
+                            if ((count & 2) != 0) {
+                                ((uint *)dmem)[0] = cc;
+                                dmem += 2;
+                            }
+                            if ((count & 1) != 0)
+                                dmem[0] = c;
+                        }
+                    }
+                }
+                return result;
             }
-    
-            return Concat(arg0.ToString(), arg1.ToString(), arg2.ToString());
+            else if (count == 0)
+                return String.Empty;
+            else
+                throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_MustBeNonNegNum", "count"));
         }
 
-        [CLSCompliant(false)] 
-        public static String Concat(Object arg0, Object arg1, Object arg2, Object arg3, __arglist) 
+        [System.Security.SecurityCritical]  // auto-generated
+        private static unsafe int wcslen(char *ptr)
         {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
-
-            Object[]   objArgs;
-            int        argCount;
-            
-            ArgIterator args = new ArgIterator(__arglist);
-
-            //+4 to account for the 4 hard-coded arguments at the beginning of the list.
-            argCount = args.GetRemainingCount() + 4;
-    
-            objArgs = new Object[argCount];
-            
-            //Handle the hard-coded arguments
-            objArgs[0] = arg0;
-            objArgs[1] = arg1;
-            objArgs[2] = arg2;
-            objArgs[3] = arg3;
+            char *end = ptr;
             
-            //Walk all of the args in the variable part of the argument list.
-            for (int i=4; i<argCount; i++) {
-                objArgs[i] = TypedReference.ToObject(args.GetNextArg());
-            }
-
-            return Concat(objArgs);
-        }
-
-        [System.Security.SecuritySafeCritical]
-        public static string Concat(params object[] args)
-        {
-            if (args == null)
-            {
-                throw new ArgumentNullException("args");
-            }
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
+            // First make sure our pointer is aligned on a word boundary
+            int alignment = IntPtr.Size - 1;
 
-            if (args.Length <= 1)
+            // If ptr is at an odd address (e.g. 0x5), this loop will simply iterate all the way
+            while (((uint)end & (uint)alignment) != 0)
             {
-                return args.Length == 0 ?
-                    string.Empty :
-                    args[0]?.ToString() ?? string.Empty;
+                if (*end == 0) goto FoundZero;
+                end++;
             }
 
-            // We need to get an intermediary string array
-            // to fill with each of the args' ToString(),
-            // and then just concat that in one operation.
-
-            // This way we avoid any intermediary string representations,
-            // or buffer resizing if we use StringBuilder (although the
-            // latter case is partially alleviated due to StringBuilder's
-            // linked-list style implementation)
-
-            var strings = new string[args.Length];
-            
-            int totalLength = 0;
-
-            for (int i = 0; i < args.Length; i++)
-            {
-                object value = args[i];
-
-                string toString = value?.ToString() ?? string.Empty; // We need to handle both the cases when value or value.ToString() is null
-                strings[i] = toString;
+#if !BIT64
+            // The following code is (somewhat surprisingly!) significantly faster than a naive loop,
+            // at least on x86 and the current jit.
 
-                totalLength += toString.Length;
+            // The loop condition below works because if "end[0] & end[1]" is non-zero, that means
+            // neither operand can have been zero. If is zero, we have to look at the operands individually,
+            // but we hope this going to fairly rare.
 
-                if (totalLength < 0) // Check for a positive overflow
-                {
-                    throw new OutOfMemoryException();
-                }
-            }
+            // In general, it would be incorrect to access end[1] if we haven't made sure
+            // end[0] is non-zero. However, we know the ptr has been aligned by the loop above
+            // so end[0] and end[1] must be in the same word (and therefore page), so they're either both accessible, or both not.
 
-            // If all of the ToStrings are null/empty, just return string.Empty
-            if (totalLength == 0)
-            {
-                return string.Empty;
+            while ((end[0] & end[1]) != 0 || (end[0] != 0 && end[1] != 0)) {
+                end += 2;
             }
 
-            string result = FastAllocateString(totalLength);
-            int position = 0; // How many characters we've copied so far
-
-            for (int i = 0; i < strings.Length; i++)
-            {
-                string s = strings[i];
+            Contract.Assert(end[0] == 0 || end[1] == 0);
+            if (end[0] != 0) end++;
+#else // !BIT64
+            // Based on https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
 
-                Contract.Assert(s != null);
-                Contract.Assert(position <= totalLength - s.Length, "We didn't allocate enough space for the result string!");
+            // 64-bit implementation: process 1 ulong (word) at a time
 
-                FillStringChecked(result, position, s);
-                position += s.Length;
-            }
+            // What we do here is add 0x7fff from each of the
+            // 4 individual chars within the ulong, using MagicMask.
+            // If the char > 0 and < 0x8001, it will have its high bit set.
+            // We then OR with MagicMask, to set all the other bits.
+            // This will result in all bits set (ulong.MaxValue) for any
+            // char that fits the above criteria, and something else otherwise.
 
-            return result;
-        }
+            // Note that for any char > 0x8000, this will be a false
+            // positive and we will fallback to the slow path and
+            // check each char individually. This is OK though, since
+            // we optimize for the common case (ASCII chars, which are < 0x80).
 
-        [ComVisible(false)]
-        public static string Concat<T>(IEnumerable<T> values)
-        {
-            if (values == null)
-                throw new ArgumentNullException("values");
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
+            // NOTE: We can access a ulong a time since the ptr is aligned,
+            // and therefore we're only accessing the same word/page. (See notes
+            // for the 32-bit version above.)
+            
+            const ulong MagicMask = 0x7fff7fff7fff7fff;
 
-            using (IEnumerator<T> en = values.GetEnumerator())
+            while (true)
             {
-                if (!en.MoveNext())
-                    return string.Empty;
-                
-                // We called MoveNext once, so this will be the first item
-                T currentValue = en.Current;
-
-                // Call ToString before calling MoveNext again, since
-                // we want to stay consistent with the below loop
-                // Everything should be called in the order
-                // MoveNext-Current-ToString, unless further optimizations
-                // can be made, to avoid breaking changes
-                string firstString = currentValue?.ToString();
-
-                // If there's only 1 item, simply call ToString on that
-                if (!en.MoveNext())
-                {
-                    // We have to handle the case of either currentValue
-                    // or its ToString being null
-                    return firstString ?? string.Empty;
-                }
-
-                StringBuilder result = StringBuilderCache.Acquire();
-                
-                result.Append(firstString);
+                ulong word = *(ulong*)end;
+                word += MagicMask; // cause high bit to be set if not zero, and <= 0x8000
+                word |= MagicMask; // set everything besides the high bits
 
-                do
+                if (word == ulong.MaxValue) // 0xffff...
                 {
-                    currentValue = en.Current;
-
-                    if (currentValue != null)
-                    {
-                        result.Append(currentValue.ToString());
-                    }
+                    // all of the chars have their bits set (and therefore none can be 0)
+                    end += 4;
+                    continue;
                 }
-                while (en.MoveNext());
-
-                return StringBuilderCache.GetStringAndRelease(result);
-            }
-        }
 
+                // at least one of them didn't have their high bit set!
+                // go through each char and check for 0.
 
-        [ComVisible(false)]
-        public static string Concat(IEnumerable<string> values)
-        {
-            if (values == null)
-                throw new ArgumentNullException("values");
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.EndContractBlock();
+                if (end[0] == 0) goto EndAt0;
+                if (end[1] == 0) goto EndAt1;
+                if (end[2] == 0) goto EndAt2;
+                if (end[3] == 0) goto EndAt3;
 
-            using (IEnumerator<string> en = values.GetEnumerator())
-            {
-                if (!en.MoveNext())
-                    return string.Empty;
-                
-                string firstValue = en.Current;
+                // if we reached here, it was a false positive-- just continue
+                end += 4;
+            }
 
-                if (!en.MoveNext())
-                {
-                    return firstValue ?? string.Empty;
-                }
+            EndAt3: end++;
+            EndAt2: end++;
+            EndAt1: end++;
+            EndAt0:
+#endif // !BIT64
 
-                StringBuilder result = StringBuilderCache.Acquire();
-                result.Append(firstValue);
+            FoundZero:
+            Contract.Assert(*end == 0);
 
-                do
-                {
-                    result.Append(en.Current);
-                }
-                while (en.MoveNext());
+            int count = (int)(end - ptr);
 
-                return StringBuilderCache.GetStringAndRelease(result);
-            }
+            return count;
         }
 
+        [System.Security.SecurityCritical]  // auto-generated
+        private unsafe String CtorCharPtr(char *ptr)
+        {
+            if (ptr == null)
+                return String.Empty;
+
+#if !FEATURE_PAL
+            if (ptr < (char*)64000)
+                throw new ArgumentException(Environment.GetResourceString("Arg_MustBeStringPtrNotAtom"));
+#endif // FEATURE_PAL
 
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public static String Concat(String str0, String str1) {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.Ensures(Contract.Result<String>().Length ==
-                (str0 == null ? 0 : str0.Length) +
-                (str1 == null ? 0 : str1.Length));
-            Contract.EndContractBlock();
+            Contract.Assert(this == null, "this == null");        // this is the string constructor, we allocate it
 
-            if (IsNullOrEmpty(str0)) {
-                if (IsNullOrEmpty(str1)) {
+            try {
+                int count = wcslen(ptr);
+                if (count == 0)
                     return String.Empty;
-                }
-                return str1;
-            }
 
-            if (IsNullOrEmpty(str1)) {
-                return str0;
+                String result = FastAllocateString(count);
+                fixed (char* dest = &result.m_firstChar)
+                    wstrcpy(dest, ptr, count);
+                return result;
+            }
+            catch (NullReferenceException) {
+                throw new ArgumentOutOfRangeException("ptr", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
             }
-
-            int str0Length = str0.Length;
-            
-            String result = FastAllocateString(str0Length + str1.Length);
-            
-            FillStringChecked(result, 0,        str0);
-            FillStringChecked(result, str0Length, str1);
-            
-            return result;
         }
 
-        [System.Security.SecuritySafeCritical]  // auto-generated
-        public static String Concat(String str0, String str1, String str2) {
-            Contract.Ensures(Contract.Result<String>() != null);
-            Contract.Ensures(Contract.Result<String>().Length ==
-                (str0 == null ? 0 : str0.Length) +
-                (str1 == null ? 0 : str1.Length) +
-                (str2 == null ? 0 : str2.Length));
-            Contract.EndContractBlock();
-
-            if (IsNullOrEmpty(str0))
-            {
-                return Concat(str1, str2);
+        [System.Security.SecurityCritical]  // auto-generated
+        private unsafe String CtorCharPtrStartLength(char *ptr, int startIndex, int length)
+        {
+            if (length < 0) {
+                throw new ArgumentOutOfRangeException("length", Environment.GetResourceString("ArgumentOutOfRange_NegativeLength"));
             }
 
-            if (IsNullOrEmpty(str1))
-            {
-                return Concat(str0, str2);
+            if (startIndex < 0) {
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_StartIndex"));
             }
+            Contract.EndContractBlock();
+            Contract.Assert(this == null, "this == null");        // this is the string constructor, we allocate it
 
-            if (IsNullOrEmpty(str2))
-            {
-                return Concat(str0, str1);
+            char *pFrom = ptr + startIndex;
+            if (pFrom < ptr) {
+                // This means that the pointer operation has had an overflow
+                throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
             }
 
-            int totalLength = str0.Length + str1.Length + str2.Length;
+            if (length == 0)
+                return String.Empty;
 
-            String result = FastAllocateString(totalLength);
-            FillStringChecked(result, 0, str0);
-            FillStringChecked(result, str0.Length, str1);
-            FillStringChecked(result, str0.Length + str1.Length, str2);
+            String result = FastAllocateString(length);
 
-            return result;
+            try {
+                fixed (char* dest = &result.m_firstChar)
+                    wstrcpy(dest, pFrom, length);
+                return result;
+            }
+            catch (NullReferenceException) {
+                throw new ArgumentOutOfRangeException("ptr", Environment.GetResourceString("ArgumentOutOfRange_PartialWCHAR"));
+            }
         }
 
         [System.Security.SecuritySafeCritical]  // auto-generated
-        public static String Concat(String str0, String str1, String str2, String str3) {
+        [MethodImplAttribute(MethodImplOptions.InternalCall)]
+        public extern String(char c, int count);
+
+   
+        // Returns this string.
+        public override String ToString() {
             Contract.Ensures(Contract.Result<String>() != null);
-            Contract.Ensures(Contract.Result<String>().Length == 
-                (str0 == null ? 0 : str0.Length) +
-                (str1 == null ? 0 : str1.Length) +
-                (str2 == null ? 0 : str2.Length) +
-                (str3 == null ? 0 : str3.Length));
             Contract.EndContractBlock();
-
-            if (IsNullOrEmpty(str0))
-            {
-                return Concat(str1, str2, str3);
-            }
-
-            if (IsNullOrEmpty(str1))
-            {
-                return Concat(str0, str2, str3);
-            }
-
-            if (IsNullOrEmpty(str2))
-            {
-                return Concat(str0, str1, str3);
-            }
-
-            if (IsNullOrEmpty(str3))
-            {
-                return Concat(str0, str1, str2);
-            }
-
-            int totalLength = str0.Length + str1.Length + str2.Length + str3.Length;
-
-            String result = FastAllocateString(totalLength);
-            FillStringChecked(result, 0, str0);
-            FillStringChecked(result, str0.Length, str1);
-            FillStringChecked(result, str0.Length + str1.Length, str2);
-            FillStringChecked(result, str0.Length + str1.Length + str2.Length, str3);
-
-            return result;
+            return this;
         }
 
-        [System.Security.SecuritySafeCritical]
-        public static String Concat(params String[] values) {
-            if (values == null)
-                throw new ArgumentNullException("values");
+        public String ToString(IFormatProvider provider) {
             Contract.Ensures(Contract.Result<String>() != null);
             Contract.EndContractBlock();
-
-            if (values.Length <= 1)
-            {
-                return values.Length == 0 ?
-                    string.Empty :
-                    values[0] ?? string.Empty;
-            }
-
-            // It's possible that the input values array could be changed concurrently on another
-            // thread, such that we can't trust that each read of values[i] will be equivalent.
-            // Worst case, we can make a defensive copy of the array and use that, but we first
-            // optimistically try the allocation and copies assuming that the array isn't changing,
-            // which represents the 99.999% case, in particular since string.Concat is used for
-            // string concatenation by the languages, with the input array being a params array.
-
-            // Sum the lengths of all input strings
-            long totalLengthLong = 0;
-            for (int i = 0; i < values.Length; i++)
-            {
-                string value = values[i];
-                if (value != null)
-                {
-                    totalLengthLong += value.Length;
-                }
+            return this;
+        }
+    
+        // Method required for the ICloneable interface.
+        // There's no point in cloning a string since they're immutable, so we simply return this.
+        public Object Clone() {
+            Contract.Ensures(Contract.Result<Object>() != null);
+            Contract.EndContractBlock();
+            return this;
+        }
+    
+        [System.Security.SecuritySafeCritical]  // auto-generated
+        unsafe public static String Copy (String str) {
+            if (str==null) {
+                throw new ArgumentNullException("str");
             }
+            Contract.Ensures(Contract.Result<String>() != null);
+            Contract.EndContractBlock();
 
-            // If it's too long, fail, or if it's empty, return an empty string.
-            if (totalLengthLong > int.MaxValue)
-            {
-                throw new OutOfMemoryException();
-            }
-            int totalLength = (int)totalLengthLong;
-            if (totalLength == 0)
-            {
-                return string.Empty;
-            }
+            int length = str.Length;
 
-            // Allocate a new string and copy each input string into it
-            string result = FastAllocateString(totalLength);
-            int copiedLength = 0;
-            for (int i = 0; i < values.Length; i++)
-            {
-                string value = values[i];
-                if (!string.IsNullOrEmpty(value))
-                {
-                    int valueLen = value.Length;
-                    if (valueLen > totalLength - copiedLength)
-                    {
-                        copiedLength = -1;
-                        break;
-                    }
+            String result = FastAllocateString(length);
 
-                    FillStringChecked(result, copiedLength, value);
-                    copiedLength += valueLen;
+            fixed(char* dest = &result.m_firstChar)
+                fixed(char* src = &str.m_firstChar) {
+                     wstrcpy(dest, src, length);
                 }
-            }
-
-            // If we copied exactly the right amount, return the new string.  Otherwise,
-            // something changed concurrently to mutate the input array: fall back to
-            // doing the concatenation again, but this time with a defensive copy. This
-            // fall back should be extremely rare.
-            return copiedLength == totalLength ? result : Concat((string[])values.Clone());
+             return result;
         }
         
         [System.Security.SecuritySafeCritical]  // auto-generated
@@ -3960,11 +888,4 @@ namespace System {
             }
         }      
     }
-
-    [ComVisible(false)]
-    [Flags]
-    public enum StringSplitOptions {
-        None = 0,
-        RemoveEmptyEntries = 1
-    }
 }
diff --git a/src/mscorlib/src/System/StringSplitOptions.cs b/src/mscorlib/src/System/StringSplitOptions.cs
new file mode 100644 (file)
index 0000000..ae95aae
--- /dev/null
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+
+namespace System
+{
+    [ComVisible(false)]
+    [Flags]
+    public enum StringSplitOptions
+    {
+        None = 0,
+        RemoveEmptyEntries = 1
+    }
+}